以下代码在HTC Desire S,Galaxy S II和仿真器上进行测试。它工作正常,但令人惊讶的是它不适用于Galaxy S Duos(GT-S7562)。会发生的是所有调用都成功,没有异常,但不会调用回调。
public class CameraManager implements PictureCallback {
private final static String DEBUG_TAG = "CameraManager";
public void TakePicture() {
try {
_camera = Camera.open(cameraId);
Log.d(DEBUG_TAG, "Camera.TakePicture.open");
SurfaceView view = new SurfaceView(CameraManager.this.getContext());
_camera.setPreviewDisplay(view.getHolder());
Log.d(DEBUG_TAG, "Camera.TakePicture.setPreviewDisplay");
_camera.startPreview();
Log.d(DEBUG_TAG, "Camera.TakePicture.startPreview");
AudioManager manager = (AudioManager) CameraManager.super.getContext().getSystemService(Context.AUDIO_SERVICE);
Log.d(DEBUG_TAG, "Camera.TakePicture.AudioManager.ctor()");
manager.setStreamVolume(AudioManager.STREAM_SYSTEM, 0 , AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Log.d(DEBUG_TAG, "Camera.TakePicture.setStreamVolume");
Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
AudioManager manager = (AudioManager) CameraManager.super.getContext().getSystemService(Context.AUDIO_SERVICE);
Log.d(DEBUG_TAG, "Camera.TakePicture.Shutter.AudioManager.ctor()");
manager.setStreamVolume(AudioManager.STREAM_SYSTEM, manager.getStreamMaxVolume(AudioManager.STREAM_SYSTEM) , AudioManager.FLAG_ALLOW_RINGER_MODES);
Log.d(DEBUG_TAG, "Camera.TakePicture.Shutter.setStreamVolume");
}
};
Camera.PictureCallback rawCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
Log.i(DEBUG_TAG, "Picture taken::RAW");
_camera.stopPreview();
_camera.release();
} else {
Log.wtf(DEBUG_TAG, "Picture NOT taken::RAW");
}
}
};
_camera.takePicture(shutter, rawCallback, CameraManager.this);
Log.d(DEBUG_TAG, "Camera.TakePicture.taken");
} catch (Exception err) {
err.printStackTrace();
Log.d(DEBUG_TAG, "Camera.TakePicture.Exception:: %s" + err.getMessage());
}
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
Log.i(DEBUG_TAG, "Picture taken::JPG");
_camera.stopPreview();
_camera.release();
} else {
Log.wtf(DEBUG_TAG, "Picture NOT taken::JPG");
}
}
}
这是用于执行上述代码的logcat的输出日志,正如您所看到的,不会调用回调。:
[ 10-16 01:39:18.711 3873:0xf21 D/CameraManager ]
Camera.TakePicture.open
[ 10-16 01:39:18.891 3873:0xf21 D/CameraManager ]
Camera.TakePicture.setFrontCamera
[ 10-16 01:39:18.901 3873:0xf21 D/CameraManager ]
Camera.TakePicture.setPreviewDisplay
[ 10-16 01:39:18.901 3873:0xf21 D/CameraManager ]
Camera.TakePicture.startPreview
[ 10-16 01:39:18.901 3873:0xf21 D/CameraManager ]
Camera.TakePicture.AudioManager.ctor()
[ 10-16 01:39:19.001 3873:0xf21 D/CameraManager ]
Camera.TakePicture.setStreamVolume
[ 10-16 01:39:19.041 3873:0xf21 D/CameraManager ]
Camera.TakePicture.taken
我还检查了SO以及Galaxy S的类似问题并找到了以下代码,我用它没有成功:
Camera.Parameters parameters = camera.getParameters();
parameters.set("camera-id", 2);
// (800, 480) is also supported front camera preview size at Samsung Galaxy S.
parameters.setPreviewSize(640, 480);
camera.setParameters(parameters);
我想知道是否有人能告诉我我的代码有什么问题?或者这个模型有一些限制,不允许在没有显示预览表面的情况下拍照。如果是这样,那么您能告诉我任何可能的解决方法吗?请注意,此代码是从Android服务执行的。
答案 0 :(得分:0)
Documentation是明确的:如果您想拍照,则必须开始预览。从您的代码中,不清楚为什么预览表面没有显示。 IIRC,在Honeycomb以后,您无法使用预览曲面坐标将其移出屏幕。但是你通常可以隐藏一些图像视图后面的预览表面。
答案 1 :(得分:0)
带有rawCallback的Camera.takePicture需要调用addRawImageCallbackBuffer
(我也遇到了这个问题,必须去查看源代码才能弄清楚)用第二个参数(回调原始)非空调用Camera.takePicture时,用户必须在以下位置调用Camera.addRawImageCallbackBuffer()在takePicture()之前至少有一次开始为返回的数据提供缓冲区。如果不这样做,将丢弃图像(显然不会调用回调。
这是android.hardware.Camera.java中的addRawImageCallbackBuffer()的块注释:
Adds a pre-allocated buffer to the raw image callback buffer queue.
Applications can add one or more buffers to the queue. When a raw image
frame arrives and there is still at least one available buffer, the
buffer will be used to hold the raw image data and removed from the
queue. Then raw image callback is invoked with the buffer. If a raw
image frame arrives but there is no buffer left, the frame is
discarded. Applications should add buffers back when they finish
processing the data in them by calling this method again in order
to avoid running out of raw image callback buffers.
The size of the buffer is determined by multiplying the raw image
width, height, and bytes per pixel. The width and height can be
read from {@link Camera.Parameters#getPictureSize()}. Bytes per pixel
can be computed from
{@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8,
using the image format from {@link Camera.Parameters#getPreviewFormat()}.
This method is only necessary when the PictureCallbck for raw image
is used while calling {@link #takePicture(Camera.ShutterCallback,
Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
Please note that by calling this method, the mode for
application-managed callback buffers is triggered. If this method has
never been called, null will be returned by the raw image callback since
there is no image callback buffer available. Furthermore, When a supplied
buffer is too small to hold the raw image data, raw image callback will
return null and the buffer will be removed from the buffer queue.
@param callbackBuffer the buffer to add to the raw image callback buffer
queue. The size should be width * height * (bits per pixel) / 8. An
null callbackBuffer will be ignored and won't be added to the queue.
@see #takePicture(Camera.ShutterCallback,
Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
在代码中将“ raw”回调参数的takePicture()设置为null。