参考博文 https://www.cnblogs.com/wanggang123/p/6056700.html
https://blog.csdn.net/sidumqz/article/details/52830622
在学习hls+nginx的过程中,需要用到ffmeg对源解封装处理,有必要学习ffmpeg.exe是使用
ffmpeg.exe方法
ffmpeg.exe -re -i "E:\avideo.mp4" -vcodec libx264 \
-vprofile baseline -acodec aac -ar 44100 -strict -2 \
-ac 1 -f flv -s 1280x720 -q 10 \
rtmp://%ip%:1935/hls/test2
ffmpeg.exe是ffmpeg库提供的一个编解码工具,可以对各种音视频进行编解码,并输出不同的封装格式文件。 -re 表示按照时间戳读取视频源文件;输出格式为flv的封装
ffmpeg.c对这些option选项做了处理
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
const OptionDef *options,
const OptionGroupDef *groups, int nb_groups)
{
int optindex = 1;
int dashdash = -2;
/* perform system-dependent conversions for arguments list */
prepare_app_arguments(&argc, &argv);
init_parse_context(octx, groups, nb_groups);
av_log(NULL, AV_LOG_DEBUG, "Splitting the commandline.\n");
while (optindex < argc) {
const char *opt = argv[optindex++], *arg;
const OptionDef *po;
int ret;
av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt);
if (opt[0] == '-' && opt[1] == '-' && !opt[2]) {
dashdash = optindex;
continue;
}
/* unnamed group separators, e.g. output filename */
if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) {
finish_group(octx, 0, opt);
av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name);
continue;
}
opt++;
#define GET_ARG(arg) \
do { \
arg = argv[optindex++]; \
if (!arg) { \
av_log(NULL, AV_LOG_ERROR, "Missing argument for option '%s'.\n", opt);\
return AVERROR(EINVAL); \
} \
} while (0)
/* named group separators, e.g. -i */
if ((ret = match_group_separator(groups, nb_groups, opt)) >= 0) {
GET_ARG(arg);
finish_group(octx, ret, arg);
av_log(NULL, AV_LOG_DEBUG, " matched as %s with argument '%s'.\n",
groups[ret].name, arg);
continue;
}
/* normal options */
po = find_option(options, opt);
if (po->name) {
if (po->flags & OPT_EXIT) {
/* optional argument, e.g. -h */
arg = argv[optindex++];
} else if (po->flags & HAS_ARG) {
GET_ARG(arg);
} else {
arg = "1";
}
add_opt(octx, po, opt, arg);
av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with "
"argument '%s'.\n", po->name, po->help, arg);
continue;
}
/* AVOptions */
if (argv[optindex]) {
ret = opt_default(NULL, opt, argv[optindex]);
if (ret >= 0) {
av_log(NULL, AV_LOG_DEBUG, " matched as AVOption '%s' with "
"argument '%s'.\n", opt, argv[optindex]);
optindex++;
continue;
} else if (ret != AVERROR_OPTION_NOT_FOUND) {
av_log(NULL, AV_LOG_ERROR, "Error parsing option '%s' "
"with argument '%s'.\n", opt, argv[optindex]);
return ret;
}
}
/* boolean -nofoo options */
if (opt[0] == 'n' && opt[1] == 'o' &&
(po = find_option(options, opt + 2)) &&
po->name && po->flags & OPT_BOOL) {
add_opt(octx, po, opt, "0");
av_log(NULL, AV_LOG_DEBUG, " matched as option '%s' (%s) with "
"argument 0.\n", po->name, po->help);
continue;
}
av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'.\n", opt);
return AVERROR_OPTION_NOT_FOUND;
}
if (octx->cur_group.nb_opts || codec_opts || format_opts || resample_opts)
av_log(NULL, AV_LOG_WARNING, "Trailing options were found on the "
"commandline.\n");
av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n");
return 0;
}
1.OptionParseContext octx;用来将命令行中的参数通过分析分别存入此结构体的对应变量中。之后argc, argv就没用了。
2.options,定义了所有的参数、参数类型、参数是否有值、是放到全局变量中还是放到OptionsContext结构的某个变量中,或者是调用一个函数来处理参数的值。
按照前篇nginx+ffmpeg的配置好后,可以调试hls以及rtmp的流媒体协议;
如下堆栈对应hls+前篇nginx的讲解,最后通过http新增访问location来设置hls的访问路径http://localhost/hls/test2.m3u 对应路径为http://ip:80/hls/test2.m3u8
#0 hls_probe (p=0x70107f) at libavformat/hls.c:2136
#1 0x00007ffff721db92 in av_probe_input_format3 (pd=0x7fffec33ac20, is_opened=1, score_ret=0x7fffec33aba4)
at libavformat/format.c:209
#2 0x00007ffff721dd95 in av_probe_input_format2 (pd=0x7fffec33ac20, is_opened=1, score_max=0x7fffec33abf4)
at libavformat/format.c:252
#3 0x00007ffff721e066 in av_probe_input_buffer2 (pb=0x7fffe400b100, fmt=0x7fffe4000928,
filename=0x701060 "http://10.28.9.125:80/hls/test2.m3u8", logctx=0x7fffe4000920, offset=0,
max_probe_size=1048576) at libavformat/format.c:332
#4 0x00007ffff7379982 in init_input (s=0x7fffe4000920, filename=0x701060 "http://10.28.9.125:80/hls/test2.m3u8",
options=0x7fffec33ace0) at libavformat/utils.c:421
#5 0x00007ffff7379e7a in avformat_open_input (ps=0x7fffec33ad40,
filename=0x701060 "http://10.28.9.125:80/hls/test2.m3u8", fmt=0x0, options=0x620c78)
at libavformat/utils.c:537
分析调用堆栈
ffplay开启读线程read_thread—–> ic = avformat_alloc_context();—->avformat_get_context_defaults—->avformat_open_input()—->init_input—->s->io_open()—->ffio_open_whitelist—->ffurl_alloc—>url_find_protocol—->av_probe_input_buffer2—>av_probe_input_format2 —>av_probe_input_format3 —>read_probe—>最终找到hls->probe