android 获取视频的某一帧画面——MediaMetadataRetriever简单封装

需求:日常开发中我们经常需要视频的开始画面或者最后结束画面

实际开发中我在做视频连续播放的时候,视频播放间隔会出现加载间隙,我想让播放画面的最后一帧一直保持,直到下个视频加在完毕开始播放,这里需要获取视频最后一帧画面,产生了这样的需求,查了下资料,做了获取帧画面的简单封装

直接上源码:

import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;
import android.support.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.HashMap;

public class MediaDecoder {
    public interface OnMediaDecoderListener {
        void onDecodeFrame(Bitmap bitmap);
    }

    private static Reference<MediaDecoder> mediaDecoder;
    private static Reference<MediaMetadataRetriever> retriever;
    private OnMediaDecoderListener listener;
    private int type;
    private int flag;
    public final static int TYPE_VIDEO_LOCAL = 0x001;
    public final static int TYPE_VIDEO_NET = 0x002;
    public final static int VIDEO_START = 0x001;
    public final static int VIDEO_CUSTOM = 0x002;
    public final static int VIDEO_END = 0x003;

    @IntDef({TYPE_VIDEO_LOCAL, TYPE_VIDEO_NET})
    @Retention(RetentionPolicy.SOURCE)
    private @interface MediaDecoderType {

    }

    @IntDef({VIDEO_START, VIDEO_CUSTOM, VIDEO_END})
    @Retention(RetentionPolicy.SOURCE)
    private @interface MediaDecoderTime {

    }

    private static MediaDecoder getMediaDecoder() {
        if (!checkNotNull()) {
            mediaDecoder = new WeakReference<>(new MediaDecoder());
        }
        return mediaDecoder.get();
    }

    public static MediaDecoder create() {
        return getMediaDecoder();
    }

    public MediaDecoder setType(@MediaDecoderType int mediaType) {
        type = mediaType;
        return getMediaDecoder();
    }

    public MediaDecoder setListener(OnMediaDecoderListener onMediaDecoderListener) {
        mediaDecoder.get().listener = onMediaDecoderListener;
        return getMediaDecoder();
    }

    public MediaDecoder setDataSource(String path) {
        retriever = new WeakReference<>(new MediaMetadataRetriever());
        switch (type) {
            case TYPE_VIDEO_LOCAL: {
                retriever.get().setDataSource(path);
            }
            break;
            case TYPE_VIDEO_NET: {
                retriever.get().setDataSource(path, new HashMap<String, String>());
            }
            break;
        }
        return getMediaDecoder();
    }


    /**
     * @param flag 只有flag为VIDEO_CUSTOM时候需要传time
     * @param time 单位为毫秒
     */
    public void start(@MediaDecoderTime int flag, int... time) {
        this.flag = flag;
        new Thread(new GetFrameThread(time)).start();
    }

    private static boolean checkNotNull() {
        return (mediaDecoder != null && mediaDecoder.get() != null);
    }

    class GetFrameThread implements Runnable {

        private int time;

        GetFrameThread(int... time) {
            switch (flag) {
                case VIDEO_CUSTOM: {
                    if (time.length == 0) {
                        flag = VIDEO_START;
                    } else {
                        this.time = time[0];
                    }
                }
                break;
            }
        }

        @Override
        public void run() {
            Bitmap bitmap;
            try {
                //获得第一帧图片
                switch (flag) {
                    case VIDEO_END: {
                        String duration = retriever.get().extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                        time = Integer.parseInt(duration);
                    }
                    case VIDEO_CUSTOM: {
                        //getFrameAtTime(单位为微秒)
                        bitmap = retriever.get().getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
                    }
                    break;
                    default: {
                        bitmap = retriever.get().getFrameAtTime();
                    }
                    break;
                }
                if (listener != null) {
                    listener.onDecodeFrame(bitmap);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } finally {
                if (retriever != null && retriever.get() != null) retriever.get().release();
            }
        }
    }
}

使用示例(获取最后一帧画面):

MediaDecoder.create()
                .setType(MediaDecoder.TYPE_VIDEO_NET)
                .setDataSource(url)
                .setListener(new MediaDecoder.OnMediaDecoderListener() {
                    @Override
                    public void onDecodeFrame(Bitmap bitmap) {
                    }
                }).start(MediaDecoder.VIDEO_END);

setType为设置视频类型,暂时为两种:网络视频、本地视频

setDataSource为设置路径:网路视频为网络Url;本地视频为存储file路径

start为设置帧位置:VIDEO_START为第一帧,VIDEO_END为最后一帧,自定义为VIDEO_CUSTOM,并且传入需要截取帧的毫秒位置(start(MediaDecoder.VIDEO_CUSTOM,5*1000))

猜你喜欢

转载自blog.csdn.net/yao11965w1616/article/details/81016017
今日推荐