Android音视频之视频采集(系统API预览)
我们了解了视频相关的基础知识,后面的文章我们要能够和音频一样可以采集我们的视频,视频是一帧一帧的图片来的,我们首先要学习预览视频,然后采集一帧图片,采集视频从简到难的来了解这个问题。首先第一个反应打开Google搜索和Android视频采集相关的东西,我们要知道如何通过API来采集,不由自主地到了Android官网的Camera API。Android有两个视频采集的API,Camera是Android 5.0以前使用的,现在已经废弃了,我们还是得学一下他的使用,Camera2是最新的视频采集API,我们重点了解它的使用。这篇文章我们掌握调用系统的拍照和录制视频API来实现拍照录像功能。
Camera
它是API21(Android5.0)以前用来对摄像头数据采集的的API,我们从开始到每个环节的关键内容记录如下。
基础知识
先来了解使用Camera有几个相关联的类。 Camera:API21以后老的API控制摄像头设备 SurfaceView:显示摄像头预览图像给用户 MediaRecorder:录制摄像头的视频
权限声明
摄像头权限:我们要使用Camera设备必须要声明一个权限
<uses-permission android:name="android.permission.CAMERA" /
但是当我们使用Intent来调用系统自己的Camera设备拍照录像就不需要这个权限。 摄像头特征:应用必须声明使用摄像头特性权限(这个不知道是啥意思的要了解uses-feature这个清单文件的意义)
<uses-feature android:name="android.hardware.camera" /
音频录制权限:当录制视频的时候我们还要音频就要加上这个权限。
<uses-permission android:name="android.permission.RECORD_AUDIO" /
存储权限:如果我们要保存相片和视频在存储设备那么就要加上这个权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /
定位权限:如果照片的标签要GPS位置信息,我们就要如下权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /
...
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --
<uses-feature android:name="android.hardware.location.gps" /
调用系统的摄像头app来拍照和录制视频
拍照
请求摄像头特征
<manifest ...
<uses-feature android:name="android.hardware.camera"
android:required="true" /
...
</manifest
这个权限可以让GooglePlay来判断是否设备支持下载我们的应用,如果设置required为true那么一定要有摄像头硬件设备的才能下载,如果设置required为false,那么没有摄像头硬件设备的也可以下载,当然我们在程序里面就要判断一下是否有摄像头可用了。
使用默认Intent开始拍照
调用默认的开启系统拍照App的Intent
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
获取拍照图片
我们刚才通过startActivityForResult来拍照了,很自然的在onActivityResult来接受返回的数据,我们把图片显示在一个ImageView上面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(imageBitmap);
}
}
通过这种默认的拍照我们不需要在Android6.0以上的机器声明任何权限就可以成功执行。
自定义保存相片图片路径
我们上面的操作,获取来的是一个bitmap,我们的图片信息都是在内存里面操作的,如果我们要保存拍照的图片到存储卡并且查看图片,那么我们只要声明一个写存储卡权限就OK。
<manifest ...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /
...
</manifest
开始重新请求拍照代码
static final int REQUEST_TAKE_PHOTO = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
...
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
上面的代码我们使用了FileProvider.getUriForFile方法,它返回content://URI,这个API在Android7.0以上使用不做处理会抛出FileUriExposedException。我们要在清单文件注册配置一个FileProvider
<application
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" </meta-data
</provider
...
</application
在res/xml/file_paths配置文件
<?xml version="1.0" encoding="utf-8"?
<paths xmlns:android="http://schemas.android.com/apk/res/android"
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /
</paths
添加照片到相册
我们上面的照片保存位置根目录为getExternalFilesDir(Environment.DIRECTORY_PICTURES);这个目录下面多媒体扫描器是不能找到我们的照片的,因为它是我们App私有的。下面的代码可以让系统的多媒体扫描器添加我们的图片到Media Provider’s 数据库,让我们的图片对系统相册和其他应用都可以使用。
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
try {
MediaStore.Images.Media.insertImage(getContentResolver(),
f.getAbsolutePath(), f.getName(), null);
Log.d(TAG, "galleryAddPic: add to Media Scanner success");
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "galleryAddPic: add to Media Scanner failed");
}
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
Toast.makeText(this, "Add to Gallery success", Toast.LENGTH_SHORT).show();
}
解码缩放图片
我们在把图片ImageView上面,没有做任何处理,如果图片较大,会导致oom的,做一个缩放处理。
private void setPic() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}
demo代码参考
录像
录制视频播放的代码很简单,如果要对视频播放器进行定制,那么久要多一些东西,我们现在只简单的可以播放调用系统录制的视频。
开启视频录制Intent
static final int REQUEST_VIDEO_CAPTURE = 1;
private void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
在onActivityResult里面接收视频Uri来播放
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
Uri videoUri = intent.getData();
Log.d(TAG, "onActivityResult: " + videoUri);
mVideoView.setVideoURI(videoUri);
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(false);//设置视频重复播放
}
});
mVideoView.start();//播放视频
MediaController mediaController = new MediaController(this);//显示控制条
mVideoView.setMediaController(mediaController);
mediaController.setMediaPlayer(mVideoView);//设置控制的对象
mediaController.show();
}
}
demo链接查看
以上就是本文的全部内容,希望对大家的学习有所帮助。
- Django 1.10中文文档-第一个应用Part6-静态文件
- Django 1.10中文文档-第一个应用Part5-测试
- 设计模式(5)-己所不欲,施之于人(代理模式)
- Python标准库笔记(4) — collections模块
- 使用captcha模块生成图形验证码
- 设计模式(6)-装饰器(认识程序中的装饰器)
- Selenium Webdriver常用方法
- 设计模式(7)-模板(从事务处理应用的模板)
- Python NLP入门教程
- 设计模式(8)-状态模式(关注状态之间的变化)
- Python标准库笔记(6) — struct模块
- Golang中image/jpeg包和image/png包用法
- Python Webdriver 重新使用已经打开的浏览器实例
- Golang-实现图片缩放
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Android评分RationBar控件使用详解
- Flutter里面错误捕获的正确方法
- django3 websockets
- 使用AccessibilityService实现自动遍历点赞功能
- Android自定义字母导航栏
- [-Flutter 自组篇-] 圆形进度条
- Flutter 滚动监听及实战appBar滚动渐变的实现
- Android 开机充电图标和充电动画效果
- 使用tea算法对数据进行加密
- Android实现页面翻转和自动翻转功能
- Android实现自定义手势和识别手势的功能
- android 使用okhttp可能引发OOM的一个点
- 到底有几个进程在运行
- Android中butterknife的使用与自动化查找组件插件详解
- Android生成条形码和二维码功能