序:
什么是影片:实际上就是很多张图片,在间隔时间很短的连续展示出来。电影实际上就是很多张图片的集合。如果我们原封不动的保存起来,纳闷占用空间会很大,如果我们使用算法将其压缩一下,变成帧,在将帧变成流,再把流放到容器中,就是我们常见的电影了。一部电影中至少包含两种流:h.264的视频流,AAC的音频流。
容器(Container):就是一种文件格式,如:flv、mkv等。包含下面5种流以及文件头信息
流(Stream) :是一种视频信息的传输方式,5种流:音频,视频,字幕,附件,数据
帧(Frame) :帧代表一副静止的图像,分为:I、P、B帧
编解码器(Codec) :是对视频进行压缩或者解压缩,CODEC =COde (编码) +DECode(解码)
复用/解复用(mux/demux):把不同的流按照某种容器的规则放入容器,这种行为叫做复用(mux)
把不同的流从某种容器中解析出来,这种行为叫做解复用(demux)
I、P、B帧:视频压缩中,每帧代表一幅静止的图像。而在实际压缩时,会采取各种算法减少数据的容量,其中IPB是最常见的
I帧:关键帧,可以理解为某一帧画面的完整保留,解码时只需要本帧数据就可以完成
P帧:表示这一帧和前一帧之间的差别,解码时只需要前一帧的画面加上本帧定义的差别就可以生成最终画面
B帧:双向差别帧,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累
从上面的解释看,我们知道I和P的解码算法比较简单,资源占用也比较少,I只要自己完成就行了,P呢,也只需要解码器把前一个画面缓存一下,遇到P时就使用之前缓存的画面就好了,如果视频流只有I和P,解码器可以不管后面的数据,边读边解码,线性前进,大家很舒服。但网络上的电影很多都采用了B帧,因为B帧记录的是前后帧的差别,比P帧能节约更多的空间,但这样一来,文件小了,解码器就麻烦了,因为在解码时,不仅要 用之前缓存的画面,还要知道下一个I或者P的画面(也就是说要预读预解码),而且,B帧不能简单地丢掉,因为B帧其实也包含了画面信息,如果简单丢掉,并 用之前的画面简单重复,就会造成画面卡(其实就是丢帧了),并且由于网络上的电影为了节约空间,往往使用相当多的B帧,B帧用的多,对不支持B帧的播放器 就造成更大的困扰,画面也就越卡。 一般平均来说,I的压缩率是7(跟JPG差不多),P是20,B可以达到50,可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质。
编解码过程:
1. 注册所有容器格式和CODEC:av_register_all()
2. 打开文件:av_open_input_file()
3. 从文件中提取流信息:av_find_stream_info()
4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO
5. 查找对应的解码器:avcodec_find_decoder()
6. 打开编解码器:avcodec_open()
7. 为解码帧分配内存:avcodec_alloc_frame()
8. 不停地从码流中提取出帧数据:av_read_frame()
9. 判断帧的类型,对于视频帧调用:avcodec_decode_video()
10. 解码完后,释放解码器:avcodec_close()
11. 关闭输入文件:av_close_input_file()
库:
1、libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含demuxers和muxer库;
2、libavcodec:用于各种类型声音/图像编解码;
3、libavutil:包含一些公共的工具函数;
4、libswscale:用于视频场景比例缩放、色彩映射转换;
5、libpostproc:用于后期效果处理;
6、ffmpeg:是一个命令行工具,用来对视频文件转换格式,也支持对电视卡实时编码;
7、ffsever:是一个HTTP多媒体实时广播流服务器,支持时光平移;
8、ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;