我不能告诉你为什么有些设备会出现乱码数据而有些设备却不会,但我可以建议一个解决方法,它对我的应用程序非常有效。
你的示例代码将相机的JPEG缩小到640x480像素后再保存到SD卡中。所以我猜想你并不需要完整尺寸的相机图像。
如果这个假设是正确的,那么你可以完全跳过相机的takePicture()
API,直接将预览帧保存到SD卡中。最简单的方法是使用setOneShotPreviewCallback()
函数:
mCamera.setOneShotPreviewCallback( new StillPictureCallback() );
这将被调用一次,并将从相机返回一个数据缓冲区。
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);
}
}
回调函数会调用后台任务来压缩数据并将其保存到文件中。我省略的代码部分仅包括通过
getCameraInfo()
查询摄像头预览帧格式、宽度和高度的部分。请注意,Android的YUVImage类是在Froyo版本中引入的,因此如果您需要支持早期版本的Android,则需要编写自己的转换代码(StackOverflow上有一些示例)。
private class SaveStillPictureTask extends AsyncTask<byte[], Void, Void> {
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);
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;
}
}
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;
yuvimg = new YuvImage(data, mPreviewImageFormat, width, height, null);
yuvimg.compressToJpeg(rect, 90, out);
} finally {
yuvimg = null;
}
}
p.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
和p.setPictureSize(optimalPictureSize.width, optimalPictureSize.height);
解决了该问题。 - Martynas Jurkus