媒体codeC和摄像头,色彩空间不正确不正确、摄像头、色彩、媒体

2023-09-04 13:42:13 作者:罗曼蒂克史

通过参考Aegonis的work 1 和工作2 ,我也得到了H.264视频流,但颜色是不正确的。我使用的HTC蝴蝶的发展。这里是我的code部分:

By referring Aegonis's work 1 and work 2, I also got the H.264 stream , but the color is not correct. I am using HTC Butterfly for development. Here is part of my code:

相机:

parameters.setPreviewSize(width, height);
parameters.setPreviewFormat(ImageFormat.YV12);
parameters.setPreviewFrameRate(frameRate);

媒体codeC:

MediaCodec:

mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 320, 240);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 500000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);   
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
mediaCodec.start();   

在使用 COLOR_FormatYUV420Planar 错误显示[OMX.qcom.video.en coder.avc]不支持彩色格式19,所以我只能用 COLOR_FormatYUV420SemiPlanar 。有谁知道为什么不支持?

When using COLOR_FormatYUV420Planar the error shows "[OMX.qcom.video.encoder.avc] does not support color format 19," so I can only use "COLOR_FormatYUV420SemiPlanar". Does anyone know the reason why no support?

明白了,通过使用:

int colorFormat = 0;
    MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
    for (int i = 0; i < capabilities.colorFormats.length && colorFormat == 0; i++) {
        int format = capabilities.colorFormats[i];
        Log.e(TAG, "Using color format " + format);           
    }

我们可以有颜色格式的 21 (COLOR_FormatYUV420SemiPlanar)和 2130708361 (没有相应的格式),我觉得格式将改变依赖于设备。

we can have color format 21 (COLOR_FormatYUV420SemiPlanar) and 2130708361 (no corresponding format), I think the format will change depends on device.

于是,我尝试的颜色与建议,work 1 和工作2 :

Then, I tried the color transform provided from the suggestions in work 1 and work 2:

public static byte[] YV12toYUV420PackedSemiPlanar(final byte[] input, final byte[] output, final int width, final int height) {
    /* 
     * COLOR_TI_FormatYUV420PackedSemiPlanar is NV12
     * We convert by putting the corresponding U and V bytes together (interleaved).
     */
    final int frameSize = width * height;
    final int qFrameSize = frameSize/4;

    System.arraycopy(input, 0, output, 0, frameSize); // Y

    for (int i = 0; i < qFrameSize; i++) {
        output[frameSize + i*2] = input[frameSize + i + qFrameSize]; // Cb (U)
        output[frameSize + i*2 + 1] = input[frameSize + i]; // Cr (V)
    }
    return output;
}

public static byte[] YV12toYUV420Planar(byte[] input, byte[] output, int width, int height) {
    /* 
     * COLOR_FormatYUV420Planar is I420 which is like YV12, but with U and V reversed.
     * So we just have to reverse U and V.
     */
    final int frameSize = width * height;
    final int qFrameSize = frameSize/4;

    System.arraycopy(input, 0, output, 0, frameSize); // Y
    System.arraycopy(input, frameSize, output, frameSize + qFrameSize, qFrameSize); // Cr (V)
    System.arraycopy(input, frameSize + qFrameSize, output, frameSize, qFrameSize); // Cb (U)

    return output;
}

public static byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
    byte[] i420bytes = new byte[yv12bytes.length];
    for (int i = 0; i < width*height; i++)
        i420bytes[i] = yv12bytes[i];
    for (int i = width*height; i < width*height + (width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i + (width/2*height/2)];
    for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i - (width/2*height/2)];
    return i420bytes;
}

显然,色彩变换的 YV12toYUV420PackedSemiPlanar 执行比其他两种更好。这是比较好,但看起来仍然与真正的颜色比较不同。是不是有什么毛病我code?任何评论将被AP preciated。

Obviously, the color transform of YV12toYUV420PackedSemiPlanar performs better than the other two. It is relatively better but still looks different in comparison with the real color. Is there something wrong with my code? Any comment will be appreciated.

推荐答案

明白了,现在颜色很好看,测试是基于HTC蝴蝶。 当分辨率设置为320×240,你的色彩变换应该是这样的:

Got it, now the color looks good, the test is based on HTC Butterfly. When set the resolution to 320x240, your color transform should looks like:

    System.arraycopy(input, 0, output, 0, frameSize);
    for (int i = 0; i < (qFrameSize); i++) {  
        output[frameSize + i*2] = (input[frameSize + qFrameSize + i - 32 - 320]);  
        output[frameSize + i*2 + 1] = (input[frameSize + i - 32 - 320]);            
    }

为分辨率640×480及以上,

for resolution 640x480 and above,

System.arraycopy(input, 0, output, 0, frameSize);    
    for (int i = 0; i < (qFrameSize); i++) {  
        output[frameSize + i*2] = (input[frameSize + qFrameSize + i]);  
        output[frameSize + i*2 + 1] = (input[frameSize + i]);   
    } 

有关帧速率的问题,我们可以使用getSupported previewFpsRange()来检查我们的设备支持的帧速率范围为:

For the frame rate issue, we can use the getSupportedPreviewFpsRange() to check the supported frame rate range of our device as:

List<int[]> fpsRange = parameters.getSupportedPreviewFpsRange();
for (int[] temp3 : fpsRange) {
System.out.println(Arrays.toString(temp3));}

当播放EN codeD下列选项设置正确的H.264 ES,

And the following setting works correct when play the encoded H.264 ES,

parameters.setPreviewFpsRange(29000, 30000);    
//parameters.setPreviewFpsRange(4000,60000);//this one results fast playback when I use the FRONT CAMERA