android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼
本文介紹了android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼,分享給大家,希望對(duì)大家有幫助
問題
在android中有時(shí)候我們需要對(duì)屏幕進(jìn)行截屏操作,單一的截屏操作好解決可以通過activity的頂層view DecorView獲取一個(gè)bitmap,得到就是當(dāng)前activity上面的全部視圖。
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
Bitmap ret = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels);
view.destroyDrawingCache();
如果activity中包含一些視頻播放器比如SurfaceView GLSurfaceView TextureView,在調(diào)用截屏代碼會(huì)發(fā)現(xiàn)播放視頻的部分是黑屏的,原因是這幾種視頻渲染的view通過以上代碼拿到的是緩沖區(qū)不是真正的圖像。
解決辦法
android5.0以上系統(tǒng)提供了一個(gè) MediaProjectionManager類來對(duì)手機(jī)進(jìn)行錄屏操作,也支持獲取手機(jī)的Image圖像的操作,知道了這些我們就可以通過提供的api來進(jìn)行截屏操作了。
這里通過Service來操作截屏和錄屏的api
1.綁定截屏的Service
Intent intent = new Intent(this, ScreenService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
public void onServiceConnected(ComponentName className, IBinder service) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
ScreenService.RecordBinder binder = (ScreenService.RecordBinder) service;
recordService = binder.getRecordService();
recordService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
mButton.setEnabled(true);
mButton.setText(recordService.isRunning() ? "結(jié)束" : "開始");
}
2.請(qǐng)求權(quán)限 onActivityResult 方法中回調(diào)。
Intent captureIntent = projectionManager.createScreenCaptureIntent(); startActivityForResult(captureIntent, RECORD_REQUEST_CODE);

成功后
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {
//######## 截屏邏輯 ########
mediaProjection = projectionManager.getMediaProjection(resultCode, data);
recordService.setMediaProject(mediaProjection);
recordService.initImageReader();
}
}
3. 獲取截屏
@Override
public void onClick(View view) {
//######## 截屏邏輯 ########
Bitmap bitmap = recordService.getBitmap();
mImageView.setImageBitmap(bitmap);
}

錄屏
錄屏需要初始化一些錄屏參數(shù),輸入麥克風(fēng)類型視頻類型,保存路徑等
private void initRecorder() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(
getSavePath() + System.currentTimeMillis() + ".mp4");
mediaRecorder.setVideoSize(width, height);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
mediaRecorder.setVideoFrameRate(30);
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
開始錄屏
mediaRecorder.start();
保存路徑

完整Service代碼
public class ScreenService extends Service {
private MediaRecorder mediaRecorder;
private VirtualDisplay virtualDisplay;
private boolean running;
private int width = 720;
private int height = 1080;
private int dpi;
private ImageReader mImageReader;
private MediaProjection mediaProjection;
@Override
public IBinder onBind(Intent intent) {
return new RecordBinder();
}
@Override
public void onCreate() {
super.onCreate();
running = false;
mediaRecorder = new MediaRecorder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public void setMediaProject(MediaProjection project) {
mediaProjection = project;
}
public boolean isRunning() {
return running;
}
public void setConfig(int width, int height, int dpi) {
this.width = width;
this.height = height;
this.dpi = dpi;
}
/**
* 開始錄屏
*
* @return true
*/
public boolean startRecord() {
if (mediaProjection == null || running) {
return false;
}
initRecorder();
createVirtualDisplay();
mediaRecorder.start();
running = true;
return true;
}
/**
* 結(jié)束錄屏
*
* @return true
*/
public boolean stopRecord() {
if (!running) {
return false;
}
running = false;
mediaRecorder.stop();
mediaRecorder.reset();
virtualDisplay.release();
mediaProjection.stop();
return true;
}
public void setMediaProjection(MediaProjection mediaProjection) {
this.mediaProjection = mediaProjection;
}
/**
* 初始化ImageRead參數(shù)
*/
public void initImageReader() {
if (mImageReader == null) {
int maxImages = 2;
mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, maxImages);
createImageVirtualDisplay();
}
}
/**
* 創(chuàng)建一個(gè)錄屏 Virtual
*/
private void createVirtualDisplay() {
virtualDisplay = mediaProjection
.createVirtualDisplay("mediaprojection", width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder
.getSurface(), null, null);
}
/**
* 創(chuàng)建一個(gè)ImageReader Virtual
*/
private void createImageVirtualDisplay() {
virtualDisplay = mediaProjection
.createVirtualDisplay("mediaprojection", width, height, dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader
.getSurface(), null, null);
}
/**
* 初始化保存屏幕錄像的參數(shù)
*/
private void initRecorder() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(
getSavePath() + System.currentTimeMillis() + ".mp4");
mediaRecorder.setVideoSize(width, height);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
mediaRecorder.setVideoFrameRate(30);
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 獲取一個(gè)保存屏幕錄像的路徑
*
* @return path
*/
public String getSavePath() {
if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
String rootDir = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" +
"ScreenRecord" + "/";
File file = new File(rootDir);
if (!file.exists()) {
if (!file.mkdirs()) {
return null;
}
}
return rootDir;
} else {
return null;
}
}
/**
* 請(qǐng)求完權(quán)限后馬上獲取有可能為null,可以通過判斷is null來重復(fù)獲取。
*/
public Bitmap getBitmap() {
Bitmap bitmap = cutoutFrame();
if (bitmap == null) {
getBitmap();
}
return bitmap;
}
/**
* 通過底層來獲取下一幀的圖像
*
* @return bitmap
*/
public Bitmap cutoutFrame() {
Image image = mImageReader.acquireLatestImage();
if (image == null) {
return null;
}
int width = image.getWidth();
int height = image.getHeight();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
Bitmap bitmap = Bitmap.createBitmap(width +
rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
return Bitmap.createBitmap(bitmap, 0, 0, width, height);
}
public class RecordBinder extends Binder {
public ScreenService getRecordService() {
return ScreenService.this;
}
}
demo下載
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android Studio使用小技巧:布局預(yù)覽時(shí)填充數(shù)據(jù)
這篇文章主要介紹了Android Studio使用小技巧:布局預(yù)覽時(shí)填充數(shù)據(jù),本文給出了代碼操作實(shí)例和效果圖例,需要的朋友可以參考下2015-05-05
詳解Flutter WebView與JS互相調(diào)用簡易指南
這篇文章主要介紹了詳解Flutter WebView與JS互相調(diào)用簡易指南,分為JS調(diào)用Flutter和Flutter調(diào)用JS,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-04-04
Android自定義View實(shí)現(xiàn)左右滑動(dòng)選擇出生年份
這篇文章主要介紹了Android自定義View實(shí)現(xiàn)左右滑動(dòng)選擇出生年份,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
解決Error:All flavors must now belong to a named flavor dimens
這篇文章主要介紹了解決Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com,需要的朋友可以參考下2017-11-11
輕松實(shí)現(xiàn)Android仿淘寶地區(qū)選擇功能
這篇文章主要介紹了輕松實(shí)現(xiàn)Android仿淘寶地區(qū)選擇功能的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06

