首页 > 代码库 > 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
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     <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>
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         @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 }
View Code

 

  运行效果图

                     

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

Android开发之打开闪光灯录制视频