简体   繁体   中英

MediaRecorder.GetSurface() returning null

I am using this code for Screen Recording on my Nexus 5 running 6.0.1 with July Security Update. The screen recording works fine on other devices running 5.0.1, 6.0, 6.0.1 however it's not working on my phone. It gives me the following error when I try to start screen recording.

E/MediaRecorder: SurfaceMediaSource could not be initialized!
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1995, result=-1, data=Intent { (has extras) }} to activity {MainActivity}: java.lang.IllegalStateException: failed to get surface
at android.app.ActivityThread.deliverResults(ActivityThread.java:3699)
Caused by: java.lang.IllegalStateException: failed to get surface
at android.media.MediaRecorder.getSurface(Native Method)

It's failing to get Surface for screen recording. What's causing this and how can I resolve this?

Source Code:

 public static MediaProjectionManager getmMediaProjectionManager(final MainActivity context) {
        DisplayMetrics metrics = new DisplayMetrics();
        context.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        mScreenDensity = metrics.densityDpi;
        DISPLAY_HEIGHT = metrics.heightPixels;
        DISPLAY_WIDTH = metrics.widthPixels;
        mMediaRecorder = new MediaRecorder();

        mMediaProjectionManager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        return mMediaProjectionManager;
    }

    @TargetApi(21)
    public static void startScreenRecording(Intent data) {
        mMediaProjectionCallback = new MediaProjectionCallback();
        initRecorder(null);
        mMediaProjection = mMediaProjectionManager.getMediaProjection(RESULT_OK, data);
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);
        mVirtualDisplay = createVirtualDisplay();
        mMediaRecorder.start();
    }

    @TargetApi(21)
    private static VirtualDisplay createVirtualDisplay() {
        return mMediaProjection.createVirtualDisplay("MainActivity",
                DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.getSurface(), null /*Callbacks*/, null
                /*Handler*/);
    }

    @TargetApi(21)
    private static void initRecorder(MainActivity context) {
        try {
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mMediaRecorder.setOutputFile(Environment
                    .getExternalStorageDirectory() + "/video"+ System.currentTimeMillis()+".mp4");
            mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setVideoEncodingBitRate(VIDEO_ENCODING_BITRATE);
            mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
            mMediaRecorder.prepare();
        } catch (Exception e) {
            Log.e("Util", e.getLocalizedMessage());
        }
    }

    @TargetApi(21)
    private static class MediaProjectionCallback extends MediaProjection.Callback {
        @Override
        public void onStop() {

        }
    }

    @TargetApi(21)
    public static void stopScreenSharing() {
        mMediaRecorder.stop();
        mMediaRecorder.reset();
        if (mVirtualDisplay == null) {
            return;
        }

        mVirtualDisplay.release();

        destroyMediaProjection();
    }

    @TargetApi(21)
    private static void destroyMediaProjection() {
        if (mMediaProjection != null) {
            Log.e(TAG, "destroying projection");
            mMediaProjection.unregisterCallback(mMediaProjectionCallback);
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }

Best Regards

This is basically the same question as this one . I'm also facing this problem. The strange thing is that it happens only on Marshmallow , on Lollipop it does work.

The documentaion says:

Surface getSurface ()

May only be called after prepare. Frames rendered to the Surface before start will be discarded. Throws:
IllegalStateException - if it is called before prepare, after stop, or is called when VideoSource is not set to SURFACE.

But in Mediarecorder.java, it is:

@throws IllegalStateException if it is called after {@link #prepare} and before {@link #stop}.

However it doesn't make a difference whether I'm placing it before or after prepare() , both does not work. It's really weird that it throws an IllegalStateException although none of the above things apply.

However, this solution from Matt Snider does work on Marshmallow. But since it is more difficult IMO (especially when trying to record audio as well) it would be great to get it also running with MediaRecorder .

If someone wants to reproduce the problem just use this or this code and run it on a Marshmallow machine.

I tried all the answers above, But I still got the same error. After an afternoon of debugging, I got the reason, If you also didn't get a solution in these answer above. then you can try my solution. I found when I replace DISPLAY_WIDTH to a smaller number, such as 1024, then it's worked。 Here is my code:

mediaRecorder.setVideoSize(2048, 1024);

This code will work !!

 package com.example.signeyweb.TestingPackage;
 import static android.content.ContentValues.TAG;
 import android.content.Context;     
 import android.content.Intent;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.media.MediaRecorder;
 import android.media.projection.MediaProjection;
 import android.media.projection.MediaProjectionManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;

 import androidx.appcompat.app.AppCompatActivity;

 import com.example.signeyweb.R;

 import java.io.File;
 import java.text.SimpleDateFormat;
 import java.util.Date;

 public class TestingTwoActivity extends AppCompatActivity {
private static final int CAST_PERMISSION_CODE = 22;
public DisplayMetrics mDisplayMetrics  = new DisplayMetrics();
public MediaProjection mMediaProjection;
public VirtualDisplay mVirtualDisplay;
public MediaRecorder mMediaRecorder;
MediaProjectionManager mProjectionManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_testing_two);
    mMediaRecorder = new MediaRecorder();

    mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

    mDisplayMetrics = getApplicationContext().getResources().getDisplayMetrics();


    prepareRecording();
}

private void startRecording() {
    // If mMediaProjection is null that means we didn't get a context, lets ask the user
    if (mMediaProjection == null) {
        // This asks for user permissions to capture the screen
        startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
        return;
    }
    mVirtualDisplay = getVirtualDisplay();
    mMediaRecorder.start();
}

private void stopRecording() {
    if (mMediaRecorder != null) {
        mMediaRecorder.stop();
        mMediaRecorder.reset();
    }
    if (mVirtualDisplay != null) {
        mVirtualDisplay.release();
    }
    if (mMediaProjection != null) {
        mMediaProjection.stop();
    }
    prepareRecording();
}

public String getCurSysDate() {
    return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
}

private void prepareRecording() {


    final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
    if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
        Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
        return;
    }
    final File folder = new File(directory);
    boolean success = true;
    if (!folder.exists()) {
        success = folder.mkdir();
    }
    String filePath;
    if (success) {
        String videoName = ("capture_" + getCurSysDate() + ".mp4");
        filePath = directory + File.separator + videoName;
    } else {
        Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
        return;
    }

    int width = mDisplayMetrics.widthPixels;
   int height = mDisplayMetrics.heightPixels;

    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(width, height);
    mMediaRecorder.setOutputFile(filePath);
    try {
        mMediaRecorder.prepare();
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode != CAST_PERMISSION_CODE) {
        // Where did we get this request from ? -_-
        Log.w(TAG, "Unknown request code: " + requestCode);
        return;
    }
    if (resultCode != RESULT_OK) {
        Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
        return;
    }
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    // TODO Register a callback that will listen onStop and release & prepare the recorder for next recording
    // mMediaProjection.registerCallback(callback, null);
    mVirtualDisplay = getVirtualDisplay();
    mMediaRecorder.start();
}

private VirtualDisplay getVirtualDisplay() {
    int screenDensity = mDisplayMetrics.densityDpi;
    int width = mDisplayMetrics.widthPixels;
    int height = mDisplayMetrics.heightPixels;

    return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
            width, height, screenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}

public void startrecording(View view) {
    startRecording();
}

public void stoprecordingg(View view) {
    stopRecording();
}
      }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM