I am attempting to build a basic camcorder that allows the user to take videos rapidly by touching the screen, this seemed straight forward however the major problem I have run into is that the Android MediaRecorder does not allow for rapid start and restart without crashing, if the user shoots and then stops and then quickly resumes shooting again it always crashes Im not sure if there is a way to directly fix this so I also devised another method to achieve this by attempting to record a single video but trying to gain some control over when the mediaRecorder actually writes to the file. however I wasnt able to get this to fully run using FileDescriptor, below I will paste my original code and my method I used in the second attempt controlling the writing, is there any way to adjust either code to achieve that pause functionality im after? any help will go a long way thanks
My first attempt using the common way of setting a file to setOutPutFile():
public class MainActivity extends Activity implements SurfaceHolder.Callback {
public static final String LOGTAG = "VIDEOCAPTURE";
private MediaRecorder recorder;
private SurfaceHolder holder;
private CamcorderProfile camcorderProfile;
private Camera camera;
boolean recording = false;
boolean usecamera = true;
boolean previewRunning = false;
double timer = 0;
ProgressBar pb;
boolean neverEnd;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
setContentView(R.layout.activity_main);
pb = (ProgressBar) findViewById(R.id.progressBar1);
pb.setProgress(0);
SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);
holder = cameraView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraView.setClickable(true);
cameraView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
recording = true;
new recordVideo().execute();
Log.v(LOGTAG, "Recording Started");
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
recording = false;
return true;
}
return false;
}
});
}
private void prepareRecorder() {
recorder = new MediaRecorder();
recorder.setPreviewDisplay(holder.getSurface());
if (usecamera) {
camera.unlock();
recorder.setCamera(camera);
}
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
recorder.setProfile(camcorderProfile);
Calendar calendarTime = Calendar.getInstance();
//initial attempt using a file path with setoutputfile
File file = new File(Environment.getExternalStorageDirectory(),
String.valueOf(calendarTime.getTimeInMillis()) + ".mp4");
if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.THREE_GPP) {
recorder.setOutputFile(file.getAbsolutePath());
} else if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.MPEG_4) {
recorder.setOutputFile(file.getAbsolutePath());
} else {
recorder.setOutputFile(file.getAbsolutePath());
}
// recorder.setMaxDuration(50000); // 50 seconds
// recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
boolean initialized = false;
while (!initialized) {
try {
recorder.prepare();
initialized = true;
} catch (IllegalStateException e) {
e.printStackTrace();
// finish();
initialized = false;
} catch (IOException e) {
e.printStackTrace();
// finish();
initialized = false;
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.v(LOGTAG, "surfaceCreated");
if (usecamera) {
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
previewRunning = true;
} catch (IOException e) {
Log.e(LOGTAG, e.getMessage());
e.printStackTrace();
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.v(LOGTAG, "surfaceChanged");
if (!recording && usecamera) {
if (previewRunning) {
camera.stopPreview();
}
try {
Camera.Parameters p = camera.getParameters();
p.setPreviewSize(camcorderProfile.videoFrameWidth,
camcorderProfile.videoFrameHeight);
p.setPreviewFrameRate(camcorderProfile.videoFrameRate);
camera.setParameters(p);
camera.setPreviewDisplay(holder);
camera.startPreview();
previewRunning = true;
} catch (IOException e) {
Log.e(LOGTAG, e.getMessage());
e.printStackTrace();
}
prepareRecorder();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(LOGTAG, "surfaceDestroyed");
if (recording) {
recorder.stop();
recording = false;
}
recorder.release();
if (usecamera) {
previewRunning = false;
// camera.lock();
camera.release();
}
finish();
}
private class recordVideo extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
recorder.start();
while (recording) {
Thread.sleep(100);
publishProgress();
}
recorder.stop();
recorder.release();
recorder = null;
// recorder.release();
Log.v(LOGTAG, "Recording Stopped");
// Let's prepareRecorder so we can record again
prepareRecorder();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
if (recording) {
timer += 0.1;
pb.setProgress((int) (timer * 10));
}
}
}
}
Here is my method using FileDescriptor, this did not work, only created a file but didnt write to it:
//Pass it into setOutputFile() like this
recorder.setOutputFile(getStreamFd());
private FileDescriptor getStreamFd() {
ParcelFileDescriptor pipe = null;
try {
Calendar calendarTime = Calendar.getInstance();
File file = new File(Environment.getExternalStorageDirectory(),
String.valueOf(calendarTime.getTimeInMillis()) + ".mp4");
pipe = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_CREATE
| ParcelFileDescriptor.MODE_APPEND
| ParcelFileDescriptor.MODE_WORLD_WRITEABLE);
byte[] buf = new byte[1024];
int len;
FileOutputStream out = new FileOutputStream(FileDescriptor.out);
InputStream is = new FileInputStream(FileDescriptor.in);
while (usecamera) {
if(recordng){
out.write(buf, 0, len);
}
}
is.close();
out.close();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
}
return pipe.getFileDescriptor();
}
Call cameraView.setClickable(true) after prepareRecorder() and call cameraView.setClickable(false) before call prepareRecorder() on AsynkTask
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