FFMPEG 时间戳PTS校正
前言
FFMPEG时间戳校正是通过DTS来进行的,在compute_pkt_fields中实现。这篇文章也写了很久了,没有空整理,先发出来供需要的人参考。
代码
static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
AVCodecParserContext *pc, AVPacket *pkt,
int64_t next_dts, int64_t next_pts)
{
int num, den, presentation_delayed, delay, i;
int64_t offset;
AVRational duration;
int onein_oneout = st->codecpar->codec_id != AV_CODEC_ID_H264 &&
st->codecpar->codec_id != AV_CODEC_ID_HEVC;
/* AVFMT_FLAG_NOFILLIN定义于AVFormatContext中,表示不需要进行pts处理,直接使用当前的pts */
if (s->flags & AVFMT_FLAG_NOFILLIN)
return;
/* 视频,且当前pkt的dts存在 */
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && pkt->dts != AV_NOPTS_VALUE) {
/* 解码时间等于显示时间,并且之前已经记录到了正常的dts */
if (pkt->dts == pkt->pts && st->last_dts_for_order_check != AV_NOPTS_VALUE) {
/* 前述记录的正常dts小于等于当前的dts,用dts_ordered表示正常顺序的pkt数目。 */
if (st->last_dts_for_order_check <= pkt->dts) {
st->dts_ordered++;
} else {
/* 当前的dts比之前记录的dts小,用dts_misordered表示dts顺序异常的Pkt数目 */
st->dts_misordered++;
}
/* 总包数大于250时,包数都减半,这是为了避免变量溢出 */
if (st->dts_ordered + st->dts_misordered > 250) {
st->dts_ordered >>= 1;
st->dts_misordered >>= 1;
}
}
/* 将当前有效的PTS设置为检查点的pts */
st->last_dts_for_order_check = pkt->dts;
/* dts正常的包少,并且当前包的pts和dts相等,则认为当前pkt的pts无效 */
if (st->dts_ordered < 8*st->dts_misordered && pkt->dts == pkt->pts)
pkt->dts = AV_NOPTS_VALUE;
}
/* 忽略DTS */
if ((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts = AV_NOPTS_VALUE;
/* 遇到B帧,将B帧存在标记置上 */
if (pc && pc->pict_type == AV_PICTURE_TYPE_B
&& !st->internal->avctx->has_b_frames)
//FIXME Set low_delay = 0 when has_b_frames = 1
st->internal->avctx->has_b_frames = 1;
/* do we have a video B-frame ? */
delay = st->internal->avctx->has_b_frames;
presentation_delayed = 0;
/* 存在B帧并且当前包不是B帧数据,显示delay置1 */
if (delay &&
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
/* pts_wrap_bits表示码流中某条流的PTS对应的bit数,
* 比如TS的码流,PTS是33位,pts_wrap_bits就是33,
* wrap在ffmpeg中是超过最大值后重新回到开始这种情况。中文翻译成换行。
*/
/* pts,dts都有值,但是dts远远大于pts,限制pts_wrap_bits小于63是为了防止移位溢出 */
if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
st->pts_wrap_bits < 63 &&
pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) {
/* 大于RELATIVE_TS_BASE的值认为是相对值,cur_dts是相对值或者pkt的dts远大于cur_dts */
if (is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits - 1)) > st->cur_dts) {
pkt->dts -= 1LL << st->pts_wrap_bits;
} else
pkt->pts += 1LL << st->pts_wrap_bits;
}
/* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg).
* We take the conservative approach and discard both.
* Note: If this is misbehaving for an H.264 file, then possibly
* presentation_delayed is not set correctly. */
if (delay == 1 && pkt->dts == pkt->pts &&
pkt->dts != AV_NOPTS_VALUE && presentation_delayed) {
av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts);
&n

本文介绍FFMPEG时间戳PTS校正,其通过DTS在compute_pkt_fields中实现。文中给出相关代码,涉及对视频、音频等不同情况的处理,如判断PTS、DTS有效性,处理B帧,校正时间戳等,还包含计算时长、更新初始时长等操作。
最低0.47元/天 解锁文章
791

被折叠的 条评论
为什么被折叠?



