0

我试图使用mediaProjection API记录屏幕,但我总是只得到一个黑色的视频(视频的整个长度显示黑色),我对为什么一无所知。在初始化MediaProjectionManager之后调用startRecording(),然后调用releaseEncoders()来停止录制。这是我的代码:屏幕记录是使用mediaprojection黑色

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

    mMediaProjectionManager = (MediaProjectionManager) getSystemService(
      android.content.Context.MEDIA_PROJECTION_SERVICE); 

    ToggleButton rec = (ToggleButton) findViewById(R.id.tggl); 

    String[] perms = {"android.permission.WRITE_EXTERNAL_STORAGE"}; 

    if (!isStorageWritable()) { 
     // We don't have permission so prompt the user 
     requestPermissions(
       perms, 
       REQUEST_EXTERNAL_STORAGE 
     ); 
    } 
    rec.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      if (((ToggleButton) view).isChecked()) { 
       if (isStorageWritable()) { 
        Intent permissionIntent = mMediaProjectionManager.createScreenCaptureIntent(); 
        startActivityForResult(permissionIntent, REQUEST_CODE_CAPTURE_PERM); 
       } 
      } else 
       releaseEncoders(); 
     } 
    }); 
} 

private boolean isStorageWritable(){ 
    int permission = ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE"); 
    if (permission == PackageManager.PERMISSION_GRANTED) 
     return true; 
    else 
     return false; 
} 

private Runnable mDrainEncoderRunnable = new Runnable() { 
    @Override 
    public void run() { 
     drainEncoder(); 
    } 
}; 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (REQUEST_CODE_CAPTURE_PERM == requestCode) { 
     if (resultCode == RESULT_OK) { 
      mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data); 
      startRecording(); // defined below 
     } else { 
      // user did not grant permissions 
     } 
    } 
} 
private void startRecording() { 
    DisplayManager dm = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); 
    Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); 
    if (defaultDisplay == null) { 
     throw new RuntimeException("No display found."); 
    } 
    prepareVideoEncoder(); 

    try { 
     mMuxer = new MediaMuxer(Environment.getExternalStorageDirectory() + "/video.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 
    } catch (IOException ioe) { 
     throw new RuntimeException("MediaMuxer creation failed", ioe); 
    } 

    // Get the display size and density. 
    DisplayMetrics metrics = getResources().getDisplayMetrics(); 
    int screenWidth = metrics.widthPixels; 
    int screenHeight = metrics.heightPixels; 
    int screenDensity = metrics.densityDpi; 

    // Start the video input. 
    mMediaProjection.createVirtualDisplay("Recording Display", screenWidth, 
      screenHeight, screenDensity, 0 /* flags */, mInputSurface, 
      null /* callback */, null /* handler */); 

    // Start the encoders 
    drainEncoder(); 
} 

private void prepareVideoEncoder() { 
    mVideoBufferInfo = new MediaCodec.BufferInfo(); 
    MediaFormat format = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT); 
    int frameRate = 30; // 30 fps 

    // Set some required properties. The media codec may fail if these aren't defined. 
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
      MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 
    format.setInteger(MediaFormat.KEY_BIT_RATE, 6000000); // 6Mbps 
    format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); 
    format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate); 
    format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000/frameRate); 
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1 seconds between I-frames 

    // Create a MediaCodec encoder and configure it. Get a Surface we can use for recording into. 
    try { 
     mVideoEncoder = MediaCodec.createEncoderByType(VIDEO_MIME_TYPE); 
     mVideoEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
     mInputSurface = mVideoEncoder.createInputSurface(); 
     mVideoEncoder.start(); 
    } catch (IOException e) { 
     releaseEncoders(); 
    } 
} 

private boolean drainEncoder() { 
    mDrainHandler.removeCallbacks(mDrainEncoderRunnable); 
    while (true) { 
     int bufferIndex = mVideoEncoder.dequeueOutputBuffer(mVideoBufferInfo, 0); 

     if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { 
      // nothing available yet 
      break; 
     } else if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
      // should happen before receiving buffers, and should only happen once 
      if (mTrackIndex >= 0) { 
       throw new RuntimeException("format changed twice"); 
      } 
      mTrackIndex = mMuxer.addTrack(mVideoEncoder.getOutputFormat()); 
      if (!mMuxerStarted && mTrackIndex >= 0) { 
       mMuxer.start(); 
       mMuxerStarted = true; 
      } 
     } else if (bufferIndex < 0) { 
      // not sure what's going on, ignore it 
     } else { 
      ByteBuffer encodedData = mVideoEncoder.getOutputBuffer(bufferIndex); 
      if (encodedData == null) { 
       throw new RuntimeException("couldn't fetch buffer at index " + bufferIndex); 
      } 

      if ((mVideoBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { 
       mVideoBufferInfo.size = 0; 
      } 

      if (mVideoBufferInfo.size != 0) { 
       if (mMuxerStarted) { 
        encodedData.position(mVideoBufferInfo.offset); 
        encodedData.limit(mVideoBufferInfo.offset + mVideoBufferInfo.size); 
        mMuxer.writeSampleData(mTrackIndex, encodedData, mVideoBufferInfo); 
       } else { 
        // muxer not started 
       } 
      } 

      mVideoEncoder.releaseOutputBuffer(bufferIndex, false); 

      if ((mVideoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
       break; 
      } 
     } 
    } 

    mDrainHandler.postDelayed(mDrainEncoderRunnable, 10); 
    return false; 
} 

private void releaseEncoders() { 
    mDrainHandler.removeCallbacks(mDrainEncoderRunnable); 
    Toast.makeText(this, "Stopping recording", Toast.LENGTH_SHORT).show(); 
    if (mMuxer != null) { 
     if (mMuxerStarted) { 
      mMuxer.stop(); 
     } 
     mMuxer.release(); 
     mMuxer = null; 
     mMuxerStarted = false; 
    } 
    if (mVideoEncoder != null) { 
     mVideoEncoder.stop(); 
     mVideoEncoder.release(); 
     mVideoEncoder = null; 
    } 
    if (mInputSurface != null) { 
     mInputSurface.release(); 
     mInputSurface = null; 
    } 
    if (mMediaProjection != null) { 
     mMediaProjection.stop(); 
     mMediaProjection = null; 
    } 
    mVideoBufferInfo = null; 
    mDrainEncoderRunnable = null; 
    mTrackIndex = -1; 
} 
+0

不过问题没有解决。有点碰撞 – Vijai

回答

0

这实际上解决了我的问题。

private static final String TAG = "MainActivity"; 
private static final int REQUEST_CODE = 1000; 
private int mScreenDensity; 
private MediaProjectionManager mProjectionManager; 
private static final int DISPLAY_WIDTH = 720; 
private static final int DISPLAY_HEIGHT = 1280; 
private MediaProjection mMediaProjection; 
private VirtualDisplay mVirtualDisplay; 
private MediaProjectionCallback mMediaProjectionCallback; 
private ToggleButton mToggleButton; 
private MediaRecorder mMediaRecorder; 
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); 
private static final int REQUEST_PERMISSIONS = 10; 

static { 
    ORIENTATIONS.append(Surface.ROTATION_0, 90); 
    ORIENTATIONS.append(Surface.ROTATION_90, 0); 
    ORIENTATIONS.append(Surface.ROTATION_180, 270); 
    ORIENTATIONS.append(Surface.ROTATION_270, 180); 
} 
@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode != REQUEST_CODE) { 
     Log.e(TAG, "Unknown request code: " + requestCode); 
     return; 
    } 
    if (resultCode != RESULT_OK) { 
     Toast.makeText(this, 
       "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show(); 
     mToggleButton.setChecked(false); 
     return; 
    } 
    mMediaProjectionCallback = new MediaProjectionCallback(); 
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data); 
    mMediaProjection.registerCallback(mMediaProjectionCallback, null); 
    mVirtualDisplay = createVirtualDisplay(); 
    mMediaRecorder.start(); 
} 

public void onToggleScreenShare(View view) { 
    if (((ToggleButton) view).isChecked()) { 
     initRecorder(); 
     shareScreen(); 
    } else { 
     mMediaRecorder.stop(); 
     mMediaRecorder.reset(); 
     Log.v(TAG, "Stopping Recording"); 
     stopScreenSharing(); 
    } 
} 

private void shareScreen() { 
    if (mMediaProjection == null) { 
     startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE); 
     return; 
    } 
    mVirtualDisplay = createVirtualDisplay(); 
    mMediaRecorder.start(); 
} 

private VirtualDisplay createVirtualDisplay() { 
    return mMediaProjection.createVirtualDisplay("MainActivity", 
      DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity, 
      DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, 
      mMediaRecorder.getSurface(), null /*Callbacks*/, null 
      /*Handler*/); 
} 

private void initRecorder() { 
    try { 
     mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
     mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); 
     mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
     mMediaRecorder.setOutputFile(Environment 
       .getExternalStoragePublicDirectory(Environment 
         .DIRECTORY_DOWNLOADS) + "/video.mp4"); 
     mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT); 
     mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 
     mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 
     mMediaRecorder.setVideoEncodingBitRate(512 * 1000); 
     mMediaRecorder.setVideoFrameRate(30); 
     int rotation = getWindowManager().getDefaultDisplay().getRotation(); 
     int orientation = ORIENTATIONS.get(rotation + 90); 
     mMediaRecorder.setOrientationHint(orientation); 
     mMediaRecorder.prepare(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private class MediaProjectionCallback extends MediaProjection.Callback { 
    @Override 
    public void onStop() { 
     if (mToggleButton.isChecked()) { 
      mToggleButton.setChecked(false); 
      mMediaRecorder.stop(); 
      mMediaRecorder.reset(); 
      Log.v(TAG, "Recording Stopped"); 
     } 
     mMediaProjection = null; 
     stopScreenSharing(); 
    } 
} 

private void stopScreenSharing() { 
    if (mVirtualDisplay == null) { 
     return; 
    } 
    mVirtualDisplay.release(); 
    //mMediaRecorder.release(); //If used: mMediaRecorder object cannot 
    // be reused again 
    destroyMediaProjection(); 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    destroyMediaProjection(); 
} 

private void destroyMediaProjection() { 
    if (mMediaProjection != null) { 
     mMediaProjection.unregisterCallback(mMediaProjectionCallback); 
     mMediaProjection.stop(); 
     mMediaProjection = null; 
    } 
    Log.i(TAG, "MediaProjection Stopped"); 
} 

更多信息here