查看: 145|回复: 1

HarmonyOS 6.1 Media Kit:批量提取视频缩略图与HDR转码实战

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
在HarmonyOS 6.1(API 23)中,Media Kit迎来了两项重磅更新:视频缩略图的批量提取和HDR视频到SDR的智能转码。这些能力直接解决了移动端视频预览的卡顿问题和HDR内容兼容性痛点。本文基于实际开发经验,详解如何利用AVMetadataExtractor和AVTranscoder实现企业级视频预览服务。

### Media Kit核心能力回顾

Media Kit是HarmonyOS的媒体服务基座,包含七大核心组件。其中与视频预览最相关的是:

- AVMetadataExtractor:影音元数据提取器,能读取视频分辨率、时长、封面等信息。
- AVImageGenerator:视频截屏器,可从任意时间点截取单帧。
- AVTranscoder:格式转换器,在6.1中新增了HDR到SDR的转码能力。

在6.1之前,提取视频多帧缩略图需要循环调用fetchFrameByTime,每次重新寻道,效率极低。而HDR视频在普通屏幕上显示偏色的问题,也缺乏系统级解决方案。

### 批量提取:从单帧到多帧的质变

6.1新增的fetchFramesByTimes接口接受一个时间点数组(单位为微秒),一次性返回所有帧的PixelMap。更关键的是配套的cancelAllFetchFrames()接口,允许开发者在中止操作时瞬间释放资源。

实战中,建议将提取器封装为单例服务,避免重复创建实例导致FD泄漏。以下是一个ArkTS实现的核心逻辑:
  1. import { media } from '@kit.MediaKit';
  2. import { image } from '@kit.ImageKit';
  3. export class MediaService {
  4.   private static instance: MediaService;
  5.   private extractor: media.AVMetadataExtractor | null = null;
  6.   public static getInstance(): MediaService {
  7.     if (!MediaService.instance) {
  8.       MediaService.instance = new MediaService();
  9.     }
  10.     return MediaService.instance;
  11.   }
  12.   async batchFetchThumbnails(fd: number, timesUs: number[]): Promise<Array<image.PixelMap>> {
  13.     this.extractor = await media.createAVMetadataExtractor();
  14.     this.extractor.fdSrc = { fd: fd };
  15.     const queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_PREVIOUS_SYNC;
  16.     const param: media.PixelMapParams = { width: 320, height: 180 };
  17.     const results: Array<image.PixelMap> = [];
  18.     return new Promise((resolve, reject) => {
  19.       this.extractor?.fetchFramesByTimes(timesUs, queryOption, param, (frameInfo, err) => {
  20.         if (err) {
  21.           reject(err);
  22.           return;
  23.         }
  24.         if (frameInfo && frameInfo.image) {
  25.           results.push(frameInfo.image);
  26.           if (results.length === timesUs.length) {
  27.             resolve(results);
  28.           }
  29.         }
  30.       });
  31.     });
  32.   }
  33.   public async cancelTasks() {
  34.     if (this.extractor) {
  35.       await this.extractor.cancelAllFetchFrames();
  36.     }
  37.   }
  38.   public async release() {
  39.     if (this.extractor) {
  40.       await this.extractor.release();
  41.       this.extractor = null;
  42.     }
  43.   }
  44. }
复制代码

### UI层集成:瀑布流展示与用户交互

在页面中,使用Grid组件以两列瀑布流展示缩略图。点击“一键提取10帧预览”按钮时,模拟10个时间点(0到9秒,间隔1秒)调用批量接口。注意页面销毁前必须调用cancelTasks和release,防止资源泄漏。
  1. @Entry
  2. @Component
  3. struct MasterPreviewPage {
  4.   @State thumbnails: Array<image.PixelMap> = [];
  5.   private mediaService = MediaService.getInstance();
  6.   build() {
  7.     Column() {
  8.       Grid() {
  9.         ForEach(this.thumbnails, (item: image.PixelMap) => {
  10.           GridItem() {
  11.             Image(item).width('100%').height(150).borderRadius(12)
  12.           }
  13.         })
  14.       }
  15.       .columnsTemplate('1fr 1fr')
  16.       .gap(12)
  17.       .padding(16)
  18.       Button('一键提取 10 帧预览')
  19.         .onClick(async () => {
  20.           const times = [0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000];
  21.           const res = await this.mediaService.batchFetchThumbnails(testFd, times);
  22.           this.thumbnails = res;
  23.         })
  24.     }
  25.   }
  26.   aboutToDisappear() {
  27.     this.mediaService.cancelTasks();
  28.     this.mediaService.release();
  29.   }
  30. }
复制代码

实际测试表明,批量接口比循环单帧提取速度提升约40%,且不再出现白块闪烁。如果用户提前返回,cancelAllFetchFrames能瞬间中止后台任务,日志会打印“任务已成功取消”。

### HDR转码:打通全场景分享链路

AVTranscoder在6.1中支持将HDR VIVID、HLG、HDR10视频转换为SDR格式。转码时自动完成动态范围压缩和色彩映射,同时可设置输出分辨率(例如将4K降为1080P),极大节省存储和带宽。

关键注意事项:输出分辨率必须为偶数,否则硬件编码器会闪退。建议在代码中做对齐处理:width = width & ~1。

### 避坑指南:企业级开发的四个要点

1. **文件描述符独占协议**:不能同时让AVPlayer和AVMetadataExtractor使用同一个FD。正确做法是每次新开实例时都通过openSync获取新的FD。

2. **奇数分辨率闪退**:使用AVTranscoder设置输出尺寸时,强制宽高为偶数。

3. **内存风暴控制**:批量提取帧数建议控制在10-15帧以内,采用滚动加载分段请求,避免单次吐出上百个高清PixelMap触发OOM。

4. **取消任务的时差处理**:cancelAllFetchFrames调用后,可能仍会收到最后一帧回调。代码中应添加状态位,判断已取消则不再更新UI数组。

### 总结

HarmonyOS 6.1的Media Kit将视频缩略图提取从重复初始化的循环简化为一次数组调用,并提供了企业级的中止机制。HDR转码能力填补了全场景影像分享的最后一公里。开发者掌握这些接口的同时,更应理解背后的性能平衡——例如批量数量控制、FD独占原则、分辨率对齐等细节。这些实战经验才是打造流畅影音应用的关键。
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: HarmonyOS 6.1 Media Kit:批量提取视频缩略图与HDR转码实战

很实用的实战分享!批量提取缩略图那个 `fetchFramesByTimes` 接口确实解决了之前的痛点,单例封装也避免了重复创建导致的文件描述符泄漏,这个细节很关键。想追问一下:HDR 转 SDR 的部分你有没有实际跑过?在 HarmonyOS 6.1 上转码速度大概什么水平?另外,瀑布流展示如果视频时长很长(比如几十分钟),提取 10 帧间隔 1 秒感觉覆盖不太够,你有没有考虑过根据时长动态计算时间点来更好地预览?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-5 15:24 , Processed in 0.027422 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部