日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

结构体成员管理AVClass AVOption之2AVOption,设置选项值

發布時間:2025/3/20 c/c++ 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 结构体成员管理AVClass AVOption之2AVOption,设置选项值 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

AVOption用于在FFmpeg中描述結構體中的成員變量。一個AVOption可以包含名稱,簡短的幫助信息,取值等。

上篇文章中概括了AVClass,AVOption和目標結構體之間的關系。以AVFormatContext為例,可以表示為下圖。



上篇文章主要概括了AVClass,AVOption和目標結構體之間的從屬關系,但是并沒有分析有關AVOption的源代碼。本文分析有關AVOption的源代碼。

AVOption有關的API

AVOption常用的API可以分成兩類:用于設置參數的API和用于讀取參數的API。其中最有代表性的用于設置參數的API就是av_opt_set();而最有代表性的用于讀取參數的API就是av_opt_get()。除了以上兩個函數之外,本文再記錄一個在FFmpeg的結構體初始化代碼中最常用的用于設置默認值的函數av_opt_set_defaults()


函數調用關系圖

av_opt_set()的函數調用關系圖如下所示。


av_opt_get()的函數調用關系圖如下所示。buf[128]





av_opt_set_defaults()的函數調用關系圖如下所示。注:av_opt_set_defaults2是deprecated的api





av_opt_set()

通過AVOption設置參數最常用的函數就是av_opt_set()了。該函數通過字符串的方式(傳入的參數是:變量名稱的字符串和變量值的字符串)設置一個AVOption的值。此外,還包含了它的一系列“兄弟”函數av_opt_set_XXX(),其中“XXX”代表了int,double這些數據類型。使用這些函數的時候,可以指定int,double這些類型的變量(而不是字符串)作為輸入,設定相應的AVOption的值。

[cpp]view plaincopy
  • /**?
  • ?*?@defgroup?opt_set_funcs?Option?setting?functions?
  • ?*?@{?
  • ?*?Those?functions?set?the?field?of?obj?with?the?given?name?to?value.?
  • ?*?
  • ?*?@param[in]?obj?A?struct?whose?first?element?is?a?pointer?to?an?AVClass.?
  • ?*?@param[in]?name?the?name?of?the?field?to?set?
  • ?*?@param[in]?val?The?value?to?set.?In?case?of?av_opt_set()?if?the?field?is?not?
  • ?*?of?a?string?type,?then?the?given?string?is?parsed.?
  • ?*?SI?postfixes?and?some?named?scalars?are?supported.?
  • ?*?If?the?field?is?of?a?numeric?type,?it?has?to?be?a?numeric?or?named?
  • ?*?scalar.?Behavior?with?more?than?one?scalar?and?+-?infix?operators?
  • ?*?is?undefined.?
  • ?*?If?the?field?is?of?a?flags?type,?it?has?to?be?a?sequence?of?numeric?
  • ?*?scalars?or?named?flags?separated?by?'+'?or?'-'.?Prefixing?a?flag?
  • ?*?with?'+'?causes?it?to?be?set?without?affecting?the?other?flags;?
  • ?*?similarly,?'-'?unsets?a?flag.?
  • ?*?@param?search_flags?flags?passed?to?av_opt_find2.?I.e.?if?AV_OPT_SEARCH_CHILDREN?
  • ?*?is?passed?here,?then?the?option?may?be?set?on?a?child?of?obj.?
  • ?*?
  • ?*?@return?0?if?the?value?has?been?set,?or?an?AVERROR?code?in?case?of?
  • ?*?error:?
  • ?*?AVERROR_OPTION_NOT_FOUND?if?no?matching?option?exists?
  • ?*?AVERROR(ERANGE)?if?the?value?is?out?of?range?
  • ?*?AVERROR(EINVAL)?if?the?value?is?not?valid?
  • ?*/??
  • int?av_opt_set?????????(void?*obj,?const?char?*name,?const?char?*val,?int?search_flags);??
  • int?av_opt_set_int?????(void?*obj,?const?char?*name,?int64_t?????val,?int?search_flags);??
  • int?av_opt_set_double??(void?*obj,?const?char?*name,?double??????val,?int?search_flags);??
  • int?av_opt_set_q???????(void?*obj,?const?char?*name,?AVRational??val,?int?search_flags);??
  • int?av_opt_set_bin?????(void?*obj,?const?char?*name,?const?uint8_t?*val,?int?size,?int?search_flags);??
  • int?av_opt_set_image_size(void?*obj,?const?char?*name,?int?w,?int?h,?int?search_flags);??
  • int?av_opt_set_pixel_fmt?(void?*obj,?const?char?*name,?enum?AVPixelFormat?fmt,?int?search_flags);??
  • int?av_opt_set_sample_fmt(void?*obj,?const?char?*name,?enum?AVSampleFormat?fmt,?int?search_flags);??
  • int?av_opt_set_video_rate(void?*obj,?const?char?*name,?AVRational?val,?int?search_flags);??
  • int?av_opt_set_channel_layout(void?*obj,?const?char?*name,?int64_t?ch_layout,?int?search_flags);??


  • 有關av_opt_set_XXX()函數的定義不再詳細分析,在這里詳細看一下av_opt_set()的源代碼。av_opt_set()的定義位于libavutil\opt.c,如下所示。

    [cpp]view plaincopy
  • int?av_opt_set(void?*obj,?const?char?*name,?const?char?*val,?int?search_flags)??
  • {??
  • ????int?ret?=?0;??
  • ????void?*dst,?*target_obj;??
  • ????//查找??
  • ????const?AVOption?*o?=?av_opt_find2(obj,?name,?NULL,?0,?search_flags,?&target_obj);??
  • ????if?(!o?||?!target_obj)??
  • ????????return?AVERROR_OPTION_NOT_FOUND;??
  • ????if?(!val?&&?(o->type?!=?AV_OPT_TYPE_STRING?&&??
  • ?????????????????o->type?!=?AV_OPT_TYPE_PIXEL_FMT?&&?o->type?!=?AV_OPT_TYPE_SAMPLE_FMT?&&??
  • ?????????????????o->type?!=?AV_OPT_TYPE_IMAGE_SIZE?&&?o->type?!=?AV_OPT_TYPE_VIDEO_RATE?&&??
  • ?????????????????o->type?!=?AV_OPT_TYPE_DURATION?&&?o->type?!=?AV_OPT_TYPE_COLOR?&&??
  • ?????????????????o->type?!=?AV_OPT_TYPE_CHANNEL_LAYOUT))??
  • ????????return?AVERROR(EINVAL);??
  • ??
  • ????if?(o->flags?&?AV_OPT_FLAG_READONLY)??
  • ????????return?AVERROR(EINVAL);??
  • ????//dst指向具體的變量??
  • ????//注意:offset的作用??
  • ????dst?=?((uint8_t*)target_obj)?+?o->offset;??
  • ????//根據AVOption不同的類型,調用不同的設置函數??
  • ????switch?(o->type)?{??
  • ????case?AV_OPT_TYPE_STRING:???return?set_string(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_BINARY:???return?set_string_binary(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_FLAGS:??
  • ????case?AV_OPT_TYPE_INT:??
  • ????case?AV_OPT_TYPE_INT64:??
  • ????case?AV_OPT_TYPE_FLOAT:??
  • ????case?AV_OPT_TYPE_DOUBLE:??
  • ????case?AV_OPT_TYPE_RATIONAL:?return?set_string_number(obj,?target_obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_IMAGE_SIZE:?return?set_string_image_size(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_VIDEO_RATE:?return?set_string_video_rate(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_PIXEL_FMT:??return?set_string_pixel_fmt(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_SAMPLE_FMT:?return?set_string_sample_fmt(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_DURATION:??
  • ????????if?(!val)?{??
  • ????????????*(int64_t?*)dst?=?0;??
  • ????????????return?0;??
  • ????????}?else?{??
  • ????????????if?((ret?=?av_parse_time(dst,?val,?1))?<?0)??
  • ????????????????av_log(obj,?AV_LOG_ERROR,?"Unable?to?parse?option?value?\"%s\"?as?duration\n",?val);??
  • ????????????return?ret;??
  • ????????}??
  • ????????break;??
  • ????case?AV_OPT_TYPE_COLOR:??????return?set_string_color(obj,?o,?val,?dst);??
  • ????case?AV_OPT_TYPE_CHANNEL_LAYOUT:??
  • ????????if?(!val?||?!strcmp(val,?"none"))?{??
  • ????????????*(int64_t?*)dst?=?0;??
  • ????????}?else?{??
  • #if?FF_API_GET_CHANNEL_LAYOUT_COMPAT??
  • ????????????int64_t?cl?=?ff_get_channel_layout(val,?0);??
  • #else??
  • ????????????int64_t?cl?=?av_get_channel_layout(val);??
  • #endif??
  • ????????????if?(!cl)?{??
  • ????????????????av_log(obj,?AV_LOG_ERROR,?"Unable?to?parse?option?value?\"%s\"?as?channel?layout\n",?val);??
  • ????????????????ret?=?AVERROR(EINVAL);??
  • ????????????}??
  • ????????????*(int64_t?*)dst?=?cl;??
  • ????????????return?ret;??
  • ????????}??
  • ????????break;??
  • ????}??
  • ??
  • ????av_log(obj,?AV_LOG_ERROR,?"Invalid?option?type.\n");??
  • ????return?AVERROR(EINVAL);??
  • }??
  • 從源代碼可以看出,av_opt_set()首先調用av_opt_find2()查找AVOption。如果找到了,則根據AVOption的type,調用不同的函數(set_string(),set_string_number(),set_string_image_size()等等)將輸入的字符串轉化為相應type的數據并對該AVOption進行賦值。如果沒有找到,則立即返回“沒有找到AVOption”的錯誤。


    av_opt_find2() / av_opt_find()

    2多一個參數void **target_obj

    av_opt_find2()本身也是一個API函數,用于查找AVOption。它的聲明位于libavutil\opt.h中,如下所示。

    [cpp]view plaincopy
  • /**?
  • ?*?Look?for?an?option?in?an?object.?Consider?only?options?which?
  • ?*?have?all?the?specified?flags?set.?
  • ?*?
  • ?*?@param[in]?obj?A?pointer?to?a?struct?whose?first?element?is?a?
  • ?*????????????????pointer?to?an?AVClass.?
  • ?*????????????????Alternatively?a?double?pointer?to?an?AVClass,?if?
  • ?*????????????????AV_OPT_SEARCH_FAKE_OBJ?search?flag?is?set.?
  • ?*?@param[in]?name?The?name?of?the?option?to?look?for.?
  • ?*?@param[in]?unit?When?searching?for?named?constants,?name?of?the?unit?
  • ?*?????????????????it?belongs?to.?
  • ?*?@param?opt_flags?Find?only?options?with?all?the?specified?flags?set?(AV_OPT_FLAG).?
  • ?*?@param?search_flags?A?combination?of?AV_OPT_SEARCH_*.?
  • ?*?@param[out]?target_obj?if?non-NULL,?an?object?to?which?the?option?belongs?will?be?
  • ?*?written?here.?It?may?be?different?from?obj?if?AV_OPT_SEARCH_CHILDREN?is?present?
  • ?*?in?search_flags.?This?parameter?is?ignored?if?search_flags?contain?
  • ?*?AV_OPT_SEARCH_FAKE_OBJ.?
  • ?*?
  • ?*?@return?A?pointer?to?the?option?found,?or?NULL?if?no?option?
  • ?*?????????was?found.?
  • ?*/??
  • const?AVOption?*av_opt_find2(void?*obj,?const?char?*name,?const?char?*unit,??
  • ?????????????????????????????int?opt_flags,?int?search_flags,?void?**target_obj);??


  • 此外還有一個和av_opt_find2()“長得很像”的API函數av_opt_find(),功能與av_opt_find2()基本類似,與av_opt_find2()相比少了最后一個參數。從源代碼中可以看出它只是簡單調用了av_opt_find2()并把所有的輸入參數原封不動的傳遞過去,并把最后一個參數設置成NULL。

    [cpp]view plaincopy
  • const?AVOption?*av_opt_find(void?*obj,?const?char?*name,?const?char?*unit,??
  • ????????????????????????????int?opt_flags,?int?search_flags)??
  • {??
  • ????return?av_opt_find2(obj,?name,?unit,?opt_flags,?search_flags,?NULL);??
  • }??


  • 下面先看一下av_opt_find2()函數的定義。該函數的定義位于libavutil\opt.c中,如下所示。

    [cpp]view plaincopy
  • const?AVOption?*av_opt_find2(void?*obj,?const?char?*name,?const?char?*unit,??
  • ?????????????????????????????int?opt_flags,?int?search_flags,?void?**target_obj)??
  • {??
  • ????const?AVClass??*c;??
  • ????const?AVOption?*o?=?NULL;??
  • ??
  • ????if(!obj)??
  • ????????return?NULL;??
  • ??
  • ????c=?*(AVClass**)obj;??
  • ??
  • ????if?(!c)??
  • ????????return?NULL;??
  • ????//查找范圍包含子節點的時候??
  • ????//遞歸調用av_opt_find2()??
  • ????if?(search_flags?&?AV_OPT_SEARCH_CHILDREN)?{??
  • ????????if?(search_flags?&?AV_OPT_SEARCH_FAKE_OBJ)?{??
  • ????????????const?AVClass?*child?=?NULL;??
  • ????????????while?(child?=?av_opt_child_class_next(c,?child))??
  • ????????????????if?(o?=?av_opt_find2(&child,?name,?unit,?opt_flags,?search_flags,?NULL))??
  • ????????????????????return?o;??
  • ????????}?else?{??
  • ????????????void?*child?=?NULL;??
  • ????????????while?(child?=?av_opt_child_next(obj,?child))??
  • ????????????????if?(o?=?av_opt_find2(child,?name,?unit,?opt_flags,?search_flags,?target_obj))??
  • ????????????????????return?o;??
  • ????????}??
  • ????}??
  • ????//遍歷??
  • ????while?(o?=?av_opt_next(obj,?o))?{??
  • ????????//比較名稱??
  • ????????if?(!strcmp(o->name,?name)?&&?(o->flags?&?opt_flags)?==?opt_flags?&&??
  • ????????????((!unit?&&?o->type?!=?AV_OPT_TYPE_CONST)?||??
  • ?????????????(unit??&&?o->type?==?AV_OPT_TYPE_CONST?&&?o->unit?&&?!strcmp(o->unit,?unit))))?{??
  • ????????????if?(target_obj)?{??
  • ????????????????if?(!(search_flags?&?AV_OPT_SEARCH_FAKE_OBJ))??
  • ????????????????????*target_obj?=?obj;??
  • ????????????????else??
  • ????????????????????*target_obj?=?NULL;??
  • ????????????}??
  • ????????????return?o;??
  • ????????}??
  • ????}??
  • ????return?NULL;??
  • }??

  • 前半部分的if()語句中的內容只有在search_flags指定為AV_OPT_SEARCH_CHILDREN的時候才會執行。后半部分代碼是重點。后半部分代碼是一個while()循環,該循環的條件是一個函數av_opt_next()。



    av_opt_next()

    av_opt_next()也是一個FFmpeg的API函數。使用它可以循環遍歷目標結構體的所有AVOption,它的聲明如下。

    [cpp]view plaincopy
  • /**?
  • ?*?Iterate?over?all?AVOptions?belonging?to?obj.?
  • ?*?
  • ?*?@param?obj?an?AVOptions-enabled?struct?or?a?double?pointer?to?an?
  • ?*????????????AVClass?describing?it.?
  • ?*?@param?prev?result?of?the?previous?call?to?av_opt_next()?on?this?object?
  • ?*?????????????or?NULL?
  • ?*?@return?next?AVOption?or?NULL?
  • ?*/??
  • const?AVOption?*av_opt_next(void?*obj,?const?AVOption?*prev);??
  • av_opt_next()的定義如下所示。

    [cpp]view plaincopy
  • const?AVOption?*av_opt_next(void?*obj,?const?AVOption?*last)??
  • {??
  • ????AVClass?*class?=?*(AVClass**)obj;??
  • ????if?(!last?&&?class?&&?class->option?&&?class->option[0].name)??
  • ????????return?class->option;??
  • ????if?(last?&&?last[1].name)??
  • ????????return?++last;??
  • ????return?NULL;??
  • }??
  • 從av_opt_next()的代碼可以看出,輸入的AVOption類型的last變量為空的時候,會返回該AVClass的option數組的第一個元素,否則會返回數組的下一個元素。

    現在再回到av_opt_find2()函數。我們發現在while()循環中有一個strcmp()函數,正是這個函數比較輸入的AVOption的name和AVClass的option數組中每個元素的name,當上述兩個name相等的時候,就代表查找到了AVOption,接著就可以返回獲得的AVOption。

    現在再回到剛才的av_opt_set()函數。(注:opt.c中有個main函數)該函數內部有一個void型的變量dst用于確定需要設定的AVOption對應變量的位置。具體的方法就是將輸入的AVClass結構體的首地址加上該AVOption的偏移量offset。確定了AVOption對應的變量的位置之后,就可以根據該AVOption的類型type的不同調用不同的字符串轉換函數設置相應的值了。我們可以看幾個設置值的的簡單例子:

    1.?AV_OPT_TYPE_STRING
    當AVOption的type為AV_OPT_TYPE_STRING的時候,調用set_string()方法設置相應的值。set_string()的定義如下:

    [cpp]view plaincopy
  • static?int?set_string(void?*obj,?const?AVOption?*o,?const?char?*val,?uint8_t?**dst)??
  • {??
  • ????av_freep(dst);??
  • ????*dst?=?av_strdup(val);??
  • ????return?0;??
  • }??
  • 其中又調用了一個函數av_strdup(),這是一個FFmpeg的API函數,用于拷貝字符串。其中調用了memcpy()。

    2.?AV_OPT_TYPE_IMAGE_SIZE
    當AVOption的type為AV_OPT_TYPE_IMAGE_SIZE的時候,調用set_string_image_size ()方法設置相應的值。set_string_image_size()的定義如下。

    [cpp]view plaincopy
  • static?int?set_string_image_size(void?*obj,?const?AVOption?*o,?const?char?*val,?int?*dst)??
  • {??
  • ????int?ret;??
  • ??
  • ????if?(!val?||?!strcmp(val,?"none"))?{??
  • ????????dst[0]?=??
  • ????????dst[1]?=?0; ?//連續賦值
  • ????????return?0;??
  • ????}??
  • ????ret?=?av_parse_video_size(dst,?dst?+?1,?val);??
  • ????if?(ret?<?0)??
  • ????????av_log(obj,?AV_LOG_ERROR,?"Unable?to?parse?option?value?\"%s\"?as?image?size\n",?val);??
  • ????return?ret;??
  • }??
  • 可見其中調用了另一個函數av_parse_video_size()。



    av_parse_video_size()

    av_parse_video_size()是一個FFmpeg的API函數,用于解析出輸入的分辨率字符串的寬高信息。例如,輸入的字符串為“1920x1080”或者“1920*1080”,經過av_parse_video_size()的處理之后,可以得到寬度為1920,高度為1080;此外,輸入一個“特定分辨率”字符串例如“vga”,也可以得到寬度為640,高度為480。該函數不屬于AVOption這部分的內容,而是整個FFmpeg通用的一個字符串解析函數。聲明位于libavutil\parseutils.h中,如下所示。

    [cpp]view plaincopy
  • /**?
  • ?*?Parse?str?and?put?in?width_ptr?and?height_ptr?the?detected?values.?
  • ?*?
  • ?*?@param[in,out]?width_ptr?pointer?to?the?variable?which?will?contain?the?detected?
  • ?*?width?value?
  • ?*?@param[in,out]?height_ptr?pointer?to?the?variable?which?will?contain?the?detected?
  • ?*?height?value?
  • ?*?@param[in]?str?the?string?to?parse:?it?has?to?be?a?string?in?the?format?
  • ?*?width?x?height?or?a?valid?video?size?abbreviation.?
  • ?*?@return?>=?0?on?success,?a?negative?error?code?otherwise?
  • ?*/??
  • int?av_parse_video_size(int?*width_ptr,?int?*height_ptr,?const?char?*str);??

  • 從聲明中可以看出,該函數輸入一個字符串str,輸出結果保存在width_ptr和height_ptr所指向的內存中。av_parse_video_size()定義位于libavutil\parseutils.c中,代碼如下。

    [cpp]view plaincopy
  • //解析分辨率??
  • int?av_parse_video_size(int?*width_ptr,?int?*height_ptr,?const?char?*str)??
  • {??
  • ????int?i;??
  • ????int?n?=?FF_ARRAY_ELEMS(video_size_abbrs);??
  • ????const?char?*p;??
  • ????int?width?=?0,?height?=?0;??
  • ????//先看看有沒有“分辨率簡稱”相同的(例如vga,qcif等)??
  • ????for?(i?=?0;?i?<?n;?i++)?{??
  • ????????if?(!strcmp(video_size_abbrs[i].abbr,?str))?{??
  • ????????????width??=?video_size_abbrs[i].width;??
  • ????????????height?=?video_size_abbrs[i].height;??
  • ????????????break;??
  • ????????}??
  • ????}??
  • ????//如果沒有使用“分辨率簡稱”,而是使用具體的數值(例如“1920x1080”),則執行下面的步驟??
  • ????if?(i?==?n)?{??
  • ????????//strtol():字符串轉換成整型,遇到非數字則停止??
  • ????????width?=?strtol(str,?(void*)&p,?10);??
  • ????????if?(*p)??
  • ????????????p++;??
  • ????????height?=?strtol(p,?(void*)&p,?10);??
  • ??
  • ????????/*?trailing?extraneous?data?detected,?like?in?123x345foobar?*/??
  • ????????if?(*p)??
  • ????????????return?AVERROR(EINVAL);??
  • ????}??
  • ????//檢查一下正確性??
  • ????if?(width?<=?0?||?height?<=?0)??
  • ????????return?AVERROR(EINVAL);??
  • ????*width_ptr??=?width;??
  • ????*height_ptr?=?height;??
  • ????return?0;??
  • }??


  • 上述代碼中包含了FFmpeg中兩種解析視頻分辨率的方法。FFmpeg中包含兩種設定視頻分辨率的方法:通過已經定義好的“分辨率簡稱”,或者通過具體的數值。代碼中首先遍歷“特定分辨率”的數組video_size_abbrs。該數組定義如下所示。

    [cpp]view plaincopy
  • typedef?struct?{??
  • ????const?char?*abbr;??
  • ????int?width,?height;??
  • }?VideoSizeAbbr;??
  • ??
  • static?const?VideoSizeAbbr?video_size_abbrs[]?=?{??
  • ????{?"ntsc",??????720,?480?},??
  • ????{?"pal",???????720,?576?},??
  • ????{?"qntsc",?????352,?240?},?/*?VCD?compliant?NTSC?*/??
  • ????{?"qpal",??????352,?288?},?/*?VCD?compliant?PAL?*/??
  • ????{?"sntsc",?????640,?480?},?/*?square?pixel?NTSC?*/??
  • ????{?"spal",??????768,?576?},?/*?square?pixel?PAL?*/??
  • ????{?"film",??????352,?240?},??
  • ????{?"ntsc-film",?352,?240?},??
  • ????{?"sqcif",?????128,??96?},??
  • ????{?"qcif",??????176,?144?},??
  • ????{?"cif",???????352,?288?},??
  • ????{?"4cif",??????704,?576?},??
  • ????{?"16cif",????1408,1152?},??
  • ????{?"qqvga",?????160,?120?},??
  • ????{?"qvga",??????320,?240?},??
  • ????{?"vga",???????640,?480?},??
  • ????{?"svga",??????800,?600?},??
  • ????{?"xga",??????1024,?768?},??
  • ????{?"uxga",?????1600,1200?},??
  • ????{?"qxga",?????2048,1536?},??
  • ????{?"sxga",?????1280,1024?},??
  • ????{?"qsxga",????2560,2048?},??
  • ????{?"hsxga",????5120,4096?},??
  • ????{?"wvga",??????852,?480?},??
  • ????{?"wxga",?????1366,?768?},??
  • ????{?"wsxga",????1600,1024?},??
  • ????{?"wuxga",????1920,1200?},??
  • ????{?"woxga",????2560,1600?},??
  • ????{?"wqsxga",???3200,2048?},??
  • ????{?"wquxga",???3840,2400?},??
  • ????{?"whsxga",???6400,4096?},??
  • ????{?"whuxga",???7680,4800?},??
  • ????{?"cga",???????320,?200?},??
  • ????{?"ega",???????640,?350?},??
  • ????{?"hd480",?????852,?480?},??
  • ????{?"hd720",????1280,?720?},??
  • ????{?"hd1080",???1920,1080?},??
  • ????{?"2k",???????2048,1080?},?/*?Digital?Cinema?System?Specification?*/??
  • ????{?"2kflat",???1998,1080?},??
  • ????{?"2kscope",??2048,?858?},??
  • ????{?"4k",???????4096,2160?},?/*?Digital?Cinema?System?Specification?*/??
  • ????{?"4kflat",???3996,2160?},??
  • ????{?"4kscope",??4096,1716?},??
  • ????{?"nhd",???????640,360??},??
  • ????{?"hqvga",?????240,160??},??
  • ????{?"wqvga",?????400,240??},??
  • ????{?"fwqvga",????432,240??},??
  • ????{?"hvga",??????480,320??},??
  • ????{?"qhd",???????960,540??},??
  • };??


  • 通過調用strcmp()方法比對輸入字符串的值與video_size_abbrs數組中每個VideoSizeAbbr元素的abbr字段的值,判斷輸入的字符串是否指定了這些標準的分辨率。如果指定了的話,則返回該分辨率的寬和高。

    如果從上述列表中沒有找到相應的“特定分辨率”,則說明輸入的字符串應該是一個具體的分辨率的值,形如“1920*1020”,“1280x720”這樣的字符串。這個時候就需要對這個字符串進行解析,并從中提取出數字信息。通過兩次調用strtol()方法,從字符串中提取出寬高信息(第一次提取出寬,第二次提取出高)。

    PS1:strtol()用于將字符串轉換成整型,遇到非數字則停止。

    PS2:從這種解析方法可以得到一個信息——
    FFmpeg并不管“寬{X}高”中間的那個{X}是什么字符,也就是說中間那個字符不一定非得是“*”或者“x”。后來試了一下,中間那個字符使用其他字母也是可以的。


    av_opt_set_defaults()

    av_opt_set_defaults()是一個FFmpeg的API,作用是給一個結構體的成員變量設定默認值。在FFmpeg初始化其各種結構體(AVFormatContext,AVCodecContext等)的時候,通常會調用該函數設置結構體中的默認值。av_opt_set_defaults()的聲明如下所示。

    編者注:其實av_opt_set_defaults2是棄用的api,不要被后面的2給騙了。


    注:avcodec_get_context_defaults3?被avcodec_alloc_context3調用

    avformat_get_context_defaults , ? ? ?被avformat_alloc_context調用

    avcodec_open2,avformat_open_input里面都調用了av_opt_set_defaults函數



  • /**?
  • ?*?Set?the?values?of?all?AVOption?fields?to?their?default?values.?
  • ?*?
  • ?*?@param?s?an?AVOption-enabled?struct?(its?first?member?must?be?a?pointer?to?AVClass)?
  • ?*/??
  • void?av_opt_set_defaults(void?*s);??

  • 可見只需要把包含AVOption功能的結構體(第一個變量是一個AVClass類型的指針)的指針提供給av_opt_set_defaults(),就可以初始化該結構體的默認值了。

    下面看一下av_opt_set_defaults()的源代碼,位于libavutil\opt.c,如下所示。

    [cpp]view plaincopy
  • void?av_opt_set_defaults(void?*s)??
  • {??
  • //奇怪的#if...#endif??
  • #if?FF_API_OLD_AVOPTIONS??
  • ????av_opt_set_defaults2(s,?0,?0);??
  • }??
  • ??
  • void?av_opt_set_defaults2(void?*s,?int?mask,?int?flags)??
  • {??
  • #endif??
  • ????const?AVOption?*opt?=?NULL;??
  • ????//遍歷所有的AVOption??
  • ????while?((opt?=?av_opt_next(s,?opt)))?{??
  • ????????//注意:offset的使用??
  • ????????void?*dst?=?((uint8_t*)s)?+?opt->offset;??
  • #if?FF_API_OLD_AVOPTIONS??
  • ????????if?((opt->flags?&?mask)?!=?flags)??
  • ????????????continue;??
  • #endif??
  • ??
  • ????????if?(opt->flags?&?AV_OPT_FLAG_READONLY)??
  • ????????????continue;??
  • ????????//讀取各種default_val??
  • ????????switch?(opt->type)?{??
  • ????????????case?AV_OPT_TYPE_CONST:??
  • ????????????????/*?Nothing?to?be?done?here?*/??
  • ????????????break;??
  • ????????????case?AV_OPT_TYPE_FLAGS:??
  • ????????????case?AV_OPT_TYPE_INT:??
  • ????????????case?AV_OPT_TYPE_INT64:??
  • ????????????case?AV_OPT_TYPE_DURATION:??
  • ????????????case?AV_OPT_TYPE_CHANNEL_LAYOUT:??
  • ????????????????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_PIXEL_FMT:??
  • ????????????????write_number(s,?opt,?dst,?1,?1,?opt->default_val.i64);??
  • ????????????????break;??
  • ????????????case?AV_OPT_TYPE_SAMPLE_FMT:??
  • ????????????????write_number(s,?opt,?dst,?1,?1,?opt->default_val.i64);??
  • ????????????????break;??
  • ????????????case?AV_OPT_TYPE_BINARY:??
  • ????????????????set_string_binary(s,?opt,?opt->default_val.str,?dst);??
  • ????????????????break;??
  • ????????????case?AV_OPT_TYPE_DICT:??
  • ????????????????/*?Cannot?set?defaults?for?these?types?*/??
  • ????????????break;??
  • ????????????default:??
  • ????????????????av_log(s,?AV_LOG_DEBUG,?"AVOption?type?%d?of?option?%s?not?implemented?yet\n",?opt->type,?opt->name);??
  • ????????}??
  • ????}??
  • }??


  • av_opt_set_defaults()代碼開始的時候有一個預編譯指令還是挺奇怪的。怪就怪在#if和#endif竟然橫跨在了兩個函數之間。簡單解讀一下這個定義的意思:當定義了FF_API_OLD_AVOPTIONS的時候,存在兩個函數av_opt_set_defaults()和av_opt_set_defaults2(),而這兩個函數的作用是一樣的;當沒有定義FF_API_OLD_AVOPTIONS的時候,只存在一個函數av_opt_set_defaults()。估計FFmpeg這么做主要是考慮到兼容性的問題。

    av_opt_set_defaults()主體部分是一個while()循環。該循環的判斷條件是一個av_opt_next(),其作用是獲得下一個AVOption。該函數的定義在前文中已經做過分析,這里再重復一下。定義如下所示。

    [cpp]view plaincopy
  • const?AVOption?*av_opt_next(void?*obj,?const?AVOption?*last)??
  • {??
  • ????AVClass?*class?=?*(AVClass**)obj;??
  • ????if?(!last?&&?class?&&?class->option?&&?class->option[0].name)??
  • ????????return?class->option;??
  • ????if?(last?&&?last[1].name)??
  • ????????return?++last;??
  • ????return?NULL;??
  • }??
  • 從av_opt_next()的代碼可以看出,輸入的AVOption類型的last為空的時候,會返回該AVClass的option數組的第一個元素,否則會返回下一個元素。

    下面簡單解讀一下av_opt_set_defaults()中while()循環語句里面的內容。有一個void類型的指針dst用于確定當前AVOption代表的變量的位置。該指針的位置由結構體的首地址和變量的偏移量offset確定。然后根據AVOption代表的變量的類型type,調用不同的函數設定相應的值。例如type為AV_OPT_TYPE_INT的話,則會調用write_number();type為AV_OPT_TYPE_STRING的時候,則會調用set_string();type為AV_OPT_TYPE_IMAGE_SIZE的時候,則會調用set_string_image_size()。有關這些設置值的函數在前文中已經有所敘述,不再重復。需要注意的是,該函數中設置的值都是AVOption中的default_val變量的值。


    av_opt_get()

    av_opt_get()用于獲取一個AVOption變量的值。需要注意的是,不論是何種類型的變量,通過av_opt_get()取出來的值都是字符串類型的。此外,還包含了它的一系列“兄弟”函數av_opt_get_XXX()(其中“XXX”代表了int,double這些數據類型)。通過這些“兄弟”函數可以直接取出int,double類型的數值。av_opt_get()的聲明如下所示。

    [cpp]view plaincopy
  • /**?
  • ?*?@defgroup?opt_get_funcs?Option?getting?functions?
  • ?*?@{?
  • ?*?Those?functions?get?a?value?of?the?option?with?the?given?name?from?an?object.?
  • ?*?
  • ?*?@param[in]?obj?a?struct?whose?first?element?is?a?pointer?to?an?AVClass.?
  • ?*?@param[in]?name?name?of?the?option?to?get.?
  • ?*?@param[in]?search_flags?flags?passed?to?av_opt_find2.?I.e.?if?AV_OPT_SEARCH_CHILDREN?
  • ?*?is?passed?here,?then?the?option?may?be?found?in?a?child?of?obj.?
  • ?*?@param[out]?out_val?value?of?the?option?will?be?written?here?
  • ?*?@return?>=0?on?success,?a?negative?error?code?otherwise?
  • ?*/??
  • /**?
  • ?*?@note?the?returned?string?will?be?av_malloc()ed?and?must?be?av_free()ed?by?the?caller?
  • ?*/??
  • int?av_opt_get?????????(void?*obj,?const?char?*name,?int?search_flags,?uint8_t???**out_val);??
  • int?av_opt_get_int?????(void?*obj,?const?char?*name,?int?search_flags,?int64_t????*out_val);??
  • int?av_opt_get_double??(void?*obj,?const?char?*name,?int?search_flags,?double?????*out_val);??
  • int?av_opt_get_q???????(void?*obj,?const?char?*name,?int?search_flags,?AVRational?*out_val);??
  • int?av_opt_get_image_size(void?*obj,?const?char?*name,?int?search_flags,?int?*w_out,?int?*h_out);??
  • int?av_opt_get_pixel_fmt?(void?*obj,?const?char?*name,?int?search_flags,?enum?AVPixelFormat?*out_fmt);??
  • int?av_opt_get_sample_fmt(void?*obj,?const?char?*name,?int?search_flags,?enum?AVSampleFormat?*out_fmt);??
  • int?av_opt_get_video_rate(void?*obj,?const?char?*name,?int?search_flags,?AVRational?*out_val);??
  • int?av_opt_get_channel_layout(void?*obj,?const?char?*name,?int?search_flags,?int64_t?*ch_layout);??
  • 下面我們看一下av_opt_get()的定義,如下所示。
    [cpp]view plaincopy
  • int?av_opt_get(void?*obj,?const?char?*name,?int?search_flags,?uint8_t?**out_val)??
  • {??
  • ????void?*dst,?*target_obj;??
  • ????//查找??
  • ????const?AVOption?*o?=?av_opt_find2(obj,?name,?NULL,?0,?search_flags,?&target_obj);??
  • ????uint8_t?*bin,?buf[128];??
  • ????int?len,?i,?ret;??
  • ????int64_t?i64;??
  • ??
  • ????if?(!o?||?!target_obj?||?(o->offset<=0?&&?o->type?!=?AV_OPT_TYPE_CONST))??
  • ????????return?AVERROR_OPTION_NOT_FOUND;??
  • ????//注意:offset的使用??
  • ????dst?=?(uint8_t*)target_obj?+?o->offset;??
  • ????//使用sprintf()轉換成字符串,存入buf??
  • ????buf[0]?=?0;??
  • ????switch?(o->type)?{??
  • ????case?AV_OPT_TYPE_FLAGS:?????ret?=?snprintf(buf,?sizeof(buf),?"0x%08X",??*(int????*)dst);break;??
  • ????case?AV_OPT_TYPE_INT:???????ret?=?snprintf(buf,?sizeof(buf),?"%d"?,?????*(int????*)dst);break;??
  • ????case?AV_OPT_TYPE_INT64:?????ret?=?snprintf(buf,?sizeof(buf),?"%"PRId64,?*(int64_t*)dst);break;??
  • ????case?AV_OPT_TYPE_FLOAT:?????ret?=?snprintf(buf,?sizeof(buf),?"%f"?,?????*(float??*)dst);break;??
  • ????case?AV_OPT_TYPE_DOUBLE:????ret?=?snprintf(buf,?sizeof(buf),?"%f"?,?????*(double?*)dst);break;??
  • ????case?AV_OPT_TYPE_VIDEO_RATE:??
  • ????case?AV_OPT_TYPE_RATIONAL:??ret?=?snprintf(buf,?sizeof(buf),?"%d/%d",???((AVRational*)dst)->num,?((AVRational*)dst)->den);break;??
  • ????case?AV_OPT_TYPE_CONST:?????ret?=?snprintf(buf,?sizeof(buf),?"%f"?,?????o->default_val.dbl);break;??
  • ????case?AV_OPT_TYPE_STRING:??
  • ????????if?(*(uint8_t**)dst)??
  • ????????????*out_val?=?av_strdup(*(uint8_t**)dst);??
  • ????????else??
  • ????????????*out_val?=?av_strdup("");??
  • ????????return?0;??
  • ????case?AV_OPT_TYPE_BINARY:??
  • ????????len?=?*(int*)(((uint8_t?*)dst)?+?sizeof(uint8_t?*));??
  • ????????if?((uint64_t)len*2?+?1?>?INT_MAX)??
  • ????????????return?AVERROR(EINVAL);??
  • ????????if?(!(*out_val?=?av_malloc(len*2?+?1)))??
  • ????????????return?AVERROR(ENOMEM);??
  • ????????if?(!len)?{??
  • ????????????*out_val[0]?=?'\0';??
  • ????????????return?0;??
  • ????????}??
  • ????????bin?=?*(uint8_t**)dst;??
  • ????????for?(i?=?0;?i?<?len;?i++)??
  • ????????????snprintf(*out_val?+?i*2,?3,?"%02X",?bin[i]);??
  • ????????return?0;??
  • ????case?AV_OPT_TYPE_IMAGE_SIZE:??
  • ????????//分辨率??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"%dx%d",?((int?*)dst)[0],?((int?*)dst)[1]);??
  • ????????break;??
  • ????case?AV_OPT_TYPE_PIXEL_FMT:??
  • ????????//像素格式??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"%s",?(char?*)av_x_if_null(av_get_pix_fmt_name(*(enum?AVPixelFormat?*)dst),?"none"));??
  • ????????break;??
  • ????case?AV_OPT_TYPE_SAMPLE_FMT:??
  • ????????//采樣格式??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"%s",?(char?*)av_x_if_null(av_get_sample_fmt_name(*(enum?AVSampleFormat?*)dst),?"none"));??
  • ????????break;??
  • ????case?AV_OPT_TYPE_DURATION:??
  • ????????//時長??
  • ????????i64?=?*(int64_t?*)dst;??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"%"PRIi64":%02d:%02d.%06d",??
  • ???????????????????????i64?/?3600000000,?(int)((i64?/?60000000)?%?60),??
  • ???????????????????????(int)((i64?/?1000000)?%?60),?(int)(i64?%?1000000));??
  • ????????break;??
  • ????case?AV_OPT_TYPE_COLOR:??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"0x%02x%02x%02x%02x",??
  • ???????????????????????(int)((uint8_t?*)dst)[0],?(int)((uint8_t?*)dst)[1],??
  • ???????????????????????(int)((uint8_t?*)dst)[2],?(int)((uint8_t?*)dst)[3]);??
  • ????????break;??
  • ????case?AV_OPT_TYPE_CHANNEL_LAYOUT:??
  • ????????i64?=?*(int64_t?*)dst;??
  • ????????ret?=?snprintf(buf,?sizeof(buf),?"0x%"PRIx64,?i64);??
  • ????????break;??
  • ????default:??
  • ????????return?AVERROR(EINVAL);??
  • ????}??
  • ??
  • ????if?(ret?>=?sizeof(buf))??
  • ????????return?AVERROR(EINVAL);??
  • ????//拷貝??
  • ????*out_val?=?av_strdup(buf);??
  • ????return?0;??
  • }??
  • 從av_opt_get()的定義可以看出,該函數首先通過av_opt_find2()查相應的AVOption,然后取出該變量的值,最后通過snprintf()將變量的值轉化為字符串(各種各樣類型的變量都這樣處理)并且輸出出來。? ?可以學到將各種類型轉換成字符串參考:結構體成員管理系統-AVOption

    總結

    以上是生活随笔為你收集整理的结构体成员管理AVClass AVOption之2AVOption,设置选项值的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 青草福利视频 | 欧美日韩国产片 | 人妻少妇偷人精品久久性色 | 日本www在线播放 | 美女干b视频 | 手机看黄色 | 人人干人人玩 | 国产一级特黄aaa大片 | 成人免费在线 | 日韩精品国产AV | 欧美日本亚洲 | 欧美a√在线| 午夜精品在线观看 | 特级新鲜大片片 | 求免费黄色网址 | 一级黄色片免费看 | 体内射精一区二区 | 国产91视频在线观看 | 综合色天天 | 亚洲精品99久久久久中文字幕 | 岛国免费av | 午夜一二区 | 欧美精品一区二区三区久久久 | 久久久久久亚洲中文字幕无码 | 翔田千里一区二区三区av | 在线看黄色网 | 亚洲综合第一 | 亚洲乱码一区二区三区 | 免费在线看污 | 一二三不卡 | 日韩污污| ass日本粉嫩pics珍品 | 好大好舒服视频 | 免费看91视频 | 偷偷草| 太久av | 精品一区二区三区视频在线观看 | 婷婷色av| 天堂男人av | 色综合久久久久综合体桃花网 | 天天干天天做天天操 | 久久久全国免费视频 | 亚洲av午夜精品一区二区三区 | 亚洲成人观看 | 欧美爱爱网站 | 国产aⅴ一区二区三区 | 欧美在线视频你懂的 | 麻豆蜜桃在线观看 | 九九免费精品视频 | 日本精品一区二区视频 | av免费高清| 91看大片 | 少妇高潮一区二区三区99小说 | 欧美黄色片| 久久国产精品无码一级毛片 | 日韩一区免费观看 | 中文字幕日韩专区 | 四季av中文字幕 | 欧美日韩另类在线 | 国产无套内射又大又猛又粗又爽 | 国产香蕉精品视频 | 国产精品蜜臀 | 中文字幕第31页 | 91成人天堂久久成人 | 欧美性久久久久 | 免费观看成人鲁鲁鲁鲁鲁视频 | 蜜桃av色偷偷av老熟女 | 精品人妻伦一二三区久久 | 亚洲欧美精品午睡沙发 | 亚洲一区91| 91亚州 | 怡春院视频| 国产福利电影在线 | 四虎永久在线 | 国产精品自产拍 | av不卡免费在线 | 午夜精品一区二区三 | 国产精品白嫩极品美女视频 | 性激情视频 | 肉色丝袜脚交一区二区 | 成人在线你懂的 | 卡通动漫亚洲综合 | 欧美日韩中文在线 | 性色在线观看 | 亚洲欧美视频一区二区 | 色欧美色 | 中国a级黄色片 | 澳门黄色 | 国产观看| 夜夜操夜夜干 | 57pao国产精品一区 | 成年人av在线 | 大学生三级中国dvd 日韩欧美一区二区区 | 大地资源中文第三页 | www.色在线观看| 在线天堂av | 免费无码毛片一区二区app | 海角社区id:1220.7126,10. | 日本真人做爰免费视频120秒 |