目录结构

驱动入口:

drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_driver.cpp

vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs

HDI接口:

drivers/interface/tvservice/video/v1_0/ITvserviceVideo.idl

drivers/interface/tvservice/video/v1_0/ITvserviceVideoHdiCallback.idl

drivers/interface/tvservice/video/v1_0/TvserviceVideoTypes.idl

drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_service.cpp

drivers/peripheral/tvservice/video/interfaces/hdi_service/include/tvservice_video_service.h

ipc通信:

out/rk3568/gen/drivers/interface/tvservice/video/v1_0/tvservice_video_proxy.cpp

out/rk3568/gen/drivers/interface/tvservice/video/v1_0/tvservice_video_stub.cpp

VDI适配接口:

drivers/peripheral/tvservice/video/interfaces/vdi_base/include/tvservice_video_vdi_impl.h

drivers/peripheral/tvservice/video/interfaces/vdi_base/src/tvservice_video_vdi_impl.cpp

驱动入口

路径:drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_driver.cpp


static void HdfTvserviceVideoDriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("HdfTvserviceVideoDriverRelease enter");
}

static struct HdfDriverEntry g_tvservicevideoDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "tvservice_video_service",
    .Bind = HdfTvserviceVideoDriverBind,
    .Init = HdfTvserviceVideoDriverInit,
    .Release = HdfTvserviceVideoDriverRelease,
};

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
HDF_INIT(g_tvservicevideoDriverEntry);
#ifdef __cplusplus
}
#endif /* __cplusplus */

此处为tvservice的hdf入口,进行tvservice的初始化、接口绑定等操作,如果新增驱动需要在此处完成Bind、Init、Release等接口内容。

HCS配置文件

路径:vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs

tvservice_video :: host {
    hostName = "tvservice_video_host";
    priority = 40;
    threadPriority = 1;
    uid = "tvservice_video_host";
    gid = ["tvservice_video_host", "tvservice_video_host", "tvservice_video_host","root"];
    device_video_manager :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 0;
            permission = 0660;
            moduleName = "libtvservice_video_driver.z.so";
            serviceName = "tvservice_video_service";
        }
    }
}

配置tvservice_host的进程的信息。

hostName:host进程名。HDF框架会根据HCS配置在out中生成包含进程信息的hdf_peripheral.cfg文件,HDF框架会启动此host进程完成:驱动加载、节点生成、so库加载、接口实例化等一系列操作。

关键log:
行 2940: 08-05 17:03:06.495 524 524 I C02510/hdf_device_host: hdf device host tvservice_video_host 13 start
行 3980: 08-05 17:03:08.029 524 524 I C02510/device_node: launch devnode tvservice_video_service
关键进程:
设备ps -ef命令查看会出现tvservice_video_host进程。

moduleName:HDF框架DevHostServiceAddDevice会根据HCS配置打开这个库,并且利用g_tvservicevideoDriverEntry入口,执行Init、Bind、Release等接口内容。

HDI接口

路径:drivers/interface/tvservice/video/v1_0/ITvserviceVideo.idl

drivers/interface/tvservice/video/v1_0/ITvserviceVideoHdiCallback.idl

drivers/interface/tvservice/video/v1_0/TvserviceVideoTypes.idl

在ITvserviceVideo.idl定义HDI接口,供上层调用:

package ohos.hdi.tvservice.video.v1_0;

import ohos.hdi.tvservice.video.v1_0.ITvserviceVideoHdiCallback;
import ohos.hdi.tvservice.video.v1_0.TvserviceVideoTypes;

interface ITvserviceVideo {
   
    SetBrightness([in] unsigned int brightness);
}

ITvserviceVideo类:必须与文件名相同,并且后续使用hdi接口时,也要用ITvserviceVideo类调用。

此处为idl语法,编译之后会在out目录下根据模板生成相应代码,不需要关注具体实现,定义好接口即可。
其余内容见IPC通信章节。

IPC通信

路径:out/rk3568/gen/drivers/interface/tvservice/video/v1_0

IDL中配置好的模板会在out下生成如图所示内容。

5.1. tvservice_video_proxy.cpp

HDI接口客户端代码,主要内容包含实例化接口、各个接口的远程实现。

5.1.1. 实例化接口

Get接口参数isStub如果为false,则说明是proxy端,会进行IPC通信命令的发送,调用接口proxy实现;如果为true则是stub端,此时与tvservice_video_stub.cpp中的处理一样,进行接口实例化。


sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(bool isStub)
{
    return ITvserviceVideo::Get("tvservice_video_service", isStub);
}

sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(const std::string& serviceName, bool isStub)
{
    if (isStub) {
        std::string desc = Str16ToStr8(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor());
        void *impl = LoadHdiImpl(desc.c_str(), serviceName == "tvservice_video_service" ? "service" : serviceName.c_str());
        if (impl == nullptr) {
            HDF_LOGE("failed to load hdi impl %{public}s", desc.data());
            return nullptr;
        }
        return reinterpret_cast<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo *>(impl);
    }

    using namespace OHOS::HDI::ServiceManager::V1_0;
    auto servMgr = IServiceManager::Get();
    if (servMgr == nullptr) {
        HDF_LOGE("%{public}s:get IServiceManager failed!", __func__);
        return nullptr;
    }

    sptr<IRemoteObject> remote = servMgr->GetService(serviceName.c_str());
    if (remote == nullptr) {
        HDF_LOGE("%{public}s:get remote object failed!", __func__);
        return nullptr;
    }

    sptr<OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy> proxy = new OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy(remote);
    if (proxy == nullptr) {
        HDF_LOGE("%{public}s:iface_cast failed!", __func__);
        return nullptr;
    }

    proxy->servMgr_ = OHOS::HDI::hdi_objcast<IServiceManager>(servMgr);
    proxy->deathRecipient_ = new OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy::IServiceManagerDeathRecipient(proxy);
    proxy->servMgr_->AddDeathRecipient(proxy->deathRecipient_);
    proxy->isReconnected_ = false;
    proxy->serviceName_ = serviceName;
    uint32_t serMajorVer = 0;
    uint32_t serMinorVer = 0;
    int32_t tvserviceVideoRet = proxy->GetVersion(serMajorVer, serMinorVer);
    if (tvserviceVideoRet != HDF_SUCCESS) {
        HDF_LOGE("%{public}s:get version failed!", __func__);
        return nullptr;
    }

    if (serMajorVer != 1) {
        HDF_LOGE("%{public}s:check version failed! version of service:%u.%u, version of client:1.0", __func__, serMajorVer, serMinorVer);
        return nullptr;
    }

    return proxy;
}

5.1.2. 接口远程调用

调用此接口时,会向stub端发送cmd,此处为CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS,通知stub端进行调用。


int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoProxy::SetBrightness_(uint32_t brightness,
     const sptr<IRemoteObject> remote)
{
    MessageParcel tvserviceVideoData;
    MessageParcel tvserviceVideoReply;
    MessageOption tvserviceVideoOption(MessageOption::TF_SYNC);

    if (!tvserviceVideoData.WriteInterfaceToken(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor())) {
        HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (!tvserviceVideoData.WriteUint32(brightness)) {
        HDF_LOGE("%{public}s: write brightness failed!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (remote == nullptr) {
        HDF_LOGE("%{public}s: invalid remote object!", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    int32_t tvserviceVideoRet = remote->SendRequest(CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS, tvserviceVideoData, tvserviceVideoReply, tvserviceVideoOption);
    if (tvserviceVideoRet != HDF_SUCCESS) {
        HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, tvserviceVideoRet);
        return tvserviceVideoRet;
    }

    return tvserviceVideoRet;
}

5.2. tvservice_video_stub.cpp

HDI接口服务端代码,主要内容包含实例化接口、各个接口的本地实现。

5.2.1. 实例化接口

这里需要注意,stub和proxy的Get接口定义时一样的,都属于ITvserviceVideo类。进行HDI接口调用的时候应使用proxy远程接口,如果调用stub本地接口则会绕过ipc通信进行接口调用。

sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(bool isStub)
{
    return OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get("tvservice_video_service", isStub);
}

sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::Get(const std::string& serviceName, bool isStub)
{
    if (!isStub) {
        return nullptr;
    }
    std::string desc = Str16ToStr8(OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor());
    void *impl = LoadHdiImpl(desc.c_str(), serviceName == "tvservice_video_service" ? "service" : serviceName.c_str());
    if (impl == nullptr) {
        HDF_LOGE("failed to load hdi impl %{public}s", desc.c_str());
        return nullptr;
    }
    return reinterpret_cast<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo *>(impl);
}

5.2.2. 接口本地调用

此处会对proxy发送的命令进行接受,然后做分发处理:

int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
{
    switch (code) {
        case CMD_TVSERVICE_VIDEO_GET_VERSION:
            return TvserviceVideoStubGetVersion(data, reply, option);
        case CMD_TVSERVICE_VIDEO_SET_BRIGHTNESS:
            return TvserviceVideoStubSetBrightness(data, reply, option);
        default: {
            HDF_LOGE("%{public}s: cmd %{public}d is not supported", __func__, code);
            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
        }
    }
}

分发之后调用如下接口,通过 int32_t tvserviceVideoRet = impl->SetBrightness(brightness);调用到vdi接口。

int32_t OHOS::HDI::Tvservice::Video::V1_0::TvserviceVideoStub::TvserviceVideoStubSetBrightness_(MessageParcel& tvserviceVideoData, MessageParcel& tvserviceVideoReply, MessageOption& tvserviceVideoOption, sptr<OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo> impl)
{
    if (tvserviceVideoData.ReadInterfaceToken() != OHOS::HDI::Tvservice::Video::V1_0::ITvserviceVideo::GetDescriptor()) {
        HDF_LOGE("%{public}s: interface token check failed!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    uint32_t brightness = 0;
    if (!tvserviceVideoData.ReadUint32(brightness)) {
        HDF_LOGE("%{public}s: read brightness failed!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (impl == nullptr) {
        HDF_LOGE("%{public}s: impl is nullptr!", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    int32_t tvserviceVideoRet = impl->SetBrightness(brightness);
    if (tvserviceVideoRet != HDF_SUCCESS) {
        HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, tvserviceVideoRet);
        return tvserviceVideoRet;
    }
    return tvserviceVideoRet;
}

VDI接口

路径:drivers/peripheral/tvservice/video/interfaces/vdi_base/include/tvservice_video_vdi_impl.h

drivers/peripheral/tvservice/video/interfaces/vdi_base/src/tvservice_video_vdi_impl.cpp

此处应对接底层SetBrightness接口实现,由VDI调用芯片SDK提供的接口。

int32_t TvserviceVideoVdiImpl::SetBrightness(uint32_t brightness)
{
    TVSERVICE_LOGI("%s is not supported", __func__);
    return HDF_SUCCESS;
}

HDI接口调用例程

7.1. build.gn编译脚本

import("//build/ohos.gni")
import("../../tvservice.gni")

config("tvservice_video_test_config") {
  visibility = [ ":*" ]
  cflags = [
    "-Wall",
    "-Werror",
    "-g3",
  ]
}

config("tvservice_video_test_public_config") {
 include_dirs = [
    ".",
    "include",
    "../interfaces/hdi_service/include",
    "../interfaces/vdi_base/include",
    "../utils/include",
  ]
}

ohos_executable("tvservice_video_test") {
  install_enable = true

  sources = [
    "//drivers/peripheral/tvservice/video/interfaces/hdi_service/src/tvservice_video_service.cpp",
    "main.cpp",
  ]

  configs = [ ":tvservice_video_test_config" ]

  public_configs = [ ":tvservice_video_test_public_config" ]

  deps = [ "//drivers/peripheral/tvservice/video/interfaces/hdi_service:hdf_tvservice_video_host"]
  deps += [ "//drivers/peripheral/tvservice/video/interfaces/vdi_base:tvservice_video_vdi_impl_default" ]

  external_deps = [
    "c_utils:utils",
    "drivers_interface_tvservice:libtvservice_video_proxy_1.0",
    "hdf_core:libhdf_utils",
    "hilog:libhilog",
    "hitrace:hitrace_meter",
    "ipc:ipc_single",
  ]

  part_name = "drivers_peripheral_tvservice"
  subsystem_name = "hdf"
}
只需要依赖proxy端即可,即"drivers_interface_tvservice:libtvservice_video_proxy_1.0"。

7.2. 测试代码

 sptr<ITvserviceVideo> iTvserviceVideo_ = nullptr;

int32_t VideoTest::test(int32_t argc, const char *argv[])
{
    if(iTvserviceVideo_ == nullptr) {
        iTvserviceVideo_ = ITvserviceVideo::Get();
    }
    if(iTvserviceVideo_ == nullptr) {
        HDF_LOGI("====== iTvserviceVideo_ is nullptr");
        return -1;
    }
    int32_t ret = -1;
    int brightness = std::stoi(argv[1]);
    HDF_LOGI("====== SetBrightness brightness:%{public}d, %{public}d, %{public}d", argc,*argv[0], brightness);
    if (argc == 2) {
        HDF_LOGI("====== SetBrightness brightness 1:%{public}d", brightness);
        ret = iTvserviceVideo_->SetBrightness(brightness);
        HDF_LOGI("====== SetBrightness brightness 2:%{public}d", brightness);
    }
    if (ret != 0) {
        HDF_LOGI("====== SetBrightness failed:%{public}d", ret);
    } else {
        HDF_LOGI("====== SetBrightness succedd:%{public}d", ret);
    }

    return 0;
}

接口实例化:iTvserviceVideo_ = ITvserviceVideo::Get();,调用HDI接口时,应使用proxy端的实例化接口,Get接口参数应为false或为空。

 

相关文件下载
hdf_demo_video20250225.rar
53.93 KB
下载
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐