• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 视频解码
2
3开发者可以调用本模块的Native API接口,完成视频解码,即将媒体数据解码成YUV文件或送显。
4
5当前支持的解码能力如下:
6
7| 视频硬解类型       | 视频软解类型   |
8| --------------------- | ---------------- |
9| AVC(H.264)、HEVC(H.265) |AVC(H.264) |
10
11视频解码软/硬件解码存在差异,基于MimeType创建解码器时,软解当前仅支持 H264 (OH_AVCODEC_MIMETYPE_VIDEO_AVC),硬解则支持 H264 (OH_AVCODEC_MIMETYPE_VIDEO_AVC) 和 H265 (OH_AVCODEC_MIMETYPE_VIDEO_HEVC)。
12
13## Surface输出与Buffer输出
14
15两者数据的输出方式不同。
16
17Surface输出是指用OHNativeWindow来传递输出数据,可以与其他模块对接,例如XComponent。
18
19Buffer输出是指经过解码的数据会以共享内存的方式输出。
20
21在接口调用的过程中,两种方式的接口调用方式基本一致,但存在以下差异点:
22
231. 在Surface模式下,可选择调用OH_VideoDecoder_FreeOutputBuffer()接口丢弃输出帧(不送显);在Buffer模式下,应用必须调用OH_VideoDecoder_FreeOutputBuffer()释放数据。
242. Surface模式下,应用在解码器就绪前,必须调用OH_VideoDecoder_SetSurface()设置OHNativeWindow,启动后,调用OH_VideoDecoder_RenderOutputBuffer()将解码数据送显;
253. 输出回调传出的buffer,在Buffer模式下,可以获取共享内存的地址和数据信息;在Surface模式下,只能获取buffer的数据信息。
26
27两种模式的开发步骤详细说明请参考:[Surface模式](#surface模式)和[Buffer模式](#buffer模式)。
28
29## 开发指导
30
31详细的API说明请参考[API文档](../../reference/apis-avcodec-kit/_video_decoder.md)。
32如下为视频解码调用关系图:
33![Invoking relationship of video decode stream](figures/video-decode.png)
34
35### 在 CMake 脚本中链接动态库
36
37``` cmake
38target_link_libraries(sample PUBLIC libnative_media_codecbase.so)
39target_link_libraries(sample PUBLIC libnative_media_core.so)
40target_link_libraries(sample PUBLIC libnative_media_vdec.so)
41```
42
43### Surface模式
44
45参考以下示例代码,开发者可以完成Surface模式下视频解码的全流程。此处以H.264码流文件输入,解码送显输出为例。
46本模块目前仅支持异步模式的数据轮转。
47
481. 添加头文件。
49
50    ```c++
51    #include <multimedia/player_framework/native_avcodec_videodecoder.h>
52    #include <multimedia/player_framework/native_avcapability.h>
53    #include <multimedia/player_framework/native_avcodec_base.h>
54    #include <multimedia/player_framework/native_avformat.h>
55    #include <multimedia/player_framework/native_avbuffer.h>
56    ```
57
582. 创建解码器实例对象。
59
60    应用可以通过名称或媒体类型创建解码器。示例中的变量说明如下:
61
62    - videoDec:视频解码器实例的指针。
63    - capability:解码器能力查询实例的指针。
64    - OH_AVCODEC_MIMETYPE_VIDEO_AVC:AVC格式视频码流的名称。
65
66    ```c++
67    // 通过codecname创建解码器,应用有特殊需求,比如选择支持某种分辨率规格的解码器,可先查询capability,再根据codec name创建解码器。
68    OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false);
69    const char *name = OH_AVCapability_GetName(capability);
70    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name);
71    ```
72
73    ```c++
74    // 通过mimetype创建解码器
75    // 软/硬解: 创建H264解码器,存在多个可选解码器时,系统会创建最合适的解码器
76    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
77    // 硬解: 创建H265解码器
78    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
79    ```
80
813. 调用OH_VideoDecoder_RegisterCallback()设置回调函数。
82
83    > **说明:**
84    >
85    > 在回调函数中,对数据队列进行操作时,需要注意多线程同步的问题。
86    >
87
88    注册回调函数指针集合OH_AVCodecCallback,包括:
89
90    - 解码器运行错误;
91    - 码流信息变化,如码流宽、高变化;
92    - 运行过程中需要新的输入数据,即解码器已准备好,可以输入数据;
93    - 运行过程中产生了新的输出数据,即解码完成。(注:Surface模式buffer参数为空)
94
95    开发者可以通过处理该回调报告的信息,确保解码器正常运转。
96
97    ```c++
98    // 解码异常回调OH_AVCodecOnError实现
99    static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
100    {
101        (void)codec;
102        (void)errorCode;
103        (void)userData;
104    }
105
106    // 解码数据流变化回调OH_AVCodecOnStreamChanged实现
107    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
108    {
109        (void)codec;
110        (void)format;
111        (void)userData;
112    }
113
114    // 解码输入回调OH_AVCodecOnNeedInputBuffer实现
115    static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
116    {
117        // 输入帧buffer对应的index,送入InIndexQueue队列
118        // 输入帧的数据buffer送入InBufferQueue队列
119        // 数据处理,请参考:
120        // - 写入解码码流
121    }
122
123    // 解码输出回调OH_AVCodecOnNewOutputBuffer实现
124    static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
125    {
126        // 完成帧buffer对应的index,送入outIndexQueue队列
127        // 完成帧的数据buffer送入outBufferQueue队列
128        // 数据处理,请参考:
129        // - 显示并释放解码帧
130    }
131    // 配置异步回调,调用 OH_VideoDecoder_RegisterCallback 接口
132    OH_AVCodecCallback cb = {&OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer};
133    // 配置异步回调
134    int32_t ret = OH_VideoDecoder_RegisterCallback(videoDec, cb, NULL);
135    ```
136
1374. 调用OH_VideoDecoder_Configure()配置解码器。
138
139    详细可配置选项的说明请参考[变量](../../reference/apis-avcodec-kit/_codec_base.md#变量)。
140    目前支持的所有格式都必须配置以下选项:视频帧宽度、视频帧高度。示例中的变量如下:
141
142    - DEFAULT_WIDTH:320像素宽度;
143    - DEFAULT_HEIGHT:240像素高度;
144    - DEFAULT_PIXELFORMAT: 颜色格式,因为示例需要保存的YUV文件颜色格式是NV12,所以设置为 AV_PIXEL_FORMAT_NV12。
145
146    ```c++
147    // 配置视频帧宽度(必须)
148    constexpr uint32_t DEFAULT_WIDTH = 320;
149    // 配置视频帧高度(必须)
150    constexpr uint32_t DEFAULT_HEIGHT = 240;
151    // 配置视频颜色格式(可选)
152    constexpr OH_AVPixelFormat DEFAULT_PIXELFORMAT = AV_PIXEL_FORMAT_NV12;
153
154    OH_AVFormat *format = OH_AVFormat_Create();
155    // 写入format
156    OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
157    OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
158    // 配置解码器
159    int32_t ret = OH_VideoDecoder_Configure(videoDec, format);
160    if (ret != AV_ERR_OK) {
161        // 异常处理
162    }
163    OH_AVFormat_Destroy(format);
164    ```
165
1665. 设置Surface。本例中的nativeWindow,需要从XComponent组件获取,获取方式请参考 [XComponent](../../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md)。
167
168    ```c++
169    // 配置送显窗口参数
170    int32_t ret = OH_VideoDecoder_SetSurface(videoDec, window);    // 从 XComponent 获取 window
171    ```
172
1736. (可选)OH_VideoDecoder_SetParameter()动态配置解码器surface参数。
174
175    ```c++
176    OH_AVFormat *format = OH_AVFormat_Create();
177    // 配置显示旋转角度
178    OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, 90);
179    // 配置视频与显示屏匹配模式(缩放与显示窗口适配,裁剪与显示窗口适配)
180    OH_AVFormat_SetIntValue(format, OH_MD_KEY_SCALING_MODE, SCALING_MODE_SCALE_CROP);
181    int32_t ret = OH_VideoDecoder_SetParameter(videoDec, format);
182    OH_AVFormat_Destroy(format);
183    ```
1847. (可选)OH_VideoDecoder_SetDecryptionConfig设置解密配置。当获取到DRM信息(参考[音视频解封装](audio-video-demuxer.md)开发步骤第3步)后,通过此接口进行解密配置。DRM相关接口详见[DRM使用指导](../../reference/apis-drm-kit)。此接口需在Prepare前调用。
185
186    添加头文件
187
188    ```c++
189    #include <multimedia/drm_framework/native_mediakeysystem.h>
190    #include <multimedia/drm_framework/native_mediakeysession.h>
191    #include <multimedia/drm_framework/native_drm_err.h>
192    #include <multimedia/drm_framework/native_drm_common.h>
193    ```
194    在 CMake 脚本中链接动态库
195
196    ``` cmake
197    target_link_libraries(sample PUBLIC libnative_drm.so)
198    ```
199
200    使用示例
201    ```c++
202    // 根据DRM信息创建指定的DRM系统, 以创建"com.clearplay.drm"为例
203    MediaKeySystem *system = nullptr;
204    int32_t ret = OH_MediaKeySystem_Create("com.clearplay.drm", &system);
205    if (system == nullptr) {
206        printf("create media key system failed");
207        return;
208    }
209    // 进行Provision认证
210    // 创建解密会话
211    MediaKeySession *session = nullptr;
212    DRM_ContentProtectionLevel contentProtectionLevel = CONTENT_PROTECTION_LEVEL_SW_CRYPTO;
213    ret = OH_MediaKeySystem_CreateMediaKeySession(system, &contentProtectionLevel, &session);
214    if (session == nullptr) {
215        printf("create media key session failed");
216        return;
217    }
218    // 获取许可证请求、设置许可证响应等
219    // 设置解密配置, 即将解密会话、安全视频通路标志设置到解码器中。
220    bool secureVideoPath = false;
221    ret = OH_VideoDecoder_SetDecryptionConfig(videoDec, session, secureVideoPath);
222    ```
223
2248. 调用OH_VideoDecoder_Prepare()解码器就绪。
225
226    该接口将在解码器运行前进行一些数据的准备工作。
227
228    ```c++
229    ret = OH_VideoDecoder_Prepare(videoDec);
230    if (ret != AV_ERR_OK) {
231        // 异常处理
232    }
233    ```
234
2359. 调用OH_VideoDecoder_Start()启动解码器。
236
237    ```c++
238    std::string_view inputFilePath = "/*yourpath*.h264";
239    std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>();
240    inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary);
241    // 启动解码器,开始解码
242    int32_t ret = OH_VideoDecoder_Start(videoDec);
243    if (ret != AV_ERR_OK) {
244        // 异常处理
245    }
246    ```
247
24810. 调用OH_VideoDecoder_PushInputBuffer()写入解码码流。
249
250    送入输入队列进行解码,以下示例中:
251
252    - buffer:回调函数OnNeedInputBuffer传入的参数,可以通过OH_AVBuffer_GetAddr接口得到共享内存地址的指针;
253    - index:回调函数OnNeedInputBuffer传入的参数,数据队列的索引;
254    - size, offset, pts:输入尺寸、偏移量、时间戳等字段信息,获取方式可以参考[音视频解封装](./audio-video-demuxer.md)
255    - flags:缓冲区标记的类别,请参考[OH_AVCodecBufferFlags](../../reference/apis-avcodec-kit/_core.md#oh_avcodecbufferflags)
256
257    ```c++
258    // 配置帧数据的输入尺寸、偏移量、时间戳等字段信息
259    OH_AVCodecBufferAttr info;
260    info.size = size;
261    info.offset = offset;
262    info.pts = pts;
263    info.flags = flags;
264    // info信息写入buffer
265    ret = OH_AVBuffer_SetBufferAttr(buffer, &info);
266    if (ret != AV_ERR_OK) {
267        // 异常处理
268    }
269    // 送入解码输入队列进行解码,index为对应队列下标
270    int32_t ret = OH_VideoDecoder_PushInputBuffer(videoDec, index);
271    if (ret != AV_ERR_OK) {
272        // 异常处理
273    }
274    ```
275
27611. 调用OH_VideoDecoder_RenderOutputBuffer()显示并释放解码帧,或调用OH_VideoDecoder_FreeOutputBuffer()释放解码帧。
277    以下示例中:
278
279    - index:回调函数OnNewOutputBuffer传入的参数,数据队列的索引。
280    - buffer: 回调函数OnNewOutputBuffer传入的参数,可以通过OH_AVBuffer_GetAddr接口得到共享内存地址的指针。
281
282    ```c++
283    int32_t ret;
284    // 获取解码后信息
285    OH_AVCodecBufferAttr info;
286    ret = OH_AVBuffer_GetBufferAttr(buffer, &info);
287    if (ret != AV_ERR_OK) {
288        // 异常处理
289    }
290    if (isRender) {
291        // 显示并释放已完成处理的信息,index为对应buffer队列下标
292        ret = OH_VideoDecoder_RenderOutputBuffer(videoDec, index);
293    } else  {
294        // 释放已完成处理的信息
295        ret = OH_VideoDecoder_FreeOutputBuffer(videoDec, index);
296    }
297    if (ret != AV_ERR_OK) {
298        // 异常处理
299    }
300    ```
301
30212. (可选)调用OH_VideoDecoder_Flush()刷新解码器。
303
304    > **注意:**
305    >
306    > Flush、Start之后,需要重新传XPS。
307    >
308
309    调用OH_VideoDecoder_Flush()后,解码器仍处于运行态,但会将当前队列清空,将已解码的数据释放。
310
311    此时需要调用OH_VideoDecoder_Start()重新开始解码。
312
313    ```c++
314    int32_t ret;
315    // 刷新解码器videoDec
316    ret = OH_VideoDecoder_Flush(videoDec);
317    if (ret != AV_ERR_OK) {
318        // 异常处理
319    }
320    // 重新开始解码
321    ret = OH_VideoDecoder_Start(videoDec);
322    if (ret != AV_ERR_OK) {
323        // 异常处理
324    }
325    ```
326
32713. (可选)调用OH_VideoDecoder_Reset()重置解码器。
328
329    调用OH_VideoDecoder_Reset()后,解码器回到初始化的状态,需要调用OH_VideoDecoder_Configure()、OH_VideoDecoder_SetSurface()重新配置。
330
331    ```c++
332     int32_t ret;
333     // 重置解码器videoDec
334     ret = OH_VideoDecoder_Reset(videoDec);
335     if (ret != AV_ERR_OK) {
336         // 异常处理
337     }
338     // 重新配置解码器参数
339     ret = OH_VideoDecoder_Configure(videoDec, format);
340     if (ret != AV_ERR_OK) {
341         // 异常处理
342     }
343     // surface模式重新配置Surface,而buffer模式不需要配置Surface
344     ret = OH_VideoDecoder_SetSurface(videoDec, window);
345     if (ret != AV_ERR_OK) {
346         // 异常处理
347     }
348    ```
349
35014. (可选)调用OH_VideoDecoder_Stop()停止解码器。
351
352    ```c++
353     int32_t ret;
354     // 终止解码器videoDec
355     ret = OH_VideoDecoder_Stop(videoDec);
356     if (ret != AV_ERR_OK) {
357         // 异常处理
358     }
359    ```
360
36115. 调用OH_VideoDecoder_Destroy()销毁解码器实例,释放资源。
362
363    > **说明:**
364    >
365    > 不能在回调函数中调用;
366    > 执行该步骤之后,需要开发者将videoDec指向nullptr,防止野指针导致程序错误。
367    >
368
369    ```c++
370     int32_t ret;
371     // 调用OH_VideoDecoder_Destroy,注销解码器
372     ret = OH_VideoDecoder_Destroy(videoDec);
373     if (ret != AV_ERR_OK) {
374         // 异常处理
375     }
376    ```
377
378### Buffer模式
379
380参考以下示例代码,开发者可以完成Buffer模式下视频解码的全流程。此处以H.264文件输入,解码成YUV文件为例。
381本模块目前仅支持异步模式的数据轮转。
382
3831. 添加头文件。
384
385    ```c++
386    #include <multimedia/player_framework/native_avcodec_videodecoder.h>
387    #include <multimedia/player_framework/native_avcapability.h>
388    #include <multimedia/player_framework/native_avcodec_base.h>
389    #include <multimedia/player_framework/native_avformat.h>
390    #include <multimedia/player_framework/native_avbuffer.h>
391    #include <native_buffer/native_buffer.h>
392    ```
393
3942. 创建解码器实例对象。
395
396    与surface模式相同,此处不再赘述。
397
398    ```c++
399    // 通过codecname创建解码器,应用有特殊需求,比如选择支持某种分辨率规格的解码器,可先查询capability,再根据codec name创建解码器。
400    OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false);
401    const char *name = OH_AVCapability_GetName(capability);
402    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name);
403    ```
404
405    ```c++
406    // 通过mimetype创建解码器
407    // 软/硬解: 创建H264解码器,存在多个可选解码器时,系统会创建最合适的解码器
408    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
409    // 硬解: 创建H265解码器
410    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
411    ```
412
4133. 调用OH_VideoDecoder_RegisterCallback()设置回调函数。
414
415    > **说明:**
416    >
417    > 在回调函数中,对数据队列进行操作时,需要注意多线程同步的问题。
418    >
419
420    注册回调函数指针集合OH_AVCodecCallback,包括:
421
422    - 解码器运行错误;
423    - 码流信息变化,如码流宽、高变化;
424    - 运行过程中需要新的输入数据,即解码器已准备好,可以输入数据;
425    - 运行过程中产生了新的输出数据,即解码完成。
426
427    开发者可以通过处理该回调报告的信息,确保解码器正常运转。
428
429    ```c++
430    // 解码异常回调OH_AVCodecOnError实现
431    static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
432    {
433        (void)codec;
434        (void)errorCode;
435        (void)userData;
436    }
437
438    // 解码数据流变化回调OH_AVCodecOnStreamChanged实现
439    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
440    {
441        (void)codec;
442        (void)format;
443        (void)userData;
444    }
445
446    // 解码输入回调OH_AVCodecOnNeedInputBuffer实现
447    static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
448    {
449        // 输入帧buffer对应的index,送入InIndexQueue队列
450        // 输入帧的数据buffer送入InBufferQueue队列
451        // 数据处理,请参考:
452        // - 写入解码码流
453    }
454
455    // 解码输出回调OH_AVCodecOnNewOutputBuffer实现
456    static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
457    {
458        // 完成帧buffer对应的index,送入outIndexQueue队列
459        // 完成帧的数据buffer送入outBufferQueue队列
460        // 数据处理,请参考:
461        // - 释放解码帧
462    }
463    // 配置异步回调,调用 OH_VideoDecoder_RegisterCallback 接口
464    OH_AVCodecCallback cb = {&OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer};
465    // 配置异步回调
466    int32_t ret = OH_VideoDecoder_RegisterCallback(videoDec, cb, NULL);
467    ```
468
4694. 调用OH_VideoDecoder_Configure()配置解码器。
470
471    与surface模式相同,此处不再赘述。
472
473    ```c++
474    // 配置视频帧宽度(必须)
475    constexpr uint32_t DEFAULT_WIDTH = 320;
476    // 配置视频帧高度(必须)
477    constexpr uint32_t DEFAULT_HEIGHT = 240;
478    // 配置视频颜色格式(可选)
479    constexpr OH_AVPixelFormat DEFAULT_PIXELFORMAT = AV_PIXEL_FORMAT_NV12;
480
481    OH_AVFormat *format = OH_AVFormat_Create();
482    // 写入format
483    OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
484    OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
485    OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXELFORMAT);
486    // 配置解码器
487    int32_t ret = OH_VideoDecoder_Configure(videoDec, format);
488    if (ret != AV_ERR_OK) {
489        // 异常处理
490    }
491    OH_AVFormat_Destroy(format);
492    ```
493
4945. 调用OH_VideoDecoder_Prepare()解码器就绪。
495
496    该接口将在解码器运行前进行一些数据的准备工作。
497
498    ```c++
499    ret = OH_VideoDecoder_Prepare(videoDec);
500    if (ret != AV_ERR_OK) {
501        // 异常处理
502    }
503    ```
504
5056. 调用OH_VideoDecoder_Start()启动解码器。
506
507    ```c++
508    std::string_view inputFilePath = "/*yourpath*.h264";
509    std::string_view outputFilePath = "/*yourpath*.yuv";
510    std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>();
511    std::unique_ptr<std::ofstream> outputFile = std::make_unique<std::ofstream>();
512    inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary);
513    outputFile->open(outputFilePath.data(), std::ios::out | std::ios::binary | std::ios::ate);
514    // 启动解码器,开始解码
515    int32_t ret = OH_VideoDecoder_Start(videoDec);
516    if (ret != AV_ERR_OK) {
517        // 异常处理
518    }
519    ```
520
5217. 调用OH_VideoDecoder_PushInputBuffer()写入解码码流。
522
523    与surface模式相同,此处不再赘述。
524
525    ```c++
526    // 配置帧数据的输入尺寸、偏移量、时间戳等字段信息
527    OH_AVCodecBufferAttr info;
528    info.size = size;
529    info.offset = offset;
530    info.pts = pts;
531    info.flags = flags;
532    // info信息写入buffer
533    ret = OH_AVBuffer_SetBufferAttr(buffer, &info);
534    if (ret != AV_ERR_OK) {
535        // 异常处理
536    }
537    // 送入解码输入队列进行解码,index为对应队列下标
538    int32_t ret = OH_VideoDecoder_PushInputBuffer(videoDec, index);
539    if (ret != AV_ERR_OK) {
540        // 异常处理
541    }
542    ```
543
5448. 调用OH_VideoDecoder_FreeOutputBuffer()释放解码帧。
545
546    以下示例中:
547
548    - index:回调函数OnNewOutputBuffer传入的参数,数据队列的索引。
549    - buffer: 回调函数OnNewOutputBuffer传入的参数,可以通过OH_AVBuffer_GetAddr接口得到共享内存地址的指针。
550
551    ```c++
552    int32_t ret;
553    // 获取解码后信息
554    OH_AVCodecBufferAttr info;
555    ret = OH_AVBuffer_GetBufferAttr(buffer, &info);
556    if (ret != AV_ERR_OK) {
557        // 异常处理
558    }
559    // 将解码完成数据data写入到对应输出文件中
560    outputFile->write(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(buffer)), info.size);
561    // buffer 模式,释放已完成写入的数据,index为对应buffer队列下标
562    ret = OH_VideoDecoder_FreeOutputBuffer(videoDec, index);
563    if (ret != AV_ERR_OK) {
564        // 异常处理
565    }
566    ```
567
568    硬件解码在处理buffer数据时(释放数据前),一般需要获取数据的宽高、跨距来保证解码输出数据被正确的处理,请参考图形子系统 [OH_NativeBuffer](../../reference/apis-arkgraphics2d/_o_h___native_buffer.md)。
569
570    ```c++
571    // OH_NativeBuffer *可以通过图形模块的接口可以获取数据的宽高、跨距等信息。
572    OH_NativeBuffer *ohNativeBuffer = OH_AVBuffer_GetNativeBuffer(buffer);
573    if (ohNativeBuffer != nullptr) {
574        // 获取OH_NativeBuffer_Config结构体,包含OH_NativeBuffer的数据信息
575        OH_NativeBuffer_Config config;
576        OH_NativeBuffer_GetConfig(ohNativeBuffer, &config);
577
578        // 释放ohNativeBuffer
579        ret = OH_NativeBuffer_Unreference(ohNativeBuffer);
580        if (ret != AV_ERR_OK) {
581            // 异常处理
582        }
583        ohNativeBuffer = nullptr;
584    }
585    ```
586
587后续流程(包括刷新解码器、重置解码器、停止解码器、销毁解码器)与Surface模式基本一致,请参考[Surface模式](#surface模式)的步骤11-14。
588