Android實(shí)現(xiàn)調(diào)用攝像頭拍照與視頻功能
應(yīng)用場(chǎng)景:
在Android開發(fā)過程中,有時(shí)需要調(diào)用手機(jī)自身設(shè)備的功能,上篇文章主要側(cè)重?cái)z像頭拍照功能的調(diào)用。本篇文章將綜合實(shí)現(xiàn)拍照與視頻的操作。
知識(shí)點(diǎn)介紹:
該部分請(qǐng)閱讀 【Android 調(diào)用攝像頭功能】
使用方式:
第一步:
新建一個(gè)Android項(xiàng)目CameraPhotoVedio,包含兩個(gè)Activity: MainActivity、CameraActivity。
第二步:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/shape_main" tools:context=".MainActivity" > <LinearLayout android:layout_height="wrap_content" android:layout_marginTop="50dp" android:layout_width="match_parent" android:orientation="vertical"> <ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" android:src="@drawable/main"/> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_marginTop="100dp" android:layout_width="match_parent" android:layout_alignParentBottom="true" android:orientation="vertical"> <Button android:id="@+id/main_button" android:layout_height="50dp" android:layout_marginBottom="50dp" android:background="@drawable/shape_main" android:layout_width="match_parent" android:textColor="#FFFFFF" android:text="使用攝像頭"/> </LinearLayout> </RelativeLayout>
MainActivity.java
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button button; //調(diào)用攝像頭按鈕
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
button = (Button) findViewById(R.id.main_button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(), CameraActivity.class));
}
});
}
} activity_camera.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#FFFFFF" android:layout_height="match_parent" tools:context=".CameraActivity" > <SurfaceView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/camera_surfaceview"/> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="計(jì)時(shí)區(qū)域" android:id="@+id/camera_time"/> <LinearLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_alignParentBottom="true" android:orientation="horizontal"> <Button android:layout_height="30dp" android:layout_width="match_parent" android:layout_marginBottom="20dp" android:layout_weight="1" android:background="@drawable/shape_main" android:id="@+id/camera_photo" android:layout_marginLeft="5dp" android:textColor="#FFFFFF" android:layout_marginRight="5dp" android:text="照片攝取"/> <Button android:layout_height="30dp" android:layout_marginBottom="20dp" android:layout_width="match_parent" android:layout_weight="1" android:background="@drawable/shape_main" android:id="@+id/camera_vedio" android:layout_marginLeft="5dp" android:textColor="#FFFFFF" android:layout_marginRight="5dp" android:text="視頻攝取"/> </LinearLayout> </RelativeLayout>
CameraActivity.java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import com.example.cameraphotovideo.utils.FormatUtil;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.app.Activity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class CameraActivity extends Activity {
private String tag ="MaHaochen_______CameraActivity";
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private Camera camera;
private MediaRecorder mediaRecorder;
private Button photoButton; //拍照按鈕
private Button vedioButton; //攝像按鈕
private TextView timeTextView;
protected boolean isPreview = false; //攝像區(qū)域是否準(zhǔn)備良好
private boolean isRecording = true; // true表示沒有錄像,點(diǎn)擊開始;false表示正在錄像,點(diǎn)擊暫停
private boolean bool;
private int hour = 0;
private int minute = 0; //計(jì)時(shí)專用
private int second = 0;
private File mRecVedioPath;
private File mRecAudioFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
initCamera();
initViews();
}
//初始化攝像頭
private void initCamera() {
mRecVedioPath = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/mahc/video/temp/");
if (!mRecVedioPath.exists()) {
mRecVedioPath.mkdirs();
}
surfaceView = (SurfaceView) findViewById(R.id.camera_surfaceview);
SurfaceHolder cameraSurfaceHolder = surfaceView.getHolder();
cameraSurfaceHolder.addCallback(new Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
//設(shè)置Camera的角度/方向
camera.setDisplayOrientation(90);
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewFrameRate(5); // 每秒5幀
parameters.setPictureFormat(ImageFormat.JPEG);// 設(shè)置照片的輸出格式
parameters.set("jpeg-quality", 85);// 照片質(zhì)量
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
isPreview = true;
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
surfaceHolder = holder;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
surfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
if (isPreview) {
camera.stopPreview();
isPreview = false;
}
camera.release();
camera = null; // 記得釋放Camera
}
surfaceView = null;
surfaceHolder = null;
mediaRecorder = null;
}
});
//開發(fā)時(shí)建議設(shè)置
//This method was deprecated in API level 11. this is ignored, this value is set automatically when needed.
cameraSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
//初始化視圖組件
private void initViews() {
timeTextView = (TextView) findViewById(R.id.camera_time);
timeTextView.setVisibility(View.GONE);
photoButton = (Button) findViewById(R.id.camera_photo);
vedioButton = (Button) findViewById(R.id.camera_vedio);
ButtonOnClickListener onClickListener = new ButtonOnClickListener();
photoButton.setOnClickListener(onClickListener);
vedioButton.setOnClickListener(onClickListener);
}
class ButtonOnClickListener implements OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.camera_vedio:
//點(diǎn)擊開始錄像
if(isRecording){
if (isPreview) {
camera.stopPreview();
camera.release();
camera = null;
}
second = 0;
minute = 0;
hour = 0;
bool = true;
if(null==mediaRecorder){
mediaRecorder = new MediaRecorder();
}else {
mediaRecorder.reset();
}
//表面設(shè)置顯示記錄媒體(視頻)的預(yù)覽
mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
//開始捕捉和編碼數(shù)據(jù)到setOutputFile(指定的文件)
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//設(shè)置用于錄制的音源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//設(shè)置在錄制過程中產(chǎn)生的輸出文件的格式
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//設(shè)置視頻編碼器,用于錄制
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//設(shè)置audio的編碼格式
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//設(shè)置要捕獲的視頻的寬度和高度
mediaRecorder.setVideoSize(320, 240);
// 設(shè)置要捕獲的視頻幀速率
mediaRecorder.setVideoFrameRate(15);
try {
mRecAudioFile = File.createTempFile("Vedio", ".3gp",
mRecVedioPath);
} catch (IOException e) {
e.printStackTrace();
}
mediaRecorder.setOutputFile(mRecAudioFile.getAbsolutePath());
try {
mediaRecorder.prepare();
timeTextView.setVisibility(View.VISIBLE);
handler.postDelayed(task, 1000);
mediaRecorder.start();
} catch (Exception e) {
e.printStackTrace();
}
isRecording = !isRecording;
Log.e(tag, "=====開始錄制視頻=====");
}else {
//點(diǎn)擊停止錄像
bool = false;
mediaRecorder.stop();
timeTextView.setText(FormatUtil.format(hour)+":"+FormatUtil.format(minute)+":"+ FormatUtil.format(second));
mediaRecorder.release();
mediaRecorder = null;
FormatUtil.videoRename(mRecAudioFile);
Log.e(tag, "=====錄制完成,已保存=====");
isRecording = !isRecording;
try {
camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
// parameters.setPreviewFrameRate(5); // 每秒5幀
parameters.setPictureFormat(ImageFormat.JPEG);// 設(shè)置照片的輸出格式
parameters.set("jpeg-quality", 85);// 照片質(zhì)量
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
isPreview = true;
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case R.id.camera_photo:
if (mediaRecorder != null) {
try {
bool = false;
mediaRecorder.stop();
timeTextView.setText(FormatUtil.format(hour) + ":" + FormatUtil.format(minute) + ":"
+ FormatUtil.format(second));
mediaRecorder.release();
mediaRecorder = null;
FormatUtil.videoRename(mRecAudioFile);
} catch (Exception e) {
e.printStackTrace();
}
isRecording = !isRecording;
Log.e(tag, "=====錄制完成,已保存=====");
try {
camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
// parameters.setPreviewFrameRate(5); // 每秒5幀
parameters.setPictureFormat(ImageFormat.JPEG);// 設(shè)置照片的輸出格式
parameters.set("jpeg-quality", 85);// 照片質(zhì)量
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
isPreview = true;
} catch (Exception e) {
e.printStackTrace();
}
}
if (camera != null) {
camera.autoFocus(null);
camera.takePicture(null, null, new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
new SavePictureTask().execute(data);
camera.startPreview();
Log.e(tag,"=====拍照成功=====");
}
}); // 拍照
}
break;
default:
break;
}
}
}
/*
* 定時(shí)器設(shè)置,實(shí)現(xiàn)計(jì)時(shí)
*/
private Handler handler = new Handler();
private Runnable task = new Runnable() {
public void run() {
if (bool) {
handler.postDelayed(this, 1000);
second++;
if (second >= 60) {
minute++;
second = second % 60;
}
if (minute >= 60) {
hour++;
minute = minute % 60;
}
timeTextView.setText(FormatUtil.format(hour) + ":" + FormatUtil.format(minute) + ":"
+ FormatUtil.format(second));
}
}
};
class SavePictureTask extends AsyncTask<byte[], String, String> {
@Override
protected String doInBackground(byte[]... params) {
String path = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/mahc/image";
File out = new File(path);
if (!out.exists()) {
out.mkdirs();
}
File picture = new File(path+"/"+new Date().getTime()+".jpg");
try {
FileOutputStream fos = new FileOutputStream(picture.getPath());
fos.write(params[0]);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.e(tag, "=====照片保存完成=====");
CameraActivity.this.finish();
return null;
}
}
} 第三步:該項(xiàng)目需要一個(gè)工具類FormatUtil.java
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.os.Environment;
public class FormatUtil {
/**
* 將緩存文件夾的數(shù)據(jù)轉(zhuǎn)存到vedio文件下
* @param recAudioFile
*/
public static void videoRename(File recAudioFile) {
String path = Environment.getExternalStorageDirectory()
.getAbsolutePath()+ "/mahc/video/"+ "0" + "/";
String fileName = new SimpleDateFormat("yyyyMMddHHmmss")
.format(new Date()) + ".3gp";
File out = new File(path);
if (!out.exists()) {
out.mkdirs();
}
out = new File(path, fileName);
if (recAudioFile.exists())
recAudioFile.renameTo(out);
}
/**
* 用以計(jì)時(shí)操作的相關(guān)方法
* @param num
* @return
*/
public static String format(int num){
String s = num + "";
if (s.length() == 1) {
s = "0" + s;
}
return s;
}
} 第四步:本項(xiàng)目需要處理界面的背景樣式和按鈕的背景,所以需要在res/drawable文件新建shape_main.xml。
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#FFCC99" android:endColor="#99CC66" android:centerColor="#0066CC" android:angle="45" /> </shape>
頁面效果:
效果截圖

下載地址:Android實(shí)現(xiàn)調(diào)用攝像頭拍照與視頻功能
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Androidstudio調(diào)用攝像頭拍照并保存照片
- Android調(diào)用手機(jī)攝像頭拍照和錄音功能
- Android實(shí)現(xiàn)調(diào)用攝像頭拍照并存儲(chǔ)照片
- Android調(diào)用系統(tǒng)攝像頭拍照并顯示在ImageView上
- Android實(shí)現(xiàn)攝像頭拍照功能
- Android調(diào)用攝像頭拍照開發(fā)教程
- Android實(shí)現(xiàn)調(diào)用攝像頭進(jìn)行拍照功能
- Android 開發(fā)隨手筆記之使用攝像頭拍照
- Android調(diào)用外置攝像頭的方法
- Android實(shí)現(xiàn)控制攝像頭拍照
相關(guān)文章
簡(jiǎn)單仿寫Android控件SlidingMenu的實(shí)例代碼
下面小編就為大家分享一篇簡(jiǎn)單仿寫Android控件SlidingMenu的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01
android指定DatePickerDialog樣式并不顯示年的實(shí)現(xiàn)代碼
下面小編就為大家?guī)硪黄猘ndroid指定DatePickerDialog樣式并不顯示年的實(shí)現(xiàn)代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,祝大家游戲愉快哦2016-08-08
Kotlin編程基礎(chǔ)數(shù)據(jù)類型示例詳解
這篇文章主要為大家介紹了Kotlin編程基礎(chǔ)數(shù)據(jù)類型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Android仿QQ消息提示實(shí)現(xiàn)彈出式對(duì)話框
這篇文章主要為大家詳細(xì)介紹了Android仿QQ消息提示實(shí)現(xiàn)彈出式對(duì)話框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
Android組件ContextMenu實(shí)現(xiàn)長按事件
這篇文章主要為大家詳細(xì)介紹了Android組件ContextMenu實(shí)現(xiàn)長按事件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
Android中ViewFlipper的使用及設(shè)置動(dòng)畫效果實(shí)例詳解
這篇文章主要介紹了Android中ViewFlipper的使用及設(shè)置動(dòng)畫效果的方法,以實(shí)例形式較為詳細(xì)的分析了ViewFlipper的功能、原理及設(shè)置與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android Studio使用教程(二):基本設(shè)置與運(yùn)行
這篇文章主要介紹了Android Studio使用教程(二):基本設(shè)置與運(yùn)行,本文講解了項(xiàng)目結(jié)構(gòu)、偏好設(shè)置、常用功能介紹、創(chuàng)建模擬器等內(nèi)容,需要的朋友可以參考下2015-05-05
Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語言的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語言的方法,涉及Android資源、控件及屬性相關(guān)操作技巧,需要的朋友可以參考下2017-06-06

