1. 程式人生 > >Android Camera學習記錄(一) 視訊錄製MediaRecorder

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開發的經驗~麼麼噠