我正在使用 LibAV 开发 mp4 解复用器。我需要一个将 PTS 转换为帧号的辅助函数。我想出了以下有效的代码。但我不确定它在 LibAV 领域对于任何视频输入有多正确。在我的例子中,视频 fps = 25,时间刻度 = 25000。 接下来的每个 PTS 都会增加 40,给我正确的
frameNumber
。
int64_t timestamp_to_frame(Demuxer* demuxer, int64_t pts)
{
AVStream* stream = demuxer->fmtc->streams[demuxer->iVideoStream];
if (!stream || pts < 0)
{
fprintf(stderr, "Invalid stream or PTS.\n");
return -1;
}
// Get the frame rate (FPS)
const double fps = get_frame_rate(stream);//here returns 25.0
// Stream time base (e.g., 1/25000 for my case)
const AVRational timeBase = stream->time_base;
// Calculate frame duration in seconds
const double frameDurationInSeconds = 1.0 / fps;
const int64_t ptsIncrement = (int64_t)((frameDurationInSeconds * timeBase.den) * frameDurationInSeconds + 0.5);
// Calculate the frame number by dividing PTS by the increment
const int64_t frameNumber = pts / ptsIncrement;
return frameNumber;
}
我想了解这段代码是否是正确的方法。我尝试使用不同的 libav 时间重新调整函数,但无法得出正确的结果。
您的代码可能没问题。 但是,您正在使用一堆浮点计算来获取 64 位[整数] PTS 增量。
一般情况下,PTS增量应该是固定值。如果没有,可能会使 A/V 同步变得更加困难。
所以,我认为你的代码应该计算 PTS 增量但保留一个副本。如果增量发生(急剧)变化,这可能是您需要考虑的过渡或丢失帧。见下文。
我不确定是否有一种“标准”方法来获取 PTS 增量/增量。但是,我能想到的另一种方法(您可以将其用作对您的方法的交叉检查)可能是:
IBBBP
的 GOP,您将收到它们作为 IPBBB
)。array[i + 1] - array[i]
该数组可以是最后 N 帧的滑动窗口。
如果您以正确的呈现顺序接收帧(例如
IBBBP
),则无需进行排序(以及数组)。而且,您只需要任意两帧之间的差异。
正如我提到的,PTS 增量应该保持不变/固定。尽管不应该这样做,但某些编码器可能会在 PTS 增量周围出现小抖动。
PTS 增量应保持恒定,除非流源发生变化。在广播或直播中:
对于前两个,如果发生这样的转换,流应该[可能]生成一个IDR,但我不确定这是否是一个要求,特别是如果视频流复用器正在“重新计时”PTS/DTS/PCR来源。
如果您只是解码本地存储的
.mp4
文件,这就是全部内容。
但是,如果您正在解码使用 UDP(相对于 TCP)的实时流,您可能必须检测并解释丢失的视频和/或音频数据包。因此,监视 PTS 增量(以及帧编号)是否有间隙可能是必要的。