Запись скриншота java на Android - PullRequest
       102

Запись скриншота java на Android

0 голосов
/ 06 декабря 2018

У меня есть следующий код, который позволяет записывать то, что происходит на экране.

Это работает, но есть некоторые проблемы и непредвиденные события, которые происходят, и я не понимаю, какой набор ситуаций позволяет этому приложениюдо сбоя.

Чтобы решить одну из проблем, выполните следующие действия:

  • Нажмите кнопку запуска
  • Начать запись
  • Нажмите кнопку остановки
  • Подождите несколько секунд
  • Нажмите кнопку запуска еще раз

Ошибка:

E/MediaRecorder: SurfaceMediaSource could not be initialized!
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.app, PID: 4465
    java.lang.IllegalStateException: failed to get surface
        at android.media.MediaRecorder.getSurface(Native Method)
        at com.app.MainActivity2.getVirtualDisplay(MainActivity2.java:170)
        at com.app.MainActivity2.startRecording(MainActivity2.java:71)
        at com.app.MainActivity2.access$100(MainActivity2.java:23)
        at com.app.MainActivity2$1.onClick(MainActivity2.java:47)....

Манифест:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Код:

package com.app;

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.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

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

public class MainActivity2 extends AppCompatActivity {

    private static final int CAST_PERMISSION_CODE = 22;
    private DisplayMetrics mDisplayMetrics;
    private MediaProjection mMediaProjection;
    private VirtualDisplay mVirtualDisplay;
    private MediaRecorder mMediaRecorder;
    private MediaProjectionManager mProjectionManager;

    private boolean startRec = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        mDisplayMetrics = new DisplayMetrics();
        mMediaRecorder = new MediaRecorder();
        mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);

        Button start = (Button) findViewById(R.id.start);
        start.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (!startRec) startRecording();
            }
        });

        Button stop = (Button) findViewById(R.id.stop);
        stop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (startRec) stopRecording();
            }
        });
    }

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

    private void stopRecording() {
        startRec = false;
        Log.w("class:", "stopRecording:start");
        if (mMediaRecorder != null) {
            mMediaRecorder.stop();
            mMediaRecorder.reset();
            //mMediaRecorder = null;
        }
        if (mVirtualDisplay != null) {
            mVirtualDisplay.release();
            //mVirtualDisplay = null;
        }
        if (mMediaProjection != null) {
            mMediaProjection.stop();
            //mMediaProjection = null;
        }
        Log.w("class:", "stopRecording:end");
    }

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

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

        String videoName = (name + "_" + getCurSysDate() + ".mp4");
        String filePath = directory + File.separator + videoName;

        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(8000 * 1000);
        mMediaRecorder.setVideoFrameRate(24);
        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) {
        if (requestCode != CAST_PERMISSION_CODE) {
            // Where did we get this request from ? -_-
            Log.w("class:", "Unknown request code: " + requestCode);
            return;
        }
        Log.w("class:", "onActivityResult:resultCode");
        if (resultCode != RESULT_OK) {
            startRec = false;
            Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
            return;
        }
        prepareRecording("start");
        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);

        Log.w("class:", "onActivityResult:mMediaProjection");

        // 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*/);
    }

}

XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start" />

    <Button
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop" />
</LinearLayout>
...