1# Synchronous Video Decoding 2 3<!--Kit: AVCodec Kit--> 4<!--Subsystem: Multimedia--> 5<!--Owner: @zhanghongran--> 6<!--Designer: @dpy2650---> 7<!--Tester: @cyakee--> 8<!--Adviser: @zengyawen--> 9 10Starting from API version 20, video decoding in synchronous mode is supported. 11 12You can call native APIs to perform synchronous video decoding. 13 14For details about the supported decoding capabilities, see [AVCodec Supported Formats](avcodec-support-formats.md#video-decoding). 15 16For details about the restrictions, supported capabilities, and state machine call relationships of video decoding, see [Video Decoding](video-decoding.md). 17 18## When to Use 19 20Asynchronous mode is generally recommended for most use cases. Synchronous mode can be used if you need to actively request buffers for frame delivery. 21 22 23## How to Develop 24 25Read [VideoDecoder](../../reference/apis-avcodec-kit/_video_decoder.md) for the API reference. 26 27The figure below shows the call relationship of synchronous video decoding. 28 29- The dotted line indicates an optional operation. 30 31- The solid line indicates a mandatory operation. 32 33 34 35### Linking the Dynamic Libraries in the CMake Script 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> **NOTE** 44> 45> The word **sample** in the preceding code snippet is only an example. Use the actual project directory name. 46> 47 48### Defining the Basic Structure 49 50The sample code provided in this section adheres to the C++17 standard and is for reference only. 51 521. Add the header files. 53 54 ```c++ 55 #include <multimedia/player_framework/native_avcodec_videodecoder.h> 56 #include <multimedia/player_framework/native_avcapability.h> 57 #include <multimedia/player_framework/native_avcodec_base.h> 58 #include <multimedia/player_framework/native_avformat.h> 59 #include <multimedia/player_framework/native_avbuffer.h> 60 #include <multimedia/player_framework/native_averrors.h> 61 #include <native_buffer/native_buffer.h> 62 #include <memory> 63 #include <fstream> 64 #include <mutex> 65 #include <shared_mutex> 66 #include <string.h> 67 ``` 68 692. Configure global variables. 70 71 These global variables are for reference only. They can be encapsulated into an object based on service requirements. 72 73 ```c++ 74 // Video frame width. 75 int32_t width = 320; 76 // Video frame height. 77 int32_t height = 240; 78 // Video pixel format. 79 OH_AVPixelFormat pixelFormat = AV_PIXEL_FORMAT_NV12; 80 // Decoder synchronization lock. 81 std::shared_mutex codecMutex; 82 // Pointer to the decoder instance. 83 OH_AVCodec *videoDec = nullptr; 84 // Decoding output. 85 bool outputDone = false; 86 // Decoding input. 87 bool inputDone = false; 88 std::unique_ptr<std::ifstream> inFile_; 89 ``` 90 91### Surface Mode 92 93The following walks you through how to implement the entire video decoding process in surface mode and implement data rotation in synchronous mode. In this example, an H.264 stream file is input, decoded, and rendered. 94 95 961. Create a decoder instance. 97 98 Create a decoder by name. In the code snippet below, the following variables are used: 99 100 - **videoDec**: pointer to the video decoder instance. 101 - **capability**: pointer to the decoder's capability. 102 - **OH_AVCODEC_MIMETYPE_VIDEO_AVC**: AVC video codec. 103 104 ```c++ 105 // Create a hardware decoder instance. 106 OH_AVCapability *capability= OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, HARDWARE); 107 const char *name = OH_AVCapability_GetName(capability); 108 OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name); 109 if (videoDec == nullptr) { 110 printf("create videoDec failed"); 111 return; 112 } 113 ``` 1142. Call **OH_VideoDecoder_Configure()** to configure the decoder. 115 116 - For details about the configurable options, see [Media Data Key-Value Pairs](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 117 - For details about the parameter verification rules, see [OH_VideoDecoder_Configure()](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_configure). 118 - The parameter value ranges can be obtained through the capability query interface. For details, see [Obtaining Supported Codecs](obtain-supported-codecs.md). 119 120 Currently, the following options must be configured for all supported formats: video frame width and height. 121 122 ```c++ 123 124 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 125 if (format == nullptr) { 126 // Handle exceptions. 127 } 128 // Set the format. 129 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_WIDTH, width); // Mandatory. 130 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_HEIGHT, height); // Mandatory. 131 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_PIXEL_FORMAT, pixelFormat); 132 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_ENABLE_SYNC_MODE, 1); // Set synchronous mode. 133 // Configure the decoder. 134 OH_AVErrCode ret = OH_VideoDecoder_Configure(videoDec, format.get()); 135 if (ret != AV_ERR_OK) { 136 // Handle exceptions. 137 } 138 ``` 139 140 > **NOTE** 141 > 142 > To enable video decoding in synchronous mode, **OH_MD_KEY_ENABLE_SYNC_MODE** must be set to **1**. 143 > 144 > To use synchronous mode, do not call **OH_VideoDecoder_RegisterCallback** in prior to **OH_VideoDecoder_Configure**. Otherwise, the decoder will run in asynchronous mode instead. 145 146 1473. Set the surface. 148 149 In the code snippet below, the following variables are used: 150 - **nativeWindow**: For details about how to obtain the native window, see step 6 in [Surface Mode](video-decoding.md#surface-mode). 151 152 ```c++ 153 // Set the surface. 154 // Set the window parameters. 155 OH_AVErrCode ret = OH_VideoDecoder_SetSurface(videoDec, nativeWindow); 156 if (ret != AV_ERR_OK) { 157 // Handle exceptions. 158 } 159 ``` 160 161 1624. Call **OH_VideoDecoder_Prepare()** to prepare internal resources for the decoder. 163 164 ```c++ 165 OH_AVErrCode ret = OH_VideoDecoder_Prepare(videoDec); 166 if (ret != AV_ERR_OK) { 167 // Handle exceptions. 168 } 169 ``` 170 1715. Call **OH_VideoDecoder_Start()** to start the decoder. 172 173 ```c++ 174 // Start the decoder. 175 OH_AVErrCode ret = OH_VideoDecoder_Start(videoDec); 176 if (ret != AV_ERR_OK) { 177 // Handle exceptions. 178 } 179 ``` 180 1816. Obtain an available buffer and write the bitstream to the decoder. 182 183 - Call [OH_VideoDecoder_QueryInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_queryinputbuffer) to obtain the index of the next available input buffer. 184 - Based on this index, call [OH_VideoDecoder_GetInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_getinputbuffer) to obtain the buffer instance. 185 - Write the data to be decoded into the buffer, and call [OH_VideoDecoder_PushInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_pushinputbuffer) to push it to the decoder for decoding. When all the data to be processed has been passed to the decoder, set flag to **AVCODEC_BUFFER_FLAGS_EOS** to notify the decoder that the input is complete. 186 187 Send the input queue for decoding. In the code snippet below, the following variables are used: 188 - **size**, **offset**, **pts**, and **frameData**: size, offset, timestamp, and frame data. For details about how to obtain such information, see step 9 in [Media Data Demultiplexing](./audio-video-demuxer.md#how-to-develop). 189 - **flags**: type of the buffer flag. For details, see [OH_AVCodecBufferFlags](../../reference/apis-avcodec-kit/_core.md#oh_avcodecbufferflags). 190 191 ```c++ 192 bool DecoderInput(OH_AVCodec *videoDec, int64_t timeoutUs) 193 { 194 uint32_t index; 195 std::shared_lock<std::shared_mutex> lock(codecMutex); 196 197 OH_AVErrCode ret = OH_VideoDecoder_QueryInputBuffer(videoDec, &index, timeoutUs); 198 switch (ret) { 199 case AV_ERR_OK: { 200 OH_AVBuffer *buffer = OH_VideoDecoder_GetInputBuffer(videoDec, index); 201 if (buffer == nullptr) { 202 // Handle exceptions. 203 return false; 204 } 205 // Write stream data. 206 uint8_t *addr = OH_AVBuffer_GetAddr(buffer); 207 if (addr == nullptr) { 208 // Handle exceptions. 209 return false; 210 } 211 // Fill in the buffer. 212 int32_t capacity = OH_AVBuffer_GetCapacity(buffer); 213 if (size > capacity) { 214 // Handle exceptions. 215 } 216 memcpy(addr, frameData, size); 217 218 OH_AVCodecBufferAttr info; 219 // Set the buffer attributes. 220 // Configure the size, offset, and timestamp of the frame data. 221 info.size = size; 222 info.offset = offset; 223 info.pts = pts; 224 if (inFile_->eof()) { 225 info.flags = AVCODEC_BUFFER_FLAGS_EOS; 226 } else { 227 info.flags = flags; 228 } 229 OH_AVErrCode setBufferRet = OH_AVBuffer_SetBufferAttr(buffer, &info); 230 if (setBufferRet != AV_ERR_OK) { 231 // Handle exceptions. 232 return false; 233 } 234 OH_AVErrCode pushInputRet = OH_VideoDecoder_PushInputBuffer(videoDec, index); 235 if (pushInputRet != AV_ERR_OK) { 236 // Handle exceptions. 237 return false; 238 } 239 if (inFile_->eof()) { 240 inputDone = 1; 241 } 242 break; 243 } 244 case AV_ERR_TRY_AGAIN_LATER: { 245 break; 246 } 247 default: { 248 // Handle exceptions. 249 return false; 250 } 251 } 252 return true; 253 } 254 ``` 255 2567. Obtain an available buffer and release the decoded frame. 257 258 - Call [OH_VideoDecoder_QueryOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_queryoutputbuffer) to obtain the index of the next available input buffer. 259 - Bsed on this index, call [OH_VideoDecoder_GetOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_getoutputbuffer) to obtain the buffer instance. 260 - Determine the subsequent operations based on the **isRender** flag. If the decoded frame does not need to be rendered, call [OH_VideoDecoder_FreeOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_freeoutputbuffer) to release the decoded frame. If the decoded frame needs to be rendered, you can call [OH_VideoDecoder_RenderOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_renderoutputbuffer) to display the decoded frame and automatically release it, or call [OH_VideoDecoder_RenderOutputBufferAtTime](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_renderoutputbufferattime) to display the decoded frame at a specified time and then release it. 261 262 ```c++ 263 bool DecoderOutput(OH_AVCodec *videoDec, int64_t timeoutUs) 264 { 265 uint32_t index; 266 std::shared_lock<std::shared_mutex> lock(codecMutex); 267 268 OH_AVErrCode ret = OH_VideoDecoder_QueryOutputBuffer(videoDec, &index, timeoutUs); 269 switch (ret) { 270 case AV_ERR_OK: { 271 OH_AVBuffer *buffer = OH_VideoDecoder_GetOutputBuffer(videoDec, index); 272 if (buffer == nullptr) { 273 // Handle exceptions. 274 return false; 275 } 276 277 // Obtain the decoded information. 278 OH_AVCodecBufferAttr info; 279 OH_AVErrCode getBufferRet = OH_AVBuffer_GetBufferAttr(buffer, &info); 280 if (getBufferRet != AV_ERR_OK) { 281 // Handle exceptions. 282 return false; 283 } 284 if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) { 285 outputDone = 1; 286 } 287 288 // Handle the decoded output data. 289 // You can determine the value. 290 bool isRender; 291 bool isNeedRenderAtTime; 292 OH_AVErrCode result = AV_ERR_OK; 293 if (isRender) { 294 // Render the data and free the output buffer. index is the index of the buffer. 295 if (isNeedRenderAtTime){ 296 // Obtain the system absolute time, and call renderTimestamp to display the time based on service requirements. 297 int64_t renderTimestamp = 298 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); 299 result = OH_VideoDecoder_RenderOutputBufferAtTime(videoDec, index, renderTimestamp); 300 } else { 301 result = OH_VideoDecoder_RenderOutputBuffer(videoDec, index); 302 } 303 } else { 304 // Free the output buffer. 305 result = OH_VideoDecoder_FreeOutputBuffer(videoDec, index); 306 } 307 if (result != AV_ERR_OK) { 308 // Handle exceptions. 309 return false; 310 } 311 break; 312 } 313 case AV_ERR_TRY_AGAIN_LATER: { 314 break; 315 } 316 case AV_ERR_STREAM_CHANGED: { 317 auto format = std::shared_ptr<OH_AVFormat>(OH_VideoDecoder_GetOutputDescription(videoDec), OH_AVFormat_Destroy); 318 if (format == nullptr) { 319 // Handle exceptions. 320 } 321 // Obtain the new width and height. 322 bool getIntRet = OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_PIC_WIDTH, &width) && 323 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_PIC_HEIGHT, &height); 324 if (!getIntRet) { 325 // Handle exceptions. 326 } 327 break; 328 } 329 default: { 330 // Handle exceptions. 331 return false; 332 } 333 } 334 return true; 335 } 336 ``` 337 3388. Enable the decoder to input and output frames in a loop. 339 340 ```c++ 341 bool result = true; 342 int64_t timeoutUs = 0; // Unit: μs. A negative value means to wait infinitely. The value 0 means to return immediately. A positive value means to wait for the specified time before exiting. 343 344 while (!outputDone && result) { 345 if (!inputDone) { 346 result = DecoderInput(videoDec, timeoutUs); 347 } 348 if (!outputDone) { 349 result = DecoderOutput(videoDec, timeoutUs); 350 } 351 } 352 ``` 353 3549. (Optional) Call **OH_VideoDecoder_Flush()** to refresh the decoder. 355 356 After **OH_VideoDecoder_Flush** is called, the decoder remains in the Running state, but the input and output data and parameter set (such as the H.264 PPS/SPS) buffered in the decoder are cleared. 357 358 In this case, you need to call [OH_VideoDecoder_Start](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_start) to start decoding again. 359 360 ```c++ 361 // Use codecMutex to avoid the problem where the decoding thread keeps running and exits the loop after the Flush API is called and the state is changed. 362 std::unique_lock<std::shared_mutex> lock(codecMutex); 363 // Refresh the decoder. 364 OH_AVErrCode ret = OH_VideoDecoder_Flush(videoDec); 365 if (ret != AV_ERR_OK) { 366 // Handle exceptions. 367 } 368 369 // Start decoding again. 370 ret = OH_VideoDecoder_Start(videoDec); 371 if (ret != AV_ERR_OK) { 372 // Handle exceptions. 373 } 374 ``` 375 37610. (Optional) Call **OH_VideoDecoder_Reset()** to reset the decoder. 377 378 After **OH_VideoDecoder_Reset** is called, the decoder returns to the Initialized state. To continue decoding, you must call [OH_VideoDecoder_Configure](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_configure), [OH_VideoDecoder_SetSurface](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_setsurface), and [OH_VideoDecoder_Prepare](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_prepare) in sequence. 379 380 ```c++ 381 // Reset the decoder. 382 std::unique_lock<std::shared_mutex> lock(codecMutex); 383 OH_AVErrCode resetRet = OH_VideoDecoder_Reset(videoDec); 384 if (resetRet != AV_ERR_OK) { 385 // Handle exceptions. 386 } 387 388 // Reconfigure the decoder. 389 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 390 if (format == nullptr) { 391 // Handle exceptions. 392 } 393 OH_AVErrCode configRet = OH_VideoDecoder_Configure(videoDec, format.get()); 394 if (configRet != AV_ERR_OK) { 395 // Handle exceptions. 396 } 397 398 // Reconfigure the surface in surface mode. This is not required in buffer mode. 399 OH_AVErrCode setRet = OH_VideoDecoder_SetSurface(videoDec, nativeWindow); 400 if (setRet != AV_ERR_OK) { 401 // Handle exceptions. 402 } 403 // The decoder is ready again. 404 OH_AVErrCode prepareRet = OH_VideoDecoder_Prepare(videoDec); 405 if (prepareRet != AV_ERR_OK) { 406 // Handle exceptions. 407 } 408 ``` 409 410 > **NOTE** 411 > 412 > When the decoder returns to the initialized state, you must call **OH_VideoDecoder_Configure** to set **OH_MD_KEY_ENABLE_SYNC_MODE** to **1** to reconfigure the decoder parameters. Otherwise, the decoder will run in asynchronous mode. 413 41411. (Optional) Call **OH_VideoDecoder_Stop()** to stop the decoder. 415 416 After **OH_VideoDecoder_Stop()** is called, the decoder retains the decoding instance and releases the input and output buffers. 417 418 ```c++ 419 // Stop the decoder. 420 std::unique_lock<std::shared_mutex> lock(codecMutex); 421 OH_AVErrCode ret = OH_VideoDecoder_Stop(videoDec); 422 if (ret != AV_ERR_OK) { 423 // Handle exceptions. 424 } 425 ``` 426 42712. Call **OH_VideoDecoder_Destroy()** to destroy the decoder instance and release resources. 428 429 ```c++ 430 // Call OH_VideoDecoder_Destroy to destroy the decoder. 431 std::unique_lock<std::shared_mutex> lock(codecMutex); 432 OH_AVErrCode ret = AV_ERR_OK; 433 if (videoDec != nullptr) { 434 ret = OH_VideoDecoder_Destroy(videoDec); 435 videoDec = nullptr; 436 } 437 if (ret != AV_ERR_OK) { 438 // Handle exceptions. 439 } 440 ``` 441 442 > **NOTE** 443 > 444 > After the call, you must set a null pointer to the decoder to prevent program errors caused by wild pointers. 445 446### Buffer Mode 447 448The following walks you through how to implement the entire video decoding process in buffer mode and implement data rotation in synchronous mode. In this example, an H.264 stream file is input and decoded into a YUV file. 449 4501. Create a decoder instance. 451 452 The procedure is the same as that in surface mode and is not described here. 453 454 ```c++ 455 // 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. 456 OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false); 457 const char *name = OH_AVCapability_GetName(capability); 458 OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name); 459 if (videoDec == nullptr) { 460 printf("create videoDec failed"); 461 return; 462 } 463 ``` 464 4652. Call **OH_VideoDecoder_Configure()** to configure the decoder. 466 467 The procedure is the same as that in surface mode and is not described here. 468 469 ```c++ 470 471 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 472 if (format == nullptr) { 473 // Handle exceptions. 474 } 475 // Set the format. 476 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_WIDTH, width); // Mandatory. 477 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_HEIGHT, height); // Mandatory. 478 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_PIXEL_FORMAT, pixelFormat); 479 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_ENABLE_SYNC_MODE, 1); // Set synchronous mode. 480 // Configure the decoder. 481 OH_AVErrCode ret = OH_VideoDecoder_Configure(videoDec, format.get()); 482 if (ret != AV_ERR_OK) { 483 // Handle exceptions. 484 } 485 ``` 486 487 > **NOTE** 488 > 489 > To enable video decoding in synchronous mode, **OH_MD_KEY_ENABLE_SYNC_MODE** must be set to **1**. 490 > 491 > To use synchronous mode, do not call **OH_VideoDecoder_RegisterCallback** in prior to **OH_VideoDecoder_Configure**. Otherwise, the decoder will run in asynchronous mode instead. 492 4933. Call **OH_VideoDecoder_Prepare()** to prepare internal resources for the decoder. 494 495 ```c++ 496OH_AVErrCode ret = OH_VideoDecoder_Prepare(videoDec); 497 if (ret != AV_ERR_OK) { 498 // Handle exceptions. 499 } 500 ``` 501 5024. Call **OH_VideoDecoder_Start()** to start the decoder. 503 504 ```c++ 505 std::unique_ptr<std::ofstream> outputFile = std::make_unique<std::ofstream>(); 506 if (outputFile != nullptr) { 507 outputFile->open("/*yourpath*.yuv", std::ios::out | std::ios::binary | std::ios::ate); 508 } 509 // Start the decoder. 510 OH_AVErrCode ret = OH_VideoDecoder_Start(videoDec); 511 if (ret != AV_ERR_OK) { 512 // Handle exceptions. 513 } 514 ``` 515 5165. Obtain an available buffer and write the bitstream to the decoder. 517 518 - Call [OH_VideoDecoder_QueryInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_queryinputbuffer) to obtain the index of the next available input buffer. 519 - Based on this index, call [OH_VideoDecoder_GetInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_getinputbuffer) to obtain the buffer instance. 520 - Write the data to be decoded into the buffer, and call [OH_VideoDecoder_PushInputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_pushinputbuffer) to push it to the decoder for decoding. When all the data to be processed has been passed to the decoder, set flag to **AVCODEC_BUFFER_FLAGS_EOS** to notify the decoder that the input is complete. 521 522 The meanings of the variables **size**, **offset**, **pts**, **frameData**, and **flags** in the example are the same as those in surface mode. 523 524 ```c++ 525 bool DecoderInput(OH_AVCodec *videoDec, int64_t timeoutUs) 526 { 527 uint32_t index; 528 std::shared_lock<std::shared_mutex> lock(codecMutex); 529 530 OH_AVErrCode ret = OH_VideoDecoder_QueryInputBuffer(videoDec, &index, timeoutUs); 531 switch (ret) { 532 case AV_ERR_OK: { 533 OH_AVBuffer *buffer = OH_VideoDecoder_GetInputBuffer(videoDec, index); 534 if (buffer == nullptr) { 535 // Handle exceptions. 536 return false; 537 } 538 // Write stream data. 539 uint8_t *addr = OH_AVBuffer_GetAddr(buffer); 540 if (addr == nullptr) { 541 // Handle exceptions. 542 return false; 543 } 544 // Fill in the buffer. 545 int32_t capacity = OH_AVBuffer_GetCapacity(buffer); 546 if (size > capacity) { 547 // Handle exceptions. 548 } 549 memcpy(addr, frameData, size); 550 551 OH_AVCodecBufferAttr info; 552 // Set the buffer attributes. 553 // Configure the size, offset, and timestamp of the frame data. 554 info.size = size; 555 info.offset = offset; 556 info.pts = pts; 557 if (inFile_->eof()) { 558 info.flags = AVCODEC_BUFFER_FLAGS_EOS; 559 } else { 560 info.flags = flags; 561 } 562 OH_AVErrCode setBufferRet = OH_AVBuffer_SetBufferAttr(buffer, &info); 563 if (setBufferRet != AV_ERR_OK) { 564 // Handle exceptions. 565 return false; 566 } 567 OH_AVErrCode pushInputRet = OH_VideoDecoder_PushInputBuffer(videoDec, index); 568 if (pushInputRet != AV_ERR_OK) { 569 // Handle exceptions. 570 return false; 571 } 572 if (inFile_->eof()) { 573 inputDone = 1; 574 } 575 break; 576 } 577 case AV_ERR_TRY_AGAIN_LATER: { 578 break; 579 } 580 default: { 581 // Handle exceptions. 582 return false; 583 } 584 } 585 return true; 586 } 587 ``` 588 5896. Obtain an available buffer and release the decoded frame. 590 591 - Call [OH_VideoDecoder_QueryOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_queryoutputbuffer) to obtain the index of the next available input buffer. 592 - Based on this index, call [OH_VideoDecoder_GetOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_getoutputbuffer) to obtain the buffer instance. 593 - Call [OH_VideoDecoder_FreeOutputBuffer](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_freeoutputbuffer) to release the decoded frame. 594 595 ```c++ 596 bool DecoderOutput(OH_AVCodec *videoDec, int64_t timeoutUs) 597 { 598 uint32_t index; 599 int32_t cropTop = 0; 600 int32_t cropBottom = 0; 601 int32_t cropLeft = 0; 602 int32_t cropRight = 0; 603 int32_t widthStride = 0; 604 int32_t heightStride = 0; 605 std::shared_lock<std::shared_mutex> lock(codecMutex); 606 607 OH_AVErrCode ret = OH_VideoDecoder_QueryOutputBuffer(videoDec, &index, timeoutUs); 608 switch (ret) { 609 case AV_ERR_OK: { 610 OH_AVBuffer *buffer = OH_VideoDecoder_GetOutputBuffer(videoDec, index); 611 if (buffer == nullptr) { 612 // Handle exceptions. 613 return false; 614 } 615 616 // Obtain the decoded information. 617 OH_AVCodecBufferAttr info; 618 OH_AVErrCode getBufferRet = OH_AVBuffer_GetBufferAttr(buffer, &info); 619 if (getBufferRet != AV_ERR_OK) { 620 // Handle exceptions. 621 return false; 622 } 623 if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) { 624 outputDone = 1; 625 } 626 627 // Free the output buffer. index is the index of the buffer. 628 OH_AVErrCode freeOutputRet = OH_VideoDecoder_FreeOutputBuffer(videoDec, index); 629 if (freeOutputRet != AV_ERR_OK) { 630 // Handle exceptions. 631 return false; 632 } 633 break; 634 } 635 case AV_ERR_TRY_AGAIN_LATER: { 636 break; 637 } 638 case AV_ERR_STREAM_CHANGED: { 639 auto format = std::shared_ptr<OH_AVFormat>(OH_VideoDecoder_GetOutputDescription(videoDec), OH_AVFormat_Destroy); 640 if (format == nullptr) { 641 // Handle exceptions. 642 } 643 // Obtain the new video width, height, and stride. 644 bool getIntRet = OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_PIC_WIDTH, &width) && 645 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_PIC_HEIGHT, &height) && 646 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_STRIDE, &widthStride) && 647 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_SLICE_HEIGHT, &heightStride) && 648 // (Optional) Obtain the cropped rectangle information. 649 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_CROP_TOP, &cropTop) && 650 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_CROP_BOTTOM, &cropBottom) && 651 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_CROP_LEFT, &cropLeft) && 652 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_CROP_RIGHT, &cropRight); 653 if (!getIntRet) { 654 // Handle exceptions. 655 } 656 break; 657 } 658 default: { 659 // Handle exceptions. 660 return false; 661 } 662 } 663 return true; 664 } 665 ``` 666 6677. Enable the decoder to input and output frames in a loop. 668 669 ```c++ 670 bool result = true; 671 int64_t timeoutUs = 0; // Unit: μs. A negative value means to wait infinitely. The value 0 means to return immediately. A positive value means to wait for the specified time before exiting. 672 673 while (!outputDone && result) { 674 if (!inputDone) { 675 result = DecoderInput(videoDec, timeoutUs); 676 } 677 if (!outputDone) { 678 result = DecoderOutput(videoDec, timeoutUs); 679 } 680 } 681 ``` 682 683The subsequent processes (including refreshing, resetting, stopping, and destroying the decoder) are the same as those in surface mode. For details, see steps 9–12 in [Surface Mode](#surface-mode). 684