Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I can't tell you why you're getting garbled data from some devices and not others, but I can suggest a workaround that seems to be working successfully for my app.</p> <p>Your example code scales the camera's JPEG down to 640x480 before saving it off to the SD card. So I'm guessing you don't require the full-sized camera image.</p> <p>If this assumption is true, you can skip Camera's <code>takePicture()</code> API entirely, and just save a preview frame to SD card. The easiest way to do this is with <code>setOneShotPreviewCallback()</code>:</p> <pre><code>mCamera.setOneShotPreviewCallback( new StillPictureCallback() ); </code></pre> <p>This will invoke once, and hand you back a buffer of data from the camera:</p> <pre><code>private class StillPictureCallback implements Camera.PreviewCallback { @Override public void onPreviewFrame(byte[] data, Camera camera) { mPictureTask = new SaveStillPictureTask(); byte[] myData = null; if ( data != null ) { myData = data.clone(); } mPictureTask.execute(myData); } } </code></pre> <p>The callback invokes a background task to compress the data and save it to the file. The only bit of code I'm leaving out is the part that queries the camera for the preview frame format, width and height via <code>getCameraInfo()</code>. Note also that the Android YUVImage class was introduced with Froyo, so if you need to support earlier versions of Android, you will need to roll your own conversion code (there are examples here on StackOverflow).</p> <pre><code>/** * Background task to compress captured image data and save to JPEG file. * */ private class SaveStillPictureTask extends AsyncTask&lt;byte[], Void, Void&gt; { private static final String TAG="VideoRecorder.SaveStillPictureTask"; @Override protected Void doInBackground(byte[]... params) { byte[] data = params[0]; FileOutputStream out = null; Bitmap bitmap = null; if ( data == null ) { Log.e(TAG, "doInBackground: data is null"); return null; } try { out = new FileOutputStream(mSnapshotFilePath); // Use the preview image format, as documented in Android SDK javadoc if ( (mPreviewImageFormat == ImageFormat.NV21) || (mPreviewImageFormat == ImageFormat.YUY2) ) { saveYUVToJPEG( mCamera, out, data ); } else if (mPreviewImageFormat == ImageFormat.JPEG) { Log.d(TAG, "directly write JPEG to storage"); out.write(data); } else { Log.d(TAG, "try decoding to byte array"); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); if ( bitmap != null ) { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); } else { Log.e(TAG, "decodeByteArray failed, no decoded data"); } } } catch (FileNotFoundException ignore) {;} catch (IOException ignore) {;} finally { if ( out != null ) { try { out.close(); } catch (IOException ignore) {;} out = null; } if ( bitmap != null ) { bitmap.recycle(); bitmap = null; } data = null; } return null; } } /** * Save YUV image data (aka NV21 or YUV420sp) data to JPEG file. * * @param camera * @param out * @param data */ protected void saveYUVToJPEG( Camera camera, FileOutputStream out, byte[] data ) { YuvImage yuvimg = null; try { int width = mPreviewWidth; int height = mPreviewHeight; Rect rect = new Rect(); rect.left = 0; rect.top = 0; rect.right = width - 1; rect.bottom = height - 1; // The -1 is required, otherwise a buffer overrun occurs yuvimg = new YuvImage(data, mPreviewImageFormat, width, height, null); yuvimg.compressToJpeg(rect, 90, out); } finally { yuvimg = null; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload