欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

webrtc 计算解码时间的方法

程序员文章站 2022-07-01 15:39:03
...

Q:如何计算?

解码的关键代码在这里:AndroidVideoDecoder.java

private static class FrameInfo {
	final long decodeStartTimeMs;
	final int rotation;
	FrameInfo(long decodeStartTimeMs, int rotation) {
	  this.decodeStartTimeMs = decodeStartTimeMs;
	  this.rotation = rotation;
	}
}

@Override
public VideoCodecStatus decode(EncodedImage frame, DecodeInfo info) {
...

frameInfos.offer(new FrameInfo(SystemClock.elapsedRealtime(), frame.rotation));

try {
	codec.queueInputBuffer(index, 0 /* offset */, size,
		TimeUnit.NANOSECONDS.toMicros(frame.captureTimeNs), 0 /* flags */);
} catch (IllegalStateException e) {
}
...
}

protected void deliverDecodedFrame() {
...
int result = codec.dequeueOutputBuffer(info, DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US);
if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
	reformat(codec.getOutputFormat());
	return;
}
if (result < 0) {
	Logging.v(TAG, "dequeueOutputBuffer returned " + result);
	return;
}
FrameInfo frameInfo = frameInfos.poll();
Integer decodeTimeMs = null;
int rotation = 0;
if (frameInfo != null) {
	decodeTimeMs = (int) (SystemClock.elapsedRealtime() - frameInfo.decodeStartTimeMs);
	rotation = frameInfo.rotation;
}
...
}

在代码中,解码时间用 decodeStartTimeMs 存储。
有一点背景知识,可能需要你先熟悉下MediaCodec

简单描述下,MediaCodec提供一个机制.

  1. 把原始的数据给它,它提供了codec.queueInputBuffer 的方法,把数据拷贝到解码器.
  2. 解出数据之后,通过codec.dequeueOutputBuffer 把数据归还给调用者。

WebRTC的代码中是这样做的,使用一个FIFO的队列;在解码的时候,存下当前时间;解出来之后,把队列的头部时间POP出来,做差。保存成解码时间。

Q:这个解码时间是不是准确的解码时间?

不是的。它还包括了从用户态拷贝数据到解码器、解码器拷贝回来的时间。

Q: 用队列算会不会有问题?

有可能有问题。
假如有ABCD几个数据,入队解码,MediaCodec在解B的时候报错,那么外面的队列还是按照原来的方式走,那么就可能存在累积误差,而且误差会累积,越来越大。

Q: 有没有办法修正这个误差?

有的,我觉得应该在入队的时候,做一个标记,标志是什么数据给了解码器。解出来后,看看是不是做了标记的数据,如果是的话,才算解码时间。
解码前: RTP.header.timestamp
解码后:PresentationTimeUs
这两个时间的关系是:
(RTP.header.timestamp/90) = frame.captureTimeNs = PresentationTimeUs/1000
我用这个关系重新校准了解码时间。

相关标签: webrtc