Android Record Video from SURFACEVIEW using MediaRecorder

11,685

Solution 1

You can't record from a SurfaceView. When you play video to a SurfaceView, the frames are being sent to a Surface, which is a queue of buffers with a producer-consumer interface. The app only has access to the producer end -- the system graphics compositor (SurfaceFlinger) is the consumer.

What you need to do is play the video twice, once for presentation and once for recording. Decoding the same video stream twice would be inefficient, so you want to render each decoded frame twice. I haven't done this with MediaRecorder, so I'll offer up two approaches.

Approach #1: the easy way? Instead of sending the video to the SurfaceView's Surface, put the MediaRecorder into SURFACE input mode, and pass its input Surface (obtained from getSurface()) to the player. Then, call the MediaRecorder's setPreviewDisplay with the SurfaceView's Surface. In theory that should give you a "preview" of the video as you're recording it.

Approach #2: run the video through a SurfaceTexture. The SurfaceTexture's Surface has both producer and consumer interfaces in the app, so you can access the generated frames.

This does involve a bit of work with OpenGL ES. The basic steps are:

  1. Create a SurfaceTexture in a new EGL context.
  2. Direct the output of your video player to the SurfaceTexture rather than the SurfaceView.
  3. Get the Surface from the SurfaceView (for display), and the Surface from the MediaRecorder (for recording). The latter comes from getSurface().
  4. As each frame becomes available from the SurfaceTexture, render it to both Surfaces.

This approach is considerably more work, but is more flexible, allowing manipulation of the image before display and/or recording. Some examples that use the lower-level MediaCodec, rather than MediaRecorder, can be found in Grafika.

Solution 2

For programmers have problems with recording I solved using Mediacodec api with yuvimages obtained by onpreviewframe and ffmpeg.

Share:
11,685
AV Engineer
Author by

AV Engineer

I am software engineer

Updated on June 11, 2022

Comments

  • AV Engineer
    AV Engineer about 2 years

    I am new here.

    I have an app in android that streams camera over network and has a surfaceView component to show the preview(what I am streaming).

    I'd like to record what I see in preview(surfaceview) without reopen camera, because it is just opened from streaming.

    In lollipop I saw you can record using MediaRecorder api and setting the video source to SURFACE.

    How can I record simply adding a new MediaRecorder object that record from surface. Suppose you have all stuff setting, the app works and streams, showing preview in surfaceview component. I 'd like define a new recorder with the source set to surfaceview.

    Thanks

    EDIT:

    Hi, I have tryied to record using this code:

    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setOutputFile(getVideoFile(activity, true).getAbsolutePath());
    mMediaRecorder.setVideoEncodingBitRate(10000000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
    int orientation = ORIENTATIONS.get(rotation);
    mMediaRecorder.setOrientationHint(orientation);
    mMediaRecorder.prepare();
    

    Consider you have the app that open the camera and stream out network and show preview in surfaceView. I want add a new mediarecorder that record what is in surfaceview.