I am using Android development (SDK 2.2) and I would like to make a video recording with mediaRecorder
and, at the same time, do some process on each preview frame.
I record video with MediaRecorder
in a project, in an other I use the onPreviewFrame(byte[] data
, Camera camera
) (from PreviewCallback
) for processing preview pictures.
I've tried to create a Camera and use it with mediaRecorder
(setCamera
function) but it doesn't work.
Is it possible to do both in the same time?
Actually I don't understand how to link two things?
My code :
package ch.fraise;
import java.io.IOException;
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraActivity extends Activity implements SurfaceHolder.Callback,
Camera.AutoFocusCallback {
private SurfaceView preview;
private SurfaceHolder previewHolder;
private MediaRecorder mRecorder;
private Camera mCamera;
private boolean mPreviewRunning = false;
private boolean mCaptureFrame = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("", "Begin onCreate");
setContentView(R.layout.main);
preview = (SurfaceView) findViewById(R.id.surfaceView1);
previewHolder = preview.getHolder();
previewHolder.addCallback(this);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mRecorder = new MediaRecorder();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.capture_menu, menu);
return true;
}
public void startRecording() {
Log.e("", "Begin StartRecording");
mCaptureFrame = true;
mRecorder.start();
}
public void stopRecording() {
Log.e("", "Begin StopChange");
mRecorder.stop();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.startRecording:
startRecording();
return true;
case R.id.stopRecording:
stopRecording();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("", "Begin surfaceDestroy");
mCamera = Camera.open();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
mRecorder.reset();
mRecorder.release();
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
}
/*
* PreviewCallback()
*
* this callback captures the preview at every frame and puts it in a byte
* buffer. we will evaluate if this is a frame that we want to process, and
* if so, we will send it to an asynchronous thread that will process it to
* an ARGB Bitmap and POST it to the server
*/
PreviewCallback previewCallback = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Log.e("", "onPreviewFrame pass");
if (mCaptureFrame) {
mCaptureFrame = false;
// new FrameHandler().execute(data);
}
}
};
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.e("", "Begin SurfaceChange");
mRecorder.reset();
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mRecorder.setOutputFile("/sdcard/videotest2.mp4");
mRecorder.setVideoFrameRate(30);
mRecorder.setPreviewDisplay(previewHolder.getSurface());
try {
mRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (mPreviewRunning)
mCamera.stopPreview();
Camera.Parameters p = mCamera.getParameters();
// p.setPreviewSize(width, height);
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mPreviewRunning = true;
}
}
and the permissions in the XML file :
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Eureka! The trick is to attach your PreviewCallback
in the surfaceChanged(...)
SurfaceHolder.Callback
! After doing this, you'll continue to get preview frame data after a MediaRecorder is running!
For example:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] _data, Camera _camera) {
Log.d("onPreviewFrame-surfaceChanged",String.format("Got %d bytes of camera data", _data.length));
}
});
}
you cannot access the video stream while recording, onPreviewFrame will not get called once you start recording. Oddly, onPreviewFrame does not seem to get called after you record either...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With