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() step
11  recorder.release(); // Now the object cannot be reused
View Code

录制视频是调用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     <LinearLayout
14         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         <EditText
23             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         <Button
31             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         <Button
40             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     <LinearLayout
51         android:layout_width="fill_parent"
52         android:layout_height="fill_parent"
53         android:gravity="center_horizontal"
54         android:orientation="vertical" >
55 
56         <ProgressBar
57             android:id="@+id/rv_schedule"
58             style="?android:attr/progressBarStyleHorizontal"
59             android:layout_width="fill_parent"
60             android:layout_height="wrap_content" />
61 
62         <TextView
63             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>
View Code

   Activity代码,因为非常简单,就没有封装多线程什么的。

  1 import java.io.File;
  2 import java.text.SimpleDateFormat;
  3 
  4 import android.content.Context;
  5 import android.content.pm.FeatureInfo;
  6 import android.content.pm.PackageManager;
  7 import android.hardware.Camera;
  8 import android.media.MediaRecorder;
  9 import android.os.Bundle;
 10 import android.os.Environment;
 11 import android.os.Handler;
 12 import android.os.Message;
 13 import android.support.v7.app.ActionBarActivity;
 14 import android.util.Log;
 15 import android.view.SurfaceHolder;
 16 import android.view.SurfaceView;
 17 import android.view.View;
 18 import android.widget.Button;
 19 import android.widget.EditText;
 20 import android.widget.ProgressBar;
 21 import android.widget.TextView;
 22 import android.widget.Toast;
 23 
 24 import com.ict.util.IOUtil;
 25 
 26 public class RecordVideoActivity extends ActionBarActivity {
 27     private static final String TAG = "RecordVideo";
 28     private SurfaceView surfaceView;
 29     private MediaRecorder mediaRecorder;
 30     private boolean record;    
 31     private TextView testusername;
 32     private Camera camera;
 33     
 34     // 计时器相关
 35     private MyChronograph myChronograph;
 36     private TextView chronograph = null;
 37     
 38     private ProgressBar schedule;
 39     private boolean recordOver = false;
 40     
 41     @Override
 42     protected void onCreate(Bundle savedInstanceState) {
 43         // TODO Auto-generated method stub
 44         super.onCreate(savedInstanceState);
 45         setContentView(R.layout.recordvideo);
 46         setTitle("录制视频");
 47         mediaRecorder = new MediaRecorder();
 48         surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
 49         this.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 50         this.surfaceView.getHolder().setFixedSize(320, 240);//设置分辨率
 51 
 52         testusername = (EditText)findViewById(R.id.rv_testusername);
 53         chronograph = (TextView)findViewById(R.id.rv_record_time);
 54         schedule = (ProgressBar)findViewById(R.id.rv_schedule);
 55         schedule.setMax(60);
 56         ButtonClickListener listener = new ButtonClickListener();
 57         Button stopButton = (Button) this.findViewById(R.id.rv_stop);
 58         Button recordButton = (Button) this.findViewById(R.id.rv_record);
 59         stopButton.setOnClickListener(listener);
 60         recordButton.setOnClickListener(listener);           
 61     }
 62 
 63     @Override
 64     protected void onDestroy() {
 65         // TODO Auto-generated method stub
 66         if(mediaRecorder!=null)
 67             mediaRecorder.release();
 68         super.onDestroy();
 69     }
 70 
 71     @Override
 72     protected void onPause() {
 73         // TODO Auto-generated method stub
 74         super.onPause();
 75     }
 76 
 77     @Override
 78     protected void onResume() {
 79         // TODO Auto-generated method stub
 80         super.onResume();
 81     }
 82     private final class ButtonClickListener implements View.OnClickListener{
 83         @Override
 84         public void onClick(View v) {
 85             if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
 86                 Toast.makeText(RecordVideoActivity.this, "木有检测到SD扩展卡", 1).show();
 87                 return ;
 88             }
 89             try {
 90                 switch (v.getId()) {
 91                 case R.id.rv_record:
 92                     // 要求输入用户名
 93                     String testuser;
 94                     if(testusername.getText()==null || testusername.getText().toString().equals("")){
 95                         Toast.makeText(RecordVideoActivity.this, "请输入测试者姓名", Toast.LENGTH_LONG).show();
 96                         return;
 97                     }
 98                     Log.i(TAG,"检测通过");
 99                     recordOver = false;
100                     testuser = testusername.getText().toString();
101                     testuser = android.os.Build.MODEL + "-" + testuser;
102                     mediaRecorder.reset();
103                     if(isSurportFlashlight(RecordVideoActivity.this)){
104                         if (camera == null)
105                             camera = Camera.open();
106                         Camera.Parameters myParameters = camera.getParameters();
107                         myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
108                         camera.setParameters(myParameters);
109                         camera.startPreview();
110                         camera.unlock();
111                         mediaRecorder.setCamera(camera);
112                     }                    
113                     mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
114                     //mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
115                     mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
116                     mediaRecorder.setVideoSize(320, 240);
117                     mediaRecorder.setVideoFrameRate(30); //每秒30帧
118                     mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 
119                     //mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
120                     SimpleDateFormat ff = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
121                     String recordTimeString = String.valueOf(ff.format(System.currentTimeMillis()));                    
122                     File videoFile = IOUtil.CreateNewFile(Environment.getExternalStorageDirectory().getPath()+"/phonedoctor/video",
123                             testuser + "-" + recordTimeString+".3gp",null);
124                     mediaRecorder.setOutputFile(videoFile.getAbsolutePath());
125                     mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
126                     mediaRecorder.prepare();
127                     mediaRecorder.start();    //    开始录制
128                     // 开启计时线程
129                     myChronograph = new MyChronograph(mHandler,60000);
130                     myChronograph.start();
131                     Toast.makeText(RecordVideoActivity.this, "开始录制视频!", Toast.LENGTH_SHORT).show();
132                     record = true;
133                     ((Button)findViewById(R.id.rv_record)).setEnabled(false);
134                     break;
135 
136                 case R.id.rv_stop:
137                     if(record){
138                         record = false;
139                         mediaRecorder.stop();
140                         mediaRecorder.reset();
141                         Log.i(TAG,"TAG-1");
142                         if(camera!=null){
143                             camera.lock();
144                             camera.stopPreview();
145                             Camera.Parameters myParameters = camera.getParameters();
146                             myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
147                             camera.setParameters(myParameters);
148                             camera.release();
149                             camera = null;
150                         }
151                         // 秒表线程控制        
152                         if(myChronograph!=null){
153                             myChronograph.exit();
154                             myChronograph = null;
155                         }
156                         ((Button)findViewById(R.id.rv_record)).setEnabled(true);
157                     }
158                     break;
159                 }
160             } catch (Exception e) {
161                 Toast.makeText(RecordVideoActivity.this, "发生异常", 1).show();
162                 e.printStackTrace();
163             }
164         }
165         
166     }
167     
168     private Handler mHandler = new Handler(){
169 
170         @Override
171         public void handleMessage(Message msg) {
172             String[] strMsg;
173             switch (msg.what) {
174             case MsgNumber.UPTIME_UI:
175                 strMsg = (String[]) msg.obj;
176                 chronograph.setText(strMsg[0]);
177                 if(!recordOver){
178                     int percent = Integer.parseInt(strMsg[1]);
179                     if(percent==-1){
180                         recordOver = true;
181                         schedule.setProgress(60);
182                         Toast.makeText(RecordVideoActivity.this, "已录制一分钟!", Toast.LENGTH_SHORT).show();
183                         return;
184                     }
185                     percent = percent>60?60:percent;
186                     schedule.setProgress(percent);
187                 }
188                 break;
189 
190             default:
191                 break;
192             }
193         }
194         
195     };
196     
197     // 闪光灯判断
198     public boolean isSurportFlashlight(Context context) {
199         boolean flag = false;
200         PackageManager pm = context.getPackageManager();
201         FeatureInfo[] features = pm.getSystemAvailableFeatures();
202         for (FeatureInfo f : features) {
203             if (PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {
204                 flag = true;
205                 break;
206             }
207         }
208         return flag;
209     }
210 }
View Code

  运行效果图

                     

  至此,主要代码已经贴出,没什么技术含量,算是Android学习过程中的一个小结,Android在线API的一个阅读笔记。

原文地址:https://www.cnblogs.com/HackingProgramer/p/4026945.html