当前位置: 移动技术网 > 移动技术>移动开发>Android > Android音视频之视频采集(系统API预览)

Android音视频之视频采集(系统API预览)

2019年07月31日  | 移动技术网移动技术  | 我要评论
我们了解了视频相关的基础知识,后面的文章我们要能够和音频一样可以采集我们的视频,视频是一帧一帧的图片来的,我们首先要学习预览视频,然后采集一帧图片,采集视频从简到难的来了解

我们了解了视频相关的基础知识,后面的文章我们要能够和音频一样可以采集我们的视频,视频是一帧一帧的图片来的,我们首先要学习预览视频,然后采集一帧图片,采集视频从简到难的来了解这个问题。首先第一个反应打开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链接查看

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网