• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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### How to Develop
88The codec HDI driver development procedure is as follows:
89
90#### Registering and Initializing the Driver
91Define the **HdfDriverEntry** struct (which defines the driver initialization method) and fill in the **g_codeccomponentmanagerDriverEntry** struct to implement the **Bind()**, **Init()**, and **Release()** pointers.
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 struct 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 from 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#### Configuring the Driver HCS
171The HCS consists of the following:
172
173- Device configuration
174- Configuration of the supported components
175
176The HCS includes 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 **vendor/hihope/rk3568/hdf_config/uhdf/** directory.
179
1801. Configure the device.
181
182    Add the **codec_component_manager_service** configuration to **codec_host** in **device_info.hcs**.
183
184    Example:
185
186    ```c
187    codec :: host {
188        hostName = "codec_host";
189        priority = 50;
190        gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"];
191        codec_omx_idl_device :: device {
192            device0 :: deviceNode {
193                policy = 2;                                       // Automatic loading, not lazy loading.
194                priority = 100;                                   // Priority.
195                moduleName = "libcodec_driver.z.so";              // Dynamic library of the driver.
196                serviceName = "codec_component_manager_service"; // Service name of the driver.
197                deviceMatchAttr = "media_codec_capabilities";    // Attribute configuration.
198            }
199        }
200    }
201    ```
202
2032. Configure supported components.
204
205    Add the component configuration to the **media_codec\media_codec_capabilities.hcs** file.
206
207    Example:
208
209    ```c
210    /* node name explanation -- HDF_video_hw_enc_avc_rk:
211    **
212    **    HDF____________video__________________hw____________________enc____________avc_______rk
213    **     |               |                    |                      |              |        |
214    ** HDF or OMX    video or audio    hardware or software    encoder or decoder    MIME    vendor
215    */
216    HDF_video_hw_enc_avc_rk {
217        role = 1;                                           // Role of the audio and video codec.
218        type = 1;                                           // Codec type.
219        name = "OMX.rk.video_encoder.avc";                  // Component name.
220        supportProfiles = [1, 32768, 2, 32768, 8, 32768];   // Supported profiles.
221        maxInst = 4;                                        // Maximum number of instances.
222        isSoftwareCodec = false;                            // Whether it is software codec.
223        processModeMask = [];                               // Codec processing mode.
224        capsMask = [0x01];                                  // CodecCapsMask configuration.
225        minBitRate = 1;                                     // Minimum bit rate.
226        maxBitRate = 40000000;                              // Maximum bit rate.
227        minWidth = 176;                                     // Minimum video width.
228        minHeight = 144;;                                   // Minimum video height.
229        maxWidth = 1920;                                    // Maximum video width.
230        maxHeight = 1088;                                   // Maximum video height.
231        widthAlignment = 16;                                // Horizontal alignment.
232        heightAlignment = 8;                                // Vertical alignment.
233        minBlockCount = 0xFFFFFFFF;
234        maxBlockCount = 0xFFFFFFFF;
235        minBlocksPerSecond = 0xFFFFFFFF;
236        maxBlocksPerSecond = 0xFFFFFFFF;
237        blockSizeWidth = 0xFFFFFFFF;
238        blockSizeHeight = 0xFFFFFFFF;
239        supportPixelFmts = [28, 24, 20, 12];                // List of colors supported by the display.
240        measuredFrameRate = [320, 240, 165, 165, 720, 480, 149, 149, 1280, 720, 73, 73, 1920, 1080, 18, 18];
241        bitRateMode = [1, 2];                               // Bit rate mode.
242        minFrameRate = 0;                                   // Frame rate.
243        maxFrameRate = 0;
244    }
245    ```
246
247### Development Example
248After completing codec module driver adaptation, use the HDI APIs provided by the codec module for further development. The codec HDI provides the following features:
249
250- Provides codec HDI APIs for video services to implement encoding and decoding for video services.
251- 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.
252
253The development procedure is as follows:
254
2551. Initialize the driver, including initializing the instances, callbacks, and component.
2562. Set codec parameters and information such as the video width, height, and bit rate.
2573. Apply for input and output buffers.
2584. Flip codec buffers, enable the component to enter the **CODEC_STATE_EXECUTING** state, and process the callbacks.
2595. Deinitialize the interface instance, destroy the buffers, close the component, and releases all interface instances.
260
261#### Initializing the Driver
262Initialize the interface instance and callbacks, and create a component.
263```cpp
264// Initialize the codec HDI ComponentManager instance.
265omxMgr_ = ICodecComponentManager::Get(false);
266if ((omxMgr_ == nullptr)) {
267    HDF_LOGE("%{public}s omxMgr_ is null", __func__);
268    return false;
269}
270// Initialize the callback.
271callback_ = new CodecHdiCallback(shared_from_this());
272if ((callback_ == nullptr)) {
273    HDF_LOGE("%{public}s callback_ is null", __func__);
274    return false;
275}
276// Create a component instance.
277err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_);
278if (err != HDF_SUCCESS) {
279    HDF_LOGE("%{public}s failed to CreateComponent", __func__);
280    return false;
281}
282```
283
284#### Setting Codec Parameters and Configuration
285Set the width and height of the input and output data, input data format, and output data format.
286```cpp
287// Set the width and height of the input image.
288OMX_PARAM_PORTDEFINITIONTYPE param;
289if (util_->InitParam(param) != HDF_SUCCESS) {
290    return HDF_FAILURE;
291}
292param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
293
294std::vector<int8_t> inVec, outVec;
295util_->ObjectToVector(param, inVec);
296auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
297if (err != HDF_SUCCESS) {
298    HDF_LOGE("%{public}s failed  PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
299    return err;
300}
301util_->VectorToObject(outVec, param);
302
303HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ",
304         param.format.video.eCompressionFormat, param.format.video.eColorFormat);
305util_->setParmValue(param, width_, height_, stride_);
306util_->ObjectToVector(param, inVec);
307err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
308if (err != HDF_SUCCESS) {
309    HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
310    return err;
311}
312// Set the output width, height, and format.
313if (util_->InitParam(param) != HDF_SUCCESS) {
314    return HDF_FAILURE;
315}
316param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
317util_->ObjectToVector(param, inVec);
318err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
319if (err != HDF_SUCCESS) {
320    HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
321             __func__);
322    return err;
323}
324util_->VectorToObject(outVec, param);
325
326HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
327         param.format.video.eCompressionFormat, param.format.video.eColorFormat);
328util_->setParmValue(param, width_, height_, stride_);
329param.format.video.eColorFormat = AV_COLOR_FORMAT; // Set the output data format to YUV420SP.
330err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
331if (err != HDF_SUCCESS) {
332    HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
333             __func__);
334    return err;
335}
336// Set the input data format to H.264/H.265.
337OMX_VIDEO_PARAM_PORTFORMATTYPE param;
338if (util_->InitParam(param) != HDF_SUCCESS) {
339    return false;
340}
341param.nPortIndex = (uint32_t)PortIndex::PORT_INDEX_INPUT;
342std::vector<int8_t> inVec, outVec;
343util_->ObjectToVector(param, inVec);
344auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec);
345if (err != HDF_SUCCESS) {
346    HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__);
347    return false;
348}
349util_->VectorToObject(outVec, param);
350
351HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
352         param.eCompressionFormat, param.eColorFormat);
353param.xFramerate = FRAME // Set the frame rate to 30.
354if (codecMime_ == codecMime::AVC) {
355    param.eCompressionFormat = OMX_VIDEO_CodingAVC;  // H264
356} else {
357    param.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingHEVC;  // H265
358}
359
360util_->ObjectToVector(param, inVec);
361err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec);
362if (err != HDF_SUCCESS) {
363    HDF_LOGE("%{public}s failed  with PortIndex::PORT_INDEX_INPUT", __func__);
364    return false;
365}
366```
367
368#### Applying for Input and Output Buffers
369Perform the following steps:
370
3711. Use **UseBuffer()** to apply for input and output buffers and save the buffer IDs. The buffer IDs can be used for subsequent buffer flipping.
3722. Check whether the corresponding port is enabled. If not, enable the port first.
3733. Use **SendCommand()** to change the component status to **CODEC_STATE_IDLE**, and wait until the operation result is obtained.
374```cpp
375// Apply for the input buffer.
376auto err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
377if (err != HDF_SUCCESS) {
378    HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__);
379    return false;
380}
381// Apply for the output buffer.
382err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
383if (err != HDF_SUCCESS) {
384    HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__);
385    return false;
386}
387// Enable the component to enter the OMX_StateIdle state.
388std::vector<int8_t> cmdData;
389auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, cmdData);
390if (err != HDF_SUCCESS) {
391    HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
392    return false;
393}
394```
395
396Implement **UseBufferOnPort()** as follows:
397
398```cpp
399int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex)
400{
401    HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex);
402    int bufferSize = 0;
403    int bufferCount = 0;
404    bool PortEnable = false;
405    // Obtain parameters of the port buffer.
406    OMX_PARAM_PORTDEFINITIONTYPE param;
407    if (util_->InitParam(param) != HDF_SUCCESS) {
408        return HDF_FAILURE;
409    }
410    param.nPortIndex = static_cast<OMX_U32>(portIndex);
411
412    std::vector<int8_t> inVec, outVec;
413    util_->ObjectToVector(param, inVec);
414    auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
415    if (err != HDF_SUCCESS) {
416        HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]",
417                 __func__, portIndex);
418        return err;
419    }
420    util_->VectorToObject(outVec, param);
421
422    bufferSize = param.nBufferSize;
423    bufferCount = param.nBufferCountActual;
424    portEnable = param.bEnabled;
425    HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], "
426             "buffer count [%{public}d], portEnable[%{public}d], ret [%{public}d]",
427             portIndex, bufferSize, bufferCount, portEnable, err);
428    // Set the port buffer.
429    if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) {
430        err = UseBufferHandle(bufferCount, bufferSize);
431    } else {
432        err = UseBufferOnPort(portIndex, bufferCount, bufferSize);
433    }
434    // Check whether the port is available.
435    if (!portEnable) {
436        err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {});
437        if (err != HDF_SUCCESS) {
438            HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__);
439            return err;
440        }
441    }
442    return HDF_SUCCESS;
443}
444
445int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize)
446{
447    if (bufferCount <= 0 || bufferSize <= 0) {
448        HDF_LOGE("UseBufferOnPort bufferCount <= 0 or bufferSize <= 0");
449        return HDF_ERR_INVALID_PARAM;
450    }
451    for (int i = 0; i < bufferCount; i++) {
452        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
453        omxBuffer->size = sizeof(OmxCodecBuffer);
454        omxBuffer->version.s.nVersionMajor = 1;
455        omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
456        int fd = AshmemCreate(0, bufferSize);
457        shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize);
458        omxBuffer->fd = fd;
459        omxBuffer->bufferhandle = nullptr;
460        omxBuffer->allocLen = bufferSize;
461        omxBuffer->fenceFd = -1;
462        omxBuffer->pts = 0;
463        omxBuffer->flag = 0;
464
465        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
466            omxBuffer->type = READ_ONLY_TYPE;  // ReadOnly
467            sharedMem->MapReadAndWriteAshmem();
468        } else {
469            omxBuffer->type = READ_WRITE_TYPE;
470            sharedMem->MapReadOnlyAshmem();
471        }
472        OmxCodecBuffer outBuffer;
473        auto err = client_->UseBuffer((uint32_t)portIndex, *omxBuffer.get(), outBuffer);
474        if (err != HDF_SUCCESS) {
475            HDF_LOGE("%{public}s failed to UseBuffer with  portIndex[%{public}d]", __func__, portIndex);
476            sharedMem->UnmapAshmem();
477            sharedMem->CloseAshmem();
478            sharedMem = nullptr;
479            return err;
480        }
481        omxBuffer->bufferId = outBuffer.bufferId;
482        omxBuffer->fd = -1;
483        HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
484
485        std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
486        bufferInfo->omxBuffer = omxBuffer;
487        bufferInfo->avSharedPtr = sharedMem;
488        bufferInfo->portIndex = portIndex;
489        omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
490        if (portIndex == PortIndex::PORT_INDEX_INPUT) {
491            unUsedInBuffers_.push_back(omxBuffer->bufferId);
492        } else {
493            unUsedOutBuffers_.push_back(omxBuffer->bufferId);
494        }
495    }
496
497    return HDF_SUCCESS;
498}
499```
500
501#### Flipping Codec Buffers
502Set the component to the **CODEC_STATE_EXECUTING** state, fill the input buffer, read data from the output buffer, and flip the buffers.
503
504```cpp
505// Set the component to the OMX_StateExecuting state and start buffer flipping.
506HDF_LOGI("...command to CODEC_STATE_EXECUTING....");
507auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
508if (err != HDF_SUCCESS) {
509    HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
510    return;
511}
512// Set the output buffer to fill.
513if (!FillAllTheBuffer()) {
514    HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
515    return;
516}
517// Fill the input buffer.
518auto t1 = std::chrono::system_clock::now();
519bool eosFlag = false;
520while (!eosFlag) {
521    if (this->exit_) {
522        break;
523    }
524    int bufferID = GetFreeBufferId();
525    if (bufferID < 0) {
526        usleep(10000);  // 10000 for wait 10ms
527        continue;
528    }
529    auto iter = omxBuffers_.find(bufferID);
530    if (iter == omxBuffers_.end()) {
531        continue;
532    }
533    auto bufferInfo = iter->second;
534    void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
535    eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
536    bufferInfo->omxBuffer->offset = 0;
537    if (eosFlag) {
538        bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
539    }
540    err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
541    if (err != HDF_SUCCESS) {
542        HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
543        return;
544    }
545}
546// Wait.
547while (!this->exit_) {
548    usleep(10000);  // 10000 for wait 10ms
549}
550// Enable the component to enter the OMX_StateIdle state after decoding.
551auto t2 = std::chrono::system_clock::now();
552std::chrono::duration<double> diff = t2 - t1;
553HDF_LOGI("cost %{public}f, count=%{public}d", diff.count(), count_);
554(void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
555return;
556}
557```
558
559Automatic framing is not supported in rk OMX decoding. Therefore, you need to manually divide data into frames. Currently, data is divided into frames from code 0x000001 or 0x00000001 and sent to the server for processing. The sample code is as follows:
560
561```cpp
562// Read a file by frame.
563bool CodecHdiDecode::ReadOnePacket(FILE *fp, char *buf, uint32_t &filledCount)
564{
565    // Read the start code.
566    size_t t = fread(buf, 1, START_CODE_SIZE_FRAME, fp);
567    if (t < START_CODE_SIZE_FRAME) {
568        return true;
569    }
570    char *temp = buf;
571    temp += START_CODE_SIZE_FRAME;
572    bool ret = true;
573    while (!feof(fp)) {
574        (void)fread(temp, 1, 1, fp);
575        if (*temp != START_CODE) {
576            temp++;
577            continue;
578        }
579        // Check the start code.
580        if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) &&
581            (temp[START_CODE_OFFSET_THIRD] == 0)) {
582            fseek(fp, -START_CODE_SIZE_FRAME, SEEK_CUR);
583            temp -= (START_CODE_SIZE_FRAME - 1);
584            ret = false;
585            break;
586            }
587        if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) {
588            fseek(fp, -START_CODE_SIZE_SLICE, SEEK_CUR);
589            temp -= (START_CODE_SIZE_SLICE - 1);
590            ret = false;
591            break;
592        }
593        temp++;
594    }
595    filledCount = (temp - buf);
596    return ret;
597}
598```
599
600The codec HDI provides the following callbacks:
601
602- **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.
603- **EmptyBufferDone**: Called when the input data is consumed. If the client needs to fill data to encode or decode, it must call **EmptyThisBuffer()** again.
604- **FillBufferDone**: Called when the output data is filled. If the client needs to read the encoded or decoded data, it must call **FillThisBuffer()** again.
605
606```cpp
607// EmptyBufferDone example
608int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
609{
610    HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId);
611    unique_lock<mutex> ulk(lockInputBuffers_);
612    unUsedInBuffers_.push_back(buffer.bufferId);
613    return HDF_SUCCESS;
614}
615// FillBufferDone example
616int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
617{
618    HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId);
619    if (exit_) {
620        return HDF_SUCCESS;
621    }
622
623    auto iter = omxBuffers_.find(buffer.bufferId);
624    if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) {
625        return HDF_SUCCESS;
626    }
627    count_++;
628    // read buffer
629    auto bufferInfo = iter->second;
630    if (bufferInfo->avSharedPtr != nullptr) {
631        const void *addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset);
632        (void)fwrite(addr, 1, buffer.filledLen, fpOut_);
633    } else if (bufferInfo->bufferHandle != nullptr && gralloc_ != nullptr) {
634        gralloc_->Mmap(*bufferInfo->bufferHandle);
635        (void)fwrite(bufferInfo->bufferHandle->virAddr, 1, buffer.filledLen, fpOut_);
636        gralloc_->Unmap(*bufferInfo->bufferHandle);
637    }
638
639    (void)fflush(fpOut_);
640    if (buffer.flag == OMX_BUFFERFLAG_EOS) {
641        // end
642        exit_ = true;
643        HDF_LOGI("OnFillBufferDone the END coming");
644        return HDF_SUCCESS;
645    }
646    // call fillthisbuffer again
647    auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
648    if (err != HDF_SUCCESS) {
649        HDF_LOGE("%{public}s FillThisBuffer error", __func__);
650        return HDF_SUCCESS;
651    }
652    return HDF_SUCCESS;
653}
654// EventHandler example
655int32_t CodecHdiDecode::EventHandler(CodecEventType event, const EventInfo &info)
656{
657    switch (event) {
658        case CODEC_EVENT_CMD_COMPLETE: {
659            CodecCommandType cmd = (CodecCommandType)info.data1;
660            if (CODEC_COMMAND_STATE_SET == cmd) {
661                HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2);
662                this->OnStatusChanged();
663            }
664            break;
665        }
666        case OMX_EventPortSettingsChanged: {
667            HDF_LOGI("OMX_EventPortSeetingsChanged reached");
668            this->HandleEventPortSettingsChanged(info.data1, info.data2);
669        }
670
671        default:
672            break;
673    }
674
675    return HDF_SUCCESS;
676}
677```
678
679#### Destroying a Component
680Change 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.
681
682##### Releasing Buffers
683
684```cpp
685// Change the component state to OMX_StateLoaded.
686client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
687
688// Release all buffers in use.
689auto iter = omxBuffers_.begin();
690while (iter != omxBuffers_.end()) {
691    auto bufferInfo = iter->second;
692    iter = omxBuffers_.erase(iter);
693    (void)client_->FreeBuffer((uint32_t)bufferInfo->portIndex, *bufferInfo->omxBuffer.get());
694    bufferInfo = nullptr;
695}
696
697unUsedInBuffers_.clear();
698unUsedOutBuffers_.clear();
699
700// After the buffers are released, the component enters the OMX_StateLoaded state.
701CodecStateType status = CODEC_STATE_INVALID;
702int32_t err = HDF_SUCCESS;
703int32_t tryCount = 3;
704do {
705    err = client_->GetState(status);
706    if (err != HDF_SUCCESS) {
707        HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
708        break;
709    }
710    if (status != CODEC_STATE_LOADED) {
711        HDF_LOGI("Wait for OMX_StateLoaded status");
712        this->WaitForStatusChanged();
713    }
714    tryCount--;
715} while ((status != CODEC_STATE_LOADED) && (tryCount > 0));
716```
717
718##### Destroying a Component Instance
719
720```cpp
721// Destroy a component instance.
722void CodecHdiDecode::Release()
723{
724    omxMgr_->DestoryComponent(componentId_);
725    client_ = nullptr;
726    callback_ = nullptr;
727    omxMgr_ = nullptr;
728}
729```
730
731# FAQs
732
733## Green Screens Displayed During the Decoding Process
734
735**Symptom**
736
737Green screens are displayed during the decoding process.
738
739**Possible Causes**
740
741OpenMAX does not support framing.
742
743**Solution**
744
745When **EmptyThisBuffer** is call, only one frame can be passed in at a time.
746
747## Only Green Screen Displayed During the Decoding Process
748
749**Symptom**
750
751Decoding fails, and all the frames decoded cannot be played.
752
753**Possible Causes**
754
755For the data in AVCC format, the first frame to be processed must be extra_data.
756
757**Solution**
758
759Write sps and pps to the buffer in extra_data format, and set the buffer flag to **OMX_BUFFERFLAG_EXTRADATA**.
760
761## Failed to Play the Encoded Video
762
763**Symptom**
764
765After the generated video stream (H.264 stream) is written to a file, the video stream cannot be played by FFplay.
766
767**Possible Causes**
768
7691. The **xFramerate** parameter of the output port is incorrectly set.
7702. The **OMX_VIDEO_PARAM_AVCTYPE** parameter is correctly set.
771
772**Solution**
773
774View 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**.
775
776
777# Reference
778
779For more information, see [Codec](https://gitee.com/openharmony/drivers_peripheral/tree/master/codec).
780