Android: Apakah mungkin untuk menampilkan thumbnail video?

94

Saya membuat aplikasi perekaman video dengan dialog perpustakaan. Dialog perpustakaan menampilkan daftar video yang direkam di mana setiap item terdiri dari ikon, judul video, tag dan informasi lokasi dengan cara berikut:

teks alt

Apakah ada yang tahu apakah mungkin mengganti ikon dengan thumbnail video (pratinjau bingkai tunggal)?

Terima kasih!

Niko Gamulin
sumber
Salah satu jawaban untuk ini [ stackoverflow.com/questions/16190374/…
Sederhanakan

Jawaban:

71

Jika Anda menggunakan API 2.0 atau yang lebih baru, ini akan berfungsi.

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
sumber
9
Jadi apa sebenarnya itu id?
phunehehe
1
Anda dapat menanyakan MediaStore untuk Video di telepon. "Id" hanyalah salah satu bagian dari informasi yang Anda minta. Lihat lebih lanjut tentang MediaStore di developer.android.com/reference/android/provider/…
Greg Zimmers
4
Terkejut semua orang tampaknya mendapatkan ini bekerja. Saya mencoba ini tetapi curThumb akhirnya menjadi null.
BlueVoodoo
7
Bagaimana jika video dari URL?
jayellos
tolong jawab ini [ stackoverflow.com/questions/16190374/…
Sederhanakan
92

jika Anda tidak atau tidak dapat melalui kursor dan jika Anda hanya memiliki jalur atau objek File, Anda dapat menggunakan sejak API level 8 (2.2) public static Bitmap createVideoThumbnail (String filePath, int kind)

Dokumentasi Android

Kode berikut berjalan dengan sempurna:

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
Damien Praca
sumber
7
ketika saya mencoba membuat thumbnail saya mendapatkan null. Saya pikir jalan saya mungkin tidak baik? myPath = "/ external / video / media / 14180"
haythem souissi
Ini bekerja seperti sihir. Bahkan ketika saya tidak menggunakan t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND`
Sami Eltamawy
Aneh itu tidak berfungsi juga ;-( videonya ada di DB, saya dapat mengambil nama / ukurannya, tetapi bukan thumbnail
Thomas Decaux
haythem souussi karena ini bukan jalur, ini Uri, Anda perlu mengubahnya menjadi jalur.
Nadir Novruzov
Ini berfungsi tetapi mengembalikan gambar dari bagian video yang salah. Saya ingin frame pertama tetapi mendapatkan 5-6 detik? Ada ide?
speedynomads
39

Menggunakan kelas:

import android.provider.MediaStore.Video.Thumbnails;

Kita bisa mendapatkan dua ukuran thumbnail pratinjau dari video:

Thumbnails.MICRO_KIND untuk 96 x 96

Thumbnails.MINI_KIND untuk 512 x 384 piksel

Ini adalah contoh kode:

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
sumber
Jika saya memiliki tautan seperti itu untuk jalur file apakah ini tidak akan berfungsi, karena saya mencoba menyetelnya ke tampilan gambar dan tidak menunjukkan apa-apa ... ini adalah jalur file "http: / /unknown.com/v3- 1aox9d1 .mp4 "jelas merupakan domain nyata, tetapi apakah jalur itu tidak dapat digunakan untuk thumbnail?
Lion789
Untuk menggunakan kelas ThumbnailUtils, Anda harus menyimpan file ke disk menggunakan metode: ThumbnailUtils.createVideoThumbnail ()
Jorgesys
Terima kasih, bagaimana cara mendapatkan jalur file baru untuk jempol buat?
Lion789
Mengapa Dosis Tidak Berfungsi Di Android 4 Dan Di Atas?
Criss
1
Hai Cris, Saya memiliki 3 perangkat 4.1 4.2.2 dan 5.0 dan berfungsi tanpa masalah, kirim pertanyaan dengan masalah Anda dan beberapa kode, dan saya dapat membantu Anda.
Jorgesys
22

Saat ini saya menggunakan kode berikut:

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

Tetapi saya menemukan solusi yang lebih baik dengan pustaka Glide dengan kode berikut (Ini juga menyimpan gambar Anda dan memiliki kinerja yang lebih baik daripada pendekatan sebelumnya)

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

Saya sangat menyarankan Anda untuk menggunakan perpustakaan Glide . Ini salah satu cara paling efisien untuk menghasilkan dan menampilkan thumbnail video untuk file video lokal.

Cukup tambahkan baris ini ke file gradle Anda:

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

Dan itu akan menjadi sesederhana:

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

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

Anda dapat menemukan informasi lebih lanjut di sini: https://futurestud.io/blog/glide-displaying-gifs-and-videos

Bersulang !

Edouard Brèthes
sumber
4
Glide hanya berfungsi dengan video lokal, bukan video Url, bukankah ada cara sederhana untuk ini
Lutaaya Huzaifah Idris
Beberapa perangkat tidak menampilkan gambar thumbnail untuk video lokal
Sathish Gadde
7

Coba ini berhasil untuk saya

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

Solusi ini akan berfungsi untuk semua versi Android. Ini telah terbukti bekerja di 1.5 dan 2.2. Ini bukan solusi lain "Ini untuk Android 2.0+". Saya menemukan ini melalui halaman koleksi papan pesan email dan tidak dapat menemukan tautan aslinya. Semua kredit diberikan ke pengirim asli.

Di aplikasi Anda, Anda akan menggunakan ini dengan memanggil:

Bitmap bm = getVideoFrame(VideoStringUri);

Di suatu tempat di fungsinya sendiri (di luar OnCreate, dll), Anda akan membutuhkan:

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

Di folder src Anda, Anda memerlukan subdirektori android / media baru yang akan menampung kelas (disalin dari sumber android itu sendiri) yang memungkinkan Anda menggunakan fungsi ini. Bagian ini tidak boleh diubah, diganti namanya, atau ditempatkan di tempat lain. MediaMetadataRetriever.java harus berada di bawah android.media di folder sumber Anda agar semua ini berfungsi.

/*
 * 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...
}
Keranjang Terbengkalai
sumber
Ini tidak berhasil untuk saya .. kesalahan di System.loadLibrary ("media_jni");
DArkO
1
Saya dapat mengonfirmasi bahwa ini tidak berhasil. Saya membutuhkan kemampuan ini juga. Ini tidak akan berfungsi karena menggunakan panggilan sistem asli yang tidak diizinkan oleh aplikasi biasa.
Andy
MediaMetadataRetrieverdidukung dari API level 10
Asahi
MediaMetadataRetriever adalah blok kode kedua. Itu ada untuk mengizinkan API sebelum 10 (yang tidak tersedia pada saat penulisan) untuk mengakses kode dari aplikasi dan bukan dari sistem. Panggilan sistem asli dimungkinkan, tetapi Anda memerlukan pemahaman kasar tentang sistem untuk menggunakannya. Sepertinya banyak masalah yang tidak menerapkan sumber yang disediakan dengan benar.
Keranjang Terbengkalai
@LoungeKatt mungkinkah membiarkannya menangkap banyak gambar dari video yang sama dari beberapa kali?
Pengembang android
5

Android 1.5 dan 1.6 tidak menawarkan thumbnail ini, tetapi 2.0, seperti yang terlihat pada catatan rilis resmi :

Media

  • MediaScanner sekarang membuat thumbnail untuk semua gambar saat dimasukkan ke MediaStore.
  • Thumbnail API baru untuk mengambil thumbnail gambar dan video sesuai permintaan.
Marc Climent
sumber
3

Saya terlambat menjawab pertanyaan ini tetapi berharap ini akan membantu kandidat lain yang menghadapi masalah yang sama.

Saya telah menggunakan dua metode untuk memuat thumbnail untuk daftar video yang pertama adalah

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

itu terlihat bagus tetapi ada masalah dengan solusi ini karena ketika saya menggulir daftar video itu akan membeku beberapa saat karena pemrosesannya yang besar.

jadi setelah ini saya menemukan solusi lain yang bekerja sempurna dengan menggunakan Glide Library.

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

Saya merekomendasikan solusi selanjutnya untuk menampilkan thumbnail dengan daftar video. Terima kasih

Mudassir Khan
sumber
-4

Ini adalah kode untuk thumbnail Video langsung.

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
sumber
2
saya mendapatkan null di Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);Perhatikan bahwa semua
parameter
1
nilai null di Bitmap bitmap = ThumbnailUtils.createVideoThumbnail (mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
Prasad