2013-04-01 62 views
6

Bằng cách giới thiệu của Aegonis work 1work 2, tôi cũng có luồng H.264, nhưng màu sắc không chính xác. Tôi đang sử dụng HTC Butterfly để phát triển. Dưới đây là một phần của mã của tôi:Mediacodec và máy ảnh, không gian màu không chính xác

Camera:

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

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(); 

Khi sử dụng COLOR_FormatYUV420Planar các chương trình báo lỗi "[OMX.qcom.video.encoder.avc] làm không hỗ trợ định dạng màu 19, "vì vậy tôi chỉ có thể sử dụng" COLOR_FormatYUV420SemiPlanar ". Có ai biết lý do tại sao không hỗ trợ?

Got nó, bằng cách sử dụng:

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);   
    } 

chúng ta có thể định dạng màu (COLOR_FormatYUV420SemiPlanar) và (không có định dạng tương ứng), tôi nghĩ rằng định dạng sẽ thay đổi phụ thuộc vào thiết bị.

Sau đó, tôi đã thử màu biến đổi được cung cấp từ những gợi ý trong work 1work 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; 
} 

Rõ ràng, màu sắc biến đổi của YV12toYUV420PackedSemiPlanar thực hiện tốt hơn so với hai người kia. Nó tương đối tốt hơn nhưng vẫn trông khác so với màu thực. Có gì sai với mã của tôi không? Mọi bình luận sẽ được đánh giá cao.

+1

+1 để viết các câu hỏi theo cách như vậy. –

+0

"khác" giống như các kênh chroma bị lạc hậu, hoặc "khác" giống như mọi thứ được tinh tế? (Nếu bạn sắp xếp lại 'YV12toYUV420PackedSemiPlanar' để hoán đổi các kênh Cb/Cr, có đúng không?) – fadden

+0

Tôi đã cố gắng hoán đổi Cb/Cr và màu không chính xác. Tôi cũng thử chỉ hiển thị màu của Y và có vẻ như video được đặt trên mặt nạ màu xanh lá cây, đó không phải là những gì tôi mong đợi. Tôi thực sự không thể tìm ra những gì đang xảy ra. – Albert

Trả lời

3

OK, bây giờ màu có vẻ tốt, thử nghiệm dựa trên HTC Butterfly. Khi thiết lập độ phân giải 320x240, màu sắc của bạn chuyển đổi nên trông giống như:

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]);    
    } 

cho độ phân giải 640x480 trở lên,

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]); 
    } 

Đối với vấn đề tỷ lệ khung hình, chúng ta có thể sử dụng getSupportedPreviewFpsRange() để kiểm tra phạm vi tốc độ khung hình được hỗ trợ của thiết bị của chúng tôi là:

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

Và cài đặt sau hoạt động chính xác khi phát mã hóa H.264 ES,

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

Cảm ơn câu trả lời của bạn, Albert. Nghiên cứu tuyệt vời. Tôi tự hỏi tại sao có -352 byte đệm khi viết các thành phần U và V cho độ phân giải 320x240? Tôi nên sử dụng padding nào cho độ phân giải 960x720? –

+0

Câu hỏi liên quan: http://stackoverflow.com/questions/17493169/getting-qualcomm-encoders-to-work-via-mediacodec-api/19883163 Dường như khi gửi khung đến bộ mã hóa, thành phần Y phải được căn chỉnh theo một số byte cho các độ phân giải nhất định. –

2

Sau khi đọc this discussion nó chỉ ra rằng cách tổng quát hơn để mã hóa khung các nghị quyết khác nhau là để sắp xếp máy bay chroma bởi 2048 byte trước khi gửi khung cho MediaCodec. Điều này là thực tế cho QualComm (OMX.qcom.video.encoder.avc) bộ mã hóa mà tôi tin rằng HTC Butterfly có, nhưng vẫn không hoạt động tốt cho tất cả các độ phân giải. 720x480176x144 vẫn có mặt phẳng chroma lệch theo video đầu ra. Ngoài ra, tránh các độ phân giải mà kích thước không thể chia cho 16.

Việc chuyển đổi là khá đơn giản:

int padding = 0; 
if (mediaCodecInfo.getName().contains("OMX.qcom")) { 
    padding = (width * height) % 2048; 
} 
byte[] inputFrameBuffer = new byte[frame.length]; 
byte[] inputFrameBufferWithPadding = new byte[padding + frame.length]; 

ColorHelper.NV21toNV12(frame, inputFrameBuffer, width, height); 
# copy Y plane 
System.arraycopy(inputFrameBuffer, 0, inputFrameBufferWithPadding, 0, inputFrameBuffer.length); 
int offset = width * height; 
# copy U and V planes aligned by <padding> boundary 
System.arraycopy(inputFrameBuffer, offset, inputFrameBufferWithPadding, offset + padding, inputFrameBuffer.length - offset); 
+0

(xem bài đăng của Andrey http://stackoverflow.com/questions/20699009/) – fadden