Frank Bush
Frank Bush

Reputation: 121

The returned color format by selectColorFormat method is not correct

I'm using the selectColorFormat method from bigflake to get supported input color format of encoder of MediaCodec.It works well on some tested devices except Huawei Mate7. The returned color format is COLOR_FormatYUV420Planar.So I configure it as the input format.But when encoding I found the input buffer's capacity is not correct,which should be 3*width*height/2.But it's smaller than that.So when queueInputBuffer called error occured. Then I observed the capabilities.colorFormats list, it has more than ten color formats.But on the normal devices the list has about 2 or 3 color formats.Then I chose the color format to COLOR_FormatYUV420SemiPlanar and it works well on Mate7 too.

So I doubt whether this is a bug of Mate7 version or the bug of selectColorFormat method?

And I find the anwser of FAQ Q5 has :

#20 COLOR_FormatYUV420PackedPlanar (also I420)
#39 COLOR_FormatYUV420PackedSemiPlanar (also NV12)
#0x7f000100 COLOR_TI_FormatYUV420PackedSemiPlanar (also also NV12) 

What's the meaning of also I420 and also NV12?Does it mean the layout is all the same with I420 or NV12?Because I have tested I420 and NV12, but haven't come across these three colors device.

The selectColorFormat method is as belows:

private MediaCodecInfo selectCodec(String mimeType) {
    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(mimeType)) {
                return codecInfo;
            }
        }
    }
    return null;
}

private int selectColorFormat(String mimeType) {
    MediaCodecInfo codecInfo = selectCodec(mimeType);
    int colorFormat = 0;
    MediaCodecInfo.CodecCapabilities capabilities =  codecInfo.getCapabilitiesForType(mimeType);
    for (int i = 0; i < capabilities.colorFormats.length; i++) {

        if (isRecognizedFormat(capabilities.colorFormats[i])) {
            colorFormat = capabilities.colorFormats[i];
            break;
        }
    }

    return colorFormat; 
}

private boolean isRecognizedFormat(int colorFormat) {
    switch (colorFormat) {
    // these are the formats we know how to handle for this test
    case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
    case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
    case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
    case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
    case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
    return true;
    default:
    return false;
    }
}

Upvotes: 0

Views: 1352

Answers (1)

fadden
fadden

Reputation: 52323

All devices running Android 4.3 (API 18) or later support YUV input in I420 or NV12 formats. I can say this with confidence because they are part of the CTS tests that all "official" Android devices must pass.

The color constants returned by the codecs have multiple values that map to either I420 or NV12. You can see in the bigflake sample code how this is handled (e.g. generateFrame() in EncodeDecodeTest).

The input buffer capacity should be equal to or slightly larger than width * height * 3 / 2. If you are encountering buffer overrun exceptions, make sure you are clearing the buffer before copying data into it.

Upvotes: 1

Related Questions