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![image](figures/Codec_architecture.png "Codec HDI driver framework")
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