首页 文章

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

提问于
浏览
76

我用库对话框创建了一个视频录制应用程序 . 库对话框显示录制视频列表,其中每个项目包括图标,视频 Headers ,标签和位置信息,方式如下:

alt text

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

谢谢!

9 回答

  • 32

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

    如果你没有或不能通过游标,如果你只有路径或文件对象,你可以使用自API级别8(2.2)公共静态位图createVideoThumbnail(String filePath,int kind)

    Android documentation

    以下代码运行完美:

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

    使用课程:

    import android.provider.MediaStore.Video.Thumbnails;
    

    我们可以从视频中获得两个预览缩略图尺寸:

    缩略图.MICRO_KIND为96 x 96

    Thumbnails.MINI_KIND for 512 x 384 px

    这是一个代码示例:

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

    目前我使用以下代码:

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

    干杯!

  • 13

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

    Media MediaScanner现在可以在将所有图像插入MediaStore时为其生成缩略图 . 新的缩略图API,用于按需检索图像和视频缩略图 .

  • 0

    此解决方案适用于任何版本的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...
    }
    
  • 5

    我迟到了回答这个问题,但希望它能帮助其他候选人面临同样的问题 .

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

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

    我建议使用后面的解决方案来显示带视频列表的缩略图谢谢

  • 80

    This is code for live Video thumbnail.

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

相关问题