Android视频的操作

上节课我们着重介绍了Android中的音频的处理,通过学习,我们已经熟悉并掌握了多媒体开发的几个操作,大致可以分为:a

  • 播放和采集
  • 编解码处理
  • 算法处理,实现特殊功能
  • 标准协议以及播放器工具类的开发

本节课我们来看一下Android的视频的相关操作。Android提供了常见的视频的编码、解码机制。使用Android自带的MediaPlayer、MediaController等类可以很方便的实现视频播放的功能。支持的视频格式有MP4和3GP等。这些多媒体数据可以来自于Android应用的资源文件,也可以来自于外部存储器上的文件,甚至可以是来自于网络上的文件流。

一、视频的播放

1.1 MediaController + VideoView

这种方式是最简单的实现方式。其中两个核心的API是:

  • VideoView:继承了SurfaceView同时实现了MediaPlayerControl接口。
  • MediaController:Android封装的辅助控制器,带有暂停,播放,停止,进度条等控件。

通过VideoView+MediaController可以很轻松的实现视频播放、停止、快进、快退等功能。

a、什么是SurfaceView

在之前的课程中,我们接触到的所有的UI控件或者布局都是View的子类,常用的View有布局组件 ConstraintLayout、RelativeLayout 与基本的显示组件ImageView、TextView 等。我们再来回顾下Android的视图渲染机制:View是通过刷新来重绘视图,系统通过发信号来进行屏幕的重绘,刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成,则没有任何问题,如果我们绘制过程逻辑很复杂,并且我们的界面更新还非常频繁,这时候就会造成界面的卡顿。

在一些要求高效率的视图更新和绘制的场景中,该如何保证视图的流畅效果呢?Android为开发者提供了SurfaceView。我们可以对SurafceView和View做一个简单的对比说明:

  • 1、View适用于主动更新的情况,而SurfaceView则适用于被动更新的情况,比如频繁刷新界面。
  • 2、 View在主线程中对页面进行刷新,而SurfaceView则开启一个子线程来对页面进行刷新。
  • 3、View在绘图时没有实现双缓冲机制,SurfaceView在底层机制中就实现了双缓冲机制。

要想使用SurfaceView需要经过创建、初始化、使用三个步骤。

Surface用来处理由屏幕合成器管理的原始缓冲区。Surface通常由图像缓冲区的使用者(例如SurfaceTexture、MediaRecorder 或 Allocation)创建或由其创建,并交给某种类型的生产者(例如OpenGL、MediaPlayer 或 CameraDevice)进行绘制。

结论:Android 平台上,无论开发者使用什么渲染 API,一切内容都会渲染到 Surface。Surface 表示缓冲队列中的生产方,在 Android 平台上创建的每个窗口都由 Surface 提供支持。SurfaceView 是对 Surface 的包装,用来向 View 树提供Surface的一个 View。

b、什么是TextureView

通过上面的内容我们已经了解到:SurfaceView 的工作方式是创建一个置于应用窗口之后的新窗口,这种方式的效率非常高,因为 SurfaceView 窗口刷新的时候不需要重绘应用程序的窗口。但是同时,使用SurfaceView也有一些非常不便的限制。因为 SurfaceView 的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等),不能使用UI控件的一些特性。

为了解决上述SurfaceView可能出现的这个问题,Android 4.0中引入了TextureView。与SurfaceView相比,TextureView并没有创建一个单独的 Surface用来绘制,这使得它可以像一般的View一样执行一些变换操作。需要注意的一点是:Textureview 必须在硬件加速开启的窗口中使用,而且 TextureView 使用也更加耗电,平均 TextureView 比 SurfaceView 会多用30%的电量。

1.2 MediaPlayer + SurfaceView + 自定义控制器

VideoView的实现方式很简单,但是因为API都是系统自带的封装好的类,所以无论是播放器的大小、位置以及控制都不受我们控制,也就是说没有办法自定义。如果想要实现自定义的视频播放和控制,可以使用第二种方式:MediaPlayer + SurfaceView + 自定义控制器。具体的操作步骤如下:

  • 1、建MediaPlayer对象,加载视频文件。数据来源支持三种方式,前文已经介绍过,此处不再赘述。
  • 2、使用SurfaceView组件,设置SurfaceView的SurfaceHolder的Callback监听器。
  • 3、通过setDisplay将MeddiaPlayer和SurfaceHolder进行绑定。
  • 4、prepareAsync方法准备视频数据。
  • 5、通过start方法开始播放

1.3 Mediaplayer + SurfaceView + MediaController

MediaController是Android系统自带的控制器。其实就是前两种的结合。此处不再赘述。

二、图像和视频的采集

视频的采集需要调用硬件摄像头,对应的API是Camera。使用Camera又分为两类:

  • Android 5.0以下:Camera
  • Android 5.0以上:Camera2

Camera相关API也体现了Android生态碎片化的特点,有时候还会遇到各家手机厂商对Camera2的支持程度也各不相同,这就导致开发者在相机开发中要花费很大精力来处理兼容性问题。

2.1 相机的使用和开发流程

  • 检测并访问相机资源:检查手机是否存在相机资源,如果存在则请求访问相机资源。
  • 创建预览界面:创建继承自SurfaceView并实现SurfaceHolder接口的拍摄预览类。有了拍摄预览类,即可创建一个布局文件,将预览画面与设计好的用户界面控件融合在一起,实时显示相机的预览图像。
  • 设置拍照监听器:给用户界面控件绑定监听器,使其能响应用户操作, 开始拍照过程。
  • 处理:拍照并保存文件,将拍摄获得的图像转换成位图文件,最终输出保存成各种常用格式的图片或者可以采集视频信息。
  • 释放相机资源:相机是一个共享资源,当相机使用完毕后,必须正确地将其释放,以免其它程序访问使用时发生冲突。

2.2 相机开发注意事项

从API到硬件,再到厂商的兼容性问题,相机开发中需要格外注意的几个点首先要有心理准备。

  • API兼容性问题:Android 5.0以下的API是Camera,Android5.0以上是Camera2;4.0以下只能使用SurfaceView,4.0以上多了选择TextureView;Android 权限升级后使用相机资源时的动态权限适配问题。
  • 硬件设备兼容性问题:前文已经提到过,,Camera/Camera2里的各种特性在有些手机厂商的设备实现方式和支持程度是不一样的,这个需要做兼容性测试,坑要一点点填。
  • 应用开发时业务场景下的硬件资源的管理问题。比如应用进入到后台或者锁屏等操作,相机资源该如何管理和操作。应用界面该如何绘制和管理等。

2.3 Camera和Camera2

Camera

Camera API中主要涉及以下几个关键类:

  • Camera:操作和管理相机资源,支持相机资源切换,设置预览和拍摄尺寸,设置光圈、曝光等相关参数。
  • SurfaceView:用于绘制相机预览图像,提供实时预览的图像。
  • SurfaceHolder:用于控制Surface的一个抽象接口,它可以控制Surface的尺寸、格式与像素等,并可以监视Surface的变化。
  • SurfaceHolder.Callback:用于监听Surface状态变化的接口。Callback中有三个函数:
    • surfaceCreated: 当Surface第一次创建的时候调用,可以在这个方法里调用camera.open()、camera.setPreviewDisplay()来实现打开相机以及连接Camera与Surface 等操作。
    • surfaceChanged:当Surface的size、format等发生变化的时候调用,可以在这个方法里调用camera.startPreview()开启预览。
    • surfaceDestroyed:当Surface被销毁的时候调用,可以在这个方法里调用camera.stopPreview(),camera.release()等方法来实现结束预览以及释放。

相机的分类和操作:

  • 分类:前置和后置
    • Camera.CameraInfo.CAMERA_FACING_FRONT:前置
    • Camera.CameraInfo.CAMERA_FACING_BACK:后置
  • open:打开相机
  • getParameters:获取相机参数
    • FLASH_MODE_AUTO:自动模式,当光线较暗时自动打开闪光灯;
    • FLASH_MODE_OFF:关闭闪光灯
    • FLASH_MODE_ON:拍照时闪光灯
    • FOCUS_MODE_AUTO:自动对焦模式
    • FOCUS_MODE_FIXED:固定焦距模式
    • SCENE_MODE_NIGHT:夜间场景;
    • ...
  • takePicture:拍照
    • ShutterCallback:拍照的瞬间被回调,播放拍照音效;
    • PictureCallback raw:未经压缩的图像数据
    • PictureCallback postview:postview类型的图像数据
    • PictureCallback jpeg:经过JPEG压缩的图像数据
  • release():释放相机资源

Camera2

Camera2 API中主要涉及的关键API:

  • CameraManager:摄像头管理器,用于打开和关闭系统摄像头
  • CameraCharacteristics:描述摄像头的各种特性,可通过CameraManager的getCameraCharacteristics(id)方法获取
  • CameraDevice:系统摄像头,类似于早期的Camera
  • CameraCaptureSession:Session类,当使用拍照、预览等功能时,需要先创建该类的实例,然后通过该实例里的方法进行控制(例如:拍照 capture())
  • CaptureRequest:拍照、预览等操作都需要先传入CaptureRequest参数,具体的参数控制也是通过其成员变量来设置
  • CaptureResult:描述拍照完成后的结果。

以上的核心API,Camera2的运行原理如下图所示

 

通过管道将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,摄像头会返回 CameraMetadata,中间的通信建立在CameraCaptureSession的会话中。

Camera2的使用流程大致如下:

  • 工作线程:创建一个专门的线程用于Camera的具体操作,可以使用HandlerThread,Android提供的具备Handler的Thread,用于通信。
  • 预览画面:可以是SurfaceView或者TextureView,用于显示采集的数据画面。
  • 获取Camera设备:使用CameraManager找到合适的Camera设备,得到相关参数,调整预览画面等操作。
  • 开启设备:调用CameraManager的openCamera,打开指定摄像头
    • cameraId:摄像头id
    • CameraDevice.StateCallback:相机回调状态
    • handler:消息数据处理

 

  • CameraDevice:通过StateCallback获取到设备Camera对象
  • Camera与视图绑定:调用CameraDevice.createCaptureRequest方法,用于将Surface和Camera进行绑定,让Surface可以接收Camera的数据。
  • 建立会话:调用CameraDevice的createCaptureSession方法创建session对象,创建成功后会回调StateCallback接口方法onConfigured,表明会话已经建立。
  • 发送请求:在创建好的会话中通过setRepeatingRequest发送请求,即向Camera发送命令。

2.4 视频的采集

路线既可以调用系统实现,也可以自定来实现。

Intent

我们都知道Intent是Android中的组件之间的通信工具,如果想要调用系统的录像功能,可以设置Intent意图,如下所示:

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 5);//限制时长 s
intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 1024*1024);//限制大小 
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//设置质量
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//设置输出位置
startActivityForResult(intent, 1);
​

另外在onActivityResult中接收:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(resultCode==RESULT_OK){
        Uri uri = data.getData();
        //视频地址
        String videoPath = getPathFromUri(this,uri);
    }
}
​
public static String getPathFromUri(Context mContext,Uri contentUri){
    String[] proj = { MediaStore.Images.Media.DATA };
    CursorLoader loader = new CursorLoader(mContext, contentUri, proj, null, null, null);
    Cursor cursor = loader.loadInBackground();
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}

MediaRecorder

如果需要自定义录制视频,需要使用前文讲到的MediaRecorder类来辅助完成。结合Camera2来进行实现。

其操作方法与预览和拍照过程相似,此处直接以案例进行演示和讲解。

热门文章

暂无图片
编程学习 ·

js 的递归写法 代码的健壮性

这几天参加面试,有个关于递归的问题,之前学红皮书的手后,看过也写过代码,但是时间长了不用就会忘记,翻书肯定没有自己记住效率高;首先解释一下为什么这么写;//因为函数的本质是一个对象,fun是声明在栈内存中,其中保存一个地址,系统通过地址可以在堆中找到一个Function的对象;fu…
暂无图片
编程学习 ·

ClassName(类名)命名

ClassName命名 ClassName的命名应该尽量精短、明确,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “_” 连接。 eg:.nav_top 注意事项 ad、banner、gg、guanggao 等有机会和广告挂勾的字眠不建议直接用来做ClassName,因为有些浏览器插件(Chrome的广告拦截…
暂无图片
编程学习 ·

系统整理springCloud (一),搭建父项目,管理jar包

一,应用springCloud 有一段时间了,Boot由1到2,springCloud 也到了H版本,alibaba 也已孵化维护自己版本,在这里对springCloud做一个系统的整理,版本为boot2版本。首先建立父工程cloud-parent加入jar包<!-- 统一管理jar包版本 --> <properties><project.bui…
暂无图片
编程学习 ·

如何更好的使用大数据

在互联网时代,依靠大数据是未来的发展趋势。大数据分析现在非常流行,但是我们需要知道的是,大数据的价值体现在有效而正确的分析中。只有通过正确有效的分析工具和分析方法来解释现有的大数据,大数据才能为我们带来有价值的结果。今天,中琛魔方将教您如何有效运用大数据。…
暂无图片
编程学习 ·

难得一遇的5G大屏手机 荣耀X10 Max配置分析

6月22日,荣耀通过微博证实了荣耀X10 Max的存在,并宣布将会在7月2日正式发布。消息一出可谓是让很多人非常欣喜,尤其是等了多年大屏手机的用户。荣耀X10 Max不仅是荣耀在5G时代发布的首款大屏手机,也是荣耀时隔两年,继荣耀8X后的续作。那么这款5G大屏手机有哪些特点和配置呢…
暂无图片
编程学习 ·

git命令大全

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git官方网站:https://git-scm.com/ 原理图Workspace:工作区 Index / Stage:暂存区 Repository:仓库…
暂无图片
编程学习 ·

php发送stmp邮件类 给有需要的人

<?php/*** email smtp (support php7)** Modified by: Reson 2019/06** More: http://www.wan0551.com**/class Smtp {/* Public Variables */public $smtp_port;public $time_out;public $host_name;public $log_file;public $relay_host;public $debug;public $auth;pu…
暂无图片
编程学习 ·

python pytest selenium 自动化测试框架搭建

python pytest selenium 自动化测试框架搭建公司一直有这个自动化测试需求,前期利用c++或者python进行了一些自动化脚本的编写。这几天没有版本更迭,基于前期的工作,把自动化测试整理了一部分功能模块。现在的状态基本达到预期:即搭建了一个AutoTest框架,基于此实现了logi…
暂无图片
编程学习 ·

云管理服务AWS Organizations正式在AWS中国区域上线

近期, AWS中国(宁夏)区域(由西云数据运营)和AWS中国(北京)区域(由光环新网运营)正式上线了云管理服务AWS Organizations。作为一种管理服务,AWS Organizations可集中控制和管理多个AWS账户,无论是初创公司还是大型企业均可以使用,而不需要额外付费。随着企业或机构…
暂无图片
编程学习 ·

(python version) 劍指offer 35. 复制链表的复制

题目描述 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。 来源:力扣(LeetCode)解题思路 剑指书上的方法 1.方法一第一步:复制原始链表上的每个节点N、创…
暂无图片
编程学习 ·

LeetCode 232. 用栈实现队列(C++)

** 232. 用栈实现队列 ** 题目描述: 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。主要思路:入队时1.直接push到inStack中出队时1.如果outStack为空,先把…
暂无图片
编程学习 ·

pandas下-综合练习

综合练习端午节的淘宝粽子交易 端午节的淘宝粽子交易 (1) 请删除最后一列为缺失值的行,并求所有在杭州发货的商品单价均值。 df=pd.read_csv(F:\Datewheel资料\pandas组队学习\Pandas(下)综合练习数据集\端午粽子数据.csv) df.head()df.info()#查看列名 df.columns()注意列名…
暂无图片
编程学习 ·

Kotlin上手(一)

标准函数with with函数接收两个参数,第一个参数是任意类型的对象,第二个是Lambda表达式。with函数会在Lambda表达式中提供第一个参数的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。 fun test() {val list = listOf("Apple", "Banana", &…
暂无图片
编程学习 ·

Niushop单商户商城系统后台新增功能啦!

随着单商户商城系统直播功能的上线,越来越多的牛友反馈,这真的是太方便啦! 抗疫期间,商城直播无疑是当下最红,再加上地摊经济,线上直播,线下溜达的功夫还能看看商品实物,简直不要太完美! 因此,Niushop研发团队就直播这一功能,又新增了几项功能,更方便于牛友们直播带…
暂无图片
编程学习 ·

java实现ipv4和ipv6字符串地址与数字类型的转换

项目中需要将IPv4或IPv6地址转换成数字类型,或者将数字类型的ip地址转换成字符串的IPv4或IPv6地址。所以需要一个工具类,这篇文章记录一下自己使用的工具类。 IpUtil.javaimport java.math.BigInteger;public class IpUtil {/**ipv4字符串转为long**/public static long ipTo…
暂无图片
编程学习 ·

标准序列化机制

序列化就是将对象转化为字节流,反序列化就是将字节流转化为对象。1. 基本用法Serializable要让一个类支持序列化,只需要让这个类实现接口 java.io.Serializable,Serializable 没有定义任何方法,只是一个标记接口。比如,对于57节提到的Student类,为支持序列化,可改为:pu…
暂无图片
编程学习 ·

半监督深度学习

半监督学习在有标签数据+无标签数据混合成的训练数据中使用的机器学习算法。一般假设,无标签数据比有标签数据多,甚至多得多。要求:无标签数据一般是有标签数据中的某一个类别的(不要不属于的,也不要属于多个类别的); 有标签数据的标签应该都是对的; 无标签数据一般是类…
暂无图片
编程学习 ·

PMP-质量成本:一致性成本和非一致性成本对比

一致性成本vs非一致性成本,原文链接:https://www.ffeeii.com/1882.html质量成本:质量成本(cost of quality)包括在产品生命周期中为预防不符合要求,为评估产品或服务是否符合要求,以及因未达到要求(返工),而发生的所有成本。一致性成本:一致性成本(cost of conform…