公司現(xiàn)在的項(xiàng)目是一個(gè)在AndroidTV上開發(fā)的励负,要添加一個(gè)新的需求谨究,錄制視頻昔案。記錄一下在AndroidTV上開發(fā)錄制視頻時(shí)遇到的小問題:
注: 對(duì)于只有一個(gè)攝像頭的手機(jī)可能會(huì)有同樣的問題瓤荔,未測(cè)試過
- 無法獲取到
Camera
對(duì)象 - 獲取到Camera對(duì)象,在設(shè)置錄制質(zhì)量等一系列數(shù)據(jù)時(shí)
MediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
時(shí)梅惯,捕獲到空指針
- 無法獲取到
Camera
對(duì)象(目標(biāo)TV上只有一個(gè)攝像頭,QQ在該TV上同樣無法獲取到攝像頭)
注意的地方: 通常我們獲取Camera
對(duì)象直接調(diào)用Camera.open()
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
LogUtils.e("camera", "Open Camera Failed", e);
}
Camera
類中提供給我們兩個(gè)獲取Camera對(duì)象的方法(無參或有參):
/**
* Creates a new Camera object to access the first back-facing camera on the
* device. If the device does not have a back-facing camera, this returns
* null.
* @see #open(int)
*/
public static Camera open() {
int numberOfCameras = getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
return new Camera(i);
}
}
return null;
}
注意到該方法的提示信息If the device does not have a back-facing camera, this returns null.
仿野,如果沒有后置攝像頭,那么返回值為 NULL
她君,即我們并沒有獲取到Camera對(duì)象脚作。只有一個(gè)攝像頭時(shí),系統(tǒng)并沒有獲取到cameraInfo.facing
缔刹,Camera.open()
無參默認(rèn)打開后置攝像頭球涛。講到這里,你可能已經(jīng)明白我沒有獲取到Camera
對(duì)象的原因了...
接下來繼續(xù)看一下校镐,Camera.open(number)
帶參數(shù)的系統(tǒng)方法:
/**
* Creates a new Camera object to access a particular hardware camera. If
* the same camera is opened by other applications, this will throw a
* RuntimeException.
*
* <p>You must call {@link #release()} when you are done using the camera,
* otherwise it will remain locked and be unavailable to other applications.
*
* <p>Your application should only have one Camera object active at a time
* for a particular hardware camera.
*
* <p>Callbacks from other methods are delivered to the event loop of the
* thread which called open(). If this thread has no event loop, then
* callbacks are delivered to the main application event loop. If there
* is no main application event loop, callbacks are not delivered.
*
* <p class="caution"><b>Caution:</b> On some devices, this method may
* take a long time to complete. It is best to call this method from a
* worker thread (possibly using {@link android.os.AsyncTask}) to avoid
* blocking the main application UI thread.
*
* @param cameraId the hardware camera to access, between 0 and
* {@link #getNumberOfCameras()}-1.
* @return a new Camera object, connected, locked and ready for use.
* @throws RuntimeException if opening the camera fails (for example, if the
* camera is in use by another process or device policy manager has
* disabled the camera).
* @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName)
*/
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
注意到該方法返回我們輸入?yún)?shù)獲取對(duì)應(yīng)的Camera對(duì)象亿扁,項(xiàng)目中我是通過Camera.open(0)
獲取到Camera
對(duì)象的。
- 程序運(yùn)行到
mediarecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
捕獲到空指針異常鸟廓。
我們先來了解一下setProfile(getProfile())
方法有什么作用:
百度上的解釋 設(shè)置錄制文件質(zhì)量从祝,格式,分辨率之類
Camcorder.get()方法和Camera.open()相似系統(tǒng)同樣有兩個(gè)重載方法
- CamcorderProfile.get(int) 單參數(shù)
- CamcorderProfile.get(int,int) 雙參數(shù)
我們看一下系統(tǒng)中兩個(gè)方法的定義:
/**
* Returns the camcorder profile for the first back-facing camera on the
* device at the given quality level. If the device has no back-facing
* camera, this returns null.
* @param quality the target quality level for the camcorder profile
* @see #get(int, int)
*/
public static CamcorderProfile get(int quality) {
int numberOfCameras = Camera.getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
return get(i, quality);
}
}
return null;
}
**和Camera.open()
一樣引谜,并沒有返回要設(shè)置的內(nèi)容牍陌,而是返回一個(gè)NULL
,所以我們只能調(diào)用CamcorderProfile.get(int,int);
來設(shè)置錄制質(zhì)量员咽,看一下雙參數(shù)的系統(tǒng)方法毒涧,如下: **
/**
* Returns the camcorder profile for the given camera at the given
* quality level.
*
* A camcorder recording session with higher quality level usually has higher output
* bit rate, better video and/or audio recording quality, larger video frame
* resolution and higher audio sampling rate, etc, than those with lower quality
* level.
*
* @param cameraId the id for the camera
* @param quality the target quality level for the camcorder profile.
* @see #QUALITY_LOW
*/
public static CamcorderProfile get(int cameraId, int quality) {
if (!((quality >= QUALITY_LIST_START &&
quality <= QUALITY_LIST_END) ||
(quality >= QUALITY_TIME_LAPSE_LIST_START &&
quality <= QUALITY_TIME_LAPSE_LIST_END) ||
(quality >= QUALITY_HIGH_SPEED_LIST_START &&
quality <= QUALITY_HIGH_SPEED_LIST_END))) {
String errMessage = "Unsupported quality level: " + quality;
throw new IllegalArgumentException(errMessage);
}
return native_get_camcorder_profile(cameraId, quality);
}
setProfile(CamcorderProfile)方法也可以看一下具體設(shè)置那些東西
/**
* Uses the settings from a CamcorderProfile object for recording. This method should
* be called after the video AND audio sources are set, and before setOutputFile().
* If a time lapse CamcorderProfile is used, audio related source or recording
* parameters are ignored.
*
* @param profile the CamcorderProfile to use
* @see android.media.CamcorderProfile
*/
public void setProfile(CamcorderProfile profile) {
setOutputFormat(profile.fileFormat);
setVideoFrameRate(profile.videoFrameRate);
setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
setVideoEncodingBitRate(profile.videoBitRate);
setVideoEncoder(profile.videoCodec);
if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {
// Nothing needs to be done. Call to setCaptureRate() enables
// time lapse video recording.
} else {
setAudioEncodingBitRate(profile.audioBitRate);
setAudioChannels(profile.audioChannels);
setAudioSamplingRate(profile.audioSampleRate);
setAudioEncoder(profile.audioCodec);
}
}