OpenHarmony 3.2 Beta多媒体系列——视频录制

OpenHarmony实战开发-如何实现简单视频录制并直接得到视频本地文件的场景。 当前仅支持AVRecorder开发视频录制,集成了音频捕获,音频编码,视频编码,音视频封装功能,适用于实现简单视频录制并直接得到视频本地文件的场景。 阅读详情

一、简介

媒体子系统为开发者提供了媒体相关的很多功能,本文针对其中的视频录制功能做个详细的介绍。首先,我将通过媒体子系统提供的视频录制Test代码作为切入点,给大家梳理一下整个录制的流程。

二、目录

foundation/multimedia/camera_framework

├── frameworks
│   ├── js
│   │   └── camera_napi                            #napi实现
│   │       └── src
│   │           ├── input                          #Camera输入
│   │           ├── output                         #Camera输出
│   │           └── session                        #会话管理
│   └── native                                     #native实现
│       └── camera
│           ├── BUILD.gn
│           ├── src
│           │   ├── input                          #Camera输入
│           │   ├── output                         #Camera输出
│           │   └── session                        #会话管理
├── interfaces                                     #接口定义
│   ├── inner_api                                  #内部native实现
│   │   └── native
│   │       ├── camera
│   │       │   └── include
│   │       │       ├── input
│   │       │       ├── output
│   │       │       └── session
│   └── kits                                       #napi接口
│       └── js
│           └── camera_napi
│               ├── BUILD.gn
│               ├── include
│               │   ├── input
│               │   ├── output
│               │   └── session
│               └── @ohos.multimedia.camera.d.ts
└── services                                       #服务端
    └── camera_service
        ├── binder
        │   ├── base
        │   ├── client                             #IPC的客户端
        │   │   └── src
        │   └── server                             #IPC的服务端
        │       └── src
        └── src

三、录制的总体流程

四、Native接口使用

在OpenAtom OpenHarmony(以下简称“OpenHarmony”)系统中,多媒体子系统通过N-API接口提供给上层JS调用,N-API相当于是JS和Native之间的桥梁,在OpenHarmony源码中,提供了C++直接调用视频录制功能的例子,foundation/multimedia/camera_framework/interfaces/inner_api/native/test目录中。本文章主要参考了camera_video.cpp文件中的视频录制流程。

首先根据camera_video.cpp的main方法,了解下视频录制的主要流程代码。

int main(int argc, char **argv)
{
    ......

    // 创建CameraManager实例
    sptr<CameraManager> camManagerObj = CameraManager::GetInstance();

    // 设置回调
    camManagerObj->SetCallback(std::make_shared<TestCameraMngerCallback>(testName));

    // 获取支持的相机设备列表
    std::vector<sptr<CameraDevice>> cameraObjList = camManagerObj->GetSupportedCameras();

    // 创建采集会话
    sptr<CaptureSession> captureSession = camManagerObj->CreateCaptureSession();

    // 开始配置采集会话
    captureSession->BeginConfig();

    // 创建CameraInput
    sptr<CaptureInput> captureInput = camManagerObj->CreateCameraInput(cameraObjList[0]);
    sptr<CameraInput> cameraInput = (sptr<CameraInput> &)captureInput;

    // 开启CameraInput
    cameraInput->Open();

    // 设置CameraInput的Error回调
    cameraInput->SetErrorCallback(std::make_shared<TestDeviceCallback>(testName));

    // 添加CameraInput实例到采集会话中
    ret = captureSession->AddInput(cameraInput);

    sptr<Surface> videoSurface = nullptr;
    std::shared_ptr<Recorder> recorder = nullptr;

    // 创建Video的Surface
    videoSurface = Surface::CreateSurfaceAsConsumer();

    sptr<SurfaceListener> videoListener = new SurfaceListener("Video", SurfaceType::VIDEO, g_videoFd, videoSurface);

    // 注册Surface的事件监听
    videoSurface->RegisterConsumerListener((sptr<IBufferConsumerListener> &)videoListener);

    // 视频的配置
    VideoProfile videoprofile = VideoProfile(static_cast<CameraFormat>(videoFormat), videosize, videoframerates);

    // 创建VideoOutput实例
    sptr<CaptureOutput> videoOutput = camManagerObj->CreateVideoOutput(videoprofile, videoSurface);

    // 设置VideoOutput的回调
    ((sptr<VideoOutput> &)videoOutput)->SetCallback(std::make_shared<TestVideoOutputCallback>(testName));

    // 添加videoOutput到采集会话中
    ret = captureSession->AddOutput(videoOutput);

    // 提交会话配置
    ret = captureSession->CommitConfig();

    // 开始录制
    ret = ((sptr<VideoOutput> &)videoOutput)->Start();


    sleep(videoPauseDuration);
    MEDIA_DEBUG_LOG("Resume video recording");
    // 暂停录制
    ret = ((sptr<VideoOutput> &)videoOutput)->Resume();

    MEDIA_DEBUG_LOG("Wait for 5 seconds before stop");
    sleep(videoCaptureDuration);
    MEDIA_DEBUG_LOG("Stop video recording");
    // 停止录制
    ret = ((sptr<VideoOutput> &)videoOutput)->Stop();

    MEDIA_DEBUG_LOG("Closing the session");
    // 停止采集会话
    ret = captureSession->Stop();

    MEDIA_DEBUG_LOG("Releasing the session");
    // 释放会话采集
    captureSession->Release();

    // Close video file
    TestUtils::SaveVideoFile(nullptr, 0, VideoSaveMode::CLOSE, g_videoFd);
    cameraInput->Release();
    camManagerObj->SetCallback(nullptr);
    return 0;
}

以上是视频录制的整体流程,其过程主要通过Camera模块支持的能力来实现,其中涉及几个重要的类:CaptureSession、CameraInput、VideoOutput。CaptureSession是整个过程的控制者,CameraInput和VideoOutput相当于是设备的输入和输出。

五、调用流程

后续主要针对上面的调用流程,梳理具体的调用流程,方便我们对了解视频录制的整理架构有一个更加深入的了解。

1. 创建CameraManager实例

通过CameraManager::GetInstance()获取CameraManager的实例,后续的一些接口都是通过该实例进行调用的。GetInstance使用了单例模式,在OpenHarmony代码中这种方式很常见。

sptr<CameraManager> &CameraManager::GetInstance()
{
    if (CameraManager::cameraManager_ == nullptr) {
        MEDIA_INFO_LOG("Initializing camera manager for first time!");
        CameraManager::cameraManager_ = new(std::nothrow) CameraManager();
        if (CameraManager::cameraManager_ == nullptr) {
            MEDIA_ERR_LOG("CameraManager::GetInstance failed to new CameraManager");
        }
    }
    return CameraManager::cameraManager_;
}

2. 获取支持的相机设备列表

通过调用CameraManager的GetSupportedCameras()接口,获取设备支持的CameraDevice列表。跟踪代码可以发现serviceProxy_->GetCameras最终会调用到Camera服务端的对应接口。

std::vector<sptr<CameraDevice>> CameraManager::GetSupportedCameras()
{
    CAMERA_SYNC_TRACE;

    std::lock_guard<std::mutex> lock(mutex_);
    std::vector<std::string> cameraIds;
    std::vector<std::shared_ptr<Camera::CameraMetadata>> cameraAbilityList;
    int32_t retCode = -1;
    sptr<CameraDevice> cameraObj = nullptr;
    int32_t index = 0;

    if (cameraObjList.size() > 0) {
        cameraObjList.clear();
    }
    if (serviceProxy_ == nullptr) {
        MEDIA_ERR_LOG("CameraManager::GetCameras serviceProxy_ is null, returning empty list!");
        return cameraObjList;
    }
    std::vector<sptr<CameraDevice>> supportedCameras;
    retCode = serviceProxy_->GetCameras(cameraIds, cameraAbilityList);
    if (retCode == CAMERA_OK) {
        for (auto& it : cameraIds) {
            cameraObj = new(std::nothrow) CameraDevice(it, cameraAbilityList[index++]);
            if (cameraObj == nullptr) {
                MEDIA_ERR_LOG("CameraManager::GetCameras new CameraDevice failed for id={public}%s", it.c_str());
                continue;
            }
            supportedCameras.emplace_back(cameraObj);
        }
    } else {
        MEDIA_ERR_LOG("CameraManager::GetCameras failed!, retCode: %{public}d", retCode);
    }

    ChooseDeFaultCameras(supportedCameras);
    return cameraObjList;
}

3. 创建采集会话

下面是比较重要的环节,通过调用CameraManager的CreateCaptureSession接口创建采集会话。CameraManager创建采集会话,是通过serviceProxy_->CreateCaptureSession方式进行调用,这里涉及到了OpenHarmony中的IPC的调用,serviceProxy_是远端服务在本地的代理,通过这个代理可以调用到具体的服务端,这里是HCameraService。

sptr<CaptureSession> CameraManager::CreateCaptureSession()
{
    CAMERA_SYNC_TRACE;
    sptr<ICaptureSession> captureSession = nullptr;
    sptr<CaptureSession> result = nullptr;
    int32_t retCode = CAMERA_OK;

    if (serviceProxy_ == nullptr) {
        MEDIA_ERR_LOG("CameraManager::CreateCaptureSession serviceProxy_ is null");
        return nullptr;
    }
    retCode = serviceProxy_->CreateCaptureSession(captureSession);
    if (retCode == CAMERA_OK && captureSession != nullptr) {
        result = new(std::nothrow) CaptureSession(captureSession);
        if (result == nullptr) {
            MEDIA_ERR_LOG("Failed to new CaptureSession");
        }
    } else {
        MEDIA_ERR_LOG("Failed to get capture session object from hcamera service!, %{public}d", retCode);
    }
    return result;
}

代码最终来到HCameraService::CreateCaptureSession中,该方法中new了一个HCaptureSession对象,并且将该对象传递给了参数session,所以前面的captureSession对象就是这里new出来的HCaptureSession,前面的CameraManager的CreateCaptureSession()方法中将captureSession封装成CaptureSession对象返回给应用层使用。

int32_t HCameraService::CreateCaptureSession(sptr<ICaptureSession> &session)
{
    CAMERA_SYNC_TRACE;
    sptr<HCaptureSession> captureSession;
    if (streamOperatorCallback_ == nullptr) {
        streamOperatorCallback_ = new(std::nothrow) StreamOperatorCallback();
        if (streamOperatorCallback_ == nullptr) {
            MEDIA_ERR_LOG("HCameraService::CreateCaptureSession streamOperatorCallback_ allocation failed");
            return CAMERA_ALLOC_ERROR;
        }
    }

    std::lock_guard<std::mutex> lock(mutex_);
    OHOS::Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
    captureSession = new(std::nothrow) HCaptureSession(cameraHostManager_, streamOperatorCallback_, callerToken);
    if (captureSession == nullptr) {
        MEDIA_ERR_LOG("HCameraService::CreateCaptureSession HCaptureSession allocation failed");
        return CAMERA_ALLOC_ERROR;
    }
    session = captureSession;
    return CAMERA_OK;
}

4. 开始配置采集会话

调用CaptureSession的BeginConfig进行采集会话的配置工作。这个工作最终调用到被封装的HCaptureSession中。

int32_t HCaptureSession::BeginConfig()
{
    CAMERA_SYNC_TRACE;
    if (curState_ == CaptureSessionState::SESSION_CONFIG_INPROGRESS) {
        MEDIA_ERR_LOG("HCaptureSession::BeginConfig Already in config inprogress state!");
        return CAMERA_INVALID_STATE;
    }
    std::lock_guard<std::mutex> lock(sessionLock_);
    prevState_ = curState_;
    curState_ = CaptureSessionState::SESSION_CONFIG_INPROGRESS;
    tempCameraDevices_.clear();
    tempStreams_.clear();
    deletedStreamIds_.clear();
    return CAMERA_OK;
}

5. 创建CameraInput

应用层通过camManagerObj->CreateCameraInput(cameraObjList[0])的方式进行CameraInput的创建,cameraObjList[0]就是前面获取支持设备的第一个。根据CameraDevice创建对应的CameraInput对象。

sptr<CameraInput> CameraManager::CreateCameraInput(sptr<CameraDevice> &camera)
{
    CAMERA_SYNC_TRACE;
    sptr<CameraInput> cameraInput = nullptr;
    sptr<ICameraDeviceService> deviceObj = nullptr;

    if (camera != nullptr) {
        deviceObj = CreateCameraDevice(camera->GetID());
        if (deviceObj != nullptr) {
            cameraInput = new(std::nothrow) CameraInput(deviceObj, camera);
            if (cameraInput == nullptr) {
                MEDIA_ERR_LOG("failed to new CameraInput Returning null in CreateCameraInput");
                return cameraInput;
            }
        } else {
            MEDIA_ERR_LOG("Returning null in CreateCameraInput");
        }
    } else {
        MEDIA_ERR_LOG("CameraManager::CreateCameraInput: Camera object is null");
    }
    return cameraInput;
}

6. 开启CameraInput

调用了CameraInput的Open方法,进行输入设备的启动打开。

void CameraInput::Open()
{
    int32_t retCode = deviceObj_->Open();
    if (retCode != CAMERA_OK) {
        MEDIA_ERR_LOG("Failed to open Camera Input, retCode: %{public}d", retCode);
    }
}

7. 添加CameraInput实例到采集会话中

通过调用captureSession的AddInput方法,将创建的CameraInput对象添加到采集会话的输入中,这样采集会话就知道采集输入的设备。

int32_t CaptureSession::AddInput(sptr<CaptureInput> &input)
{
    CAMERA_SYNC_TRACE;
    if (input == nullptr) {
        MEDIA_ERR_LOG("CaptureSession::AddInput input is null");
        return CAMERA_INVALID_ARG;
    }
    input->SetSession(this);
    inputDevice_ = input;
    return captureSession_->AddInput(((sptr<CameraInput> &)input)->GetCameraDevice());
}

最终调用到HCaptureSession的AddInput方法,该方法中核心的代码是tempCameraDevices_.emplace_back(localCameraDevice),将需要添加的CameraDevice插入到tempCameraDevices_容器中。

int32_t HCaptureSession::AddInput(sptr<ICameraDeviceService> cameraDevice)
{
    CAMERA_SYNC_TRACE;
    sptr<HCameraDevice> localCameraDevice = nullptr;

    if (cameraDevice == nullptr) {
        MEDIA_ERR_LOG("HCaptureSession::AddInput cameraDevice is null");
        return CAMERA_INVALID_ARG;
    }
    if (curState_ != CaptureSessionState::SESSION_CONFIG_INPROGRESS) {
        MEDIA_ERR_LOG("HCaptureSession::AddInput Need to call BeginConfig before adding input");
        return CAMERA_INVALID_STATE;
    }
    if (!tempCameraDevices_.empty() || (cameraDevice_ != nullptr && !cameraDevice_->IsReleaseCameraDevice())) {
        MEDIA_ERR_LOG("HCaptureSession::AddInput Only one input is supported");
        return CAMERA_INVALID_SESSION_CFG;
    }
    localCameraDevice = static_cast<HCameraDevice*>(cameraDevice.GetRefPtr());
    if (cameraDevice_ == localCameraDevice) {
        cameraDevice_->SetReleaseCameraDevice(false);
    } else {
        tempCameraDevices_.emplace_back(localCameraDevice);
        CAMERA_SYSEVENT_STATISTIC(CreateMsg("CaptureSession::AddInput"));
    }

    sptr<IStreamOperator> streamOperator;
    int32_t rc = localCameraDevice->GetStreamOperator(streamOperatorCallback_, streamOperator);
    if (rc != CAMERA_OK) {
        MEDIA_ERR_LOG("HCaptureSession::GetCameraDevice GetStreamOperator returned %{public}d", rc);
        localCameraDevice->Close();
        return rc;
    }
    return CAMERA_OK;
}

8. 创建Video的Surface

通过Surface::CreateSurfaceAsConsumer创建Surface。

sptr<Surface> Surface::CreateSurfaceAsConsumer(std::string name, bool isShared)
{
    sptr<ConsumerSurface> surf = new ConsumerSurface(name, isShared);
    GSError ret = surf->Init();
    if (ret != GSERROR_OK) {
        BLOGE("Failure, Reason: consumer surf init failed");
        return nullptr;
    }
    return surf;
}

9. 创建VideoOutput实例

通过调用CameraManager的CreateVideoOutput来创建VideoOutput实例。

sptr<VideoOutput> CameraManager::CreateVideoOutput(VideoProfile &profile, sptr<Surface> &surface)
{
    CAMERA_SYNC_TRACE;
    sptr<IStreamRepeat> streamRepeat = nullptr;
    sptr<VideoOutput> result = nullptr;
    int32_t retCode = CAMERA_OK;
    camera_format_t metaFormat;

    metaFormat = GetCameraMetadataFormat(profile.GetCameraFormat());
    retCode = serviceProxy_->CreateVideoOutput(surface->GetProducer(), metaFormat,
                                               profile.GetSize().width, profile.GetSize().height, streamRepeat);
    if (retCode == CAMERA_OK) {
        result = new(std::nothrow) VideoOutput(streamRepeat);
        if (result == nullptr) {
            MEDIA_ERR_LOG("Failed to new VideoOutput");
        } else {
            std::vector<int32_t> videoFrameRates = profile.GetFrameRates();
            if (videoFrameRates.size() >= 2) { // vaild frame rate range length is 2
                result->SetFrameRateRange(videoFrameRates[0], videoFrameRates[1]);
            }
            POWERMGR_SYSEVENT_CAMERA_CONFIG(VIDEO,
                                            profile.GetSize().width,
                                            profile.GetSize().height);
        }
    } else {
        MEDIA_ERR_LOG("VideoOutpout: Failed to get stream repeat object from hcamera service! %{public}d", retCode);
    }
    return result;
}

该方法中通过IPC的调用最终调用到了HCameraService的CreateVideoOutput(surface->GetProducer(), format, streamRepeat)。

sptr<VideoOutput> CameraManager::CreateVideoOutput(VideoProfile &profile, sptr<Surface> &surface)
{
    CAMERA_SYNC_TRACE;
    sptr<IStreamRepeat> streamRepeat = nullptr;
    sptr<VideoOutput> result = nullptr;
    int32_t retCode = CAMERA_OK;
    camera_format_t metaFormat;

    metaFormat = GetCameraMetadataFormat(profile.GetCameraFormat());
    retCode = serviceProxy_->CreateVideoOutput(surface->GetProducer(), metaFormat,
                                               profile.GetSize().width, profile.GetSize().height, streamRepeat);
    if (retCode == CAMERA_OK) {
        result = new(std::nothrow) VideoOutput(streamRepeat);
        if (result == nullptr) {
            MEDIA_ERR_LOG("Failed to new VideoOutput");
        } else {
            std::vector<int32_t> videoFrameRates = profile.GetFrameRates();
            if (videoFrameRates.size() >= 2) { // vaild frame rate range length is 2
                result->SetFrameRateRange(videoFrameRates[0], videoFrameRates[1]);
            }
            POWERMGR_SYSEVENT_CAMERA_CONFIG(VIDEO,
                                            profile.GetSize().width,
                                            profile.GetSize().height);
        }
    } else {
        MEDIA_ERR_LOG("VideoOutpout: Failed to get stream repeat object from hcamera service! %{public}d", retCode);
    }
    return result;
}

HCameraService的CreateVideoOutput方法中主要创建了HStreamRepeat,并且通过参数传递给前面的CameraManager使用,CameraManager通过传递的HStreamRepeat对象,进行封装,创建出VideoOutput对象。

10. 添加videoOutput到采集会话中,并且提交采集会话

该步骤类似添加CameraInput到采集会话的过程,可以参考前面的流程。

11. 开始录制

通过调用VideoOutput的Start进行录制的操作。

int32_t VideoOutput::Start()
{
    return static_cast<IStreamRepeat *>(GetStream().GetRefPtr())->Start();
}

该方法中会调用到HStreamRepeat的Start方法。

int32_t HStreamRepeat::Start()
{
    CAMERA_SYNC_TRACE;

    if (streamOperator_ == nullptr) {
        return CAMERA_INVALID_STATE;
    }
    if (curCaptureID_ != 0) {
        MEDIA_ERR_LOG("HStreamRepeat::Start, Already started with captureID: %{public}d", curCaptureID_);
        return CAMERA_INVALID_STATE;
    }
    int32_t ret = AllocateCaptureId(curCaptureID_);
    if (ret != CAMERA_OK) {
        MEDIA_ERR_LOG("HStreamRepeat::Start Failed to allocate a captureId");
        return ret;
    }
    std::vector<uint8_t> ability;
    OHOS::Camera::MetadataUtils::ConvertMetadataToVec(cameraAbility_, ability);
    CaptureInfo captureInfo;
    captureInfo.streamIds_ = {streamId_};
    captureInfo.captureSetting_ = ability;
    captureInfo.enableShutterCallback_ = false;
    MEDIA_INFO_LOG("HStreamRepeat::Start Starting with capture ID: %{public}d", curCaptureID_);
    CamRetCode rc = (CamRetCode)(streamOperator_->Capture(curCaptureID_, captureInfo, true));
    if (rc != HDI::Camera::V1_0::NO_ERROR) {
        ReleaseCaptureId(curCaptureID_);
        curCaptureID_ = 0;
        MEDIA_ERR_LOG("HStreamRepeat::Start Failed with error Code:%{public}d", rc);
        ret = HdiToServiceError(rc);
    }
    return ret;
}

核心的代码是streamOperator_->Capture,其中最后一个参数true,表示采集连续数据。

12. 录制结束,保存录制文件

六、总结

本文主要对OpenHarmony 3.2 Beta多媒体子系统的视频录制进行介绍,首先梳理了整体的录制流程,然后对录制过程中的主要步骤进行了详细地分析。视频录制主要分为以下几个步骤:

(1) 获取CameraManager实例。

(2) 创建采集会话CaptureSession。

(3) 创建CameraInput实例,并且将输入设备添加到CaptureSession中。

(4) 创建Video录制需要的Surface。

(5) 创建VideoOutput实例,并且将输出添加到CaptureSession中。

(6) 提交采集会话的配置。

(7) 调用VideoOutput的Start方法,进行视频的录制。

(8) 录制结束,保存录制的文件。

关于OpenHarmony 3.2 Beta多媒体系列开发,我之前还分享过

《OpenHarmony 3.2 Beta源码分析之MediaLibrary》

《OpenHarmony 3.2 Beta多媒体系列——音视频播放框架》

《OpenHarmony 3.2 Beta多媒体系列——音视频播放gstreamer》

这几篇文章,欢迎感兴趣的开发者进行阅读。

深入鸿蒙开发-OpenHarmony ArkUI 如何调用相机 本指导主要展示了openharmony arkui调用相机的调用过程,以及调用相机的权限准备;本指导对比了两种设计方案优劣,并给出推荐方案;Camera由于相机强关联硬件设备,在开发前要确保硬件设备完整性。其次,相机开发主要关注权限问题,避免因权限问题延长调试时间。此外,还因关注不同设备差异性产生的接口不兼容问题,需要测试覆盖完整。​Camera。 阅读详情

相关推荐

OpenHarmony南向之Camera简述

OpenHarmony南向之Camera简述 | DD'NotesOpenHarmony南向之Camera简述Camera驱动框架该驱动框架模型内部分为三层,依次为HDI实现层、框架层和设备适配层: HDI实现层:实现OHOS(OpenHarmony Operation System)相机标准南向接口。框架层:对接HDI实现层的控制、流的转发,实现数据通路的搭建,管理相机各个硬件设备等功能。设备适配层:屏蔽底层芯片和OS(Operation System)

DD'Notes 1192

openharmony camera 模块学习

openharmony camera 模块学习

qqq1112345的博客 1178

RK3568 OpenHarmony3.2 Camera介绍(MIPI、USB)

本文主要介绍OpenHarmony下的Camera整体框架,以及USB、MIPI摄像头在RK3568下的驱动调试。

Martian_Jonas的博客 2335

OpenHarmony视频录制开发

1、OpenHarmony视频录制开发简介视频录制的主要工作是捕获音视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的编码格式、封装格式、文件路径等参数。

程序猿老樊的博客 1010

【Claude Code】Claude Code 使用指南

本文介绍了AI编码助手Claude的基础和进阶操作指南。基础部分涵盖启动命令、模式切换(自动编辑/Plan/Yolo模式)、资源监控等核心功能,重点讲解了斜杠命令的使用方法。进阶操作详细说明了CLAUDE.md文件的创建与管理,包括项目规范、代码风格等内容的配置,以及如何通过该文件建立持久上下文。同时提醒了使用过程中的安全风险,建议通过配置文件限制AI对关键代码的访问权限。全文提供了完整的操作指引和安全建议,帮助开发者高效安全地使用Claude进行编码辅助。

大家好,我是敖云岚,一个沉迷代码的 “技术玩家”。擅长 Java、C++ 开发,对 MySQL、Redis、RabbitMQ 等技术也颇有研究。博客里既有硬核技术干货,也有诙谐幽默的编程日常分享。愿和你一起,笑着学技术,快乐敲代码! 1万+

开关电源环路稳定性分析(01)-Buck变换器

这篇文章主要是根据Buck变换器的拓扑结构,利用欧姆定律,基尔霍夫定律,积分微分,这些我们所熟悉的理论推导出了开关电源输入和输出关系的表达式,我相信看完这篇文章,应该是可以自己推导一次。在后面的文章中,我们同样会按照这样的风格,尽量使用大家都已经掌握的知识,来一步一步的拆解晦涩难懂的环路稳定性的问题,在前面先把积木搭起来,后面综合分析的时候就不会显得那么困难!

D_Katter的博客 3831

OpenHarmony AVCodec模块分析(六):速看5.0-Beta1更新了什么

本文将介绍OpenHarmony-v5.0-beta1 AVCodec模块更新的内容及应用的调用流程。

m0_64778763的博客 1791

Trae CN 使用入门指南

【代码】Trae CN 使用入门指南。

weixin_42551921的博客 8765

鸿蒙(API 12 Beta3版)【获取视频缩略图】视频播放与录制

使用AVImageGenerator可以实现从原始媒体资源中获取视频指定时间的缩略图,本开发指导将以获取一个视频资源的缩略图作为示例,向开发者讲解AVImageGenerator相关功能。 获取视频资源的缩略图的全流程包含:创建AVImageGenerator对象,设置资源,获取缩略图,销毁资源。

鸿蒙的技术博客 785

实战MSP-M0G3507与陶晶驰串口屏的通信协议解析

本文详细解析了MSP-M0G3507微控制器与陶晶驰串口屏的通信协议实现。内容涵盖串口配置、协议帧结构、数据校验机制及ASCII协议实战代码,重点介绍了陶晶驰串口屏的指令集应用和调试技巧,为嵌入式开发提供可靠的串口通信解决方案。

h9j8k7l6m5n的博客 867

PowerBI参数化实战:3分钟搞定动态数据源切换(附常见错误排查)

本文详细介绍了PowerBI参数化实战技巧,教你3分钟实现动态数据源切换。通过创建参数、改造查询和测试切换三步,轻松应对多环境部署与团队协作中的路径问题,并附上常见错误排查指南,有效提升报表的可维护性和工作效率。

p1q2r的博客 585

OpenHarmony 3.1 Beta版本关键特性解析——HiStreamer轻量级可定制的媒体管线框架

(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 陈国栋 数字多媒体技术在过去的数十年里得到了飞速的发展,多媒体终端设备如智能音箱、智能门锁、智能手表广泛应用于人们生活中。如此小的设备却能承载如此多功能是如何实现的呢?HiStreamer 轻量级可定制的媒体管线框架为你解答! 接下来,咱们一起探秘 HiStreamer 轻量级可定制的媒体管线框架。 一、媒体管线框架是什么? 在讲 HiStreamer 之前,咱们先来了解下媒体管线框架是什么?.

OpenHarmony_dev的博客 1548

libopus 实现pcm 编码到opus

opus 是一种音频格式,常用于语音通话、视频会议中。最近做了个pcm 到opus 的编码,踩了不少坑,特此记录一下。

sinat_27720649的博客 9464

OpenHarmony开发之——Camera模块

OpenHarmony相机驱动框架模型对上实现相机HDI(Hardware Device Interface)接口,对下实现相机Pipeline模型,管理相机各个硬件设备。HDI实现层:实现OHOS(OpenHarmony Operation System)相机标准南向接口。框架层:对接HDI实现层的控制、流的转发,实现数据通路的搭建,管理相机各个硬件设备等功能。设备适配层:屏蔽底层芯片和OS(Operation System)差异,支持多平台适配。图 1Camera驱动模块架构图。

m0_71263309的博客 1450

Label Studio保姆级教程:从零搭建医疗影像标注平台(DICOM格式支持)

本文提供基于Label Studio从零搭建医疗影像标注平台的保姆级教程。针对DICOM格式支持,详细阐述了环境部署、DICOM深度集成与预处理、团队协作权限管理以及质量审核闭环等核心环节,旨在构建一个高效、可落地的医疗AI数据标注解决方案,助力模型落地。

nft7creator的博客 303

Spring Boot集成ShardingSphere实现数据加密及数据脱敏 | Spring Cloud 48

利用ShardingSphere实现: - 数据加密 - 数据脱敏

gmHappy 1万+

OpenHarmony实战开发-如何实现录制和播放相关功能。

本示例主要展示了音频低时延录制和播放的相关功能:1. 低时延录制。2. 低时延播放。

2401_82546228的博客 1064

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

OpenHarmony相机开发

1、OpenHarmony相机开发简介OpenHarmony相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照和录像等。开发者也可以通过合适的接口或者接口组合实现闪光灯控制、曝光时间控制、手动对焦和自动对焦控制、变焦控制以及更多的功能。2、OpenHarmony相机开发流程及接口说明。

程序猿老樊的博客 2119

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

OpenHarmony AVScreenCaptureRecorder录屏开发指导

本篇文章介绍OpenHarmony 5.0新增的录屏API

m0_64778763的博客 1589

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

OpenHarmony Camera源码分析

调用流程来到了StreamOperatorProxy的Capture接口,StreamOperatorProxy是HDI模块的client端,HDI模块的client通过IPC调用到HDI的server端进行具体的操作,这个属于底层调用模块,暂时不继续分析。在HCaptureSession的调用中,调用HStreamRepeat的Start接口,HStreamRepeat在上述的创建预览输出时创建的对象,最终调用到HStreamRepeat的StartPreview接口。以下对几个核心代码进行具体分析。

OpenHarmony_dev的博客 1527

OpenHarmony相机系统详解

相机框架中主要包含会话管理、设备输入和数据输出,设备的输入和数据的输出配置都是在采集会话中完成,会话管理模块管理相机设备输入和数据输出。底层硬件提供了相机设备功能,比如相机的设备管理,包括相机设备枚举、相机设备能力查询、流的创建管理以及图像的捕获。相机组件支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照和录像等。(3).数据输出:相机的输出有拍照输出、预览输出和录像输出,分别对应三个不同的类,所以上层需要根据不同的场景创建出不同的数据输出。

程序猿老樊的博客 845

HarmonyOS实战开发:@ohos.multimedia.camera (相机管理)

本模块首批接口从API version 10开始支持.........

2401_84194030的博客 2536

《HarmonyOS开发 - IPC Camera开发笔记》第6章 基于RTSP的实时监控

开发环境: 开发系统:Ubuntu 20.04 开发板:HiSpark IPC Camera(Hi3518) Openharmony版本:v1.1.4 RTSP,Real Time Streaming Protocol,RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议!协议主要规定定了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP体系结位于RTP和RTCP之上(RTCP用于控制传输,RTP用于数据传输),使用TCP或UDP完成数据传输! openharmony中已经实

不问归期的博客 2418

OpenHarmony 的 Binder C++ 框架

添加依赖此外,IPC/RPC依赖的refbase实现在公共基础库下,请增加对utils定义IPC接口ITestAbilitySA接口继承IPC基类接口,接口里定义描述符、业务函数和消息码,其中业务函数在Proxy端和Stub端都需要实现。定义和实现服务端该类是和IPC框架相关的实现,需要继承。Stub端作为接收请求的一端,需重写方法用于接收客户端调用。定义服务端业务函数具体实现类定义和实现客户端 TestAbilityProxy该类是Proxy端实现,继承,调用接口向Stub。

朝花夕拾 1816
上一篇: 稀疏镜像在OpenHarmony上的应用
下一篇: 重磅官宣,OpenHarmony技术峰会来了
OpenHarmony开发者
博客等级 码龄5年 626粉丝 221原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值