歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android開發之打開閃光燈錄制視頻

  Android的SDK在線API上對錄制視頻的方法、步驟都寫得非常清楚,但是如果沒有一點思路,寫起來也比較式費事。錄制視頻的全過程要打開閃光燈(可能是因為項目需要,或者特殊原因),則必須按照一定的順序進行開關,畢竟容易出錯。要實現錄制的同時開啟閃光燈也不難,官方API給出了一個大體的步驟.因為要采集點視頻數據,臨時寫了個簡單的Demo學習下,必要時再深度開發。

  首先在工程中的AndroidManifest.xml中添加權限聲明,因為要使用到攝像頭,故需要添加Camera的相關權限,另外還需要寫SD卡的權限,如果同時需要錄制音頻,則還需要添加RECORD_AUDIO權限。

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  再來分析下要使用到的類,錄制視頻使用的MediaRecorder類,官方給出了調用MediaRecorder錄制視頻的一個簡單狀態機,展示了各個狀態之間的轉化。然後也給出了一個簡單的調用方法,代碼如下:

MediaRecorder recorder = new MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 recorder.setOutputFile(PATH_NAME);
 recorder.prepare();
 recorder.start();  // Recording is now started
 ...
 recorder.stop();
 recorder.reset();  // You can reuse the object by going back to setAudioSource() step
 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。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ffffff"
    android:orientation="vertical" >

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="fill_parent"
        android:layout_height="220dip" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="20dp"
        android:gravity="right"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/rv_testusername"
            android:layout_width="156dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.27"
            android:ems="10"
            android:hint="輸入姓名或標識" />

        <Button
            android:id="@+id/rv_record"
           
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:minHeight="40dp"
            android:minWidth="70dp"
            android:text="錄制" />

        <Button
            android:id="@+id/rv_stop"
           
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dip"
            android:minHeight="40dp"
            android:minWidth="70dp"
            android:text="停止" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <ProgressBar
            android:id="@+id/rv_schedule"
           
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/rv_record_time"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="00:00:000"
            android:textColor="#FF750000"
            android:textSize="24sp"
            android:text />
    </LinearLayout>

</LinearLayout>

Activity代碼,因為非常簡單,就沒有封裝多線程什麼的。

import java.io.File;
import java.text.SimpleDateFormat;

import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.ict.util.IOUtil;

public class RecordVideoActivity extends ActionBarActivity {
    private static final String TAG = "RecordVideo";
    private SurfaceView surfaceView;
    private MediaRecorder mediaRecorder;
    private boolean record;   
    private TextView testusername;
    private Camera camera;
   
    // 計時器相關
    private MyChronograph myChronograph;
    private TextView chronograph = null;
   
    private ProgressBar schedule;
    private boolean recordOver = false;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recordvideo);
        setTitle("錄制視頻");
        mediaRecorder = new MediaRecorder();
        surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
        this.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        this.surfaceView.getHolder().setFixedSize(320, 240);//設置分辨率

        testusername = (EditText)findViewById(R.id.rv_testusername);
        chronograph = (TextView)findViewById(R.id.rv_record_time);
        schedule = (ProgressBar)findViewById(R.id.rv_schedule);
        schedule.setMax(60);
        ButtonClickListener listener = new ButtonClickListener();
        Button stopButton = (Button) this.findViewById(R.id.rv_stop);
        Button recordButton = (Button) this.findViewById(R.id.rv_record);
        stopButton.setOnClickListener(listener);
        recordButton.setOnClickListener(listener);         
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        if(mediaRecorder!=null)
            mediaRecorder.release();
        super.onDestroy();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
    }
    private final class ButtonClickListener implements View.OnClickListener{
        @Override
        public void onClick(View v) {
            if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                Toast.makeText(RecordVideoActivity.this, "木有檢測到SD擴展卡", 1).show();
                return ;
            }
            try {
                switch (v.getId()) {
                case R.id.rv_record:
                    // 要求輸入用戶名
                    String testuser;
                    if(testusername.getText()==null || testusername.getText().toString().equals("")){
                        Toast.makeText(RecordVideoActivity.this, "請輸入測試者姓名", Toast.LENGTH_LONG).show();
                        return;
                    }
                    Log.i(TAG,"檢測通過");
                    recordOver = false;
                    testuser = testusername.getText().toString();
                    testuser = android.os.Build.MODEL + "-" + testuser;
                    mediaRecorder.reset();
                    if(isSurportFlashlight(RecordVideoActivity.this)){
                        if (camera == null)
                            camera = Camera.open();
                        Camera.Parameters myParameters = camera.getParameters();
                        myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                        camera.setParameters(myParameters);
                        camera.startPreview();
                        camera.unlock();
                        mediaRecorder.setCamera(camera);
                    }                   
                    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                    //mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                    mediaRecorder.setVideoSize(320, 240);
                    mediaRecorder.setVideoFrameRate(30); //每秒30幀
                    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
                    //mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                    SimpleDateFormat ff = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
                    String recordTimeString = String.valueOf(ff.format(System.currentTimeMillis()));                   
                    File videoFile = IOUtil.CreateNewFile(Environment.getExternalStorageDirectory().getPath()+"/phonedoctor/video",
                            testuser + "-" + recordTimeString+".3gp",null);
                    mediaRecorder.setOutputFile(videoFile.getAbsolutePath());
                    mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
                    mediaRecorder.prepare();
                    mediaRecorder.start();    //    開始錄制
                    // 開啟計時線程
                    myChronograph = new MyChronograph(mHandler,60000);
                    myChronograph.start();
                    Toast.makeText(RecordVideoActivity.this, "開始錄制視頻!", Toast.LENGTH_SHORT).show();
                    record = true;
                    ((Button)findViewById(R.id.rv_record)).setEnabled(false);
                    break;

                case R.id.rv_stop:
                    if(record){
                        record = false;
                        mediaRecorder.stop();
                        mediaRecorder.reset();
                        Log.i(TAG,"TAG-1");
                        if(camera!=null){
                            camera.lock();
                            camera.stopPreview();
                            Camera.Parameters myParameters = camera.getParameters();
                            myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                            camera.setParameters(myParameters);
                            camera.release();
                            camera = null;
                        }
                        // 秒表線程控制       
                        if(myChronograph!=null){
                            myChronograph.exit();
                            myChronograph = null;
                        }
                        ((Button)findViewById(R.id.rv_record)).setEnabled(true);
                    }
                    break;
                }
            } catch (Exception e) {
                Toast.makeText(RecordVideoActivity.this, "發生異常", 1).show();
                e.printStackTrace();
            }
        }
       
    }
   
    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            String[] strMsg;
            switch (msg.what) {
            case MsgNumber.UPTIME_UI:
                strMsg = (String[]) msg.obj;
                chronograph.setText(strMsg[0]);
                if(!recordOver){
                    int percent = Integer.parseInt(strMsg[1]);
                    if(percent==-1){
                        recordOver = true;
                        schedule.setProgress(60);
                        Toast.makeText(RecordVideoActivity.this, "已錄制一分鐘!", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    percent = percent>60?60:percent;
                    schedule.setProgress(percent);
                }
                break;

            default:
                break;
            }
        }
       
    };
   
    // 閃光燈判斷
    public boolean isSurportFlashlight(Context context) {
        boolean flag = false;
        PackageManager pm = context.getPackageManager();
        FeatureInfo[] features = pm.getSystemAvailableFeatures();
        for (FeatureInfo f : features) {
            if (PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {
                flag = true;
                break;
            }
        }
        return flag;
    }
}

Activity代碼,因為非常簡單,就沒有封裝多線程什麼的。

import java.io.File;
import java.text.SimpleDateFormat;

import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.ict.util.IOUtil;

public class RecordVideoActivity extends ActionBarActivity {
    private static final String TAG = "RecordVideo";
    private SurfaceView surfaceView;
    private MediaRecorder mediaRecorder;
    private boolean record;   
    private TextView testusername;
    private Camera camera;
   
    // 計時器相關
    private MyChronograph myChronograph;
    private TextView chronograph = null;
   
    private ProgressBar schedule;
    private boolean recordOver = false;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recordvideo);
        setTitle("錄制視頻");
        mediaRecorder = new MediaRecorder();
        surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
        this.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        this.surfaceView.getHolder().setFixedSize(320, 240);//設置分辨率

        testusername = (EditText)findViewById(R.id.rv_testusername);
        chronograph = (TextView)findViewById(R.id.rv_record_time);
        schedule = (ProgressBar)findViewById(R.id.rv_schedule);
        schedule.setMax(60);
        ButtonClickListener listener = new ButtonClickListener();
        Button stopButton = (Button) this.findViewById(R.id.rv_stop);
        Button recordButton = (Button) this.findViewById(R.id.rv_record);
        stopButton.setOnClickListener(listener);
        recordButton.setOnClickListener(listener);         
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        if(mediaRecorder!=null)
            mediaRecorder.release();
        super.onDestroy();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
    }
    private final class ButtonClickListener implements View.OnClickListener{
        @Override
        public void onClick(View v) {
            if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                Toast.makeText(RecordVideoActivity.this, "木有檢測到SD擴展卡", 1).show();
                return ;
            }
            try {
                switch (v.getId()) {
                case R.id.rv_record:
                    // 要求輸入用戶名
                    String testuser;
                    if(testusername.getText()==null || testusername.getText().toString().equals("")){
                        Toast.makeText(RecordVideoActivity.this, "請輸入測試者姓名", Toast.LENGTH_LONG).show();
                        return;
                    }
                    Log.i(TAG,"檢測通過");
                    recordOver = false;
                    testuser = testusername.getText().toString();
                    testuser = android.os.Build.MODEL + "-" + testuser;
                    mediaRecorder.reset();
                    if(isSurportFlashlight(RecordVideoActivity.this)){
                        if (camera == null)
                            camera = Camera.open();
                        Camera.Parameters myParameters = camera.getParameters();
                        myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                        camera.setParameters(myParameters);
                        camera.startPreview();
                        camera.unlock();
                        mediaRecorder.setCamera(camera);
                    }                   
                    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                    //mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                    mediaRecorder.setVideoSize(320, 240);
                    mediaRecorder.setVideoFrameRate(30); //每秒30幀
                    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
                    //mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                    SimpleDateFormat ff = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
                    String recordTimeString = String.valueOf(ff.format(System.currentTimeMillis()));                   
                    File videoFile = IOUtil.CreateNewFile(Environment.getExternalStorageDirectory().getPath()+"/phonedoctor/video",
                            testuser + "-" + recordTimeString+".3gp",null);
                    mediaRecorder.setOutputFile(videoFile.getAbsolutePath());
                    mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
                    mediaRecorder.prepare();
                    mediaRecorder.start();    //    開始錄制
                    // 開啟計時線程
                    myChronograph = new MyChronograph(mHandler,60000);
                    myChronograph.start();
                    Toast.makeText(RecordVideoActivity.this, "開始錄制視頻!", Toast.LENGTH_SHORT).show();
                    record = true;
                    ((Button)findViewById(R.id.rv_record)).setEnabled(false);
                    break;

                case R.id.rv_stop:
                    if(record){
                        record = false;
                        mediaRecorder.stop();
                        mediaRecorder.reset();
                        Log.i(TAG,"TAG-1");
                        if(camera!=null){
                            camera.lock();
                            camera.stopPreview();
                            Camera.Parameters myParameters = camera.getParameters();
                            myParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                            camera.setParameters(myParameters);
                            camera.release();
                            camera = null;
                        }
                        // 秒表線程控制       
                        if(myChronograph!=null){
                            myChronograph.exit();
                            myChronograph = null;
                        }
                        ((Button)findViewById(R.id.rv_record)).setEnabled(true);
                    }
                    break;
                }
            } catch (Exception e) {
                Toast.makeText(RecordVideoActivity.this, "發生異常", 1).show();
                e.printStackTrace();
            }
        }
       
    }
   
    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            String[] strMsg;
            switch (msg.what) {
            case MsgNumber.UPTIME_UI:
                strMsg = (String[]) msg.obj;
                chronograph.setText(strMsg[0]);
                if(!recordOver){
                    int percent = Integer.parseInt(strMsg[1]);
                    if(percent==-1){
                        recordOver = true;
                        schedule.setProgress(60);
                        Toast.makeText(RecordVideoActivity.this, "已錄制一分鐘!", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    percent = percent>60?60:percent;
                    schedule.setProgress(percent);
                }
                break;

            default:
                break;
            }
        }
       
    };
   
    // 閃光燈判斷
    public boolean isSurportFlashlight(Context context) {
        boolean flag = false;
        PackageManager pm = context.getPackageManager();
        FeatureInfo[] features = pm.getSystemAvailableFeatures();
        for (FeatureInfo f : features) {
            if (PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {
                flag = true;
                break;
            }
        }
        return flag;
    }
}

運行效果圖

 

至此,主要代碼已經貼出,沒什麼技術含量,算是Android學習過程中的一個小結,Android在線API的一個閱讀筆記。

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved