记录一下踩到的 AV_PKT_FLAG_DISCARD 一个坑。

背景

做一个 取帧 的功能,能够传入指定时间,并获取该时间点的帧。

实现步骤如下:

  1. 获取视频流的 duration
    由于部分格式的素材需要做适配,所以这里是通过取 pkt->pts + pkt->duration 的最大值来计算的。
  2. 根据 duration 做容错,大于或等于duration 时,就取 duration 时间点的帧。
  3. 取帧的判断条件是:

    if (frame->pts <= clock && clock < frame->pts + frame->duration) {
         // 采用的是左闭右开的方式 [pts, pts+duration) 取帧
    }

问题

看似都比较正常,但是奇怪的事情出现了,视频流的 duration6133 (即: {pkt->pts: 6100, pkt->duration: 33})
但是解码出来最后一帧 AVFramepts 却是 6067

这就导致了按照上述的取帧方式始终取不到时间点为 大于6100 的帧。

解决

经排查,发现在计算视频流 duration 的时候,最后一个 AVPacketflags 字段中包含了 AV_PKT_FLAG_DISCARD 标志。该标志的作用如下:

/**
 * Flag is used to discard packets which are required to maintain valid
 * decoder state but are not required for output and should be dropped
 * after decoding.
 **/
#define AV_PKT_FLAG_DISCARD   0x0004

大致的意思可以简单的理解为:带有该标志的AVPacket所携带的数据为解码器相关的信息,不会被解码出一幅图像。

原因找到了,计算 duration 的时候由于 AV_PKT_FLAG_DISCARD 标志的影响多计算了一帧的时间,导致无法获取到最后一帧。解决方式就是在计算 duration 的时候判断如果是该标志就跳过就好了。


oogh
222 声望5 粉丝

绝知此事要躬行!