应用场景:
在Android开发过程中,有时需要调用手机自身设备的功能,上篇文章主要侧重摄像头拍照功能的调用。本篇文章将综合实现拍照与视频的操作。知识点介绍:
该部分请阅读 【Android 调用摄像头功能】使用方式:
第一步:新建一个Android项目CameraPhotoVedio,包含两个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; //调用摄像头按钮 @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="计时区域" 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; //摄像区域是否准备良好 private boolean isRecording = true; // true表示没有录像,点击开始;false表示正在录像,点击暂停 private boolean bool; private int hour = 0; private int minute = 0; //计时专用 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(); //设置Camera的角度/方向 camera.setDisplayOrientation(90); Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewFrameRate(5); // 每秒5帧 parameters.setPictureFormat(ImageFormat.JPEG);// 设置照片的输出格式 parameters.set("jpeg-quality", 85);// 照片质量 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; } }); //开发时建议设置 //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: //点击开始录像 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(); } //表面设置显示记录媒体(视频)的预览 mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface()); //开始捕捉和编码数据到setOutputFile(指定的文件) mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); //设置用于录制的音源 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //设置在录制过程中产生的输出文件的格式 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //设置视频编码器,用于录制 mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //设置audio的编码格式 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置要捕获的视频的宽度和高度 mediaRecorder.setVideoSize(320, 240); // 设置要捕获的视频帧速率 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 { //点击停止录像 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);// 设置照片的输出格式 parameters.set("jpeg-quality", 85);// 照片质量 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);// 设置照片的输出格式 parameters.set("jpeg-quality", 85);// 照片质量 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; } } } /* * 定时器设置,实现计时 */ 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; } }}
第三步:该项目需要一个工具类FormatUtil.java
import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import android.os.Environment;public class FormatUtil { /** * 将缓存文件夹的数据转存到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); } /** * 用以计时操作的相关方法 * @param num * @return */ public static String format(int num){ String s = num + ""; if (s.length() == 1) { s = "0" + s; } return s; }}
<?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>
页面效果:
效果截图