鸿蒙屏幕捕后通过AVCodec Kit使用Surface模式编码成h264

前一篇文章已经把捕获屏幕的功能实现,现在我们要把捕获的视频数据编码成264为后面保存成文件,或者通过流媒体的形式分发做准备

鸿蒙avcodec kit编码的关系图如下

编码调用关系官方图

 

下面实现整个编码过程

1,在CMake脚本中链接动态库

target_link_libraries(entry PUBLIC libace_napi.z.so
                                    libnative_avscreen_capture.so
                                    libhilog_ndk.z.so
                                    libnative_media_core.so
                                    libnative_buffer.so
                                    libnative_media_codecbase.so
                                    libnative_media_venc.so
                                    libnative_media_acodec.so)        

2,新建video_encoder类,并实现相关函数

 

视频编码器类中包括创建编码器,配置编码器,启动编码器,停止二号释放编码器

int32_t Create(const std::string &videoCodecMime);
int32_t Config(VideoSampleInfo &sampleInfo, AVCodecUserData *codecUserData);
int32_t Start();
int32_t Stop();
int32_t Release();

 

1,根据mine type创建编码器,这里我们用的mine type是
OH_AVCODEC_MIMETYPE_VIDEO_AVC就是h264

int32_t VideoEncoder::Create(const std::string &videoCodecMime)
{
       // 通过 MIME TYPE 创建编码器,系统会根据MIME创建最合适的编码器。
//     OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
//     const char *codecName = OH_AVCapability_GetName(capability);
//     codec = OH_VideoEncoder_CreateByName(codecName);
    encoder_ = OH_VideoEncoder_CreateByMime(videoCodecMime.c_str());
    CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
    return AVCODEC_SAMPLE_ERR_OK;
}

2,配置编码器,主要包括色彩格式,视频宽度,视频高度,视频帧率,关键帧间隔,和编码回调等

int32_t VideoEncoder::Config(VideoSampleInfo &sampleInfo, AVCodecUserData *codecUserData)
{
    CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
    CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Invalid param: codecUserData");

    // Configure video encoder
    int32_t ret = Configure(sampleInfo);
    CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed");

    // GetSurface from video encoder
    ret = GetSurface(sampleInfo);
    CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Get surface failed");
    
    // SetCallback for video encoder
    ret = SetCallback(codecUserData);
    CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
                             "Set callback failed, ret: %{public}d", ret);

    // Prepare video encoder
    ret = OH_VideoEncoder_Prepare(encoder_);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);

    return AVCODEC_SAMPLE_ERR_OK;
}

这里写了两个辅助函数,

创建surface模式对应的窗口

int32_t VideoEncoder::GetSurface(VideoSampleInfo &sampleInfo)
{
    int32_t ret = OH_VideoEncoder_GetSurface(encoder_, &sampleInfo.window);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK && sampleInfo.window, AVCODEC_SAMPLE_ERR_ERROR,
        "Get surface failed, ret: %{public}d", ret);
    (void)OH_NativeWindow_NativeWindowHandleOpt(sampleInfo.window, SET_BUFFER_GEOMETRY, sampleInfo.videoWidth,
                                                sampleInfo.videoHeight);
    (void)OH_NativeWindow_NativeWindowHandleOpt(sampleInfo.window, SET_USAGE, 16425); // 16425: Window usage
    (void)OH_NativeWindow_NativeWindowHandleOpt(sampleInfo.window, SET_FORMAT,
        ToGraphicPixelFormat(sampleInfo.pixelFormat, sampleInfo.isHDRVivid));
    return AVCODEC_SAMPLE_ERR_OK;
}

配置编码器的相关回调:编码错误回调,编码格式更新回调,编码输入缓存回调(这是surface模式,未使用),编码输出缓存回调

 

int32_t VideoEncoder::SetCallback(AVCodecUserData *codecUserData)
{
    int32_t ret = OH_VideoEncoder_RegisterCallback(encoder_,
    {VideoSampleCallback::OnCodecError, VideoSampleCallback::OnCodecFormatChange,
        VideoSampleCallback::OnNeedInputBuffer, VideoSampleCallback::OnNewOutputBuffer},
        codecUserData);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);

    return AVCODEC_SAMPLE_ERR_OK;
}

3,启动编码器

int32_t VideoEncoder::Start()
{
    CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");

    int ret = OH_VideoEncoder_Start(encoder_);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
    return AVCODEC_SAMPLE_ERR_OK;
}

然后改造screen_capture

 

引入视频编码类,额外启动一个线程用来接受编码后的数据,并写入文件


CreateAndInitWithSurfaceMode函数中实例化视频编码器

 

在StartWithSurfaceMode函数中加入

 

 


StopAndReleaseWithSurfaceMode添加停止编码相关逻辑

 

这里我们把视频保存成h264文件了,文件地址如下

运行测后会在手机报名目录下生成文件

用ffplay播放文件显示如下信息
 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值