MediaProjection
android在5.0系統(tǒng)之前森爽,是沒有開放視頻錄制的接口的,如果要錄制視頻,必須要先root。
在5.0步做,Google終于開放了視頻錄制的接口(其實嚴格來說伦籍,是屏幕采集的接口)嫩舟,也就是MediaProjection
和MediaProjectionManager
声功。
首先來說MediaProjectionManager,它是一個系統(tǒng)級的服務(wù)执桌,類似WindowManager鄙皇,AlarmManager等,你可以通過getSystemService方法來獲取它的實例:
MediaProjectionManager mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
獲取到實例后仰挣,錄像的過程如下
首先:
Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, REQUEST_CODE);
createScreenCaptureIntent方法的注釋如下:
/**
* Returns an Intent that <b>must</b> passed to startActivityForResult()
* in order to start screen capture. The activity will prompt
* the user whether to allow screen capture. The result of this
* activity should be passed to getMediaProjection.
*/
大致意思是伴逸,這個方法會返回一個intent,你可以通過startActivityForResult方法來傳遞這個intent膘壶,為了能開始屏幕捕捉错蝴,activity會提示用戶是否允許屏幕捕捉(為了防止開發(fā)者做一個木馬洲愤,來捕獲用戶私人信息),你可以通過getMediaProjection來獲取屏幕捕捉的結(jié)果顷锰。
createScreenCaptureIntent的代碼我們可以看一下:
public Intent createScreenCaptureIntent() {
Intent i = new Intent();
i.setClassName("com.android.systemui",
"com.android.systemui.media.MediaProjectionPermissionActivity");
return i;
}
所以這里是創(chuàng)建了一個隱式的intent柬赐,用來調(diào)用系統(tǒng)的錄屏程序。
然后正如上面的注釋所說官紫,我們通過startActivityForResult來傳遞這個intent肛宋,所以我們可以通過onActivityResult來獲取結(jié)果,通過getMediaProjection來取出intent中的數(shù)據(jù):
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != PERMISSION_CODE) {
Log.e(TAG, "Unknown request code: " + requestCode);
return;
}
if (resultCode != RESULT_OK) {
Toast.makeText(this,
"User denied screen sharing permission", Toast.LENGTH_SHORT).show();
return;
}
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
mMediaProjection.registerCallback(new MediaProjectionCallback(), null);
mVirtualDisplay = createVirtualDisplay();
}
我們通過getMediaProjection獲取到mediaProjection束世,并注冊了一個callback回調(diào)酝陈。
看看createVirtualDisplay做了什么:
private VirtualDisplay createVirtualDisplay() {
return mMediaProjection.createVirtualDisplay("ScreenSharingDemo",
mDisplayWidth, mDisplayHeight, mScreenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mSurface, null /*Callbacks*/, null /*Handler*/);
}
可以看到,我們調(diào)用了MediaProjection的createVirtualDisplay方法良狈,來創(chuàng)建了一個VirtualDisplay的實例后添,說幾個createVirtualDisplay的參數(shù)含義:
name: 是生成的VirtualDisplay實例的名稱笨枯;
width, height: 分別是生成實例的寬高薪丁,必須大于0;
dpi: 生成實例的像素密度馅精,必須大于0严嗜,一般都取1;
surface: 這個比較重要洲敢,是你生成的VirtualDisplay的載體漫玄,
我的理解是,VirtualDisplay的內(nèi)容是一幀幀的屏幕截圖(所以你看到是有寬高压彭,像素密度等設(shè)置)睦优,
所以MediaProjection獲取到的其實是一幀幀的圖,然后通過 surface(surface你可以理解成是android的一個畫布壮不,
默認它會以每秒60幀來刷新汗盘,這里我們不再展開細說),來順序播放這些圖片询一,形成視頻隐孽。
這樣,屏幕所捕獲的內(nèi)容健蕊,就顯示在這個SurfaceView上面了
Android 實現(xiàn)錄屏推流的方案整理
一菱阵、錄屏推流實現(xiàn)的步驟
采集數(shù)據(jù)
主要是采集屏幕獲得視頻數(shù)據(jù),采集麥克風獲得音頻數(shù)據(jù)
缩功,如果可以實現(xiàn)的話晴及,我們還可以采集一些應(yīng)用內(nèi)置的音頻數(shù)據(jù)。數(shù)據(jù)格式轉(zhuǎn)換
主要是將獲取到的視頻和音頻轉(zhuǎn)換成常見的推流的標準格式
嫡锌,這樣能保證讓觀看終端正常觀看抗俄。編碼處理
如果不進行編碼的話脆丁,數(shù)據(jù)量會非常大,這樣不僅浪費帶寬动雹,而且會浪費觀看終端的性能槽卫,所以需要對音視頻數(shù)據(jù)進行編碼處理
。封包&推流
這塊的邏輯可以采用和普通的直播方式進行封裝和推流
胰蝠。
總結(jié):其實錄屏推流直播和普通的直播的區(qū)別就是采集源發(fā)生了變化歼培,而在技術(shù)層面來將真正需要我們做的事情就是將錄屏獲取到的數(shù)據(jù)處理成穩(wěn)定的編碼格式。
二茸塞、Android 實現(xiàn)錄屏的思路
主流實現(xiàn)思路:
MediaProjection + VirtualDisplay
方法
在Android 5.0 發(fā)布后躲庄,谷歌開放了截屏的接口,我們可以通過VirtualDisplay來實現(xiàn)錄屏的視頻源數(shù)據(jù)的獲取钾虐。需ROOT思路:讀取 /dev/graphics/fb0 方法 or screencap -p xxx.png/screenshot xxx.png 方法
Android 基于 Linux噪窘,所以可以通過讀取 fb0 設(shè)備節(jié)點,即 framebuffer 中的幀數(shù)據(jù)來實現(xiàn)屏幕的錄制效扫。但是讀取這個設(shè)備節(jié)點需要 root 權(quán)限倔监。
screencap 是 Android shell 的命令,可以通過該 shell 命令讀取到屏幕的幀數(shù)據(jù)來達到錄屏的功能菌仁。但該命令仍然需要 root 權(quán)限浩习。