2013-04-01 2 views
6

Отсылаю Aegonis's work 1 и work 2, у меня также есть поток H.264, но цвет неправильный. Я использую HTC Butterfly для разработки. Вот часть моего кода:Mediacodec и фотоаппарат, неправильное цветовое пространство

камеры:

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

При использовании 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);   
    } 

мы можем иметь цвет формат (COLOR_FormatYUV420SemiPlanar) и (не соответствующий формат), я думаю, что формат будет меняться в зависимости от устройства.

Затем я попробовал преобразования цвета при условии, из предложений в work 1 и 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 работает лучше, чем два других. Это относительно лучше, но по-прежнему выглядит по-другому по сравнению с реальным цветом. Что-то не так с моим кодом? Любой комментарий будет оценен.

+1

+1 для написания вопрос таким образом. –

+0

«разные», как каналы цветности, отстают, или «разные», как вещи, тонко отключены? (Если вы переставляете 'YV12toYUV420PackedSemiPlanar' для обмена каналами Cb/Cr, выглядит ли оно правильно?) – fadden

+0

Я попытался поменять Cb/Cr и неправильный цвет. Я также пытаюсь просто показать цвет Y, и кажется, что видео было помещено в зеленую маску, это не то, что я ожидаю. Я действительно не могу понять, что происходит. – Albert

ответ

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

для разрешения 640х480 и выше,

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

Для выдачи частоты кадров, мы можем использовать getSupportedPreviewFpsRange(), чтобы проверить поддерживаемый диапазон частоты кадров нашего устройства, как:

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

А следующий параметр работает правильно, когда играют закодированную H.264 ES,

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

Спасибо за ваш ответ, Альберт. Отличные исследования. Мне интересно, почему есть заполнение -352 байта при записи U и V-компонентов для разрешения 320x240? И какое дополнение следует использовать для разрешения 960x720? –

+0

Связанный вопрос: http://stackoverflow.com/questions/17493169/getting-qualcomm-encoders-to-work-via-mediacodec-api/19883163 Кажется, что при отправке кадра в кодировщик Y компонент должен быть выровнен по некоторому числу байтов для определенных разрешений. –

2

После прочтения this discussion получается, что более обобщенный способ для кодирования кадров различных резолюций для выравнивания плоскости цветности до 2048 байт перед отправкой кадра в MediaCodec. Это актуально для кодировщика QualComm (OMX.qcom.video.encoder.avc), который, я считаю, HTC Butterfly имеет, но все еще не работает хорошо для всех разрешений. 720x480 и 176x144 по-прежнему имеют плоскость цветности, несогласованную согласно выходному видео. Также избегайте разрешений, размеры которых нельзя разделить на 16.

Преобразование довольно прост:

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

(см. Сообщение Андрея http://stackoverflow.com/questions/20699009/) – fadden

Смежные вопросы