OpenHarmony 3.2 Release版本实战开发——Codec HDI适配过程

简介

OpenHarmony Codec HDI(Hardware Device Interface)驱动框架基于 OpenMax 实现了视屏硬件编解码驱动,提供 Codec 基础能力接口供上层媒体服务调用,包括获取组件编解码能力、创建组件、参数设置、数据的轮转和控制、以及销毁组件等功能,实现对视频数据的编解码处理。

视频编解码驱动架构

Codec HDI 2.0 接口依赖 OpenMax IL 的标准接口。OMX Wrapper 将 OMX 接口的实现封装成 libOMX_Core.z.so 供 HDI 层调用。如果 codec 驱动为实现 OpenMax 标准接口,则需根据驱动适配实现 OMX Interface 接口。

Codec HDI 2.0 接口列表:

头文件接口名称功能描述
codec_component _manager.hint32_t (*GetComponentNum)();获取 Codec 编解码组件数量
int32_t (*GetComponentCapabilityList)(CodecCompCapability *capList, int32_t count);获取编解码能力集表
int32_t (*CreateComponent)(struct CodecComponentType **component, uint32_t *componentId, char *compName, int64_t appData, struct CodecCallbackType *callbacks);创建 Codec 组件实例
int32_t (*DestroyComponent)(uint32_t componentId);销毁组件实例
codec_component _if.hint32_t (*GetComponentVersion)(struct CodecComponentType *self, struct CompVerInfo *verInfo);获取 Codec 组件版本号
int32_t (*SendCommand)(struct CodecComponentType *self, enum OMX_COMMANDTYPE cmd, uint32_t param, int8_t *cmdData, uint32_t cmdDataLen);发送命令给组件
int32_t (*GetParameter)(struct CodecComponentType *self, uint32_t paramIndex, int8_t *paramStruct, uint32_t paramStructLen);获取组件参数设置
int32_t (*SetParameter)(struct CodecComponentType *self, uint32_t index, int8_t *paramStruct, uint32_t paramStructLen);设置组件需要的参数
int32_t (*GetConfig)(struct CodecComponentType *self, uint32_t index, int8_t *cfgStruct, uint32_t cfgStructLen);获取组件的配置结构
int32_t (*SetConfig)(struct CodecComponentType *self, uint32_t index, int8_t *cfgStruct, uint32_t cfgStructLen);设置组件的配置
int32_t (*GetExtensionIndex)(struct CodecComponentType *self, const char *paramName, uint32_t *indexType);根据字符串获取组件的扩展索引
int32_t (*GetState)(struct CodecComponentType *self, enum OMX_STATETYPE *state);获取组件的状态
int32_t (*ComponentTunnelRequest)(struct CodecComponentType *self, uint32_t port, int32_t tunneledComp, uint32_t tunneledPort, struct OMX_TUNNELSETUPTYPE *tunnelSetup);设置组件 Tunneled 方式通信
int32_t (*UseBuffer)(struct CodecComponentType *self, uint32_t portIndex, struct OmxCodecBuffer *buffer);指定组件端口的 buffer
int32_t (*AllocateBuffer)(struct CodecComponentType *self, uint32_t portIndex, struct OmxCodecBuffer *buffer);向组件申请端口 buffer
int32_t (*FreeBuffer)(struct CodecComponentType *self, uint32_t portIndex, const struct OmxCodecBuffer *buffer);释放 buffer
int32_t (*EmptyThisBuffer)(struct CodecComponentType *self, const struct OmxCodecBuffer *buffer);编解码输入待处理 buffer
int32_t (*FillThisBuffer)(struct CodecComponentType *self, const struct OmxCodecBuffer *buffer);编解码输出填充 buffer
int32_t (*SetCallbacks)(struct CodecComponentType *self, struct CodecCallbackType *callback, int64_t appData);设置 Codec 组件的回调函数
int32_t (*ComponentDeInit)(struct CodecComponentType *self);组件去初始化
int32_t (*UseEglImage)(struct CodecComponentType *self, struct OmxCodecBuffer *buffer, uint32_t portIndex, int8_t *eglImage, uint32_t eglImageLen);使用已在 ELG 中申请的空间
int32_t (*ComponentRoleEnum)(struct CodecComponentType *self, uint8_t *role, uint32_t roleLen, uint32_t index);获取组件角色
codec_callback_if.hint32_t (*EventHandler)(struct CodecCallbackType *self, enum OMX_EVENTTYPE event, struct EventInfo *info);事件上报
int32_t (*EmptyBufferDone)(struct CodecCallbackType *self, int64_t appData, const struct OmxCodecBuffer *buffer);上报输入 buffer 编码或者解码处理完毕
int32_t (*FillBufferDone)(struct CodecCallbackType *self, int64_t appData, const struct OmxCodecBuffer *buffer);上报输出 buffer 填充完毕

Codec HDI 相关目录接口

├── //drivers/peripheral/codec
│   ├── hal
│   │   ├── BUILD.gn
│   │   ├── idl_service
│   │   ├── include
│   │   ├── passthrough             # v2.0到v1.0的转换,v1.0接口已弃用,无需实现
│   │   ├── src
│   │   ├── v1.0                    # codec hdi v1.0接口的实现,已弃用,MediaService已不对接相关接口。
│   │   └── v2.0                    # codec hdi v2.0接口的实现,依赖OpenMax接口,需封装实现libOMX_Core.z.so
│   ├── hdi_service                 # codec_host相关实现
│   │   ├── BUILD.gn
│   │   ├── codec_proxy
│   │   ├── codec_service_stub
│   │   └── common
│   ├── interfaces
│   │   └── include
│   └── test

OMX_Core 相关接口

codec hdi V2.0 的实现依赖 libOMX_Core.z.so,需根据 OpenMax 标准接口封装实现。

参考 drivers/peripheral/codec/hal/v2.0/hdi_impl/include/codec_omx_core.h 的定义调用过程。

typedef OMX_ERRORTYPE (*InitFunc)();
typedef OMX_ERRORTYPE (*DeinitFunc)();
typedef OMX_ERRORTYPE (*ComponentNameEnumFunc)(OMX_STRING, OMX_U32, OMX_U32);
typedef OMX_ERRORTYPE (*GetHandleFunc)(OMX_HANDLETYPE *, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE *);
typedef OMX_ERRORTYPE (*FreeHandleFunc)(OMX_HANDLETYPE);
typedef OMX_ERRORTYPE (*GetRolesOfComponentFunc)(OMX_STRING, OMX_U32 *, OMX_U8 **);

HCS 配置

配置 codec_host 服务

./hdf_config/uhdf/device_info.hcs

codec :: host {
    hostName = "codec_host";
    priority = 50;
    gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"];
    codec_omx_device :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            moduleName = "libcodec_hdi_omx_server.z.so";
            serviceName = "codec_hdi_omx_service";
            deviceMatchAttr = "media_codec_capabilities";
        }
    }
}

配置 codec_capabilities

根据 codec::host 中配置的 deviceMatchAttr,配置 hdf.hcs

./hdf_config/uhdf/hdf.hcs

#include "media_codec_capabilitie.hcs"

参考 media_codec_capabilitie.hcs

root {
    module = "master";
    codec_config {
        match_attr = "media_codec_capabilities";
        use_openmax = true;
        // capsMask: 0x01, Adaptive playback; 0x02, Secure playback; 0x04, Tunnel playback.
        // allocateMask: 0x01, Input buffer allocated within the Codec module;
        // allocateMask: 0x02, Input buffer allocated by an external user;
        // allocateMask: 0x04, Output buffer allocated within the Codec module;
        // allocateMask: 0x08, Output buffer allocated by an external user.

        VideoHwEncoders {
            /* node name explanation -- HDF_video_hw_enc_avc_rk:
            **
            **    HDF____________video__________________hw____________________enc____________avc_______rk
            **     |               |                    |                      |              |        |
            ** HDF or OMX    video or audio    hardware or software    encoder or decoder    mime    vendor
            */
            HDF_video_hw_enc_avc_rk {
                role = 1;
                type = 1;
                name = "OMX.rk.video_encoder.avc";
                supportProfiles = [1, 32768, 2, 32768, 8, 32768];
                maxInst = 4;
                isSoftwareCodec = false;
                processModeMask = [];
                capsMask = [0x01];
                minBitRate = 1;
                maxBitRate = 40000000;
                minWidth = 176;
                minHeight = 144;
                maxWidth = 1920;
                maxHeight = 1088;
                widthAlignment = 16;
                heightAlignment = 8;
                minBlockCount = 99;
                maxBlockCount = 8160;
                minBlocksPerSecond = 99;
                maxBlocksPerSecond = 489600;
                blockSizeWidth = 16;
                blockSizeHeight = 16;
                supportPixelFmts = [28, 24, 20, 12];
                measuredFrameRate = [320, 240, 165, 165, 720, 480, 149, 149, 1280, 720, 73, 73, 1920, 1080, 18, 18];
                bitRateMode = [1, 2];
                minFrameRate = 1;
                maxFrameRate = 60;
            }
            ......
            ......
            ......
      }
}

RK3568 的参考适配过程

OMX Wrapper 的封装

根据 gn 文件://drivers/peripheral/codec/BUILD.gn

OMX_IL_PATH = rebase_path(
          "//device/soc/${device_company}/${product_name}/hardware/omx_il")
  cmd = "if [ -f ${OMX_IL_PATH}/BUILD.gn ]; then echo true; else echo false; fi"
  HAVE_OMX_IL_PATH =
      exec_script("//build/lite/run_shell_cmd.py", [ cmd ], "value")

  if (HAVE_OMX_IL_PATH) {
    deps += [ "${OMX_IL_PATH}:lib_omx" ]
  }

需创建 lib_omx 工程,并封装实现 libOMX_Core.z.so,供 codec hdi 接口调用。

如果 codec 驱动已实现 OpenMax 标准接口,则可直接封装 libOMX_Core 库,否则需要根据私有驱动实现 OpenMax 接口。

参考 RK3568 的适配过程,因 codec 驱动使用 rockchip 的 mpp 平台实现,需根据私有驱动实现 OpenMax 的接口。

参考 gn 文件://device/soc/rockchip/rk3568/hardware/omx_il/BUILD.gn

group("lib_omx") {
  if (product_name == "rk3568") {
    deps = [
      "//device/soc/rockchip/rk3568/hardware/omx_il/component/video/dec:libomxvpu_dec",
      "//device/soc/rockchip/rk3568/hardware/omx_il/component/video/enc:libomxvpu_enc",
      "//device/soc/rockchip/rk3568/hardware/omx_il/core:libOMX_Core",
      "//device/soc/rockchip/rk3568/hardware/omx_il/libOMXPlugin:libOMX_Pluginhw",
    ]
  }
}

hcs 配置

  • 配置 codec_host 服务
    //vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs

    codec :: host {
        hostName = "codec_host";
        priority = 50;
        gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"];
        codec_omx_device :: device {
            device0 :: deviceNode {
                policy = 2;
                priority = 100;
                moduleName = "libcodec_hdi_omx_server.z.so";
                serviceName = "codec_hdi_omx_service";
                deviceMatchAttr = "codec_component_capabilities";
            }
        }
    }
    
    
  • 配置 codec hcs
    需根据硬件信息配置编解码组件的配置参数
    //vendor/hihope/rk3568/hdf_config/uhdf/hdf.hcs

    #include "media_codec/codec_component_capabilities.hcs"
    
    

    //vendor/hihope/rk3568/hdf_config/uhdf/media_codec/codec_component_capabilities.hcs

    root {
        module = "master";
        codec_config {
            match_attr = "codec_component_capabilities";
            use_openmax = true;
            // capsMask: 0x01, Adaptive playback; 0x02, Secure playback; 0x04, Tunnel playback.
            // allocateMask: 0x01, Input buffer allocated within the Codec module;
            // allocateMask: 0x02, Input buffer allocated by an external user;
            // allocateMask: 0x04, Output buffer allocated within the Codec module;
            // allocateMask: 0x08, Output buffer allocated by an external user.
    
            VideoHwEncoders {
                /* node name explanation -- HDF_video_hw_enc_avc_rk:
                **
                **    HDF____________video__________________hw____________________enc____________avc_______rk
                **     |               |                    |                      |              |        |
                ** HDF or OMX    video or audio    hardware or software    encoder or decoder    mime    vendor
                */
                HDF_video_hw_enc_avc_rk {
                    role = 1;
                    type = 1;
                    name = "OMX.rk.video_encoder.avc";
                    supportProfiles = [1, 32768, 2, 32768, 8, 32768];
                    maxInst = 4;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 40000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 16;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 0xFFFFFFFF;
                    maxBlocksPerSecond = 0xFFFFFFFF;
                    blockSizeWidth = 0xFFFFFFFF;
                    blockSizeHeight = 0xFFFFFFFF;
                    supportPixelFmts = [28, 24, 20, 12];
                    measuredFrameRate = [320, 240, 165, 165, 720, 480, 149, 149, 1280, 720, 73, 73, 1920, 1080, 18, 18];
                    bitRateMode = [1, 2];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
            }
            VideoHwDecoders {
                HDF_video_hw_dec_avc_rk {
                    role = 1;
                    type = 0;
                    name = "OMX.rk.video_decoder.avc";
                    supportProfiles = [1, 32768, 2, 32768, 8, 32768];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 4096;
                    maxHeight = 2160;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [320, 240, 617, 617, 720, 480, 559, 559, 1280, 720, 276, 276, 1920, 1080, 164, 164, 3840, 2160, 30, 30];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_mpeg2_rk {
                    role = 0xFFFFFFFF;
                    type = 0;
                    name = "OMX.rk.video_decoder.m2v";
                    supportProfiles = [0, 3, 1, 3];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 8;
                    supportPixelFmts = [24];
                    measuredFrameRate = [];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_v8p_rk {
                    role = 0xFFFFFFFF;
                    type = 0;
                    name = "OMX.rk.video_decoder.vp8";
                    supportProfiles = [];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [320, 180, 500, 500, 640, 360, 387, 387, 1280, 720, 112, 112, 1920, 1080, 77, 77];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_h263_rk {
                    role = 0xFFFFFFFF;
                    type = 0;
                    name = "OMX.rk.video_decoder.h263";
                    supportProfiles = [1, 1, 1, 2, 1, 4, 1, 16, 8, 1, 8, 2, 8, 4, 8, 16];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [176, 144, 600, 600, 352, 288, 600, 600];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_m4v_rk {
                    role = 3;
                    type = 0;
                    name = "OMX.rk.video_decoder.m4v";
                    supportProfiles = [1, 1, 1, 2, 1, 4, 1, 8, 1, 16];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [176, 144, 600, 600];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_flv_rk {
                    role = 0xFFFFFFFF;
                    type = 0;
                    name = "OMX.rk.video_decoder.flv1";
                    supportProfiles = [];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_mjpeg_rk {
                    role = 0;
                    type = 0;
                    name = "OMX.rk.video_decoder.mjpeg";
                    supportProfiles = [];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 10000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 8;
                    heightAlignment = 8;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
                HDF_video_hw_dec_hevc_rk {
                    role = 2;
                    type = 0;
                    name = "OMX.rk.video_decoder.hevc";
                    supportProfiles = [1, 1, 1, 4, 1, 16, 1, 64, 1, 256, 1, 1024, 1, 4096, 1, 16384, 1, 65536, 2, 65536];
                    maxInst = 6;
                    isSoftwareCodec = false;
                    processModeMask = [];
                    capsMask = [0x01];
                    minBitRate = 1;
                    maxBitRate = 160000000;
                    minWidth = 176;
                    minHeight = 144;
                    maxWidth = 1920;
                    maxHeight = 1088;
                    widthAlignment = 2;
                    heightAlignment = 2;
                    minBlockCount = 0xFFFFFFFF;
                    maxBlockCount = 0xFFFFFFFF;
                    minBlocksPerSecond = 1;
                    maxBlocksPerSecond = 244800;
                    blockSizeWidth = 16;
                    blockSizeHeight = 16;
                    supportPixelFmts = [24];
                    measuredFrameRate = [352, 288, 700, 700, 720, 480, 700, 700, 640, 360, 980, 980, 1280, 720, 600, 600, 1920, 1080, 130, 130, 3840, 2160, 130, 130];
                    bitRateMode = [];
                    minFrameRate = 0;
                    maxFrameRate = 0;
                }
            }
            VideoSwEncoders {
            }
            VideoSwDecoders {
            }
            AudioHwEncoders {
            }
            AudioHwDecoders {
            }
            AudioSwEncoders {
            }
            AudioSwDecoders {
            }
        }
    }
    
    

适配验证

  • 当系统启动后,拉起 codec_host 进程,日志中有加载 hcs 配置的 component 相关组件的 log,则初步判定适配过程正常。

  • 当前系统通过 gstreamer 插件实现视频编解码功能。当未实现硬件编解码时,默认使用 FFmpeg 软件编解码。
    codec hdi 插件加载过程如下:
    ///foundation/multimedia/player_framework/services/engine/gstreamer/plugins/codec/hdi_plugins/hdi_init.cpp

    void HdiInit::AddHdiCap(CodecCompCapability &hdiCap)
    {
        MEDIA_LOGI("Add codec name %{public}s", hdiCap.compName);
        CapabilityData codecCap;
        codecCap.codecName = hdiCap.compName;
        codecCap.codecType = GetCodecType(hdiCap.type);
        codecCap.mimeType = GetCodecMime(hdiCap.role);
        codecCap.isVendor = !hdiCap.isSoftwareCodec;
        codecCap.alignment = {hdiCap.port.video.whAlignment.widthAlignment, hdiCap.port.video.whAlignment.heightAlignment};
        codecCap.bitrateMode = GetBitrateMode(hdiCap.port.video);
        codecCap.width = {hdiCap.port.video.minSize.width, hdiCap.port.video.maxSize.width};
        codecCap.height = {hdiCap.port.video.minSize.height, hdiCap.port.video.maxSize.height};
        codecCap.bitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
        codecCap.frameRate = {hdiCap.port.video.frameRate.min, hdiCap.port.video.frameRate.max};
        codecCap.format = GetCodecFormats(hdiCap.port.video);
        codecCap.blockPerFrame = {hdiCap.port.video.blockCount.min, hdiCap.port.video.blockCount.max};
        codecCap.blockPerSecond = {hdiCap.port.video.blocksPerSecond.min, hdiCap.port.video.blocksPerSecond.max};
        codecCap.blockSize = {hdiCap.port.video.blockSize.width, hdiCap.port.video.blockSize.height};
        codecCap.measuredFrameRate = GetMeasuredFrameRate(hdiCap.port.video);
        codecCap.profileLevelsMap = GetCodecProfileLevels(hdiCap);
        capabilitys_.push_back(codecCap);
    }
    

码牛课堂也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线。大家可以进行参考学习:https://qr21.cn/FV7h05

①全方位,更合理的学习路径
路线图包括ArkTS基础语法、鸿蒙应用APP开发、鸿蒙能力集APP开发、次开发多端部署开发、物联网开发等九大模块,六大实战项目贯穿始终,由浅入深,层层递进,深入理解鸿蒙开发原理!

②多层次,更多的鸿蒙原生应用
路线图将包含完全基于鸿蒙内核开发的应用,比如一次开发多端部署、自由流转、元服务、端云一体化等,多方位的学习内容让学生能够高效掌握鸿蒙开发,少走弯路,真正理解并应用鸿蒙的核心技术和理念。

③实战化,更贴合企业需求的技术点
学习路线图中的每一个技术点都能够紧贴企业需求,经过多次真实实践,每一个知识点、每一个项目,都是码牛课堂鸿蒙研发团队精心打磨和深度解析的成果,注重对学生的细致教学,每一步都确保学生能够真正理解和掌握。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:https://qr21.cn/FV7h05

如何快速入门:

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr21.cn/FV7h05

大厂鸿蒙面试题::https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/609048.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

晶片的厚度会影响晶振的频率吗?

晶振,是一种能够产生稳定频率的电子元件,广泛应用于各种电子设备中。晶振的频率参数,即其振荡产生的频率大小,是晶振性能的重要指标之一。石英晶体的切割方式显得至关重要。不同的切割方式,如AT-cut、CT-cut、SC-cut等…

文心一言 VS 讯飞星火 VS chatgpt (255)-- 算法导论18.1 1题

一、请说明依次从图18-8(f)中删除C、P和V后的结果。如果要写代码,请用go语言。 文心一言: 首先,让我们明确一点:由于您没有提供具体的图18-8(f)的内容,我只能假设它是一个数据结构(可能是图、树或列表等&…

1011: 二叉排序树的实现和查找

解法: 二叉排序树(Binary Search Tree,简称BST)也被称为二叉搜索树或二叉查找树,是一种重要的二叉树结构,它具有以下性质: 左子树上所有节点的值都小于根节点的值;右子树上所有节点的…

网络编程套接字和传输层tcp,udp协议

认识端口号 我们知道在网络数据传输的时候,在IP数据包头部有两个IP地址,分别叫做源IP地址和目的IP地址。IP地址是帮助我们在网络中确定最终发送的主机,但是实际上数据应该发送到主机上指定的进程上的,所以我们不仅要确定主机&…

单片机智能灯控制系统源程序仿真原理图与论文全套资料

目录 1、设计描述 2、仿真图 3、程序 4、资料内容 资料下载地址:单片机智能灯控制系统源程序仿真原理图与论文全套资料下载 1、设计描述 设计了一款智能控制系统。 AT89C51LCD1602DS1302按键LED组成了这样一个完整的设计。 P2.0-P2.3 4个LED等代表庭院内的4…

Mock.js 问题记录

文章目录 Mock.js 问题记录1. 浮点数范围限制对小数不起效2. increment 全局共用 Mock.js 问题记录 最新写网页的时候引入了 Mock.js 来生成模拟数据; Mock使用起来很方便,具体可以参考 官网 很快就能上手, 但是这个项目最近一次提交还是在2…

Windows 跨服务器进行 MYSQL备份脚本

Windows 服务器进行 MYSQL备份的脚本,使用该脚本前,请先测试一下 1、新建一个文本文档 2、将下面代码放入文本文档中,保存退出 echo off :: 命令窗口名 title mysql-bak:: 参数定义 set "Y%date:~,4%" set "m%date:~5,2%&qu…

公司服务器内网OA网站如何实现外网访问?

目前很多公司会用windows自带的IIS搭建局域网ftp服务器,并搭建WEB服务办公网站。公司内部OA服务器,在公司内网是可以正常访问的,如何将公司内部的OA服务器映射到internet网络,让不在公司的企业员工可以正常访问到内部的OA服务器&a…

你用什么笔记软件记录自己的成长过程?

大家好,这里是大话硬件。祝大家新年好! 前两天我们在群里谈到记笔记的软件,其中有人记日记一开始是使用手写,后面改为电子笔记软件。作为一个知识型的博主,在笔记软件方面属于深度用户,有些笔记软件会员充到了几年后,在多年的使用中,总结了一些方法。 基于上次聊到的…

未授权访问:Jenkins未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 4、利用未授权访问写入webshell 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验,一共有好多篇,内容主要是参考先知社区的一位大佬的关于未授权访问的好文章,还有其他大佬总结好…

Visual Studio编译QT工程

1、安装QT 2、安装VS 3、选择扩展和更新 4、搜索Qt Visual Studio Tools,安装或卸载 5、安装成功后工具栏显示Qt VS Tools 6、配置Qt VS Tools:打开Qt VS Tools的下拉菜单,选择Qt Versions 7、选择qt qmake.exe 的路径

【知识碎片】2024_05_09

本篇记录了关于C语言的一些题目(puts,printf函数的返回值,getchar,跳出多重循环),和一道关于位运算的代码[整数转换]。 C语言碎片知识 如下程序的功能是( ) #…

通过编写dockerfile部署python项目

docker命令总览 docker通过dockerfile构建镜像常用命令 # 创建镜像(进入dockerfile所在的路径) docker build -t my_image:1.0 .# 查看镜像 docker images# 创建容器 docker run -dit --restartalways -p 9700:9700 --name my_container my_image:1.0 #…

互动科技如何强化法治教育基地体验?

近年来,多媒体互动技术正日益融入我们生活的各个角落,法治教育领域亦不例外。步入法治教育基地,我们不难发现,众多创新的多媒体互动装置如雨后春笋般涌现,这些装置凭借前沿的科技手段,不仅极大地丰富了法制…

电机控制系列模块解析(20)—— MTPA

一、MTPA MTPA 是 "Maximum Torque Per Ampere" 的缩写,意为“最大转矩电流比”。在电机控制系统中,特别是永磁同步电机(PMSM)或其它永磁电机的控制策略中,MTPA 控制旨在实现电机在给定负载条件下&#xff…

利用ansible playbook部署LNMP架构

接:ansible批量运维管理-CSDN博客 由于host01主机环境不纯净,决定弃用host01主机,编写剧本时要确保环境纯洁 (只做实验用途一台控制) [rootansible-server ~]# vim /etc/ansible/hosts [webserver] host02 1、在a…

盲盒一番赏小程序:探索未知,开启神秘宝藏之旅

开启神秘之门,探索未知的乐趣 在繁忙的生活中,我们渴望一丝丝未知带来的惊喜与乐趣。盲盒一番赏小程序,正是为了满足您这种探索未知的欲望而诞生。它不仅仅是一个购物平台,更是一个充满神秘与惊喜的宝藏世界。 精选好物&#xf…

AI视频教程下载:给企业管理层和商业精英的ChatGpt课程

课程内容大纲: 1-引言 2-面向初学者的生成性人工智能 3-与ChatGPT一起学习提示101 详细介绍了如何使用ChatGPT的六种沟通模式,并提供了各种实际应用场景和示例: **Q&A模式(问题与答案模式)**: - 这…

如何在mac电脑安装 Android SDK

1、在 Mac 电脑上安装 Android SDK 的步骤如下: 前往 Android 开发者网站下载 Android SDK 打开 Android 开发者网站 (https://developer.android.com/studio) 打开下载好的 Android SDK 安装包 2、解压 Android SDK 安装包 打开下载好的 Android SDK 安装包 将 android-…

Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件

目录 1. 前言 2. 部署Node服务 2.1. 前置环境安装 2.2. 将Node服务加入集群 3. 部署JNI网络插件 4. 测试集群 5. 总结 1. 前言 我们在上一篇文章完成了Matster结点的部署,这次我们接着来部署Node服务,注意,我Node服务是部署在另外两台…