1# Codec 2 3## Overview 4### Function 5 6The OpenHarmony codec Hardware Device Interface (HDI) driver framework implements the video hardware codec driver based on OpenMAX. It provides APIs for the upper-layer media services to obtain component encoding and decoding capabilities, create a component, set parameters, transfer data, and destroy a component. The codec driver can encode video data in YUV or RGB format to H.264 or H.265 format, and decode raw stream data from H.264 or H.265 format to YUV or RGB format. This document describes the codec functionality developed based on the OpenHarmony Hardware Driver Foundation (HDF). 7 8The codec HDI driver framework is implemented based on the HDF. The figure below shows the codec HDI driver framework. 9 10**Figure 1** Codec HDI driver framework 11 12 13 14- Codec HDI Callback Remote Service: an anonymous callback service used to process callbacks. 15- Codec HDI: provides standard APIs based on OpenMAX. The upper layer services call the APIs to implement hardware encoding and decoding. 16- Codec HDI Adapter: HDI implementation layer, which implements HDI APIs and interacts with OpenMAX Integration layer (IL). 17- OpenMAX IL interface: provides OpenMAX IL APIs to directly interact with the codec HDI driver. 18- Vendor Impl: vendor adaptation layer, which is the OpenMAX implementation layer adapted by each vendor. 19- Codec Hardware: hardware decoding device. 20 21### Basic Concepts 22Before you get started, understand the following concepts: 23 24- Sampling rate 25 26 The number of samples taken from continuous signals every second to form discrete signals, in Hz. 27 28- OpenMAX IL 29 30 A standardized media component interface to enable applications and media frameworks to interact with multimedia codecs and supported components in a unified manner. 31 32- Frame rate 33 34 Number of frames of images transmitted per second, or the number of times that a GPU can refresh images per second. A higher frame rate indicates smoother motion, while a lower frame rate means choppier motion and blurry footage. 35 36- Bit rate 37 38 Number of bits transmitted or processed per unit of time, generally in kbit/s. A higher bit rate indicates clearer image, while a lower bit rate means blurry image with artifacts. 39 40- Component 41 42 An OpenMAX IL component, which is an abstraction of modules in video streams. The components in this document refer to codec components used for video encoding and decoding. 43 44### Constraints 45 46The codec HDI applies only to the standard system. 47 48For more details, see [OpenMAX IL](https://www.khronos.org/api/openmax/il). 49 50## Development Guidelines 51 52### When to Use 53The codec module implements hardware encoding and decoding of video data. It converts raw stream data such as H.264 data into YUV or RGB data, and converts YUV or RGB data into data formats such as H.264. 54 55### Available APIs 56 57- icodec_component_manager.h 58 59 | API | Description | 60 | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------| 61 | int32_t CreateComponent(sptr<ICodecComponent>& component, uint32_t& componentId,<br>const std::string& compName, int64_t appData, const sptr<ICodecCallback>& callbacks) | Creates a codec component instance. | 62 | int32_t DestoryComponent(uint32_t componentId) | Destroys a codec component instance. | 63 64- icodec_component.h 65 66 | API | Description | 67 | ------------------------------------------------------------ | ---------------------- | 68 | int32_t SendCommand(CodecCommandType cmd, uint32_t param, const std::vector<int8_t>& cmdData) | Sends commands to a component. | 69 | int32_t GetParameter(uint32_t index, const std::vector<int8_t>& inParamStruct, std::vector<int8_t>& outParamStruct) | Obtains component parameter settings. | 70 | int32_t SetParameter(uint32_t index, const std::vector<int8_t>& paramStruct) | Sets component parameters. | 71 | int32_t GetState(CodecStateType& state) | Obtains the component status. | 72 | int32_t UseBuffer(uint32_t portIndex, const OmxCodecBuffer& inBuffer, OmxCodecBuffer& outBuffer) | Requests a port buffer for the component. | 73 | int32_t FreeBuffer(uint32_t portIndex, const OmxCodecBuffer& buffer) | Releases the buffer. | 74 | int32_t EmptyThisBuffer(const OmxCodecBuffer& buffer) | Empties this buffer.| 75 | int32_t FillThisBuffer(const OmxCodecBuffer& buffer) | Fills this buffer. | 76 77- icodec_callback.h 78 79 | API | Description | 80 | ------------------------------------------------------------ | ---------------------------------- | 81 | int32_t EventHandler(CodecEventType event, const EventInfo& info) | Called to report an event. | 82 | int32_t EmptyBufferDone(int64_t appData, const OmxCodecBuffer& buffer) | Called to report an event indicating that the encoding or decoding in the input buffer is complete.| 83 | int32_t FillBufferDone(int64_t appData, const OmxCodecBuffer& buffer) | Called to report an event indicating that the output buffer is filled. | 84 85For more information, see [codec](https://gitee.com/openharmony/drivers_peripheral/tree/master/codec). 86 87### Development Procedure 88The codec HDI driver development procedure is as follows: 89 90#### Registering and Initializing the Driver 91Define the **HdfDriverEntry** structure (which defines the driver initialization method) and fill in the **g_codeccomponentmanagerDriverEntry** structure to implement the pointers in **Bind()**, **Init()**, and **Release()**. 92 93```c 94static struct HdfDriverEntry g_codeccomponentmanagerDriverEntry = { 95 .moduleVersion = 1, 96 .moduleName = "codec_component_manager_service", 97 .Bind = HdfCodecComponentManagerDriverBind, 98 .Init = HdfCodecComponentManagerDriverInit, 99 .Release = HdfCodecComponentManagerDriverRelease, 100}; // Register the HdfDriverEntry structure of the codec HDI with the HDF. 101``` 102 103- **HdfCodecComponentManagerDriverBind**: binds the device in the HDF to the **HdfCodecComponentManagerHost** and registers the codec service with the HDF. 104 105 ```c 106 static int HdfCodecComponentManagerDriverBind(struct HdfDeviceObject *deviceObject) 107 { 108 CODEC_LOGI("HdfCodecComponentManagerDriverBind enter"); 109 110 auto *hdfCodecComponentManagerHost = new (std::nothrow) HdfCodecComponentManagerHost; 111 if (hdfCodecComponentManagerHost == nullptr) { 112 CODEC_LOGE("failed to create create HdfCodecComponentManagerHost object"); 113 return HDF_FAILURE; 114 } 115 116 hdfCodecComponentManagerHost->ioService.Dispatch = CodecComponentManagerDriverDispatch; 117 hdfCodecComponentManagerHost->ioService.Open = NULL; 118 hdfCodecComponentManagerHost->ioService.Release = NULL; 119 120 auto serviceImpl = ICodecComponentManager::Get(true); 121 if (serviceImpl == nullptr) { 122 CODEC_LOGE("failed to get of implement service"); 123 delete hdfCodecComponentManagerHost; 124 return HDF_FAILURE; 125 } 126 127 hdfCodecComponentManagerHost->stub = 128 OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, ICodecComponentManager::GetDescriptor()); 129 if (hdfCodecComponentManagerHost->stub == nullptr) { 130 CODEC_LOGE("failed to get stub object"); 131 delete hdfCodecComponentManagerHost; 132 return HDF_FAILURE; 133 } 134 135 deviceObject->service = &hdfCodecComponentManagerHost->ioService; 136 return HDF_SUCCESS; 137 } 138 ``` 139 140- **HdfCodecComponentManagerDriverInit**: loads the attribute configuration in the HDF Configuration Source (HCS). 141 142 ```c 143 static int HdfCodecComponentManagerDriverInit(struct HdfDeviceObject *deviceObject) 144 { 145 CODEC_LOGI("HdfCodecComponentManagerDriverInit enter"); 146 if (DevHostRegisterDumpHost(CodecDfxService::DevCodecHostDump) != HDF_SUCCESS) { 147 CODEC_LOGE("DevHostRegisterDumpHost error!"); 148 } 149 return HDF_SUCCESS; 150 } 151 ``` 152 153- **HdfCodecComponentTypeDriverRelease**: releases the driver instance. 154 155 ```c 156 static void HdfCodecComponentManagerDriverRelease(struct HdfDeviceObject *deviceObject) 157 { 158 CODEC_LOGI("HdfCodecComponentManagerDriverRelease enter"); 159 if (deviceObject->service == nullptr) { 160 CODEC_LOGE("HdfCodecComponentManagerDriverRelease not initted"); 161 return; 162 } 163 164 auto *hdfCodecComponentManagerHost = 165 CONTAINER_OF(deviceObject->service, struct HdfCodecComponentManagerHost, ioService); 166 delete hdfCodecComponentManagerHost; 167 } 168 ``` 169 170#### Driver HCS 171The HCS consists of the following: 172 173- Device configuration 174- Configuration of the supported components 175 176You need to configure the driver node, loading sequence, and service name. For details about the HCS syntax, see [Configuration Management](driver-hdf-manage.md). 177 178The following uses the RK3568 development board as an example. The configuration files of the standard system are in the 179**vendor/hihope/rk3568/hdf_config/uhdf/** directory. 180 1811. Configure the device. 182 183 Add the **codec_component_manager_service** configuration to **codec_host** in **device_info.hcs**. The following is an example: 184 ```c 185 codec :: host { 186 hostName = "codec_host"; 187 priority = 50; 188 gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"]; 189 codec_omx_idl_device :: device { 190 device0 :: deviceNode { 191 policy = 2; // Automatic loading, not lazy loading. 192 priority = 100; // Priority. 193 moduleName = "libcodec_driver.z.so"; // Dynamic library of the driver. 194 serviceName = "codec_component_manager_service"; // Service name of the driver. 195 deviceMatchAttr = "media_codec_capabilities"; // Attribute configuration. 196 } 197 } 198 } 199 ``` 200 2012. Configure supported components. 202 203 Add the component configuration to the **media_codec\media_codec_capabilities.hcs** file. The following is an example: 204 ```c 205 /* Explanation to the node name HDF_video_hw_enc_avc_rk: 206 ** 207 ** HDF____________video__________________hw____________________enc____________avc_______rk 208 ** | | | | | | 209 ** HDF or OMX video or audio hardware or software encoder or decoder MIME vendor 210 */ 211 HDF_video_hw_enc_avc_rk { 212 role = 1; // Role of the audio and video codec. 213 type = 1; // Codec type. 214 name = "OMX.rk.video_encoder.avc"; // Component name. 215 supportProfiles = [1, 32768, 2, 32768, 8, 32768]; // Supported profiles. 216 maxInst = 4; // Maximum number of instances. 217 isSoftwareCodec = false; // Whether it is software codec. 218 processModeMask = []; // Codec processing mode. 219 capsMask = [0x01]; // CodecCapsMask configuration. 220 minBitRate = 1; // Minimum bit rate. 221 maxBitRate = 40000000; // Maximum bit rate. 222 minWidth = 176; // Minimum video width. 223 minHeight = 144;; // Minimum video height. 224 maxWidth = 1920; // Maximum video width. 225 maxHeight = 1088; // Maximum video height. 226 widthAlignment = 16; // Horizontal alignment. 227 heightAlignment = 8; // Vertical alignment. 228 minBlockCount = 0xFFFFFFFF; 229 maxBlockCount = 0xFFFFFFFF; 230 minBlocksPerSecond = 0xFFFFFFFF; 231 maxBlocksPerSecond = 0xFFFFFFFF; 232 blockSizeWidth = 0xFFFFFFFF; 233 blockSizeHeight = 0xFFFFFFFF; 234 supportPixelFmts = [28, 24, 20, 12]; // List of colors supported by the display. 235 measuredFrameRate = [320, 240, 165, 165, 720, 480, 149, 149, 1280, 720, 73, 73, 1920, 1080, 18, 18]; 236 bitRateMode = [1, 2]; // Bit rate mode. 237 minFrameRate = 0; // Frame rate. 238 maxFrameRate = 0; 239 } 240 ``` 241 242### Development Example 243After completing codec module driver adaptation, use the HDI APIs provided by the codec module for further development. The codec HDI provides the following features: 244 2451. Provides codec HDI APIs for video services to implement encoding and decoding for video services. 2462. Provides standard interfaces for device developers to ensure that the OEM vendors comply with the HDI adapter standard. This promises a healthy evolution of the ecosystem. 247 248The development procedure is as follows: 249 2501. Initialize the driver, including initializing the instances, callbacks, and component. 2512. Set codec parameters and information such as the video width, height, and bit rate. 2523. Apply for input and output buffers. 2534. Flip codec buffers, enable the component to enter the **CODEC_STATE_EXECUTING** state, and process the callbacks. 2545. Deinitialize the interface instance, destroy the buffers, close the component, and releases all interface instances. 255 256#### Initializing the Driver 257Initialize the interface instance and callbacks, and create a component. 258```cpp 259// Initialize the codec HDI ComponentManager instance. 260omxMgr_ = ICodecComponentManager::Get(false); 261if ((omxMgr_ == nullptr)) { 262 HDF_LOGE("%{public}s omxMgr_ is null", __func__); 263 return false; 264} 265// Initialize the callback. 266callback_ = new CodecHdiCallback(shared_from_this()); 267if ((callback_ == nullptr)) { 268 HDF_LOGE("%{public}s callback_ is null", __func__); 269 return false; 270} 271// Create a component instance. 272err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_); 273if (err != HDF_SUCCESS) { 274 HDF_LOGE("%{public}s failed to CreateComponent", __func__); 275 return false; 276} 277``` 278 279#### Setting Codec Parameters and Configuration 280Set the width and height of the input and output data, input data format, and output data format. 281```cpp 282// Set the width and height of the input image. 283OMX_PARAM_PORTDEFINITIONTYPE param; 284if (util_->InitParam(param) != HDF_SUCCESS) { 285 return HDF_FAILURE; 286} 287param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT); 288 289std::vector<int8_t> inVec, outVec; 290util_->ObjectToVector(param, inVec); 291auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 292if (err != HDF_SUCCESS) { 293 HDF_LOGE("%{public}s failed PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__); 294 return err; 295} 296util_->VectorToObject(outVec, param); 297 298HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ", 299 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 300util_->setParmValue(param, width_, height_, stride_); 301util_->ObjectToVector(param, inVec); 302err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec); 303if (err != HDF_SUCCESS) { 304 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__); 305 return err; 306} 307// Set the output width, height, and format. 308if (util_->InitParam(param) != HDF_SUCCESS) { 309 return HDF_FAILURE; 310} 311param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT); 312util_->ObjectToVector(param, inVec); 313err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 314if (err != HDF_SUCCESS) { 315 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 316 __func__); 317 return err; 318} 319util_->VectorToObject(outVec, param); 320 321HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 322 param.format.video.eCompressionFormat, param.format.video.eColorFormat); 323util_->setParmValue(param, width_, height_, stride_); 324param.format.video.eColorFormat = AV_COLOR_FORMAT; // Set the output data format to YUV420SP. 325err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec); 326if (err != HDF_SUCCESS) { 327 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", 328 __func__); 329 return err; 330} 331// Set the input data format to H.264/H.265. 332OMX_VIDEO_PARAM_PORTFORMATTYPE param; 333if (util_->InitParam(param) != HDF_SUCCESS) { 334 return false; 335} 336param.nPortIndex = (uint32_t)PortIndex::PORT_INDEX_INPUT; 337std::vector<int8_t> inVec, outVec; 338util_->ObjectToVector(param, inVec); 339auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec); 340if (err != HDF_SUCCESS) { 341 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__); 342 return false; 343} 344util_->VectorToObject(outVec, param); 345 346HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d", 347 param.eCompressionFormat, param.eColorFormat); 348param.xFramerate = FRAME // Set the frame rate to 30. 349if (codecMime_ == codecMime::AVC) { 350 param.eCompressionFormat = OMX_VIDEO_CodingAVC; // H264 351} else { 352 param.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingHEVC; // H265 353} 354 355util_->ObjectToVector(param, inVec); 356err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec); 357if (err != HDF_SUCCESS) { 358 HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__); 359 return false; 360} 361``` 362 363#### Applying for Input and Output Buffers 364Perform the following steps: 365 3661. Use **UseBuffer()** to apply for input and output buffers and save the buffer IDs. The buffer IDs can be used for subsequent buffer flipping. 3672. Check whether the corresponding port is enabled. If not, enable the port first. 3683. Use **SendCommand()** to change the component status to **CODEC_STATE_IDLE**, and wait until the operation result is obtained. 369```cpp 370// Apply for the input buffer. 371auto err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT); 372if (err != HDF_SUCCESS) { 373 HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__); 374 return false; 375} 376// Apply for the output buffer. 377err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT); 378if (err != HDF_SUCCESS) { 379 HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__); 380 return false; 381} 382// Enable the component to enter the OMX_StateIdle state. 383std::vector<int8_t> cmdData; 384auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, cmdData); 385if (err != HDF_SUCCESS) { 386 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__); 387 return false; 388} 389``` 390 391Implement **UseBufferOnPort()** as follows: 392 393```cpp 394int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex) 395{ 396 HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex); 397 int bufferSize = 0; 398 int bufferCount = 0; 399 bool PortEnable = false; 400 // Obtain parameters of the port buffer. 401 OMX_PARAM_PORTDEFINITIONTYPE param; 402 if (util_->InitParam(param) != HDF_SUCCESS) { 403 return HDF_FAILURE; 404 } 405 param.nPortIndex = static_cast<OMX_U32>(portIndex); 406 407 std::vector<int8_t> inVec, outVec; 408 util_->ObjectToVector(param, inVec); 409 auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec); 410 if (err != HDF_SUCCESS) { 411 HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]", 412 __func__, portIndex); 413 return err; 414 } 415 util_->VectorToObject(outVec, param); 416 417 bufferSize = param.nBufferSize; 418 bufferCount = param.nBufferCountActual; 419 portEnable = param.bEnabled; 420 HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], " 421 "buffer count [%{public}d], portEnable[%{public}d], ret [%{public}d]", 422 portIndex, bufferSize, bufferCount, portEnable, err); 423 // Set the port buffer. 424 if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) { 425 err = UseBufferHandle(bufferCount, bufferSize); 426 } else { 427 err = UseBufferOnPort(portIndex, bufferCount, bufferSize); 428 } 429 // Check whether the port is available. 430 if (!portEnable) { 431 err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {}); 432 if (err != HDF_SUCCESS) { 433 HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__); 434 return err; 435 } 436 } 437 return HDF_SUCCESS; 438} 439 440int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize) 441{ 442 if (bufferCount <= 0 || bufferSize <= 0) { 443 HDF_LOGE("UseBufferOnPort bufferCount <= 0 or bufferSize <= 0"); 444 return HDF_ERR_INVALID_PARAM; 445 } 446 for (int i = 0; i < bufferCount; i++) { 447 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>(); 448 omxBuffer->size = sizeof(OmxCodecBuffer); 449 omxBuffer->version.s.nVersionMajor = 1; 450 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD; 451 int fd = AshmemCreate(0, bufferSize); 452 shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize); 453 omxBuffer->fd = fd; 454 omxBuffer->bufferhandle = nullptr; 455 omxBuffer->allocLen = bufferSize; 456 omxBuffer->fenceFd = -1; 457 omxBuffer->pts = 0; 458 omxBuffer->flag = 0; 459 460 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 461 omxBuffer->type = READ_ONLY_TYPE; // ReadOnly 462 sharedMem->MapReadAndWriteAshmem(); 463 } else { 464 omxBuffer->type = READ_WRITE_TYPE; 465 sharedMem->MapReadOnlyAshmem(); 466 } 467 OmxCodecBuffer outBuffer; 468 auto err = client_->UseBuffer((uint32_t)portIndex, *omxBuffer.get(), outBuffer); 469 if (err != HDF_SUCCESS) { 470 HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex); 471 sharedMem->UnmapAshmem(); 472 sharedMem->CloseAshmem(); 473 sharedMem = nullptr; 474 return err; 475 } 476 omxBuffer->bufferId = outBuffer.bufferId; 477 omxBuffer->fd = -1; 478 HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId); 479 480 std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>(); 481 bufferInfo->omxBuffer = omxBuffer; 482 bufferInfo->avSharedPtr = sharedMem; 483 bufferInfo->portIndex = portIndex; 484 omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo)); 485 if (portIndex == PortIndex::PORT_INDEX_INPUT) { 486 unUsedInBuffers_.push_back(omxBuffer->bufferId); 487 } else { 488 unUsedOutBuffers_.push_back(omxBuffer->bufferId); 489 } 490 } 491 492 return HDF_SUCCESS; 493} 494``` 495 496#### Codec Buffer Flipping 497Set the component to the **CODEC_STATE_EXECUTING** state, fill the input buffer, read data from the output buffer, and flip the buffers. 498 499```cpp 500// Set the component to the OMX_StateExecuting state and start buffer flipping. 501HDF_LOGI("...command to CODEC_STATE_EXECUTING...."); 502auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {}); 503if (err != HDF_SUCCESS) { 504 HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__); 505 return; 506} 507// Set the output buffer to fill. 508if (!FillAllTheBuffer()) { 509 HDF_LOGE("%{public}s FillAllTheBuffer error", __func__); 510 return; 511} 512// Fill the input buffer. 513auto t1 = std::chrono::system_clock::now(); 514bool eosFlag = false; 515while (!eosFlag) { 516 if (this->exit_) { 517 break; 518 } 519 int bufferID = GetFreeBufferId(); 520 if (bufferID < 0) { 521 usleep(10000); // 10000 for wait 10ms 522 continue; 523 } 524 auto iter = omxBuffers_.find(bufferID); 525 if (iter == omxBuffers_.end()) { 526 continue; 527 } 528 auto bufferInfo = iter->second; 529 void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0)); 530 eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen); 531 bufferInfo->omxBuffer->offset = 0; 532 if (eosFlag) { 533 bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS; 534 } 535 err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get()); 536 if (err != HDF_SUCCESS) { 537 HDF_LOGE("%{public}s EmptyThisBuffer error", __func__); 538 return; 539 } 540} 541// Wait. 542while (!this->exit_) { 543 usleep(10000); // 10000 for wait 10ms 544} 545// Enable the component to enter the OMX_StateIdle state after decoding. 546auto t2 = std::chrono::system_clock::now(); 547std::chrono::duration<double> diff = t2 - t1; 548HDF_LOGI("cost %{public}f, count=%{public}d", diff.count(), count_); 549(void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {}); 550return; 551} 552``` 553 554The RK3568 development board does not support data framing during the decoding process. Therefore, you need to manually divide the data into frames from code 0x000001 or 0x00000001 and sent the frames to the server for processing. The sample code is as follows: 555 556```cpp 557// Read a file by frame. 558bool CodecHdiDecode::ReadOnePacket(FILE *fp, char *buf, uint32_t &filledCount) 559{ 560 // Read the start code. 561 size_t t = fread(buf, 1, START_CODE_SIZE_FRAME, fp); 562 if (t < START_CODE_SIZE_FRAME) { 563 return true; 564 } 565 char *temp = buf; 566 temp += START_CODE_SIZE_FRAME; 567 bool ret = true; 568 while (!feof(fp)) { 569 (void)fread(temp, 1, 1, fp); 570 if (*temp != START_CODE) { 571 temp++; 572 continue; 573 } 574 // Check the start code. 575 if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) && 576 (temp[START_CODE_OFFSET_THIRD] == 0)) { 577 fseek(fp, -START_CODE_SIZE_FRAME, SEEK_CUR); 578 temp -= (START_CODE_SIZE_FRAME - 1); 579 ret = false; 580 break; 581 } 582 if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) { 583 fseek(fp, -START_CODE_SIZE_SLICE, SEEK_CUR); 584 temp -= (START_CODE_SIZE_SLICE - 1); 585 ret = false; 586 break; 587 } 588 temp++; 589 } 590 filledCount = (temp - buf); 591 return ret; 592} 593``` 594 595The codec HDI provides the following callbacks: 596 597- **EventHandler**: Called when a command is executed. For example, when the command for changing the component state from **CODEC_STATE_IDLE** to **CODEC_STATE_EXECUTING** is executed, this callback is invoked to return the result. 598- **EmptyBufferDone**: Called when the input data is consumed. If the client needs to fill data to encode or decode, it must call **EmptyThisBuffer()** again. 599- **FillBufferDone**: Called when the output data is filled. If the client needs to read the encoded or decoded data, it must call **FillThisBuffer()** again. 600 601```cpp 602// EmptyBufferDone example 603int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer) 604{ 605 HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId); 606 unique_lock<mutex> ulk(lockInputBuffers_); 607 unUsedInBuffers_.push_back(buffer.bufferId); 608 return HDF_SUCCESS; 609} 610// FillBufferDone example 611int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer) 612{ 613 HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId); 614 if (exit_) { 615 return HDF_SUCCESS; 616 } 617 618 auto iter = omxBuffers_.find(buffer.bufferId); 619 if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) { 620 return HDF_SUCCESS; 621 } 622 count_++; 623 // read buffer 624 auto bufferInfo = iter->second; 625 if (bufferInfo->avSharedPtr != nullptr) { 626 const void *addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset); 627 (void)fwrite(addr, 1, buffer.filledLen, fpOut_); 628 } else if (bufferInfo->bufferHandle != nullptr && gralloc_ != nullptr) { 629 gralloc_->Mmap(*bufferInfo->bufferHandle); 630 (void)fwrite(bufferInfo->bufferHandle->virAddr, 1, buffer.filledLen, fpOut_); 631 gralloc_->Unmap(*bufferInfo->bufferHandle); 632 } 633 634 (void)fflush(fpOut_); 635 if (buffer.flag == OMX_BUFFERFLAG_EOS) { 636 // end 637 exit_ = true; 638 HDF_LOGI("OnFillBufferDone the END coming"); 639 return HDF_SUCCESS; 640 } 641 // call fillthisbuffer again 642 auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get()); 643 if (err != HDF_SUCCESS) { 644 HDF_LOGE("%{public}s FillThisBuffer error", __func__); 645 return HDF_SUCCESS; 646 } 647 return HDF_SUCCESS; 648} 649// EventHandler example 650int32_t CodecHdiDecode::EventHandler(CodecEventType event, const EventInfo &info) 651{ 652 switch (event) { 653 case CODEC_EVENT_CMD_COMPLETE: { 654 CodecCommandType cmd = (CodecCommandType)info.data1; 655 if (CODEC_COMMAND_STATE_SET == cmd) { 656 HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2); 657 this->OnStatusChanged(); 658 } 659 break; 660 } 661 case OMX_EventPortSettingsChanged: { 662 HDF_LOGI("OMX_EventPortSeetingsChanged reached"); 663 this->HandleEventPortSettingsChanged(info.data1, info.data2); 664 } 665 666 default: 667 break; 668 } 669 670 return HDF_SUCCESS; 671} 672``` 673 674#### Destroying a Component 675Change the component state to **CODEC_STATE_IDLE**, release the input and output buffers, change the component state to **CODEC_STATE_LOADED**, and call **DestoryComponent** to destroy the component. 676 677##### Example of Releasing Buffers 678 679```cpp 680// Change the component state to OMX_StateLoaded. 681client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {}); 682 683// Release all buffers in use. 684auto iter = omxBuffers_.begin(); 685while (iter != omxBuffers_.end()) { 686 auto bufferInfo = iter->second; 687 iter = omxBuffers_.erase(iter); 688 (void)client_->FreeBuffer((uint32_t)bufferInfo->portIndex, *bufferInfo->omxBuffer.get()); 689 bufferInfo = nullptr; 690} 691 692unUsedInBuffers_.clear(); 693unUsedOutBuffers_.clear(); 694 695// After the buffers are released, the component enters the OMX_StateLoaded state. 696CodecStateType status = CODEC_STATE_INVALID; 697int32_t err = HDF_SUCCESS; 698int32_t tryCount = 3; 699do { 700 err = client_->GetState(status); 701 if (err != HDF_SUCCESS) { 702 HDF_LOGE("%s GetState error [%{public}x]", __func__, err); 703 break; 704 } 705 if (status != CODEC_STATE_LOADED) { 706 HDF_LOGI("Wait for OMX_StateLoaded status"); 707 this->WaitForStatusChanged(); 708 } 709 tryCount--; 710} while ((status != CODEC_STATE_LOADED) && (tryCount > 0)); 711``` 712 713##### Example of Destroying a Component Instance 714 715```cpp 716// Destroy a component instance. 717void CodecHdiDecode::Release() 718{ 719 omxMgr_->DestoryComponent(componentId_); 720 client_ = nullptr; 721 callback_ = nullptr; 722 omxMgr_ = nullptr; 723} 724``` 725 726# FAQs 727 728## Green Screens Displayed During the Decoding Process 729 730**Symptom** 731 732Green screens are displayed during the decoding process. 733 734**Possible Causes** 735 736OpenMAX does not support framing. 737 738**Solution** 739 740When **EmptyThisBuffer** is call, only one frame can be passed in at a time. 741 742## Only Green Screen Displayed During the Decoding Process 743 744**Symptom** 745 746Decoding fails, and all the frames decoded cannot be played. 747 748**Possible Causes** 749 750For the data in AVCC format, the first frame to be processed must be extra_data. 751 752**Solution** 753 754Write sps and pps to the buffer in extra_data format, and set the buffer flag to **OMX_BUFFERFLAG_EXTRADATA**. 755 756## Failed to Play the Encoded Video 757 758**Symptom** 759 760After the generated video stream (H.264 stream) is written to a file, the video stream cannot be played by FFplay. 761 762**Possible Causes** 763 7641. The **xFramerate** parameter of the output port is incorrectly set. 7652. The **OMX_VIDEO_PARAM_AVCTYPE** parameter is correctly set. 766 767**Solution** 768 769View the **codec_host** log generated during encoding, search for "encode params init settings", and check for incorrect parameters. If **framerate** is **0**, **xFramerate** is incorrectly set. In this case, move the frame rate leftwards by 16 bits. <br>In other cases, correct the setting of **OMX_VIDEO_PARAM_AVCTYPE**. 770 771 772# Reference 773 774For more information, see [codec](https://gitee.com/openharmony/drivers_peripheral/tree/master/codec). 775