【问题标题】:use ffmpeg to parse info about presentation time in h264 stream encoded by MediaCodec使用 ffmpeg 解析由 MediaCodec 编码的 h264 流中有关呈现时间的信息
【发布时间】:2014-07-08 10:36:35
【问题描述】:

我已经看到下面使用MediaCodec API 进行编码/解码的示例。 https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java

其中将猜测的呈现时间与从解码信息接收的呈现时间进行比较。

assertEquals("Wrong time stamp", computePresentationTime(checkIndex),
    info.presentationTimeUs);

由于解码器只是解码编码缓冲区中的数据,我认为在此编码器的输出 H.264 流中可以解析任何时间戳信息。

我正在编写一个 Android 应用程序,它使用 ffmpeg (libavformat) 将由 MediaCodec 编码的 H264 流 (.h264) 混合到 mp4 容器。 我不想使用MediaMuxer,因为它需要的 4.3 版本太高了。

但是,ffmpeg 似乎无法识别由MediaCodec 编码的数据包中的呈现时间戳,因此当我尝试从流中读取帧时总是得到 NO_PTS 值。

有谁知道在这种情况下如何获得正确的演示时间戳?

【问题讨论】:

  • 基本问题是 H.264 流不包括演示时间戳。它们必须带外传送,或写入包装器(例如,MediaMuxer 创建的 .mp4 文件包装器)。
  • 但是为什么解码器队列中的解码信息显示正确的时间戳?
  • 在EncodeDecodeTest代码中,PTS由computePresentationTime()生成,通过queueInputBuffer()eglPresentationTime()传递给编码器,在BufferInfo中与输出缓冲区一起接收,与输入一起传递给解码器queueInputBuffer() 的缓冲区,然后在 BufferInfo 中与输出一起接收。如果您查看 DecodeEditEncodeTest 中的 VideoChunks,您可以看到它为每一帧保存了三个部分(编码数据、标志和 PTS)。时间戳与编解码器内部的缓冲区相关联,但它只是通过。
  • 谢谢你。现在我知道MediaCodec 编码器/解码器是如何工作的了。

标签: android ffmpeg encode android-mediacodec pts


【解决方案1】:

要将时间戳从MediaCodec 编码器发送到ffmpeg,您需要这样转换:

jint Java_com_classclass_WriteVideoFrame(JNIEnv * env, jobject this, jbyteArray data, jint datasize, jlong timestamp) {

    ....

AVPacket pkt;
av_init_packet(&pkt);

AVCodecContext *c = m_pVideoStream->codec;

pkt.pts = (long)((double)timestamp * (double)c->time_base.den / 1000.0);
pkt.stream_index    = m_pVideoStream->index;
pkt.data            = rawjBytes;
pkt.size            = datasize;

time_base 取决于帧率

更新重新时间戳在管道中流动: 解码器和编码器都不知道自己的时间戳。通过

为这些组件设置时间戳
decoder.queueInputBuffer(inputBufIndex, 0, info.size, info.presentationTimeUs, info.flags);

encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, info.flags);

这些时间戳可以取自提取器、相机或应用程序生成,但解码器\编码器只是通过这些时间戳而不更改它们。因此,时间戳从源到接收器(复用器)保持不变。

当然有一些例外情况:如果帧频发生变化 - 例如帧频转换。或者如果编码器使用 B 帧进行编码并发生重新排序。 或编码器可以将时间戳添加到编码器帧头 - 可选,不是标准强制要求。我认为所有这些都不适用于当前的 android 版本、编解码器或您的使用场景。

【讨论】:

  • 感谢您的建议。我知道如何将时间戳从MediaCodec 编码器发送到ffmpeg,但不知道为什么只有MediaCodec 解码器能够从编码数据中获取时间戳信息?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 2015-12-26
  • 2011-08-26
  • 2021-08-30
  • 2020-10-06
  • 2011-08-21
  • 2019-06-21
相关资源
最近更新 更多