保存录制的手机屏幕

时间:2015-02-10 23:35:34

标签: android android-mediaprojection

我尝试使用MediaProjection在Android 5.0 Lollipop中录制手机屏幕并保存录制的视频。

我尝试了此代码,但在我将saveFile(uri)添加到onActivityResult后,应用程序在开始录制时崩溃了。

获取录制视频和保存视频的正确方法是什么?

   public class MainActivity extends Activity {
        private static final String TAG = "MediaProjectionDemo";
        private static final int PERMISSION_CODE = 1;
        private static final List<Resolution> RESOLUTIONS = new ArrayList<Resolution>() {{
            add(new Resolution(640,360));
            add(new Resolution(960,540));
            add(new Resolution(1366,768));
            add(new Resolution(1600,900));
        }};

        private int mScreenDensity;
        private MediaProjectionManager mProjectionManager;

        private int mDisplayWidth;
        private int mDisplayHeight;
        private boolean mScreenSharing;

        private MediaProjection mMediaProjection;
        private VirtualDisplay mVirtualDisplay;
        private Surface mSurface;
        private SurfaceView mSurfaceView;

        @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;

            mSurfaceView = (SurfaceView) findViewById(R.id.surface);
            mSurface = mSurfaceView.getHolder().getSurface();
            mProjectionManager =
                    (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

            ArrayAdapter<Resolution> arrayAdapter = new ArrayAdapter<Resolution>(
                    this, android.R.layout.simple_list_item_1, RESOLUTIONS);
            Spinner s = (Spinner) findViewById(R.id.spinner);
            s.setAdapter(arrayAdapter);
            s.setOnItemSelectedListener(new ResolutionSelector());
            s.setSelection(0);
        }

        @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,
                        "User denied screen sharing permission", Toast.LENGTH_SHORT).show();
                return;
            }

            try {
                java.net.URI uri = new java.net.URI(data.getData().toString());
                saveFile(uri);

            } catch (URISyntaxException e) {
                e.printStackTrace();
            }

            mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
            mVirtualDisplay = createVirtualDisplay();
        }

        void saveFile(URI sourceUri)
        {
            String sourceFilename= sourceUri.getPath();
            String destinationFilename = android.os.Environment.getExternalStorageDirectory().getPath()+ File.separatorChar+"abc.mp4";

            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;

            try {
                bis = new BufferedInputStream(new FileInputStream(sourceFilename));
                bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false));
                byte[] buf = new byte[1024];
                bis.read(buf);
                do {
                    bos.write(buf);
                } while(bis.read(buf) != -1);
            } catch (IOException e) {

            } finally {
                try {
                    if (bis != null) bis.close();
                    if (bos != null) bos.close();
                } catch (IOException e) {

                }
            }
        }

        public void onToggleScreenShare(View view) {
            if (((ToggleButton) view).isChecked()) {
                shareScreen();
            } else {
                stopScreenSharing();
            }
        }

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

        private void stopScreenSharing() {
            mScreenSharing = false;
            if (mVirtualDisplay == null) {
                return;
            }
            mVirtualDisplay.release();
        }

        private VirtualDisplay createVirtualDisplay() {
            return mMediaProjection.createVirtualDisplay("ScreenSharingDemo",
                    mDisplayWidth, mDisplayHeight, mScreenDensity,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    mSurface, null /*Callbacks*/, null /*Handler*/);
        }

        private void resizeVirtualDisplay() {
            if (mVirtualDisplay == null) {
                return;
            }
            mVirtualDisplay.resize(mDisplayWidth, mDisplayHeight, mScreenDensity);
        }

        private class ResolutionSelector implements Spinner.OnItemSelectedListener {
            @Override
            public void onItemSelected(AdapterView<?> parent, View v, int pos, long id) {
                Resolution r = (Resolution) parent.getItemAtPosition(pos);
                ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
                if (getResources().getConfiguration().orientation
                        == Configuration.ORIENTATION_LANDSCAPE) {
                    mDisplayHeight = r.y;
                    mDisplayWidth = r.x;
                } else {
                    mDisplayHeight = r.x;
                    mDisplayWidth = r.y;
                }
                lp.height = mDisplayHeight;
                lp.width = mDisplayWidth;
                mSurfaceView.setLayoutParams(lp);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) { /* Ignore */ }
        }

        private class MediaProjectionCallback extends MediaProjection.Callback {
            @Override
            public void onStop() {
                mMediaProjection = null;
                stopScreenSharing();
            }
        }

        private class SurfaceCallbacks implements SurfaceHolder.Callback {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                mDisplayWidth = width;
                mDisplayHeight = height;
                resizeVirtualDisplay();
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                mSurface = holder.getSurface();
                if (mScreenSharing) {
                    shareScreen();
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (!mScreenSharing) {
                    stopScreenSharing();
                }
            }
        }

        private static class Resolution {
            int x;
            int y;

            public Resolution(int x, int y) {
                this.x = x;
                this.y = y;
            }

            @Override
            public String toString() {
                return x + "x" + y;
            }
        }
    }

logcat的:

    java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {com.name.name/com.name.name.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
            at android.app.ActivityThread.deliverResults(ActivityThread.java:3539)
            at android.app.ActivityThread.handleSendResult(ActivityThread.java:3582)
            at android.app.ActivityThread.access$1300(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            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:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
            at com.name.name.MainActivity.onActivityResult(MainActivity.java:103) // java.net.URI uri = new java.net.URI(data.getData().toString());
            at android.app.Activity.dispatchActivityResult(Activity.java:6135)
            at android.app.ActivityThread.deliverResults(ActivityThread.java:3535)
            at android.app.ActivityThread.handleSendResult(ActivityThread.java:3582)
            at android.app.ActivityThread.access$1300(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            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:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

1 个答案:

答案 0 :(得分:0)

当您致电startActivityOnResult时,它会在设备上显示确认对话框。对此对话框做出反应后,将调用onActivityResult。如果resultCode == RESULT_OK,并不意味着您开始录制,则仅表示您已获得捕获屏幕的权限(将屏幕镜像到您的活动中)。

您现在需要做的是使用MediaRecorder开始在您的活动表面录制视频。