Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MediaRecorder start() fail if called too quickly

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();
}
like image 874
Edmund Rojas Avatar asked Jun 10 '13 13:06

Edmund Rojas


1 Answers

Call cameraView.setClickable(true) after prepareRecorder() and call cameraView.setClickable(false) before call prepareRecorder() on AsynkTask

like image 195
INDAPP Avatar answered Oct 10 '22 20:10

INDAPP