一个偶然遇到了ffmpeg,看起来不多,而且通用性很强,算是一个扎实的技术。
研究了两天了,万事开头难啊。
主要是新手学习一个东西的时候,没有宏观的概念,如果猛地往某个细节去钻,往往碰的焦头烂额,事倍功半。
如果由一个“师傅”,能先点拨一下,讲讲宏观的概念,再说说改如何去学,那将很提升效率,可惜这样的“师傅”很难找。
问别人问题,太叼的人不屑于鸟你,太弱的人,也答不上来。
还有一点,我由于不懂这玩意儿,掌握不了发问的技巧,往往就问ffmpeg是什么啊,能不能给我讲讲,但是一般人都会反问,你想知道点什么呢?这个问题真的很难,我不知道我需要知道什么,我不知道我想要知道什么,所以我也无从回答。
我今天能有机会作为一个完全的新手,只具备linux+c的基本技能,来学习播放器,ffmpeg,libav这些东西,我想要把我整个学习的过程记录下来,然后分享给任何一个后来的新手,让他们能快速上手,快速的知道这是什么,我们要学什么。
首先要有一点基础知识来支撑,下面开始对我自己扫盲,答案不一定对,以后可以改正。
1. 什么是编解码,什么是codec?为什么要这样做。
答:编解码,就是codec。CODEC =COde (编码) +DECode(解码)。
假设显示器的设置是:每秒刷新60次,也就是刷新率为60Hz,1024 * 768的分辨率,
那么此时显卡每秒要处理的数据量是 60 * 1024 * 768 个像素点,可想而知,视频文件的大小是很恐怖的。
如果不用任何方法压缩,就单纯的存储视频文件,那么1GB的文件,也只能存储37秒左右的视频内容。
所以,咱们需要一个方式来压缩(code,编码)它,再存储起来,要播放的时候,再解压缩(decode,解码)。
这样牺牲一些时间,来换取很大一部分空间,这是值得的,并且咱们的硬件设备也有这个能力做到。
2. 如何来编解码呢?根据什么前提来做呢?
答:假设一个纯粹的没压缩过的视频文件,假设很大很大,他在展示给我们观看的时候,有些内容,即使被删去,也不会影响我们的观看效果。举个例子,你喝白开水的时候,里面的矿物质元素含量多少,有或者没有,并不影响你的口感。
所以,有些内容是不影响我们观看感受的,所以可以删去,那就是
编解码的编码器
原视频文件(很大) -------------------> 编码后的视频文件(相对要小一些)
前后两者在空间大小上有区别,后者小一些,当然后者的质量也要差一些。
观看时:
编解码的解码器
编码后的视频文件(相对要小一些)-------------------> 原视频文件(大) ------------->给显卡展示。
所以,那就应该要有某一套规范来制约,那也肯定有某个配套的算法来支持这种规范。
上面举得这个例子是不影响我们观看的前提下的压缩。再举一个例子。
平常电脑上的视频文件,动辄1G多一个。但是放在移动设备上去观看是不是有点浪费呢。
所以,也可以在影响我们观看的前提下进行压缩,结果就会是:你把移动设备上的视频文件放在22寸显示器上去播放,而且还全屏,你肯定看着不爽,觉得质量超差,但是这也是很有必要的。
把高清的1080P压缩成半高清或者标清的也是一种损失质量的编码方式。
3. 基础概念扫盲,Container(容器),Stream(流),Frame(帧),Codec(编解码器),mux/demux(复用/解复用)。
答:一个container就是一个文件,一种container就是一种文件格式,举例:xxx.flv 和 yyy.mkv是两个文件,我们可以说他们是两个容器,并且是两种不同的容器。
容器和流 以及 复用/解复用
先看xxx.flv文件,假设里面包含两种stream,一种是音频流(audio stream),另一种是视频流(video stream),并且以flv规定的格式把这两个流封装在.flv容器里面。
再看yyy.mkv文件,假设里面包含三种stream,一种是音频流(audio stream),另一种是视频流(video stream),还有一种流是字幕流(subtitle stream),并且以mkv规定的格式把这三种流封装在.mkv的容器里面。
上面讲了容器和流的关系,那把不同的流按照某种容器的规则从那种容器(文件)中解析(或者说抽出来)出来,这种行为叫做解复用(demux),使用解复用器(demuxer),那反过来,把不同的流按照某种容器的规则放入那种容器(最后肯定生成了某种格式的文件),这种行为叫做复用(mux),使用复用器(muxer)。
这四个概念是抽象出来的,会有不同的结构体在实现这些抽象概念的。每个不同的容器都有不同的规则来整合流,常见的容器有,.mkv .rm .flv .mp4等等一些,那么针对不同的容器,就应该有不同的解复用器来解复用了。其实我们也可以自己实现这些解复用器,前提是我们能够清楚的掌握某每种容器的内部格式。
流和帧 以及 编解码器
如果仔细读了上文的话,大概也能猜到,这一段叙述的方式和上一段也会是一样的。两种不同的东西之间要发生转换,肯定要有正反两种器具,使得转换正进行,或者反进行。
直接了当,帧就是包含在流里面的!
当从容器中得到一个流以后,或者说不管你怎么弄的,反正你得到了一个流,那这个流就认为是被某种编码器 编码过后生成的,你需要把这个流里面的帧去解码。其实这样讲是反的,我们换个角度来理解。
什么是影片?其实就是一组(很多张)图片,时间间隔很小的连续展示出来,人们就觉得画面中的人物在动,这就是影片。那电影的实质就是N多张图片的集合。那每张图片和帧又有什么关系呢?事实上,如果一部影片里面的图片,我们原封不动的全部存起来,空间会很大很大很大,但是如果通过一定的算法(这里不讲相关算法),把每一张图片压缩(编码_encode)一下,变成 帧。再把帧连起来变成流,再把不同的流放到某个容器里面,这就是我们平常看见的电影文件了,比如这个文件 碟中谍4.H264.ACC.mkv,他为什么要这样命名呢? mkv表达了它的容器是.mkv的,且包含至少两个流,h264的视频流,ACC的音频流。这是一种典型的 牺牲时间来换取空间的做法。
现在应该明白了吧,回到之前的话题,得到一个流之后,就得设法找出里面的帧,然后使用 解码器/decoder 把帧还原,然后再去播放,也可以再去使用另一个编码器/encoder编码压缩成另一种格式的帧(这就是所谓的转格式软件要完成的一个步骤)。
4. ffmpeg是什么?
下面摘抄一段ffmpeg官网的东西。
FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。
5. 我们学习ffmpeg,究竟是学什么呢?
ffmpeg是一个方案,里面解决了编解码,复用解复用,里面提供很多API给我们用,当然,还有一些工作我们必须自己完成,比如同步的问题。首先我们要了解从打卡一个视频文件到解复用到解码到播放这一套流程,然后学习他提供的API怎么用,使用顺序是怎么样的。然后再去了解API的实现细节,最后把实现细节也掌握好了,咱们就可以按照自己的需求,进行修改,然后做一个符合需求的定制版。
6. 我试图编译ffmpeg的源文件包,发现编译出来了ffplay、ffmpeg、ffserver等等一些二进制文件,这些是什么?干什么用的?
ffplay:他就是一个真正的播放器了,就像vlc、mplayer等播放器,有图形界面的。
ffmpeg:可以理解成一个工具,利用ffmpeg方案提供的一些API,再加上一些其他操作,可以实现转码等一些功能。
ffserver:顾名思义了,做服务器的。可以单播或多播一些流。