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 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         @Override
174         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 }
View Code

 

  运行效果图

                     

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

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。