Android: Ist es möglich, Video-Miniaturansichten anzuzeigen?

90

Ich habe eine Videoaufzeichnungsanwendung mit Bibliotheksdialog erstellt. Im Bibliotheksdialog wird die Liste der aufgezeichneten Videos angezeigt, wobei jedes Element auf folgende Weise aus Symbol, Videotitel, Tags und Standortinformationen besteht:

Alt-Text

Weiß jemand, ob es möglich ist, Symbole durch Video-Miniaturansichten zu ersetzen (Einzelbildvorschau)?

Vielen Dank!

Niko Gamulin
quelle
Jede Antwort auf diese Frage
Machen Sie es einfach

Antworten:

71

Wenn Sie API 2.0 oder höher verwenden, funktioniert dies.

int id = **"The Video's ID"**
ImageView iv = (ImageView ) convertView.findViewById(R.id.imagePreview);
ContentResolver crThumb = getContentResolver();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap curThumb = MediaStore.Video.Thumbnails.getThumbnail(crThumb, id, MediaStore.Video.Thumbnails.MICRO_KIND, options);
iv.setImageBitmap(curThumb);
Greg Zimmers
quelle
9
Was genau ist das id?
Phunehehe
1
Sie können den MediaStore auf dem Telefon nach Videos abfragen. Die "ID" ist nur eine der Informationen, die Sie abfragen. Weitere Informationen zum MediaStore finden Sie unter developer.android.com/reference/android/provider/…
Greg Zimmers
4
Überrascht scheint jeder das zum Laufen zu bringen. Ich habe es versucht, aber der curThumb ist am Ende null.
BlueVoodoo
7
Wie wäre es, wenn Video von einer URL?
Jayellos
Bitte antworten Sie darauf [ stackoverflow.com/questions/16190374/…
Machen Sie es einfach
91

Wenn Sie den Cursor nicht durchlaufen oder nicht durchlaufen können und nur Pfade oder Dateiobjekte haben, können Sie seit API Level 8 (2.2) die öffentliche statische Bitmap createVideoThumbnail (String filePath, int kind) verwenden.

Android-Dokumentation

Der folgende Code läuft perfekt:

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
Damien Praca
quelle
6
Wenn ich versuche, ein Miniaturbild zu erstellen, erhalte ich null. Ich denke mein Weg ist vielleicht nicht in Ordnung? myPath = "/ external / video / media / 14180"
haythem souissi
Es funktioniert wie Magie. Auch wenn ich t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND`
Sami Eltamawy
Seltsamerweise funktioniert es auch nicht ;-( das Video existiert in der DB, ich kann den Namen / die Größe abrufen, aber nicht das Vorschaubild
Thomas Decaux
haythem souussi Da dies kein Pfad ist, ist dies Uri. Sie müssen ihn in einen Pfad konvertieren.
Nadir Novruzov
Dies funktioniert, gibt jedoch ein Bild aus dem falschen Teil des Videos zurück. Ich möchte das allererste Bild, bekomme aber 5-6 Sekunden in? Irgendwelche Ideen?
Speedynomads
38

Verwenden der Klasse:

import android.provider.MediaStore.Video.Thumbnails;

Wir können zwei Vorschaubildergrößen aus dem Video erhalten:

Thumbnails.MICRO_KIND für 96 x 96

Thumbnails.MINI_KIND für 512 x 384 px

Dies ist ein Codebeispiel:

String filePath = "/sdcard/DCIM/Camera/my_video.mp4"; //change the location of your file!

ImageView imageview_mini = (ImageView)findViewById(R.id.thumbnail_mini);
ImageView imageview_micro = (ImageView)findViewById(R.id.thumbnail_micro);

Bitmap bmThumbnail;

//MICRO_KIND, size: 96 x 96 thumbnail
bmThumbnail = ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MICRO_KIND);
imageview_micro.setImageBitmap(bmThumbnail);
     
// MINI_KIND, size: 512 x 384 thumbnail 
bmThumbnail = ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MINI_KIND);
imageview_mini.setImageBitmap(bmThumbnail);
Jorgesys
quelle
Wenn ich einen solchen Link für den Dateipfad habe, würde dies nicht funktionieren, da ich versuche, ihn auf eine Bildansicht zu setzen und er nichts anzeigt ... dies ist der Dateipfad "http: / /unknown.com/v3-" 1aox9d1 .mp4 "ist offensichtlich eine echte Domain, aber ist dieser Pfad nicht für Miniaturansichten geeignet?
Lion789
Um die ThumbnailUtils-Klasse zu verwenden, müssen Sie die Datei auf der Festplatte speichern und die folgende Methode verwenden: ThumbnailUtils.createVideoThumbnail ()
Jorgesys
Danke, wie bekomme ich dann den neuen Dateipfad für den Erstellungsdaumen?
Lion789
Warum funktioniert die Dosis unter Android 4 und höher nicht?
Criss
1
Hallo Cris, ich habe 3 Geräte 4.1 4.2.2 und 5.0 und es funktioniert ohne Probleme, poste eine Frage mit deinem Problem und etwas Code, und ich könnte dir helfen.
Jorgesys
19

Derzeit verwende ich folgenden Code:

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);

Aber ich habe eine bessere Lösung mit der Glide- Bibliothek mit folgendem Code gefunden (sie speichert auch Ihr Bild zwischen und hat eine bessere Leistung als der vorherige Ansatz).

Glide.with(context)
                .load(uri)
                .placeholder(R.drawable.ic_video_place_holder)
                .into(imageView);
Amir
quelle
19

Ich empfehle Ihnen wirklich, die Glide- Bibliothek zu verwenden. Dies ist eine der effizientesten Methoden zum Generieren und Anzeigen eines Video-Miniaturbilds für eine lokale Videodatei.

Fügen Sie einfach diese Zeile zu Ihrer Gradle-Datei hinzu:

compile 'com.github.bumptech.glide:glide:3.7.0'

Und es wird so einfach wie:

String filePath = "/storage/emulated/0/Pictures/example_video.mp4";

Glide  
    .with( context )
    .load( Uri.fromFile( new File( filePath ) ) )
    .into( imageViewGifAsBitmap );

Weitere Informationen finden Sie hier: https://futurestud.io/blog/glide-displaying-gifs-and-videos

Prost !

Edouard Brèthes
quelle
4
Glide funktioniert nur mit lokalen Videos, nicht mit URL-Videos. Es gibt keinen einfachen Weg dafür
Lutaaya Huzaifah Idris
6

Diese Lösung funktioniert für jede Android-Version. Es hat sich in 1.5 und 2.2 bewährt. Dies ist keine weitere "Dies ist für Android 2.0+" -Lösung. Ich habe dies über eine E-Mail-Message-Board-Sammlungsseite gefunden und kann den ursprünglichen Link nicht finden. Alle Gutschriften gehen an das Originalplakat.

In Ihrer App würden Sie dies verwenden, indem Sie Folgendes aufrufen:

Bitmap bm = getVideoFrame(VideoStringUri);

Irgendwo in seiner eigenen Funktion (außerhalb von OnCreate, ect) würden Sie Folgendes benötigen:

private Bitmap getVideoFrame(String uri) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
            retriever.setDataSource(uri);
            return retriever.captureFrame();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
            }
        }
        return null;
    }

In Ihrem src-Ordner benötigen Sie ein neues Unterverzeichnis android / media, in dem die Klasse (kopiert von der Android-Quelle selbst) gespeichert ist, mit der Sie diese Funktion verwenden können. Dieser Teil sollte nicht geändert, umbenannt oder an einer anderen Stelle platziert werden. MediaMetadataRetriever.java muss sich in Ihrem Quellordner unter android.media befinden, damit dies alles funktioniert.

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;

/**
 * MediaMetadataRetriever class provides a unified interface for retrieving
 * frame and meta data from an input media file. {@hide}
 */
public class MediaMetadataRetriever {
    static {
        System.loadLibrary("media_jni");
        native_init();
    }

    // The field below is accessed by native methods
    private int mNativeContext;

    public MediaMetadataRetriever() {
        native_setup();
    }

    /**
     * Call this method before setDataSource() so that the mode becomes
     * effective for subsequent operations. This method can be called only once
     * at the beginning if the intended mode of operation for a
     * MediaMetadataRetriever object remains the same for its whole lifetime,
     * and thus it is unnecessary to call this method each time setDataSource()
     * is called. If this is not never called (which is allowed), by default the
     * intended mode of operation is to both capture frame and retrieve meta
     * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). Often,
     * this may not be what one wants, since doing this has negative performance
     * impact on execution time of a call to setDataSource(), since both types
     * of operations may be time consuming.
     * 
     * @param mode
     *            The intended mode of operation. Can be any combination of
     *            MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: 1.
     *            MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: For neither
     *            frame capture nor meta data retrieval 2.
     *            MODE_GET_METADATA_ONLY: For meta data retrieval only 3.
     *            MODE_CAPTURE_FRAME_ONLY: For frame capture only 4.
     *            MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: For both
     *            frame capture and meta data retrieval
     */
    public native void setMode(int mode);

    /**
     * @return the current mode of operation. A negative return value indicates
     *         some runtime error has occurred.
     */
    public native int getMode();

    /**
     * Sets the data source (file pathname) to use. Call this method before the
     * rest of the methods in this class. This method may be time-consuming.
     * 
     * @param path
     *            The path of the input media file.
     * @throws IllegalArgumentException
     *             If the path is invalid.
     */
    public native void setDataSource(String path)
            throws IllegalArgumentException;

    /**
     * Sets the data source (FileDescriptor) to use. It is the caller's
     * responsibility to close the file descriptor. It is safe to do so as soon
     * as this call returns. Call this method before the rest of the methods in
     * this class. This method may be time-consuming.
     * 
     * @param fd
     *            the FileDescriptor for the file you want to play
     * @param offset
     *            the offset into the file where the data to be played starts,
     *            in bytes. It must be non-negative
     * @param length
     *            the length in bytes of the data to be played. It must be
     *            non-negative.
     * @throws IllegalArgumentException
     *             if the arguments are invalid
     */
    public native void setDataSource(FileDescriptor fd, long offset, long length)
            throws IllegalArgumentException;

    /**
     * Sets the data source (FileDescriptor) to use. It is the caller's
     * responsibility to close the file descriptor. It is safe to do so as soon
     * as this call returns. Call this method before the rest of the methods in
     * this class. This method may be time-consuming.
     * 
     * @param fd
     *            the FileDescriptor for the file you want to play
     * @throws IllegalArgumentException
     *             if the FileDescriptor is invalid
     */
    public void setDataSource(FileDescriptor fd)
            throws IllegalArgumentException {
        // intentionally less than LONG_MAX
        setDataSource(fd, 0, 0x7ffffffffffffffL);
    }

    /**
     * Sets the data source as a content Uri. Call this method before the rest
     * of the methods in this class. This method may be time-consuming.
     * 
     * @param context
     *            the Context to use when resolving the Uri
     * @param uri
     *            the Content URI of the data you want to play
     * @throws IllegalArgumentException
     *             if the Uri is invalid
     * @throws SecurityException
     *             if the Uri cannot be used due to lack of permission.
     */
    public void setDataSource(Context context, Uri uri)
            throws IllegalArgumentException, SecurityException {
        if (uri == null) {
            throw new IllegalArgumentException();
        }

        String scheme = uri.getScheme();
        if (scheme == null || scheme.equals("file")) {
            setDataSource(uri.getPath());
            return;
        }

        AssetFileDescriptor fd = null;
        try {
            ContentResolver resolver = context.getContentResolver();
            try {
                fd = resolver.openAssetFileDescriptor(uri, "r");
            } catch (FileNotFoundException e) {
                throw new IllegalArgumentException();
            }
            if (fd == null) {
                throw new IllegalArgumentException();
            }
            FileDescriptor descriptor = fd.getFileDescriptor();
            if (!descriptor.valid()) {
                throw new IllegalArgumentException();
            }
            // Note: using getDeclaredLength so that our behavior is the same
            // as previous versions when the content provider is returning
            // a full file.
            if (fd.getDeclaredLength() < 0) {
                setDataSource(descriptor);
            } else {
                setDataSource(descriptor, fd.getStartOffset(),
                        fd.getDeclaredLength());
            }
            return;
        } catch (SecurityException ex) {
        } finally {
            try {
                if (fd != null) {
                    fd.close();
                }
            } catch (IOException ioEx) {
            }
        }
        setDataSource(uri.toString());
    }

    /**
     * Call this method after setDataSource(). This method retrieves the meta
     * data value associated with the keyCode.
     * 
     * The keyCode currently supported is listed below as METADATA_XXX
     * constants. With any other value, it returns a null pointer.
     * 
     * @param keyCode
     *            One of the constants listed below at the end of the class.
     * @return The meta data value associate with the given keyCode on success;
     *         null on failure.
     */
    public native String extractMetadata(int keyCode);

    /**
     * Call this method after setDataSource(). This method finds a
     * representative frame if successful and returns it as a bitmap. This is
     * useful for generating a thumbnail for an input media source.
     * 
     * @return A Bitmap containing a representative video frame, which can be
     *         null, if such a frame cannot be retrieved.
     */
    public native Bitmap captureFrame();

    /**
     * Call this method after setDataSource(). This method finds the optional
     * graphic or album art associated (embedded or external url linked) the
     * related data source.
     * 
     * @return null if no such graphic is found.
     */
    public native byte[] extractAlbumArt();

    /**
     * Call it when one is done with the object. This method releases the memory
     * allocated internally.
     */
    public native void release();

    private native void native_setup();

    private static native void native_init();

    private native final void native_finalize();

    @Override
    protected void finalize() throws Throwable {
        try {
            native_finalize();
        } finally {
            super.finalize();
        }
    }

    public static final int MODE_GET_METADATA_ONLY = 0x01;
    public static final int MODE_CAPTURE_FRAME_ONLY = 0x02;

    /*
     * Do not change these values without updating their counterparts in
     * include/media/mediametadataretriever.h!
     */
    public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
    public static final int METADATA_KEY_ALBUM = 1;
    public static final int METADATA_KEY_ARTIST = 2;
    public static final int METADATA_KEY_AUTHOR = 3;
    public static final int METADATA_KEY_COMPOSER = 4;
    public static final int METADATA_KEY_DATE = 5;
    public static final int METADATA_KEY_GENRE = 6;
    public static final int METADATA_KEY_TITLE = 7;
    public static final int METADATA_KEY_YEAR = 8;
    public static final int METADATA_KEY_DURATION = 9;
    public static final int METADATA_KEY_NUM_TRACKS = 10;
    public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11;
    public static final int METADATA_KEY_CODEC = 12;
    public static final int METADATA_KEY_RATING = 13;
    public static final int METADATA_KEY_COMMENT = 14;
    public static final int METADATA_KEY_COPYRIGHT = 15;
    public static final int METADATA_KEY_BIT_RATE = 16;
    public static final int METADATA_KEY_FRAME_RATE = 17;
    public static final int METADATA_KEY_VIDEO_FORMAT = 18;
    public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
    public static final int METADATA_KEY_VIDEO_WIDTH = 20;
    public static final int METADATA_KEY_WRITER = 21;
    public static final int METADATA_KEY_MIMETYPE = 22;
    public static final int METADATA_KEY_DISCNUMBER = 23;
    public static final int METADATA_KEY_ALBUMARTIST = 24;
    // Add more here...
}
Verlassener Wagen
quelle
Dies funktioniert bei mir nicht. Fehler bei System.loadLibrary ("media_jni");
DArkO
1
Ich kann bestätigen, dass dies nicht funktioniert. Ich brauchte diese Fähigkeit auch. Es funktioniert nicht, da native Systemaufrufe verwendet werden, für deren Verwendung eine reguläre Anwendung keine Berechtigungen hat.
Andy
MediaMetadataRetrieverwird von API Level 10
Asahi
Der MediaMetadataRetriever ist der zweite Codeblock. Es ist vorhanden, APIs vor 10 (die zum Zeitpunkt des Schreibens noch nicht verfügbar waren) den Zugriff auf den Code aus der Anwendung anstelle des Systems zu ermöglichen. Native Systemaufrufe sind möglich, Sie benötigen jedoch ein grobes Verständnis des Systems, um sie verwenden zu können. Es hört sich so an, als ob ein Großteil des Problems darin besteht, die bereitgestellte Quelle nicht ordnungsgemäß zu implementieren.
Verlassener Wagen
@LoungeKatt ist es möglich, dass mehrere Bilder desselben Videos mehrmals aufgenommen werden?
Android-Entwickler
6

Versuchen Sie das, es funktioniert für mich

RequestOptions requestOptions = new RequestOptions();
 Glide.with(getContext())
      .load("video_url")
      .apply(requestOptions)
      .thumbnail(Glide.with(getContext()).load("video_url"))
      .into("yourimageview");
Karan Brahmaxatriya
quelle
5

Android 1.5 und 1.6 bieten diese Miniaturansichten nicht an, 2.0 jedoch, wie aus den offiziellen Versionshinweisen hervorgeht :

Medien

  • MediaScanner generiert jetzt Miniaturansichten für alle Bilder, wenn diese in MediaStore eingefügt werden.
  • Neue Thumbnail-API zum Abrufen von Bild- und Video-Thumbnails bei Bedarf.
Marc Climent
quelle
1

Ich beantworte diese Frage zu spät, hoffe aber, dass sie dem anderen Kandidaten hilft, der vor dem gleichen Problem steht.

Ich habe zwei Methoden verwendet, um Miniaturansichten für die Videoliste zu laden. Die erste war

    Bitmap bmThumbnail;
    bmThumbnail = ThumbnailUtils.createVideoThumbnail(FILE_PATH
                    + videoList.get(position),
            MediaStore.Video.Thumbnails.MINI_KIND);

    if (bmThumbnail != null) {
        Log.d("VideoAdapter","video thumbnail found");
        holder.imgVideo.setImageBitmap(bmThumbnail);
    } else {
        Log.d("VideoAdapter","video thumbnail not found");
    }

Es sieht gut aus, aber es gab ein Problem mit dieser Lösung, da es beim Scrollen der Videoliste aufgrund seiner großen Verarbeitung einige Zeit einfriert.

Danach habe ich eine andere Lösung gefunden, die mit Glide Library perfekt funktioniert.

 Glide
            .with( mContext )
            .load( Uri.fromFile( new File( FILE_PATH+videoList.get(position) ) ) )
            .into( holder.imgVideo );

Ich habe die spätere Lösung zum Anzeigen von Miniaturansichten mit Videoliste empfohlen. Vielen Dank

Mudassir Khan
quelle
-4

Dies ist der Code für Live-Video-Miniaturansichten.

public class LoadVideoThumbnail extends AsyncTask<Object, Object, Bitmap>{

        @Override
        protected Bitmap doInBackground(Object... params) {try {

            String mMediaPath = "http://commonsware.com/misc/test2.3gp";
            Log.e("TEST Chirag","<< thumbnail doInBackground"+ mMediaPath);
            FileOutputStream out;
            File land=new File(Environment.getExternalStorageDirectory().getAbsoluteFile()
                            +"/portland.jpg");

                Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                        byte[] byteArray = stream.toByteArray();

                        out=new  FileOutputStream(land.getPath());
                        out.write(byteArray);
                        out.close();
                 return bitmap;

            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        return null;
            }
        @Override
        protected void onPostExecute(Bitmap result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            if(result != null){
                 ((ImageView)findViewById(R.id.imageView1)).setImageBitmap(result);
            }
            Log.e("TEST Chirag","====> End");
        }

    }
Chirag
quelle
2
Ich bekomme null bei Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);Beachten Sie, dass alle Parameter gesetzt sind
Chulo
1
Nullwert bei Bitmap bitmap = ThumbnailUtils.createVideoThumbnail (mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
Prasad