Android音視頻之視頻采集(系統(tǒng)API預(yù)覽)
我們了解了視頻相關(guān)的基礎(chǔ)知識,后面的文章我們要能夠和音頻一樣可以采集我們的視頻,視頻是一幀一幀的圖片來的,我們首先要學習預(yù)覽視頻,然后采集一幀圖片,采集視頻從簡到難的來了解這個問題。首先第一個反應(yīng)打開Google搜索和Android視頻采集相關(guān)的東西,我們要知道如何通過API來采集,不由自主地到了Android官網(wǎng)的Camera API。Android有兩個視頻采集的API,Camera是Android 5.0以前使用的,現(xiàn)在已經(jīng)廢棄了,我們還是得學一下他的使用,Camera2是最新的視頻采集API,我們重點了解它的使用。這篇文章我們掌握調(diào)用系統(tǒng)的拍照和錄制視頻API來實現(xiàn)拍照錄像功能。
Camera
它是API21(Android5.0)以前用來對攝像頭數(shù)據(jù)采集的的API,我們從開始到每個環(huán)節(jié)的關(guān)鍵內(nèi)容記錄如下。
基礎(chǔ)知識
先來了解使用Camera有幾個相關(guān)聯(lián)的類。
Camera:API21以后老的API控制攝像頭設(shè)備
SurfaceView:顯示攝像頭預(yù)覽圖像給用戶
MediaRecorder:錄制攝像頭的視頻
權(quán)限聲明
攝像頭權(quán)限:我們要使用Camera設(shè)備必須要聲明一個權(quán)限
<uses-permission android:name="android.permission.CAMERA" />
但是當我們使用Intent來調(diào)用系統(tǒng)自己的Camera設(shè)備拍照錄像就不需要這個權(quán)限。
攝像頭特征:應(yīng)用必須聲明使用攝像頭特性權(quán)限(這個不知道是啥意思的要了解uses-feature這個清單文件的意義)
<uses-feature android:name="android.hardware.camera" />
音頻錄制權(quán)限:當錄制視頻的時候我們還要音頻就要加上這個權(quán)限。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
存儲權(quán)限:如果我們要保存相片和視頻在存儲設(shè)備那么就要加上這個權(quán)限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
定位權(quán)限:如果照片的標簽要GPS位置信息,我們就要如下權(quán)限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
調(diào)用系統(tǒng)的攝像頭app來拍照和錄制視頻
拍照
請求攝像頭特征
<manifest ... >
<uses-feature android:name="android.hardware.camera"
android:required="true" />
...
</manifest>
這個權(quán)限可以讓GooglePlay來判斷是否設(shè)備支持下載我們的應(yīng)用,如果設(shè)置required為true那么一定要有攝像頭硬件設(shè)備的才能下載,如果設(shè)置required為false,那么沒有攝像頭硬件設(shè)備的也可以下載,當然我們在程序里面就要判斷一下是否有攝像頭可用了。
使用默認Intent開始拍照
調(diào)用默認的開啟系統(tǒng)拍照App的Intent
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
獲取拍照圖片
我們剛才通過startActivityForResult來拍照了,很自然的在onActivityResult來接受返回的數(shù)據(jù),我們把圖片顯示在一個ImageView上面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(imageBitmap);
}
}
通過這種默認的拍照我們不需要在Android6.0以上的機器聲明任何權(quán)限就可以成功執(zhí)行。
自定義保存相片圖片路徑
我們上面的操作,獲取來的是一個bitmap,我們的圖片信息都是在內(nèi)存里面操作的,如果我們要保存拍照的圖片到存儲卡并且查看圖片,那么我們只要聲明一個寫存儲卡權(quán)限就OK。
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
開始重新請求拍照代碼
static final int REQUEST_TAKE_PHOTO = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
...
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
上面的代碼我們使用了FileProvider.getUriForFile方法,它返回content://URI,這個API在Android7.0以上使用不做處理會拋出FileUriExposedException。我們要在清單文件注冊配置一個FileProvider
<application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.android.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> ... </application>
在res/xml/file_paths配置文件
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> </paths>
添加照片到相冊
我們上面的照片保存位置根目錄為getExternalFilesDir(Environment.DIRECTORY_PICTURES);這個目錄下面多媒體掃描器是不能找到我們的照片的,因為它是我們App私有的。下面的代碼可以讓系統(tǒng)的多媒體掃描器添加我們的圖片到Media Provider's 數(shù)據(jù)庫,讓我們的圖片對系統(tǒng)相冊和其他應(yīng)用都可以使用。
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
try {
MediaStore.Images.Media.insertImage(getContentResolver(),
f.getAbsolutePath(), f.getName(), null);
Log.d(TAG, "galleryAddPic: add to Media Scanner success");
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "galleryAddPic: add to Media Scanner failed");
}
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
Toast.makeText(this, "Add to Gallery success", Toast.LENGTH_SHORT).show();
}
解碼縮放圖片
我們在把圖片ImageView上面,沒有做任何處理,如果圖片較大,會導致oom的,做一個縮放處理。
private void setPic() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}
錄像
錄制視頻播放的代碼很簡單,如果要對視頻播放器進行定制,那么久要多一些東西,我們現(xiàn)在只簡單的可以播放調(diào)用系統(tǒng)錄制的視頻。
開啟視頻錄制Intent
static final int REQUEST_VIDEO_CAPTURE = 1;
private void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
在onActivityResult里面接收視頻Uri來播放
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
Uri videoUri = intent.getData();
Log.d(TAG, "onActivityResult: " + videoUri);
mVideoView.setVideoURI(videoUri);
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(false);//設(shè)置視頻重復(fù)播放
}
});
mVideoView.start();//播放視頻
MediaController mediaController = new MediaController(this);//顯示控制條
mVideoView.setMediaController(mediaController);
mediaController.setMediaPlayer(mVideoView);//設(shè)置控制的對象
mediaController.show();
}
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android ImageView 固定寬高比例的實現(xiàn)方法
這篇文章主要介紹了Android ImageView 固定寬高比例的實現(xiàn)方法的相關(guān)資料,,方法一:設(shè)置 adjustViewBounds="true",方法二:使用 Universal-Image-Loader 圖片緩存類,需要注意的是方法二和方法一同時使用導致設(shè)置無效,需要的朋友可以參考下2017-07-07
Android?Camera實現(xiàn)旋轉(zhuǎn)角度
這篇文章主要為大家詳細介紹了Android?Camera實現(xiàn)旋轉(zhuǎn)角度,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07
Android SDK Manager國內(nèi)無法更新的解決方案
本文主要介紹Android SDK Manager國內(nèi)無法更新的解決方案,這里提供了解決方法,及簡單說明實現(xiàn)流程,有興趣的小伙伴可以參考下2016-09-09
Android開發(fā)之全屏與非全屏的切換設(shè)置方法小結(jié)
這篇文章主要介紹了Android開發(fā)之全屏與非全屏的切換設(shè)置方法,結(jié)合實例形式分析了Android全屏切換靜態(tài)與動態(tài)兩種實現(xiàn)方法,需要的朋友可以參考下2017-08-08
Android usb設(shè)備權(quán)限查詢及自動獲取詳解流程
本篇文章介紹了我想要獲取Android系統(tǒng)usb設(shè)備使用權(quán)限時遇到的問題,以及解決該問題的過程及思路,通讀本篇對大家的學習或工作具有一定的價值,需要的朋友可以參考下2021-10-10
Android編程實現(xiàn)動態(tài)更新ListView的方法
這篇文章主要介紹了Android編程實現(xiàn)動態(tài)更新ListView的方法,結(jié)合實例形式詳細分析了ListView的布局及動態(tài)更新實現(xiàn)方法,需要的朋友可以參考下2016-02-02
Android 中ScrollView與ListView沖突問題的解決辦法
這篇文章主要介紹了Android 中ScrollView與ListView沖突問題的解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握解決問題的辦法,需要的朋友可以參考下2017-10-10

