Android Camera 使用小結

Android Camera 使用小結

Android手機關於Camera的使用,一是拍照,二是攝像,因爲Android提供了強大的組件功能,爲此對於在Android手機系統上進行Camera的開發,咱們可使用兩類方法:一是藉助Intent和MediaStroe調用系統Camera App程序來實現拍照和攝像功能,二是根據Camera API自寫Camera程序。因爲自寫Camera須要對Camera API瞭解很充分,並且對於通用的拍照和攝像應用只須要藉助系統Camera App程序就能知足要求了,爲此先從調用系統Camera App應用開始來對Android Camera作個簡單的使用小結。html

調用系統Camera App實現拍照和攝像功能

不是專門的Camera應用,通常用到Camera的需求就是獲取照片或者視頻,好比微博分享、隨手記等,對於在Symbian系統上經過簡單地調用系統自帶的Camera APP來實現該功能是作不到的,可是Android系統強大的組件特性,使得應用開發者只需經過Intent就能夠方便的打開系統自帶的Camera APP,並經過MediaStroe方便地獲取照片和視頻的文件路徑。具體咱們仍是用代碼來講話吧:android

例一、 實現拍照app

在菜單或按鈕的選擇操做中調用以下代碼,開啓系統自帶Camera APP,並傳遞一個拍照存儲的路徑給系統應用程序,具體以下:ide

imgPath = "/sdcard/test/img.jpg";函數

//必須確保文件夾路徑存在,不然拍照後沒法完成回調佈局

File vFile = new File(imgPath);post

if(!vFile.exists())測試

{this

File vDirPath = vFile.getParentFile(); //new File(vFile.getParent());url

vDirPath.mkdirs();

}

Uri uri = Uri.fromFile(vFile);

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//

startActivityForResult(intent, SystemCapture);

上面咱們使用的是startActivityForResult,因此最好須要重載void onActivityResult(int requestCode, int resultCode, Intent data)函數,不過由於當傳入文件路徑的的狀況下,data返回參數是null值,只要resultCode爲RESULT_OK,則上述代碼中/sdcard/test/img.jpg的圖片文件就是最新的照片文件。因此咱們在這裏只需給出以下簡單的代碼,將其顯示到ImageView中

if (resultCode == RESULT_OK)

{

iViewPic.setImageURI(Uri.fromFile(new File(imgPath)));

}

假設不傳參數MediaStore.EXTRA_OUTPUT的狀況下,onActivityResult函數在resultCode爲RESULT_OK的狀況下,data返回的參數是通過實際拍攝照片通過縮放的圖像數據,能夠經過相似以下方法來打印縮放圖像的尺寸

if (resultCode == RESULT_OK)

{

Bitmap bmp = (Bitmap)data.getExtras().get("data");

Log.d("Test", "bmp width:" + bmp.getWidth() + ", height:" + bmp.getHeight());

}

另外假如僅僅是調用系統照相機拍照,不關心拍照結果,則能夠簡單使用以下代碼

Intent intent = new Intent(); //調用照相機

intent.setAction("android.media.action.STILL_IMAGE_CAMERA");

startActivity(intent);

備註:上面設置MediaStore.EXTRA_OUTPUT的方法,通過手機實測除了咱們設定的路徑下有照片外,在手機存儲卡上也會保存一份照片,默認目錄爲sdcard/dcim/camera下面,我曾經嘗試着想若是每次返回能夠取得sdcard/dcim/camera下面的路徑就行了,可是目前看來沒辦法直接得到,能夠藉助MediaStroe每次去查詢最後一條照片記錄,應該也是可行的。

例二、 實現攝像

在攝像功能時,嘗試着設置MediaStore.EXTRA_OUTPUT以傳入相似拍照時的文件路徑,結果在個人測試真機上,那個視頻文件竟然是一個0k的空文件,最後經過相似以下代碼實現

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//參數設置能夠省略

startActivityForResult(intent, SystemVideoRecord);

在onActivityResult函數中進行以下代碼調用

Uri videoUri = data.getData();

//String[] projection = { MediaStore.Video.Media.DATA, MediaStore.Video.Media.SIZE };

Cursor cursor = managedQuery(videoUri, null, null, null, null);

cursor.moveToFirst();//這個必須加,不然下面讀取會報錯

int num = cursor.getCount();

String recordedVideoFilePath = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));

int recordedVideoFileSize = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));

iResultText.setText(recordedVideoFilePath);

Log.i("videoFilePath", recordedVideoFilePath);

Log.i("videoSize", ""+recordedVideoFileSize);

上面的返回參數data,也會由於用戶是否設置MediaStore.EXTRA_OUTPUT參數而改變,假設沒有經過EXTRA_OUTPUT設置路徑,data.getData返回的Uri爲content://media/external/video/media/*,*個數字,表明具體的記錄號,經過managedQuery能夠獲取到路徑,假如設置了EXTRA_OUTPUT的話(好比/sdcard/test.3gp),則data.getData返回的Uri則爲file:///sdcard/test.3gp,可是該文件竟然是空白內容(不知道是否是跟手機有關,也沒有在其它手機上驗證過)。

根據Camera API實現本身的拍照和攝像程序

經過上面對調用系統Camera App實現拍照和攝像功能的例子,咱們發現雖然可以知足咱們的需求,可是畢竟自由度下降了,並且拍照的界面就是系統的樣子,如今不少拍照程序,好比火爆的Camera 360軟件等,就須要根據SDK提供的Camera API來編寫本身的程序。

準備工做

上面調用系統Camera App,咱們壓根不須要任何權限,可是這裏用Camera API,就必須在manifest內聲明使用權限,一般由如下三項

<uses-permission android:name = "android.permission.CAMERA" />

<uses-feature android:name = "android.hardware.camera" />

<uses-feature android:name = "android.hardware.camera.autofocus" />

通常拍照和攝像的時候須要寫到sd卡上,因此還有一貫權限聲明以下

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

真作攝像功能時,須要音頻錄製和視頻錄製功能,因此又須要下面兩項權限聲明

<uses-permission android:name="android.permission.RECORD_VIDEO"/>

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

另外使用Camera API拍照或攝像,都須要用到預覽,預覽就要用到SurfaceView,爲此Activity的佈局中必須有SurfaceView。

拍照流程

上面簡單介紹了下準備工做,下面結合拍照過程當中的須要用到的API對拍照流程作下簡單描述

一、在Activity的OnCreate函數中設置好SurfaceView,包括設置SurfaceHolder.Callback對象和SurfaceHolder對象的類型,具體以下

SurfaceView mpreview = (SurfaceView) this.findViewById(R.id.camera_preview);

SurfaceHolder mSurfaceHolder = mpreview.getHolder();

mSurfaceHolder.addCallback(this);

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

二、在SurfaceHolder.Callback的surfaceCreated函數中,使用Camera的Open函數開機攝像頭硬件,這個API在SDK 2.3以前,是沒有參數的,2.3之後支持多攝像頭,因此開啓前能夠經過getNumberOfCameras先獲取攝像頭數目,再經過getCameraInfo獲得須要開啓的攝像頭id,而後傳入Open函數開啓攝像頭,假如攝像頭開啓成功則返回一個Camera對象,不然就拋出異常;

三、開啓成功的狀況下,在SurfaceHolder.Callback的surfaceChanged函數中調用getParameters函數獲得已打開的攝像頭的配置參數Parameters對象,若是有須要就修改對象的參數,而後調用setParameters函數設置進去(SDK2.2之後,還能夠經過Camera::setDisplayOrientation設置方向);

四、一樣在surfaceChanged函數中,經過Camera::setPreviewDisplay爲攝像頭設置SurfaceHolder對象,設置成功後調用Camera::startPreview函數開啓預覽功能,上面3,4兩步的代碼能夠以下所示

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)

{

//已經得到Surface的width和height,設置Camera的參數

Camera.Parameters parameters = camera.getParameters();

parameters.setPreviewSize(w, h);

List<Size> vSizeList = parameters.getSupportedPictureSizes();

for(int num = 0; num < vSizeList.size(); num++)

{

Size vSize = vSizeList.get(num);

}

if(this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE)

{

//若是是豎屏

parameters.set("orientation", "portrait");

//在2.2以上可使用

//camera.setDisplayOrientation(90);

}

else

{

parameters.set("orientation", "landscape");

//在2.2以上可使用

//camera.setDisplayOrientation(0);

}

camera.setParameters(parameters);

try {

//設置顯示

camera.setPreviewDisplay(holder);

} catch (IOException exception) {

camera.release();

camera = null;

}

//開始預覽

camera.startPreview();

}

五、假設要支持自動對焦功能,則在須要的狀況下,或者在上述surfaceChanged調用完startPreview函數後,能夠調用Camera::autoFocus函數來設置自動對焦回調函數,該步是可選操做,有些設備可能不支持,能夠經過Camera::getFocusMode函數查詢。代碼能夠參考以下:

// 自動對焦

camera.autoFocus(new AutoFocusCallback()

{

@Override

public void onAutoFocus(boolean success, Camera camera)

{

if (success)

{

// success爲true表示對焦成功,改變對焦狀態圖像

ivFocus.setImageResource(R.drawable.focus2);

}

}

});

六、在須要拍照的時候,調用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)函數來完成拍照,這個函數中能夠四個回調接口,ShutterCallback是快門按下的回調,在這裏咱們能夠設置播放「咔嚓」聲之類的操做,後面有三個PictureCallback接口,分別對應三份圖像數據,分別是原始圖像、縮放和壓縮圖像和JPG圖像,圖像數據能夠在PictureCallback接口的void onPictureTaken(byte[] data, Camera camera)中得到,三份數據相應的三個回調正好按照參數順序調用,一般咱們只關心JPG圖像數據,此時前面兩個PictureCallback接口參數能夠直接傳null;

七、每次調用takePicture獲取圖像後,攝像頭會中止預覽,假如須要繼續拍照,則咱們須要在上面的PictureCallback的onPictureTaken函數末尾,再次掉喲更Camera::startPreview函數;

八、在不須要拍照的時候,咱們須要主動調用Camera::stopPreview函數中止預覽功能,而且調用Camera::release函數釋放Camera,以便其餘應用程序調用。SDK中建議放在Activity的Pause函數中,可是我以爲放在surfaceDestroyed函數中更好,示例代碼以下

// 中止拍照時調用該方法

public void surfaceDestroyed(SurfaceHolder holder)

{

// 釋放手機攝像頭

camera.release();

}

以上就是本身實現拍照程序的的流程,通常還能夠還能夠獲取預覽幀的圖像數據,能夠分別經過Camera::setPreviewCallback和Camera::setOneShotPreviewCallback來設置每幀或下一幀圖像數據的回調,這裏就不作展開了。

攝像流程

攝像流程也是須要預覽的,並且流程上與拍照流程在起始的1~4步流程和結束的8流程是同樣的,惟一不一樣的是6和7兩個步驟,至於5自動對焦自己就是可選的,在攝像流程也不必。

六、開啓視頻錄製,須要建立一個MediaRecorder對象,並調用Camera::unLock操做解鎖攝像頭,由於默認Camera都是鎖定的,只有解鎖後MediaRecorder等多媒體進程調用,並設置一些參數,而後調用MediaRecorder:: start開啓錄製具體能夠參閱以下代碼:

MediaRecorder mMediaRecorder = new MediaRecorder();

// Unlock the camera object before passing it to media recorder.

camera.unlock();

mMediaRecorder.setCamera(camera);

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);

mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

mMediaRecorder.setProfile(mProfile);

mMediaRecorder.setMaxDuration(100000);//ms爲單位

long dateTaken = System.currentTimeMillis();

Date date = new Date(dateTaken);

SimpleDateFormat dateFormat = new SimpleDateFormat(getString(R.string.video_file_name_format));

String title = dateFormat.format(date);

String filename = title + ".3gp"; // Used when emailing.

String cameraDirPath = ImageManager.CAMERA_IMAGE_BUCKET_NAME;

String filePath = cameraDirPath + "/" + filename;

File cameraDir = new File(cameraDirPath);

cameraDir.mkdirs();

mMediaRecorder.setOutputFile(filePath);

try {

mMediaRecorder.prepare();

mMediaRecorder.start(); // Recording is now started

} catch (RuntimeException e) {

Log.e(TAG, "Could not start media recorder. ", e);

return;

}

七、上面設置了最大間隔爲100s,當100是視頻錄製結束,錄製就會被中止,若是沒有設時長和文件大小限制,那麼一般須要調用MediaRecorder:: stop函數主動中止視頻的錄製,並將Camera對象經過lock函數繼續加鎖,示例代碼以下

mMediaRecorder.stop();

mMediaRecorder.reset();

mMediaRecorder.release();

mMediaRecorder = null;

if(camera != null)

camera.lock();

以後的操做根據交互要麼從新錄製要麼就釋放Camera對象回到拍照流程的8步驟了。在這裏就不作贅述了。

使用和整理過程當中,因爲英文不太好,很是感謝網上的一篇SDK中文翻譯,連接地址以下

http://blog.csdn.net/raindrophust/article/details/6205038

另外Android開發,最佳借鑑,我以爲仍是源碼,Camera的不少參數和使用方法能夠參照源碼中Camera APP的源碼,目錄爲packages\apps\Camera。

相關文章
相關標籤/搜索