?
?
?
簡介
?
OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)作為“開源”世界的“連接器”,不斷為智能社會的發(fā)展提供源源不斷的“源動力”。深開鴻一直以來積極投身于OpenHarmony社區(qū)建設,不斷推動開源事業(yè)的發(fā)展。
?
身為深開鴻的一名OS框架開發(fā)工程師,我在OpenHarmony 開源項目成立伊始便積極加入OpenHarmony 社區(qū)建設,負責OpenHarmony框架和結構的研發(fā)工作,此次我將帶來OpenHarmony多媒體子系統(tǒng)的源碼分析,希望能為廣大的開發(fā)者提供參考。
?
OpenHarmony多媒體子系統(tǒng),是OpenHarmony系統(tǒng)框架中的其中一個比較重要的子系統(tǒng)。OpenHarmony中集成了ffmpeg的第三方庫,多媒體的很多功能實現(xiàn)需要ffmpeg庫。另外,媒體文件的處理包含了對音視頻裁剪、音視頻分離等應用場景的處理,有些功能多媒體子系統(tǒng)沒有提供給外部相應的接口,對此可以通過NAPI的機制實現(xiàn)一套JS接口,提供給應用層去調用,以此實現(xiàn)更多的多媒體功能。
?
效果展示
?
本文通過實現(xiàn)音視頻文件裁剪的功能,讓開發(fā)者熟悉實現(xiàn)該功能的整個操作流程。
?
以下是效果圖:
?

?
?
?首先選擇源文件,在裁剪設置中設定裁剪的起始時間和結束時間(單位為秒),參數(shù)設定完以后,我們點擊裁剪按鈕,進而對源文件進行裁剪,裁剪成功后,會顯示播放按鈕。
?
在整個操作過程中,源文件選擇模塊的播放按鈕是對源文件進行播放,裁剪模塊的播放按鈕是對裁剪后文件的播放,我們可以通過播放視頻文件來查看裁剪前后的效果對比。
?
代碼已經上傳至SIG倉庫,鏈接如下:
?
https://gitee.com/openharmony-sig/knowledge_demo_entainment/tree/master/FA/MediaCuteDemo
?
https://gitee.com/openharmony-sig/knowledge_demo_entainment/tree/master/docs/MediaCuteDemo
?
源碼分析
?
源碼分析分為兩個部分,一部分是NAPI實現(xiàn)的本地功能,另一部分是JS實現(xiàn)的應用功能。
?
一、NAPI實現(xiàn)
?
以下是源碼分析的內容,核心的模塊主要代碼是myffmpegsys,為應用端提供了js的接口。
?
1. myffmpegsys作為一個新的子系統(tǒng)集成到OpenHarmony源碼中,放置在OpenHarmony源碼的根目錄下,和foundation在同一目錄下。
?
2. 配置build/subsystem_config.json。
- ?
- ?
- ?
- ?
"myffmpegsys":?{"path": "myffmpegsys","name": "myffmpegsys"},
?
3. 配置產品的productdefine/common/products/XXXX.json(其中XXXX對應的設備型號)。
- ?
- ?
- ?
- ?
- ?
"parts":{"myffmpegsys:myffmpegpart":{},"ace:ace_engine_standard":{},......}
?
4. 配置好子系統(tǒng)以及對應的組件后,下面再對myffmpegsys子系統(tǒng)的源碼進行分析。
?
? (1)目錄結構
?

?
myffmpegdemo中主要處理napi相關的接口轉換,ffmpeg_utils通過調用ffmpeg三方庫處理實際的視頻文件裁剪功能。
?
(2)OpenHarmony集成的ffmpeg三方庫的路徑是third_party/ffmpeg,myffmpegdemo會依賴ffmpeg,并且頭文件也會引用ffmpeg頭文件,所以在BUILD.gn文件中會添加相關的依賴和路徑。
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
import("//build/ohos.gni")ohos_shared_library("myffmpegdemo") {include_dirs = ["http://foundation/ace/napi/interfaces/kits","http://myffmpegsys/myffmpegpart/myffmpegdemo/include","http://third_party/ffmpeg",]sources = ["myffmpegdemo.cpp","ffmpeg_utils.cpp",]public_deps = ["http://foundation/ace/napi:ace_napi","http://third_party/ffmpeg:libohosffmpeg"]external_deps = ["hiviewdfx_hilog_native:libhilog",]relative_install_dir = "module"subsystem_name = "myffmpegsys"part_name = "myffmpegpart"}
?
(3)流程圖
?

?
(4)代碼分析
?
? ? Napi接口注冊:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
/************************************************ Module export and register***********************************************/static napi_value registerMyffmpegdemo(napi_env env, napi_value exports){static napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("videoCute", videoCute),DECLARE_NAPI_FUNCTION("videoToAacH264", videoToAacH264),};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;}
?
NAPI實現(xiàn)videoCute接口,將NAPI類型轉換成C++類型,然后調用FfmpegUtils的videoCute接口:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
static?void?executeVideoCute(napi_env?env,?void*?data)?{VideoCuteAddOnData *addonData = (VideoCuteAddOnData *) data;//調用視頻剪切的功能addonData->result = FfmpegUtils::videoCute((const char*)addonData->args0.c_str(),addonData->args1,addonData->args2,(const char*)addonData->args3.c_str());}
?
FfmpegUtils初始化輸入,輸出格式上下文:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//初始化上下文ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0);if (ret < 0) {ERROR_BUF(ret);HiLog::Error(LABEL, "gyf avformat_open_input error = %{public}s", errbuf);return ret;}ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);if (ret < 0) {ERROR_BUF(ret);HiLog::Error(LABEL, "gyf avformat_alloc_output_context2 error = %{public}s", errbuf);goto end;}ofmt = ofmt_ctx->oformat;
?
根據(jù)輸入流創(chuàng)建輸出流,并且拷貝codec參數(shù):
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//創(chuàng)建流以及參數(shù)拷貝for (int i = 0; i < (int)ifmt_ctx->nb_streams; i++) {in_stream = ifmt_ctx->streams[i];AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);if (!out_stream) {ret = AVERROR_UNKNOWN;goto end;}avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);out_stream->codecpar->codec_tag = 0;}
?
打開輸出文件,并寫入頭文件:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//打開輸出文件ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);if (ret < 0) {ERROR_BUF(ret);HiLog::Error(LABEL, "gyf avio_open error = %{public}s", errbuf);goto end;} // 寫頭信息ret = avformat_write_header(ofmt_ctx, NULL);if (ret < 0) {ERROR_BUF(ret);HiLog::Error(LABEL, "gyf avformat_write_header error = %{public}s", errbuf);goto end;}
?
根據(jù)設置的截取時間段,跳轉到指定幀:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//跳轉到指定幀ret = av_seek_frame(ifmt_ctx, -1, start_seconds * AV_TIME_BASE, AVSEEK_FLAG_ANY);if (ret < 0) {ERROR_BUF(ret);HiLog::Error(LABEL, "gyf av_seek_frame error = %{public}s", errbuf);goto end;}
?
循環(huán)讀取幀數(shù)據(jù),當達到截取時間點后,退出循環(huán):
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//讀取數(shù)據(jù)ret = av_read_frame(ifmt_ctx, &pkt);if (ret < 0) {break;}in_stream = ifmt_ctx->streams[pkt.stream_index];out_stream = ofmt_ctx->streams[pkt.stream_index];// 時間超過要截取的時間,就退出循環(huán)if (av_q2d(in_stream->time_base) * pkt.pts > end_seconds) {av_packet_unref(&pkt);break;}
?
寫入文件尾部信息:
- ?
- ?
?//寫文件尾信息ret = av_write_trailer(ofmt_ctx);
?
二、JS應用實現(xiàn)
?
目錄結構
?

?
代碼主要包含兩部分,index主要是裁剪相關的設置,player是針對視頻文件進行播放的頁面。
?
index中設置了源文件,裁剪的起始時間,結束時間以后,通過裁剪按鈕,進行視頻的裁剪功能,這一部分的代碼是通過底層NAPI提供的接口進行的。
?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
cutevideo()?{globalThis.isCuteSuccess = false;console.log('gyf cutevideo');myffmpegdemo.videoCute(this.src, this.startTime, this.endTime, this.srcOut,function (result) {console.log('gyf cutevideo callback result = ' + result);globalThis.showPrompt('videoCute finished!');if (0 === result) {globalThis.isCuteSuccess = true;} else {globalThis.isCuteSuccess = false;}});},
?
視頻一旦裁剪成功以后,頁面就會出現(xiàn)播放的按鈕,點擊播放按鈕后,便可對裁剪后的文件進行觀看。
?
總結
?
本文通過NAPI方式給大家講解了如何利用OpenHarmony系統(tǒng)能力實現(xiàn)更多的功能。開發(fā)者可以利用OpenHarmony自帶的三方庫,實現(xiàn)音視頻分離、音視頻轉碼、音視頻編解碼等多媒體處理功能,而且這些功能都可以在系統(tǒng)層實現(xiàn),并通過NAPI的方式提供對應的接口進行調用。對于OpenHarmony集成的其他內在的能力,也可以通過NAPI的方式來對外提供接口,以此實現(xiàn)更多功能。
?
開發(fā)工作是一條漫長的道路,開發(fā)者唯有舉一反三、觸類旁通,才能在未來的開發(fā)工作中達到事半功倍的效果。
?
電子發(fā)燒友App















評論