2013-02-28 3 views
7

私はこの質問をたくさん検索しようとしましたが、満足のいく答えは見たことがないので、ここで最後の希望があります。onPreviewFrameコールバックによってキャプチャされたバイト[]フレームの向きを変更するにはどうすればよいですか?

私はonPreviewFrameコールバックを設定しました。これにより、サポートされているプレビュー形式(NV21H.264エンコードタイプ)の生フレームのbyte[]が得られます。

ここで問題は、デバイスが回転するたびにキャプチャされたbyte[]フレームに反映されない場合は常に、byte[]フレームの固定方向からのコールバックを開始することです。私はsetDisplayOrientationsetRotationで試しましたが、これらのAPIはキャプチャされたbyte []フレームには全く表示されていないプレビューに反映されています。

Androidのドキュメントも、フレームバイトではない、Camera.setDisplayOrientationのみ表示するプレビューに影響を与え、こう述べています。

これは、onPreviewFrameに渡されたバイト配列(バイト[]、カメラ)の順に影響を与えるJPEG画像、または記録されていませんビデオ。

最後に、どのAPIレベルでも、byte[]フレームの向きを変更する方法はありますか?

答えて

3

フォーマットを気にしない場合は、YuvImageクラスを使用してJPEGバッファを取得してください。このバッファを使用してBitmapを作成し、対応する角度に回転してください。そのような何か:私は移調取ると、撮影したフレームのサイズを変更するには、このOpen Source Android Touch-To-Record libraryのonPreviewFrame方法を変更した

@Override 
public void onPreviewFrame(byte[] data, Camera camera) { 

    Size previewSize = camera.getParameters().getPreviewSize(); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    byte[] rawImage = null; 

    // Decode image from the retrieved buffer to JPEG 
    YuvImage yuv = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null); 
    yuv.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), YOUR_JPEG_COMPRESSION, baos); 
    rawImage = baos.toByteArray(); 

    // This is the same image as the preview but in JPEG and not rotated 
    Bitmap bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length); 
    ByteArrayOutputStream rotatedStream = new ByteArrayOutputStream(); 

    // Rotate the Bitmap 
    Matrix matrix = new Matrix(); 
    matrix.postRotate(YOUR_DEFAULT_ROTATION); 

    // We rotate the same Bitmap 
    bitmap = Bitmap.createBitmap(bitmap, 0, 0, previewSize.width, previewSize.height, matrix, false); 

    // We dump the rotated Bitmap to the stream 
    bitmap.compress(CompressFormat.JPEG, YOUR_JPEG_COMPRESSION, rotatedStream); 

    rawImage = rotatedStream.toByteArray(); 

    // Do something we this byte array 
} 
+0

解像度を下げる – cxphong

1

setCameraParams()メソッドでは、「yuvIplImage」を次のように定義しました。

IplImage yuvIplImage = IplImage.create(mPreviewSize.height, mPreviewSize.width, opencv_core.IPL_DEPTH_8U, 2); 

これは私のonPreviewFrame()メソッドです、私は基本的にこの方法を解決するために使用され、このlink

見つかり

@Override 
public void onPreviewFrame(byte[] data, Camera camera) 
{ 

    long frameTimeStamp = 0L; 

    if(FragmentCamera.mAudioTimestamp == 0L && FragmentCamera.firstTime > 0L) 
    { 
     frameTimeStamp = 1000L * (System.currentTimeMillis() - FragmentCamera.firstTime); 
    } 
    else if(FragmentCamera.mLastAudioTimestamp == FragmentCamera.mAudioTimestamp) 
    { 
     frameTimeStamp = FragmentCamera.mAudioTimestamp + FragmentCamera.frameTime; 
    } 
    else 
    { 
     long l2 = (System.nanoTime() - FragmentCamera.mAudioTimeRecorded)/1000L; 
     frameTimeStamp = l2 + FragmentCamera.mAudioTimestamp; 
     FragmentCamera.mLastAudioTimestamp = FragmentCamera.mAudioTimestamp; 
    } 

    synchronized(FragmentCamera.mVideoRecordLock) 
    { 
     if(FragmentCamera.recording && FragmentCamera.rec && lastSavedframe != null && lastSavedframe.getFrameBytesData() != null && yuvIplImage != null) 
     { 
      FragmentCamera.mVideoTimestamp += FragmentCamera.frameTime; 

      if(lastSavedframe.getTimeStamp() > FragmentCamera.mVideoTimestamp) 
      { 
       FragmentCamera.mVideoTimestamp = lastSavedframe.getTimeStamp(); 
      } 

      try 
      { 
       yuvIplImage.getByteBuffer().put(lastSavedframe.getFrameBytesData()); 

       IplImage bgrImage = IplImage.create(mPreviewSize.width, mPreviewSize.height, opencv_core.IPL_DEPTH_8U, 4);// In my case, mPreviewSize.width = 1280 and mPreviewSize.height = 720 
       IplImage transposed = IplImage.create(mPreviewSize.height, mPreviewSize.width, yuvIplImage.depth(), 4); 
       IplImage squared = IplImage.create(mPreviewSize.height, mPreviewSize.height, yuvIplImage.depth(), 4); 

       int[] _temp = new int[mPreviewSize.width * mPreviewSize.height]; 

       Util.YUV_NV21_TO_BGR(_temp, data, mPreviewSize.width, mPreviewSize.height); 

       bgrImage.getIntBuffer().put(_temp); 

       opencv_core.cvTranspose(bgrImage, transposed); 
       opencv_core.cvFlip(transposed, transposed, 1); 

       opencv_core.cvSetImageROI(transposed, opencv_core.cvRect(0, 0, mPreviewSize.height, mPreviewSize.height)); 
       opencv_core.cvCopy(transposed, squared, null); 
       opencv_core.cvResetImageROI(transposed); 

       videoRecorder.setTimestamp(lastSavedframe.getTimeStamp()); 
       videoRecorder.record(squared); 
      } 
      catch(com.googlecode.javacv.FrameRecorder.Exception e) 
      { 
       e.printStackTrace(); 
      } 
     } 

     lastSavedframe = new SavedFrames(data, frameTimeStamp); 
    } 
} 

このコードは、メソッドを使用しています "YUV_NV21_TO_BGR"、私は「Androidの緑の悪魔の問題」と呼んでいます。あなたは他のSOスレッドで同じ問題に直面している他のアンドロイド開発者を見ることができます。 YUV_NV21_TO_BGRメソッドを追加する前に、YuvIplImageの転置、より重要な転置、反転(サイズ変更の有無にかかわらず)の組み合わせにより、結果として得られるビデオには緑色の出力がありました。この "YUV_NV21_TO_BGR"メソッドはその日を保存しました。上記のGoogleグループのスレッドの@David Hanに感謝します。

また、onPreviewFrameのすべての処理(トランスポーズ、フリップ、リサイズ)には時間がかかり、フレーム/秒(FPS)レートで非常に重大なヒットを引き起こすことにご注意ください。このコードを使用すると、onPreviewFrameメソッドの中で、結果として記録されたビデオのFPSは30fpsから3フレーム/秒に低下しました。

このアプローチを使用しないことをお勧めします。代わりに、AsyncTaskでJavaCVを使用してビデオファイルのポストレコーディング処理(トランスポーズ、反転、サイズ変更)を行うことができます。お役に立てれば。

関連する問題