EncodeDecodeMux - 三星设备 - 在S6 Edge和S5

时间:2016-03-15 09:40:54

标签: android samsung-mobile codec mediacodec mediamuxer

参考:https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java

我正在使用上面的代码对/ 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.

1 个答案:

答案 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()由于某种原因失败时,很高兴看到它无法移动到下一个编解码器。