【发布时间】:2019-12-31 12:32:51
【问题描述】:
我目前正在为 H264 视频流编写解码器。 目标平台是 Android,所以我使用 MediaCodec API (Android OS >= 6.0)。
我已经在 4 台设备上测试了我的代码(所有 4 台设备相同):
- 在小米红米 5 Plus 上运行良好(实际上速度很快)。
- 在 Nexus 7 和三星 Galaxy Tab A 上运行缓慢
- 在三星 Galaxy Tab S2 上失败,出现神秘错误代码 -10000
AMediaCodec_dequeueOutputBuffer(configure和start返回正确的值 (AMEDIA_OK))。
所以我的问题是:
- 我能以某种方式对其进行优化吗?我测试了每个 MediaCodec API 调用的时间性能,看起来
AMediaCodec_dequeueOutputBuffer在这里是一个巨大的瓶颈(每帧 80%-90% 的时间)。 - 对于 Galaxy Tab 2 上的这个 -10000 错误,我能做些什么吗?
我阅读了 MediaCodecs 文档,但那里没有描述。我只在 VLC 的源代码 (modules/codec/omxil/mediacodec_ndk.c) 中找到了
const AMEDIA_ERROR_UNKNOWN = -10000(问题 2.b:他们在哪里找到了这个常量?)。
设备规范(来自 /etc/media_codecs.xml 的解码器):
小米红米5 Plus: 安卓 7.1.2 “video/avc”解码器:OMX.qcom.video.decoder.avc、OMX.qcom.video.decoder.avc.secure
Nexus 7(平板电脑) 安卓 6.0.1 “video/avc”编解码器:OMX.qcom.video.decoder.avc、OMX.qcom.video.decoder.avc.secure
三星标签 A
安卓 7.1.1 “video/avc”解码器:OMX.qcom.video.decoder.avc、OMX.qcom.video.decoder.avc.secure、OMX.SEC.avc.sw.dec三星 Tab S2:
安卓7.0 “视频/avc”解码器:OMX.Exynos.avc.dec、OMX.Exynos.avc.dec.secure、OMX.SEC.avc.sw.dec
我可以看到所有执行正常(即使速度很慢)的设备都具有共同的高通解码器。
我的代码:
//initialization (I omitted checks for errors, all initialization is executed without any errors.:
//f contains pointers to functions from libmediandk.so
const char mime[] = "video/avc";
mDecoder = f.createDecoderByType(mime);
AMediaFormat* mFormat = f.createMediaFormat();
const int colorFormat = 19; //COLOR_FormatYUV420Planar
f.setString(mFormat, c.keyMime, mime);
f.setInt32(mFormat, c.keyWidth, width);
f.setInt32(mFormat, c.keyHeight, height);
f.setInt32(mFormat, c.keyColorFormat, colorFormat);
f.setInt32(mFormat, "encoder", 0);
f.setInt32(mFormat, "max-input-size", 0);
//both sps and pps are extracted from the stream
f.setBuffer(mFormat, "csd-0", sps, sizeof(sps));
f.setBuffer(mFormat, "csd-1", pps, sizeof(pps));
media_status_t status = f.configure (mDecoder, mFormat, NULL, NULL, 0);
status = f.start(mDecoder);
f.deleteMediaFormat(mFormat);
lastOutputBufferIdx = -1;
//this is executed every loop
//data -> char* with this frame's H264 encoded data
//I omitted error check for clarity
const int TIMEOUT_US = -1; //-1 -> blocking mode
AMediaCodecBufferInfo info;
char* buf = NULL;
if (lastOutputBufferIdx != -1){
f.releaseOutputBuffer(mDecoder, lastOutputBufferIdx, false);
lastOutputBufferIdx = -1;
}
ssize_t iBufIdx = f.dequeueInputBuffer(mDecoder, TIMEOUT_US);
if (iBufIdx >= 0){
buf = f.getInputBuffer(mDecoder, iBufIdx, &bufsize);
int usedBufSize = 0;
if (buf){
usedBufSize = dataSize;
memcpy(buf, data, usedBufSize);
}
media_status_t res = f.queueInputBuffer(mDecoder, iBufIdx, 0, usedBufSize, getTimestamp(), 0);
}
//here's my nemesis (this line is both bottleneck and -10000 generator):
ssize_t oBufIdx = f.dequeueOutputBuffer(mDecoder, &info, TIMEOUT_US);
//I am not interested in processing any error codes from {-1,-2,-3}
//INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED, INFO_OUTPUT_BUFFERS_CHANGED)
while (oBufIdx == -1 || oBufIdx == -2 || oBufIdx == -3){
oBufIdx = f.dequeueOutputBuffer(mDecoder, &info, TIMEOUT_US);
}
while (oBufIdx >= 0)
{
buf = f.getOutputBuffer(mDecoder, oBufIdx, &bufsize);
AMediaFormat format = f.getOutputFormat(mDecoder);
f.getInt32(format, "width", &width);
f.getInt32(format, "height", &height);
f.deleteMediaFormat(format);
//yuv_ is struct returned by my function
yuv_.data = buf + info.offset;
yuv_.size = bufsize;
yuv_.width = width;
yuv_.height = height;
yuv_.yPlane = yuv_.data + info.offset;
yuv_.uPlane = yuv_.yPlane + height * width;
yuv_.vPlane = yuv_.uPlane + (height * width) / 4;
yuv_.yStride = width;
yuv_.uStride = width / 2;
yuv_.vStride = width / 2;
}
lastOutputBufferIdx = oBufIdx;
我已经看到 MediaCodec 可以在异步模式下运行(可能会快一点),但我不确定是否可以使用它,因为我正在解码实时流视频而不是从硬盘。 我想说的是(可能)没有同时运行解码的选项。
【问题讨论】:
标签: android-ndk video-streaming android-mediacodec decoder video-codecs