Android 使用ffmpeg解析MediaCodec编码的h264流中有关表示时间的信息

Android 使用ffmpeg解析MediaCodec编码的h264流中有关表示时间的信息,android,ffmpeg,encode,android-mediacodec,pts,Android,Ffmpeg,Encode,Android Mediacodec,Pts,我已经看到了下面使用MediaCodecAPI进行编码/解码的示例。 其中对猜测的呈现时间和从解码信息接收到的呈现时间进行了比较 assertEquals("Wrong time stamp", computePresentationTime(checkIndex), info.presentationTimeUs); 因为解码器只是对编码缓冲区中的数据进行解码,所以我认为在此编码器的输出H.264流中可以解析任何时间戳信息 我正在编写一个Android应用程序,它使用ffmpeg(

我已经看到了下面使用
MediaCodec
API进行编码/解码的示例。

其中对猜测的呈现时间和从解码信息接收到的呈现时间进行了比较

assertEquals("Wrong time stamp", computePresentationTime(checkIndex),
    info.presentationTimeUs);
因为解码器只是对编码缓冲区中的数据进行解码,所以我认为在此编码器的输出H.264流中可以解析任何时间戳信息

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

然而,
ffmpeg
似乎无法识别由
MediaCodec
编码的数据包中的表示时间戳,因此在尝试从流中读取帧时,我总是得不到PTS值


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

要将时间戳从
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\u base
取决于帧率

upd重新时间戳在管道中流动: 解码器和编码器都不知道自己的时间戳。通过为这些组件设置时间戳

decoder.queueInputBuffer(inputBufIndex, 0, info.size, info.presentationTimeUs, info.flags);

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

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

基本问题是H.264流不包括演示时间戳。它们必须带外发送,或写入包装器(例如MediaMuxer创建的.mp4文件包装器)。但为什么解码器队列中的解码信息显示正确的时间戳?在EncodeDecodeTest代码中,PTS由
computePresentationTime()
生成,通过
queueInputBuffer()传递给编码器
eglPresentationTime()
,使用BufferInfo中的输出缓冲区接收,使用
queueInputBuffer()
将输入缓冲区传递给解码器,然后使用BufferInfo中的输出接收。如果查看DecodeEditEncodeTest中的VideoChunk,可以看到它为每一帧保存三个片段(编码数据、标志和PTS)。时间戳在编解码器中与缓冲区关联,但它只是简单地传递。谢谢fadden。现在我知道了
MediaCodec
编码器/解码器的工作原理。谢谢你的建议。我知道如何从
MediaCodec
编码器向
ffmpeg
发送时间戳,但不知道为什么只有
MediaCodec
解码器才能从编码数据中获取时间戳信息?
encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, info.flags);