You need to enable JavaScript to run this app.
导航

雪碧图

最近更新时间2024.04.26 18:39:27

首次发布时间2024.04.26 18:39:27

点播 SDK 支持在拖拽进度条或执行 Seek 操作时,通过查看视频缩略图快速预览指定进度的视频内容。进度条缩略图预览功能基于视频雪碧图实现。雪碧图是由多帧截图拼接而成的一张大图,具有以下好处:

  • 图片体积小:将许多小图合并到一张大图中,可以减少图片文件的大小。

  • 请求次数少:通过图片整合,减少用户对服务器的请求次数,从而提高页面打开速度。

以下为一张雪碧图示例。该雪碧图中共包含 13 张缩略图。

基于上述雪碧图的进度条缩略图预览效果如下:

前提条件

获取雪碧图信息

通过 onFetchedVideoInfo 回调获取雪碧图信息 VideoThumbInfo。示例代码如下:

public boolean onFetchedVideoInfo(VideoModel model) {
    final List<VideoThumbInfo> thumbInfoList = videoModel.getThumbInfoList();
    if (thumbInfoList != null && thumbInfoList.size() > 0) {
        // 使用 index 为 0 的 VideoThumbInfo 即可。
        VideoThumbInfo info = thumbInfoList.get(0);
    }
}

以下为 VideoThumbInfo 示例。详细参数说明请见 ThumbInfoList

// 本示例中视频时长 270 秒。Interval 为 10,表示每 10 秒截取一张缩略小图,一共截取 27 张,由 CaptureNum 表示。
// 每张雪碧大图包含 5*5 = 25 张缩略小图,所以需要 2 张雪碧大图。
// 两张雪碧大图的 URL 可从 StoreUrls 参数中获取。
[{
        "CaptureNum": 27,
        "StoreUrls": ["http://vod-demo-cover.volccdn.com/tos-cn-v-c91ba9/622ceb0b7f5b41afadf0fd9eb7572971_1639039860~tplv-vod-noop.image", 
                      "http://vod-demo-cover.volccdn.com/tos-cn-v-c91ba9/26d92b1fdbc74599a713b1c3c2bc3824_1639039860~tplv-vod-noop.image"],
        "CellWidth": 242,
        "CellHeight": 136,
        "ImgXLen": 5,
        "ImgYLen": 5,
        "Interval": 10,
        "Format": "jpg"
}]

参考以下示例代码获取雪碧图参数的值:

// 缩略小图总个数。
int imgNum = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CAPTURE_NUM)
// 雪碧大图中每行包含的缩略小图数量。
int xLength = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_X_LEN);
// 雪碧大图中每列包含的缩略小图数量。
int yLength = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_Y_LEN);
// 每张缩略小图的宽,单位为 pixel。
int xSize = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CELL_WIDTH);
// 每张缩略小图的高,单位为 pixel。
int ySize = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CELL_HEIGHT);
// 雪碧大图格式。
int format = info.getValueStr(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_FORMAT);
// 雪碧大图 URL 列表。
List<String> urls = info.getUrls();
// 相邻缩略小图的时间间隔,单位为秒。
double interval = info.getValueDouble(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_INTERVAL);

获取并展示缩略图

参考以下示例代码获取并展示指定播放位置的缩略图:

// 1. 根据播放位置 postion 和雪碧图 Interval 计算出缩略小图在雪碧大图中的 index。
final int currentThumbIndex = getCurrentThumbIndex(mVideoThumbInfo, position);
// 2. 根据缩略小图的 index 和每张雪碧大图包含缩略小图的个数,计算出待展示的缩略小图在哪张雪碧大图中。
final int currentSpriteIndex = getSpriteIndex(mVideoThumbInfo, currentThumbIndex);
// 3. 下载对应的雪碧大图并缓存到磁盘。
downloadThumbs(mVideoThumbInfo, currentSpriteIndex);
// 4. 获取播放位置 postion 对应的缩略小图。
Bitmap bitmap = getThumbBitmap(context, mVideoThumbInfo, position);
// 5. 将 bitmap 展示到对应的控件即可。
final RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), bitmap);
drawable.setAntiAlias(true);
mImageView.setImageDrawable(drawable);

private static void downloadThumbs(VideoThumbInfo thumbInfo,  int  splitIndex)  {
    String url = thumbInfo.getUrls().get(splitIndex);
    // 缓存到磁盘的路径需自定义,以下仅为简单示例。
    String path = context.getCacheDir().getAbsolutePath() + "/thumb/" + md5(url) + ".jpg" ;
    File imageFile = new File(path);
    if (!imageFile.exists()) {
        // 下载雪碧图并存入本地。
    } else {
        // 已存在,无需重复下载。
    }
}

private int getCurrentThumbIndex(final VideoThumbInfo currentThumbInfo,
        final long position) {
    double interval = currentThumbInfo.getValueDouble(
            VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_INTERVAL);
    return (int) (position / 1000 / interval);
}

private int getSpriteIndex(final VideoThumbInfo currentThumbInfo,
        final long thumbIndex) {
    final int xLength = currentThumbInfo.getValueInt(
            VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_X_LEN);
    final int yLength = currentThumbInfo.getValueInt(
            VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_Y_LEN);
    return (int) (thumbIndex / (xLength * yLength));
}

public Bitmap getThumbBitmap(Context context, VideoThumbInfo info, int index) {
    if (context == null || info == null) {
        return null;
    }

    Rect rect = new Rect();
    int xLength = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_X_LEN);
    int yLength = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_IMG_Y_LEN);
    int xSize = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CELL_WIDTH);
    int ySize = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CELL_HEIGHT);
    int imgNum = info.getValueInt(VideoThumbInfo.VALUE_VIDEO_THUMB_INFO_CAPTURE_NUM);

    if (index >= imgNum) {
        index = imgNum - 1;
    }
    int spriteIndex = index / (xLength * yLength);
    // 缩略小图在雪碧大图中的 index
    index = index % (xLength * yLength);

    rect.left = (index % xLength) * xSize;
    rect.top = (index / xLength) * ySize;
    rect.right = rect.left + xSize;
    rect.bottom = rect.top + ySize;
    try {
        // 磁盘的路径需自定义,以下仅为简单示例。
        String url = info.getUrls().get(spriteIndex);
        String path = context.getCacheDir().getAbsolutePath() + "/thumb/" + md5(url) + ".jpg" ;
        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(path, false);
        Bitmap decodeBitmap = decoder.decodeRegion(rect, null);
        decoder.recycle();
        return decodeBitmap;
    } catch (Exception e) {
        Log.d(TAG, "getThumbBitmap Exception " + e);
    }
    return null;
}