![](/img/trans.png)
[英]if (ourHolder.getSurface().isValid() appears to be returning false
[英]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
。
我嘗試了上述所有答案,但仍然出現相同的錯誤。 經過一個下午的調試,我找到了原因,如果您在上面的這些答案中也沒有得到解決方案。 那么你可以試試我的解決方案。 我發現當我將 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.