2013-04-01 15 views
6

Aegonisのwork 1work 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 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; 
} 

、色はYV12toYUV420PackedSemiPlanarの変換は他の二つよりもパフォーマンスが向上します。それは比較的良いですが、実際の色と比較してまだ異なって見えます。私のコードに何か問題がありますか?すべてのコメントをいただければ幸いです。

+1

+1ように質問を書き込むため。 –

+0

クロマチャンネルのように「異なっている」のは逆で、「違う」ものは微妙に消えていますか? ( 'YV12toYUV420PackedSemiPlanar'を再配置してCb/Crチャンネルを入れ替えると、それは正しく見えますか?) – fadden

+0

Cb/Crを入れ替えようとしましたが、色が正しくありません。私もYの色を表示しようとすると、ビデオが緑のマスクに置かれているように見える、それは私が期待しているものではない。私は本当に何が起こっているのか理解できません。 – Albert

答えて

3

これで、色がよく見え、テストはHTC Butterflyに基づいています。 320×240の解像度を設定すると、あなたの色がどのように見えるべきで変換:解像度640×480以上のため

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

、フレームレートの問題については

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を()を使用することができます私たちのデバイスのサポートフレームレート範囲:エンコードされたH.264 ESを再生するとき

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

そして、以下の設定が正しく動作しますが、

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

あなたの答え、Albertに感謝します。偉大な研究。 320x240解像度のUおよびVコンポーネントを書き込むときに-352バイトのパディングがあるのはなぜですか?そして、960x720の解像度にはどのパッディングを使用しますか? –

+0

関連の質問:http://stackoverflow.com/questions/17493169/getting-qualcomm-encoders-to-work-via-mediacodec-api/19883163エンコーダにフレームを送信するとき、Yコンポーネントはある数特定の解像度のバイト数。 –

2

this discussionを読んだ後には、フレームを符号化するためのより一般的な方法は、様々な解像度の がMediaCodecにフレームを送信する前に、2048のバイトにより彩度平面を整列することであることが判明しました。これはHTC Butterflyが持っていると信じているQualCommOMX.qcom.video.encoder.avc)エンコーダの実際ですが、まだすべての解像度でうまく動作しません。 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

(参照、Andreyの投稿http://stackoverflow.com/questions/20699009/) – fadden

関連する問題