SPYOFF VPN

2017-07-19


思考: 视频播放时,拖拉进度条缩略图预览功能的实现?

下一篇内容将会进行 Android 上视频播放时实现进度缩略图预览功能的实现的演示。

上一节内容 FFmpeg 视频生成图片功能,我们留了一个思考问题。

这一节内容我们就来针对上面的思考问题讲解一下思路。

当我们公司 APP 上要实现这个功能时,我找了一下解决方案,大概有下面几种:

  • 使用 MediaMetadataRetriever.getFrameAtTime API (GitHub 有开源库实现方案,兼容性不好,获取图片时间长)
  • 使用一个静音的播放器来获取对应的进度缩略图 (GitHub 一样有开源库实现方案,这个直接放弃了,没什么好说的)
  • 使用多张小图合成大图方式,截取对应时间段小缩略图 (涉及 FFmpeg,Chrome 下调试 Bilibili Web 播放器视频进度缩略图就是这种方式实现)

当然选择上面的第三种方案去实现这个功能辣。

具体看看实现步骤:

  • 生成缩略图

    使用 FFmpeg 命令:

    ffmpeg -i https://www.zengzhihao.pw/videos/girl/index.m3u8 -vf scale=iw/4:-1,fps=1/3,tile index.webp
    

    其中生成的图是一张有着 21 张小图的大图,分为 3 行 6 列,每张小图大小为 200x150。

    index.webp 放到服务器上,链接为 https://www.zengzhihao.pw/images/girl/index.webp

  • 新建 Android Studio 工程

    使用的视频地址为 https://www.zengzhihao.pw/videos/girl/index.m3u8,其中使用 ExoPlayer 实现视频播放。

    初始化播放器代码片段:

    // init player
    RenderersFactory renderersFactory = new DefaultRenderersFactory(this);
    LoadControl loadControl = new DefaultLoadControl();
    TrackSelector trackSelector = new DefaultTrackSelector();
    player = ExoPlayerFactory.newSimpleInstance(renderersFactory,
            trackSelector, loadControl);
    
    // init media source
    CacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024);
    final Cache cache = new SimpleCache(new File(getExternalCacheDir(), "exo_cache"), evictor);
    HttpDataSource.Factory upstreamFactory = new DefaultHttpDataSourceFactory(
            Util.getUserAgent(this, getString(R.string.app_name)));
    CacheDataSourceFactory dataSourceFactory = new CacheDataSourceFactory(cache,
            upstreamFactory,
            CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
    MediaSource mediaSource = new HlsMediaSource(Uri.parse(VIDEO_URL), dataSourceFactory, null, null);
    
    // prepare to play
    player.prepare(mediaSource);
    playerView.setPlayer(player);
    

    获取具体帧图像代码片段:

    private static final int DEFAULT_THUMBNAIL_TIME_INTERVAL = 3;
    private static final int DEFAULT_THUMBNAIL_COLUMN_COUNT = 6;
    private static final int DEFAULT_THUMBNAIL_WIDTH = 200;
    private static final int DEFAULT_THUMBNAIL_HEIGHT = 150;
    
    private Bitmap getBitmapAtFrame(long timeMs) {
        if (thumbnailBitmap == null) {
            getThumbnailBitmap();
            return null;
        } else {
            long position = timeMs / DEFAULT_THUMBNAIL_TIME_INTERVAL;
            long x = position % DEFAULT_THUMBNAIL_COLUMN_COUNT * DEFAULT_THUMBNAIL_WIDTH;
            long y = position / DEFAULT_THUMBNAIL_COLUMN_COUNT * DEFAULT_THUMBNAIL_HEIGHT;
            Bitmap source = Bitmap.createBitmap(thumbnailBitmap,
                    (int) x, (int) y,
                    DEFAULT_THUMBNAIL_WIDTH, DEFAULT_THUMBNAIL_HEIGHT);
            Bitmap target = Bitmap.createScaledBitmap(source,
                    dpToPx(source.getWidth()), dpToPx(source.getHeight()), false);
            source.recycle();
            return target;
        }
    }
    
  • 源码

    工程源码放在 GitHub 上面,具体可以看看效果图。

    链接:ExoPlayerVideoThumbnails

    当然,这些只是简单的方案演示,具体还需要服务器端的配合。



温馨提醒

为了获得更好的阅读体验,您应该使用 Chrome 浏览器访问本站!


联系站长

Email: hi@zengzhihao.pw



VULTR