Android: Можно ли отображать эскизы видео?

94

Я создал приложение для записи видео с диалогом библиотеки. В диалоговом окне библиотеки отображается список записанных видео, каждый элемент которого состоит из значка, названия видео, тегов и информации о местоположении следующим образом:

альтернативный текст

Кто-нибудь знает, можно ли заменить иконки на миниатюры видео (покадровый превью)?

Благодарность!

Нико Гамулин
источник
Любой ответ на этот вопрос [ stackoverflow.com/questions/16190374/…
Сделайте это

Ответы:

71

Если вы используете API 2.0 или новее, это сработает.

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);
Грег Циммерс
источник
9
Так что же такое id?
phunehehe
1
Вы можете запросить MediaStore для видео по телефону. «Идентификатор» - это всего лишь одна из частей информации, которую вы запрашиваете. Дополнительную информацию о
магазине MediaStore
4
Удивлен, что у всех это работает. Я пробовал это, но curThumb оказался нулевым.
BlueVoodoo 06
7
как насчет видео с URL?
jayellos
ответьте на это [ stackoverflow.com/questions/16190374/…
Сделайте это
92

если вы не используете или не можете пройти через курсор, и если у вас есть только пути или объекты File, вы можете использовать общедоступное статическое Bitmap уровня API 8 (2.2), начиная с уровня API 8 (2.2) createVideoThumbnail (String filePath, int kind)

Документация Android

Следующий код работает отлично:

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
Дэмиен Прака
источник
7
когда я пытаюсь создать эскиз, я получаю ноль. Я думаю, мой путь, может быть, не в порядке? myPath = "/ external / video / media / 14180"
haythem souissi
Это работает как по волшебству. Даже когда я использую t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND`
Сами Эльтамави
Странно, это тоже не работает ;-( видео существует в БД, я могу получить имя / размер, но не эскиз
Томас Деко
haythem souussi, потому что это не путь, это Ури, вам нужно преобразовать его в путь.
Надир Новрузов
Это работает, но возвращает изображение из неправильной части видео. Я хочу самый первый кадр, но получаю примерно 5-6 секунд? Любые идеи?
speedynomads
39

Используя класс:

import android.provider.MediaStore.Video.Thumbnails;

Из видео мы можем получить два размера миниатюр предварительного просмотра:

Thumbnails.MICRO_KIND для 96 x 96

Thumbnails.MINI_KIND для 512 x 384 пикселей

Это пример кода:

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
источник
Если у меня есть такая ссылка для пути к файлу, это не сработает, потому что я пытаюсь установить ее для просмотра изображения, и он ничего не показывает ... это путь к файлу "http: / / /unknown.com/v3- 1aox9d1 .mp4 ", очевидно, является реальным доменом, но не поддерживает ли этот путь эскизы?
Lion789
Чтобы использовать класс ThumbnailUtils, вы должны сохранить файл на диск, используя метод: ThumbnailUtils.createVideoThumbnail ()
Jorgesys
Спасибо, как мне тогда получить новый путь к файлу для большого пальца создания?
Lion789
Почему не работает на Android 4 и выше?
Крисс
1
Привет, Крис, у меня есть 3 устройства 4.1, 4.2.2 и 5.0, и они работают без проблем, задайте вопрос с вашей проблемой и некоторым кодом, и я могу вам помочь.
Jorgesys
22

В настоящее время я использую следующий код:

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

Но я нашел лучшее решение с библиотекой Glide со следующим кодом (он также кеширует ваше изображение и имеет лучшую производительность, чем предыдущий подход)

Glide.with(context)
                .load(uri)
                .placeholder(R.drawable.ic_video_place_holder)
                .into(imageView);
Амир
источник
20

Я действительно предлагаю вам использовать библиотеку Glide . Это один из наиболее эффективных способов создания и отображения эскизов видео для локального видеофайла.

Просто добавьте эту строку в свой файл gradle:

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

И станет так просто:

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

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

Вы можете найти дополнительную информацию здесь: https://futurestud.io/blog/glide-displaying-gifs-and-videos

Ура!

Эдуард Брет
источник
4
Glide работает только с локальными видео, а не с URL-видео, разве нет простого способа для этого
Лутая Хузайфа Идрис
На некоторых устройствах не отображаются миниатюры для локальных видео
Сатиш Гадде,
7

Попробуй, это работает для меня

RequestOptions requestOptions = new RequestOptions();
 Glide.with(getContext())
      .load("video_url")
      .apply(requestOptions)
      .thumbnail(Glide.with(getContext()).load("video_url"))
      .into("yourimageview");
каран брахмахатрия
источник
6

Это решение будет работать с любой версией Android. Доказано, что он работает в версиях 1.5 и 2.2. Это не еще одно решение «Это для Android 2.0+». Я нашел это на странице коллекции доски сообщений электронной почты и не могу найти исходную ссылку. Вся заслуга принадлежит оригинальному плакату.

В своем приложении вы можете использовать это, позвонив:

Bitmap bm = getVideoFrame(VideoStringUri);

Где-то в его собственной функции (вне OnCreate и т. Д.) Вам понадобятся:

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

В папке src вам понадобится новый подкаталог android / media, в котором будет размещен класс (скопированный из самого источника Android), который позволяет вам использовать эту функцию. Эту деталь нельзя изменять, переименовывать или размещать где-либо еще. MediaMetadataRetriever.java должен находиться в папке android.media в исходной папке, чтобы все это работало.

/*
 * 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...
}
Брошенная тележка
источник
У меня это не работает .. ошибка в System.loadLibrary ("media_jni");
DArkO
1
Могу подтвердить, что это не работает. Мне тоже была нужна эта возможность. Он не будет работать, потому что он использует собственные системные вызовы, которые обычное приложение не имеет разрешений на использование.
Энди
MediaMetadataRetrieverподдерживается с уровня API 10
Asahi
MediaMetadataRetriever - это второй блок кода. Он присутствует, чтобы позволить API до 10 (который был недоступен на момент написания) получать доступ к коду из приложения, а не из системы. Возможны собственные системные вызовы, но для их использования вам потребуется общее представление о системе. Похоже, что большая часть проблемы заключается в неправильной реализации предоставленного источника.
Брошенная тележка
@LoungeKatt, можно ли разрешить ему захватывать несколько изображений одного и того же видео несколько раз?
разработчик Android
5

Android 1.5 и 1.6 не предлагают эти эскизы, но 2.0, как видно из официальных примечаний к выпуску :

Средства массовой информации

  • MediaScanner теперь генерирует эскизы для всех изображений, когда они вставляются в MediaStore.
  • Новый API миниатюр для получения миниатюр изображений и видео по запросу.
Марк Климент
источник
3

Я отвечаю на этот вопрос поздно, но надеюсь, что это поможет другому кандидату, столкнувшемуся с той же проблемой.

Я использовал два метода для загрузки миниатюр для списка видео, первым из которых был

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

он выглядит хорошо, но с этим решением возникла проблема, потому что, когда я прокручиваю список видео, он на некоторое время зависает из-за большой обработки.

поэтому после этого я нашел другое решение, которое отлично работает с использованием библиотеки Glide.

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

Я рекомендовал более позднее решение для отображения эскизов со списком видео. Благодарность

Мудасир Хан
источник
-4

Это код для эскиза живого видео.

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

    }
Чираг
источник
2
я получаю null в Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);Обратите внимание, что все параметры установлены
Chulo
1
нулевое значение в Bitmap bitmap = ThumbnailUtils.createVideoThumbnail (mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
Прасад