0

以下代码在 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

我还检查了 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 服务执行的。

4

2 回答 2

0

文档很明确:如果要拍照,必须开始预览。从您的代码中,尚不清楚为什么未显示预览表面。IIRC,在 Honeycomb 及更高版本中,您无法使用预览表面坐标将其移出屏幕。但是您通常可以将预览表面隐藏在某些图像视图后面。

于 2013-10-16T15:50:06.550 回答
0

带有 rawCallback 的 Camera.takePicture 需要调用 addRawImageCallbackBuffer

(我也遇到了这个问题,不得不去源代码弄清楚)当 Camera.takePicture 用第二个参数(Callback raw)非空调用时,用户必须至少调用一次 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)}.

尝试将 takePicture() 的“原始”回调参数设置为 null 的代码。

于 2019-07-22T00:26:00.740 回答