4

I want to make an app that record video, it seems like vine, hold to record, release it stop, hold to record and keep that to the end.

I have used MediaRecorder, but it just record once a time, if I start record again, app is crashed.

Please tell me there is any way to do this? I edited my code:

public class VideoRecordingActivity extends AppCompatActivity implements View.OnTouchListener, View.OnLongClickListener {
private Context myContext;
private boolean hasCamera;
private boolean onRecording;

private Camera mCamera;
private CameraPreview mPreview;
private MediaRecorder mediaRecorder;
private boolean cameraFront = false;
private int cameraId;

private int videoNumer;
private boolean isActionDown = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_video_introduction_recording);
    initUI();
    initialize();
}
private LinearLayout lnCameraPreview;
private ImageButton btn_recording;

private void initUI() {
    lnCameraPreview = (LinearLayout) findViewById(R.id.ln_body_recording);
    btn_recording = (ImageButton) findViewById(R.id.btn_recording);

}

public void initialize() {
    myContext = this;
    mPreview = new CameraPreview(this, cameraId, mCamera);
    lnCameraPreview.addView(mPreview);
    btn_recording.setOnLongClickListener(this);
    btn_recording.setOnTouchListener(this);
    videoNumer = 0;
}
public boolean onLongClick(View v) {
    isActionDown = true;
    try {
        boolean isPrepared = false;
        if (isActionDown)
            isPrepared = prepareMediaRecorder();
        if (isPrepared && isActionDown) {
            // work on UiThread for better performance
            runOnUiThread(new Runnable() {
                public void run() {
                    mediaRecorder.start();
                    onRecording = true;
                }
            });

        }
    } catch (Exception e) {
        e.printStackTrace();
        Log.e("onLongPress Error ", e.toString());
    }

    return true;
}


@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_UP:
            isActionDown = false;

            try {
                if (onRecording) {

                    if (mediaRecorder != null) {
                        mediaRecorder.stop();
                    }
                    onRecording = false;
                    videoNumer++;
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            break;
    }
    return false;
}



public void onResume() {
    super.onResume();
    if (!hasCamera(myContext)) {
        Toast.makeText(myContext, "Sorry, your phone does not have a camera!", Toast.LENGTH_LONG).show();
        return;
    }
    initCamera();
}

@Override
protected void onPause() {
    super.onPause();
    // when on Pause, release camera in order to be used from other
    // applications
    releaseCamera();
}


private final int cMaxRecordDurationInMs = 30000;
private final long cMaxFileSizeInBytes = 5000000;
private final int cFrameRate = 20;
private File prRecordedFile;

@SuppressLint("SdCardPath")
private boolean prepareMediaRecorder() {
    mediaRecorder = new MediaRecorder();

    try {
        mCamera.unlock();
    } catch (Exception ex) {
        return false;
    }

        // adjust the camera the way you need
        mediaRecorder.setCamera(mCamera);
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);

        //
        CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
        mediaRecorder.setProfile(cpHigh);
        mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    mediaRecorder.setOutputFile("/sdcard/" + videoNumer + "videocapture_example.mp4");

    //set max size
    mediaRecorder.setMaxDuration(600000); // Set max duration 60 sec.
    mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M

    try {
        mediaRecorder.prepare();
    } catch (Exception e) {
        releaseMediaRecorder();
        e.printStackTrace();
    }
    return true;
}

private void releaseMediaRecorder() {
    if (mediaRecorder != null) {
        mediaRecorder.reset(); // clear recorder configuration
        mediaRecorder.release(); // release the recorder object
        mediaRecorder = null;
        if (mCamera != null) {
            mCamera.lock(); // lock camera for later use
        }
    }
}

/**
 * Camera
 */

private void initCamera() {
    if (mCamera == null) {
        // if the front facing camera does not exist
        if (findFrontFacingCamera() < 0) {
            Toast.makeText(this, "No front facing camera found.", Toast.LENGTH_LONG).show();
        }
        mCamera = Camera.open(findBackFacingCamera());
        mPreview.refreshCamera(mCamera);
    }
    onRecording = false;
}

private boolean hasCamera(Context context) {
    // check if the device has camera
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        hasCamera = true;
    } else {
        hasCamera = false;
    }
    return hasCamera;
}

private int findFrontFacingCamera() {
    int cameraId = -1;
    // Search for the front facing camera
    int numberOfCameras = Camera.getNumberOfCameras();
    for (int i = 0; i < numberOfCameras; i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            cameraId = i;
            cameraFront = true;
            break;
        }
    }
    this.cameraId = cameraId;
    return cameraId;
}

private int findBackFacingCamera() {
    int cameraId = -1;
    // Search for the back facing camera
    // get the number of cameras
    int numberOfCameras = Camera.getNumberOfCameras();
    // for every camera check
    for (int i = 0; i < numberOfCameras; i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            cameraId = i;
            cameraFront = false;
            break;
        }
    }
    this.cameraId = cameraId;
    return cameraId;
}

public void switchCamera() {
    // if the camera preview is the front
    if (cameraFront) {
        int cameraId = findBackFacingCamera();
        if (cameraId >= 0) {
            // open the backFacingCamera
            mCamera = Camera.open(cameraId);
            // refresh the preview
            mPreview.refreshCamera(mCamera);
        }
    } else {
        int cameraId = findFrontFacingCamera();
        if (cameraId >= 0) {
            // open the backFacingCamera
            mCamera = Camera.open(cameraId);
            // refresh the preview
            mPreview.refreshCamera(mCamera);
        }
    }
}

private void releaseCamera() {
    // stop and release camera
    if (mCamera != null) {
        mCamera.release();
        mCamera = null;
    }
}

}

Nguyen Khoi
  • 110
  • 1
  • 8
  • you need to show your code, Community can't help unless you show us what you did so far. – Brij Raj Singh - MSFT Sep 30 '15 at 04:57
  • I think you have written code in `longClickListener()` to record a video and you may not have written `onTouch()` method, write `onTouch()` method with ACTION_UP and ACTION_CANCEL to release `mediaRecorder` when long click event ends, show your code though – Apurva Sep 30 '15 at 04:59
  • When I start at first, recording, stop. It's ok but when I press start again. It's crash – Nguyen Khoi Sep 30 '15 at 07:03
  • Ca you please show your Camera preview class, because i am facing problem in my project because of Camera Preview Class – Sarbjyot Nov 19 '16 at 06:09

2 Answers2

5

You can do achieve this functionality by setting OnLongClickListener() and OnTouchListener() on your record button. Like this:

recordBtn.setOnLongClickListener(recordBtnLCListener);
recordBtn.setOnTouchListener(recordBtnTouchListener);

then :

@Override
public boolean onLongClick(View v) {
    ivCancel.setVisibility(View.GONE);
    ivDone.setVisibility(View.GONE);
    isActionDown = true;
    try {
        if (isActionDown) {
            initRecorder();
            if (isActionDown)
                prepareRecorder();
        }
        if (isPrepared && isActionDown) {
            mMediaRecorder.start();
            isRecording = true;
        }
    } catch (Exception e) {
        e.printStackTrace();
        Log.e("onLongPress Error ", e.toString());
    }

    return true;
}

and :

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_UP:
            isActionDown = false;

            try {
                if (isRecording) {

                    if (mMediaRecorder != null) {
                        mMediaRecorder.stop();
                    }
                    isRecording = false;
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            break;
    }
    return false;
}

So, in this way you can record the parts of video.Means each time you LongPress your record button, the recording starts. And time you release the button, the recording stops and here you have to save this part of video in any temporary folder. Once you done taking all parts of videos as many as you want, then you have to combine all that parts of videos to make a single video.

Here, is the code to merge all that video parts saved in temperory folder:

public void mergeVideos() {
    try {
        List<Movie> inMovies = new ArrayList<>();
        for (int i = 0; i < videosPathList.size(); i++) {
            String filePath = videosPathList.get(i);
            try {
                Movie movie = MovieCreator.build(filePath);
                if (movie != null)
                    inMovies.add(movie);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        List<Track> videoTracks = new LinkedList<Track>();
        List<Track> audioTracks = new LinkedList<Track>();
        for (Movie m : inMovies) {
            for (Track t : m.getTracks()) {
                try {
                    if (t.getHandler().equals("soun")) {
                        audioTracks.add(t);
                    }
                    if (t.getHandler().equals("vide")) {
                        videoTracks.add(t);
                    }
                } catch (Exception e) {

                }
            }
        }
        Movie result = new Movie();
        if (audioTracks.size() > 0) {
            result.addTrack(new AppendTrack(audioTracks
                    .toArray(new Track[audioTracks.size()])));
        }
        if (videoTracks.size() > 0) {
            result.addTrack(new AppendTrack(videoTracks
                    .toArray(new Track[videoTracks.size()])));
        }
        BasicContainer out = (BasicContainer) new DefaultMp4Builder().build(result);
        File f = null;
        String finalVideoPath;
        try {
            f = setUpVideoFile(Environment
        .getExternalStorageDirectory()+"/MyApp/videos/");
            finalVideoPath = f.getAbsolutePath();

        } catch (IOException e) {
            e.printStackTrace();
            f = null;
            finalVideoPath = null;
        }
        WritableByteChannel fc = new RandomAccessFile(finalVideoPath, "rw").getChannel();
        out.writeContainer(fc);
        fc.close();
        deleteFilesDir(); //In this method you have to delete all parts of video stored in temporary folder.


    } catch (Exception e) {
        e.printStackTrace();
       progressDialog.dismiss();
        finish();
    }
}

File setUpVideoFile(String directory) throws IOException {
    File videoFile = null;
    if (Environment.MEDIA_MOUNTED.equals(Environment
            .getExternalStorageState())) {
        File storageDir = new File(directory);
        if (storageDir != null) {
            if (!storageDir.mkdirs()) {
                if (!storageDir.exists()) {
                    Log.d("CameraSample", "failed to create directory");
                    return null;
                }
            }
        }
        videoFile = File.createTempFile("video_"
                        + System.currentTimeMillis() + "_",
                .mp4, storageDir);
    }
    return videoFile;
}

You can call mergeVideos() method after stopping mediaRecorder.

Hope this code helps you. :)

For merging the videos you have to use the isoparser library. So you have to add following dependendy in your gradle file :

compile 'com.googlecode.mp4parser:isoparser:1.0.5.4'
Er.Rohit Sharma
  • 696
  • 5
  • 21
  • Wow! I haven't tried your code yet but so cool. Thanks for your supporting. I'm gonna try it and tell you later. – Nguyen Khoi Sep 30 '15 at 07:00
  • Sure:) It will definitely work @Ngyyen koi. Just implement it carefully because handling camera and media recirder is not an easy task – Er.Rohit Sharma Sep 30 '15 at 07:03
  • I edited my code above. Please check again. It didn't record any video – Nguyen Khoi Sep 30 '15 at 10:47
  • 1
    Try start media recorder without running it on the UI thread... And please follow the steps to use media recorder carefully. Please refer to http://developer.android.com/guide/topics/media/camera.html – Er.Rohit Sharma Sep 30 '15 at 11:08
  • Hi Er.Rohit Sharma, I made it. But if the video's length is <10s it cannot be recorded. Do you have any suggestion? – Nguyen Khoi Oct 01 '15 at 04:04
  • How can i suggest you with seeing the code? And also how it is possible that your code is working for the videos more than 10 secs but not for less than 10 secs. And please implement some progress bar or timer on the start and stop of recording, so that you can easily find out if the recording starts or not. – Er.Rohit Sharma Oct 01 '15 at 04:17
  • It seems android is must be prepared and after recording more than 10s the video file can be played. – Nguyen Khoi Oct 01 '15 at 04:58
  • I have done it. But I can not deal with merge code, is it native code or any lib? – Nguyen Khoi Oct 02 '15 at 03:03
  • Great !!!. And sorry, i forgot to post the dependency for merging the videos. Yes, for merging the video IsoParser library is used. I have edit my code with the isoparser dependency. Please add that in your gradle file to use mergeVideo() code. – Er.Rohit Sharma Oct 03 '15 at 04:33
  • I try your code but it throws an error java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.coremedia.iso.boxes.MovieBox.getBoxes(java.lang.Class)' on a null object reference Although I check the path and it has files already. – Nguyen Khoi Oct 05 '15 at 01:09
  • I have edited my code again. setUpVideoPath() method will help you to get the path where you want to store your video file. – Er.Rohit Sharma Oct 05 '15 at 04:43
  • I think the problem is not about the path because I can get it with File.getPath() method – Nguyen Khoi Oct 05 '15 at 07:13
  • It crashes at this line Movie movie = MovieCreator.build(filePath); – Nguyen Khoi Oct 05 '15 at 07:25
  • Then i think you are passing the wrong filePath to Movie movie = MovieCreator.build(filePath); .In this, you have to pass the path of each part of video one by one. So you can store path of all the parts of videos in an arrayList (say videoPathList in my code)on the time when new part start recording. – Er.Rohit Sharma Oct 05 '15 at 07:36
  • can u provide this on demo if u have ? – Drim Mar 10 '16 at 16:03
1

This is my code.

public class VideoRecordingActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {
MediaRecorder recorder;
SurfaceHolder holder;
boolean recording = false;
private boolean isPrepared = false;
int videoNumber = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    super.onCreate(savedInstanceState);

    recorder = new MediaRecorder();
    initRecorder();
    setContentView(R.layout.activity_video_introduction_recording);

    SurfaceView cameraView = (SurfaceView) findViewById(R.id.ln_body_recording);
    holder = cameraView.getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    cameraView.setClickable(true);
    cameraView.setOnClickListener(this);
}

private void initRecorder() {
    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "CameraSample");

    recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
    CamcorderProfile cpHigh = CamcorderProfile
            .get(CamcorderProfile.QUALITY_HIGH);
    recorder.setProfile(cpHigh);
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
    //CGlobal.VIDEO_RECORD_PATH = CGlobal.VIDEO_HOME_PATH + "VID_" + timeStamp;
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "VID_"+ timeStamp + ".mp4");

    recorder.setOutputFile(mediaFile+".mp4");
    recorder.setMaxDuration(50000); // 50 seconds
    recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
}

private void prepareRecorder() {
    recorder.setPreviewDisplay(holder.getSurface());
    try {
        recorder.prepare();
        isPrepared = true;
    } catch (IllegalStateException e) {
        e.printStackTrace();
        finish();
    } catch (IOException e) {
        e.printStackTrace();
        finish();
    }
}

public void onClick(View v) {
    if (recording) {
        recorder.stop();
        recording = false;
        isPrepared = false;
        videoNumber++;
        // Let's initRecorder so we can record again
    } else {
        if (!isPrepared){
            initRecorder();
            prepareRecorder();
        }
        recording = true;
        recorder.start();
    }
}

public void surfaceCreated(SurfaceHolder holder) {
    prepareRecorder();
}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
                           int height) {
}

public void surfaceDestroyed(SurfaceHolder holder) {
    if (recording) {
        recorder.stop();
        recording = false;
    }
    recorder.release();
    finish();
    }
}
Md Imran Choudhury
  • 9,343
  • 4
  • 62
  • 60
Nguyen Khoi
  • 110
  • 1
  • 8