亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android怎么實現錄屏

發布時間:2021-05-07 14:35:26 來源:億速云 閱讀:296 作者:小新 欄目:移動開發

這篇文章主要介紹Android怎么實現錄屏,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

Android是什么

Android是一種基于Linux內核的自由及開放源代碼的操作系統,主要使用于移動設備,如智能手機和平板電腦,由美國Google公司和開放手機聯盟領導及開發。

本文總結三種用于安卓錄屏的解決方案:

adb shell命令screenrecord
MediaRecorder, MediaProjection
MediaProjection , MediaCodec和MediaMuxer

screenrecord命令

screenrecord是一個shell命令,支持Android4.4(API level 19)以上,錄制的視頻格式為mp4 ,存放到手機sd卡里,默認錄制時間為180s

adb shell screenrecord --size 1280*720 --bit-rate 6000000 --time-limit 30 /sdcard/demo.mp4

 --size 指定視頻分辨率;

 --bit-rate 指定視頻比特率,默認為4M,該值越小,保存的視頻文件越小;

 --time-limit 指定錄制時長,若設定大于180,命令不會被執行;

MediaRecorder

MediaProjection是Android5.0后才開放的屏幕采集接口,通過系統級服務MediaProjectionManager進行管理。

錄屏過程可以分成兩個部分,即通過MediaProjectionManage申請錄屏權限,用戶允許后開始錄制屏幕;然后通過MediaRecorder對音視頻數據進行處理。

獲取MediaProjectionManager實例

MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService("media_projection");

申請權限

Intent captureIntent = mProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, LOCAL_REQUEST_CODE);

createScreenCaptureIntent()這個方法會返回一個intent,你可以通過startActivityForResult方法來傳遞這個intent,為了能開始屏幕捕捉,activity會提示用戶是否允許屏幕捕捉(為了防止開發者做一個木馬,來捕獲用戶私人信息),你可以通過getMediaProjection來獲取屏幕捕捉的結果。

在onActivityResult中獲取結果

@Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    MediaProjection mediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    if (mediaProjection == null) {
    Log.e(TAG, "media projection is null");
    return;
  }
    File file = new File("xx.mp4"); //錄屏生成文件
    mediaRecord = new MediaRecordService(displayWidth, displayHeight, 6000000, 1, 
      mediaProjection, file.getAbsolutePath());
    mediaRecord.start();
}

創建MediaRecorder進程

package com.unionpay.service;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.util.Log;
public class MediaRecordService extends Thread {
  private static final String TAG = "MediaRecordService";
  private int mWidth;
  private int mHeight;
  private int mBitRate;
  private int mDpi;
  private String mDstPath;
  private MediaRecorder mMediaRecorder;
  private MediaProjection mMediaProjection;
  private static final int FRAME_RATE = 60; // 60 fps
  private VirtualDisplay mVirtualDisplay;
  public MediaRecordService(int width, int height, int bitrate, int dpi, MediaProjection mp, String dstPath) {
  mWidth = width;
  mHeight = height;
  mBitRate = bitrate;
  mDpi = dpi;
  mMediaProjection = mp;
  mDstPath = dstPath;
  }
  @Override
  public void run() {
  try {
    initMediaRecorder();
    //在mediarecorder.prepare()方法后調用
    mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display", mWidth, mHeight, mDpi,
      DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mMediaRecorder.getSurface(), null, null);
    Log.i(TAG, "created virtual display: " + mVirtualDisplay);
    mMediaRecorder.start();
    Log.i(TAG, "mediarecorder start");
  } catch (Exception e) {
    e.printStackTrace();
  }
  }
  /**
   * 初始化MediaRecorder
   * 
   * @return
   */
  public void initMediaRecorder() {
  mMediaRecorder = new MediaRecorder();
  mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
  mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
  mMediaRecorder.setOutputFile(mDstPath);
  mMediaRecorder.setVideoSize(mWidth, mHeight);
  mMediaRecorder.setVideoFrameRate(FRAME_RATE);
  mMediaRecorder.setVideoEncodingBitRate(mBitRate);
  mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
  mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

  try {
    mMediaRecorder.prepare();
  } catch (Exception e) {
    e.printStackTrace();
  }
  Log.i(TAG, "media recorder" + mBitRate + "kps");
  }

  public void release() {
  if (mVirtualDisplay != null) {
    mVirtualDisplay.release();
    mVirtualDisplay = null;
  }
  if (mMediaRecorder != null) {
    mMediaRecorder.setOnErrorListener(null);
    mMediaProjection.stop();
    mMediaRecorder.reset();
    mMediaRecorder.release();
  }
  if (mMediaProjection != null) {
    mMediaProjection.stop();
    mMediaProjection = null;
  }
  Log.i(TAG, "release");
  }
}

MediaCodec與MediaMuxer

MediaCodec提供對音視頻壓縮編碼和解碼功能,MediaMuxer可以將音視頻混合生成多媒體文件,生成MP4文件。
與MediaRecorder類似,都需要先通過MediaProjectionManager獲取錄屏權限,在回調中進行屏幕數據處理。

這里創建另一個進程:

package com.unionpay.service;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.projection.MediaProjection;
import android.util.Log;
import android.view.Surface;
public class ScreenRecordService extends Thread{
    private static final String TAG = "ScreenRecordService";
  private int mWidth;
  private int mHeight;
  private int mBitRate;
  private int mDpi;
  private String mDstPath;
  private MediaProjection mMediaProjection;
  // parameters for the encoder
  private static final String MIME_TYPE = "video/avc"; // H.264 Advanced
                 // Video Coding
  private static final int FRAME_RATE = 30; // 30 fps
  private static final int IFRAME_INTERVAL = 10; // 10 seconds between
                // I-frames
  private static final int TIMEOUT_US = 10000;
  private MediaCodec mEncoder;
  private Surface mSurface;
  private MediaMuxer mMuxer;
  private boolean mMuxerStarted = false;
  private int mVideoTrackIndex = -1;
  private AtomicBoolean mQuit = new AtomicBoolean(false);
  private MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
  private VirtualDisplay mVirtualDisplay;
  public ScreenRecordService(int width, int height, int bitrate, int dpi, MediaProjection mp, String dstPath) {
    super(TAG);
    mWidth = width;
    mHeight = height;
    mBitRate = bitrate;
    mDpi = dpi;
    mMediaProjection = mp;
    mDstPath = dstPath;
  }
  /**
   * stop task
   */
  public final void quit() {
    mQuit.set(true);
  }
  @Override
  public void run() {
    try {
    try {
      prepareEncoder();
      mMuxer = new MediaMuxer(mDstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display", mWidth, mHeight, mDpi,
      DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, null);
    Log.d(TAG, "created virtual display: " + mVirtualDisplay);
    recordVirtualDisplay();
    } finally {
    release();
    }
  }
  private void recordVirtualDisplay() {
    while (!mQuit.get()) {
    int index = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
//   Log.i(TAG, "dequeue output buffer index=" + index);
    if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
      // 后續輸出格式變化
      resetOutputFormat();
    } else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
      // 請求超時
//     Log.d(TAG, "retrieving buffers time out!");
      try {
      // wait 10ms
      Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    } else if (index >= 0) {
      // 有效輸出
      if (!mMuxerStarted) {
      throw new IllegalStateException("MediaMuxer dose not call addTrack(format) ");
      }
      encodeToVideoTrack(index);
      mEncoder.releaseOutputBuffer(index, false);
    }
    }
  }
  /**
   * 硬解碼獲取實時幀數據并寫入mp4文件
   * 
   * @param index
   */
  private void encodeToVideoTrack(int index) {
    // 獲取到的實時幀視頻數據
    ByteBuffer encodedData = mEncoder.getOutputBuffer(index);
    if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
    // The codec config data was pulled out and fed to the muxer
    // when we got
    // the INFO_OUTPUT_FORMAT_CHANGED status.
    // Ignore it.
    Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
    mBufferInfo.size = 0;
    }
    if (mBufferInfo.size == 0) {
    Log.d(TAG, "info.size == 0, drop it.");
    encodedData = null;
    } else {
//   Log.d(TAG, "got buffer, info: size=" + mBufferInfo.size + ", presentationTimeUs="
//     + mBufferInfo.presentationTimeUs + ", offset=" + mBufferInfo.offset);
    }
    if (encodedData != null) {
    mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
    }
  }
  private void resetOutputFormat() {
    // should happen before receiving buffers, and should only happen
    // once
    if (mMuxerStarted) {
    throw new IllegalStateException("output format already changed!");
    }
    MediaFormat newFormat = mEncoder.getOutputFormat();
    mVideoTrackIndex = mMuxer.addTrack(newFormat);
    mMuxer.start();
    mMuxerStarted = true;
    Log.i(TAG, "started media muxer, videoIndex=" + mVideoTrackIndex);
  }
  private void prepareEncoder() throws IOException {
    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
    format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
    format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
    Log.d(TAG, "created video format: " + format);
    mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
    mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    mSurface = mEncoder.createInputSurface();
    Log.d(TAG, "created input surface: " + mSurface);
    mEncoder.start();
  }
  private void release() {
    if (mEncoder != null) {
    mEncoder.stop();
    mEncoder.release();
    mEncoder = null;
    }
    if (mVirtualDisplay != null) {
    mVirtualDisplay.release();
    }
    if (mMediaProjection != null) {
    mMediaProjection.stop();
    }
    if (mMuxer != null) {
    mMuxer.stop();
    mMuxer.release();
    mMuxer = null;
    }
  }
}

該進程只實現了視頻錄制,調用該進程只需修改主進程中的onActivityResult方法。

以上是“Android怎么實現錄屏”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿拉善盟| 环江| 玉屏| 黎川县| 大渡口区| 石棉县| 肇源县| 商丘市| 兴山县| 麦盖提县| 乐安县| 苍南县| 松溪县| 万载县| 道真| 岑巩县| 平罗县| 南靖县| 奎屯市| 文昌市| 康保县| 嵊州市| 越西县| 社会| 梅河口市| 鹰潭市| 安顺市| 曲靖市| 高安市| 尉氏县| 新闻| 长寿区| 佛山市| 仁寿县| 崇义县| 汕头市| 洛浦县| 开阳县| 磐安县| 泽库县| 德安县|