avcodec_avcodec_avcodec

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

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

编码调用关系官方图

avcodec_avcodec_avcodec

下面实现整个编码过程

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类,并实现相关函数

avcodec_avcodec_avcodec

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

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

avcodec_avcodec_avcodec

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

avcodec_avcodec_avcodec

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

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

avcodec_avcodec_avcodec

在StartWithSurfaceMode函数中加入

avcodec_avcodec_avcodec

在StopAndReleaseWithSurfaceMode添加停止编码相关逻辑

avcodec_avcodec_avcodec

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

avcodec_avcodec_avcodec

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

avcodec_avcodec_avcodec

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

avcodec_avcodec_avcodec

限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注