Android: est-il possible d'afficher des miniatures vidéo?

91

J'ai créé une application d'enregistrement vidéo avec un dialogue de bibliothèque. La boîte de dialogue de la bibliothèque affiche la liste des vidéos enregistrées où chaque élément se compose d'une icône, d'un titre vidéo, de balises et d'informations de localisation de la manière suivante:

texte alternatif

Quelqu'un sait-il s'il est possible de remplacer les icônes par des miniatures vidéo (aperçu d'une seule image)?

Merci!

Niko Gamulin
la source
Une seule réponse à cette [ stackoverflow.com/questions/16190374/…
Simplifiez-vous la vie

Réponses:

71

Si vous utilisez l'API 2.0 ou une version plus récente, cela fonctionnera.

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
la source
9
Alors, quel est exactement le id?
phunehehe
1
Vous pouvez interroger le MediaStore pour les vidéos sur le téléphone. L '"id" n'est qu'une des informations que vous interrogez. Pour en savoir plus sur le MediaStore, consultez developer.android.com/reference/android/provider/…
Greg Zimmers
4
Tout le monde surpris semble faire fonctionner cela. J'ai essayé ceci mais le curThumb finit par être nul.
BlueVoodoo
7
et si la vidéo à partir d'une URL?
jayellos
s'il vous plaît répondre à ceci [ stackoverflow.com/questions/16190374/…
Simplifiez-vous le
91

si vous ne pouvez pas ou ne pouvez pas passer par le curseur et si vous n'avez que des chemins ou des objets File, vous pouvez utiliser depuis le niveau API 8 (2.2) public static Bitmap createVideoThumbnail (String filePath, int kind)

Documentation Android

Le code suivant fonctionne parfaitement:

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
Damien Praca
la source
6
lorsque j'essaye de créer une miniature, j'obtiens une valeur nulle Je pense que mon chemin n'est peut-être pas ok? myPath = "/ external / video / media / 14180"
haythem souissi
Cela fonctionne comme par magie. Même quand je donne t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND`
Sami Eltamawy
Etrange ça ne marche pas aussi ;-( la vidéo existe dans la DB, je peux récupérer le nom / la taille, mais pas la vignette
Thomas Decaux
haythem souussi parce que ce n'est pas un chemin c'est Uri, vous devez le convertir en chemin.
Nadir Novruzov
Cela fonctionne mais renvoie une image de la mauvaise partie de la vidéo. Je veux la toute première image mais j'en ai 5-6 secondes? Des idées?
speedynomads
38

Utilisation de la classe:

import android.provider.MediaStore.Video.Thumbnails;

Nous pouvons obtenir deux tailles de vignettes d'aperçu à partir de la vidéo:

Thumbnails.MICRO_KIND pour 96 x 96

Thumbnails.MINI_KIND pour 512 x 384 px

Ceci est un exemple de code:

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
la source
Si j'ai un lien comme celui-ci pour le chemin du fichier, cela ne fonctionnerait pas, car j'essaie de le définir sur une vue d'image et qu'il ne montre rien ... c'est le chemin du fichier "http: / /unknown.com/v3- 1aox9d1 .mp4 "étant un vrai domaine de toute évidence, mais ce chemin ne peut-il pas être miniature?
Lion789
Pour utiliser la classe ThumbnailUtils, vous devez enregistrer le fichier sur le disque en utilisant la méthode: ThumbnailUtils.createVideoThumbnail ()
Jorgesys
Merci, comment puis-je obtenir le nouveau chemin de fichier pour le pouce de création?
Lion789 du
Pourquoi Dose ne fonctionne pas sur Android 4 et supérieur?
Criss
1
Salut Cris, j'ai 3 appareils 4.1 4.2.2 et 5.0 et cela fonctionne sans problème, postez une question avec votre problème et du code, et je pourrais vous aider.
Jorgesys
19

Actuellement, j'utilise le code suivant:

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

Mais j'ai trouvé une meilleure solution avec la bibliothèque Glide avec le code suivant (elle met également en cache votre image et a de meilleures performances que l'approche précédente)

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

Je vous suggère vraiment d'utiliser le Glide bibliothèque . C'est l'un des moyens les plus efficaces de générer et d'afficher une vignette vidéo pour un fichier vidéo local.

Ajoutez simplement cette ligne à votre fichier gradle:

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

Et cela deviendra aussi simple que:

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

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

Vous pouvez trouver plus d'informations ici: https://futurestud.io/blog/glide-displaying-gifs-and-videos

À votre santé !

Edouard Brèthes
la source
4
Glide ne fonctionne qu'avec des vidéos locales, pas des vidéos URL, il n'y a pas de moyen simple pour cela
Lutaaya Huzaifah Idris
6

Cette solution fonctionnera pour n'importe quelle version d'Android. Il a prouvé qu'il fonctionnait dans les versions 1.5 et 2.2. Ce n'est pas une autre solution "Ceci est pour Android 2.0+". J'ai trouvé cela via une page de collecte de babillards électroniques et je ne trouve pas le lien d'origine. Tout le mérite revient à l'affiche originale.

Dans votre application, vous utiliseriez ceci en appelant:

Bitmap bm = getVideoFrame(VideoStringUri);

Quelque part dans sa propre fonction (en dehors de OnCreate, ect), vous auriez besoin de:

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;
    }

Dans votre dossier src, vous avez besoin d'un nouveau sous-répertoire android / media qui hébergera la classe (copiée à partir de la source android elle-même) qui vous permettra d'utiliser cette fonction. Cette partie ne doit pas être modifiée, renommée ou placée ailleurs. MediaMetadataRetriever.java doit être sous android.media dans votre dossier source pour que tout cela fonctionne.

/*
 * 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...
}
Panier abandonné
la source
Cela ne fonctionne pas pour moi .. erreur sur System.loadLibrary ("media_jni");
DArkO
1
Je peux confirmer que cela ne fonctionne pas. J'avais également besoin de cette capacité. Cela ne fonctionnera pas car il utilise des appels système natifs qu'une application standard ne dispose pas des autorisations d'utilisation.
Andy
MediaMetadataRetrieverest pris en charge à partir du niveau d'API 10
Asahi
Le MediaMetadataRetriever est le deuxième bloc de code. Il est présent pour permettre aux API antérieures à 10 (qui n'était pas disponible au moment de la rédaction) d'accéder au code depuis l'application au lieu du système. Les appels système natifs sont possibles, mais vous aurez besoin d'une compréhension approximative du système pour les utiliser. Il semble qu'une grande partie du problème soit une implémentation incorrecte de la source fournie.
Panier abandonné
@LoungeKatt est-il possible de le laisser capturer plusieurs images de la même vidéo à plusieurs reprises?
développeur android
6

Essayez ça, ça marche pour moi

RequestOptions requestOptions = new RequestOptions();
 Glide.with(getContext())
      .load("video_url")
      .apply(requestOptions)
      .thumbnail(Glide.with(getContext()).load("video_url"))
      .into("yourimageview");
karan brahmaxatriya
la source
5

Android 1.5 et 1.6 n'offrent pas ces vignettes, mais 2.0, comme on le voit dans les notes de version officielles :

Médias

  • MediaScanner génère désormais des miniatures pour toutes les images lorsqu'elles sont insérées dans MediaStore.
  • Nouvelle API Thumbnail pour récupérer des vignettes d'images et de vidéos à la demande.
Marc Climent
la source
1

Je réponds tardivement à cette question mais j'espère que cela aidera l'autre candidat confronté au même problème.

J'ai utilisé deux méthodes pour charger la vignette de la liste des vidéos, la première était

    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");
    }

cela a l'air bien mais il y avait un problème avec cette solution car lorsque je fais défiler la liste de vidéos, elle gèlera un certain temps en raison de son traitement important.

donc après cela, j'ai trouvé une autre solution qui fonctionne parfaitement en utilisant Glide Library.

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

J'ai recommandé la solution la plus récente pour afficher la vignette avec la liste des vidéos. Merci

Mudassir Khan
la source
-4

Ceci est le code pour la vignette vidéo en direct.

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
la source
2
j'obtiens null à Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);Notez que tous les paramètres sont définis
Chulo
1
valeur nulle à Bitmap bitmap = ThumbnailUtils.createVideoThumbnail (mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
Prasad