如何减少MediaCodec视频/AVC解码中的延迟



我在grafika mediacodec示例代码上执行了MoviePlayer.java的一些简单计时。

在第203行

之前
decoder.queueInputBuffer

在第244行

之后
decoder.dequeueOutputBuffer

我使用presentationTimeUs

将日志语句关联

这是LogCat的摘录:

01-29 10:56:43.295: I/Grafika(21286): queueInputBuffer index/pts, 2,0
01-29 10:56:43.305: I/Grafika(21286): queueInputBuffer index/pts, 0,33100
01-29 10:56:43.315: I/Grafika(21286): queueInputBuffer index/pts, 3,66466
01-29 10:56:43.325: I/Grafika(21286): queueInputBuffer index/pts, 1,99833
01-29 10:56:43.325: I/Grafika(21286): queueInputBuffer index/pts, 2,133200
01-29 10:56:43.335: I/Grafika(21286): queueInputBuffer index/pts, 0,166566
01-29 10:56:43.345: I/ATSParser(21286): discontinuity on stream pid 0x1011
01-29 10:56:43.345: I/ATSParser(21286): discontinuity on stream pid 0x1100
01-29 10:56:43.345: I/Grafika(21286): queueInputBuffer index/pts, 3,199933
01-29 10:56:43.345: I/Grafika(21286): dequeueOutputBuffer index/pts, 7,0
01-29 10:56:43.345: I/Grafika(21286): queueInputBuffer index/pts, 1,300033
01-29 10:56:43.355: I/Grafika(21286): dequeueOutputBuffer index/pts, 6,33100
01-29 10:56:43.385: I/Grafika(21286): queueInputBuffer index/pts, 2,333400
01-29 10:56:43.385: I/Grafika(21286): dequeueOutputBuffer index/pts, 5,66466
01-29 10:56:43.415: I/Grafika(21286): queueInputBuffer index/pts, 0,366766
01-29 10:56:43.415: I/Grafika(21286): dequeueOutputBuffer index/pts, 4,99833
01-29 10:56:43.445: I/Grafika(21286): queueInputBuffer index/pts, 3,400133
01-29 10:56:43.445: I/Grafika(21286): dequeueOutputBuffer index/pts, 3,133200

我发现,从第一个输入缓冲区排队到相应的输出缓冲区脱水为50毫米时的时间差。这似乎是HW加速解码的时间。

有没有办法减少此潜伏期?

我认为您看到了第一帧独有的效果。我重复了您的实验,并进一步添加了在第244行中强制doRender = false,以避免用于管理输出帧速率的睡眠电话。我看到:

01-29 14:05:36.552  9115  9224 I Grafika : queueInputBuffer index/pts, 2,0
01-29 14:05:36.562  9115  9224 I Grafika : queueInputBuffer index/pts, 0,66655
01-29 14:05:36.572  9115  9224 I Grafika : queueInputBuffer index/pts, 3,133288
01-29 14:05:36.582  9115  9224 I Grafika : queueInputBuffer index/pts, 1,199955
01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 4,0
01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 3,66655
01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 2,133288
01-29 14:05:36.612  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 4,199955

(为了清楚起见,除去外部线。)这确认了您的结果。请注意,虽然PTS = 0的输入和输出之间存在50毫秒,但随后的输出帧几乎立即可用。我使用的视频是" camera-test.mp4"(720p相机输出)。

洞察为什么会发生这种情况,请查看日志中的其他内容以及它出现的位置。从第一个queueInputBuffer日志线开始,计算出在该日志和第一个dequeueOutputBuffer行之间出现的日志数。我在我的OMX-VDEC-1080P上计算了大约60行的产出。现在,计算输出缓冲区开始出现后出现多少个OMX-VDEC线。我没有看到视频结束之前。

视频解码器显然会推迟一些昂贵的初始化,直到数据可用。因此,下一个问题是...需要多少数据?提交第二帧后,我添加了500ms的睡眠(PTS == 66633)。结果:提交了两个帧,500毫秒暂停,提交了两个帧,大堆OMX-VDEC日志。因此,似乎解码器需要几帧才能启动。

这表明我们可以通过快速喂食前几个帧来减少启动潜伏期。为了进行测试,我将TIMEOUT_USEC更改为零,因此它会迅速响应,但燃烧CPU。新的日志输出(您的日志,没有睡眠,没有渲染):

01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 0,0
01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 2,66633
01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 3,133288
...
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 4,0
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 3,66633
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 2,133288

通过快速喂食初始帧,我们将初始延迟从50ms降低到30ms。

(请注意,所有时间戳在'2'中如何结束?用于日志时间的计时器似乎舍入到最接近的10ms,因此实际时间delta可能略有不同。)

我们慢慢喂食初始帧的原因是,在提交每个输入缓冲区后,我们试图从解码器中排出输出,等待10毫秒的输出,从未出现。我最初的想法是,我们想等待 dequeueInputBuffer() dequeueOutputBuffer()的超时,但不是两者兼而有之 - 也许在输入上使用超时,并进行快速的民意调查首先输出,然后在输入输入输入时切换到输出超时。(为此,输入的初始超时可能为-1,因为我们知道在排队之前什么都不会发生。)

我不知道是否有办法进一步降低潜伏期。

最新更新