如何使相机可以使用连拍模式

Posted

技术标签:

【中文标题】如何使相机可以使用连拍模式【英文标题】:How to make burst mode available to Camera 【发布时间】:2011-10-16 21:14:50 【问题描述】:

我正在尝试为相机构建一个带有连拍模式的小型照片应用程序。主要思想是每 0.3 秒拍摄一张照片,并将照片存储在一个数组中,直到拍摄最后一张照片。应指定要​​拍摄的照片数量。

我只能每 2 秒拍一张照片。作为最短间隔。然后,当应该将图片写入存储时,应用程序就会崩溃。

有人知道如何实现吗?这是我的代码:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;

public class CamaeaView extends Activity implements SurfaceHolder.Callback, OnClickListener 

    static final int FOTO_MODE = 1;
    private static final String TAG = "Test";
    Camera mCamera;
    boolean mPreviewRunning = false;
    private Context mContext = this;
    ArrayList<Object> listImage = null;
    public static ArrayList<Object> List1[];

    public void onCreate(Bundle icicle) 
        super.onCreate(icicle);

        Log.e(TAG, "onCreate");

        @SuppressWarnings("unused")
        Bundle extras = getIntent().getExtras();

        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.main);
        mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
        mSurfaceView.setOnClickListener(this);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) 
        super.onRestoreInstanceState(savedInstanceState);
    

    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() 
        public void onPictureTaken(byte[] imageData, Camera c) 
            Log.d("Start: ","Imagelist");

            Intent mIntent = new Intent();
            listImage.add(StoreByteImage(imageData));
            SaveImage(listImage);
            mCamera.startPreview();

            setResult(FOTO_MODE, mIntent);
            finish();

        
    ;

    protected void onResume() 
        Log.d(TAG, "onResume");
        super.onResume();
    

    protected void onSaveInstanceState(Bundle outState) 
        super.onSaveInstanceState(outState);
    

    protected void onStop() 
        Log.e(TAG, "onStop");
        super.onStop();
    

    public void surfaceCreated(SurfaceHolder holder) 
        Log.d(TAG, "surfaceCreated");
        mCamera = Camera.open();

    

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 
        Log.d(TAG, "surfaceChanged");

        // XXX stopPreview() will crash if preview is not running
        if (mPreviewRunning) 
            mCamera.stopPreview();
        

        Camera.Parameters p = mCamera.getParameters();
        p.setPreviewSize(w, h);
        p.setPictureSize(1024, 768);
        p.getSupportedPictureFormats();
        p.setPictureFormat(PixelFormat.JPEG);
        mCamera.setParameters(p);
        try 
            mCamera.setPreviewDisplay(holder);
         catch (IOException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        mCamera.startPreview();
        mPreviewRunning = true;
    

    public void surfaceDestroyed(SurfaceHolder holder) 
        Log.e(TAG, "surfaceDestroyed");
        mCamera.stopPreview();
        mPreviewRunning = false;
        mCamera.release();
    

    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;

    public void onClick(View arg0) 
        int i = 0;
        while (i < 4) 

            mCamera.takePicture(null, mPictureCallback, mPictureCallback);
            i = i + 1;
            try 
                Thread.sleep(3000);
             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
    

    public static Object StoreByteImage(byte[] imageData) 

        Object obj = null;
        try 
            ByteArrayInputStream bis = new ByteArrayInputStream(imageData);
            ObjectInputStream objImageData = new ObjectInputStream(bis);
            obj = objImageData.readObject();

         catch (IOException ex) 
            // TODO: Handle the exception
         catch (ClassNotFoundException ex) 
            // TODO: Handle the exception
        
        return obj;

    

    public static Object createImagesArray(byte[] imageData) 

        Object obj = null;
        try 
            ByteArrayInputStream bis = new ByteArrayInputStream(imageData);
            ObjectInputStream objImageData = new ObjectInputStream(bis);
            obj = objImageData.readObject();

         catch (IOException ex) 
            // TODO: Handle the exception
         catch (ClassNotFoundException ex) 
            // TODO: Handle the exception
        
        return obj;

    

    public static boolean SaveImage(List<Object> listImage) 

        FileOutputStream outStream = null;
        Log.d("ListSize: ", Integer.toString(listImage.size()));
        Iterator<Object> itList = listImage.iterator();
        byte[] imageBytes = null;
        while (itList.hasNext()) 

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try 
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(listImage);
                oos.flush();
                oos.close();
                bos.close();
                imageBytes = bos.toByteArray();
             catch (IOException ex) 
                // TODO: Handle the exception
            

            try 
                // Write to SD Card
                outStream = new FileOutputStream(String.format(
                        "/sdcard/DCIM/%d.jpg", System.currentTimeMillis())); // <9>
                outStream.write(imageBytes);
                outStream.close();

             catch (FileNotFoundException e)  // <10>
                e.printStackTrace();
             catch (IOException e) 
                e.printStackTrace();
             finally 
            
        
        Log.d(TAG, "onPictureTaken - jpeg");

        return true;
    


来自 cmets 的错误:

ERROR/MemoryHeapBase(1382): error opening /dev/pmem_camera: No such file or directory 
ERROR/QualcommCameraHardware(1382): failed to construct master heap for pmem pool /dev/pmem_camera 
ERROR/QualcommCameraHardware(1382): initRaw X failed with pmem_camera, trying with pmem_adsp

【问题讨论】:

请用实际描述和堆栈跟踪指定“崩溃”?应该有用... 是的当然:) 实际上这些行是红色 07-31 14:12:32.801: ERROR/MemoryHeapBase(1382): error opening /dev/pmem_camera: No such file or directory 07 -31 14:12:32.801:错误/QualcommCameraHardware(1382):无法为 pmem 池 /dev/pmem_camera 构造主堆 07-31 14:12:32.801:错误/QualcommCameraHardware(1382):initRaw X 使用 pmem_camera 失败,正在尝试使用 pmem_adsp 会不会是内存用完了?您必须考虑到您拥有的有限堆空间...... 嗯 chrash 意味着它只是挂断了我的手机,所以我必须取出电池。 我的手机有 200MB 内存,有 512 个。所以 4 张 1024x768 大小的图片应该是个问题 【参考方案1】:

AFAIK,在第一张完成之前,您不能再拍摄另一张照片。消除您的for 循环和Thread.sleep()。在mPictureCallback拍下一张照片。

主要思想是每 0.3 秒拍摄一张照片,并将照片存储在一个数组中,直到拍摄完最后一张照片。

“0,3sec”目标比大多数设备处理图像的速度要快,而且您的图像数组可能没有足够的堆空间。我怀疑您必须将每个图像通过AsyncTask 写入磁盘,这样您就可以释放堆空间,同时也不会占用主应用程序线程。

【讨论】:

这是这个应用程序 (play.google.com/store/apps/…),它可以每隔 0.1 或更短时间拍摄一张照片,不会有任何延迟。我很好奇你是否能猜出这个应用程序可能使用什么方法来实现这种突发模式。我已经知道预览回调。但我也知道它会产生低质量的图像。 @MrSMAK:由于他们声明“由于速度快,所以不会以可能的最高分辨率拍摄照片”,如果他们使用预览回调,我一点也不感到惊讶。事实上,声明“零快门延迟 - 按下快门按钮后立即拍摄照片”几乎可以确保他们正在使用预览回调,因为当您调用 takePicture() 时,他们无法控制任何硬件施加的延迟。 感谢您的回复 :-) 现在我很清楚 Burst Camera 方法了。 @CommonsWare 能不能举个例子,怎么爆图片?【参考方案2】:

您可以尝试在预分配的字节数组中捕获后续预览帧。 请参阅以下方法:

http://developer.android.com/reference/android/hardware/Camera.html#addCallbackBuffer(byte[]) http://developer.android.com/reference/android/hardware/Camera.html#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)

...或http://developer.android.com/reference/android/hardware/Camera.html#setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback) 以更好地控制时间。

【讨论】:

以上是关于如何使相机可以使用连拍模式的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 上将图像保存为连拍

笔记本摄像头怎么开启

Android | 教你如何使用HwCameraKit接入相机人像模式

HarmonyOS之深入解析相机的功能和使用

如何使相机适合对象

如何使用 Glut 使相机飞过 OpenGL 中的对象?