Mediacodec和相机,色彩空间不正确

Alb*_*ert 6 android colors h.264

通过参考Aegonis的工作1工作2,我也得到了H.264流,但颜色不正确.我正在使用HTC Butterfly进行开发.这是我的代码的一部分:

相机:

parameters.setPreviewSize(width, height);
parameters.setPreviewFormat(ImageFormat.YV12);
parameters.setPreviewFrameRate(frameRate);
Run Code Online (Sandbox Code Playgroud)

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();   
Run Code Online (Sandbox Code Playgroud)

使用COLOR_FormatYUV420Planar时,错误显示"[OMX.qcom.video.encoder.avc]不支持颜色格式19",因此我只能使用" COLOR_FormatYUV420SemiPlanar ".有谁知道为什么没有支持?

通过使用得到它:

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);           
    }
Run Code Online (Sandbox Code Playgroud)

我们可以有21种颜色格式(COLOR_FormatYUV420SemiPlanar)和2130708361(没有相应的格式),我认为格式会改变取决于设备.

然后,我尝试了工作1工作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;
}
Run Code Online (Sandbox Code Playgroud)

显然,YV12toYUV420PackedSemiPlanar的颜色变换比其他两个更好.它相对更好,但与真实颜色相比仍然看起来不同.我的代码有问题吗?任何评论将不胜感激.

Alb*_*ert 3

明白了,现在颜色看起来不错,测试基于 HTC Butterfly。当将分辨率设置为 320x240 时,您的颜色变换应如下所示:

    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]);            
    }
Run Code Online (Sandbox Code Playgroud)

对于分辨率 640x480 及以上,

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]);   
    } 
Run Code Online (Sandbox Code Playgroud)

对于帧率问题,我们可以使用 getSupportedPreviewFpsRange() 来检查我们的设备支持的帧率范围:

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

当播放编码的 H.264 ES 时,以下设置工作正常,

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