[英]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.