process_input处理输入文件

FFmpeg 的社群来了,想加入微信社群的朋友请购买《FFmpeg原理》VIP版 电子书,里有更高级的内容与答疑服务。


在刚开始的时候,滤镜容器都是未打开的状态,所以会从所有的输入流里面选出一个还未解码出来 AVFrame 的输入流,来进行处理,如下:

process_input() 函数的定义如下:

/*
 * Return
 * - 0 -- one packet was read and processed
 * - AVERROR(EAGAIN) -- no packets were available for selected file,
 *   this function should be called again
 * - AVERROR_EOF -- this function should not be called again
 */
static int process_input(int file_index){
    ...省略代码...
}

可以看到,注释写得很清楚,一共有 3 个返回值。

1,返回 0 ,代表已经读取了一个 AVPacket,并且处理了。

2,返回 AVERROR(EAGAIN),代表暂时没有 AVPacket 可以读取出来进行处理。实际上就是 av_read_frame() 返回 AVERROR(EAGAIN)process_input() 就会返回 AVERROR(EAGAIN)

3,返回 AVERROR_EOF,代表所有的输入文件,都处理完成,不能再次调 process_input()


process_input() 函数的重点代码如下:

第一个重点:处理文件循环以及文件结束,如下:

由于本文是初步讲解 ffmpeg.exe 转换器的转码过程,所以暂时不讲结束的处理逻辑,读者可以后面再看《FFmpeg结束处理》一文。


第二个重点:统计数据,如下:

注意上面的 ist->discard,这个字段不是 API 数据结构的,而是 ffmpeg.c 自己定义的,属于用户层定义的丢弃规则。如果你设置的是 AVStream 的 discard,那根本不可能读到这个流的 AVPacket


第三个是非重点:处理时间戳回环问题,如下:

if(!ist->wrap_correction_done && is->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
        int64_t stime, stime2;
          ...省略代码..
}

在一些流格式,例如 TS,会有时间戳环回的问题,int64 的最大值是 xxx,超过这个大小会环回,ffmpeg.exe 需要处理环回的逻辑。


第四个是非重点:处理 side data,如下:

/* add the stream-global side data to the first packet */
if (ist->nb_packets == 1) {
    for (i = 0; i < ist->st->nb_side_data; i++) {
        ...省略代码..
    }
}

一些非重点的代码,不用特意去看,用到去看就行了。


第五个是非重点:处理时间戳,如下:

if (pkt->dts != AV_NOPTS_VALUE)
    pkt->dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt->pts != AV_NOPTS_VALUE)
    pkt->pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);

if (pkt->pts != AV_NOPTS_VALUE)
    pkt->pts *= ist->ts_scale;
if (pkt->dts != AV_NOPTS_VALUE)
    pkt->dts *= ist->ts_scale;

上面的 ts_offset 默认是 0,ts_scale 默认是 1,所以如果你的命令行参数没用到对应的选项,这些代码跟没运行一样。


第六个是重点:对时间戳进行纠正,如下:

上面的 ifile->last_ts 记录的是上一次读取出来的 AVPacket 的 dts 时间。


第七个是重点:pts 附加上文件的当前时间,如下:

注意,上面的 ifile->duration,不是指输入文件的时长,而是这样的,怎么说呢,这个 duration 默认是 0, 如果文件循环了一次,duration 就是输入文件的时长,如果循环了两次,duration 就是输入文件的时长乘以 2,这是为了 -loop 选项服务的代码。


第八个是重点:还是对时间戳就行修正,如下:

上面的 ist->next_dts 是 由上一个 pkt 的 dts + duration 计算出来的,duration 是根据帧率算的。

可以看到,第六 ,第八 个重点都是修正时间戳,但是计算 delta 的方式是不一样的。

还有一个小彩蛋,就是 if (debug_ts) {..},在纠正时间之前会打印一次,纠正之后,也会打印一次,如果你想看看纠正时间的日志,就可以打开 debug_ts 这个调试选项


最后就是调 process_input_packet() 函数来处理读取到的 AVPacket

process_input_packet(ist, pkt, 0);

因此,process_input() 函数的总体流程如下:

提示:我一般会用圆角矩形来表示这个逻辑是有条件的,也就是这个逻辑可能会执行,也可能不会执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Loken2020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值