zoukankan      html  css  js  c++  java
  • 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的一个阅读笔记。

  • 相关阅读:
    从新浪财经获取金融新闻类数据并进行打分计算
    SQL窗口函数的用法总结
    从新浪财经获取金融新闻类数据并保存到MySQL
    [ZJOI2015]幻想乡战略游戏
    二次剩余入门
    [多校赛20210406]迫害 DJ
    [NOI Online 2021 提高组] 愤怒的小N
    [NOI Online 2021 提高组] 岛屿探险
    「UNR #3」百鸽笼
    [ZJOI2019]开关
  • 原文地址:https://www.cnblogs.com/HackingProgramer/p/4026945.html
Copyright © 2011-2022 走看看