HarmonyOS鸿蒙Next中使用AVPlayer添加视频内封字幕怎么实现

HarmonyOS鸿蒙Next中使用AVPlayer添加视频内封字幕怎么实现 【问题描述】:我在使用avplayer播放视频,试了很多方法来挂载内封字幕,都没有成功,有没有文档或者什么案例?播放视频的时候,视频本身带有字幕文件,这个是内封字幕,如何获取到这个字幕文件并显示。
官网我只看到外挂字幕文件(外挂字幕文件是独立于视频的字幕文件)

【问题现象】:使用AVPlayer添加视频内封字幕怎么实现

9 回复

尊敬的开发者,您好!该功能正在规划中,还请关注后续版本,感谢您的理解与支持。

更多关于HarmonyOS鸿蒙Next中使用AVPlayer添加视频内封字幕怎么实现的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


截至目前,官方暂未提供 AVPlayer“直接读取并显示内封字幕”的现成方案,当前仅支持视频播放前设置外挂字幕。

如果你的片源是 mkv、mp4 这类带内封字幕的文件,通常要先把字幕轨抽出来,转成 srt 等外挂字幕文件,再通过 AVPlayer 挂载播放。

如果要做内封字幕,可以参考以下两条建议方案:

  1. 服务端或预处理阶段把内封字幕抽成 srt,比如用 ffmpeg 之类工具,先把视频里的字幕轨导出来,再在 HarmonyOS 端按外挂字幕方式接入;

  2. 自己接入第三方解封装能力,自己解析 mkv/mp4 容器,把字幕轨读出来,再按时间轴自己绘制字幕层,这条工作量会明显大很多,AVPlayer 本身不能替你把这件事做完。

【先转外挂字幕:注意需在资源目录src/main/resources/rawfile/自备test.mp4以及test.srt】示例代码:

import { media } from '@kit.MediaKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  @State subtitleText: string = '';
  private avPlayer: media.AVPlayer | null = null;
  private surfaceId: string = '';
  private xComponentController: XComponentController = new XComponentController();

  aboutToAppear() {
    this.initPlayer();
  }

  aboutToDisappear() {
    this.releasePlayer();
  }

  async initPlayer() {
    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    this.avPlayer = await media.createAVPlayer();

    this.avPlayer.on('stateChange', async (state: string) => {
      if (!this.avPlayer) {
        return;
      }
      switch (state) {
        case 'initialized':
          if (this.surfaceId) {
            this.avPlayer.surfaceId = this.surfaceId;
          }
          await this.avPlayer.prepare();
          break;
        case 'prepared':
          await this.avPlayer.play();
          break;
      }
    });

    this.avPlayer.on('subtitleUpdate', (info: media.SubtitleInfo) => {
      this.subtitleText = info?.text ? info.text : '';
    });

    this.avPlayer.on('error', (err: BusinessError) => {
      console.error('player error: ' + err.code + ', ' + err.message);
    });

    let videoFd = await context.resourceManager.getRawFd('test.mp4');
    this.avPlayer.fdSrc = {
      fd: videoFd.fd,
      offset: videoFd.offset,
      length: videoFd.length
    };

    let subtitleFd = await context.resourceManager.getRawFd('test.srt');
    await this.avPlayer.addSubtitleFromFd(subtitleFd.fd, subtitleFd.offset, subtitleFd.length);
  }

  onSurfaceReady() {
    this.surfaceId = this.xComponentController.getXComponentSurfaceId();
    if (this.avPlayer && this.surfaceId && this.avPlayer.state === 'initialized') {
      this.avPlayer.surfaceId = this.surfaceId;
    }
  }

  async releasePlayer() {
    if (this.avPlayer) {
      try {
        await this.avPlayer.release();
      } catch (e) {
      }
      this.avPlayer = null;
    }
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      XComponent({
        id: 'video_surface',
        type: 'surface',
        controller: this.xComponentController
      })
        .width('100%')
        .height(260)
        .onLoad(() => {
          this.onSurfaceReady();
        })

      Text(this.subtitleText)
        .fontSize(18)
        .fontColor(Color.White)
        .backgroundColor('#66000000')
        .padding(8)
        .margin({ bottom: 20, left: 12, right: 12 })
    }
    .width('100%')
  }
}

如果当前文档只给了外挂字幕能力,就不要默认 AVPlayer 能直接把容器里的内封字幕轨解析出来并暴露给业务层。内封字幕通常涉及封装格式、轨道选择、时间轴同步和字幕格式,播放器公开 API 没暴露时,业务侧很难直接控制。

工程上可以先走两条路:1. 在服务端或构建阶段把内封字幕抽取成 srt/vtt 等外挂字幕文件,再按外挂字幕方案加载;2. 如果必须端侧处理,先用媒体解析/解复用能力确认能否枚举字幕轨,不能枚举就只能做预处理。

也建议把“需要内封字幕轨选择/显示”的诉求单独反馈给 AVPlayer 文档或能力入口,这和普通外挂字幕不是同一个能力点。

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

目前 ArkUI / HarmonyOS 的 AVPlayer 暂不支持直接解析和显示视频内封字幕(内挂字幕)

官方目前公开能力主要是:

  • 播放视频音轨
  • 挂载外挂字幕(独立字幕文件,如 srt / vtt)
  • 基础轨道控制

但对于你说的这种 从视频容器(mp4 / mkv)里解析 embedded subtitle stream,并直接通过 AVPlayer 获取字幕轨道内容并渲染,当前没有公开 API,也没有官方示例支持。

所以目前有两个方案:

  1. 转成外挂字幕(推荐)
    提前把视频里的字幕轨提取成 .srt / .vtt,再通过 AVPlayer 字幕接口加载。

  2. 自己解析容器(成本高)
    自行解析视频封装格式,提取字幕流后再自定义渲染到页面。这个实现复杂,而且 AVPlayer 本身不给你直接拿内封字幕流。

也就是说:

现阶段 AVPlayer 不能像 VLC 那样直接读取并显示内挂字幕,官方只支持外挂字幕方案。

如果项目必须支持内封字幕,建议在服务端或预处理阶段统一转外挂字幕。

先区分“内封字幕”和“外挂字幕”。外挂字幕可以走 AddFdSubtitleSource/AddUrlSubtitleSource 这类能力;内封字幕则需要播放器先识别出媒体里的字幕轨道。

建议流程是:设置视频源并 prepare 后,获取媒体/轨道描述,确认是否存在 subtitle track;如果存在,再用 selectTrack(index) 选择对应字幕轨道,默认通常不会自动播放字幕轨。API23 的 native AVPlayer 还提供 GetTrackCount/GetTrackFormat、SelectTrack/DeselectTrack、PreferredSubtitleLanguage 等相关能力。

如果你现在只用 ArkTS AVPlayer 且拿不到轨道信息,可能需要走 Native AVPlayer 或先把字幕抽成外挂字幕文件再加载。还要注意容器格式和字幕编码是否在当前系统版本支持范围内。

关注一下

在HarmonyOS Next中,AVPlayer支持内封字幕。创建AVPlayer并设置媒体源后,调用getTrackInfo()获取轨道列表,筛选trackTypeSUBTITLE的轨道,再通过selectTrack(trackIndex)选中即可。播放时字幕自动同步渲染。

在HarmonyOS NEXT中,AVPlayer 本身支持解析视频内封字幕轨道,无需额外挂载字幕文件。关键步骤是通过 trackInfoUpdate 回调获取轨道列表,筛选出字幕轨道并调用 selectTrack 启用即可。

实现要点

  1. 创建 AVPlayer 并设置播放源。
  2. 监听 trackInfoUpdate 事件(API 11+ 可用),该事件在媒体信息解析完成后触发,返回当前媒体包含的所有轨道描述。
  3. 遍历轨道数组,根据 mimeTypetrackType 找到字幕轨道(通常为 text/vttapplication/x-subrip 等)。
  4. 调用 avPlayer.selectTrack(index) 选择对应字幕轨道,播放器会自动渲染字幕。

示例代码(关键部分)

import media from '@ohos.multimedia.media';

let avPlayer = await media.createAVPlayer();
avPlayer.url = 'fd://或http://...'; // 设置视频源

// 监听轨道信息
avPlayer.on('trackInfoUpdate', (tracks: Array<media.MediaDescription>) => {
  for (let i = 0; i < tracks.length; i++) {
    let track = tracks[i];
    // 检查是否为字幕轨道,常见 MIME:'text/vtt'、'application/x-subrip'
    if (track.mimeType && track.mimeType.startsWith('text/')) {
      console.info(`字幕轨道索引:${i}, 语言:${track.language}`);
      // 选择该字幕轨道
      avPlayer.selectTrack(i);
      break;
    }
  }
});

// 准备并播放
await avPlayer.prepare();
await avPlayer.play();

注意事项

  • 确保视频文件确实包含内封字幕(如 MKV、MP4 带 tx3g/CC 字幕)。
  • selectTrack 必须在 prepare() 之后调用才生效。
  • 部分设备可能需要系统版本 ≥ HarmonyOS NEXT Developer Beta1。
  • 如果仍无显示,可检查播放窗口是否正常叠加字幕层(通常 AVPlayer 自动处理,无需额外设置 XComponent)。

官网外挂字幕文档对应的是独立 .vtt/.srt 文件场景,而内封字幕只需上述轨道选择即可启用。

回到顶部