当前位置: 首页 > 知识库问答 >
问题:

MediaRecorder.GetSurface()返回null

孔经武
2023-03-14

我正在将此代码用于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)

它无法获得屏幕录制的表面。这是什么原因造成的,我该如何解决?

源代码:

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

此致敬意

共有3个答案

薛承志
2023-03-14

这个代码会工作的!!

 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();
}
      }
陶星渊
2023-03-14

我尝试了上面的所有答案,但我仍然得到同样的错误。经过一个下午的调试,我得到了原因,如果你在上面的这些答案中也没有得到解决方案。然后你可以试试我的解决方案。我发现当我将DISPLAY_WIDTH替换为较小的数字时,例如1024,那么它就起作用了。这是我的代码

mediaRecorder.setVideoSize(2048, 1024);
邓毅
2023-03-14

这与这个问题基本相同。我也面临着这个问题。奇怪的是,它只在Marshmallow上发生,在Lollipop上确实有效。

文件说:

表面获取表面 ()

只能在准备后才能打电话。在开始之前渲染到表面的帧将被丢弃。抛出:
非法状态异常 - 如果在准备之前、停止之后调用它,或者在视频源未设置为 SURFACE 时调用它。

但在Mediarecorder中。java,它是:

如果在{@link #prepare}之后和{@link #stop}之前调用,@将引发IllegalStateException。

但是,无论我把它放在preset()之前还是之后都没有区别,两者都不起作用。奇怪的是,它抛出了一个非法状态异常,尽管上述所有事情都不适用。

但是,马特·斯奈德的这个解决方案确实适用于Marshmallow。但是,由于IMO更加困难(尤其是在尝试录制音频时),因此最好也能与MediaRecorder一起运行它。

如果有人想重现问题,只需使用这个或这个代码,并在Marshmallow机器上运行它。

 类似资料:
  • 问题内容: 例如我有一个功能: 我怎样才能返回AJAX后得到的? 问题答案: 因为请求是异步的,所以您无法返回ajax请求的结果(而同步ajax请求是一个 糟糕的 主意)。 最好的选择是将自己的回调传递给f1 然后,您将像这样致电:

  • 我有两个活动和两个布局。当我在第一个活动中显示列表时,一切都正常,并在单击时给出列表中项目的编号,但当我尝试在第二个活动中重复相同的内容时,它会告诉我RecycleServiceClickListener侦听器为空。 适配器: 第一项活动: 第二项活动: 错误: 我不明白为什么在第一种情况下,它正常处理单击,而在第二种情况下,它说RecyclerViewClickListener为null

  • 问题内容: 我在使用Ajax时遇到问题。 问题是,在获得ajax响应之前,它会返回cnt。因此它总是返回NULL。 有没有办法使正确的返回响应值? 谢谢! 问题答案: 由于AJAX请求是异步的,因此您的cnt变量将在请求返回并调用成功处理程序之前返回。 我建议重构您的代码以解决此问题。 一种方法是从AJAX请求的成功处理程序中调用调用了GetGrantAmazonItemCnt()的任何函数,此方

  • 我想在下面返回JSON。 {“名字”:“杰基”} 新来的春靴在这里。1天大。有没有合适的方法可以做到这一点?

  • 加载样式表,并在用户单击按钮时将其应用于场景 调用getScene()返回null。 函数所在的类是场景的控制器和根节点,我使用SceneBuilder 2.0,并将类设置为加载fxml的控制器,它是一个。 问题代码是类中的一个成员函数,标记是这样的,我可以通过设置按钮来调用它。 完整的代码可以在https://github.com/SebastianTroy/FactorioManufactur

  • 问题内容: 我创建了一个自定义错误类型来包装错误,以便更轻松地在Golang中进行调试。当有打印错误时它可以工作,但是现在引起了恐慌。 演示版 当我调用一个函数时,它不会返回错误,我仍然应该能够包装该错误。 预期的行为是,如果错误为nil,则应该简单地忽略它,不幸的是,它会做相反的事情。 我希望它能打印出来。而是即使错误为nil也会打印。 问题答案: 正在将err变量与nil进行比较,但实际上它是