ffmpeg命令分析-re - 弦外之音

/ 0评 / 0

本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8

本系列主要分析各种 ffmpeg 命令参数 在代码里是如何实现的。a.mp4下载链接:百度网盘,提取码:nl0s 。


命令如下:ffmpeg -re -i a.mp4 a.flv

-re 参数控制读取 AVpacket 的速度,按照帧率速度读取文件 AVpacket。如果有多个流,以最慢的帧率为准。


命令行参数 -re 定义如下:

ffmpeg_opt.c 3453行
{ "re",OPT_BOOL | OPT_EXPERT | OPT_OFFSET |  OPT_INPUT,  { .off =  OFFSET(rate_emu) },"read input at native frame rate", "" },

命令行参数 -re 赋值给 InputFile 结构, 如下:

ffmpeg_opt.c 1209行
f->rate_emu   = o->rate_emu;

可以看到,在 ffmpeg_opt.c 1209行 把 OptionsContext 里面的 rate_emu 赋值给了 InputFile 的 rate_emu。

InputFile 的 rate_emu 赋值给 InputStream 的start, 如下:

ffmpeg.c 4134行
 /* init framerate emulation */
 for (i = 0; i < nb_input_files; i++) {
    InputFile *ifile = input_files[i];
    if (ifile->rate_emu) //注意这里
        for (j = 0; j < ifile->nb_streams; j++)
            input_streams[j + ifile->ist_index]->start = av_gettime_relative(); //注意这里
 }

InputStream 的start 的用途,如下:

fmpeg.c 4134行
static int get_input_packet(InputFile *f, AVPacket *pkt)
{
    if (f->rate_emu) { //注意这里
        int i;
        for (i = 0; i < f->nb_streams; i++) {
            InputStream *ist = input_streams[f->ist_index + i];
            int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
            int64_t now = av_gettime_relative() - ist->start;
            if (pts > now)
                return AVERROR(EAGAIN);
        }
    }
​
    return av_read_frame(f->ctx, pkt);
}

从上面的逻辑可以看到,InputStream 的start 实际上就是存一个启动时间,然后在 get_input_packet() 里面根据 now 跟 ist->dts 控制频率 读取 AVpacket 的数据。

如果有多个流,以最慢的帧率为准。


分析到这里,这也是我之前的《FFmpeg 源码分析》 专栏不断强调的重点,初学者学ffmpeg的源码,不需要一开始就去看多余的分支逻辑,因为 ffmpeg.c 里面实现了非常多的命令参数功能。

如果一开始就把 ffmpeg 的所有参数的结构讲完,没有意义。就好像初学者一开始看 这个 InputStream 的start字段,根本不可能猜出来 start 这个字段的真正用途。我一开始还以为start 是流的第一个帧的pts。

所以,学习ffmpeg源码,只需要学会用 Qt 来断点调试,了解了主干逻辑就行。其他细枝末节的逻辑,你后面用到了,断点调试即可了解ffmpeg是如何实现这些功能的,这样会影响更加深刻。


版权所属:知识星球:弦外之音,QQ:2338195090。 由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注