5. 排除編譯錯誤。
這部分主要是修改C99的語法,常見的不兼容語法如下:
5.1 例如在文件av_codec_4xm.c最後的結構體初始化代碼如下:
AVCodec ff_fourxm_decoder = {
.name = "4xm",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_4XM,
.priv_data_size = sizeof(FourXContext),
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("4X Movie"),
};
修改之後的代碼應該如下:
AVCodec ff_fourxm_decoder;
void init_ff_fourxm_decoder(){
ff_fourxm_decoder.name = "4xm";
ff_fourxm_decoder.type = AVMEDIA_TYPE_VIDEO;
ff_fourxm_decoder.id = AV_CODEC_ID_4XM;
ff_fourxm_decoder.priv_data_size = sizeof(FourXContext);
ff_fourxm_decoder.init = decode_init;
ff_fourxm_decoder.close = decode_end;
ff_fourxm_decoder.decode = decode_frame;
ff_fourxm_decoder.capabilities = CODEC_CAP_DR1;
ff_fourxm_decoder.long_name = NULL_IF_CONFIG_SMALL("4X Movie");
};
AVInputFormat ff_fourxm_demuxer = {
.name = "4xm",
.long_name = NULL_IF_CONFIG_SMALL("4X Technologies"),
.priv_data_size = sizeof(FourxmDemuxContext),
.read_probe = fourxm_probe,
.read_header = fourxm_read_header,
.read_packet = fourxm_read_packet,
.read_close = fourxm_read_close,
};
修改之後的代碼應該如下;
AVInputFormat ff_fourxm_demuxer;
void init_ff_fourxm_demuxer(){
ff_fourxm_demuxer.name = "4xm";
ff_fourxm_demuxer.long_name = NULL_IF_CONFIG_SMALL("4X Technologies");
ff_fourxm_demuxer.priv_data_size = sizeof(FourxmDemuxContext);
ff_fourxm_demuxer.read_probe = fourxm_probe;
ff_fourxm_demuxer.read_header = fourxm_read_header;
ff_fourxm_demuxer.read_packet = fourxm_read_packet;
ff_fourxm_demuxer.read_close = fourxm_read_close;
};
如果對每一個文件都手動的去這樣修改,勢必會佔用大量的時間。我們可以用UE的正則表達式功能一定程度上減輕工作量。
5.2 正則表達式的運用
每次,用UE打開字母排序連續的50個文件。太多了,UE會吃不消。執行正則表達式的替換語法:
Find what: (AVCodec)\s+([\w_]+)\s*=\s*\{
replace: $1 $2;\nvoid init_$2\(\)\{
上述正則表達式將把上述第一段代碼替換爲:
AVCodec ff_fourxm_decoder;
void init_ff_fourxm_decoder(){
.name = "4xm",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_4XM,
.priv_data_size = sizeof(FourXContext),
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("4X Movie"),
};
如果你精通用某種語言操作正則表達式的話,你就可以在這個結果上再寫一個正則表達式解析出字符串ff_fourxm_decoder,然後再解析出.name,.type等,在此基礎上替換爲上面的第二段代碼。
幾乎每一個文件的最後對結構體的初始化代碼都和上面的類似,所以用幾乎完全相同的正則表達式可以減少絕大部分的工作量。除非,你能百分百地確定你的正則表達式的正確性,否則,你應該一次執行替換一個而不是全部替換,至少前面幾個的替換要一次執行一個,以確保你的正則表達式的正確性。
6. 其它主要的正則表達式
6.1 static const AVOption options[]變量的初始化
原始代碼如下:
static const AVOption options[] = {
{"dual_mono_mode", "Select the channel to decode for dual mono",
offsetof(AACContext, force_dmono_mode), AV_OPT_TYPE_INT, {.i64=-1}, -1, 2,
AACDEC_FLAGS, "dual_mono_mode"},
{"auto", "autoselection", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"main", "Select Main/Left channel", 0, AV_OPT_TYPE_CONST, {.i64= 1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"sub" , "Select Sub/Right channel", 0, AV_OPT_TYPE_CONST, {.i64= 2}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"both", "Select both channels", 0, AV_OPT_TYPE_CONST, {.i64= 0}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{NULL},
};
修改之後的初始化如下:
static const AVOption options[] = {
{"dual_mono_mode", "Select the channel to decode for dual mono",
offsetof(AACContext, force_dmono_mode), AV_OPT_TYPE_INT, (int64_t)(-1), -1, 2,
AACDEC_FLAGS, "dual_mono_mode"},
{"auto", "autoselection", 0, AV_OPT_TYPE_CONST, (int64_t)(-1), INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"main", "Select Main/Left channel", 0, AV_OPT_TYPE_CONST, (int64_t)(1), INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"sub" , "Select Sub/Right channel", 0, AV_OPT_TYPE_CONST, (int64_t)(2), INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{"both", "Select both channels", 0, AV_OPT_TYPE_CONST, (int64_t)(0), INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
{NULL},
};
正則表達式如下:
Find what: \{\s*\.i64\s*=\s*(-?[\w\*]+)\s*\}
Replace:\(int64_t\)\($1\)
上述正則表達式把以 .i64 = 後面的一個合法標示符變換爲 (int64_t)後面接原始標示符。
類似的還有幾個如下,分別替換雙精度類型和字符串類型:
Find what:\{\s*\.dbl\s*=\s*(-?[\w.]+)\s*\}
Replace:\(double\)\($1\)
Find what:\{\s*\.str\s*=\s*(-?[\w"]+)\s*\}
Find what:\(const char\*\)\($1\)
注意,冒號之後的爲正則表達式。不同的人執行同一個任務寫出來的正則表達式不唯一!
6.2 變量AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB]的初始化
這個變量很重要,如果它初始化不正確,程序將會crash掉。這個變量的初始化放在單獨的一個文件裏面,因爲它太長太長!這個文件就是前面提到的ffmpeg_init_av_pix_fmt_descriptors.c
原始初始化代碼如下:
const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_YUV420P] = {
.name = "yuv420p",
.nb_components = 3,
.log2_chroma_w = 1,
.log2_chroma_h = 1,
.comp = {
{ 0, 0, 1, 0, 7 }, /* Y */
{ 1, 0, 1, 0, 7 }, /* U */
{ 2, 0, 1, 0, 7 }, /* V */
},
.flags = PIX_FMT_PLANAR,
},
[AV_PIX_FMT_YUYV422] = {
.name = "yuyv422",
.nb_components = 3,
.log2_chroma_w = 1,
.log2_chroma_h = 0,
.comp = {
{ 0, 1, 1, 0, 7 }, /* Y */
{ 0, 3, 2, 0, 7 }, /* U */
{ 0, 3, 4, 0, 7 }, /* V */
},
},
這裏只列舉了前兩個,後面還有很長很長的幾乎類似的代碼。
修改之後的代碼應該寫成這個樣子:
void init_g_AVPixFmtDescriptor_av_pix_fmt_descriptors(){
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].name = "yuv420p";
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].nb_components = 3;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].log2_chroma_w = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].log2_chroma_h = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[0].plane = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[0].step_minus1 = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[0].offset_plus1 = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[0].shift = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[0].depth_minus1 = 7;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[1].plane = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[1].step_minus1 = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[1].offset_plus1 = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[1].shift = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[1].depth_minus1 = 7;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[2].plane = 2;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[2].step_minus1 = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[2].offset_plus1 = 1;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[2].shift = 0;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].comp[2].depth_minus1 = 7;
av_pix_fmt_descriptors[AV_PIX_FMT_YUV420P].flags = PIX_FMT_PLANAR;
Find what:
\[(\w+)\].+\s+(\.name.+),\s+(\.nb_components.+),\s+(\.log2_chroma_w.+),\s+(\.log2_chroma_h.+),\s+(.comp.+)
Replace:
av_pix_fmt_descriptors[$1]$2;\n av_pix_fmt_descriptors[$1]$3;\n av_pix_fmt_descriptors[$1]$4;\n av_pix_fmt_descriptors[$1]$5;\n av_pix_fmt_descriptors[$1]$6;
Find what:
av_pix_fmt_descriptors\[(\w+)\]\.comp\s*.+\s+\{(.+)\}.+\s+\{(.+)\}.+\s+\{(.+)\}.+
Replace:
av_pix_fmt_descriptors[$1].comp[0] = $2;\n av_pix_fmt_descriptors[$1].comp[1] = $3;\n av_pix_fmt_descriptors[$1].comp[2] = $4;
Find what:
av_pix_fmt_descriptors\[(\w+)\]\.comp\[2\]\s*(.+)\s+\{(.+)\}.+
Replace:
av_pix_fmt_descriptors[$1].comp[2] $2\n av_pix_fmt_descriptors[$1].comp[3] = $3;
Find what:
av_pix_fmt_descriptors\[(\w+)\]\.comp\[(\d+)\]\s*=\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+).+
Replace:
av_pix_fmt_descriptors[$1].comp[$2].plane = $3;\n av_pix_fmt_descriptors[$1].comp[$2].step_minus1 = $4;\n av_pix_fmt_descriptors[$1].comp[$2].offset_plus1 = $5;\n av_pix_fmt_descriptors[$1].comp[$2].shift = $6;\n av_pix_fmt_descriptors[$1].comp[$2].depth_minus1 = $7;
Find what:
av_pix_fmt_descriptors\[(\w+)\](.+)\s+\},\s+\.flags\s*=\s*([\w\| ]+),\s+\},
Replace:
av_pix_fmt_descriptors[$1]$2\n av_pix_fmt_descriptors[$1].flags = $3;\n
注意,上述一系列正則表達式都比較長,沒有折行的地方不能換行,否則會出現格式上的錯誤。