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"
style="@style/mainactivitybtnstyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="40dp"
android:minWidth="70dp"
android:text="录制" /> <Button
android:id="@+id/rv_stop"
style="@style/mainactivitybtnstyle"
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"
style="?android:attr/progressBarStyleHorizontal"
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:textStyle="bold" />
</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;
}
}
运行效果图
至此,主要代码已经贴出,没什么技术含量,算是Android学习过程中的一个小结,Android在线API的一个阅读笔记。
Android开发之打开闪光灯录制视频的更多相关文章
-
Android Camera系列开发 (二)通过Intent录制视频
Android Camera系列开发 (二)通过Intent录制视频 作者:雨水 2013-8-18 CSDN博客:http://blog.csdn.net/gobitan/ 概述 使用Camera ...
-
Android ADB工具-截图和录制视频(五)
Android ADB工具-截图和录制视频(五) 标签(空格分隔): Android ADB 7. 截图和录制视 命令 功能 adb shell screencap –p <path/file& ...
-
OpenCV x64 vs2010 下打开摄像头录制视频写成avi(代码为转载)
首先参照下面这里进行opencv x64位机器下面的配置 http://wiki.opencv.org.cn/index.php/VC_2010%E4%B8%8B%E5%AE%89%E8%A3%85O ...
-
Android开发之使用VideoView播放视频
Android提供了 VideoView组件.它的作用与ImageView类似,仅仅是ImageView用于显示图片.而VideoView用于播放视频. 使用VideoView播放视频的过程例如以下: ...
-
Android WebView 实现文件选择、拍照、录制视频、录音
原文地址:Android WebView 实现文件选择.拍照.录制视频.录音 | Stars-One的杂货小窝 Android中的WebView如果不进行相应的设置,H5页面的上传按钮是无法触发And ...
-
Android之打开闪光灯关键代码
在AndroidManifest中注册相应的权限: <uses-permission android:name="android.permission.FLASHLIGHT" ...
-
调研android开发环境的发展演变
这是第一次接触android开发,特意上网搜索视频进行了自身知识补充,觉得说视频做得很不错,从android的发展历程以及一些基本常识都讲得很详细,也很有趣,也所以拿出来同大家一起分享学习,网址是:h ...
-
win7下android开发环境搭建(win7 64位)
win7下android开发环境搭建(win7 64位) 一.安装 JDK 下载JDK最新版本,下载地址如下: http://www.oracle.com/technetwork/java/jav ...
-
Android 开发 MediaRecorder视频录制入门
前言 MediaRecorder是Android SDK提供用于录制音视频,关于音频的录制在我另一篇博客里已经介绍.传送门: https://www.cnblogs.com/guanxinjing/p ...
随机推荐
-
Python:eval的妙用和滥用
时间 2014-07-08 13:05:24 CSDN博客 原文 http://blog.csdn.net/zhanh1218/article/details/37562167 主题 Python ...
-
MaxTemperature程序Mapper ClassNotFoundException
错误: 执行hadoop权威指南上MaxTemperature程序出现Mapper类ClassNotFoundException异常: 解决: 将书上的 JobConf job = new JobCo ...
-
解决html5 video不能播放 能播放声音不能播放视频
<video id="playVideo" style="width:90%; height:auto;" controls poster=". ...
-
Ehcache(02)——ehcache.xml简介
http://haohaoxuexi.iteye.com/blog/2113728 ehcache.xml简介 ehcache.xml文件是用来定义Ehcache的配置信息的,更准确的来说它是定义Ca ...
-
js知识简单归纳
js简单的归纳 基本类型 number,string,boolean,null,undefined 组合类型 一种对象类型: object 数组 函数 对象 正则 关于函数 作用域 闭包 构造函数 原 ...
-
SDL实现按钮
是的,按钮控件很常见,几乎在每一个Windows窗体内都能找到它的身影.SDL作为一套“一套开放源代码的跨平台多媒体开发库”,自然可以实现按钮.而按钮实现的重点,就是SDL的鼠标响应事件. SDL的鼠 ...
-
转:使用WebDriver过程中遇到的那些问题
在做web项目的自动化端到端测试时主要使用的是Selenium WebDriver来驱动浏览器.Selenium WebDriver的优点是支持的语言多,支持的浏览器多.主流的浏览器Chrome.Fi ...
-
【BZOJ3110】K大数查询(整体二分)
[BZOJ3110]K大数查询(整体二分) 题面 BZOJ 题解 看了很久整体二分 一直不知道哪里写错了 ... 又把树状数组当成线段树区间加法来用了.. 整体二分还是要想清楚在干什么: 我们考虑第\ ...
-
POJ 1985 Cow Marathon (模板题)(树的直径)
<题目链接> 题目大意: 给定一颗树,求出树的直径. 解题分析:树的直径模板题,以下程序分别用树形DP和两次BFS来求解. 树形DP: #include <cstdio> #i ...
-
Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇)【转】
转自:https://blog.csdn.net/radianceblau/article/details/74722395 版权声明:本文为博主原创文章,未经博主允许不得转载.如本文对您有帮助,欢迎 ...