• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Video Decoding
2
3You can call the native APIs provided by the **VideoDecoder** module to decode video, that is, to decode media data into a YUV file or send it for display.
4
5Currently, the following decoding capabilities are supported:
6
7| Container Specification| Video Hardware Decoding Type      | Video Software Decoding Type  |
8| -------- | --------------------- | ---------------- |
9| mp4      | AVC (H.264), HEVC (H.265)|AVC (H.264) |
10
11
12Video software decoding and hardware decoding are different. When a decoder is created based on the MIME type, only H.264 (video/avc) is supported for software decoding, and H.264 (video/avc) and H.265 (video/hevc) are supported for hardware decoding.
13
14## How to Develop
15
16Read [VideoDecoder](../reference/native-apis/_video_decoder.md) for the API reference.
17
18The figure below shows the call relationship of video decoding.
19
20![Call relationship of video decoding](figures/video-decode.png)
21
22### Linking the Dynamic Library in the CMake Script
23``` cmake
24target_link_libraries(sample PUBLIC libnative_media_codecbase.so)
25target_link_libraries(sample PUBLIC libnative_media_core.so)
26target_link_libraries(sample PUBLIC libnative_media_vdec.so)
27```
28
29### How to Develop
30
311. Create a decoder instance.
32
33   You can create a decoder by name or MIME type.
34
35   ``` c++
36    // To create a decoder by name, call OH_AVCapability_GetName to obtain the codec names available and then call OH_VideoDecoder_CreateByName. If your application has special requirements, for example, expecting a decoder that supports a certain resolution, you can call OH_AVCodec_GetCapability to query the capability first.
37    OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false);
38    const char *name = OH_AVCapability_GetName(capability);
39    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name);
40   ```
41   ```c++
42    // Create a decoder by MIME type.
43    // Create an H.264 decoder for software/hardware decoding. The system creates the most appropriate decoder if multiple decoders are available.
44    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
45    // Create an H.265 decoder for hardware decoding.
46    OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
47   ```
48   ``` c++
49   // Initialize the queues.
50   class VDecSignal {
51   public:
52       std::mutex inMutex_;
53       std::mutex outMutex_;
54       std::condition_variable inCond_;
55       std::condition_variable outCond_;
56       std::queue<uint32_t> inQueue_;
57       std::queue<uint32_t> outQueue_;
58       std::queue<OH_AVMemory *> inBufferQueue_;
59       std::queue<OH_AVMemory *> outBufferQueue_;
60       std::queue<OH_AVCodecBufferAttr> attrQueue_;
61   };
62   VDecSignal *signal_;
63   ```
64
652. Call **OH_VideoDecoder_SetCallback()** to set callback functions.
66
67   Register the **OH_AVCodecAsyncCallback** struct that defines the following callback function pointers:
68
69   - **OH_AVCodecOnError**, a callback used to report a codec operation error
70   - **OH_AVCodecOnStreamChanged**, a callback used to report a codec stream change, for example, stream width or height change.
71   - **OH_AVCodecOnNeedInputData**, a callback used to report input data required, which means that the decoder is ready for receiving data
72   - **OH_AVCodecOnNewOutputData**, a callback used to report output data generated, which means that decoding is complete (Note: The **data** parameter in the callback function is empty in surface output mode.)
73
74   You need to process the callback functions to ensure that the decoder runs properly.
75
76   ``` c++
77    // Implement the OH_AVCodecOnError callback function.
78    static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
79    {
80        (void)codec;
81        (void)errorCode;
82        (void)userData;
83    }
84
85    // Implement the OH_AVCodecOnStreamChanged callback function.
86    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
87    {
88        (void)codec;
89        (void)format;
90        (void)userData;
91    }
92
93    // Implement the OH_AVCodecOnNeedInputData callback function.
94    static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
95    {
96        (void)codec;
97        VDecSignal *signal_ = static_cast<VDecSignal *>(userData);
98        std::unique_lock<std::mutex> lock(signal_->inMutex_);
99        // The ID of the input frame is sent to inQueue_.
100        signal_->inQueue_.push(index);
101        // The input frame data is sent to inBufferQueue_.
102        signal_->inBufferQueue_.push(data);
103        signal_->inCond_.notify_all();
104    }
105
106    // Implement the OH_AVCodecOnNewOutputData callback function.
107    static void OnNeedOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
108                                        void *userData)
109    {
110        (void)codec;
111        VDecSignal *signal_ = static_cast<VDecSignal *>(userData);
112        std::unique_lock<std::mutex> lock(signal_->outMutex_);
113        // The index of the output buffer is sent to outQueue_.
114        signal_->outQueue_.push(index);
115        // The decoded data (specified by data) is sent to outBufferQueue_. (Note: data is empty in surface output mode.)
116        signal_->outBufferQueue_.push(data);
117        signal_->attrQueue_.push(*attr);
118        signal_->outCond_.notify_all();
119    }
120    OH_AVCodecAsyncCallback cb = {&OnError, &OnStreamChanged, &OnNeedInputData, &OnNeedOutputData};
121    // Set the asynchronous callbacks.
122    int32_t ret = OH_VideoDecoder_SetCallback(videoDec, cb, signal_);
123   ```
124
1253. Call **OH_VideoDecoder_Configure()** to configure the decoder.
126
127   The following options are mandatory: video frame width, video frame height, and video color format.
128
129   ``` c++
130    // (Mandatory) Configure the video frame width.
131    constexpr uint32_t DEFAULT_WIDTH = 320;
132    // (Mandatory) Configure the video frame height.
133    constexpr uint32_t DEFAULT_HEIGHT = 240;
134    OH_AVFormat *format = OH_AVFormat_Create();
135    // Set the format.
136    OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
137    OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
138    OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV21);
139    // Configure the decoder.
140    int32_t ret = OH_VideoDecoder_Configure(videoDec, format);
141    OH_AVFormat_Destroy(format);
142   ```
143
1444. (Optional) Set the surface.
145
146   This step is required only when the surface is used to send the data for display. The application obtains the native window from the XComponent. For details about the process, see [XComponent](../reference/arkui-ts/ts-basic-components-xcomponent.md).
147
148   ``` c++
149    // Set the parameters of the display window.
150    int32_t ret = OH_VideoDecoder_SetSurface(videoDec, window); // Obtain the window from the XComponent.
151    bool isSurfaceMode = true;
152   ```
153
1545. (Optional) Configure the surface parameters of the decoder. This step is required only when the surface is used.
155
156   ``` c++
157    OH_AVFormat *format = OH_AVFormat_Create();
158    // Configure the display rotation angle.
159    OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, 90);
160    // Configure the matching mode (scaling or cropping) between the video and the display screen.
161    OH_AVFormat_SetIntValue(format, OH_MD_KEY_SCALING_MODE, SCALING_MODE_SCALE_CROP);
162    int32_t ret = OH_VideoDecoder_SetParameter(videoDec, format);
163    OH_AVFormat_Destroy(format);
164   ```
165
1666. Call **OH_VideoDecoder_Start()** to start the decoder.
167
168   ``` c++
169    string_view outputFilePath = "/*yourpath*.yuv";
170    std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>();
171    // Open the path of the binary file to be decoded.
172    inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary);
173    // Configure the parameter in buffer mode.
174    if(!isSurfaceMode) {
175        // Configure the output file path in buffer mode.
176        std::unique_ptr<std::ofstream> outFile = std::make_unique<std::ofstream>();
177        outFile->open(outputFilePath.data(), std::ios::out | std::ios::binary);
178    }
179    // Start decoding.
180    int32_t ret = OH_VideoDecoder_Start(videoDec);
181   ```
182
1837. Call **OH_VideoDecoder_PushInputData()** to push the stream to the input queue for decoding.
184
185   ``` c++
186    // Configure the buffer information.
187    OH_AVCodecBufferAttr info;
188    // Call av_packet_alloc of FFmpeg to initialize and return a container packet.
189    AVPacket pkt = av_packet_alloc();
190    // Configure the input size, offset, and timestamp of the buffer.
191    info.size = pkt->size;
192    info.offset = 0;
193    info.pts = pkt->pts;
194    info.flags = AVCODEC_BUFFER_FLAGS_NONE;
195    // Send the data to the input queue for decoding. The index is the subscript of the queue.
196    int32_t ret = OH_VideoDecoder_PushInputData(videoDec, index, info);
197   ```
198
1998. In surface display mode, call **OH_VideoDecoder_RenderOutputData()** to display and release the decoded frames. In the surface no display mode or buffer mode, call **OH_VideoDecoder_FreeOutputData()** to the release decoded frames.
200
201``` c++
202    int32_t ret;
203    // Write the decoded data (specified by data) to the output file.
204    outFile->write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), data.size);
205    // Free the buffer that stores the output data. The index is the subscript of the surface/buffer queue.
206    if (isSurfaceMode && isRender) {
207        ret = OH_VideoDecoder_RenderOutputData(videoDec, index);
208    } else {
209        ret = OH_VideoDecoder_FreeOutputData(videoDec, index);
210    }
211    if (ret != AV_ERR_OK) {
212        // Exception handling.
213    }
214   ```
215
2169. (Optional) Call **OH_VideoDecoder_Flush()** to refresh the decoder.
217
218   After **OH_VideoDecoder_Flush()** is called, the decoder remains in the running state, but the current queue is cleared and the buffer storing the decoded data is freed.
219
220   To continue decoding, you must call **OH_VideoDecoder_Start()** again.
221
222   ``` c++
223    int32_t ret;
224    // Refresh the decoder.
225    ret = OH_VideoDecoder_Flush(videoDec);
226    if (ret != AV_ERR_OK) {
227        // Exception handling.
228    }
229    // Start decoding again.
230    ret = OH_VideoDecoder_Start(videoDec);
231   ```
232
23310. (Optional) Call **OH_VideoDecoder_Reset()** to reset the decoder.
234
235    After **OH_VideoDecoder_Reset()** is called, the decoder returns to the initialized state. To continue decoding, you must call **OH_VideoDecoder_Configure()** and then **OH_VideoDecoder_Start()**.
236
237    ``` c++
238     int32_t ret;
239     // Reset the decoder.
240     ret = OH_VideoDecoder_Reset(videoDec);
241     if (ret != AV_ERR_OK) {
242         // Exception handling.
243     }
244     // Reconfigure the decoder.
245     ret = OH_VideoDecoder_Configure(videoDec, format);
246    ```
247
24811. Call **OH_VideoDecoder_Stop()** to stop the decoder.
249
250    ``` c++
251     int32_t ret;
252     // Stop the decoder.
253     ret = OH_VideoDecoder_Stop(videoDec);
254     if (ret != AV_ERR_OK) {
255         // Exception handling.
256     }
257    ```
258
25912. Call **OH_VideoDecoder_Destroy()** to destroy the decoder instance and release resources.
260
261    ``` c++
262     int32_t ret;
263     // Call OH_VideoDecoder_Destroy to destroy the decoder.
264     ret = OH_VideoDecoder_Destroy(videoDec);
265     if (ret != AV_ERR_OK) {
266         // Exception handling.
267     }
268    ```
269