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

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序制作、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了普陀免費(fèi)建站歡迎大家使用!
Android是一種基于Linux內(nèi)核的自由及開(kāi)放源代碼的操作系統(tǒng),主要使用于移動(dòng)設(shè)備,如智能手機(jī)和平板電腦,由美國(guó)Google公司和開(kāi)放手機(jī)聯(lián)盟領(lǐng)導(dǎo)及開(kāi)發(fā)。
本文總結(jié)三種用于安卓錄屏的解決方案:
adb shell命令screenrecord
MediaRecorder, MediaProjection
MediaProjection , MediaCodec和MediaMuxer
screenrecord命令
screenrecord是一個(gè)shell命令,支持Android4.4(API level 19)以上,錄制的視頻格式為mp4 ,存放到手機(jī)sd卡里,默認(rèn)錄制時(shí)間為180s
adb shell screenrecord --size 1280*720 --bit-rate 6000000 --time-limit 30 /sdcard/demo.mp4
--size 指定視頻分辨率;
--bit-rate 指定視頻比特率,默認(rèn)為4M,該值越小,保存的視頻文件越小;
--time-limit 指定錄制時(shí)長(zhǎng),若設(shè)定大于180,命令不會(huì)被執(zhí)行;
MediaRecorder
MediaProjection是Android5.0后才開(kāi)放的屏幕采集接口,通過(guò)系統(tǒng)級(jí)服務(wù)MediaProjectionManager進(jìn)行管理。
錄屏過(guò)程可以分成兩個(gè)部分,即通過(guò)MediaProjectionManage申請(qǐng)錄屏權(quán)限,用戶允許后開(kāi)始錄制屏幕;然后通過(guò)MediaRecorder對(duì)音視頻數(shù)據(jù)進(jìn)行處理。
獲取MediaProjectionManager實(shí)例
MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService("media_projection");
申請(qǐng)權(quán)限
Intent captureIntent = mProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, LOCAL_REQUEST_CODE);
createScreenCaptureIntent()這個(gè)方法會(huì)返回一個(gè)intent,你可以通過(guò)startActivityForResult方法來(lái)傳遞這個(gè)intent,為了能開(kāi)始屏幕捕捉,activity會(huì)提示用戶是否允許屏幕捕捉(為了防止開(kāi)發(fā)者做一個(gè)木馬,來(lái)捕獲用戶私人信息),你可以通過(guò)getMediaProjection來(lái)獲取屏幕捕捉的結(jié)果。
在onActivityResult中獲取結(jié)果
@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();
}創(chuàng)建MediaRecorder進(jìn)程
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()方法后調(diào)用
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提供對(duì)音視頻壓縮編碼和解碼功能,MediaMuxer可以將音視頻混合生成多媒體文件,生成MP4文件。
與MediaRecorder類似,都需要先通過(guò)MediaProjectionManager獲取錄屏權(quán)限,在回調(diào)中進(jìn)行屏幕數(shù)據(jù)處理。
這里創(chuàng)建另一個(gè)進(jìn)程:
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) {
// 后續(xù)輸出格式變化
resetOutputFormat();
} else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
// 請(qǐng)求超時(shí)
// 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);
}
}
}
/**
* 硬解碼獲取實(shí)時(shí)幀數(shù)據(jù)并寫(xiě)入mp4文件
*
* @param index
*/
private void encodeToVideoTrack(int index) {
// 獲取到的實(shí)時(shí)幀視頻數(shù)據(jù)
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;
}
}
}該進(jìn)程只實(shí)現(xiàn)了視頻錄制,調(diào)用該進(jìn)程只需修改主進(jìn)程中的onActivityResult方法。
以上是“Android怎么實(shí)現(xiàn)錄屏”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)頁(yè)標(biāo)題:Android怎么實(shí)現(xiàn)錄屏
分享URL:http://chinadenli.net/article22/ipgcjc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、域名注冊(cè)、App設(shè)計(jì)、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)