如何使相机可以使用连拍模式
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) 以更好地控制时间。
【讨论】:
以上是关于如何使相机可以使用连拍模式的主要内容,如果未能解决你的问题,请参考以下文章