diff --git a/code/BasicFeature/Media/AVCodec/.gitignore b/code/BasicFeature/Media/AVCodec/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..fbabf771011fe78f9919db0b1195ab6cadffc2b0
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/.gitignore
@@ -0,0 +1,11 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/AppScope/app.json5 b/code/BasicFeature/Media/AVCodec/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..1bafa013f53730b51b5d8d84a23666f8f916efff
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/AppScope/app.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "app": {
+ "bundleName": "com.samples.avcodecsample",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/code/BasicFeature/Media/AVCodec/AppScope/resources/base/element/string.json b/code/BasicFeature/Media/AVCodec/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8427310926f445f5313595f2990e44c6ced2af54
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "AVCodec"
+ }
+ ]
+}
diff --git a/code/BasicFeature/Media/AVCodec/AppScope/resources/base/media/app_icon.png b/code/BasicFeature/Media/AVCodec/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521
Binary files /dev/null and b/code/BasicFeature/Media/AVCodec/AppScope/resources/base/media/app_icon.png differ
diff --git a/code/BasicFeature/Media/AVCodec/README_zh.md b/code/BasicFeature/Media/AVCodec/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..72aaf01dcd79fed3c198ef132cd74cb4e4710866
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/README_zh.md
@@ -0,0 +1,568 @@
+# AVCodecSample
+
+### 介绍
+
+AVCodec 部件示例 Sample,基于 API12 构建,提供视频播放(含音频)和录制的功能。
+
+- 视频播放的主要流程是将视频文件通过解封装->解码->送显/播放。
+- 视频录制的主要流程是相机采集->编码->封装成mp4文件。
+
+### 播放支持的原子能力规格
+
+| 媒体格式 | 封装格式 | 码流格式 |
+|------|:-----------------|:-------------------------------------------------------------------------------------------------------------------------------------------------|
+| 视频 | mp4、mkv、mpeg-ts等 | 视频码流:
- 硬解:AVC(H.264)、HEVC(H.265)
- 软解:MPEG2、MPEG4、H.263、AVC(H.264)
音频码流:
AAC、MPEG(MP3)、Flac、Vorbis、AMR(amrnb、amrwb)、G711mu、APE |
+
+更多格式[参考](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/avcodec/avcodec-support-formats.md#avcodec%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F)
+
+### 录制支持的原子能力规格
+
+| 封装格式 | 视频编解码类型 |
+|------|-------------------------|
+| mp4 | HEVC(H.265)、 AVC(H.264) |
+
+注意,目前仅支持视频录制,未集成音频能力,更多格式[参考](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/avcodec/avcodec-support-formats.md#avcodec%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F)
+
+### 效果预览
+
+| 播放(模式选择) | 播放(选择播放路径) | 播放(横屏) | 播放(竖屏) |
+|-------------------------------------------|-----------------------------------------------|---------------------------------------|---------------------------------------|
+|  |  |  |  |
+
+| 播放(倍速) | 录制(选择相机分辨率) | 录制(开始录制) |
+|---------------------------------------|-------------------------------------------------|-------------------------------------------|
+|  |  |  |
+
+### 使用说明
+
+弹出是否允许“AVCodec”使用相机?点击“允许”
+
+- 推送视频到文件管理?
+ hdc file send xx.xx storage/media/100/local/files/Docs
+- 推送视频到图库?
+ hdc file send xx.mp4 storage/media/100/local/files
+ hdc shell mediatool send /storage/media/100/local/files/xx.mp4
+
+#### 播放
+
+1. 推送文件到本地(可单独音频、单独视频、视频含音频)或点击下方“录制”,录制一个视频文件(无音频)
+
+2. 点击播放按钮,选择从文件管理选取或从图库选取,点击确定,选择文件播放
+
+3. 播放过程中,可长按播放窗口2倍速播放,松开原速播放,或点击播放按钮,选择指定倍速播放
+
+#### 录制
+
+1. (可选)设置-配置相机参数
+
+2. 点击“录制”
+
+3. 点击“保存”
+
+4. 点击“开始录制”
+
+5. 点击“停止录制”
+
+### 目录
+
+仓目录结构如下:
+
+```
+video-codec-sample/entry/src/main/
+├── cpp # Native层
+│ ├── capbilities # 能力接口和实现
+│ │ ├── include # 能力接口
+│ │ ├── audio_decoder.cpp # 音频解码实现
+│ │ ├── demuxer.cpp # 解封装实现
+│ │ ├── muxer.cpp # 封装实现
+│ │ ├── video_decoder.cpp # 视频解码实现
+│ │ └── video_encoder.cpp # 视频编码实现
+│ ├── common # 公共模块
+│ │ ├── dfx # 日志
+│ │ ├── sample_callback.cpp # 编解码回调实现
+│ │ ├── sample_callback.h # 编解码回调定义
+│ │ └── sample_info.h # 功能实现公共类
+│ ├── render # 送显模块接口和实现
+│ │ ├── include # 送显模块接口
+│ │ ├── plugin_manager.cpp # 送显模块管理实现
+│ │ └── plugin_render.cpp # 送显逻辑实现
+│ ├── sample # Native层
+│ │ ├── player # Native层播放接口和实现
+│ │ │ ├── Player.cpp # Native层播放功能调用逻辑的实现
+│ │ │ ├── Player.h # Native层播放功能调用逻辑的接口
+│ │ │ ├── PlayerNative.cpp # Native层 播放的入口
+│ │ │ └── PlayerNative.h #
+│ │ └── recorder # Native层录制接口和实现
+│ │ ├── Recorder.cpp # Native层录制功能调用逻辑的实现
+│ │ ├── Recorder.h # Native层录制功能调用逻辑的接口
+│ │ ├── RecorderNative.cpp # Native层 录制的入口
+│ │ └── RecorderNative.h #
+│ ├── types # Native层暴露上来的接口
+│ │ ├── libplayer # 播放模块暴露给UI层的接口
+│ │ └── librecorder # 录制模块暴露给UI层的接口
+│ └── CMakeLists.txt # 编译入口
+├── ets # UI层
+│ ├── common # 公共模块
+│ │ └──utils # 共用的工具类
+│ │ ├── CameraCheck.ets # 相机能力查询
+│ │ ├── DateTimeUtils.ets # 获取当前时间
+│ │ └── Logger.ts # 日志工具
+│ ├── CommonConstants.ets # 参数常量
+│ ├── entryability # 应用的入口
+│ │ └── EntryAbility.ts # 申请权限弹窗实现
+│ ├── pages # EntryAbility 包含的页面
+│ │ └── Index.ets # 首页/播放页面
+│ └── sample # sample
+│ └── recorder # 录制
+│ └── Recorder.ets # 录制页面
+├── resources # 用于存放应用所用到的资源文件
+│ ├── base # 该目录下的资源文件会被赋予唯一的ID
+│ │ ├── element # 用于存放字体和颜色
+│ │ ├── media # 用于存放图片
+│ │ └── profile # 应用入口首页
+│ ├── en_US # 设备语言是美式英文时,优先匹配此目录下资源
+│ └── zh_CN # 设备语言是简体中文时,优先匹配此目录下资源
+└── module.json5 # 模块配置信息
+```
+
+### 具体实现
+
+#### *视频播放*
+
+- 应用启动,Xcomponent加载, 触发OnSurfaceCreatedCB(), 此时能拿到一个surface,同时调用OH_NativeWindow_NativeWindowSetScalingModeV2接口给window配置一个自适应等比例拉伸原图像尺寸的Key,后续无论播放横屏视频还是竖屏视频,都不用更改XComponent的尺寸。
+- 点击播放,选择文件后,能拿到文件fd,fileSize,根据拿到的fd和fileSize创建解封装器。
+- 根据解封装器从文件中拿到的文件属性,创建对应的解码器,若走解码器的Surface模式,则要把之前拿到的surface也配置给解码器。
+- 调用解码器Start,开始buffer轮转。buffer轮转时,由于buffer数量有上限,需要各个模块及时消费收到的buffer,否则会影响整体速度。
+- 解码器Start调用后,首先会触发4次输入回调,里面会给应用OH_AVBuffer和其对应的index。
+- 应用需要把待解码的码流,一帧帧填充到输入回调给到应用的OH_AVBuffer里的buffer地址里,然后调用OH_VideoDecoder_PushInputBuffer,传给解码器。
+ ```text
+ 本示例里使用的是解封装器一键填充配置,若码流直送解码器:
+ (1) 需要调用OH_AVBuffer_GetAddr获取OH_AVBuffer内buffer的内存地址,以进行之后的拷贝。
+ (2) 可以调用OH_AVBuffer_GetCapacity获取OH_AVBuffer内buffer容量大小,避免拷贝越界。
+ (3) 必须调用OH_AVBuffer_SetBufferAttr配置实际拷贝到OH_AVBuffer内buffer的实际size,按照规范,pts,offset,flags最好也配置对。
+ (4) 给解码器的输入,要保证以下三点,才能正常解码:
+ ①当前仅支持传入annexB格式帧,不支持avcc格式帧。
+ ②确保buffer size正确传入。
+ ③首帧要传XPS信息。(可以pps、sps和I帧同时传,也可以先传pps、sps,再传I帧)
+ 仅关键帧(I帧):AVCODEC_BUFFER_FLAGS_SYNC_FRAME
+ 仅配置帧(pps,sps):AVCODEC_BUFFER_FLAGS_CODEC_DATA
+ 是配置帧又是关键帧:AVCODEC_BUFFER_FLAGS_CODEC_DATA|AVCODEC_BUFFER_FLAGS_SYNC_FRAME
+ 普通帧(P帧):AVCODEC_BUFFER_FLAGS_NONE
+ ```
+- 待传给解码器解码完成后,会触发输出回调给应用。
+ - 若是Surface模式,则输出侧实际的buffer只会在框架、解码器、surface侧轮转,回调给应用的OH_AVBuffer只是个壳子,里面会带一些flag,size等信息,以及应用在输入时配置的pts信息,但由于实际的buffer不会随着OH_AVBuffer回调给用户,所以Surface模式下调用OH_AVBuffer_GetAddr拿不到buffer的地址,不能直接拷贝解码后的buffer数据,如果有这个需求,则需把surface配置成NativeImage的window,调用NativeImage的接口获取。
+ - 若是Buffer模式,实际的buffer会通过回调给到应用。由于buffer模式没法通过解码直接送显,本示例会将解码后的yuv/rgba图像dump到应用的沙箱目录/data/app/el2/100/base/com.samples.avcodecsample/haps/entry/files/haps/entry/files/下,应用可将此文件提取上来检验效果。
+ ```text
+ Surface里维护着一个surfaceBuffer队列,供生产者、消费者轮换使用,且生产者和消费者往往不在同一个进程。
+ - 生产者的逻辑:
+ · RequestBuffer:生产者获取一个空闲的、可以往里填数据的buffer,同时获取出这个buffer对应的releaseFence。当fence等到后,生产者可以往这块buffer里生产数据
+ · FlushBuffer:生产者生产完后,将该buffer以及该buffer对应的acquireFence送回给surface。
+ · CancelBuffer:生产者没有向该buffer里生产数据,仅做归还。
+ - 消费者的逻辑:
+ · AcquireBuffer: 消费者获取一个已生产好的buffer,同时获取出这个buffer对应的acquireFence。当fence等到后,消费者可以开始读取这块buffer里的内容。
+ · ReleaseBuffer:消费者消费完成后将buffer以及该buffer对应的releaseFence归还给surface。
+ ```
+- 应用收到解码后的OH_AVBuffer后,需要及时调用OH_VideoDecoder_FreeOutputBuffer或OH_VideoDecoder_RenderOutputBuffer或OH_VideoDecoder_RenderOutputBufferAtTime释放归还buffer。
+ ```text
+ 用RK3568设备播放,由于调用OH_NativeWindow_NativeWindowSetScalingModeV2接口后,实际未生效,最后显示画面可能会有拉伸,应用可以用另一种方法解决:
+ 在解封装拿到视频的宽高信息后,回调到UI层,UI层根据这个宽高,更改XComponet的尺寸,达到一样的效果,参考如下代码:
+ import display from '@ohos.display'
+ private display = display.getDefaultDisplaySync()
+ @State xcomponentHeight: number | string | Resource = 1
+ @State xcomponentWidth: number | string | Resource = 1
+
+ if (data.videoWidth / data.videoHeight > this.display.width / this.display.height) {
+ this.xcomponentHeight = (this.display.width * data.videoHeight / data.videoWidth) + 'px';
+ this.xcomponentWidth = this.display.width + 'px';
+ } else {
+ this.xcomponent = this.display.height + 'px';
+ this.xcompoentWidth = (this.display.height * data.videoWidth / data.videoHeight) + 'px'
+ }
+ ```
+
+
+##### Buffer轮转
+一、surface的buffer轮转
+
+轮转方最多有四个:
+- us : hcodec/框架自己
+- user : hcodec的调用者
+- omx : vendor编解码器
+
+surface: 在解码时,surface指消费者;编码时,surface指生产者
+
+以解码器surface模式的某个输出buffer为例:
+
+一开始是hcodec分配出来————owned by us
+
+然后给到vendor(即us->omx)————owned by omx
+
+vendor填好后还给hcodec(即omx->us)————owned by us
+
+hcodec给到应用(即us->user)————owned by user
+
+app等到音画同步后还给hcodec(即user->us)————owned by us
+
+hcodec flushBuffer给surface, 让消费者消费(即us->surface)————owned by surface
+
+消费者消费完后,hcodec去requestBuffer(即surface->us)————owned by us
+
+给vendor(即us->omx)————owned by omx
+
+其他模式不再赘述,直接看图表
+
+
+
+#### *录制*
+
+- 点击“设置”(可选),设置相应的规格后,本示例会先校验当前的相机是否支持输出该规格的流,不支持则更改为默认的1080P的流,若1080P的流仍不支持,则更改为相机能输出配置流的第一个配置。
+- 点击录制后,确定保存后,本示例会根据用户设置选择的配置(未选择则默认1080P),首先创建一个该配置对应的编码器,同时创建好封装器,Surface模式下,编码器OH_VideoEncoder_GetSurface接口,会给应用一个OHNativeWindow **window,来接收编码输入。
+- 使用这个window,调用OH_NativeWindow_GetSurfaceId接口,能拿到window对应的surface的surfaceId,此surfaceId用做相机的录像流的输出surfaceId。
+- 把surfaceId回调到UI层,UI层拿到surfaceId后,携带主页配置的参数信息和surfaceId,路由跳转到录制页面。
+- 录制页面构建时,XComponent构建时,会触发.onLoad()方法,此时能拿到Xcomonent对应的surface的surfaceId,此surfaceId用做相机的预览流的输出surfaceId。
+- 有了两个surfaceId,和想要的相机配置,就能开始创建相机,开始录像了。
+- 参考上文的buffer轮转,本示例在XComponent.onLoad()触发后,建立了一个相机生产,XComponent消费相机预览流,编码器消费相机录像流的生产消费模型,但此时编码器还未开始消费。
+- 待用户在录像页面点击“开始录制”后,本示例才会调用编码器的OH_VideoEncoder_Start()方法,开始录像编码。
+- 编码Surface,由surface生产端(本例是相机)直接往surface内flush SurfaceBuffer,surface内收到buffer后,编码器自动开始编码。
+- 待编码完成后,会触发输出回调给应用,里面会带有每帧编码后的OH_AVBuffer和其对应的index。
+- 此时应用可以调用OH_AVBuffer_GetAddr获取OH_AVBuffer内buffer的内存地址,OH_AVBuffer_GetBufferAttr获取编码后buffer的size等参数信息,本例是直接通过封装器,将其写入文件帧。
+ ```text
+ 若使用RK3568相机录制,相机输出RGBA格式流到编码器Surface,实际flush到Surface里的buffer画面异常,导致最后的录像文件,播放起来的效果不对。
+ ```
+
+
+
+### 音画同步
+
+#### 前言
+
+##### 背景和目的
+
+目前手机播放器在输出设备为蓝牙耳机时会出现严重音视频不同步现象, 严重影响用户体验。本文旨在指导第三方视频播放应用正确获取并使用音频相关信息来保证音视频同步。
+
+精确的音视频同步是媒体播放的关键性能指标之一。一般来说,在录音设备上同时录制的音频和视频需要在播放设备(例如手机,电视,媒体播放器)上同时播放。为了实现设备上的音视频同步,可以按如下指南操作。
+
+##### 概念定义
+
+| Abbreviations缩略语 | Full spelling 英文全名 | Chinese explanation 中文解释 |
+|------------------|:------------------------|:-------------------------|
+| PTS | Presentation Time Stamp | 送显时间戳 |
+| DTS | Decoding Time Stamp | 解码时间戳 |
+
+- DTS(解码时间戳)
+ 指音视频数据在解码器中开始解码的时间戳。它表示解码器应该从输入数据流中读取和解码的特定时间点。DTS用于控制解码器的解码顺序,确保音视频数据按照正确的顺序解码。
+- PTS(显示时间戳)
+ 指音视频数据在播放时应该显示给用户的时间戳。它表示解码后的音视频数据在播放时应该出现在屏幕上或传递给音视频输出设备的时间点。PTS用于控制音视频的播放顺序和时序,以确保音视频在正确的时间点进行显示或播放。
+
+##### 音画同步原理
+
+音视频数据的最小处理单元称为帧。音频流和视频流都被分割成帧,所有帧都被标记为需要按特定的时间戳显示。音频和视频可以独立下载和解码,但就具有匹配时间戳的音频和视频帧应同时呈现,达到A/V同步的效果。
+
+
+
+理论上,因为音频通路存在时延,匹配音频和视频处理,有三种A/V同步解决方案可用;
+
+(1)连续播放音频帧:使用音频播放位置作为主时间参考,并将视频播放位置与其匹配。
+
+(2)使用系统时间作为参考:将音频和视频播放与系统时间匹配。
+
+(3)使用视频播放作为参考:让音频匹配视频。
+
+
+| 策略名称 | 优点 | 缺点 |
+|-------------|:----------------------------------------------------|:-------------------------------------------------------------------------|
+| 连续播放音频帧(推荐) | ①用户肉眼的敏感度较弱,不易察觉视频微小的调整。
②容易实现,因为视频刷新时间的调整相对容易。 | ①如果视频帧率不稳定或延迟渲染大,可能导致视频卡顿或跳帧。 |
+| 使用系统时间作为参考 | 可以最大限度地保证音频和视频都不发生跳帧行为。 | ①需要额外依赖系统时钟,增加系统复杂性和维护成本。
②系统时钟的准确性对同步效果影响较大,如果系统时钟不准确,可能导致同步效果大打折扣。 |
+| 使用视频播放作为参考 | 音频可以根据视频帧进行调整,减少音频跳帧的情况。 | ①音频播放可能会出现等待或加速的情况,相较于视频,会对用户的影响更为严重和明显。
②如果视频帧率不稳定,可能导致音频同步困难。 |
+
+第一个选项是唯一一个具有连续音频数据流的选项,没有对音频帧的显示时间、播放速度或持续时间进行任何调整。这些参数的任何调整都很容易被人的耳朵注意到,并导致干扰的音频故障,除非音频被重新采样;但是,重新采样也会改变音调。因此,一般的多媒体应用使用音频播放位置作为主时间参考。以下段落将讨论此解决方案。(其它两个选项不在本文档的范围内)
+
+### 效果展示
+
+#### 场景说明
+
+#### 适用范围
+
+适用于应用中视频播放过程中,由于设备渲染延迟、播放链路异常导致的音画不同步的场景
+
+##### 场景体验指标
+
+音画同步标准
+
+① 为了衡量音画同步的性能,用对应音频和视频帧实际播放时间的差值作为数值指标,数值大于0表示声音提前画面,小于0表示声音落后画面。
+
+② 最大卡顿时长,单帧图像停滞时间超过100ms的,定义为卡顿一次。连续测试5分钟,建议设置为100ms。
+
+③ 平均播放帧率,平均每秒播放帧数,不反映每帧显示时长。
+
+测试基准:一倍速场景
+
+| | 范围 | 主观体验 |
+|--------|:---------------|:-----|
+| S标(建议) | [-80ms, 25ms] | 无法察觉 |
+| A标 | [-125ms, 45ms] | 能够察觉 |
+| B标 | [-185ms, 90ms] | 能够察觉 |
+
+| 描述 | 应用内播放视频,音画同步指标应满足[-125ms, 45ms]。 |
+|------|:---------------------------------|
+| 类型 | 规则 |
+| 适用设备 | 手机、折叠屏、平板 |
+| 说明 | 无 |
+
+#### 场景分析
+
+##### 典型场景及优化方案
+
+**典型场景描述**
+应用内播放视频,音画同步指标应满足[-80ms, 25ms].
+**场景优化方案**
+该解决方案使用:
+
+- 视频同步到音频(主流方案)
+- 获取音频渲染进度动态调整视频渲染进度
+
+最终实现音画同步[-80ms,25ms]的效果。
+
+
+**图2 音画同步示意图**
+
+
+
+#### 场景实现
+
+##### 场景整体介绍
+
+音频和视频的管道必须同时以相同的时间戳呈现每帧数据。音频播放位置用作主时间参考,而视频管道只输出与最新渲染音频匹配的视频帧。对于所有可能的实现,精确计算最后一次呈现的音频时间戳是至关重要的。OS提供API来查询音频管道各个阶段的音频时间戳和延迟。
+
+音频管道支持查询最新呈现的时间戳,getTimeStamp()
+方法提供了一种简单的方法来确定我们要查找的值。如果时间戳可用,则audioTimestamp实例将填充以帧单位表示的位置,以及显示该帧时的估计时间。此信息可用于控制视频管道,使视频帧与音频帧匹配。
+
+##### 接口说明
+
+```cpp
+/*
+ * Query the the time at which a particular frame was presented.
+ *
+ * @since 10
+ *
+ * @param renderer Reference created by OH_AudioStreamBuilder_GenerateRenderer()
+ * @param clockId {@link #CLOCK_MONOTONIC}
+ * @param framePosition Pointer to a variable to receive the position
+ * @param timestamp Pointer to a variable to receive the timestamp
+ * @return Function result code:
+ * {@link AUDIOSTREAM_SUCCESS} If the execution is successful.
+ * {@link AUDIOSTREAM_ERROR_INVALID_PARAM}:
+ * 1.The param of renderer is nullptr;
+ * 2.The param of clockId invalid.
+ * {@link AUDIOSTREAM_ERROR_ILLEGAL_STATE} Execution status exception.
+ */
+OH_AudioStream_Result OH_AudioRenderer_GetTimestamp(OH_AudioRenderer* renderer,
+ clockid_t clockId, int64_t* framePosition, int64_t* timestamp);
+```
+
+注意事项:
+
+(1)
+OH_AudioRenderer_Start到真正写入硬件有一定延迟,因此该接口在OH_AudioRenderer_Start之后过一会儿才会再拿到有效值,期间音频未发声时建议画面帧先按照正常速度播放,后续再逐步追赶音频位置从而提升用户看到画面的起搏时延。
+
+(2)当framePosition和timeStamp稳定之前,调用可以比较频繁(如100ms)
+,当以稳定的速度增长前进后,建议OH_AudioRenderer_GetTimestamp的频率不要太频繁,可以每分钟一次,最好不要低于500ms一次,因为频繁调用可能会带来功耗问题,因此在能保证音画同步效果的情况下,不需要频繁地查询时间戳。
+
+(3)OH_AudioRenderer_Flush接口执行后,framePosition返回值会重新(从0)开始计算。
+
+(4)OH_AudioRenderer_GetFramesWritten 接口在Flush的时候不会清空,该接口和OH_AudioRenderer_GetTimestamp接口并不建议配合使用。
+
+(5)音频设备切换过程中OH_AudioRenderer_GetTimestamp返回的framePosition和timestamp不会倒退,但由于新设备写入有时延,会出现短暂时间内音频进度无增长,建议画面帧保持流程播放不要产生卡顿。
+
+(6)
+OH_AudioRenderer_GetTimeStamp获取的是实际写到硬件的采样帧数,不受倍速影响。对AudioRender设置了倍速的场景下,播放进度计算需要特殊处理,系统保证应用设置完倍速播放接口后,新写入AudioRender的采样点才会做倍速处理。
+
+##### 关键代码片段
+
+(1)获取音频渲染的位置
+
+```cpp
+// get audio render position
+int64_t framePosition = 0;
+int64_t timestamp = 0;
+int32_t ret = OH_AudioRenderer_GetTimestamp(audioRenderer_, CLOCK_MONOTONIC, &framePosition, ×tamp);
+AVCODEC_SAMPLE_LOGI("VD framePosition: %{public}li, nowTimeStamp: %{public}li", framePosition, nowTimeStamp);
+audioTimeStamp = timestamp; // ns
+```
+
+(2)音频启动前暂不做音画同步
+
+- 音频未启动前,timestamp和framePosition返回结果为0,为避免出现卡顿等问题,暂不同步
+
+```cpp
+// audio render getTimeStamp error, render it
+ if (ret != AUDIOSTREAM_SUCCESS || (timestamp == 0) || (framePosition == 0)) {
+ DumpOutput(bufferInfo);
+ // first frame, render without wait
+ ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, sampleInfo_.codecRunMode ? false : true,
+ GetCurrentTime());
+ if (ret != AVCODEC_SAMPLE_ERR_OK) {
+ AVCODEC_SAMPLE_LOGW("FreeOutputBuffer failed: %{public}d", ret);
+ return false;
+ }
+ std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval));
+ lastPushTime = std::chrono::system_clock::now();
+ return true;
+ }
+```
+
+(3)根据视频帧pts和音频渲染位置计算延迟waitTimeUs
+
+- audioPlayedTime音频帧期望渲染时间
+- videoPlayedTime视频帧期望送显时间
+
+```cpp
+// after seek, audio render flush, framePosition = 0, then writtenSampleCnt = 0
+int64_t latency = (audioDecContext_->frameWrittenForSpeed - framePosition) * 1000 *
+ 1000 / sampleInfo_.audioSampleRate / speed;
+AVCODEC_SAMPLE_LOGI("VD latency: %{public}li writtenSampleCnt: %{public}li", latency, writtenSampleCnt);
+
+nowTimeStamp = GetCurrentTime();
+int64_t anchordiff = (nowTimeStamp - audioTimeStamp) / 1000;
+
+// us, audio buffer accelerate render time
+int64_t audioPlayedTime = audioDecContext_->currentPosAudioBufferPts - latency + anchorDiff;
+// us, video buffer expected render time
+int64_t videoPlayedTime = bufferInfo.attr.pts;
+
+// audio render timestamp and now timestamp diff
+int64_t waitTimeUs = videoPlayedTime - audioPlayedTime; // us
+```
+
+(4)根据业务延迟做音画同步策略
+
+- [,-40ms) 视频帧较晚,此帧丢掉
+- [-40ms,0ms)视频帧直接送显
+- [0ms,)视频帧较早,根据业务需要选择现象追帧
+
+```cpp
+// video buffer is too late, drop it
+if (waitTimeUs < WAIT_TIME_US_THRESHOLD_WARNING) {
+ dropFrame = true;
+ AVCODEC_SAMPLE_LOGI("VD buffer is too late");
+} else {
+ AVCODEC_SAMPLE_LOGE("VD buffer is too early waitTimeUs:%{public}ld", waitTimeUs);
+ // [0, ), render it wait waitTimeUs, max 1s
+ // [-40, 0), render it
+ if (waitTimeUs > WAIT_TIME_US_THRESHOLD) {
+ waitTimeUs = WAIT_TIME_US_THRESHOLD;
+ }
+ // per frame render time reduced by frame interval
+ if (waitTimeUs > sampleInfo_.frameInterval + perSinkTimeThreshold) {
+ waitTimeUs = sampleInfo_.frameInterval + perSinkTimeThreshold;
+ AVCODEC_SAMPLE_LOGE("VD buffer is too early and reduced, waitTimeUs: %{public}ld", waitTimeUs);
+ }
+}
+```
+
+(5)进行音画同步
+若视频帧的时间大于2倍vsync的时间,则需要sleep超过的时间。
+
+```cpp
+if (static_cast(waitTimeUs) > VSYNC_TIME * LIP_SYNC_BALANCE_VALUE) {
+ std::this_thread::sleep_for(std::chrono::microseconds(
+ static_cast(static_cast(waitTimeUs) - VSYNC_TIME * LIP_SYNC_BALANCE_VALUE)));
+}
+DumpOutput(bufferInfo);
+int32_t ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex,
+ sampleInfo_.codecRunMode ? false : !dropFrame,
+ VSYNC_TIME * LIP_SYNC_BALANCE_VALUE * MS_TO_S + GetCurrentTime());
+if (ret != AVCODEC_SAMPLE_ERR_OK) {
+ AVCODEC_SAMPLE_LOGE("FreeOutputBuffer failed: %{public}d", ret);
+ return false;
+}
+return true;
+```
+
+### 倍速播放方案
+
+#### 当前问题
+
+
+
+通过Audio GetTimeStamp拿到的Position始终是一倍速参考系下计算的,导致应用写下多倍速的音频帧后不清楚底层实际播放的原始位置。
+
+**比如假设采样率是48k,应用写的frameIn A一共写了48000,2倍速后的frameOut A' 只有24000,
+底层播了一半后返回给应用的position是12000 - 硬件latency(假设是100ms)
+,也就是倍速后播了150ms,但应用实际播放的pts应该是24000-硬件latency×2 = 300ms**
+
+Position表示的是音频帧,一个音频帧包括左右声道的采样点交织形成的数据包,比如双声道16bit采样点,一帧数据是4个字节,48k采样率的音频,一秒播放48000帧
+
+应用一般音画同步做法:
+
+视频每解码一帧,获取一下音频clock,视频帧永远跟随音频pts
+
+#### **倍速的音频时间戳计算算法(此方法也同样适用于三方自研播放器)**
+
+原理:记录每次setSpeed时的最后position状态作为基准,更新speed之后,按照上一次speed末尾的基准+数据delta×最新speed返回给应用
+
+| **时间线** | **应用行为** | **播放范围(写给AudioRender的数据)** | **此刻音频服务处理的位置(frameOutC)** | **pulseaudio实际返回的position** | **audiorender矫正后返回给应用的值** | **音频PTS(假设起始时间是X)** |
+|:---------------:|:--------:|:---------------------------------------:|:--------------------------:|:-----------------------------------------------------------------------------------------------------------------:|:-------------------------:|:----------------------------------------------------------------:|
+| **T0时刻** | 先一倍速 | 1-1000 | 800 | 600 | 600 | X + 600/48000 |
+| **T1时刻** | 倍速调节成2 | | | 记录倍速调节之前写的位置
lastSpeedX = 1000
lastSpeedFramesWritten = 1000 | | |
+| **T2时刻** | 2倍速 | 原始数据1001-2000,倍速后送给Audio服务的是(1001-1500) | 1400 | 1200 | | |
+| **计算T2时刻音频PTS** | | | | 1200如何倒推音源Position?
实际位置=(position-lastSpeedIdx)*speed + lastSpeedFramesWritten
(1200-1000)×2+1000 = 1400 | 1400 | X+1400/48000
记录lastPosition = 1400
lastPositionTime = T2 |
+| **视频出帧T2'时刻** | | | | | | 送显delay = 视频PTS - (X + 1400 / 48000 + (T2' - T2)*2 |
+| **T3时刻** | 倍速调节成3 | | | 记录倍速调节之前写的位置
lastSpeedIdx = 1500
lastSpeedFramesWritten = 2000 | | |
+| **T4时刻** | 3倍速 | 原始数据2001-3500,倍速后送欸Audio服务的是(1501-2000) | 1600 | 1400 | | |
+| **计算T4时刻音频PTS** | | | | 1400 < 1500, 说明底层还在播老倍速的数据,复用上一次的音频pts做偏移 | 1400+(T4-T2)×2 | X+(lastPosition+(T4-T2)×2) |
+| **T5时刻** | 3倍速 | 原始数据2001-3500 播放中 | 1900 | 1700 | | |
+| **计算T5时刻音频PTS** | | Content | | 实际位置=(position-lastSpeedIdx)*speed + lastSpeedFramesWritten
(1700-1500)×3+2000 = 2600 | 2600 | X+2600/48000 |
+
+### 环境配置
+#### OpenHarmony
+切换OpenHarmony工程,签名后运行,右下角报错:
+
+
+
+通过文件-设置打开OpenHarmonySDK目录:
+
+
+
+根据你的SDK version找到Local\OpenHarmony\Sdk\13\ets\api\device-define文件夹(此例为13)的default.json
+
+
+
+这个就是你“default”类型的设备的system capability的要求
+
+此例,缺这两个:
+
+SystemCapability.HiviewDFX.HiDumper,
+
+SystemCapability.Multimedia.AVSession.ExtendedDisplayCast.
+
+那就打开json文件,删掉这个要求,保存再编,就行了
+
+#### HarmonyOS
+若切换成HarmonyOS工程,搜索runtimeOS,将OpenHarmony字段改成HarmonyOS,上面的sdkVersion,改成"5.0.0(12)"这样的形式(保留双引号),搜索删除abiFilters字段后的"armeabi-v7a"参数。
+
+### 相关权限
+
+#### [ohos.permission.CAMERA](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/security/AccessToken/permissions-for-all.md#ohospermissioncamera)
+
+### 依赖
+
+XComponent Camera
+
+### 约束与限制
+
+1.本示例仅支持标准系统上运行,支持Phone, RK3568;
+
+2.本示例为Stage模型,仅支持 API12 及以上版本SDK, SDK版本号5.0.0.19及以上版本,镜像版本号支持5.0.0.19及以上版本;
+
+3.本示例需要使用DevEco Studio 5.0 才可编译运行。
+
+### 下载
+如需单独下载本工程,执行如下命令:
+```text
+git init
+git config core.sparsecheckout true
+echo code/BasicFeature/Media/AVCodec/ > .git/info/sparse-checkout
+git remote add origin https://gitee.com/openharmony/applications_app_samples.git
+git pull origin master
+```
diff --git a/code/BasicFeature/Media/AVCodec/build-profile.json5 b/code/BasicFeature/Media/AVCodec/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..11baa04c9cac9badc9318281cdebf824383787ab
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/build-profile.json5
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "app": {
+ "signingConfigs": [
+ ],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compileSdkVersion": 13,
+ "compatibleSdkVersion": 13,
+ //指定HarmonyOS应用/服务兼容的最低版本。注意使用英文.和()
+ "targetSdkVersion": 13,
+ //指定HarmonyOS应用/服务目标版本。若没有设置,默认为compatibleSdkVersion
+ "runtimeOS": "OpenHarmony",
+ //指定为HarmonyOS
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/.gitignore b/code/BasicFeature/Media/AVCodec/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/build-profile.json5 b/code/BasicFeature/Media/AVCodec/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..52be05d874aebc88521e3420513e878adb69fbdd
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/build-profile.json5
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "apiType": 'stageMode',
+ "buildOption": {
+ "externalNativeOptions": {
+ "abiFilters": ["arm64-v8a", "x86_64", "armeabi-v7a"],
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": "",
+ }
+ },
+ "targets": [
+ {
+ "name": "default",
+ "runtimeOS": "OpenHarmony"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/hvigorfile.ts b/code/BasicFeature/Media/AVCodec/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4d1f1d423fecb1d23d9db5d82759899f44227bdb
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/hvigorfile.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { hapTasks } from '@ohos/hvigor-ohos-plugin';
diff --git a/code/BasicFeature/Media/AVCodec/entry/oh-package.json5 b/code/BasicFeature/Media/AVCodec/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d4e4debb1ee628315bf76e638d49c5b8283c4e6a
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/oh-package.json5
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "license": "",
+ "devDependencies": {},
+ "author": "",
+ "name": "entry",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "version": "1.0.0",
+ "dependencies": {
+ "libplayer.so": "file:./src/main/cpp/types/libplayer",
+ "librecorder.so": "file:./src/main/cpp/types/librecorder"
+ }
+}
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/CMakeLists.txt b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5cfaabf41fcc2d48176bb2eb9d661392df346495
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,41 @@
+# the minimum version of CMake.
+cmake_minimum_required(VERSION 3.4.1)
+project(videoCodecSample)
+
+set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${NATIVERENDER_ROOT_PATH}
+ ${NATIVERENDER_ROOT_PATH}/capbilities/include
+ ${NATIVERENDER_ROOT_PATH}/common
+ ${NATIVERENDER_ROOT_PATH}/common/dfx/err
+ ${NATIVERENDER_ROOT_PATH}/common/dfx/log
+ ${NATIVERENDER_ROOT_PATH}/render/include
+ ${NATIVERENDER_ROOT_PATH}/sample/player
+ ${NATIVERENDER_ROOT_PATH}/sample/recorder
+)
+
+set(BASE_LIBRARY
+ libace_napi.z.so libGLESv3.so libace_ndk.z.so libuv.so libhilog_ndk.z.so
+ libnative_media_codecbase.so libnative_media_core.so libnative_media_vdec.so libnative_window.so
+ libnative_media_venc.so libnative_media_acodec.so libnative_media_avdemuxer.so libnative_media_avsource.so libnative_media_avmuxer.so
+ libohaudio.so
+)
+add_library(player SHARED sample/player/PlayerNative.cpp
+ sample/player/Player.cpp
+ capbilities/demuxer.cpp
+ capbilities/video_decoder.cpp
+ capbilities/audio_decoder.cpp
+ render/plugin_render.cpp
+ render/plugin_manager.cpp
+ common/sample_callback.cpp
+)
+
+add_library(recorder SHARED sample/recorder/RecorderNative.cpp
+ sample/recorder/Recorder.cpp
+ capbilities/muxer.cpp
+ capbilities/video_encoder.cpp
+ common/sample_callback.cpp
+)
+
+target_link_libraries(player PUBLIC ${BASE_LIBRARY})
+target_link_libraries(recorder PUBLIC ${BASE_LIBRARY})
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/audio_decoder.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/audio_decoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e27afaf73ae479f74288da1ef0e4d1b3de82104a
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/audio_decoder.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "audio_decoder.h"
+
+#undef LOG_TAG
+#define LOG_TAG "AudioDecoder"
+
+AudioDecoder::~AudioDecoder()
+{
+ Release();
+}
+
+int32_t AudioDecoder::Create(const std::string &codecMime)
+{
+ decoder_ = OH_AudioCodec_CreateByMime(codecMime.c_str(), false);
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::SetCallback(CodecUserData *codecUserData)
+{
+ int32_t ret = AV_ERR_OK;
+ ret = OH_AudioCodec_RegisterCallback(decoder_,
+ {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
+ SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
+ codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::Configure(const SampleInfo &sampleInfo)
+{
+ OH_AVFormat *format = OH_AVFormat_Create();
+ CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");
+
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, SAMPLE_S16LE); // SAMPLE_S16LE SAMPLE_F32P
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, sampleInfo.audioChannelCount);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, sampleInfo.audioSampleRate);
+ OH_AVFormat_SetLongValue(format, OH_MD_KEY_CHANNEL_LAYOUT, sampleInfo.audioChannelLayout);
+
+ if (sampleInfo.codecConfigLen > 0) {
+ AVCODEC_SAMPLE_LOGI("====== AudioDecoder config ====== codecConfig:%{public}p, len:%{public}i, "
+ "adts:${public}i, 0:0x%{public}02x, 1:0x%{public}02x",
+ sampleInfo.codecConfig, sampleInfo.codecConfigLen, sampleInfo.aacAdts,
+ sampleInfo.codecConfig[0], sampleInfo.codecConfig[1]);
+ uint8_t tmpCodecConfig[2];
+ tmpCodecConfig[0] = 0x13; // 0x11
+ tmpCodecConfig[1] = 0x10; // 0x90
+ tmpCodecConfig[0] = sampleInfo.codecConfig[0]; // 0x11
+ tmpCodecConfig[1] = sampleInfo.codecConfig[1]; // 0x90
+ AVCODEC_SAMPLE_LOGI("====== AudioDecoder config ====== 0:0x%{public}02x, 1:0x%{public}02x", tmpCodecConfig[0],
+ tmpCodecConfig[1]);
+ OH_AVFormat_SetBuffer(format, OH_MD_KEY_CODEC_CONFIG, sampleInfo.codecConfig, sampleInfo.codecConfigLen);
+ }
+
+ AVCODEC_SAMPLE_LOGI("====== AudioDecoder config ======");
+ int ret = OH_AudioCodec_Configure(decoder_, format);
+ AVCODEC_SAMPLE_LOGI("====== AudioDecoder config ======");
+ if (ret != AV_ERR_OK) {
+ AVCODEC_SAMPLE_LOGE("Config failed, ret: %{public}d", ret);
+ OH_AVFormat_Destroy(format);
+ format = nullptr;
+ return AVCODEC_SAMPLE_ERR_ERROR;
+ }
+ OH_AVFormat_Destroy(format);
+ format = nullptr;
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+ CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Invalid param: codecUserData");
+
+ // Configure audio decoder
+ int32_t ret = Configure(sampleInfo);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed");
+
+ // SetCallback for audio decoder
+ ret = SetCallback(codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
+ "Set callback failed, ret: %{public}d", ret);
+
+ // Prepare audio decoder
+ {
+ int ret = OH_AudioCodec_Prepare(decoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);
+ }
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::Start()
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int ret = OH_AudioCodec_Start(decoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::PushInputBuffer(CodecBufferInfo &info)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+ int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast(info.buffer), &info.attr);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set avbuffer attr failed");
+ ret = OH_AudioCodec_PushInputBuffer(decoder_, info.bufferIndex);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Push input data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::FreeOutputBuffer(uint32_t bufferIndex, bool render)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int32_t ret = AVCODEC_SAMPLE_ERR_OK;
+ ret = OH_AudioCodec_FreeOutputBuffer(decoder_, bufferIndex);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Free output data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t AudioDecoder::Release()
+{
+ if (decoder_ != nullptr) {
+ OH_AudioCodec_Flush(decoder_);
+ OH_AudioCodec_Stop(decoder_);
+ OH_AudioCodec_Destroy(decoder_);
+ decoder_ = nullptr;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/demuxer.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/demuxer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e765d96f6af94b70c14f877f7d23ce5a74dede2b
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/demuxer.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "demuxer.h"
+#include
+
+#undef LOG_TAG
+#define LOG_TAG "Demuxer"
+
+namespace {
+using namespace std;
+}
+
+Demuxer::~Demuxer() { Release(); }
+
+int32_t Demuxer::Create(SampleInfo &info)
+{
+ /**
+ * // Need request Internet Permission first in module.json.
+ * const char *url = "https://hd.ijycnd.com/play/Ddw1W2Ra/index.m3u8";
+ * source_ = OH_AVSource_CreateWithURI(const_cast(url));
+ */
+ source_ = OH_AVSource_CreateWithFD(info.inputFd, info.inputFileOffset, info.inputFileSize);
+ CHECK_AND_RETURN_RET_LOG(source_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR,
+ "Create demuxer source failed, fd: %{public}d, offset: %{public}" PRId64", file size: %{public}" PRId64,
+ info.inputFd, info.inputFileOffset, info.inputFileSize);
+ demuxer_ = OH_AVDemuxer_CreateWithSource(source_);
+ CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create demuxer failed");
+
+ auto sourceFormat = std::shared_ptr(OH_AVSource_GetSourceFormat(source_), OH_AVFormat_Destroy);
+ CHECK_AND_RETURN_RET_LOG(sourceFormat != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get source format failed");
+
+ int32_t ret = GetTrackInfo(sourceFormat, info);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Get video track info failed");
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Demuxer::ReadSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr)
+{
+ CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Demuxer is null");
+ int32_t ret = OH_AVDemuxer_ReadSampleBuffer(demuxer_, trackId, buffer);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Read sample failed");
+ ret = OH_AVBuffer_GetBufferAttr(buffer, &attr);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "GetBufferAttr failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Demuxer::Release()
+{
+ if (demuxer_ != nullptr) {
+ OH_AVDemuxer_Destroy(demuxer_);
+ demuxer_ = nullptr;
+ }
+ if (source_ != nullptr) {
+ OH_AVSource_Destroy(source_);
+ source_ = nullptr;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Demuxer::GetTrackInfo(std::shared_ptr sourceFormat, SampleInfo &info)
+{
+ int32_t trackCount = 0;
+ OH_AVFormat_GetIntValue(sourceFormat.get(), OH_MD_KEY_TRACK_COUNT, &trackCount);
+ for (int32_t index = 0; index < trackCount; index++) {
+ auto trackFormat = GetTrackFormat(index);
+ int trackType = GetTrackType(trackFormat);
+ if (trackType == MEDIA_TYPE_VID) {
+ ProcessVideoTrack(trackFormat, index, info);
+ } else if (trackType == MEDIA_TYPE_AUD) {
+ ProcessAudioTrack(trackFormat, index, info);
+ }
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+std::shared_ptr Demuxer::GetTrackFormat(int32_t index)
+{
+ return std::shared_ptr(OH_AVSource_GetTrackFormat(source_, index), OH_AVFormat_Destroy);
+}
+
+int Demuxer::GetTrackType(std::shared_ptr trackFormat)
+{
+ int trackType = -1;
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_TRACK_TYPE, &trackType);
+ return trackType;
+}
+
+void Demuxer::ProcessVideoTrack(std::shared_ptr trackFormat, int32_t index, SampleInfo &info)
+{
+ OH_AVDemuxer_SelectTrackByID(demuxer_, index);
+
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_WIDTH, &info.videoWidth);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_HEIGHT, &info.videoHeight);
+ OH_AVFormat_GetDoubleValue(trackFormat.get(), OH_MD_KEY_FRAME_RATE, &info.frameRate);
+ OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_BITRATE, &info.bitrate);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_ROTATION, &info.rotation);
+
+ char *videoCodecMime;
+ OH_AVFormat_GetStringValue(trackFormat.get(), OH_MD_KEY_CODEC_MIME, const_cast(&videoCodecMime));
+ info.videoCodecMime = videoCodecMime;
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_PROFILE, &info.hevcProfile);
+ videoTrackId_ = index;
+
+ LogVideoConfig(info, videoCodecMime);
+}
+
+void Demuxer::ProcessAudioTrack(std::shared_ptr trackFormat, int32_t index, SampleInfo &info)
+{
+ OH_AVDemuxer_SelectTrackByID(demuxer_, index);
+
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUDIO_SAMPLE_FORMAT, &info.audioSampleForamt);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_CHANNEL_COUNT, &info.audioChannelCount);
+ OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_CHANNEL_LAYOUT, &info.audioChannelLayout);
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_SAMPLE_RATE, &info.audioSampleRate);
+
+ char *audioCodecMime;
+ OH_AVFormat_GetStringValue(trackFormat.get(), OH_MD_KEY_CODEC_MIME, const_cast(&audioCodecMime));
+
+ HandleCodecConfig(trackFormat, info);
+
+ OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AAC_IS_ADTS, &info.aacAdts);
+ info.audioCodecMime = audioCodecMime;
+ audioTrackId_ = index;
+
+ LogAudioConfig(info, audioCodecMime);
+}
+
+void Demuxer::HandleCodecConfig(std::shared_ptr trackFormat, SampleInfo &info)
+{
+ uint8_t *codecConfig = nullptr;
+ OH_AVFormat_GetBuffer(trackFormat.get(), OH_MD_KEY_CODEC_CONFIG, &codecConfig, &info.codecConfigLen);
+
+ if (info.codecConfig != nullptr && info.codecConfigLen > 0 && info.codecConfigLen < sizeof(info.codecConfig)) {
+ copy(codecConfig, codecConfig + info.codecConfigLen, info.codecConfig);
+ LogCodecConfigDetails(info);
+ }
+}
+
+void Demuxer::LogVideoConfig(const SampleInfo &info, const char *videoCodecMime)
+{
+ AVCODEC_SAMPLE_LOGI("====== Demuxer Video config ======");
+ AVCODEC_SAMPLE_LOGI("Mime: %{public}s", videoCodecMime);
+ AVCODEC_SAMPLE_LOGI("%{public}d * %{public}d, %{public}.1ffps, %{public}" PRId64 "kbps",
+ info.videoWidth, info.videoHeight, info.frameRate, info.bitrate / 1024);
+ AVCODEC_SAMPLE_LOGI("====== Demuxer Video config ======");
+}
+
+void Demuxer::LogAudioConfig(const SampleInfo &info, const char *audioCodecMime)
+{
+ AVCODEC_SAMPLE_LOGI("====== Demuxer Audio config ======");
+ AVCODEC_SAMPLE_LOGI("audioMime:%{public}s sampleForamt:%{public}d sampleRate:%{public}d "
+ "channelCount:%{public}d channelLayout:%{public}ld adts:%{public}i",
+ audioCodecMime, info.audioSampleForamt, info.audioSampleRate,
+ info.audioChannelCount, info.audioChannelLayout, info.aacAdts);
+ AVCODEC_SAMPLE_LOGI("====== Demuxer Audio config ======");
+}
+
+void Demuxer::LogCodecConfigDetails(const SampleInfo &info)
+{
+ AVCODEC_SAMPLE_LOGI("codecConfig:%{public}p, len:%{public}i, 0:0x%{public}02x 1:0x:%{public}02x, bufLen:%{public}u",
+ info.codecConfig, static_cast(info.codecConfigLen),
+ info.codecConfig[0], info.codecConfig[1],
+ static_cast(sizeof(info.codecConfig)));
+}
+
+int32_t Demuxer::GetVideoTrackId() { return videoTrackId_; }
+int32_t Demuxer::GetAudioTrackId() { return audioTrackId_; }
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/audio_decoder.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/audio_decoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..0716ea097abb0bb5fdbd34fd92914b895c2419ee
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/audio_decoder.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIODECODER_H
+#define AUDIODECODER_H
+
+#include "multimedia/player_framework/native_avcodec_audiocodec.h"
+#include "multimedia/player_framework/native_avbuffer_info.h"
+#include "sample_callback.h"
+#include "dfx/error/av_codec_sample_error.h"
+#include "av_codec_sample_log.h"
+
+class AudioDecoder {
+public:
+ AudioDecoder() = default;
+ ~AudioDecoder();
+
+ int32_t Create(const std::string &codecMime);
+ int32_t Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData);
+ int32_t Start();
+ int32_t PushInputBuffer(CodecBufferInfo &info);
+ int32_t FreeOutputBuffer(uint32_t bufferIndex, bool render);
+ int32_t Release();
+
+private:
+ int32_t SetCallback(CodecUserData *codecUserData);
+ int32_t Configure(const SampleInfo &sampleInfo);
+
+ bool isAVBufferMode_ = false;
+ OH_AVCodec *decoder_;
+};
+#endif // AUDIODECODER_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/demuxer.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/demuxer.h
new file mode 100644
index 0000000000000000000000000000000000000000..e02347414cbdfe58db0efcca59f8ad33b8f4dac0
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/demuxer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DEMUXER_H
+#define DEMUXER_H
+
+#include
+#include
+#include "napi/native_api.h"
+#include "multimedia/player_framework/native_avdemuxer.h"
+#include "sample_info.h"
+#include "dfx/error/av_codec_sample_error.h"
+#include "av_codec_sample_log.h"
+
+
+class Demuxer {
+public:
+ Demuxer() = default;
+ ~Demuxer();
+ int32_t Create(SampleInfo &sampleInfo);
+ int32_t ReadSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr);
+ int32_t Release();
+ int32_t GetVideoTrackId();
+ int32_t GetAudioTrackId();
+
+private:
+ int32_t GetTrackInfo(std::shared_ptr sourceFormat, SampleInfo &info);
+ std::shared_ptr GetTrackFormat(int32_t index);
+ int GetTrackType(std::shared_ptr trackFormat);
+ void ProcessVideoTrack(std::shared_ptr trackFormat, int32_t index, SampleInfo &info);
+ void ProcessAudioTrack(std::shared_ptr trackFormat, int32_t index, SampleInfo &info);
+ void HandleCodecConfig(std::shared_ptr trackFormat, SampleInfo &info);
+ void LogVideoConfig(const SampleInfo &info, const char *videoCodecMime);
+ void LogAudioConfig(const SampleInfo &info, const char *audioCodecMime);
+ void LogCodecConfigDetails(const SampleInfo &info);
+
+ OH_AVSource *source_;
+ OH_AVDemuxer *demuxer_;
+ int32_t videoTrackId_;
+ int32_t audioTrackId_;
+};
+
+#endif // DEMUXER_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/muxer.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/muxer.h
new file mode 100644
index 0000000000000000000000000000000000000000..b623dcc0402c2f991f9ce04f4fc259bf1b261005
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/muxer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MUXER_H
+#define MUXER_H
+
+#include
+#include "multimedia/player_framework/native_avmuxer.h"
+#include "sample_info.h"
+#include "dfx/error/av_codec_sample_error.h"
+#include "av_codec_sample_log.h"
+
+class Muxer {
+public:
+ Muxer() = default;
+ ~Muxer();
+
+ int32_t Create(int32_t fd);
+ int32_t Config(SampleInfo &sampleInfo);
+ int32_t Start();
+ int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr);
+ int32_t Stop();
+ int32_t Release();
+
+private:
+ OH_AVMuxer *muxer_ = nullptr;
+ int32_t videoTrackId_ = -1;
+};
+
+#endif // MUXER_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_decoder.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_decoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ec7b39ca789738efe5a5c3ad37f844e5942e688
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_decoder.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIDEODECODER_H
+#define VIDEODECODER_H
+
+#include "multimedia/player_framework/native_avcodec_videodecoder.h"
+#include "multimedia/player_framework/native_avcapability.h"
+#include "multimedia/player_framework/native_avbuffer_info.h"
+#include "sample_info.h"
+#include "sample_callback.h"
+#include "dfx/error/av_codec_sample_error.h"
+#include "av_codec_sample_log.h"
+
+class VideoDecoder {
+public:
+ VideoDecoder() = default;
+ ~VideoDecoder();
+
+ int32_t Create(const std::string &videoCodecMime, int32_t videoDecoderType);
+ int32_t Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData);
+ int32_t PushInputBuffer(CodecBufferInfo &info);
+ int32_t FreeOutputBuffer(uint32_t bufferIndex, bool render);
+ int32_t FreeOutputBuffer(uint32_t bufferIndex, bool render, int64_t timeStamp);
+ int32_t Start();
+ int32_t Release();
+
+private:
+ int32_t SetCallback(CodecUserData *codecUserData);
+ int32_t Configure(const SampleInfo &sampleInfo);
+ OH_AVCodec *GetCodecByCategory(const char *mime, bool isEncoder, OH_AVCodecCategory category);
+
+ bool isAVBufferMode_ = false;
+ OH_AVCodec *decoder_;
+};
+#endif // VIDEODECODER_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_encoder.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_encoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..0a2a13d1d25c7fcd5ed5b950a95623068ef0ce85
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/include/video_encoder.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIDEOENCODER_H
+#define VIDEOENCODER_H
+
+#include "multimedia/player_framework/native_avcodec_videoencoder.h"
+#include "multimedia/player_framework/native_avbuffer_info.h"
+#include "sample_info.h"
+#include "native_window/external_window.h"
+#include "native_window/buffer_handle.h"
+#include "sample_callback.h"
+#include "dfx/error/av_codec_sample_error.h"
+#include "av_codec_sample_log.h"
+
+class VideoEncoder {
+public:
+ VideoEncoder() = default;
+ ~VideoEncoder();
+
+ int32_t Create(const std::string &videoCodecMime);
+ int32_t Config(SampleInfo &sampleInfo, CodecUserData *codecUserData);
+ int32_t Start();
+ int32_t PushInputBuffer(CodecBufferInfo &info);
+ int32_t FreeOutputBuffer(uint32_t bufferIndex);
+ int32_t NotifyEndOfStream();
+ int32_t Stop();
+ int32_t Release();
+
+private:
+ int32_t SetCallback(CodecUserData *codecUserData);
+ int32_t Configure(const SampleInfo &sampleInfo);
+ int32_t GetSurface(SampleInfo &sampleInfo);
+ bool isAVBufferMode_ = false;
+ OH_AVCodec *encoder_ = nullptr;
+};
+#endif // VIDEOENCODER_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/muxer.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/muxer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..959d9a745e281ba59a7c8b384235073e734abbb8
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/muxer.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "muxer.h"
+
+#undef LOG_TAG
+#define LOG_TAG "Muxer"
+
+namespace {
+constexpr int32_t VERTICAL_ANGLE = 90;
+constexpr int32_t HORIZONTAL_ANGLE = 0;
+}
+
+Muxer::~Muxer()
+{
+ Release();
+}
+
+int32_t Muxer::Create(int32_t fd)
+{
+ muxer_ = OH_AVMuxer_Create(fd, AV_OUTPUT_FORMAT_MPEG_4);
+ CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer create failed, fd: %{public}d", fd);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Muxer::Config(SampleInfo &sampleInfo)
+{
+ CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null");
+
+ OH_AVFormat *formatVideo = OH_AVFormat_CreateVideoFormat(sampleInfo.videoCodecMime.data(),
+ sampleInfo.videoWidth, sampleInfo.videoHeight);
+ CHECK_AND_RETURN_RET_LOG(formatVideo != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create video format failed");
+
+ OH_AVFormat_SetDoubleValue(formatVideo, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
+ OH_AVFormat_SetStringValue(formatVideo, OH_MD_KEY_CODEC_MIME, sampleInfo.videoCodecMime.data());
+ if (sampleInfo.isHDRVivid) {
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_VIDEO_IS_HDR_VIVID, 1);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_RANGE_FLAG, sampleInfo.rangFlag);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_COLOR_PRIMARIES, sampleInfo.primary);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_TRANSFER_CHARACTERISTICS, sampleInfo.transfer);
+ OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_MATRIX_COEFFICIENTS, sampleInfo.matrix);
+ }
+
+ int32_t ret = OH_AVMuxer_AddTrack(muxer_, &videoTrackId_, formatVideo);
+ OH_AVFormat_Destroy(formatVideo);
+ // 由于相机只有1920×1080的profile,没有1080×1920的profile,所以得往文件里封装一个90度的角度信息,后续播放才会是竖屏显示。
+ OH_AVMuxer_SetRotation(muxer_, 90);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "AddTrack failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Muxer::Start()
+{
+ CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null");
+
+ int ret = OH_AVMuxer_Start(muxer_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr)
+{
+ CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null");
+ CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get a empty buffer");
+
+ int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &attr);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "SetBufferAttr failed");
+
+ ret = OH_AVMuxer_WriteSampleBuffer(muxer_, videoTrackId_, buffer);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Write sample failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Muxer::Stop()
+{
+ CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null");
+
+ int32_t ret = OH_AVMuxer_Stop(muxer_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Muxer stop failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t Muxer::Release()
+{
+ if (muxer_ != nullptr) {
+ OH_AVMuxer_Destroy(muxer_);
+ muxer_ = nullptr;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_decoder.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_decoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44b669bc26910788fec85bfe9d8eb191a2031725
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_decoder.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "video_decoder.h"
+
+#undef LOG_TAG
+#define LOG_TAG "VideoDecoder"
+
+namespace {
+constexpr int LIMIT_LOGD_FREQUENCY = 50;
+constexpr int ROTATION_ANGLE = 90;
+} // namespace
+
+VideoDecoder::~VideoDecoder() { Release(); }
+
+OH_AVCodec *VideoDecoder::GetCodecByCategory(const char *mime, bool isEncoder, OH_AVCodecCategory category)
+{
+ OH_AVCapability *capability = OH_AVCodec_GetCapabilityByCategory(mime, isEncoder, category);
+ CHECK_AND_RETURN_RET_LOG(capability != nullptr, nullptr, "Capability is nullptr");
+ const char *codecName = OH_AVCapability_GetName(capability);
+ return OH_VideoDecoder_CreateByName(codecName);
+}
+
+int32_t VideoDecoder::Create(const std::string &videoCodecMime, int32_t videoDecoderType)
+{
+ switch (videoDecoderType) {
+ case AUTO:
+ decoder_ = OH_VideoDecoder_CreateByMime(videoCodecMime.c_str());
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
+ break;
+ case VIDEO_HW_DECODER:
+ if (!strcmp(videoCodecMime.data(), "video/avc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, HARDWARE);
+ } else if (!strcmp(videoCodecMime.data(), "video/hevc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, false, HARDWARE);
+ } else if (!strcmp(videoCodecMime.data(), "video/vvc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_VVC, false, HARDWARE);
+ } else {
+ AVCODEC_SAMPLE_LOGE("INVALID MIMETYPE");
+ return AVCODEC_SAMPLE_ERR_ERROR;
+ }
+ break;
+ case VIDEO_SW_DECODER:
+ if (!strcmp(videoCodecMime.data(), "video/avc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, SOFTWARE);
+ } else if (!strcmp(videoCodecMime.data(), "video/hevc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, false, SOFTWARE);
+ } else if (!strcmp(videoCodecMime.data(), "video/vvc")) {
+ decoder_ = GetCodecByCategory(OH_AVCODEC_MIMETYPE_VIDEO_VVC, false, SOFTWARE);
+ } else {
+ AVCODEC_SAMPLE_LOGE("INVALID MIMETYPE");
+ return AVCODEC_SAMPLE_ERR_ERROR;
+ }
+ break;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::SetCallback(CodecUserData *codecUserData)
+{
+ int32_t ret = AV_ERR_OK;
+ ret = OH_VideoDecoder_RegisterCallback(decoder_,
+ {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
+ SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
+ codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::Configure(const SampleInfo &sampleInfo)
+{
+ OH_AVFormat *format = OH_AVFormat_Create();
+ CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");
+
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
+ OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.rotation);
+
+ AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======");
+ AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps", sampleInfo.videoWidth, sampleInfo.videoHeight,
+ sampleInfo.frameRate);
+ AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======");
+
+ int ret = OH_VideoDecoder_Configure(decoder_, format);
+ OH_AVFormat_Destroy(format);
+ format = nullptr;
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Config failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+ CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Invalid param: codecUserData");
+
+ // Configure video decoder
+ int32_t ret = Configure(sampleInfo);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed");
+
+ // SetSurface from video decoder
+ if (sampleInfo.window != nullptr) {
+ int ret = OH_VideoDecoder_SetSurface(decoder_, sampleInfo.window);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK && sampleInfo.window, AVCODEC_SAMPLE_ERR_ERROR,
+ "Set surface failed, ret: %{public}d", ret);
+ }
+
+ // SetCallback for video decoder
+ ret = SetCallback(codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
+ "Set callback failed, ret: %{public}d", ret);
+
+ // Prepare video decoder
+ {
+ int ret = OH_VideoDecoder_Prepare(decoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);
+ }
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::Start()
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int ret = OH_VideoDecoder_Start(decoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::PushInputBuffer(CodecBufferInfo &info)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+ int32_t ret = OH_VideoDecoder_PushInputBuffer(decoder_, info.bufferIndex);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Push input data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::FreeOutputBuffer(uint32_t bufferIndex, bool render)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int32_t ret = AVCODEC_SAMPLE_ERR_OK;
+ if (render) {
+ ret = OH_VideoDecoder_RenderOutputBuffer(decoder_, bufferIndex);
+ } else {
+ ret = OH_VideoDecoder_FreeOutputBuffer(decoder_, bufferIndex);
+ }
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Free output data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::FreeOutputBuffer(uint32_t bufferIndex, bool render, int64_t timeStamp)
+{
+ CHECK_AND_RETURN_RET_LOG(decoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int32_t ret = AVCODEC_SAMPLE_ERR_OK;
+ if (render) {
+ ret = OH_VideoDecoder_RenderOutputBufferAtTime(decoder_, bufferIndex, timeStamp);
+ } else {
+ ret = OH_VideoDecoder_FreeOutputBuffer(decoder_, bufferIndex);
+ }
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Free output data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoDecoder::Release()
+{
+ if (decoder_ != nullptr) {
+ OH_VideoDecoder_Destroy(decoder_);
+ decoder_ = nullptr;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_encoder.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_encoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c27c82445328bd749bc5b6f782976f0998d4093
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/capbilities/video_encoder.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "video_encoder.h"
+
+#undef LOG_TAG
+#define LOG_TAG "VideoEncoder"
+
+namespace {
+
+int32_t ToGraphicPixelFormat(int32_t avPixelFormat, bool isHDRVivid)
+{
+ if (isHDRVivid) {
+ return NATIVEBUFFER_PIXEL_FMT_YCBCR_P010;
+ }
+ switch (avPixelFormat) {
+ case AV_PIXEL_FORMAT_RGBA:
+ return NATIVEBUFFER_PIXEL_FMT_RGBA_8888;
+ case AV_PIXEL_FORMAT_YUVI420:
+ return NATIVEBUFFER_PIXEL_FMT_YCBCR_420_P;
+ case AV_PIXEL_FORMAT_NV21:
+ return NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP;
+ default: // NV12 and others
+ return NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP;
+ }
+}
+} // namespace
+
+VideoEncoder::~VideoEncoder()
+{
+ Release();
+}
+
+int32_t VideoEncoder::Create(const std::string &videoCodecMime)
+{
+ encoder_ = OH_VideoEncoder_CreateByMime(videoCodecMime.c_str());
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::Config(SampleInfo &sampleInfo, CodecUserData *codecUserData)
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
+ CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Invalid param: codecUserData");
+
+ // Configure video encoder
+ int32_t ret = Configure(sampleInfo);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed");
+
+ // GetSurface from video encoder
+ ret = GetSurface(sampleInfo);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Get surface failed");
+
+ // SetCallback for video encoder
+ ret = SetCallback(codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
+ "Set callback failed, ret: %{public}d", ret);
+
+ // Prepare video encoder
+ ret = OH_VideoEncoder_Prepare(encoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::Start()
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
+
+ int ret = OH_VideoEncoder_Start(encoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::PushInputBuffer(CodecBufferInfo &info)
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
+
+ int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast(info.buffer), &info.attr);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set avbuffer attr failed");
+ ret = OH_VideoEncoder_PushInputBuffer(encoder_, info.bufferIndex);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Push input data failed");
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::FreeOutputBuffer(uint32_t bufferIndex)
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
+
+ int32_t ret = OH_VideoEncoder_FreeOutputBuffer(encoder_, bufferIndex);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
+ "Free output data failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::NotifyEndOfStream()
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
+
+ int32_t ret = OH_VideoEncoder_NotifyEndOfStream(encoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
+ "Notify end of stream failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::Stop()
+{
+ CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
+
+ int ret = OH_VideoEncoder_Flush(encoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Flush failed, ret: %{public}d", ret);
+
+ ret = OH_VideoEncoder_Stop(encoder_);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Stop failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::Release()
+{
+ if (encoder_ != nullptr) {
+ OH_VideoEncoder_Destroy(encoder_);
+ encoder_ = nullptr;
+ }
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::SetCallback(CodecUserData *codecUserData)
+{
+ int32_t ret = OH_VideoEncoder_RegisterCallback(encoder_,
+ {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
+ SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
+ codecUserData);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);
+
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::Configure(const SampleInfo &sampleInfo)
+{
+ OH_AVFormat *format = OH_AVFormat_Create();
+ CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");
+
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
+ OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, sampleInfo.bitrateMode);
+ OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, sampleInfo.bitrate);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, sampleInfo.hevcProfile);
+ if (sampleInfo.isHDRVivid) {
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, sampleInfo.iFrameInterval);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, sampleInfo.rangFlag);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, sampleInfo.primary);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, sampleInfo.transfer);
+ OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, sampleInfo.matrix);
+ }
+ AVCODEC_SAMPLE_LOGI("====== VideoEncoder config ======");
+ AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps",
+ sampleInfo.videoWidth, sampleInfo.videoHeight, sampleInfo.frameRate);
+ // 1024: ratio of kbps to bps
+ AVCODEC_SAMPLE_LOGI("BitRate Mode: %{public}d, BitRate: %{public}" PRId64 "kbps",
+ sampleInfo.bitrateMode, sampleInfo.bitrate / 1024);
+ AVCODEC_SAMPLE_LOGI("====== VideoEncoder config ======");
+
+ int ret = OH_VideoEncoder_Configure(encoder_, format);
+ OH_AVFormat_Destroy(format);
+ format = nullptr;
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Config failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
+int32_t VideoEncoder::GetSurface(SampleInfo &sampleInfo)
+{
+ int32_t ret = OH_VideoEncoder_GetSurface(encoder_, &sampleInfo.window);
+ CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK && sampleInfo.window, AVCODEC_SAMPLE_ERR_ERROR,
+ "Get surface failed, ret: %{public}d", ret);
+ return AVCODEC_SAMPLE_ERR_OK;
+}
+
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h
new file mode 100644
index 0000000000000000000000000000000000000000..258ec92c243b0382f1b483671bee96f3a26856e5
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AVCODEC_SAMPLE_ERROE_H
+#define AVCODEC_SAMPLE_ERROE_H
+
+enum AVCodecSampleError : int {
+ AVCODEC_SAMPLE_ERR_OK = 0,
+ AVCODEC_SAMPLE_ERR_ERROR = -1,
+};
+
+#endif // AVCODEC_SAMPLE_ERROE_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h
new file mode 100644
index 0000000000000000000000000000000000000000..124aea62d4483bb882f6592b98667b316f544f2c
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AVCODEC_SAMPLE_LOG_H
+#define AVCODEC_SAMPLE_LOG_H
+
+#include
+#include
+
+#undef LOG_DOMAIN
+#define LOG_DOMAIN 0x0002B66
+
+#define AVCODEC_SAMPLE_LOG_FREQ_LIMIT(frequency) \
+ if (1) { \
+ thread_local uint64_t currentTimes = 0; \
+ if (currentTimes++ % ((uint64_t)(frequency)) != 0) { \
+ break; \
+ } \
+ }
+
+#define AVCODEC_SAMPLE_LOG(func, fmt, args...) \
+ do { \
+ (void)func(LOG_APP, "{%{public}s():%{public}d} " fmt, __FUNCTION__, __LINE__, ##args); \
+ } while (0)
+
+#define AVCODEC_SAMPLE_LOGF(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_FATAL, fmt, ##__VA_ARGS__)
+#define AVCODEC_SAMPLE_LOGE(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_ERROR, fmt, ##__VA_ARGS__)
+#define AVCODEC_SAMPLE_LOGW(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_WARN, fmt, ##__VA_ARGS__)
+#define AVCODEC_SAMPLE_LOGI(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_INFO, fmt, ##__VA_ARGS__)
+#define AVCODEC_SAMPLE_LOGD(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_DEBUG, fmt, ##__VA_ARGS__)
+#define AVCODEC_SAMPLE_LOGD_LIMIT(frequency, fmt, ...) \
+ do { \
+ AVCODEC_SAMPLE_LOG_FREQ_LIMIT(frequency); \
+ AVCODEC_SAMPLE_LOGD(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ AVCODEC_SAMPLE_LOGE(fmt, ##__VA_ARGS__); \
+ return ret; \
+ } \
+ } while (0)
+
+#define CHECK_AND_RETURN_LOG(cond, fmt, ...) \
+ do { \
+ if (!(cond)) { \
+ AVCODEC_SAMPLE_LOGE(fmt, ##__VA_ARGS__); \
+ return; \
+ } \
+ } while (0)
+
+#define CHECK_AND_BREAK_LOG(cond, fmt, ...) \
+ if (1) { \
+ if (!(cond)) { \
+ AVCODEC_SAMPLE_LOGW(fmt, ##__VA_ARGS__); \
+ break; \
+ } \
+ } else void (0)
+
+#define CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \
+ if (1) { \
+ if (!(cond)) { \
+ AVCODEC_SAMPLE_LOGW(fmt, ##__VA_ARGS__); \
+ continue; \
+ } \
+ } else void (0)
+
+#endif // AVCODEC_SAMPLE_LOG_H
\ No newline at end of file
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.cpp b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..27e53c53dfca44bb5efb9172e87b700c68d968de
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sample_callback.h"
+#include "av_codec_sample_log.h"
+
+namespace {
+constexpr int LIMIT_LOGD_FREQUENCY = 50;
+constexpr int32_t BYTES_PER_SAMPLE_2 = 2;
+} // namespace
+
+// 自定义写入数据函数
+int32_t SampleCallback::OnRenderWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length)
+{
+ (void)renderer;
+ (void)length;
+ CodecUserData *codecUserData = static_cast(userData);
+
+ // 将待播放的数据,按length长度写入buffer
+ uint8_t *dest = (uint8_t *)buffer;
+ size_t index = 0;
+ std::unique_lock lock(codecUserData->outputMutex);
+ // 从队列中取出需要播放的长度为length的数据
+ while (!codecUserData->renderQueue.empty() && index < length) {
+ dest[index++] = codecUserData->renderQueue.front();
+ codecUserData->renderQueue.pop();
+ }
+ AVCODEC_SAMPLE_LOGD("render BufferLength:%{public}d Out buffer count: %{public}u, renderQueue.size: %{public}u "
+ "renderReadSize: %{public}u",
+ length, codecUserData->outputFrameCount, codecUserData->renderQueue.size(), index);
+
+ codecUserData->frameWrittenForSpeed +=
+ length / codecUserData->speed / codecUserData->sampleInfo->audioChannelCount / BYTES_PER_SAMPLE_2;
+ codecUserData->currentPosAudioBufferPts =
+ codecUserData->endPosAudioBufferPts - codecUserData->renderQueue.size() /
+ codecUserData->sampleInfo->audioSampleRate /
+ codecUserData->sampleInfo->audioChannelCount / BYTES_PER_SAMPLE_2;
+
+ if (codecUserData->renderQueue.size() < length) {
+ codecUserData->renderCond.notify_all();
+ }
+ return 0;
+}
+// 自定义音频流事件函数
+int32_t SampleCallback::OnRenderStreamEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event)
+{
+ (void)renderer;
+ (void)userData;
+ (void)event;
+ // 根据event表示的音频流事件信息,更新播放器状态和界面
+ return 0;
+}
+// 自定义音频中断事件函数
+int32_t SampleCallback::OnRenderInterruptEvent(OH_AudioRenderer *renderer, void *userData,
+ OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
+{
+ (void)renderer;
+ (void)userData;
+ (void)type;
+ (void)hint;
+ // 根据type和hint表示的音频中断信息,更新播放器状态和界面
+ return 0;
+}
+// 自定义异常回调函数
+int32_t SampleCallback::OnRenderError(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error)
+{
+ (void)renderer;
+ (void)userData;
+ (void)error;
+ AVCODEC_SAMPLE_LOGE("OnRenderError");
+ // 根据error表示的音频异常信息,做出相应的处理
+ return 0;
+}
+
+void SampleCallback::OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
+{
+ (void)codec;
+ (void)errorCode;
+ (void)userData;
+ AVCODEC_SAMPLE_LOGE("On codec error, error code: %{public}d", errorCode);
+}
+
+void SampleCallback::OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
+{
+ AVCODEC_SAMPLE_LOGI("On codec format change");
+}
+
+void SampleCallback::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+ if (userData == nullptr) {
+ return;
+ }
+ (void)codec;
+ CodecUserData *codecUserData = static_cast(userData);
+ std::unique_lock lock(codecUserData->inputMutex);
+ if (codecUserData->isEncFirstFrame) {
+ OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(codec);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &codecUserData->width);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &codecUserData->height);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &codecUserData->widthStride);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &codecUserData->heightStride);
+ OH_AVFormat_Destroy(format);
+ codecUserData->isEncFirstFrame = false;
+ }
+ codecUserData->inputBufferInfoQueue.emplace(index, buffer);
+ codecUserData->inputCond.notify_all();
+}
+
+void SampleCallback::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+ if (userData == nullptr) {
+ return;
+ }
+ (void)codec;
+ CodecUserData *codecUserData = static_cast(userData);
+ std::unique_lock lock(codecUserData->outputMutex);
+ if (codecUserData->isDecFirstFrame) {
+ OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(codec);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &codecUserData->width);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &codecUserData->height);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &codecUserData->widthStride);
+ OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &codecUserData->heightStride);
+ OH_AVFormat_Destroy(format);
+ codecUserData->isDecFirstFrame = false;
+ }
+ codecUserData->outputBufferInfoQueue.emplace(index, buffer);
+ codecUserData->outputCond.notify_all();
+}
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1e1f60b2e7a49ab81102321ac324a81d43291a6
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_callback.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AVCODEC_SAMPLE_CALLBACK_H
+#define AVCODEC_SAMPLE_CALLBACK_H
+
+#include
+#include
+#include
+#include "sample_info.h"
+class SampleCallback {
+public:
+ static int32_t OnRenderWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length);
+ static int32_t OnRenderStreamEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event);
+ static int32_t OnRenderInterruptEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type,
+ OH_AudioInterrupt_Hint hint);
+ static int32_t OnRenderError(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error);
+
+ static void OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData);
+ static void OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
+ static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
+ static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
+};
+
+#endif // AVCODEC_SAMPLE_CALLBACK_H
diff --git a/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_info.h b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..79b22251ae9c422e061093c5a30cded28a69ddca
--- /dev/null
+++ b/code/BasicFeature/Media/AVCodec/entry/src/main/cpp/common/sample_info.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AVCODEC_SAMPLE_INFO_H
+#define AVCODEC_SAMPLE_INFO_H
+#include
+#include
+#include