FFmpeg源代碼簡單分析-編碼-avformat_alloc_output_context2()

參考鏈接

  • FFmpeg源代碼簡單分析:avformat_alloc_output_context2()_雷霄驊的博客-CSDN博客_avformat_alloc_context

avformat_alloc_output_context2()

  • 在基于FFmpeg的視音頻編碼器程序中,該函數通常是第一個調用的函數(除了組件注冊函數av_register_all())
  • avformat_alloc_output_context2()函數可以初始化一個用于輸出的AVFormatContext結構體
  • 它的聲明位于libavformat\avformat.h,如下所示
/*** Allocate an AVFormatContext for an output format.* avformat_free_context() can be used to free the context and* everything allocated by the framework within it.** @param *ctx is set to the created format context, or to NULL in* case of failure* @param oformat format to use for allocating the context, if NULL* format_name and filename are used instead* @param format_name the name of output format to use for allocating the* context, if NULL filename is used instead* @param filename the name of the filename to use for allocating the* context, may be NULL* @return >= 0 in case of success, a negative AVERROR code in case of* failure*/
int avformat_alloc_output_context2(AVFormatContext **ctx, const AVOutputFormat *oformat,const char *format_name, const char *filename);
  • 參數介紹
    • ctx:函數調用成功之后創建的AVFormatContext結構體。
    • oformat:指定AVFormatContext中的AVOutputFormat,用于確定輸出格式。如果指定為NULL,可以設定后兩個參數(format_name或者filename)由FFmpeg猜測輸出格式。
  • PS:使用該參數需要自己手動獲取AVOutputFormat,相對于使用后兩個參數來說要麻煩一些。
    • format_name:指定輸出格式的名稱。根據格式名稱,FFmpeg會推測輸出格式。輸出格式可以是“flv”,“mkv”等等。
    • filename:指定輸出文件的名稱。根據文件名稱,FFmpeg會推測輸出格式。文件名稱可以是“xx.flv”,“yy.mkv”等等。
  • 函數執行成功的話,其返回值大于等于0。?
  • avformat_alloc_output_context2()的函數定義。該函數的定義位于libavformat\mux.c中
int avformat_alloc_output_context2(AVFormatContext **avctx, const AVOutputFormat *oformat,const char *format, const char *filename)
{AVFormatContext *s = avformat_alloc_context();int ret = 0;*avctx = NULL;if (!s)goto nomem;if (!oformat) {if (format) {oformat = av_guess_format(format, NULL, NULL);if (!oformat) {av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);ret = AVERROR(EINVAL);goto error;}} else {oformat = av_guess_format(NULL, filename, NULL);if (!oformat) {ret = AVERROR(EINVAL);av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",filename);goto error;}}}s->oformat = oformat;if (s->oformat->priv_data_size > 0) {s->priv_data = av_mallocz(s->oformat->priv_data_size);if (!s->priv_data)goto nomem;if (s->oformat->priv_class) {*(const AVClass**)s->priv_data= s->oformat->priv_class;av_opt_set_defaults(s->priv_data);}} elses->priv_data = NULL;if (filename) {if (!(s->url = av_strdup(filename)))goto nomem;}*avctx = s;return 0;
nomem:av_log(s, AV_LOG_ERROR, "Out of memory\n");ret = AVERROR(ENOMEM);
error:avformat_free_context(s);return ret;
}
  • 從代碼中可以看出,avformat_alloc_output_context2()的流程如要包含以下2步:
  • 1) ?調用avformat_alloc_context()初始化一個默認的AVFormatContext。
  • 2) 如果指定了輸入的AVOutputFormat,則直接將輸入的AVOutputFormat賦值給AVOutputFormat的oformat。如果沒有指定輸入的AVOutputFormat,就需要根據文件格式名稱或者文件名推測輸出的AVOutputFormat。無論是通過文件格式名稱還是文件名推測輸出格式,都會調用一個函數av_guess_format()。?

函數調用結構圖

  • 函數調用結構圖如下所示

?

avformat_alloc_context()

  • avformat_alloc_context()的是一個FFmpeg的API,它的定義如下。
AVFormatContext *avformat_alloc_context(void)
{FFFormatContext *const si = av_mallocz(sizeof(*si));AVFormatContext *s;if (!si)return NULL;s = &si->pub;s->av_class = &av_format_context_class;s->io_open  = io_open_default;s->io_close = ff_format_io_close_default;s->io_close2= io_close2_default;av_opt_set_defaults(s);si->pkt = av_packet_alloc();si->parse_pkt = av_packet_alloc();if (!si->pkt || !si->parse_pkt) {avformat_free_context(s);return NULL;}si->shortest_end = AV_NOPTS_VALUE;return s;
}
  • 從代碼中可以看出,avformat_alloc_context()首先調用av_malloc()為AVFormatContext分配一塊內存。
  • 然后調用了一個函數av_opt_set_defaults()用于給AVFormatContext設置默認值。
  • av_opt_set_defaults()的定義如下。?
void av_opt_set_defaults(void *s)
{av_opt_set_defaults2(s, 0, 0);
}void av_opt_set_defaults2(void *s, int mask, int flags)
{const AVOption *opt = NULL;while ((opt = av_opt_next(s, opt))) {void *dst = ((uint8_t*)s) + opt->offset;if ((opt->flags & mask) != flags)continue;if (opt->flags & AV_OPT_FLAG_READONLY)continue;switch (opt->type) {case AV_OPT_TYPE_CONST:/* Nothing to be done here */break;case AV_OPT_TYPE_BOOL:case AV_OPT_TYPE_FLAGS:case AV_OPT_TYPE_INT:case AV_OPT_TYPE_INT64:case AV_OPT_TYPE_UINT64:case AV_OPT_TYPE_DURATION:
#if FF_API_OLD_CHANNEL_LAYOUT
FF_DISABLE_DEPRECATION_WARNINGScase AV_OPT_TYPE_CHANNEL_LAYOUT:
FF_ENABLE_DEPRECATION_WARNINGS
#endifcase AV_OPT_TYPE_PIXEL_FMT:case AV_OPT_TYPE_SAMPLE_FMT:write_number(s, opt, dst, 1, 1, opt->default_val.i64);break;case AV_OPT_TYPE_DOUBLE:case AV_OPT_TYPE_FLOAT: {double val;val = opt->default_val.dbl;write_number(s, opt, dst, val, 1, 1);}break;case AV_OPT_TYPE_RATIONAL: {AVRational val;val = av_d2q(opt->default_val.dbl, INT_MAX);write_number(s, opt, dst, 1, val.den, val.num);}break;case AV_OPT_TYPE_COLOR:set_string_color(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_STRING:set_string(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_IMAGE_SIZE:set_string_image_size(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_VIDEO_RATE:set_string_video_rate(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_BINARY:set_string_binary(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_CHLAYOUT:set_string_channel_layout(s, opt, opt->default_val.str, dst);break;case AV_OPT_TYPE_DICT:set_string_dict(s, opt, opt->default_val.str, dst);break;default:av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n",opt->type, opt->name);}}
}
  • 從代碼中可以看出,avformat_alloc_context()首先調用memset()將AVFormatContext的內存置零
  • 然后指定它的AVClass(指定了AVClass之后,該結構體就支持和AVOption相關的功能)
  • 最后調用av_opt_set_defaults()給AVFormatContext的成員變量設置默認值(av_opt_set_defaults()就是和AVOption有關的一個函數,專門用于給指定的結構體設定默認值,此處暫不分析)。?

av_guess_format()

  • av_guess_format()是FFmpeg的一個API
  • 它的聲明如下
/*** Return the output format in the list of registered output formats* which best matches the provided parameters, or return NULL if* there is no match.** @param short_name if non-NULL checks if short_name matches with the* names of the registered formats* @param filename if non-NULL checks if filename terminates with the* extensions of the registered formats* @param mime_type if non-NULL checks if mime_type matches with the* MIME type of the registered formats*/
const AVOutputFormat *av_guess_format(const char *short_name,const char *filename,const char *mime_type);
  • 拿中文簡單解釋一下參數。
    • short_name:格式的名稱。
    • filename:文件的名稱。
    • mime_type:MIME類型。
  • 返回最匹配的AVOutputFormat。如果沒有很匹配的AVOutputFormat,則返回NULL。
  • av_guess_format()的代碼如下所示。
const AVOutputFormat *av_guess_format(const char *short_name, const char *filename,const char *mime_type)
{const AVOutputFormat *fmt = NULL;const AVOutputFormat *fmt_found = NULL;void *i = 0;int score_max, score;/* specific test for image sequences */
#if CONFIG_IMAGE2_MUXERif (!short_name && filename &&av_filename_number_test(filename) &&ff_guess_image2_codec(filename) != AV_CODEC_ID_NONE) {return av_guess_format("image2", NULL, NULL);}
#endif/* Find the proper file type. */score_max = 0;while ((fmt = av_muxer_iterate(&i))) {score = 0;if (fmt->name && short_name && av_match_name(short_name, fmt->name))score += 100;if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))score += 10;if (filename && fmt->extensions &&av_match_ext(filename, fmt->extensions)) {score += 5;}if (score > score_max) {score_max = score;fmt_found = fmt;}}return fmt_found;
}
  • 從代碼中可以看出,av_guess_format()中使用一個整型變量score記錄每種輸出格式的匹配程度。
  • 函數中包含了一個while()循環,該循環利用函數av_muxer_iterate()遍歷FFmpeg中所有的AVOutputFormat,并逐一計算每個輸出格式的score。
  • 具體的計算過程分成如下幾步:
    • 1) ?如果封裝格式名稱匹配,score增加100。匹配中使用了函數av_match_name()。
    • 2) ?如果mime類型匹配,score增加10。匹配直接使用字符串比較函數strcmp()。
    • 3) ?如果文件名稱的后綴匹配,score增加5。匹配中使用了函數av_match_ext()。
  • while()循環結束后,得到得分最高的格式,就是最匹配的格式。
  • 下面看一下一個AVOutputFormat的實例,就可以理解“封裝格式名稱”,“mine類型”,“文件名稱后綴”這些概念了。
  • 下面是flv格式的視音頻復用器(Muxer)對應的AVOutputFormat格式的變量ff_flv_muxer。
const AVOutputFormat ff_flv_muxer = {.name           = "flv",.long_name      = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),.mime_type      = "video/x-flv",.extensions     = "flv",.priv_data_size = sizeof(FLVContext),.audio_codec    = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF,.video_codec    = AV_CODEC_ID_FLV1,.init           = flv_init,.write_header   = flv_write_header,.write_packet   = flv_write_packet,.write_trailer  = flv_write_trailer,.check_bitstream= flv_check_bitstream,.codec_tag      = (const AVCodecTag* const []) {flv_video_codec_ids, flv_audio_codec_ids, 0},.flags          = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |AVFMT_TS_NONSTRICT,.priv_class     = &flv_muxer_class,
};

av_muxer_iterate

  • 參數不為NULL的時候用于獲得下一個AVOutputFormat
const AVOutputFormat *av_muxer_iterate(void **opaque)
{static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1;uintptr_t i = (uintptr_t)*opaque;const AVOutputFormat *f = NULL;uintptr_t tmp;if (i < size) {f = muxer_list[i];} else if (tmp = atomic_load_explicit(&outdev_list_intptr, memory_order_relaxed)) {const AVOutputFormat *const *outdev_list = (const AVOutputFormat *const *)tmp;f = outdev_list[i - size];}if (f)*opaque = (void*)(i + 1);return f;
}

av_match_name()

  • av_match_name()是一個API函數,定義如下所示。
  • av_match_name()用于比較兩個格式的名稱。簡單地說就是比較字符串。
  • 注意該函數的字符串是不區分大小寫的:字符都轉換為小寫進行比較。
int av_match_name(const char *name, const char *names)
{const char *p;int len, namelen;if (!name || !names)return 0;namelen = strlen(name);while (*names) {int negate = '-' == *names;p = strchr(names, ',');if (!p)p = names + strlen(names);names += negate;len = FFMAX(p - names, namelen);if (!av_strncasecmp(name, names, len) || !strncmp("ALL", names, FFMAX(3, p - names)))return !negate;names = p + (*p == ',');}return 0;
}
  • 上述函數還有一點需要注意,其中使用了一個while()循環,用于搜索“,”。
  • 這是因為FFmpeg中有些格式是對應多種格式名稱的,例如MKV格式的解復用器(Demuxer)的定義如下。
const AVInputFormat ff_matroska_demuxer = {.name           = "matroska,webm",.long_name      = NULL_IF_CONFIG_SMALL("Matroska / WebM"),.extensions     = "mkv,mk3d,mka,mks,webm",.priv_data_size = sizeof(MatroskaDemuxContext),.flags_internal = FF_FMT_INIT_CLEANUP,.read_probe     = matroska_probe,.read_header    = matroska_read_header,.read_packet    = matroska_read_packet,.read_close     = matroska_read_close,.read_seek      = matroska_read_seek,.mime_type      = "audio/webm,audio/x-matroska,video/webm,video/x-matroska"
};
  • 從代碼可以看出,ff_matroska_demuxer中的name字段對應“matroska,webm”。
  • av_match_name()函數對于這樣的字符串,會把它按照“,”截斷成一個個封裝格式名稱,然后一一進行比較。

av_match_ext()

  • av_match_ext()是一個API函數,聲明如下所示。
/*** Return a positive value if the given filename has one of the given* extensions, 0 otherwise.** @param filename   file name to check against the given extensions* @param extensions a comma-separated list of filename extensions*/
int av_match_ext(const char *filename, const char *extensions);
  • av_match_ext()用于比較文件的后綴。
  • 該函數首先通過反向查找的方式找到輸入文件名中的“.”,就可以通過獲取“.”后面的字符串來得到該文件的后綴。
  • 然后調用av_match_name(),采用和比較格式名稱的方法比較兩個后綴。?
/*** @file* Format register and lookup*/int av_match_ext(const char *filename, const char *extensions)
{const char *ext;if (!filename)return 0;ext = strrchr(filename, '.');if (ext)return av_match_name(ext + 1, extensions);return 0;
}
  • 經過以上幾步之后,av_guess_format()最終可以得到最合適的AVOutputFormat并且返回給avformat_alloc_output_context2()。
  • avformat_alloc_output_context2()接下來將獲得的AVOutputFormat賦值給剛剛新建的AVFormatContext,即可完成初始化工作

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445948.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445948.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445948.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《深入理解JVM.2nd》筆記(一):走進Java

概述 Java技術體系 Java程序設計語言各種硬件平臺上的Java虛擬機Class文件格式Java API類庫來自商業機構和開源社區的第三方Java類庫 Java發展史 Java虛擬機發展史 展望Java技術的未來 模塊化 混合語言 多核并行 進一步豐富語法 64位虛擬機 實戰&#xff1a;自己編譯…

js監聽只讀文本框_js 動態控制 input 框 的只讀屬性

input 框的只讀屬性&#xff1a; readonly在頁面中直接添加為只讀時&#xff0c;可在input中直接添加 readonly"readonly"&#xff0c;但是如果想通過點擊按鈕來改變的話&#xff0c;需要通過js(或jquery)來實現。最近一次使用這個&#xff0c;終于發現了以前寫這…

FFmpeg源代碼簡單分析-編碼-avformat_write_header()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;avformat_write_header()_雷霄驊的博客-CSDN博客_avformat_write_header avformat_write_header() FFmpeg寫文件用到的3個函數&#xff1a;avformat_write_header()&#xff0c;av_write_frame()以及av_write_trailer()其中av_writ…

《深入理解JVM.2nd》筆記(二):Java內存區域與內存溢出異常

文章目錄概述運行時數據區域程序計數器Java虛擬機棧本地方法棧Java堆方法區運行時常量池直接內存HotSpot虛擬機對象探秘對象的創建第一步第二步第三步第四步最后一腳對象的內存布局對象頭Header第一部分第二部分實例數據Instance對齊填充Padding對象的訪問定位句柄直接指針對象…

vue底部選擇器_Vue組件-極簡的地址選擇器

一、前言本文用Vue完成一個極簡的地點選擇器&#xff0c;我們接下來帶大家實現這個。當然其中也有一些值得學習與注意的地方。話不多說&#xff0c;我們先上demo圖。因為每個人的需要不一樣&#xff0c;我這邊就不在實現更多的功能&#xff0c;所以留有更大的空間供大家增刪改。…

FFmpeg源代碼簡單分析-編碼-avcodec_encode_video()已被send_frame 和 receive_packet替代

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;avcodec_encode_video()_雷霄驊的博客-CSDN博客_avcodec_encode_video2 avcodec_encode_video() 該函數用于編碼一幀視頻數據。函數已被棄用參考鏈接&#xff1a;FFmpeg 新舊版本編碼 API 的區別_zouzhiheng的博客-CSDN博客 send_f…

《深入理解JVM.2nd》筆記(三):垃圾收集器與垃圾回收策略

文章目錄概述對象已死嗎引用計數算法可達性分析算法再談引用finalize()&#xff1a;生存還是死亡回收方法區垃圾收集算法標記-清除算法復制算法標記-整理算法分代收集算法HotSpot的算法實現枚舉根結點安全點安全區域垃圾收集器SerialParNewParallel ScavengeSerial OldParallel…

python計算股票趨勢_通過機器學習的線性回歸算法預測股票走勢(用Python實現)...

1 波士頓房價數據分析安裝好Python的Sklearn庫后&#xff0c;在安裝包下的路徑中就能看到描述波士頓房價的csv文件&#xff0c;具體路徑是“python安裝路徑\Lib\site-packages\sklearn\datasets\data”&#xff0c;在這個目錄中還包含了Sklearn庫會用到的其他數據文件&#xff…

FFmpeg源代碼簡單分析-編碼-av_write_frame()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;av_write_frame()_雷霄驊的博客-CSDN博客_av_write_frame av_write_frame() av_write_frame()用于輸出一幀視音頻數據&#xff0c;它的聲明位于libavformat\avformat.h&#xff0c;如下所示。 /*** Write a packet to an output me…

《深入理解JVM.2nd》筆記(四):虛擬機性能監控與故障處理工具

文章目錄概述JDK的命令行工具jps&#xff1a;虛擬機進程狀況工具jstat&#xff1a;虛擬機統計信息監視工具jinfo&#xff1a;Java配置信息工具jmap&#xff1a;Java內存映像工具jhat&#xff1a;虛擬機堆轉儲快照分析工具jstack&#xff1a;Java堆棧跟蹤工具HSDIS&#xff1a;J…

postgresql 主從配置_Postgresql主從配置

一、簡介PostgreSql在9.0之后引入了主從的流復制機制&#xff0c;所謂流復制&#xff0c;就是從服務器通過tcp流從主服務器中同步相應的數據。這樣當主服務器數據丟失時從服務器中仍有備份。與基于文件日志傳送相比&#xff0c;流復制允許保持從服務器更新。 從服務器連接主服務…

FFmpeg源代碼簡單分析-編碼-av_write_trailer()

參考鏈接&#xff1a; FFmpeg源代碼簡單分析&#xff1a;av_write_trailer()_雷霄驊的博客-CSDN博客_av_malloc av_write_trailer() av_write_trailer()用于輸出文件尾&#xff0c;它的聲明位于libavformat\avformat.h&#xff0c;如下所示 /*** Write the stream trailer to…

科沃斯掃地機器人風扇模塊_掃地機器人不能開機,不能關機,風扇不轉

家庭的重要性自不必再細說&#xff0c;而小編今天要說的則是家庭環境的重要性。一般家庭最少居住三口人&#xff0c;兩個大人加一個孩子&#xff0c;每天回到家&#xff0c;看到家里整潔舒適的環境&#xff0c;心情該是多么地愜意。要是我們每天下班回到家中&#xff0c;看到滿…

MySQL關鍵字EXPLAIN的用法及其案例

文章目錄概述EXPLAIN輸出的列的解釋實例說明select_type的說明UNIONDEPENDENT UNION與DEPENDENT SUBQUERYSUBQUERYDERIVEDtype的說明system&#xff0c;consteq_refrefref_or_nullindex_mergeunique_subqueryindex_subqueryrangeindexALLextra的說明DistinctNot existsRange ch…

FFmpeg源代碼簡單分析-其他-日志輸出系統(av_log()等)

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;日志輸出系統&#xff08;av_log()等&#xff09;_雷霄驊的博客-CSDN博客_ffmpeg源碼分析 日志輸出系統&#xff08;av_log()等&#xff09; 本文分析一下FFmpeg的日志&#xff08;Log&#xff09;輸出系統的源代碼。日志輸出部分的…

FFmpeg源代碼簡單分析-其他-AVClass和AVoption

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;結構體成員管理系統-AVClass_雷霄驊的博客-CSDN博客FFmpeg源代碼簡單分析&#xff1a;結構體成員管理系統-AVOption_雷霄驊的博客-CSDN博客 概述 AVOption用于在FFmpeg中描述結構體中的成員變量。它最主要的作用可以概括為兩個字&a…

oracle手工收集awr報告_oracle手工生成AWR報告方法記錄-阿里云開發者社區

AWR(Automatic Workload Repository)報告是我們進行日常數據庫性能評定、問題SQL發現的重要手段。熟練掌握AWR報告&#xff0c;是做好開發、運維DBA工作的重要基本功。AWR報告的原理是基于Oracle數據庫的定時鏡像功能。默認情況下&#xff0c;Oracle數據庫后臺進程會以一定間隔…

IntelliJ IDEA 默認快捷鍵大全

文章目錄Remember these ShortcutsGeneralDebuggingSearch / ReplaceEditingRefactoringNavigationCompile and RunUsage SearchVCS / Local HistoryLive Templates參考資料Remember these Shortcuts 常用功能快捷鍵備注●Smart code completionCtrl Shift Space-●Search e…

python爬蟲的數據如何解決亂碼_寫爬蟲時如何解決網頁亂碼問題

實戰講解&#xff0c;文章較長&#xff0c;對爬蟲比較熟悉的瀏覽翻看章節 2.3 獲取新聞文本內容。寫爬蟲時經常對網址發起請求&#xff0c;結果返回的html數據除了標簽能看懂&#xff0c;其他的全部是亂碼。大家如果對爬蟲感興趣&#xff0c;請耐心閱讀本文&#xff0c;我們就以…

FFmpeg源代碼簡單分析-其他-libswscale的sws_getContext()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;libswscale的sws_getContext()_雷霄驊的博客-CSDN博客 libswscale的sws_getContext() FFmpeg中類庫libswsscale用于圖像處理&#xff08;縮放&#xff0c;YUV/RGB格式轉換&#xff09;libswscale是一個主要用于處理圖片像素數據的類…