我正在使用上面的代码对/ decode / mux进行编码,以便制作分辨率和比特率较低的视频。 它的所有分辨率都非常好,包括nexus5上的4k视频,LG g3,一个加号。
但三星设备显示不当行为。
如果我将4k视频(3840x2160)作为输入并希望将其分辨率降低到1920x1080,我会得到例外。
如果我将4k视频(3840x2160)作为输入并希望将其分辨率降低到1280x720,我仍然会遇到异常。
如果我将目标分辨率设置为640x360,则效果非常好。
我认为这可能与三星设备上的编解码器问题有关。
以下是代码段
MediaCodec encoder = MediaCodec.createByCodecName(codecInfo.getName());
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
surfaceReference.set(encoder.createInputSurface());
encoder.start();
MediaCodec decoder = MediaCodec.createDecoderByType(getMimeTypeFor(inputFormat));
decoder.configure(inputFormat, surface, null, 0);
decoder.start();
以下语句导致异常
decoder.configure(inputFormat, surface, null, 0);
以下是堆栈跟踪
I/ACodec: [OMX.Exynos.AVC.Encoder] Now Executing
03-15 14:35:23.801 25357-26008/com.test I/ACodec: [] Now uninitialized
03-15 14:35:23.801 25357-26036/com.test I/OMXClient: Using client-side OMX mux.
03-15 14:35:23.811 25357-26036/com.test I/ACodec: can't find wfdsink-exynos-enable
03-15 14:35:23.811 25357-26036/com.test E/ACodec: configureCodec multi window instance fail appPid : 25357
03-15 14:35:23.811 25357-26036/com.test E/ACodec: [OMX.Exynos.avc.dec] configureCodec returning error -1021
03-15 14:35:23.811 25357-26036/com.test E/ACodec: signalError(omxError 0x80001001, internalError -1021)
03-15 14:35:23.811 25357-26035/com.test E/MediaCodec: Codec reported err 0xfffffc03, actionCode 0, while in state 3
03-15 14:35:23.811 25357-26008/com.test E/MediaCodec: configure failed with err 0xfffffc03, resetting...
03-15 14:35:23.811 25357-26036/com.test I/ACodec: [OMX.Exynos.avc.dec] Now uninitialized
03-15 14:35:23.811 25357-26008/com.test I/ACodec: [] Now uninitialized
03-15 14:35:23.811 25357-26036/com.test I/OMXClient: Using client-side OMX mux.
答案 0 :(得分:3)
基本上,似乎有些三星设备可能只是Exynos解码器有问题。我收到了你看到的几乎相同的错误信息。解决方案很复杂,但似乎解决了这个问题。
我替换了这两行代码:
decoder = MediaCodec.createDecoderByType(mime);
decoder.configure(format, surface, null, 0);
使用这种方法:
private MediaCodec configDecoder(MediaFormat format, Surface surface) {
if (format == null || surface == null) {
return null;
}
MediaCodec codec;
String mime = format.getString(MediaFormat.KEY_MIME);
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
MediaCodecInfo[] infos = list.getCodecInfos();
for (MediaCodecInfo info : infos) {
CodecCapabilities capabilities;
boolean formatSupported;
// does codec support this mime type
try {
capabilities = info.getCapabilitiesForType(mime);
} catch (IllegalArgumentException ignored) {
continue;
}
// does codec support his video format
try {
formatSupported = capabilities.isFormatSupported(format);
} catch (IllegalArgumentException ignored) {
continue;
}
// can we configure it successfully
if (formatSupported) {
// try decoder
try {
codec = MediaCodec.createByCodecName(info.getName());
} catch (IOException e) {
continue;
}
try {
codec.configure(format, surface, null, 0);
} catch (IllegalArgumentException ignored) {
// configure() failed
codec.release();
continue;
} catch (IllegalStateException ignored) {
// configure() failed
codec.release();
continue;
}
// configure() successful
return codec;
}
} // end of for loop
// no decoder found
return null;
}
通常,要获得编解码器,只需调用
即可MediaCodec.createDecoderByType(mimeType)
或
MediaCodecList.findDecoderForFormat(format)
但这只给你一个选择。使用上面的方法,您可以更好地控制您使用的编解码器。例如,您可以通过添加
轻松过滤掉所有 Exynos 编解码器if (!info.getName().contains("Exynos"))
或类似的东西。
无论如何,希望这有助于将来的其他人。这让我很沮丧几天。
作为最后一点,我的旧设备与旧代码配合得很好,新代码使用了一些棒棒糖和更高级的方法,所以我的最终解决方案看起来像这样:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
decoder = configDecoder(format, surface);
} else {
decoder = MediaCodec.createDecoderByType(mime);
decoder.configure(format, surface, null, 0);
}
看着代码运行,它仍然在很多时候使用Exynos,但是当configure()由于某种原因失败时,很高兴看到它无法移动到下一个编解码器。