Android 音視訊開發【視訊篇】【二】視訊採集 | 8月更文挑戰
這是我參與8月更文挑戰的第2天,活動詳情檢視:8月更文挑戰
上一章介紹了
RGB
、YUV
格式,本章將介紹如何採集YUV
格式的資料
一、視訊相關概念
1.1 解析度
用以橫向
和縱向
的畫素點個數來衡量一副影象的大小,比如1080*960
,其中1080
表示橫向
的畫素點個數為1080
個,960
表示縱向
的畫素點個數為960
個
1.2 幀率
1s
內有多少個副影象,比如30fps
,表示1s
內有30
副影象,即30
幀,而60fps
,表示1s
內有60
幀,更高的還有90fps
、120fps
,幀率越高,相對來說,畫面就會更流暢
根據人眼的視覺暫留特性,24fps
時,人眼就會認為是流暢
的,而更高的幀率,會給人一種身臨其境的感覺
當然,也不是幀率越高越好,需要考慮顯示器的重新整理率,幀率過高可能反而浪費不必要的資源
1.3 位元速率/位元率
位元速率,也即位元率,單位是bps
,表示視訊的位元數,計算公式是:
$$ 位元速率 = 檔案大小(kb) / 時長(s) $$
二、視訊採集
採集視訊,在手機中可以通過攝像頭進行採集,那麼,在Android
也提供了很多對攝像頭進行操作的類
-
Camera
操作相對簡單,提供對攝像頭的很多的操作方法,比如開啟、關閉攝像頭、變焦、拍照等,不過谷歌已經不建議使用,而是建議使用
CameraX
,或者是Camera2
-
Camera2
Camera2
相對於Camera
增加了很多特性,比如對Api
的架構進行了很大的優化,比Camera
更先進,還可以獲取每幀的資訊,等等,還有很多特性,不過,Camera2
相對於Camera
,使用上變得更加複雜 -
CameraX
JetPack
家族的一員,CameraX
是在Camea2
之後新出的一個相機框架,可能是谷歌覺得雖然Camera2
功能強大,但是使用起來確實麻煩了很多,所有為了在保證功能的前提的下,操作變得更簡潔,所有推出了CameraX
雖然谷歌建議我們使用CameraX
或者是Camera2
,但是視訊系列的相關文章,還是以Camera
,不為別的,就是為了簡單,哈哈
2.1 Camera
關於相機的使用,可以放入子執行緒去使用
首先,第一步,當然是開啟相機
開啟相機
java
camera = Camera.open(id);
開啟相機,使用的是Camera
類的靜態方法open()
,該方法需要傳入一個int
型別的id
,有兩個值可選
-
Camera.CameraInfo.CAMERA_FACING_BACK
後攝
-
Camera.CameraInfo.CAMERA_FACING_FRONT
前攝
在獲取camera
例項後,此時攝像頭並沒有正在的開啟
接下來需要對camera
做一些引數配置,比如預覽尺寸
獲取相機引數
java
Camera.Parameters parameters = camera.getParameters();
對camera
進行引數設定,先得呼叫該方法,然後下面就會對parameters
進行一些引數設定
獲取全部預覽尺寸
java
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
通過呼叫parameters.getSupportedPreviewSizes()
獲取當前相機所支援的預覽尺寸,因為我們傳入相機的預覽尺寸必須得是相機所支援的
一般來說,我們通常希望相機的尺寸能夠和螢幕一樣大,或者是和螢幕同等比例,這樣,顯示出來的效果也就比較好,所有下面通過一個演算法,找到最佳的尺寸
java
/**
* 尋找最合適的尺寸
*/
public static Camera.Size findTheBestSize(List<Camera.Size> sizeList, int screenW, int screenH) {
if (sizeList == null || sizeList.isEmpty()) {
throw new IllegalArgumentException();
}
Camera.Size bestSize = sizeList.get(0);
for (Camera.Size size : sizeList) {
int width = size.height;
int height = size.width;
float ratioW = (float) width / screenW;
float ratioH = (float) height / screenH;
if (ratioW == ratioH) {
bestSize = size;
break;
}
}
return bestSize;
}
一個引數,直接傳入相機所支援的預覽尺寸,後面兩個引數是螢幕的尺寸
該演算法的目的就是遍歷每一個預覽尺寸,但預覽尺寸的比例和螢幕的尺寸比例一致時,就可以返回,而如果當遍歷完,還是沒找到合適的尺寸,就返回第一個相機所支援的尺寸
通過此方法,就獲取到了一個最佳的尺寸
設定預覽尺寸
java
parameters.setPreviewSize(width, height);
本章的目的是取樣視訊資料,所以我們得設定相機預覽資料的回撥格式
設定預覽格式
java
parameters.setPreviewFormat(ImageFormat.NV21);
相機設定引數
java
camera.setParameters(parameters);
在對parameters
做了一系列的設定後,我們就可以將其設定給camera
設定旋轉角度
java
camera.setDisplayOrientation(CameraUtils.getDisplayOrientation(activity, id));
設定旋轉角度,使用的是CameraUtils.getDisplayOrientation(activity, id)
方法
java
/**
* 獲取攝像頭旋轉角度
*/
public static int getDisplayOrientation(Activity activity, int facing) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(facing, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
設定資料快取和回撥
之前設定了預覽資料的回撥格式為NV21
,它是一種YUV420
的格式
camera
提供了addCallbackBuffer
和setPreviewCallbackWithBuffer
的方法,用於接收預覽資料和設定回撥,它能夠減少物件的建立
java
camera.addCallbackBuffer(nv21Data);
camera.setPreviewCallbackWithBuffer(this);
設定回撥後,我們需要重寫onPreviewFrame
方法
java
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG, "onPreviewFrame: " + nv21Data.length);
camera.addCallbackBuffer(nv21Data);
if (fos == null) {
return;
}
try {
fos.write(nv21Data);
} catch (IOException e) {
e.printStackTrace();
}
}
在該方法中,每次回撥預覽資料,都會先呼叫addCallbackBuffer
方法,該方法會複用對應的物件
接著後面將資料寫入到檔案中
設定SurfaceTexture,開啟預覽
當然,上面還沒結束,還需要設定SurfaceTexture
才能正常開啟預覽,也就才能正常獲取預覽回撥資料
java
try {
camera.setPreviewTexture(new SurfaceTexture(0));
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
這裡設定的是一個new
出來的surfaceTexture
,產生的效果是無預覽取樣視訊
你也可以使用SurfaceView
或者TextureView
顯示預覽畫面
停止預覽,釋放資源
當我們停止錄製時,需要停止預覽並釋放資源
java
private void release() {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
if (fos != null) {
try {
fos.close();
fos = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、GitHub
- 豐田加速在中國推進氫能應用,氫燃料電池車 MIRAI 應用場景擴大
- Mirai 惡意軟體變體 MooBot 瞄準 D-Link 裝置
- 使用 GO-CQHttp或mirai框架 搭建QQ的機器人
- Android 音視訊開發【視訊篇】【二】視訊採集 | 8月更文挑戰
- Android 音視訊開發【特效篇】【一】抖音傳送帶特效 | 8月更文挑戰
- 如何打造一款高效能的全屏紅包雨
- 新型Enemybot DDoS僵屍網路借用Mirai和Gafgyt攻擊程式碼
- 惡意軟體Mirai正積極利用Spring4Shell漏洞
- Linux 惡意軟體呈上升趨勢:XorDDoS、Mirai 和 Mozi 最流行
- Python mirai開發QQ機器人起步教程(2021.9.9測試有效)
- 通報:Confluence遠端程式碼執行漏洞(CVE-2021-26084)被黑產大規模利用
- 通報:騰訊主機安全捕獲YAPI遠端程式碼執行0day漏洞在野利用,該攻擊正在擴散,可使用防火牆阻截
- Mirai_ptea Botnet利用KGUARD DVR未公開漏洞報告
- 研究人員通過 Mirai 惡意軟體有效載荷確定了兩個新的物聯網漏洞
- 研究人員發現了另一種針對新物聯網漏洞的Mirai變種
- 防禦DDoS措施種類太多選暈了頭?學會利用他人經驗做對的選擇
- 豐田將成汽車界諾基亞?
- HTB-靶機-Mirai
- 黑客通常可以分為以下8種類型
- 研究人員通過 Mirai 惡意軟體 payload 確定了兩個新的 IoT 漏洞