Android:是不是可以显示视频缩略图?

Posted

技术标签:

【中文标题】Android:是不是可以显示视频缩略图?【英文标题】:Android: Is it possible to display video thumbnails?Android:是否可以显示视频缩略图? 【发布时间】:2010-11-23 00:15:47 【问题描述】:

我创建了一个带有库对话框的视频录制应用程序。库对话框显示录制的视频列表,其中每个项目由图标、视频标题、标签和位置信息组成,方式如下:

有谁知道是否可以用视频缩略图替换图标(单帧预览)?

谢谢!

【问题讨论】:

任何一个答案 [***.com/questions/16190374/… 【参考方案1】:

如果您没有或不能通过光标,并且您只有路径或文件对象,则可以从 API 级别 8 (2.2) 开始使用 public static Bitmap createVideoThumbnail(String filePath, int kind)

android documentation

以下代码运行完美:

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

【讨论】:

当我尝试创建缩略图时,我得到空值。我觉得我的路可能不太好? myPath ="/external/video/media/14180" 它就像魔术一样工作。即使我不t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND` 奇怪,它也不起作用 ;-( 视频存在于数据库中,我可以检索名称/大小,但不能检索缩略图 haythem souussi 因为这不是路径这是 Uri,您需要将其转换为路径。 'createVideoThumbnail(java.lang.String, int)' 已弃用【参考方案2】:

如果您使用的是 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);

【讨论】:

那么id到底是什么? 您可以在手机上的MediaStore中查询视频。 “id”只是您查询的信息之一。在developer.android.com/reference/android/provider/… 上查看有关 MediaStore 的更多信息 很惊讶每个人似乎都可以正常工作。我试过了,但 curThumb 最终为空。 如果来自 URL 的视频呢? 使用 Glide,真的很简单【参考方案3】:

使用类:

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

【讨论】:

如果我有这样的文件路径链接,这将不起作用,因为我正在尝试将其设置为图像视图并且它没有显示任何内容......这是文件路径“http: //unknown.com/v3-1aox9d1 .mp4" 显然是一个真实的域,但是那个路径不能缩略图吗? 要使用 ThumbnailUtils 类,您必须使用方法将文件保存到磁盘:ThumbnailUtils.createVideoThumbnail( ) 谢谢,我该如何获取创建拇指的新文件路径? 为什么 Dose 不能在 Android 4 及更高版本上运行? 嗨 Cris,我有 3 台设备 4.1 4.2.2 和 5.0,它可以正常工作,发布一个关于您的问题和一些代码的问题,我可以为您提供帮助。【参考方案4】:

我真的建议您使用 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

干杯!

【讨论】:

Glide 仅适用于本地视频,不适用于 Url 视频,没有简单的方法 部分设备不显示本地视频缩略图【参考方案5】:

目前我使用以下代码:

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

【讨论】:

【参考方案6】:

试试这个对我有用

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

【讨论】:

【参考方案7】:

此解决方案适用于任何版本的 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"); 中的错误; 我可以确认这不起作用。我也需要这种能力。它不会工作,因为它使用常规应用程序无权使用的本机系统调用。 MediaMetadataRetriever 从 API 级别 10 开始支持 MediaMetadataRetriever 是第二个代码块。它的存在是为了允许 10 之前的 API(在撰写本文时不可用)从应用程序而不是系统访问代码。本地系统调用是可能的,但您需要对系统有一个粗略的了解才能使用它们。听起来很多问题都在不正确地实现所提供的源代码。 @LoungeKatt 是否可以让它多次捕获同一视频的多个图像?【参考方案8】:

Android 1.5 和 1.6 不提供此缩略图,但 2.0 提供,如 the official release notes 所示:

媒体

MediaScanner 现在会在将所有图像插入 MediaStore 时为其生成缩略图。 新的 Thumbnail API 用于按需检索图像和视频缩略图。

【讨论】:

【参考方案9】:

我回答这个问题较晚,但希望它能帮助其他面临同样问题的候选人。

我使用了两种方法来加载视频列表的缩略图,第一种是

    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 Library 完美运行的解决方案。

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

我推荐后一种解决方案来显示带有视频列表的缩略图。 谢谢

【讨论】:

嗨@AllanRibas 很高兴听到这个解决方案对您有用。【参考方案10】:

这是实时视频缩略图的代码。

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

    

【讨论】:

我在Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND); 得到 null 请注意,所有参数都已设置 位图位图的空值 = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);

以上是关于Android:是不是可以显示视频缩略图?的主要内容,如果未能解决你的问题,请参考以下文章

Android - 从服务器检索视频的缩略图并显示在手机上

video html5:是不是可以在特定时间显示视频的缩略图?

ios获取本地视频第一帧,缩略图

是否可以从android中的视频网址生成缩略图

C#获取本地视频的缩略图的方法都有哪些?

从 YouTube API 中获得 YouTube 视频的缩略图