【问题标题】:Precise seeking with ffmpeg使用 ffmpeg 进行精确搜索
【发布时间】:2015-08-06 11:20:08
【问题描述】:

假设我有一个使用ffmpeg 解码的音频文件。源格式类似于AAC,其中音频被拆分为数据包。当寻找一个特定的时间时,很明显该时间不会在大多数时候落在数据包边界上,而是在数据包持续时间的某个地方。我必须自己在数据包中搜索还是 av_seek_frame 自己完成所有操作并设置解码,以便下一个解码帧应该从我请求的位置开始?

如果我将函数 av_seek_frame 与标志 AVSEEK_FLAG_BACKWARD 一起使用,我假设 av_read_frame 返回的下一个数据包将是包含我正在寻找的时间位置的数据包到。对吗?

如果我使用 avcodec_decode_audio4 解码此数据包,返回的帧是否包含数据包开始时间或从我传递到 av_seek_frame的时间开始的音频数据>?在后一种情况下,我如何找出帧/数据包时间戳以估计解码帧中要跳过的样本数?搜索后的PTS 为零,DTS 看起来也没用。

是否可以使用ffmpeg 精确到特定时间?

【问题讨论】:

    标签: c audio ffmpeg


    【解决方案1】:

    在 ffmpeg 中没有帧精确或音频样本精确搜索,这是一个应用程序级别的问题。原因很简单:libavformat 进行搜索,但它不知道各个解复用器返回的数据包中的内容。它只有一个带有时间戳 X 和持续时间 Y 的数据块。它对该数据一无所知,您必须对数据进行解码才能对其执行任何有意义的操作,即 libavcodec,而不是 libvformat。

    所以,回答你的问题:av_seek_frame 寻求数据包边界,AVSEEK_FLAG_BACKWARD 意味着数据包将严格在给定 ts 之前;对于音频,这意味着数据包很可能包含您的时间戳。然而,情况并非总是如此,因为一些解复用器基于索引进行搜索,并且并非每个数据包都可能具有索引条目。您可能需要多次调用 av_read_frame() 才能到达包含搜索后指定时间戳的数据包。

    除了你调用 avcodec_flush() 之外,libavcodec 对搜索一无所知,因此下一次调用 avcodec_decode_audio4 的输出将从输入数据包的开头开始。对于特定样本的搜索,应用程序必须自己砍掉领先的样本。

    【讨论】:

    • 我部分同意帧精确搜索是一个应用程序级别的问题。由于可以在各种编解码器/格式上使用,ffmpeg 至少可以改进av_seek_frame 的文档,指定在AVPacket dts 上执行搜索。这很令人困惑,因为帧索引是一个与表示相关的概念。
    • 查找并不总是在 dts 上执行,它实际上取决于容器。如果容器时间戳是 pts,则寻找是在 pts 中;如果容器时间戳是 dts,则在 dts 中查找。
    • 那么它也应该被记录下来。相反,av_seek_frame 的文档几乎没有提供任何细节。如何可靠地确定容器时间戳是否在 pts 或 dts 中打开?
    • 我同意记录它可能很有用。你应该提交一个补丁。 :-)。至于为什么我们没有记录它,你必须明白,多媒体确实有数以万亿计的特殊情况规则或类似的令人讨厌的行为,不是因为我们——作为 ffmpeg 开发者——想要激怒,而是因为技术非常不统一,并且需要针对各种情况的特殊情况进行分类工作。我们可以让它完全不起作用或记录所有特殊情况,但这会更令人困惑。了解您的技术堆栈。 :-)。
    【解决方案2】:

    是的,源代码确认 av_seek_frame 确实会搜索到数据包边界。

    为了在数据包中寻找,我使用由 av_seek_frame 更新的 AVStream::cur_dts 时间戳来告诉它所寻找的边界。使用该值,可以找出要在数据包中跳过的剩余样本数。这样就解决了问题。

    【讨论】:

    • 这是正确的。我在answer 上发布了一些代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-05
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-05
    相关资源
    最近更新 更多