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 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