我正在使用MediaCodec
API来解码H264视频流,使用SurfaceView
作为输出曲面。解码器配置成功,没有任何错误。当我尝试使用SurfaceView
最终将解码的视频帧渲染到releaseOutputBuffer(bufferIndex, true)
时,它会抛出MediaCodec.CodecException
,但视频会正确呈现。
在异常对象上调用getDiagnosticInfo()
和getErrorCode()
会返回错误代码-34,但我无法在文档中找到此错误代码的含义。关于何时抛出此异常,文档也非常不清楚。
之前是否有人遇到此异常/错误代码?我该如何解决这个问题?
PS:虽然视频效果很好,但每次releaseOutputBuffer(bufferIndex, true),
电话都会抛出此异常。
答案 0 :(得分:0)
Android media-codec非常依赖于设备供应商。三星是一个令人难以置信的问题,运行相同代码的其他设备运行正常。这是我过去6个月的生活。
尽管可能感觉不对,最好的方法是尝试+ catch +重试。 MediaCodec将有4个不同的地方会抛出异常:
注意:我的代码在Xamarin中,但调用与原始java非常接近。
配置格式描述的方式也很重要。如果您未指定:
,则媒体编解码器可能会在NEXUS设备上崩溃formatDescription.SetInteger(MediaFormat.KeyMaxInputSize, currentPalette.Width * currentPalette.Height);
当您发现任何异常时,您需要确保重置mediacodec。不幸的重置不适用于较旧的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,对视频来说是最稳定的。即使在屏幕上同时有多达21个并发视频。三星S4可以在4-6左右取决于分辨率/ fps,但像HTC这样的东西可以和Hudl一样工作。这是一个警醒,让我意识到三星设备实际上是在复制苹果设计和使用android-sdk,实际上在整个过程中打破了很多功能。
答案 1 :(得分:-1)
这很可能是您正在使用的编解码器的问题。尝试使用这样的东西
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());
这可以通过确保完全支持您选择的编解码器来解决您的错误。