Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I test screen record in emulator in Android Studio?

Tags:

android

I try to test a sample code about screen record from below link, I modified some code to disable recording audio.

http://www.truiton.com/2015/05/capture-record-android-screen-using-mediaprojection-apis/

I test the code in Android Studio V1.3, but I get the following error, and the file capture.mp4 is blank.

I'm not sure whether I must test the code in real mobile phone? Could you help me ? Thanks!

Error Info

09-22 06:41:50.250    2167-2167/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: screencapture.truiton.com.myapplication, PID: 2167
    java.lang.RuntimeException: stop failed.
            at android.media.MediaRecorder.stop(Native Method)
            at screencapture.truiton.com.myapplication.MainActivity.onToggleScreenShare(MainActivity.java:93)
            at screencapture.truiton.com.myapplication.MainActivity$1.onClick(MainActivity.java:55)
            at android.view.View.performClick(View.java:4780)
            at android.widget.CompoundButton.performClick(CompoundButton.java:120)
            at android.view.View$PerformClick.run(View.java:19866)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Source Code

package screencapture.truiton.com.myapplication;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    private static final int PERMISSION_CODE = 1;
    private int mScreenDensity;
    private MediaProjectionManager mProjectionManager;
    private static final int DISPLAY_WIDTH = 480;
    private static final int DISPLAY_HEIGHT = 640;
    private MediaProjection mMediaProjection;
    private VirtualDisplay mVirtualDisplay;
    private MediaProjectionCallback mMediaProjectionCallback;
    private ToggleButton mToggleButton;
    private MediaRecorder mMediaRecorder;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        mScreenDensity = metrics.densityDpi;

        mMediaRecorder = new MediaRecorder();
        initRecorder();
        prepareRecorder();

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

        mToggleButton = (ToggleButton) findViewById(R.id.toggle);
        mToggleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onToggleScreenShare(v);
            }
        });

        mMediaProjectionCallback = new MediaProjectionCallback();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mMediaProjection != null) {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode != PERMISSION_CODE) {
            Log.e(TAG, "Unknown request code: " + requestCode);
            return;
        }
        if (resultCode != RESULT_OK) {
            Toast.makeText(this,
                    "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show();
            mToggleButton.setChecked(false);
            return;
        }
        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);
        mVirtualDisplay = createVirtualDisplay();
        mMediaRecorder.start();
    }

    public void onToggleScreenShare(View view) {
        if (((ToggleButton) view).isChecked()) {
            shareScreen();
        } else {
            mMediaRecorder.stop();
            mMediaRecorder.reset();
            Log.v(TAG, "Recording Stopped");
            stopScreenSharing();
            initRecorder();
            prepareRecorder();
        }
    }

    private void shareScreen() {
        if (mMediaProjection == null) {
            startActivityForResult(mProjectionManager.createScreenCaptureIntent(), PERMISSION_CODE);
            return;
        }
        mVirtualDisplay = createVirtualDisplay();
        mMediaRecorder.start();
    }

    private void stopScreenSharing() {
        if (mVirtualDisplay == null) {
            return;
        }
        mVirtualDisplay.release();
        //mMediaRecorder.release();
    }

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

    private class MediaProjectionCallback extends MediaProjection.Callback {
        @Override
        public void onStop() {
            if (mToggleButton.isChecked()) {
                mToggleButton.setChecked(false);
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                Log.v(TAG, "Recording Stopped");
                initRecorder();
                prepareRecorder();
            }
            mMediaProjection = null;
            stopScreenSharing();
            Log.i(TAG, "MediaProjection Stopped");
        }
    }

    private void prepareRecorder() {
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            e.printStackTrace();
            finish();
        } catch (IOException e) {
            e.printStackTrace();
            finish();
        }
    }

    private void initRecorder() {

        //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(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        mMediaRecorder.setOutputFile(Environment.getExternalStorageDirectory() + "/capture.mp4");
    }
}
like image 294
HelloCW Avatar asked Sep 22 '15 07:09

HelloCW


People also ask

How to record screen from Android emulator?

Now you can also record video from Android emulator to follow below option: Then select Record screen option. Show activity on this post. You will find the record icon at the bottom left corner. If you are using an AVD, make sure "Use host GPU" is disabled.

How to use Android Studio screen record in your project?

How to use Android Studio screen record in your project. 1- Open up any project that you have in Android Studio and then click on Logcat. Android Studio Logcat tab. (Large preview) Note: Please make sure that you have an emulator running or you have your physical device connected your computer to be able to record.

Should you test your Android app on an emulator?

Testing your app on the emulator is in some ways faster and easier than doing so on a physical device. For example, you can transfer data faster to the emulator than to a device connected over USB. The emulator comes with predefined configurations for various Android phone, tablet, Wear OS, and Android TV devices.

How do I run the emulator in Android Studio?

To run the emulator in Android Studio, make sure you're using Android Studio 4.1 or higher with version 30.0.10 or higher of the Android Emulator, then follow these steps: Click File > Settings > Tools > Emulator (or Android Studio > Preferences > Tools > Emulator on macOS), then select Launch in a tool window and click OK.


1 Answers

From my experience, Android emulators do allow reading from surfaces (which is the only thing really required for recording) but fail to encode video (and sometimes take screenshots) due to bugs/limitations in framework Java code. There are two primary reasons:

  • The emulator may not declare support for EGL_ANDROID_recordable extension, which is demanded by MediaRecorder/MediaCodec. You can check for the extension support by executing following command:

    adb shell dumpsys SurfaceFlinger | grep EGL_ANDROID_recordable
    
  • The only color format, supported by Android 6 builtin software encoder, is YUV. Video buffers, coming from emulator GPU, are likely to have different format.

Note, that above limitations aren't exclusive to emulator and may cause failures on actual devices as well. You can work around them by doing format conversion in software (on CPU or via GLES), using approach outlines in this answer, but the performance of software encoder is going to be abysmal either way.

like image 61
user1643723 Avatar answered Sep 29 '22 14:09

user1643723