首页 > 代码库 > Android开发之打开闪光灯录制视频
Android开发之打开闪光灯录制视频
Android的SDK在线API上对录制视频的方法、步骤都写得非常清楚,但是如果没有一点思路,写起来也比较式费事。录制视频的全过程要打开闪光灯(可能是因为项目需要,或者特殊原因),则必须按照一定的顺序进行开关,毕竟容易出错。要实现录制的同时开启闪光灯也不难,官方API给出了一个大体的步骤.因为要采集点视频数据,临时写了个简单的Demo学习下,必要时再深度开发。
首先在工程中的AndroidManifest.xml中添加权限声明,因为要使用到摄像头,故需要添加Camera的相关权限,另外还需要写SD卡的权限,如果同时需要录制音频,则还需要添加RECORD_AUDIO权限。
1 <uses-permission android:name="android.permission.CAMERA" />2 <uses-feature android:name="android.hardware.camera" />3 <uses-feature android:name="android.hardware.camera.autofocus" />4 <uses-permission android:name="android.permission.RECORD_AUDIO"/>5 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
再来分析下要使用到的类,录制视频使用的MediaRecorder类,官方给出了调用MediaRecorder录制视频的一个简单状态机,展示了各个状态之间的转化。然后也给出了一个简单的调用方法,代码如下:
1 MediaRecorder recorder = new MediaRecorder(); 2 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 3 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 4 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 5 recorder.setOutputFile(PATH_NAME); 6 recorder.prepare(); 7 recorder.start(); // Recording is now started 8 ... 9 recorder.stop();10 recorder.reset(); // You can reuse the object by going back to setAudioSource() step11 recorder.release(); // Now the object cannot be reused
录制视频是调用MediaRecorder类,但API中真正介绍如何录制视频的一般步骤却被放在了Camera类中,在线API上有句话提示“For more information about how to use MediaRecorder for recording video, read the Camera developer guide.”。转到Camera类去看看。
Camera类是用来控制照相机的,没错,就是这个类。照相机可以用来拍照,也可以用来录制视频(也叫捕捉视频),但是录制视频需要按照一定的步骤来编写程序,不然发生运行时错误是非常正常的。录制视频需要调用Camera和MediaRecorder类,下面说说一般步骤。
1) 打开照相机。直接调用Camera.open()来获取一个Camera的实例。
2) 设置预览控件。一般是设置在SurfaceView上面,通过调用Camera.setPreviewDisplay()来完成,但是这一步也可以放到MediaRecorder类DataSourceConfigured步骤中完成。
3) 开启预览。调用Camera.startPreview()。
4) 开始录制视频。为了确保你录制成功,请务必按要求完成下面的步骤。
A. 解锁照相机。通过调用Camera.unlock()解锁照相机,以便照相机被MediaRecorder使用。
B. 设置MediaRecorder。
这里有一系列的设置,根据需要设置吧。比如说,你只需要录制视频,就不必设置音频的输入源,也就不用设置音频的编码方式。对应于MediaRecorder state diagram中的Initialized和DataSourceConfigured。具体方法调用可以查看Android在线API的MediaRecorder类,上文已经将主要的代码贴出,下文还会贴出实例代码,这里就不详细介绍了。
C. 准备MediaRecorder。在调用MediaRecorder.prepare()之前一定要先设置好MediaRecorder对象的各项属性,后面设置会引发运行时错误。
D. 开始MediaRecorder。调用MediaRecorder.start()之后,就开始录制视频了。
5) 停止录制。
A. 停止MediaRecorder。调用MediaRecorder.stop()停止录制。
B. 恢复MediaRecorder的默认设置。调用MediaRecorder.reset()来取消你对MediaRecorder所做的设置,但调用玩之后,MediaRecorder对象还是可以再次使用的。
C. 释放MediaRecorder对象。调用MediaRecorder.release()释放资源,之后该MediaRecorder对象销毁了,再调用会出错。
D. 给Camera上锁。为了后面的MediaRecorder对象可以再次使用,需要调用Camera.lock(),Android 4.0以后,这个操作并不是必须的,除非MediaRecorder.prepare()调用失败。
6) 停止预览,调用Camera.stopPreview()。
7) 释放照相机资源,调用Camera.release()。
以上就是打开照相机录制视频的一般步骤,当然你可以可以在录制之前实现预览,决定什么时间开始录制,这个其实可以先开启照相机进行预览即可然后,需要录制时调用Camera.unlock(),然后按流程接入MediaRecorder进行录制。现在考虑第一种情况,直接开始录制。
权限要求已经贴出来了,再贴个布局文件,recordvideo.xml。
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:background="#ffffff" 6 android:orientation="vertical" > 7 8 <SurfaceView 9 android:id="@+id/surfaceView"10 android:layout_width="fill_parent"11 android:layout_height="220dip" />12 13 <LinearLayout14 android:layout_width="fill_parent"15 android:layout_height="wrap_content"16 android:layout_marginLeft="5dp"17 android:layout_marginRight="5dp"18 android:layout_marginTop="20dp"19 android:gravity="right"20 android:orientation="horizontal" >21 22 <EditText23 android:id="@+id/rv_testusername"24 android:layout_width="156dp"25 android:layout_height="wrap_content"26 android:layout_weight="0.27"27 android:ems="10"28 android:hint="输入姓名或标识" />29 30 <Button31 android:id="@+id/rv_record"32 style="@style/mainactivitybtnstyle"33 android:layout_width="wrap_content"34 android:layout_height="wrap_content"35 android:minHeight="40dp"36 android:minWidth="70dp"37 android:text="录制" />38 39 <Button40 android:id="@+id/rv_stop"41 style="@style/mainactivitybtnstyle"42 android:layout_width="wrap_content"43 android:layout_height="wrap_content"44 android:layout_marginLeft="10dip"45 android:minHeight="40dp"46 android:minWidth="70dp"47 android:text="停止" />48 </LinearLayout>49 50 <LinearLayout51 android:layout_width="fill_parent"52 android:layout_height="fill_parent"53 android:gravity="center_horizontal"54 android:orientation="vertical" >55 56 <ProgressBar57 android:id="@+id/rv_schedule"58 style="?android:attr/progressBarStyleHorizontal"59 android:layout_width="fill_parent"60 android:layout_height="wrap_content" />61 62 <TextView63 android:id="@+id/rv_record_time"64 android:layout_width="fill_parent"65 android:layout_height="wrap_content"66 android:gravity="center"67 android:text="00:00:000"68 android:textColor="#FF750000"69 android:textSize="24sp"70 android:textStyle="bold" />71 </LinearLayout>72 73 </LinearLayout>
Activity代码,因为非常简单,就没有封装多线程什么的。
1 package com.ict.phonedoctor.camerasign; 2 3 import java.io.File; 4 import java.text.SimpleDateFormat; 5 6 import android.content.Context; 7 import android.content.pm.FeatureInfo; 8 import android.content.pm.PackageManager; 9 import android.hardware.Camera; 10 import android.media.MediaRecorder; 11 import android.os.Bundle; 12 import android.os.Environment; 13 import android.os.Handler; 14 import android.os.Message; 15 import android.support.v7.app.ActionBarActivity; 16 import android.util.Log; 17 import android.view.SurfaceHolder; 18 import android.view.SurfaceView; 19 import android.view.View; 20 import android.widget.Button; 21 import android.widget.EditText; 22 import android.widget.ProgressBar; 23 import android.widget.TextView; 24 import android.widget.Toast; 25 26 import com.ict.phonedoctor.R; 27 import com.ict.util.IOUtil; 28 29 public class RecordVideoActivity extends ActionBarActivity { 30 private static final String TAG = "RecordVideo"; 31 private SurfaceView surfaceView; 32 private MediaRecorder mediaRecorder; 33 private boolean record; 34 private TextView testusername; 35 private Camera camera; 36 37 // 计时器相关 38 private MyChronograph myChronograph; 39 private TextView chronograph = null; 40 41 private ProgressBar schedule; 42 private boolean recordOver = false; 43 44 @Override 45 protected void onCreate(Bundle savedInstanceState) { 46 // TODO Auto-generated method stub 47 super.onCreate(savedInstanceState); 48 setContentView(R.layout.recordvideo); 49 setTitle("录制视频"); 50 mediaRecorder = new MediaRecorder(); 51 surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView); 52 this.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 53 this.surfaceView.getHolder().setFixedSize(320, 240);//设置分辨率 54 55 testusername = (EditText)findViewById(R.id.rv_testusername); 56 chronograph = (TextView)findViewById(R.id.rv_record_time); 57 schedule = (ProgressBar)findViewById(R.id.rv_schedule); 58 schedule.setMax(60); 59 ButtonClickListener listener = new ButtonClickListener(); 60 Button stopButton = (Button) this.findViewById(R.id.rv_stop); 61 Button recordButton = (Button) this.findViewById(R.id.rv_record); 62 stopButton.setOnClickListener(listener); 63 recordButton.setOnClickListener(listener); 64 } 65 66 @Override 67 protected void onDestroy() { 68 // TODO Auto-generated method stub 69 if(mediaRecorder!=null) 70 mediaRecorder.release(); 71 super.onDestroy(); 72 } 73 74 @Override 75 protected void onPause() { 76 // TODO Auto-generated method stub 77 super.onPause(); 78 } 79 80 @Override 81 protected void onResume() { 82 // TODO Auto-generated method stub 83 super.onResume(); 84 } 85 private final class ButtonClickListener implements View.OnClickListener{ 86 @Override 87 public void onClick(View v) { 88 if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 89 Toast.makeText(RecordVideoActivity.this, "木有检测到SD扩展卡", 1).show(); 90 return ; 91 } 92 try { 93 switch (v.getId()) { 94 case R.id.rv_record: 95 // 要求输入用户名 96 String testuser; 97 if(testusername.getText()==null || testusername.getText().toString().equals("")){ 98 Toast.makeText(RecordVideoActivity.this, "请输入测试者姓名", Toast.LENGTH_LONG).show(); 99 return;100 }101 Log.i(TAG,"检测通过");102 recordOver = false;103 testuser = testusername.getText().toString();104 testuser = android.os.Build.MODEL + "-" + testuser;105 mediaRecorder.reset();106 if(isSurportFlashlight(RecordVideoActivity.this)){107 if (camera == null)108 camera = Camera.open();109 Camera.Parameters myParameters = camera.getParameters();110 myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);111 camera.setParameters(myParameters);112 camera.startPreview();113 camera.unlock();114 mediaRecorder.setCamera(camera);115 } 116 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);117 //mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 118 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);119 mediaRecorder.setVideoSize(320, 240);120 mediaRecorder.setVideoFrameRate(30); //每秒30帧121 mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 122 //mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);123 SimpleDateFormat ff = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");124 String recordTimeString = String.valueOf(ff.format(System.currentTimeMillis())); 125 File videoFile = IOUtil.CreateNewFile(Environment.getExternalStorageDirectory().getPath()+"/phonedoctor/video",126 testuser + "-" + recordTimeString+".3gp",null);127 mediaRecorder.setOutputFile(videoFile.getAbsolutePath());128 mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());129 mediaRecorder.prepare();130 mediaRecorder.start(); // 开始录制131 // 开启计时线程132 myChronograph = new MyChronograph(mHandler,60000);133 myChronograph.start();134 Toast.makeText(RecordVideoActivity.this, "开始录制视频!", Toast.LENGTH_SHORT).show();135 record = true;136 ((Button)findViewById(R.id.rv_record)).setEnabled(false);137 break;138 139 case R.id.rv_stop:140 if(record){141 record = false;142 mediaRecorder.stop();143 mediaRecorder.reset();144 Log.i(TAG,"TAG-1");145 if(camera!=null){146 camera.lock();147 camera.stopPreview();148 Camera.Parameters myParameters = camera.getParameters();149 myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);150 camera.setParameters(myParameters);151 camera.release();152 camera = null;153 }154 // 秒表线程控制 155 if(myChronograph!=null){156 myChronograph.exit();157 myChronograph = null;158 }159 ((Button)findViewById(R.id.rv_record)).setEnabled(true);160 }161 break;162 }163 } catch (Exception e) {164 Toast.makeText(RecordVideoActivity.this, "发生异常", 1).show();165 e.printStackTrace();166 }167 }168 169 }170 171 private Handler mHandler = new Handler(){172 173 @Override174 public void handleMessage(Message msg) {175 String[] strMsg;176 switch (msg.what) {177 case MsgNumber.UPTIME_UI:178 strMsg = (String[]) msg.obj;179 chronograph.setText(strMsg[0]);180 if(!recordOver){181 int percent = Integer.parseInt(strMsg[1]);182 if(percent==-1){183 recordOver = true;184 schedule.setProgress(60);185 Toast.makeText(RecordVideoActivity.this, "已录制一分钟!", Toast.LENGTH_SHORT).show();186 return;187 }188 percent = percent>60?60:percent;189 schedule.setProgress(percent);190 }191 break;192 193 default:194 break;195 }196 }197 198 };199 200 // 闪光灯判断201 public boolean isSurportFlashlight(Context context) {202 boolean flag = false;203 PackageManager pm = context.getPackageManager();204 FeatureInfo[] features = pm.getSystemAvailableFeatures();205 for (FeatureInfo f : features) {206 if (PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {207 flag = true;208 break;209 }210 }211 return flag;212 }213 }
运行效果图
至此,主要代码已经贴出,没什么技术含量,算是Android学习过程中的一个小结,Android在线API的一个阅读笔记。
Android开发之打开闪光灯录制视频