[关闭]
@TryLoveCatch 2017-06-22T16:12:05.000000Z 字数 5763 阅读 1798

视频编辑

android 视频


基础知识

为什么需要编解码

首先,我们常说编码,就是压缩;解码,就是解压缩。
视频文件的本质其实就是图片的集合而已,当一段连续的图片不断的出现在人眼前(一般一个连贯的电影或者动画至少要求一秒24帧,也就是一秒内连续出现24张图片),肉眼就会“欺骗性”的告诉大脑我们在看一个视频,而不是幻灯片。

那我们可以开始做点算术题了,

假设一张像素为1280X720(清晰度,宽1280个像素点,高720个像素点)的图片,大小为约为1280X720X3(RGB) bytes,就是2.7MB。大家可以猜想一下为何我这里还需要乘以一个数字3.那么一段60秒钟的小电影,就需要60X24(24帧)X2.7MB ,约为3.9GB了!

这个是怎么可能忍受呢?所以就有了Codec,它是一种程序,这种程序可以对视频文件进行编码和解码。
它会把这些连续的图片们通过一定的算法压缩成体积更小的文件格式,这就是我们所谓的编码,压缩。但是在播放器的客户端,不管是PC,手机也好,他们要显示在屏幕上的,必须是实实在在的图片啊,所以这些被压缩过的文件最终又必须被还原成图片格式,这就是解码,解压缩。

播放一个视频

视频播放器播放一个互联网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码视音频,视音频同步。如果播放本地文件则不需要解协议,为以下几个步骤:解封装,解码视音频,视音频同步。他们的过程如图所示。

1. 解协议

视音频在网络上传播的时候,除了传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。

常见格式:http,RTMP,或是MMS等。
作用:将流媒体协议的数据,解析为标准的相应的封装格式数据。
举例:采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。

2. 解封装

所谓封装格式,就是把视频数据和音频数据打包成一个文件的规范。仅仅靠看文件的后缀,很难能看出具体使用了什么视音频编码标准。总的来说,不同的封装格式之间差距不大,各有优劣。

封装格式种类很多,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。

常见格式:MP4,MKV,RMVB,TS,FLV,AVI等。
作用:将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。
举例:FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

3. 解码

解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。

常见格式:音频,AAC,MP3,AC-3等;视频,H.264,MPEG2,VC-1等。
作用:就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。

4. 视音频同步

视音频同步的作用,就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

原始数据

视频:YUV420P,RGB等。
音频:PCM等。

总结

封装格式

封装格式,是把视频码流和音频码流按照一定的格式存储在一个文件中。

名称 推出机构 流媒体 视频编码 音频编码 应用领域
AVI Microsoft 不支持 几乎所有格式 几乎所有格式 BT下载
MP4 MPEG 支持 MPEG-2, MPEG-4, H.264, H.263等 AAC, MPEG-1 Layers I, II, III, AC-3等 互联网视频网站
TS MPEG 支持 MPEG-1, MPEG-2, MPEG-4, H.264 MPEG-1 Layers I, II, III, AAC, IPTV,数字电视
FLV Adobe 支持 Sorenson, VP6, H.264 MP3, ADPCM, Linear PCM, AAC等 互联网视频网站
MKV CoreCodec 支持 几乎所有格式 几乎所有格式 互联网视频网站
RMVB Real Networks 支持 RealVideo 8, 9, 10 AAC, Cook Codec, RealAudio Lossless BT下载

注:有些封装格式支持的视音频编码标准十分广泛,应该算比较优秀的封装格式,比如MKV;而有些封装格式支持的视音频编码标准很少,应该属于落后的封装格式,比如RMVB。

视频编码

视频编码的主要作用是将视频像素数据(RGB,YUV等)压缩成为视频码流,从而降低视频的数据量。

名称 推出机构 推出时间 应用领域
HEVC(H.265) MPEG/ITU-T 2013 研发中
H.264 MPEG/ITU-T 2003 各个领域
MPEG4 MPEG 2001 不温不火
MPEG2 MPEG 1994 数字电视
VP9 Google 2013 研发中
VP8 Google 2008 不普及
VC-1 Microsoft 2006 微软平台

注:当前使用最多的视频编码方案就是H.264。

音频编码

音频编码的主要作用是将音频采样数据(PCM等)压缩成为音频码流,从而降低音频的数据量。

名称 推出机构 推出时间 应用领域
AAC MPEG 1997 各个领域(新)
AC-3 Dolby 1992 电影
MP3 MPEG 1993 各个领域(旧)
WMA Microsoft 1999 微软平台

由表可见,近年来并未推出全新的音频编码方案,可见音频编码技术已经基本可以满足人们的需要。音频编码技术近期绝大部分的改动都是在MP3的继任者——AAC的基础上完成的。

MediaMetadataRetriever

MediaMetadataRetriever,解析媒体文件、获取媒体文件中取得帧和元数据(视频/音频包含的标题、格式、艺术家等信息)。

视频缩略图

1、2.2 之后:因为用了ThumbnailUtils

  1. Bitmap b = ThumbnailUtils.createVideoThumbnail(path,Video.Thumbnails.MICRO_KIND);
  2. ImageView iv = new ImageView(this);

2、MediaMetadataRetrievergetFrameAtTime()取得指定时间位置的Bitmap,即可以实现抓图(包括缩略图)功能,更加强大。

  1. MediaMetadataRetriever mmr = new MediaMetadataRetriever();
  2. mmr.setDataSource("/sdcard/33.mp4");
  3. Bitmap bitmap = mmr.getFrameAtTime();

3、MediaExtractorMediaCodec来获取帧视图
Android帧率控制视频播放器FramePlayer

获取其他信息

  1. /**解析音乐标签
  2. * 测试发现无法解析wma音乐文件
  3. * 可解析mp3 ma4等
  4. * Created by junny on 12/17/13.
  5. */
  6. public class MusicParseUtil {
  7. public static String getAlbum(String filePath){
  8. String album;
  9. try {
  10. MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
  11. mediaMetadataRetriever.setDataSource(filePath);
  12. album = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
  13. } catch (Exception e) {
  14. album = null;
  15. }
  16. return album;
  17. }
  18. public static String getTitle(String filePath){
  19. String title;
  20. try {
  21. MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
  22. mediaMetadataRetriever.setDataSource(filePath);
  23. title = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
  24. } catch (Exception e) {
  25. title = null;
  26. }
  27. return title;
  28. }
  29. public static String getArtist(String filePath){
  30. String artist;
  31. try{
  32. MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
  33. mediaMetadataRetriever.setDataSource(filePath);
  34. artist = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
  35. }catch (Exception e){
  36. artist = null;
  37. }
  38. return artist;
  39. }
  40. public static byte[] getMusicThumbail(String filPath){
  41. byte[] pic;
  42. try{
  43. MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
  44. mediaMetadataRetriever.setDataSource(filPath);
  45. pic = mediaMetadataRetriever.getEmbeddedPicture();
  46. }catch (Exception e){
  47. pic = null;
  48. }
  49. return pic;
  50. }
  51. }

getFrameAtTime()

  1. public Bitmap getFrameAtTime(long timeUs, int option) {
  2. if (option < OPTION_PREVIOUS_SYNC ||
  3. option > OPTION_CLOSEST) {
  4. throw new IllegalArgumentException("Unsupported option: " + option);
  5. }
  6. return _getFrameAtTime(timeUs, option);
  7. }

这里有两个参数:
timeUs 表示每一帧的开始时间位置,给定的时间的帧不一定存在,但是系统会将临近的一帧返回给我们。
option 参数表示获取帧的方式
OPTION_CLOSEST 在给定的时间,检索最近一个帧,这个帧不一定是关键帧
OPTION_CLOSEST_SYNC 在给定的时间,检索与当前时间最近的关键帧
OPTION_NEXT_SYNC 在给定时间之后检索一个关键帧
OPTION_PREVIOUS_SYNC 在给定时间之前检索一个关键帧

这个方法的问题:
1、获取的Bitmap是与原视频尺寸相同的,图片会比较大,并没有提供获取压缩的图片的接口。
2、获取的帧的速度较慢,测试下来获取一帧的时间为250ms左右。
3、即使使用OPTION_CLOSEST获得的也是有一定偏差的,并不能保证获取指定时间点的帧。
因此,实际实现中,通常使用ffmpeg来获取视频帧,不仅可以获取任意大小的图片,速度也有比较大的提升,使用ffmpeg通常可以精确获得指定时间的帧

MediaMuxer

MediaMuxer用于将音频和视频进行混合生成多媒体文件。缺点是目前只能支持一个audio track和一个video track,而且仅支持mp4输出

MediaExtractor

MediaCodec


MediaCodec 架构上采用了2个缓冲区队列,异步处理数据,下面描述的 Client 和 MediaCodec 模块是并行工作的(注:这里的 Client 就是指 “开发者,API 的使用者”):

(1)Client 从 input 缓冲区队列申请 empty buffer [dequeueInputBuffer]

(2)Client 把需要编解码的数据拷贝到 empty buffer,然后放入 input 缓冲区队列 [queueInputBuffer]

(3)MediaCodec 模块从 input 缓冲区队列取一帧数据进行编解码处理

(4)编解码处理结束后,MediaCodec 将原始数据 buffer 置为 empty 后放回 input 缓冲区队列,将编解码后的数据放入到 output 缓冲区队列

(5)Client 从 output 缓冲区队列申请编解码后的 buffer [dequeueOutputBuffer]

(6)Client 对编解码后的 buffer 进行渲染/播放

(7)渲染/播放完成后,Client 再将该 buffer 放回 output 缓冲区队列 [releaseOutputBuffer]

“生产者”和“消费者”其实是共用这一个缓冲区队列,“生产者”负责从队列中取出未使用的 Buffer,填入数据,然后放回队列,“消费者”则负责取出填入数据后的 Buffer,进行处理,处理结束后,再把 Buffer 标记为“空”,退回到队列中去以供“生产者”继续填充数据。

在 input 端,“Client”是这个环形缓冲区“生产者”,“MediaoCodec 模块”是“消费者”。

在 output 端,“MediaoCodec 模块”是这个环形缓冲区“生产者”,而“Client”则变成了“消费者”。

这就是其核心的工作原理,其实并不复杂,大家静下心来,很快就能理解其中的奥妙。

TextureView SurfaceTexture SurfaceView

参考

视音频编解码技术零基础学习方法
Android视频开发进阶(part1-关于视频的那些术语)

Android视频开发基础(二)

Android Multimedia框架总结

MediaCodec状态周期及Codec与输入/输出Buffer过程(附实例)

Android音频开发(5):音频数据的编解码

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注