安卓Java相机捕获来自异步任务

3
我正在尝试使用AsyncTask编写代码,从摄像头拍摄照片并通过UDP协议将其发送到服务器100次。然而,PictureCallback没有被调用。请有人帮助我吗?以下是我的尝试内容:
public class MainAsyncTask extends AsyncTask<Void, String, Void> {

protected static final String TAG = null;
public MainActivity mainAct;

public MainAsyncTask(MainActivity mainActivity)
{
    super();
    this.mainAct = mainActivity;
}

@Override
protected Void doInBackground(Void... params) {
    DatagramSocket clientSocket = null;
    InetAddress IPAddress = null;
    try {
        clientSocket = new DatagramSocket();
        IPAddress = InetAddress.getByName("192.168.1.15");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    byte [] data;
    DatagramPacket sendPacket;

    try {
        for (int i=0; i < 100; i++)
        {
            publishProgress("");
            File file = new File(Environment.getExternalStorageDirectory()+ File.separator +"img.jpg");
            while (!file.exists() || file.length() == 0);
            Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+ File.separator +"img.jpg");
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes);
            data = bytes.toByteArray();
            sendPacket = new DatagramPacket(data, data.length, IPAddress, 3107);
            clientSocket.send(sendPacket);
            file.delete();
        }

        clientSocket.close();


    } catch (Exception e) {
        // TODO Auto-generated catch block
        publishProgress(e.getMessage());
    }
    return null;
}

public static void takeSnapShots(MainActivity mainAct)
{
    PictureCallback jpegCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) 
        {
            FileOutputStream outStream = null;
            try {
                outStream = new FileOutputStream(Environment.getExternalStorageDirectory()+File.separator+"img"+".jpg");    
                outStream.write(data);
                outStream.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally 
            {
                camera.stopPreview();
                camera.release();
                camera = null;
            }
            Log.d(TAG, "onPictureTaken - jpeg");
        }
        };
    SurfaceView surface = new SurfaceView(mainAct.getApplicationContext());
    Camera camera = Camera.open();
    try {
        camera.setPreviewDisplay(surface.getHolder());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    camera.startPreview();
    camera.takePicture(null,null,jpegCallback);
}


protected void onProgressUpdate(String... progress) {
    takeSnapShots(mainAct);
}

@Override
protected void onPostExecute(Void result)
{
}

}

3个回答

1
我认为AsyncTask不是完成此任务最方便的工具。
你需要一个不是从无处创建而是连接到屏幕的SurfaceView。你应该只初始化一次相机,并且不能在循环中调用camera.takePicture()。你可以从onPictureTaken()回调中调用takePicture(),但你也应该记住不能从UI线程中使用套接字。幸运的是,你可以遵循Google的建议。
引用:

访问相机的推荐方式是在单独的线程上打开相机

当调用open(int)时,回调将在事件线程上被调用

如果你在一个新的HandlerThread中打开相机,就像这里所示,图片回调将在该后台线程上到达,该线程也可用于网络。
此外,我建议您直接发送从相机接收到的JPEG缓冲区。我认为将图像保存到文件,读取文件到位图并压缩后者到另一个JPEG的开销可能会过高。要控制图像大小,请选择适当的图片大小。请注意,应从特定相机支持的尺寸列表中选择尺寸。
public class CameraView extends SurfaceView 
    implements SurfaceHolder.Callback, Camera.PictureCallback {

    private static final String TAG = "CameraView";

    private Camera camera;
    private HandlerThread cameraThread;
    private Handler handler;
    private boolean bCameraInitialized = false;
    private int picturesToTake = 0;

    public CameraView(Context context, AttributeSet attr) {
        super(context, attr);

        // install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        getHolder().addCallback(this);
    }

    @Override public void surfaceCreated(SurfaceHolder holder) {
        cameraThread = new HandlerThread("CameraHandlerThread");
        cameraThread.start();
        handler = new Handler(cameraThread.getLooper());
        hanlder.post(new Runnable() {
            @Override public void run() {
                openRearCamera();
                bCameraInitialized = false;
            }
        });
    }

    @Override public void surfaceDestroyed(SurfaceHolder holder) {
        if (camera != null) {
            Log.d(TAG, "Camera release");
            camera.release();
            camera = null;
            bCameraInitialized = false;
        }
    }

    // finalize the camera init now that we know preview size
    @Override public void surfaceChanged(SurfaceHolder holder, int format, final int w, final int h) {
        Log.w(TAG, "surfaceChanged(" + w + ", " + h + ")");
        if (!bCameraInitialized) {
            cameraSetup(w, h);
            bCameraInitialized = true;
        }
    }

    private void openRearCamera() {
        if (camera != null) {
            Log.e(TAG, "openRearCamera(): camera is not null");
            return;
        }
        try {
            camera = Camera.open(0);
            Log.d(TAG, "Camera ready " + String.valueOf(camera));
        }
        catch (Throwable e) {
            Log.e(TAG, "openRearCamera(): Camera.open() failed", e);
        }
    }

    private void cameraSetup(int w, int h) {

        if (camera == null) {
            Log.e(TAG, "cameraSetup(): camera is null");
            return;
        }

        Log.d(TAG, "Camera setup");
        try {
            Camera.Parameters params = camera.getParameters();

            // still picture settings - be close to preview size
            Camera.Size pictureSize = params.getSupportedPictureSizes()[0];
            params.setPictureSize(pictureSize.width, optimalPictureSize.height);

            camera.setParameters(params);
            camera.setPreviewDisplay(getHolder());
            camera.startPreview();
        }
        catch (Throwable e) {
            Log.e(TAG, "Failed to finalize camera setup", e);
        }
    }

    private void sendJpeg(byte[] data) {
        DatagramSocket clientSocket = null;
        InetAddress IPAddress = null;
        try {
            clientSocket = new DatagramSocket();
            IPAddress = InetAddress.getByName("192.168.1.15");
        }
        catch (Exception e) {
            Log.e(TAG, "failed to initialize client socket", e);
        }
        DatagramPacket sendPacket;
        sendPacket = new DatagramPacket(data, data.length, IPAddress, 3107);
        clientSocket.send(sendPacket);
        Log.d(TAG, "sent image");
    }

    @Override public void onPictureTaken(byte[] data, Camera camera) {
        sendJpeg(data);
        camera.startPreview();
        takePictures(picturesToTake-1);
    }

    public void takePictures(int n) {
        if (n > 0) {
            picturesToTake = n;
            Log.d(TAG, "take " + n + " images");
            camera.takePicture(null, null, this);
        }
        else {
            Log.d(TAG, "all images captured");
        }
    }
}

上面的类是从几个项目中编译而来,为了简洁起见,错误检查已经最小化。它可能需要一些修复才能编译。您只需将<CameraView />添加到您的活动布局中,并在用户单击按钮或其他东西时调用其takePictures即可。

0

你不能这样做

camera.setPreviewDisplay(surface.getHolder());

来自文档:

http://developer.android.com/reference/android/hardware/Camera.html#setPreviewDisplay(android.view.SurfaceHolder)

在调用此方法时,SurfaceHolder 必须已经包含一个 surface。如果您正在使用 SurfaceView,则需要使用 addCallback(SurfaceHolder.Callback) 注册 SurfaceHolder.Callback 并等待 surfaceCreated(SurfaceHolder) 调用后再调用 setPreviewDisplay() 或启动预览。

您需要执行类似以下操作:

SurfaceHolder surfaceHolder = surface.getHolder();
surfaceHolder.addCallback(new Callback() {
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                camera.setPreviewDisplay(holder);
                camera.startPreview();
                camera.takePicture(null,null,jpegCallback);
            } catch (IOException e) {
            }
        }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {}
    }
);

0
你是这样调用你的AsyncTask的吗?仅仅创建AsyncTask是不够的。
new MainAsyncTask(ActivityContext).execute();

是的,那我需要做什么? - eyal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接