使用媒体投影

时间:2016-09-26 06:53:48

标签: android android-5.0-lollipop screen-recording android-mediaprojection

我尝试使用MediaProjection API录制屏幕,但我似乎总是只获得一个黑色视频(整个视频长度显示为黑色)而且我对其原因一无所知。我在初始化startRecording()后拨打MediaProjectionManager,然后拨打releaseEncoders()停止录制。这是我的代码:

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

1 个答案:

答案 0 :(得分:-3)

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

 /// <summary>
    /// place single bet, Low
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button4_Click(object sender, EventArgs e)
    {
        CurrentSite.amount =((decimal)nudApiBet.Value);
        CurrentSite.chance = (decimal)(nudApiChance.Value);
        CurrentSite.PlaceBet(false, (decimal)nudApiBet.Value,(decimal)(nudApiChance.Value));
    }

    private void nudApiBet_ValueChanged(object sender, EventArgs e)
    {
        if ((sender as NumericUpDown).Name == "nudApiBet")
        {

            lblApiBetProfit.Text = ((nudApiBet.Value * nudApiPayout.Value) - nudApiBet.Value).ToString("0.00000000"); 
        }
        else if ((sender as NumericUpDown).Name == "nudApiChance")
        {
            decimal payout = (100m - CurrentSite.edge) / (nudApiChance.Value);
            if (nudApiPayout.Value != payout)
                nudApiPayout.Value = payout;
            lblApiBetProfit.Text = ((nudApiBet.Value * payout) - nudApiBet.Value).ToString("0.00000000"); 
        }
        else if ((sender as NumericUpDown).Name == "nudApiPayout")
        {
            decimal chance = (100m - CurrentSite.edge) / (nudApiPayout.Value);
            if (nudApiChance.Value != chance)
                nudApiChance.Value = chance;
            lblApiBetProfit.Text = ((nudApiBet.Value * nudApiPayout.Value) - nudApiBet.Value).ToString("0.00000000"); 
        }
    }

更多信息here