Android Camera學習記錄(一) 視訊錄製MediaRecorder
第一次寫自己的技術部落格,本人Android菜鳥一枚,寫部落格也只是為了記錄自己學習過的東西,以便以後可以更容找到屬於自己的資料。
最近一直在做Camera的開發,今天主要想將使用Camera錄製視訊的方法記錄下來。
其實網上關於這方面的技術其實都有比較清晰的講解,不過大部分都是講一部分空一部分,所以就想著要整理綜合一下。
<?xml version="1.0" encoding="utf-8"?>
這個佈局基本上來說就是相對佈局,只不過增加了一些顯示功能而已~所以可以忽略不計,因為是功能測試的App,所以資料上也懶得用dimens來寫了,就先將就這麼看吧~哈哈~
好了,下面就可以進入主題,使用MediaRecorder進行視訊的錄製。
首先,我們需要使用Camera, 需要在AndroidManifest.xml中對使用許可權進行申請,一般來說,使用camera功能都需要使用以下幾個許可權
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.HARDWARE" />
首先先是對Camera的設定,這裡使用的是谷歌大大不推薦使用的Camera,而並非Camera2,童鞋們要注意咯~
public void preview() { try { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // 使用後置攝像頭 camera.setDisplayOrientation(90); // 鏡頭順時旋轉90度 camera.setPreviewDisplay(VideoActivity.getHolder()); // 將SurfaceHolder給camera Camera.Parameters parameters = camera.getParameters(); // 自動對焦 List<String> focusModes = parameters.getSupportedFocusModes(); if (focusModes != null) { for (String mode : focusModes) { mode.contains("continuous-video"); parameters.setFocusMode("continuous-video"); } } camera.setParameters(parameters); camera.startPreview(); } catch (Exception e) { // TODO: handle exception } }
這裡需要注意的有三點
1:在我們使用Camera的時候,無論是預覽還是最終得到的照片,都會逆時針的旋轉90度,尤其是在預覽模式下,預覽的效果還是失真的效果,所以,我們需要用到
camera.setDisplayOrientation(90); // 將預覽效果旋轉90度
recorder.setOrientationHint(90); // 將獲得的視訊結果旋轉90度
setOrientationHint()是針對MediaRecorder屬性的設定,我們後面也會說到。2:自動對焦的問題。我們發現如果不加這段程式碼,也是可以錄製視訊的,但是無論是預覽還是最終得到的視訊,都非常模糊。因此,你肯定會說,那就加上就好了。坑就在這裡了,因為如果用了這段程式碼,某些手機得到的視訊結果就會莫名其妙的產生馬賽克,如果說一直保持一個位置還好,如果運動拍攝的話,這個問題就會非常的明顯。因為我手頭只有4款Android測試機,所以沒有辦法說到底哪幾種機型會出現這樣的結果,不過就現有測試的結果來說,小米的機器就會出現這個問題,不知道有沒有大神可以幫忙解決這個蛋疼的問題呢?
// 自動對焦
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes != null) {
for (String mode : focusModes) {
mode.contains("continuous-video");
parameters.setFocusMode("continuous-video");
}
3:關於程式碼順序的問題。在谷歌開發文件裡面其實已經強調了這方面的問題,有關Camera屬性設定,必須嚴格按照谷歌所給的順序進行設定,否則會觸發各種各樣的BUG。
接下來就在Activity中將surfaceView設定好,並獲得SurfaceHolder傳給我們已經寫好的函式中,完成Camera初始化。
具體的SurfaceHolder的設定這裡就跳過了,不過還需要強調的一點是,我建議大家在設定SurfaceHolder的時候加入
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
加入這個之後,你就發現原本會卡頓的瀏覽介面變得流暢了很多。
之後就是在holder中新增CallBack,然後可以在surfaceChanged或者surfaceCreate中設定Camera的屬性,即呼叫上方的函式即可。
private SurfaceHolder.Callback mSurfaceHolder = new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
videoManager.preview();
}
};
OK,完事具備,只欠最後的錄製了。過程中的設定控制元件監聽啥基礎的東西,寶寶我就直接跳過了哈~
總算是要講到今天的主題MediaRecorder了
recorder = new MediaRecorder();
recorder.reset();
recorder.setCamera(camera);
// 選擇角度(視訊結果)
recorder.setOrientationHint(90);
// 設定採集影象
recorder.setVideoSource(Camera.CameraInfo.CAMERA_FACING_BACK);
// 設定視訊的輸出格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 設定視訊編碼格式
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 設定視訊質量
CamcorderProfile profile = CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH);
// 設定高質量錄製, 改變位元速率
recorder.setVideoEncodingBitRate(5 * 1024 * 1024);
// 設定解析度
recorder.setVideoSize(profile.videoFrameWidth,
profile.videoFrameHeight);
// 設定幀率
recorder.setVideoFrameRate(60);
// 儲存到檔案中(路徑)
saveFile = new File(Environment.getExternalStorageDirectory()
.getCanonicalFile()
+ "/"
+ System.currentTimeMillis()
+ ".mp4");
recorder.setOutputFile(saveFile.getAbsolutePath());
// 設定預覽顯示區
recorder.setPreviewDisplay(VideoActivity.getHolder().getSurface());
recorder.prepare();
recorder.start();
基本上來說,每一個API我都加上了註釋,看的還是應該比較清晰的,不過這裡還是需要提及幾點需要注意的點:
1:之前在將Camera的時候就有強調過程式碼順序的問題,這裡同樣也是需要注意這個問題的,尤其是編碼格式後面的幾個屬性,最好是不要隨意的修改程式碼的順序;
2:我看到很多博主都有寫到
// 設定解析度
recorder.setVideoSize(profile.videoFrameWidth,profile.videoFrameHeight);
這個API的問題,後面跟著的兩個寬高值不外乎都是640,480,我也試過寫大於這兩個數值的引數,均會報錯,因此一開始也是預設認為這兩個引數是一個最大可選引數,可是親們也看到了,最後我並沒有指定這兩個引數,而是使用CamcorderProfile獲取寬高。這是由於我在列印日誌的時候發現,這兩個值是可以到達1080或者1280的,因此可以極大的提高視訊的質量,可是具體是為什麼寶寶也沒有搞明白,是否有哪個大神出來解釋一下捏,嘿嘿~3:另外,對於幀率和位元速率來說,其實並沒有必要設定的這麼高,只是由於寶寶的這個App適用於影象識別處理,所以對影象質量的要求比較高,因此設定的比較高。
最後,當我們停止錄製的時候,要將MediaRecorder清空重置,便於下次的使用
public void stopVideo() {
try {
releaseMedioRecorder();
} catch (Exception e) {
}
}
private void releaseMedioRecorder() {
if (recorder != null) {
recorder.reset();
recorder.release();
recorder = null;
camera.lock();
}
}
當然在整個程式關閉的時候,我們還需要將Camera釋放,便於其他程序的使用
public void releaseCamera() {
if (camera != null) {
camera.release();
camera = null;
}
}
第一次寫東西哈,有什麼問題希望各位大大指正哈~嘿嘿~以後應該也是會不定期更新部落格,希望可以多多和大家交流Android開發的經驗~麼麼噠