2017-09-22 6 views
0

私はAndroidのCamera2 APIを使用しており、カメラのプレビューフレームで画像処理をいくつか行い、その変更をプレビュー(TextureView)に表示したいと考えています。Androidビデオ処理 - ImageReaderサーフェスをプレビューに接続するにはどうすればいいですか?

私はopenCamera()に共通のcamera2videoの例から、ImageReaderをセットアップしました。

mImageReader = ImageReader.newInstance(mVideoSize.getWidth(), 
    mVideoSize.getHeight(), ImageFormat.YUV_420_888, mMaxBufferedImages); 
    mImageReader.setOnImageAvailableListener(mImageAvailable, mBackgroundHandler); 

私のstartPreview()では、CaptureRequestからフレームを受け取るようにサーフェスを設定しました。

SurfaceTexture texture = mTextureView.getSurfaceTexture(); 
    assert texture != null; 
    texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 
    mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 

    List<Surface> surfaces = new ArrayList<>(); 

    // Here is where we connect the mPreviewSurface to the mTextureView. 
    mPreviewSurface = new Surface(texture); 
    surfaces.add(mPreviewSurface); 
    mPreviewBuilder.addTarget(mPreviewSurface); 

    // Connect our Image Reader to the Camera to get the preview frames. 
    Surface readerSurface = mImageReader.getSurface(); 
    surfaces.add(readerSurface); 
    mPreviewBuilder.addTarget(readerSurface); 

それから私はOnImageAvailableListener()コールバックで画像データを修正します。

ImageReader.OnImageAvailableListener mImageAvailable = new ImageReader.OnImageAvailableListener() { 
    @Override 
    public void onImageAvailable(ImageReader reader) { 
     try { 
      Image image = reader.acquireLatestImage(); 
      if (image == null) 
       return; 

      final Image.Plane[] planes = image.getPlanes(); 

      // Do something to the pixels. 
      // Black out part of the image. 
      ByteBuffer y_data_buffer = planes[0].getBuffer(); 
      byte[] y_data = new byte[y_data_buffer.remaining()]; 
      y_data_buffer.get(y_data); 
      byte y_value; 
      for (int row = 0; row < image.getHeight()/2; row++) { 
       for (int col = 0; col < image.getWidth()/2; col++) { 
        y_value = y_data[row * image.getWidth() + col]; 
        y_value = 0; 
        y_data[row * image.getWidth() + col] = y_value; 
       } 
      } 

      image.close(); 
     } catch (IllegalStateException e) { 
      Log.d(TAG, "mImageAvailable() Too many images acquired"); 
     } 
    } 
}; 

私は今それを理解として、私は、2面の場合、私のImageReaderのためmTextureViewおよびその他のための1つに画像を送信しています。

mTextureViewにImageReaderと同じSurfaceを使用させるにはどうすればよいですか、またはmTextureViewのSurfaceから直接画像データを操作する必要がありますか?

おかげ

答えて

1

あなただけ変更された出力を表示したい場合は、設定された2つの出力(TextureViewとするImageReader)を持っている理由は、私はわかりません。一般

、あなたがしたい場合は、ようにしたいの編集、およびコーディング、パフォーマンスのしやすさとの間に様々なトレードオフ、との種類に応じて、いくつかのオプションを持っている

camera -> in-app edits -> display 

ような何か。

最も効率的なオプションの1つは、OpenGLシェーダとして編集を行うことです。 その場合、GLSurfaceViewはおそらく最も簡単なオプションです。 GLSurfaceViewのEGLコンテキストで使用されていないテクスチャIDを持つSurfaceTextureオブジェクトを作成し、SurfaceTextureから作成されたSurfaceをカメラセッションおよび要求に渡します。 次に、SurfaceView描画メソッドでSurfaceTextureのupdateTexImage()メソッドを呼び出し、テクスチャIDを使用して出力をレンダリングします。

OpenGLコードが大量に必要なので、使い慣れていないと難しいかもしれません。

RenderScriptを使用しても同様の効果が得られます。 SurfaceViewまたはTextureViewの出力があり、Cameraからの入力の割り当てを読み込み、Viewへの出力の割り当てに書き込むRenderScriptスクリプトがあります。そのような割り当てをサーフェスから作成することができます。 Google HdrViewfinderDemo camera2サンプルアプリではこのアプローチを使用しています。それははるかに少ない定型文です。

第3に、今行っているようにImageReaderを使用することはできますが、画面に書き込むには多くの変換を自分で行う必要があります。最も単純な(しかし最も遅い)オプションは、SurfaceViewまたはImageViewからCanvasを取得し、それにピクセルを1つずつ書き込むことです。または、より高速ですが、JNIコードを書く必要がありますが、YUV-> RGB変換を自分で行う必要があります(または、文書化されていないAPIを使用してYUVをANativeWindowにプッシュしてうまく動作するようにする必要があります)。ANativeWindow NDK。

+0

したがって、私がANativeWindow NDKルートを使用すると、TextureViewにRGB形式が必要なため、YUV-> RGBの理由がありますか? – jimbo

+0

さて、NDKは現在のところ、RGB画像フォーマットのみを選択できるようになっています:https://developer.android.com/ndk/reference/hardware__buffer_8h.html#a06fc87d81c62e9abb8790b6e5713c55ba521c192d1f9b5e85aa68b86ead204fbe –

関連する問題