Android 媒体编解码器非常依赖设备供应商。三星存在令人难以置信的问题,其他运行相同代码的设备也能正常运行。这就是我过去 6 个月的生活。
尽管感觉不对,但最好的方法是尝试 + 捕获 + 重试。 MediaCodec 将在 4 个不同的地方引发异常:
- 配置 - NativeDecoder.Configure(...);
- 开始 - NativeDecoder.Start();
- 渲染输出 - NativeDecoder.ReleaseOutputBuffer(...);
- 输入 - codec.QueueInputBuffer(...);
注意:我的代码在 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 并且实际上在此过程中破坏了很多功能。