前一篇文章已經(jīng)把捕獲屏幕的功能實(shí)現(xiàn)卿城,現(xiàn)在我們要把捕獲的視頻數(shù)據(jù)編碼成264為后面保存成文件,或者通過(guò)流媒體的形式分發(fā)做準(zhǔn)備
鴻蒙avcodec kit編碼的關(guān)系圖如下
編碼調(diào)用關(guān)系官方圖
下面實(shí)現(xiàn)整個(gè)編碼過(guò)程
1唆姐,在CMake腳本中鏈接動(dòng)態(tài)庫(kù)
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類廓八,并實(shí)現(xiàn)相關(guān)函數(shù)
視頻編碼器類中包括創(chuàng)建編碼器奉芦,配置編碼器,啟動(dòng)編碼器剧蹂,停止二號(hào)釋放編碼器
int32_t Create(const std::string &videoCodecMime);int32_t Config(VideoSampleInfo &sampleInfo, AVCodecUserData *codecUserData);int32_t Start();int32_t Stop();int32_t Release();
1声功,根據(jù)mine type創(chuàng)建編碼器,這里我們用的mine type是OH_AVCODEC_MIMETYPE_VIDEO_AVC就是h264
int32_t VideoEncoder::Create(const std::string &videoCodecMime){ // 通過(guò) MIME TYPE 創(chuàng)建編碼器宠叼,系統(tǒng)會(huì)根據(jù)MIME創(chuàng)建最合適的編碼器先巴。// 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,配置編碼器车吹,主要包括色彩格式筹裕,視頻寬度,視頻高度窄驹,視頻幀率朝卒,關(guān)鍵幀間隔,和編碼回調(diào)等
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;}
這里寫(xiě)了兩個(gè)輔助函數(shù)乐埠,
創(chuàng)建surface模式對(duì)應(yīng)的窗口
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;}
配置編碼器的相關(guān)回調(diào):編碼錯(cuò)誤回調(diào)抗斤,編碼格式更新回調(diào)囚企,編碼輸入緩存回調(diào)(這是surface模式,未使用)瑞眼,編碼輸出緩存回調(diào)
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龙宏,啟動(dòng)編碼器
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
引入視頻編碼類,額外啟動(dòng)一個(gè)線程用來(lái)接受編碼后的數(shù)據(jù)伤疙,并寫(xiě)入文件
在CreateAndInitWithSurfaceMode函數(shù)中實(shí)例化視頻編碼器
在StartWithSurfaceMode函數(shù)中加入
在StopAndReleaseWithSurfaceMode添加停止編碼相關(guān)邏輯
這里我們把視頻保存成h264文件了银酗,文件地址如下
運(yùn)行測(cè)后會(huì)在手機(jī)報(bào)名目錄下生成文件
用ffplay播放文件顯示如下信息