1# Synchronous Video Encoding 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 encoding in synchronous mode is supported. 11 12You can call native APIs to perform synchronous video encoding. 13 14For details about the supported encoding capabilities, see [AVCodec Supported Formats](avcodec-support-formats.md#video-encoding). 15 16For details about the restrictions, supported capabilities, and state machine call relationships of video encoding, see [Video Encoding](video-encoding.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 [VideoEncoder](../../reference/apis-avcodec-kit/_video_encoder.md) for the API reference. 26 27The figure below shows the call relationship of synchronous video encoding. 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_venc.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_videoencoder.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 ``` 67 682. Configure global variables. 69 70 These global variables are for reference only. They can be encapsulated into an object based on service requirements. 71 72 ```c++ 73 // Video frame width. 74 int32_t width = 320; 75 // Video frame height. 76 int32_t height = 240; 77 // Video width stride. 78 int32_t widthStride = 0; 79 // Video height stride. 80 int32_t heightStride = 0; 81 // Video pixel format. 82 OH_AVPixelFormat pixelFormat = AV_PIXEL_FORMAT_NV12; 83 // Encoder synchronization lock. 84 std::shared_mutex codecMutex; 85 // Pointer to the encoder instance. 86 OH_AVCodec *videoEnc = nullptr; 87 // Encoding output. 88 bool outputDone = false; 89 // Encoding input. 90 bool inputDone = false; 91 std::unique_ptr<std::ifstream> inFile_; 92 ``` 93 94### Surface Mode 95 96The following walks you through how to implement the entire video encoding process in surface mode and implement data rotation in synchronous mode. In this example, surface data is input and encoded into a H.264 stream. 97 98 991. Create an encoder instance. 100 101 Create an encoder by name. In the code snippet below, the following variables are used: 102 103 - **videoEnc**: pointer to the video encoder instance. 104 - **capability**: pointer to the encoder's capability. 105 - [OH_AVCODEC_MIMETYPE_VIDEO_AVC](../../reference/apis-avcodec-kit/_codec_base.md#oh_avcodec_mimetype_video_avc): video codec in AVC format. 106 107 ```c++ 108 // Create a hardware encoder instance. 109 OH_AVCapability *capability= OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true, HARDWARE); 110 const char *name = OH_AVCapability_GetName(capability); 111 OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByName(name); 112 if (videoEnc == nullptr) { 113 printf("create videoEnc failed"); 114 return; 115 } 116 ``` 117 1182. Call **OH_VideoEncoder_Configure()** to configure the encoder. 119 120 - For details about the configurable options, see [Media Data Key-Value Pairs](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 121 - For details about the parameter verification rules, see [OH_VideoEncoder_Configure()](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_configure). 122 - The parameter value ranges can be obtained through the capability query interface. For details, see [Obtaining Supported Codecs](obtain-supported-codecs.md). 123 124 Currently, the following options must be configured for all supported formats: video frame width, video frame height, and video pixel format. 125 126 ```c++ 127 128 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 129 if (format == nullptr) { 130 // Handle exceptions. 131 } 132 // Set the format. 133 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_WIDTH, width); // Mandatory. 134 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_HEIGHT, height); // Mandatory. 135 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_PIXEL_FORMAT, pixelFormat); // Mandatory. 136 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_ENABLE_SYNC_MODE, 1); // Set the synchronous mode. 137 // Configure the encoder. 138 OH_AVErrCode ret = OH_VideoEncoder_Configure(videoEnc, format.get()); 139 if (ret != AV_ERR_OK) { 140 // Handle exceptions. 141 } 142 ``` 143 144 > **NOTE** 145 > 146 > To enable video encoding in synchronous mode, **OH_MD_KEY_ENABLE_SYNC_MODE** must be set to **1**. 147 > 148 > To use synchronous mode, do not call **OH_VideoEncoder_RegisterCallback** or **OH_VideoEncoder_RegisterParameterCallback** in prior to **OH_VideoEncoder_Configure**. Otherwise, the encoder will run in asynchronous mode instead. 149 > 150 > Synchronous mode is not supported for frame-specific channels in surface mode. 151 1523. Set the surface. 153 154 In the code snippet below, the following variables are used: 155 156 - **nativeWindow**: For details about how to obtain the native window, see step 6 in [Surface Mode](video-encoding.md#surface-mode). 157 158 ```c++ 159 // Obtain the surface used for data input. 160 OH_AVErrCode ret = OH_VideoEncoder_GetSurface(videoEnc, &nativeWindow); 161 if (ret != AV_ERR_OK) { 162 // Handle exceptions. 163 } 164 ``` 165 1664. Call **OH_VideoEncoder_Prepare()** to prepare internal resources for the encoder. 167 168 ```c++ 169 OH_AVErrCode ret = OH_VideoEncoder_Prepare(videoEnc); 170 if (ret != AV_ERR_OK) { 171 // Handle exceptions. 172 } 173 ``` 174 1755. Call **OH_VideoEncoder_Start()** to start the encoder. 176 177 ```c++ 178 // Configure the paths of the input and output files. 179 std::string_view outputFilePath = "/*yourpath*.h264"; 180 std::unique_ptr<std::ofstream> outputFile = std::make_unique<std::ofstream>(); 181 if (outputFile != nullptr) { 182 outputFile->open(outputFilePath.data(), std::ios::out | std::ios::binary | std::ios::ate); 183 } 184 // Start the encoder. 185 OH_AVErrCode ret = OH_VideoEncoder_Start(videoEnc); 186 if (ret != AV_ERR_OK) { 187 // Handle exceptions. 188 } 189 ``` 190 1916. Obtain an available buffer and release the encoded frame. 192 193 - Call [OH_VideoEncoder_QueryOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_queryoutputbuffer) to obtain the index of the next available output buffer. 194 - Based on this index, call [OH_VideoEncoder_GetOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_getoutputbuffer) to obtain the buffer instance. 195 - Call [OH_VideoEncoder_FreeOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_freeoutputbuffer) to release the encoded frame. 196 197 ```c++ 198 bool EncoderOutput(OH_AVCodec *videoEnc, int64_t timeoutUs) 199 { 200 uint32_t index; 201 std::shared_lock<std::shared_mutex> lock(codecMutex); 202 203 OH_AVErrCode ret = OH_VideoEncoder_QueryOutputBuffer(videoEnc, &index, timeoutUs); 204 switch (ret) { 205 case AV_ERR_OK: { 206 OH_AVBuffer *buffer = OH_VideoEncoder_GetOutputBuffer(videoEnc, index); 207 if (buffer == nullptr) { 208 // Handle exceptions. 209 return false; 210 } 211 212 // Obtain the encoded information. 213 OH_AVCodecBufferAttr info; 214 OH_AVErrCode getBufferRet = OH_AVBuffer_GetBufferAttr(buffer, &info); 215 if (getBufferRet != AV_ERR_OK) { 216 // Handle exceptions. 217 return false; 218 } 219 if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) { 220 outputDone = 1; 221 } 222 223 // Write the encoded frame data (specified by buffer) to the output file. 224 uint8_t *addr = OH_AVBuffer_GetAddr(buffer); 225 if (addr == nullptr) { 226 // Handle exceptions. 227 return false; 228 } 229 if (outputFile != nullptr && outputFile->is_open()) { 230 outputFile->write(reinterpret_cast<char *>(addr), info.size); 231 } 232 // Free the output buffer. index is the index of the buffer. 233 OH_AVErrCode freeOutputRet = OH_VideoEncoder_FreeOutputBuffer(videoEnc, index); 234 if (freeOutputRet != AV_ERR_OK) { 235 // Handle exceptions. 236 return false; 237 } 238 break; 239 } 240 case AV_ERR_TRY_AGAIN_LATER: { 241 break; 242 } 243 case AV_ERR_STREAM_CHANGED: { 244 auto format = std::shared_ptr<OH_AVFormat>(OH_VideoEncoder_GetOutputDescription(videoEnc), OH_AVFormat_Destroy); 245 if (format == nullptr) { 246 // Handle exceptions. 247 } 248 // Obtain the new width and height. 249 bool getIntRet = OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_WIDTH, &width) && 250 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_HEIGHT, &height); 251 if (!getIntRet) { 252 // Handle exceptions. 253 } 254 break; 255 } 256 default: { 257 // Handle exceptions. 258 return false; 259 } 260 } 261 return true; 262 } 263 ``` 264 2657. Enable the encoder to output frames in a loop. 266 267 ```c++ 268 bool result = true; 269 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. 270 271 while (!outputDone && result) { 272 if (!outputDone ) { 273 result = EncoderOutput(videoEnc, timeoutUs); 274 } 275 } 276 ``` 277 2788. Call **OH_VideoEncoder_NotifyEndOfStream()** to notify the encoder of EOS. 279 280 ```c++ 281 // In surface mode, you only need to call this API to notify the encoder of EOS. 282 OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(videoEnc); 283 if (ret != AV_ERR_OK) { 284 // Handle exceptions. 285 } 286 ``` 287 2889. (Optional) Call **OH_VideoEncoder_Flush()** to refresh the encoder. 289 290 After **OH_VideoEncoder_Flush** is called, the encoder remains in the Running state, but the input and output data and parameter set (such as the H.264 PPS/SPS) buffered in the encoder are cleared. 291 292 To continue encoding, you must call [OH_VideoEncoder_Start](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_start) again. 293 294 ```c++ 295 // Use codecMutex to avoid the problem where the encoding thread keeps running and exits the loop after the Flush API is called and the state is changed. 296 std::unique_lock<std::shared_mutex> lock(codecMutex); 297 // Refresh the encoder. 298 OH_AVErrCode flushRet = OH_VideoEncoder_Flush(videoEnc); 299 if (flushRet != AV_ERR_OK) { 300 // Handle exceptions. 301 } 302 303 // Start encoding again. 304 OH_AVErrCode startRet = OH_VideoEncoder_Start(videoEnc); 305 if (startRet != AV_ERR_OK) { 306 // Handle exceptions. 307 } 308 ``` 309 31010. (Optional) Call **OH_VideoEncoder_Reset()** to reset the encoder. 311 312 After **OH_VideoEncoder_Reset** is called, the encoder returns to the initialized state. To continue encoding, you must call **[OH_VideoEncoder_Configure](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_configure)** and then **[OH_VideoEncoder_Prepare](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_prepare)**. 313 314 ```c++ 315 // Reset the encoder. 316 std::unique_lock<std::shared_mutex> lock(codecMutex); 317 OH_AVErrCode resetRet = OH_VideoEncoder_Reset(videoEnc); 318 if (resetRet != AV_ERR_OK) { 319 // Handle exceptions. 320 } 321 322 // Reconfigure the encoder. 323 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 324 if (format == nullptr) { 325 // Handle exceptions. 326 } 327 OH_AVErrCode configRet = OH_VideoEncoder_Configure(videoEnc, format.get()); 328 if (configRet != AV_ERR_OK) { 329 // Handle exceptions. 330 } 331 332 // The encoder is ready again. 333 OH_AVErrCode prepareRet = OH_VideoEncoder_Prepare(videoEnc); 334 if (prepareRet != AV_ERR_OK) { 335 // Handle exceptions. 336 } 337 ``` 338 339 > **NOTE** 340 > 341 > When the encoder returns to the initialized state, you must call **OH_VideoEncoder_Configure** to set **OH_MD_KEY_ENABLE_SYNC_MODE** to **1** to reconfigure the encoder parameters. Otherwise, the encoder will run in asynchronous mode. 342 34311. (Optional) Call **OH_VideoEncoder_Stop()** to stop the encoder. 344 345 After **OH_VideoEncoder_Stop** is called, the encoder retains the encoding instance and releases the input and output buffers. You can directly call **OH_VideoEncoder_Start** to continue encoding. The first **buffer** passed must carry the parameter set, starting from the IDR frame. 346 347 ```c++ 348 // Stop the encoder. 349 std::unique_lock<std::shared_mutex> lock(codecMutex); 350 OH_AVErrCode ret = OH_VideoEncoder_Stop(videoEnc); 351 if (ret != AV_ERR_OK) { 352 // Handle exceptions. 353 } 354 ``` 355 35612. Call **OH_VideoEncoder_Destroy()** to destroy the encoder instance and release resources. 357 358 ```c++ 359 // Destroy the encoder. 360 std::unique_lock<std::shared_mutex> lock(codecMutex); 361 OH_AVErrCode ret = AV_ERR_OK; 362 if (videoEnc != nullptr) { 363 ret = OH_VideoEncoder_Destroy(videoEnc); 364 videoEnc = nullptr; 365 } 366 if (ret != AV_ERR_OK) { 367 // Handle exceptions. 368 } 369 ``` 370 371 > **NOTE** 372 > 373 > After the call, you must set a null pointer to the encoder to prevent program errors caused by wild pointers. 374 375### Buffer Mode 376 377The following walks you through how to implement the entire video encoding process in buffer mode and implement data rotation in synchronous mode. It uses the YUV file input and H.264 encoding format as an example. 378 3791. Create an encoder instance. 380 381 The procedure is the same as that in surface mode and is not described here. 382 383 ```c++ 384 // Create an encoder by name. If your application has special requirements, for example, expecting an encoder that supports a certain resolution, you can call OH_AVCodec_GetCapability to query the capability first. 385 OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true); 386 const char *name = OH_AVCapability_GetName(capability); 387 OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByName(name); 388 if (videoEnc == nullptr) { 389 printf("create videoEnc failed"); 390 return; 391 } 392 ``` 393 3942. Call **OH_VideoEncoder_Configure()** to configure the encoder. 395 396 The procedure is the same as that in surface mode and is not described here. 397 398 ```c++ 399 auto format = std::shared_ptr<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy); 400 if (format == nullptr) { 401 // Handle exceptions. 402 } 403 // Set the format. 404 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_WIDTH, width); // Mandatory. 405 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_HEIGHT, height); // Mandatory. 406 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_PIXEL_FORMAT, pixelFormat); // Mandatory. 407 OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_ENABLE_SYNC_MODE, 1); // Set the synchronous mode. 408 // Configure the encoder. 409 OH_AVErrCode ret = OH_VideoEncoder_Configure(videoEnc, format.get()); 410 if (ret != AV_ERR_OK) { 411 // Handle exceptions. 412 } 413 ``` 414 415 > **NOTE** 416 > 417 > To enable video encoding in synchronous mode, **OH_MD_KEY_ENABLE_SYNC_MODE** must be set to **1**. 418 > 419 > To use synchronous mode, do not call **OH_VideoEncoder_RegisterCallback** or **OH_VideoEncoder_RegisterParameterCallback** in prior to **OH_VideoEncoder_Configure**. Otherwise, the encoder will run in asynchronous mode instead. 420 4213. Call **OH_VideoEncoder_Prepare()** to prepare internal resources for the encoder. 422 423 ```c++ 424 ret = OH_VideoEncoder_Prepare(videoEnc); 425 if (ret != AV_ERR_OK) { 426 // Handle exceptions. 427 } 428 ``` 429 4304. Call **OH_VideoEncoder_Start()** to start the encoder. 431 432 Configure the input and output files. 433 434 ```c++ 435 // Configure the paths of the input and output files. 436 std::string_view inputFilePath = "/*yourpath*.yuv"; 437 std::string_view outputFilePath = "/*yourpath*.h264"; 438 std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>(); 439 std::unique_ptr<std::ofstream> outputFile = std::make_unique<std::ofstream>(); 440 if (inputFile != nullptr) { 441 inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary); 442 } 443 if (outputFile != nullptr) { 444 outputFile->open(outputFilePath.data(), std::ios::out | std::ios::binary | std::ios::ate); 445 } 446 // Start the encoder. 447 OH_AVErrCode ret = OH_VideoEncoder_Start(videoEnc); 448 if (ret != AV_ERR_OK) { 449 // Handle exceptions. 450 } 451 ``` 452 4535. Obtain an available buffer and write the bitstream to the encoder. 454 455 - Call [OH_VideoEncoder_QueryInputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_queryinputbuffer) to obtain the index of the next available input buffer. 456 - Based on this index, call [OH_VideoEncoder_GetInputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_getinputbuffer) to obtain the buffer instance. 457 - Write the data to be encoded to the buffer, and call [OH_VideoEncoder_PushInputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_pushinputbuffer) to push it into the encoding input queue for encoding. When all the data to be processed has been passed to the encoder, set flag to **AVCODEC_BUFFER_FLAGS_EOS** to notify the encoder that the input is complete. 458 459 The meanings of the variables **size**, **offset**, **pts**, **frameData**, and **flags** in the example are the same as those in surface mode. 460 461 ```c++ 462 bool EncoderInput(OH_AVCodec *videoEnc, int64_t timeoutUs) 463 { 464 uint32_t index; 465 std::shared_lock<std::shared_mutex> lock(codecMutex); 466 467 OH_AVErrCode ret = OH_VideoEncoder_QueryInputBuffer(videoEnc, &index, timeoutUs); 468 switch (ret) { 469 case AV_ERR_OK: { 470 OH_AVBuffer *buffer = OH_VideoEncoder_GetInputBuffer(videoEnc, index); 471 if (buffer == nullptr) { 472 // Handle exceptions. 473 return false; 474 } 475 476 // Write image data. 477 int32_t frameSize = 0; 478 bool isFirstFrame = true; 479 // Obtain the video width stride and height stride. 480 if (isFirstFrame) { 481 auto format = std::shared_ptr<OH_AVFormat>(OH_VideoEncoder_GetInputDescription(videoEnc), OH_AVFormat_Destroy); 482 if (format == nullptr) { 483 // Handle exceptions. 484 } 485 bool getIntRet = OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_STRIDE, &widthStride) && 486 OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_VIDEO_SLICE_HEIGHT, &heightStride); 487 if (!getIntRet) { 488 // Handle exceptions. 489 } 490 isFirstFrame = false; 491 } 492 if (widthStride == width && heightStride == height) { 493 frameSize = width * height * 3 / 2; // Formula for calculating the data size of each frame in NV12 pixel format. 494 // Process the file stream and obtain the frame length, and then write the data to encode to the buffer of the specified index. 495 uint8_t *addr = OH_AVBuffer_GetAddr(buffer); 496 if (addr == nullptr) { 497 // Handle exceptions. 498 return false; 499 } 500 if (inputFile != nullptr && inputFile->is_open()) { 501 inputFile->read(reinterpret_cast<char *>(addr), frameSize); 502 } 503 } else { 504 // If the stride is not equal to the width, perform offset based on the stride. For details, see step 8 in "Buffer Mode in Video Encoding". 505 } 506 507 // Configure the buffer information. 508 OH_AVCodecBufferAttr info; 509 info.size = frameSize; 510 info.offset = 0; 511 info.pts = 0; 512 OH_AVErrCode setBufferRet = OH_AVBuffer_SetBufferAttr(buffer, &info); 513 if (setBufferRet != AV_ERR_OK) { 514 // Handle exceptions. 515 return false; 516 } 517 // Send the data to the input buffer for encoding. index is the index of the buffer. 518 OH_AVErrCode pushInputRet = OH_VideoEncoder_PushInputBuffer(videoEnc, index); 519 if (pushInputRet != AV_ERR_OK) { 520 // Handle exceptions. 521 return false; 522 } 523 if (inFile_->eof()) { 524 inputDone = 1; 525 } 526 break; 527 } 528 case AV_ERR_TRY_AGAIN_LATER: { 529 break; 530 } 531 default: { 532 // Handle exceptions. 533 return false; 534 } 535 } 536 return true; 537 } 538 ``` 539 540 5416. Obtain an available buffer and release the encoded frame. 542 543 - Call [OH_VideoEncoder_QueryOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_queryoutputbuffer) to obtain the index of the next available output buffer. 544 - Based on this index, call [OH_VideoEncoder_GetOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_getoutputbuffer) to obtain the buffer instance. 545 - Call [OH_VideoEncoder_FreeOutputBuffer](../../reference/apis-avcodec-kit/_video_encoder.md#oh_videoencoder_freeoutputbuffer) to release the encoded frame. 546 547 ```c++ 548 bool EncoderOutput(OH_AVCodec *videoEnc, int64_t timeoutUs) 549 { 550 uint32_t index; 551 std::shared_lock<std::shared_mutex> lock(codecMutex); 552 553 OH_AVErrCode ret = OH_VideoEncoder_QueryOutputBuffer(videoEnc, &index, timeoutUs); 554 switch (ret) { 555 case AV_ERR_OK: { 556 OH_AVBuffer *buffer = OH_VideoEncoder_GetOutputBuffer(videoEnc, index); 557 if (buffer == nullptr) { 558 // Handle exceptions. 559 return false; 560 } 561 562 // Obtain the encoded information. 563 OH_AVCodecBufferAttr info; 564 OH_AVErrCode getBufferRet = OH_AVBuffer_GetBufferAttr(buffer, &info); 565 if (getBufferRet != AV_ERR_OK) { 566 // Handle exceptions. 567 return false; 568 } 569 // Write the encoded frame data (specified by buffer) to the output file. 570 uint8_t *addr = OH_AVBuffer_GetAddr(buffer); 571 if (addr == nullptr) { 572 // Handle exceptions. 573 return false; 574 } 575 if (outputFile != nullptr && outputFile->is_open()) { 576 outputFile->write(reinterpret_cast<char *>(addr), info.size); 577 } 578 if (info.flags & AVCODEC_BUFFER_FLAGS_EOS) { 579 outputDone = 1; 580 } 581 // Free the output buffer. index is the index of the buffer. 582 OH_AVErrCode freeOutputRet = OH_VideoEncoder_FreeOutputBuffer(videoEnc, index); 583 if (freeOutputRet != AV_ERR_OK) { 584 // Handle exceptions. 585 return false; 586 } 587 break; 588 } 589 case AV_ERR_TRY_AGAIN_LATER: { 590 break; 591 } 592 case AV_ERR_STREAM_CHANGED: { 593 break; 594 } 595 default: { 596 // Handle exceptions. 597 return false; 598 } 599 } 600 return true; 601 } 602 ``` 603 6047. Enable the encoder to input and output frames in a loop. 605 606 ```c++ 607 bool result = true; 608 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. 609 610 while (!outputDone && result) { 611 if (!inputDone) { 612 result = EncoderInput(videoEnc, timeoutUs); 613 } 614 if (!outputDone) { 615 result = EncoderOutput(videoEnc, timeoutUs); 616 } 617 } 618 ``` 619 620The subsequent processes (including refreshing, resetting, stopping, and destroying the encoder) are the same as those in surface mode. For details, see steps 9–12 in [Surface Mode](#surface-mode). 621