[英]Android MediaCodec releaseOutputBuffer throws MediaCodec.CodecException when decoding H264 video
我正在使用MediaCodec
API 使用SurfaceView
作为输出表面解码 H264 视频流。 解码器配置成功,没有任何错误。 当我尝试最终使用releaseOutputBuffer(bufferIndex, true)
将解码的视频帧渲染到SurfaceView
,它会抛出MediaCodec.CodecException
,但是视频渲染正确。
在异常对象上调用getDiagnosticInfo()
和getErrorCode()
返回 -34 的错误代码,但我在文档中找不到此错误代码的含义。 文档也非常不清楚何时抛出此异常。
有没有人遇到过这个异常/错误代码? 我怎样才能解决这个问题?
PS:虽然视频工作正常,但在每个releaseOutputBuffer(bufferIndex, true),
调用时都会抛出这个异常。
Android 媒体编解码器非常依赖于设备供应商。 三星的问题令人难以置信,其他运行相同代码的设备也能正常运行。 这就是我过去 6 个月的生活。
尽管可能会感觉不对,但最好的方法是尝试 + 捕获 + 重试。 MediaCodec 将在 4 个不同的地方抛出异常:
注意:我的代码在 Xamarin 中,但调用非常接近原始 Java。
您配置格式描述的方式也很重要。 如果您不指定,媒体编解码器可能会在 NEXUS 设备上崩溃:
formatDescription.SetInteger(MediaFormat.KeyMaxInputSize, currentPalette.Width * currentPalette.Height);
当您捕获任何异常时,您需要确保媒体编解码器已重置。 不幸的是,较旧的 api 级别无法使用重置,但您可以使用以下方法模拟相同的效果:
#region Close + Release Native Decoder
void StopAndReleaseNativeDecoder() {
FlushNativeDecoder();
StopNativeDecoder();
ReleaseNativeDecoder();
}
void FlushNativeDecoder() {
if (NativeDecoder != null) {
try {
NativeDecoder.Flush();
} catch {
// ignore
}
}
}
void StopNativeDecoder() {
if (NativeDecoder != null) {
try {
NativeDecoder.Stop();
} catch {
// ignore
}
}
}
void ReleaseNativeDecoder() {
while (NativeDecoder != null) {
try {
NativeDecoder.Release();
} catch {
// ignore
} finally {
NativeDecoder = null;
}
}
}
#endregion
在传递新输入时捕获错误后,您可以检查:
if (!DroidDecoder.IsRunning && streamView != null && streamView.VideoLayer.IsAvailable) {
DroidDecoder.StartDecoder(streamView.VideoLayer.SurfaceTexture);
}
DroidDecoder.DecodeH264FrameBuffer(payload, payloadSize, frameDuration, presentationTime, isKeyFrame);
渲染到纹理视图似乎是目前最稳定的选项。 但是设备碎片化确实在这方面伤害了android。 我们发现更便宜的设备(例如 Tesco Hudl)对于视频来说是最稳定的。 甚至 1 次屏幕上最多可同时显示 21 个视频。 三星 S4 可以达到 4-6 左右,具体取决于分辨率/fps,但像 HTC 这样的东西可以像 Hudl 一样工作。 它敲响了警钟,让我意识到三星设备实际上是在复制苹果设计并使用 android-sdk,实际上在此过程中破坏了许多功能。
这很可能是您使用的编解码器的问题。 尝试使用这样的东西
private static MediaCodecInfo selectCodec(String mime){
int numCodecs = MediaCodecList.getCodecCount();
for(int i = 0; i < numCodecs; i++){
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
if(!codecInfo.isEncoder()){
continue;
}
String[] types = codecInfo.getSupportedTypes();
for(int j = 0; j < types.length; j++){
if(types[j].equalsIgnoreCase(mime)){
return codecInfo;
}
}
}
return null;
}
然后设置您的编码器:
MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
mEncoder = MediaCodec.createCodecByName(codecInfo.getName());
这可以通过确保您选择的编解码器得到完全支持来解决您的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.