簡體   English   中英

MediaRecorder.GetSurface() 返回 null

[英]MediaRecorder.GetSurface() returning null

我在我的 Nexus 5 上使用此代碼進行屏幕錄制,該 Nexus 5 運行 6.0.1,帶有 7 月安全更新。 屏幕錄制在運行 5.0.1、6.0、6.0.1 的其他設備上工作正常,但它在我的手機上不起作用。 當我嘗試開始屏幕錄制時出現以下錯誤。

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)

無法獲取用於屏幕錄制的 Surface。 是什么原因造成的,我該如何解決?

源代碼:

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

最好的祝福

這與這個問題基本相同。 我也面臨這個問題。 奇怪的是它只發生在 Marshmallow 上,在 Lollipop 上它確實有效。

文檔說:

表面getSurface()

只能在准備后調用。 在開始之前渲染到 Surface 的幀將被丟棄。 拋出:
IllegalStateException - 如果准備之前、停止之后調用,或者在 VideoSource 未設置為 SURFACE 時調用。

但在 Mediarecorder.java 中,它是:

如果{@link #prepare} 之后和 {@link #stop} 之前調用 @throws IllegalStateException。

但是,我將它放在prepare()之前還是之后並沒有什么區別,兩者都不起作用。 盡管上述情況都不適用,但它拋出IllegalStateException真的很奇怪。

但是,Matt Snider 的這個解決方案確實適用於 Marshmallow。 但是由於 IMO 更加困難(尤其是在嘗試錄制音頻時),因此讓它也與MediaRecorder運行會MediaRecorder

如果有人想重現該問題,只需使用代碼並在 Marshmallow 機器上運行它。

我嘗試了上述所有答案,但仍然出現相同的錯誤。 經過一個下午的調試,我找到了原因,如果您在上面的這些答案中也沒有得到解決方案。 那么你可以試試我的解決方案。 我發現當我將 DISPLAY_WIDTH 替換為較小的數字,例如 1024 時,它起作用了。 這是我的代碼:

mediaRecorder.setVideoSize(2048, 1024);

此代碼將工作!

 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();
}
      }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM