web-dev-qa-db-ja.com

BitmapFactory.decodeByteArray()がNULLを返しています

カメラからpreviewCallbackを使用して、画像を取得しようとしています。これが私が使っているコードです

private Camera.PreviewCallback mPrevCallback = new Camera.PreviewCallback() 
{
        public void onPreviewFrame( byte[] data, Camera Cam ) {
                Log.d("CombineTestActivity", "Preview started");
                Log.d("CombineTestActivity", "Data length = " 
                        + data.length );
                currentprev = BitmapFactory.decodeByteArray( data, 0, 
                        data.length );

               if( currentprev == null )
                   Log.d("CombineTestActivity", "currentprev is null" );

                Log.d("CombineTestActivity", "Preview Finished" );

        }
};

データの長さは常に576000と同じになります。

また、カメラのパラメータを変更して、画像がさまざまな形式で返されるようにしました。これが私がそれをしたときの様子です。

mCamera = Camera.open();
camParam = mCamera.getParameters();
camParam.setPreviewFormat( ImageFormat.RGB_565 );
mCamera.setParameters( camParam );
    mCamera.setPreviewCallback( mPrevCallback );

ただし、プレビュー形式を変更した場合と、デフォルトのNV21のままにしておく場合の両方で、BitmapFactory.decodeByteArrayはnullとして返されます。また、プレビュー形式をJPEGタイプに変更してみました。私はddmsでデバッグステートメントを取得します、これは私が取得するものです

"D/skia(14391):--- SkImageDecoder :: Factoryがnullを返しました"

21
RyoxSinfar

了解しました。これがお役に立てば幸いです。

速い解決策を探してインターネットを精査し、完璧なものを見つけました。

これはAndroid 2.1の時点で機能します

このページ のoff3nsiv3に感謝します。

// Convert to JPG
Size previewSize = camera.getParameters().getPreviewSize(); 
YuvImage yuvimage=new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, baos);
byte[] jdata = baos.toByteArray();

// Convert to Bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);

Off3nsiv3のコードを少し変更するだけで、準備が整います。 FPSは、手動デコードと比較して、依然として信じられないほど高いです。

上記のコードの場合、80はjpeg品質です(100から0、100が最適)。

あなたはこれを試すことができ、それは機能しています...

mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    Camera.Parameters parameters = camera.getParameters();
                    int format = parameters.getPreviewFormat();
                    //YUV formats require more conversion
                    if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) {
                        int w = parameters.getPreviewSize().width;
                        int h = parameters.getPreviewSize().height;
                        // Get the YuV image
                        YuvImage yuv_image = new YuvImage(data, format, w, h, null);
                        // Convert YuV to Jpeg
                        Rect rect = new Rect(0, 0, w, h);
                        ByteArrayOutputStream output_stream = new ByteArrayOutputStream();
                        yuv_image.compressToJpeg(rect, 100, output_stream);
                        byte[] byt = output_stream.toByteArray();
                        FileOutputStream outStream = null;
                        try {
                            // Write to SD Card
                            File file = createFileInSDCard(FOLDER_PATH, "Image_"+System.currentTimeMillis()+".jpg");
                            //Uri uriSavedImage = Uri.fromFile(file);
                            outStream = new FileOutputStream(file);
                            outStream.write(byt);
                            outStream.close();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                        }
                    }
                }
7
ROHIT PARMAR

私は同じことをしようとしています。 ここここ の議論に基づくと、Android 2.1/2.2の時点で、decodeByteArray()がNV21形式を処理できるようになる運がなかったようです。エミュレーターやDroidIncredibleでは絶対に機能しませんが、これはネイティブコードを呼び出すため、ドライバーによっては一部の電話で機能する可能性がありますか?

別の方法として、JavaでNV21を自分でデコードしてみることができます(例については上記のリンクを参照)。ただし、これは明らかに遅すぎてほとんどの場合に役立ちません。 CameraPreviewに別の形式を送信させようとしても、あまり運がなかったので、別のハードウェア間で移植可能なコードを書き込もうとすると、これが問題になると思います。 NDKでNV21デコードメソッドを作成した場合、フレームレートが少し上がる可能性があります。

この問題を自分で確認していませんが、CameraPreviewを処理しようとすると、競合状態による安定性の問題もあるようです。 Android 2.1/2.2で追加されたバッファ付きプレビューコールバックメソッドsetPreviewCallbackWithBuffer()を使用して、これを回避し、フレームレートを少し上げることもできると思います。これは2.1で追加されましたが、2.2まで非表示のままでした。 2.1で使用するには、非表示をハックする必要があります。

MediaRecorderの代わりにCameraPreviewを使用することを提案する人もいます。残念ながら、MediaRecorderCameraPreviewよりもプレビューフレームを取得するために提供されているものがさらに少ないようであるため、そのルートをお勧めすることはできません。

3
Chinasaur

これは私のために働いています...

 private Camera.PreviewCallback getPreviewCallback() {
    Log.d("TAG", "previewCallBack ==> " + "getPreviewCallback");
    Camera.PreviewCallback previewBitmap = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            YuvImage yuvimage=new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, baos);
            byte[] jdata = baos.toByteArray();
            // Convert to Bitmap
            Bitmap bitmap = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
            Log.d("TAG", "BITMAP ==> " + bitmap);
            runModelInference(bitmap);
        }
    };

    return previewBitmap;
}
2
NagarjunaReddy

以前の回答から更新しますが、Qixの回答に注意してください。これはより単純に見えます

私は実際、純粋なJavaでのデコードでまともな結果を得ました。プレビューサイズが大きすぎない限り、フレームレートは約10〜15fpsです。悲しいことに、Android 2.3アップデートでDroidIncを使用すると、プレビューサイズの小さいオプションの一部が削除されたようです:(。別のプロジェクトから取得したネイティブコードでも試してみましたが、これはバグがあり、私が行っていた比較的単純な処理では高速に見えなかったので、それ以上追求しませんでした。ソースについては my Github を参照してください(両方Java =およびネイティブ)。

1
Chinasaur