2016-08-30 25 views
1

Camera2apiを使用してカメラアプリケーションを構築するために、生の画像を保存しようとする際に小さな問題があります。ImageSaverのDngSaverに渡されたCaptureResultがnullです。camera2 api

私はキャプチャ結果を次のコードビットでメンバーに割り当てます。

@Override 

public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { 
         super.onCaptureCompleted(session, request, result); 


         mCaptureResult = result; 
         Toast.makeText(getApplicationContext(), 
           "Image Captured",Toast.LENGTH_SHORT).show(); 

        } 
       }; 

この場所でデバッグすると、メンバーは割り当てられ、nullではありません。しかし、それはDngCreatorのヌルエラーをImageSaverクラスでスローします。

マイリスナー:

private ImageReader mImageReader; 
private ImageReader.OnImageAvailableListener mOnImageAvailableListener = 
     new ImageReader.OnImageAvailableListener() { 
      @Override 
      public void onImageAvailable(ImageReader imageReader) { 
       mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler, 
         mCaptureResult, mCameraCharacteristics)); 
      } 
     }; 

private ImageReader mRawImageReader; 
private ImageReader.OnImageAvailableListener mOnRawImageAvailableListener = 
     new ImageReader.OnImageAvailableListener() { 
      @Override 
      public void onImageAvailable(ImageReader imageReader) { 
       mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler, 
         mCaptureResult, mCameraCharacteristics)); 
      } 
     }; 

私のイメージセーバークラス:私はDngCreatorを初期化しようとすると、次のようにスタックトレースがあるとき

private ImageSaver(Image image, Handler handler, CaptureResult captureResult, 
         CameraCharacteristics cameraCharacteristics) { 
     mImage = image; 
     mHandler =handler; 
     mCaptureResult = captureResult; 
     mCameraCharacteristics = cameraCharacteristics; 
    } 



    @Override 
    public void run() { 
     int format = mImage.getFormat(); 
     switch(format){ 
      case ImageFormat.JPEG: 
       ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer(); 
       byte[] bytes = new byte[byteBuffer.remaining()]; 
       byteBuffer.get(bytes); 

       FileOutputStream fileOutputStream = null; 
       try { 
        fileOutputStream = new FileOutputStream(mImageFile); 
        fileOutputStream.write(bytes); 
       } 
       catch (IOException e){ 
        e.printStackTrace(); 
       } 
       finally { 
        mImage.close(); 
        if(fileOutputStream != null){ 
         try{ 
          fileOutputStream.close(); 
         } 
         catch (IOException e){ 
          e.printStackTrace(); 
         } 
        } 
        //Message message = mHandler.obtainMessage(); 
        //message.sendToTarget(); 
       } 
       break; 
      case ImageFormat.RAW_SENSOR: 
       DngCreator dngCreator = new DngCreator(mCameraCharacteristics,mCaptureResult); 
       FileOutputStream rawFileOutputStream = null; 
       try { 
        rawFileOutputStream = new FileOutputStream(mRawImageFile); 
        dngCreator.writeImage(rawFileOutputStream, mImage); 
       } 
       catch (IOException e){ 
        e.printStackTrace(); 
       } 
       finally{ 
        mImage.close(); 
        if(rawFileOutputStream != null){ 
         try { 
          rawFileOutputStream.close(); 
         } 
         catch (IOException e){ 
          e.printStackTrace(); 
         } 
        } 
       } 
       break; 
     } 


    } 
} 

は今のところ、それは私にエラーを与えます。

FATAL EXCEPTION: Camera2 Background Thread Process: com.something.something, PID: 5162 java.lang.IllegalArgumentException: Null argument to DngCreator constructor at android.hardware.camera2.DngCreator.<init>(DngCreator.java:89) at com.something.something.ControlCameraActivity$ImageSaver.run(ControlCameraActivity.java:328) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.os.HandlerThread.run(HandlerThread.java:61)

誰かが私はこの問題を解決する助けてくださいことはできますか?あなたが私からの情報をもっと必要としたら、今私に教えてください。ありがとう

答えて

1

最初。 imageReader.acquireNextImage()に電話するとImageオブジェクトに設定し、使用後はImage.closeを実行します。 ImageReaderはガベージコレクタでは本当に危険で、ImageReaderのmaxImagesに数字が少ない場合は、イメージを閉じないのでかなり速く入力します。

第2に、参考文献については、あなたのsavingImageメソッドはどこですか?あなたがそれをサービスや別のクラスに送るのであれば、そのイメージに問題があるかもしれません。

最後に、@Eddyのように、OnImageAvailableの前にonCaptureCompleteが呼び出されないことがあります。あなたはリスナーを作成することができ、

if (mImage != null && mCameraCharacteristics != null && mDngResult != null) { 
//process your dng 
} 

または:

ちょうどアプリで回避するFCのチェックを追加します。だから、あなたはこの約2つのソリューションを持っています。したがって、あなたがonImageAvailable()を受け取ったときに、あなたはカスタムリスト、またはHastableに請願書を入れることができます。

List33にはcaptureResultがあり、CaptureResultを持っていればそれを取得してDNGを処理します(onCaptureCompleteで呼び出されるリスナーをインスタンス化しない場合)。そこでは、リスナーがnullであるかどうかを確認するだけで、そうでない場合は、結果が利用可能になった時点で画像を「処理」するよう呼び出す必要があります。

public class MyResultList { 

    private DngListener mDngListener; 
    private Hashtable<String, CaptureResult> mDngCaptureResults; 

    public int getSize() { 
     return mDngCaptureResults.size(); 
    } 

    public Object getResult() { 
     if (mDngCaptureResults.size() == 0){ 
      mDngListener = new DngListener() { 
       @Override 
       public void onResultAvailable() { 
        //Now result is not null, so you can get the available item 
        YourSavingImage(mDngCaptureResults.get(0)); 
       } 
      } 
      return null; 
     } else { 
      return mDngCaptureResults.get(0); 
     } 
    } 

    public void add(CaptureResult result, String index){ 
     mDngCaptureResults.put(index,result); 
    } 
} 

私はちょうどそのアイデアを作った、あなたのobjetivesのためにそれを変更します。それは非常に単純ですし、あなたが多くの依存関係を持っているなら、それほどうまくいかないかもしれません。とにかくそれがあなたを助けることを願っています!

2

OnImageAvailable()の前にonCaptureCompleted()が発生するという保証はありません。実際、RAW画像バッファはプレビューや結果メタデータの画像処理よりも早く準備ができていることが多いため、onImageAvailable()の後にonCaptureCompleted()が発生する可能性が非常に高いです。

最初にonImageAvailableが発生した場合は、まだキャプチャ結果がありません。

代わりに、イメージとキャプチャ結果の両方が完了するまで待ってからImageSaverを作成してください。 1つのオプションとして、両方のコールバックがそれぞれの出力(結果と画像のキャプチャ)をいくつかの共有場所に保存し、両方がnullでないかどうかを確認します。そうであればImageSaverを呼び出します。その後、最初に実行されるものは問題ではなく、2番目に実行されるものがImageSaverを起動します。

+0

onCaptureCompleted()とonImageAvailable()コールバックを互いに一致させることは可能ですか?特定のCaptureResultにどのイメージが関連しているかを知るには?正確には、私はカスタムAEを書いており、適切なISOとシャッタースピードの値を計算するために、イメージとその統計値を繰り返すプレビュー要求と照合する必要があります。 –

+1

はい。 ImageReaderから取得したImageオブジェクトのタイムスタンプと、CaptureResult(SENSOR_TIMESTAMPフィールド)のタイムスタンプは同じキャプチャで同じです。 –