1# 创建视频解码器和NativeWindow初始化并行
2
3## 场景介绍
4
5为了解码Surface模式的正常创建,在XComponent尚未创建或OpenGL后处理(NativeImage)尚未初始化的情况下,
6可以创建一个空的surface,以确保视频解码器能够正常创建和运行。
7
8
9## 开发步骤
10
11以下步骤描述了在surface的消费端没有创建之前,如何并行创建视频解码器和NativeWindow,让视频解码器正常创建执行。
12
13**添加动态链接库**
14
15``` cmake
16target_link_libraries(sample PUBLIC libnative_image.so)
17target_link_libraries(sample PUBLIC libnative_window.so)
18target_link_libraries(sample PUBLIC libnative_buffer.so)
19target_link_libraries(sample PUBLIC libnative_media_vdec.so)
20```
21
22> **说明:**
23>
24> 上述'sample'字样仅为示例,此处由调用者根据实际工程目录自定义。
25>
26
27**头文件**
28
29```c++
30#include <iostream>
31#include <string>
32#include <native_image/native_image.h>
33#include <native_window/external_window.h>
34#include <native_buffer/native_buffer.h>
35#include <multimedia/player_framework/native_avcodec_videodecoder.h>
36```
37
381. 创建OH_NativeImage实例。
39
40    ```c++
41    // 创建NativeImage实例,作为surface的消费者
42    OH_NativeImage* image = OH_ConsumerSurface_Create();
43    ```
44
452. 获取对应的数据生产者端NativeWindow。
46
47    ```c++
48    // 获取生产者NativeWindow
49    OHNativeWindow* nativeImageWindow = OH_NativeImage_AcquireNativeWindow(image);
50    ```
51
523. 设置NativeWindow的宽高。
53
54    ```c++
55    int code = SET_BUFFER_GEOMETRY;
56    int32_t width = 800;
57    int32_t height = 600;
58    int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeImageWindow, code, width, height);
59    if (ret != AV_ERR_OK) {
60        // 异常处理
61    }
62    ```
63
644. 注册NativeImage的回调函数。
65
66    注册OH_NativeImage的监听者OH_OnFrameAvailableListener,包括:
67
68    - context 用户自定义的上下文信息;
69    - onFrameAvailable 有buffer可获取触发时的回调函数。
70
71    ```c++
72    // onFrameAvailable实现
73    static void onFrameAvailable()
74    {
75      OHNativeWindowBuffer *buffer = nullptr;
76      int fenceFd;
77      // 通过消费端的OH_NativeImage获取一个OHNativeWindowBuffer
78      OH_NativeImage_AcquireNativeWindowBuffer(image, &buffer, &fenceFd);
79      // 通过OH_NativeImage实例将OHNativeWindowBuffer归还到buffer队列中
80      OH_NativeImage_ReleaseNativeWindowBuffer(image, &buffer, &fenceFd);
81    }
82
83    static void context()
84    {
85      // 调用者自定义的上下文信息
86    }
87
88    // 设置回调监听者
89    OH_OnFrameAvailableListener listener = {&onFrameAvailable, &context};
90    // 设置帧可用回调
91    ret = OH_NativeImage_SetOnFrameAvailableListener(image, listener);
92    if (ret != AV_ERR_OK) {
93        // 异常处理
94    }
95    ```
96
97    > **说明:**
98    >
99    > 在此示例中,回调函数的实现仅仅是将buffer取出来并释放,调用者可以根据业务需求自行拓展。
100    >
101
1025. 配置解码器。
103
104    具体开发指导请参考[视频解码Surface模式](video-decoding.md#surface模式)“步骤-5:调用OH_VideoDecoder_Configure()配置解码器”。
105
1066. 设置surface。
107
108    在应用业务真正的surface消费端创建成功之前,可以先使用上面临时创建的消费端连接解码器。
109
110    示例中的变量说明如下:
111    - videoDec:视频解码器实例的指针。创建方式可参考[视频解码Surface模式](video-decoding.md#surface模式)“步骤-2:创建解码器实例对象”。
112
113    ```c++
114
115    ret = OH_VideoDecoder_SetSurface(videoDec, nativeImageWindow);
116    if (ret != AV_ERR_OK) {
117        // 异常处理
118    }
119    ```
120
1217. 启动解码器。
122
123    具体开发指导请参考[视频解码Surface模式](video-decoding.md#surface模式)“步骤-9:调用OH_VideoDecoder_Start()启动解码器”。
124
125
1268. 设置surface。
127
128    在应用业务真正的surface消费端创建成功后,可以调用OH_VideoDecoder_SetSurface接口,将解码输出重定向到新的surface上。
129
130    本例中的nativeWindow,有两种方式获取:
131    1. 如果解码后直接显示,则从XComponent组件获取,获取方式请参考 [XComponent](../../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md);
132    2. 如果解码后接OpenGL后处理,则从NativeImage获取,获取方式请参考 [NativeImage](../../graphics/native-image-guidelines.md)。
133
134    ```c++
135
136    ret = OH_VideoDecoder_SetSurface(videoDec, nativeWindow);
137    if (ret != AV_ERR_OK) {
138        // 异常处理
139    }
140    ```
141
1429. 销毁OH_NativeImage实例。
143
144   在调用OH_VideoDecoder_Destroy接口后,调用OH_NativeImage_Destroy接口销毁OH_NativeImage实例
145   ```c++
146   // 销毁OH_NativeImage实例
147   OH_NativeImage_Destroy(&image);
148   ```