一、概述
之前做了一個(gè) Android 應(yīng)用,有一個(gè)功能是:用戶錄制視頻并保存到本地浸遗,然后可以查看在當(dāng)前 APP 中錄制的視頻并進(jìn)行一些“上傳”或“刪除”操作癣漆。
這里主要有兩個(gè)功能暑脆,首先要錄制視頻然后保存到一個(gè)特定的文件夾交排,這個(gè)文件夾就用來存放本應(yīng)用中錄制的視頻。然后可以將這個(gè)文件夾中的所有文件以列表的形式展示給用戶看饵筑,并附帶縮略圖埃篓。
剛開始的時(shí)候我想自己寫一個(gè)錄制的功能,無奈本領(lǐng)不濟(jì)根资,左改右改都不好用架专,要么是視頻被拉伸,要么是錄制時(shí)不清晰玄帕,所以最后還是決定使用手機(jī)自帶的錄像功能部脚,現(xiàn)在把該模塊的 Demo 拿上來與大家交流一下。
Demo
二裤纹、代碼解析
這里的代碼解析只貼了一些重要代碼委刘,想要完整代碼可以下載上面的 Demo 運(yùn)行。
1. 錄制及保存
從代碼中我們看出鹰椒,我們點(diǎn)擊“錄制”按鈕锡移,會(huì)首先生成一個(gè)文件的 uri,這個(gè) uri 就代表將要錄制的視頻文件漆际,uri 里有這個(gè)文件保存的文件夾以及這個(gè)文件的名字淆珊。
之后我們通過隱式 Intent 啟動(dòng)系統(tǒng)的錄像功能,并將文件的 uri 傳入奸汇,文件就能根據(jù)設(shè)置的 uri 保存到指定文件夾施符。
/**
* 點(diǎn)擊錄制視頻,調(diào)用系統(tǒng)播放器開始錄像
*/
main_button_record.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
fileUri = Uri.fromFile(createMediaFile());
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.setAction("android.media.action.VIDEO_CAPTURE");
intent.addCategory("android.intent.category.DEFAULT");
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // 設(shè)置視頻文件的名字
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // 設(shè)置視頻質(zhì)量為高
startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}
});
/**
* 創(chuàng)建一個(gè)文件的 uri擂找,供視頻錄制完保存
*/
private File createMediaFile() throws IOException {
// 如果 SD 卡存在戳吝,則在外部存儲(chǔ)建立一個(gè)文件夾用于存放視頻
if ((Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))) {
// 選擇自己的文件夾
String path = Environment.getExternalStorageDirectory().getPath();
// Constants.video_url 是一個(gè)常量,代表存放視頻的文件夾
File mediaStorageDir = new File(path + Constants.video_url);
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.e("TAG", "文件夾創(chuàng)建失敗");
return null;
}
}
// 文件根據(jù)當(dāng)前的毫秒數(shù)給自己命名
String timeStamp = String.valueOf(System.currentTimeMillis());
timeStamp = timeStamp.substring(7);
String imageFileName = "V" + timeStamp;
String suffix = ".mp4";
File mediaFile = new File(mediaStorageDir + File.separator + imageFileName + suffix);
return mediaFile;
}
return null;
}
2. 查看視頻文件列表
這里有兩個(gè)重要方法贯涎。
一個(gè)是獲取文件的列表听哭,在這個(gè)方法中,我們先判斷外部 SD 卡是否可用柬采,如果可用欢唾,就獲取之前保存文件的目錄下的所有文件且警。文件的屬性中有一個(gè)最后修改時(shí)間粉捻,我們就拿來用作文件的發(fā)布時(shí)間。
第二個(gè)方法是用于獲取視頻的縮略圖的斑芜,這個(gè)方法需要文件的路徑并通過路徑獲取縮略圖肩刃。路徑 filePath 使用 files.getPath() 或 files.getAbsolutePath() 都可以。
/**
* 獲取文件列表
*/
public void GetVideoFiles(){
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 獲取該文件夾下的所有文件
String path = Environment.getExternalStorageDirectory().getPath();
File mediaStorageDir = new File(path + Constants.video_url);
File[] files = mediaStorageDir.listFiles();
if (files != null && files.length > 0) {
for(int i = 0; i < files.length; i++){
VideoItem videoItem = new VideoItem();
videoItem.setVideoName(files[i].getName());
String publish_time = new SimpleDateFormat("yyyy年MM月dd日").format(files[i].lastModified());
videoItem.setTime(publish_time);
videoItem.setBitmap(getVideoThumbnail(files[i].getAbsolutePath()));
mVideoItems.add(videoItem);
}
} else {
Toast.makeText(this, "沒有視頻文件!", Toast.LENGTH_SHORT).show();
}
}
}
/**
* 根據(jù)視頻文件的路徑獲取視頻的縮略圖
* filePath 使用 files.getPath() 或 files.getAbsolutePath() 都可以
*/
public Bitmap getVideoThumbnail(String filePath) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(filePath);
bitmap = retriever.getFrameAtTime();
} catch(IllegalArgumentException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
try {
retriever.release();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
return bitmap;
}