ffmpeg和流媒体视频编解码的研究

常见视频格式的一些特点和区别
  • mkv、rmvb、avi、MP4、flv、wmv这些指的都是文件格式,也就是封装格式,都是容器,而不是真正的数据压缩格式,内部封装都是采用不同的音视频编码压缩后的数据,比如mp4,flv内部都是h264格式的视频数据和aac的音频数据
  • 1、mkv:mkv不等同于音频或视频编码格式,它只是为这些进行过音视频编码的数据提供了一个封装的格式,简单的说就是指定音视频数据在文件中如何排列放置。
    MKV最大的特点就是能容纳多种不同类型编码的视频、音频及字幕流,俗称万能媒体容器。
    MKV加入AVI所没有的EDC错误检测代码,这意味着即使是没有下载完毕的MKV文件也可以顺利回放,这些对AVI来说完全是不可想象的。虽然MKV加入了错误检测代码,但由于采用了新的更高效的组织结构,用MKV封装后的电影还是比AVI源文件要小了约1%,这就是说即使加上了多个字幕,MKV文件的体积也不可能比AVI文件大。
    MKV支持可变帧率,它可在动态画面中使用较大的帧率,而在静态画面中使用较小的帧率,这样可以有效的减少视频文件的体积,并改善动态画面的质量。它的作用比目前广泛使用的VBR(可变码率)更为明显。
  • 2、avi 可容纳多种类型的音频和视频流,他的封装格式比较老了,在功能上不能像mkv那样满足更多的需求
  • 3、rmvb 是rm的升级版本,vb代表变比特率,意思是在画面平缓的时候采用低比特率,画面变化剧烈的时候采用高比特率,有效降低文件尺寸,又不影响太多画质。一般来说,一个700MB的 DVDrip 采用平均比特率为450Kbps的压缩率,生成的 RMVB 大小仅为400MB,但是画质并没有太大变化。但是由于编码器的关系,在画质上还是略输于h.264,所以现在压缩高清视频时更偏重于使用mkv封装。
  • 4、mp4 视频MP4格式实际上指的是使用MPEG-4编码格式、或使用MPEG-4衍生出来的编码格式进行编码的文件,比如DivX、XviD、H.263、H.264、 MS MPEG-4 3688 、 Microsoft Video1 、Microsoft RLE,此种文件格式功能不如mkv丰富。
  • 5、flv FLV文件体积小巧,清晰的FLV视频1分钟在1MB左右,一部电影在100MB左右,是普通视频文件体积的1/3。再加上CPU占有率低、视频质量良好等特点使其在网络上盛行,目前网上的几家著名视频共享网站均采用FLV格式文件提供视频
    6、wmv WMV是微软推出的一种流媒体格式,它是在“同门”的ASF(AdvancedStreamFormat)格式升级延伸来得。在同等视频质量下,WMV格式的文件可以边下载边播放,因此很适合在网上播放和传输。
  • 由于flv在流媒体中有体积小,视频清晰,消耗CPU小等特点,故在视频直播,流媒体传输中应用十分广泛,比如映客拉流数据就采用flv流
ffmpeg模块划分
  • libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能
  • libavcodec:用于各种类型声音/图像编解码
  • libavutil:包含一些公共的工具函数
  • libswscale:用于视频场景比例缩放、色彩映射转换
  • libpostproc:用于后期效果处理
  • ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等
  • ffsever:一个 HTTP 多媒体即时广播串流服务器
  • ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示
H264编码原理与I、P、B帧

三种帧的说明

I帧:帧内编码帧 ,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)

I帧特点:
1.它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
2.解码时仅用I帧的数据就可重构完整图像;
3.I帧描述了图像背景和运动主体的详情;
4.I帧不需要参考其他画面而生成;
5.I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
6.I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧;
7.I帧不需要考虑运动矢量;
8.I帧所占数据的信息量比较大。

P帧:前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)

P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。

P帧特点:
1.P帧是I帧后面相隔1~2帧的编码帧;
2.P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
3.解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
4.P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
5.P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧;
6.由于P帧是参考帧,它可能造成解码错误的扩散;
7.由于是差值传送,P帧的压缩比较高。

B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

B帧的预测与重构
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。
B帧特点
1.B帧是由前面的I或P帧和后面的P帧来进行预测的;
2.B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
3.B帧是双向预测编码帧;
4.B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确;
5.B帧不是参考帧,不会造成解码错误的扩散。

注:I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧。一般来说,I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50。可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质。

IDR: 在H.264中,图像以序列为单位进行组织。一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。 IDR 图像一定是 I 图像,但 I 图像不一定是 IDR 图像。I帧之后的图像有可能会使用I帧之前的图像做运动参考。

H264的压缩

h264的压缩方法:
1.分组:把几帧图像分为一组(GOP,也就是一个序列),为防止运动变化,帧数不宜取多。
2.定义帧:将每组内各帧图像定义为三种类型,即I帧、B帧和P帧;
3.预测帧:以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧;
4.数据传输:最后将I帧数据与预测的差值信息进行存储和传输。

帧内(Intraframe)压缩也称为空间压缩(Spatial compression)。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。帧内压缩一般达不到很高的压缩,跟编码jpeg差不多。

帧间(Interframe)压缩的原理是:相邻几帧的数据有很大的相关性,或者说前后两帧信息变化很小的特点。也即连续的视频其相邻帧之间具有冗余信息,根据这一特性,压缩相邻帧之间的冗余量就可以进一步提高压缩量,减小压缩比。帧间压缩也称为时间压缩(Temporal compression),它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值(Frame differencing)算法是一种典型的时间压缩法,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。

顺便说下有损(Lossy )压缩和无损(Lossy less)压缩。无损压缩也即压缩前和解压缩后的数据完全一致。多数的无损压缩都采用RLE行程编码算法。有损压缩意味着解压缩后的数据与压缩前的数据不一致。在压缩的过程中要丢失一些人眼和人耳所不敏感的图像或音频信息,而且丢失的信息不可恢复。几乎所有高压缩的算法都采用有损压缩,这样才能达到低数据率的目标。丢失的数据率与压缩比有关,压缩比越小,丢失的数据越多,解压缩后的效果一般越差。此外,某些有损压缩算法采用多次重复压缩的方式,这样还会引起额外的数据丢失。

H264的NALU头解析

如果NALU对应的Slice为一帧的开始,则用4字节表示,即0x00000001;否则用3字节表示,0x000001。 
NAL Header:forbidden_bit,nal_reference_bit(优先级)2bit,nal_unit_type(类型)5bit。 标识NAL单元中的RBSP数据类型,其中,nal_unit_type为1, 2, 3, 4, 5的NAL单元称为VCL的NAL单元,其他类型的NAL单元为非VCL的NAL单元。
0:未规定
1:非IDR图像中不采用数据划分的片段
2:非IDR图像中A类数据划分片段
3:非IDR图像中B类数据划分片段
4:非IDR图像中C类数据划分片段
5:IDR图像的片段
6:补充增强信息(SEI)
7:序列参数集(SPS)
8:图像参数集(PPS)
9:分割符
10:序列结束符
11:流结束符
12:填充数据
13:序列参数集扩展
14:带前缀的NAL单元
15:子序列参数集
16 – 18:保留
19:不采用数据划分的辅助编码图像片段
20:编码片段扩展
21 – 23:保留
24 – 31:未规定

H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。

几个相关概念
  • AAC:(Advanced Audio Coding)基于MPEG-2的音频编码技术和音频格式。相对于MP3音质更佳体积更小。AAC属于有损压缩的格式,与时下流行的APE、FLAC等无损格式相比音质存在“本质上”的差距。
  • ADTS、RAW流: ADTS全称是(Audio Data Transport Stream),是AAC的一种十分常见的传输格式。
    AAC解码器都需要把AAC的ES流打包成ADTS的格式,一般是在AAC ES流前添加7个字节的ADTS header。也就是说你可以吧ADTS这个头看作是AAC的frameheader。
  • 音频采样率:音频采样率是指录音设备在一秒钟内对声音信号的采样次数,采样频率越高声音的还原就越真实越自然。在当今的主流采集卡上,采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级,22.05KHz只能达到FM广播的声音品质,44.1KHz则是理论上的CD音质界限,48KHz则更加精确一些。
  • 比特率(码率)是指每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,传送数据速度越快。声音中的比特率是指将模拟声音信号转换成数字声音信号后,单位时间内的二进制数据量,是间接衡量音频质量的一个指标。 视频中的比特率(码率)原理与声音中的相同,都是指由模拟信号转换为数字信号后,单位时间内的二进制数据量。
ffmpeg中几种关键结构体
  • 解协议(http,rtsp,rtmp,mms)
    AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)
  • 解封装(flv,avi,rmvb,mp4)
    AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
  • 解码(h264,mpeg2,aac,mp3)
    每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
  • 存数据
    视频的话,每个结构一般是存一帧;音频可能有好几帧
  • 解码前数据:AVPacket,解码后数据:AVFrame

AVCodec
AVCodec是存储编解码器信息的结构体
const char *name:编解码器的名字,比较短 const char *long_name:编解码器的名字,全称,比较长 enum AVMediaType type:指明了类型,是视频,音频,还是字幕 enum AVCodecID id:ID,不重复 const AVRational *supported_framerates:支持的帧率(仅视频) const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频) const int *supported_samplerates:支持的采样率(仅音频) const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频) const uint64_t *channel_layouts:支持的声道数(仅音频) int priv_data_size:私有数据的大小
1.注册所有编解码器:av_register_all();
2.声明一个AVCodec类型的指针,比如说AVCodec* first_c;
3.调用av_codec_next()函数,即可获得指向链表下一个解码器的指针,循环往复可以获得所有解码器的信息。注意,如果想要获得指向第一个解码器的指针,则需要将该函数的参数设置为NULL。

AVCodecContext
这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息
如果是单纯使用libavcodec,这部分信息需要调用者进行初始化;如果是使用整个FFMPEG库,这部分信息在调用 av_open_input_fileav_find_stream_info的过程中根据文件的头信息及媒体流内的头部信息完成初始化。
其中几个主要 域的释义如下:
extradata/extradata_size: 这个buffer中存放了解码器可能会用到的额外信息,在av_read_frame中填充。一般来说,首先,某种具体格式的demuxer在读取格式头 信息的时候会填充extradata,其次,如果demuxer没有做这个事情,比如可能在头部压根儿就没有相关的编解码信息,则相应的parser会继 续从已经解复用出来的媒体流中继续寻找。在没有找到任何额外信息的情况下,这个buffer指针为空。
time_base: width/height:视频的宽和高。 sample_rate/channels:音频的采样率和信道数目。 sample_fmt: 音频的原始采样格式。 codec_name/codec_type/codec_id/codec_tag:编解码器的信息。

AVStream
该结构体描述一个媒体流
主要域的释义如下,其中大部分域的值可以由av_open_input_file根据文件头的信息确定,缺少的信息需要通过调用av_find_stream_info读帧及软解码进一步获取:index/id:index对应流的索引,这个数字是自动生成的,根据index可以从AVFormatContext::streams表中索引到该流;而id则是流的标识,依赖于具体的容器格式。比如对于MPEG TS格式,id就是pid。

time_base:流的时间基准,是一个实数,该流中媒体数据的pts和dts都将以这个时间基准为粒度。通常,使用av_rescale/av_rescale_q可以实现不同时间基准的转换。 start_time:流的起始时间,以流的时间基准为单位,通常是该流中第一个帧的pts。 duration:流的总时间,以流的时间基准为单位。 need_parsing:对该流parsing过程的控制域。 nb_frames:流内的帧数目。 r_frame_rate/framerate/avg_frame_rate:帧率相关。 codec:指向该流对应的AVCodecContext结构,调用av_open_input_file时生成。 parser:指向该流对应的AVCodecParserContext结构,调用av_find_stream_info时生成。

AVFormatContext
这个结构体描述了一个媒体文件或媒体流的构成和基本信息这是FFMpeg中最为基本的一个结构,是其他所有结构的根,是一个多媒体文件或流的根本抽象。其中:nb_streams和streams所表示的AVStream结构指针数组包含了所有内嵌媒体流的描述;iformat和oformat指向对应的demuxer和muxer指针;pb则指向一个控制底层数据读写的ByteIOContext结构。
start_time和duration是从streams数组的各个AVStream中推断出的多媒体文件的起始时间和长度,以微妙为单位。
通常,这个结构由av_open_input_file在内部创建并以缺省值初始化部分成员。但是,如果调用者希望自己创建该结构,则需要显式为该结构的一些成员置缺省值——如果没有缺省值的话,会导致之后的动作产生异常。以下成员需要被关注:probesize mux_rate packet_size flags max_analyze_duration key max_index_size max_picture_buffer max_delay

AVPacket
AVPacket定义在avcodec.h中
FFMPEG使用AVPacket来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)。其中:
dts 表示解码时间戳,pts表示显示时间戳,它们的单位是所属媒体流的时间基准。
stream_index 给出所属媒体流的索引; data 为数据缓冲区指针,size为长度; duration 为数据的时长,也是以所属媒体流的时间基准为单位; pos 表示该数据在媒体流中的字节偏移量; destruct 为用于释放数据缓冲区的函数指针; flags 为标志域,其中,最低为置1表示该数据是一个关键帧。
AVPacket 结构本身只是个容器,它使用data成员指向实际的数据缓冲区,这个缓冲区可以通过av_new_packet创建,可以通过 av_dup_packet 拷贝,也可以由FFMPEG的API产生(如av_read_frame),使用之后需要通过调用av_free_packet释放。
av_free_packet调用的是结构体本身的destruct函数,它的值有两种情况:(1)av_destruct_packet_nofree或 0;(2)av_destruct_packet,其中,前者仅仅是将data和size的值清0而已,后者才会真正地释放缓冲区。FFMPEG内部使用 AVPacket结构建立缓冲区装载数据,同时提供destruct函数,如果FFMPEG打算自己维护缓冲区,则将destruct设为 av_destruct_packet_nofree,用户调用av_free_packet清理缓冲区时并不能够将其释放;如果FFMPEG不会再使用 该缓冲区,则将destruct设为av_destruct_packet,表示它能够被释放。对于缓冲区不能够被释放的AVPackt,用户在使用之前 最好调用av_dup_packet进行缓冲区的克隆,将其转化为缓冲区能够被释放的AVPacket,以免对缓冲区的不当占用造成异常错误。而 av_dup_packet会为destruct指针为av_destruct_packet_nofree的AVPacket新建一个缓冲区,然后将原 缓冲区的数据拷贝至新缓冲区,置data的值为新缓冲区的地址,同时设destruct指针为av_destruct_packet

AVFrame
构体保存的是解码后和原始的音视频信息。AVFrame通过函数av_frame_alloc()初始化,该函数仅仅分配AVFrame实例本身,而没有分配其内部的缓存。AVFrame实例由av_frame_free()释放;AVFrame实例通常分配一次,重复使用,如分配一个AVFrame实例来保留解码器中输出的视频帧(此时应在恰当的时候使用av_frame_unref()清理参考帧并将AVFrame归零)。该类所描述的数据通常由AVBuffer的API来保存一个引用计数,并保存于AVFrame.buf
/AVFrame.extended_buf,在至少存在一个参考的时候(如AVFrame.buf[0] != NULL),则该对象被标记为“被引用”。在此情况下,AVFrame所包含的每一组数据必须包含于AVFrame的缓存中。

H.264 中的 NAL 技术

1.NAL概述
NAL 全称 Network Abstract Layer,即网络抽象层。在 H.264/AVC 视频编码标准中,整个系统框架被分为 了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容, 而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。 现实中的传输系统是多样化的,其可靠性,服务质量,封装方式等特征各不相同,NAL 这一概念的提出 提供了一个视频编码器和传输系统的友好接口,使得编码后的视频数据能够有效地在各种不同的网络环境 中传输。
2.NAL 单元
NAL 单元是 NAL 的基本语法结构,它包含一个字节的头信息和一系列来自 VCL 的称为原始字节序列载荷 (RBSP)的字节流。头信息中包含着一个可否丢弃的指示标记,标识着该 NAL 单元的丢弃能否引起错误 扩散,一般,如果 NAL 单元中的信息不用于构建参考图像,则认为可以将其丢弃;最后包含的是 NAL 单 元的类型信息,暗示着其内含有效载荷的内容。 送到解码器端的 NAL 单元必须遵守严格的顺序,如果应 用程序接收到的 NAL 单元处于乱序,则必须提供一种恢复其正确顺序的方法。
3.NAL 实现编解码器与传输网络的结合
NAL 提供了一个编解码器与传输网络的通用接口,而对于不同的网络环境,具体的实现方案是不同的。 对于基于流的传输系统如 H.320、MPEG 等,需要按照解码顺序组织 NAL 单元,并为每个 NAL 单元增加 若干比特字节对齐的前缀以形成字节流;对于 RTP/UDP/IP 系统,则可以直接将编码器输出的 NAL 单元 作为 RTP 的有效载荷;而对于同时提供多个逻辑信道的传输系统,甚至可以根据重要性将不同类型的 NAL 单元在不同服务质量的信道中传输。
4.结论
为了实现编解码器良好的网络适应性,需要做两方面的工作:第一、在 Codec 中将 NAL 这一技术完整而 有效的实现;第二、在遵循 H.264/AVC NAL 规范的前提下设计针对不同网络的最佳传输方案。如果实现 了以上两个目标,所实现的就不仅仅是一种视频编解码技术,而是一套适用范围很广的多媒体传输方案, 该方案适用于如视频会议,数据存储,电视广播,流媒体,无线通信,远程监控等多种领域。
NALU 类型
标识 NAL 单元中的 RBSP 数据类型,其中,nal_unit_type 为 1, 2, 3, 4, 5 的 NAL 单元称为 VCL 的 NAL
单元,其他类型的 NAL 单元为非 VCL 的 NAL 单元。

  • 0:未规定
  • 1:非IDR图像中不采用数据划分的片段
  • 2:非IDR图像中A类数据划分片段
  • 3:非IDR图像中B类数据划分片段
  • 4:非IDR图像中C类数据划分片段
  • 5:IDR图像的片段
  • 6:补充增强信息(SEI)
  • 7:序列参数集(SPS)
  • 8:图像参数集(PPS)
  • 9:分割符
  • 10:序列结束符
  • 11:流结束符
  • 12:填充数据
  • 13:序列参数集扩展
  • 14:带前缀的NAL单元
  • 15:子序列参数集
  • 16–18:保留
  • 19:不采用数据划分的辅助编码图像片段
  • 20:编码片段扩展
  • 21–23:保留
  • 24–31:未规定

5.NAL 在多媒体传输、存储系统中的应用
NAL 的头占用了一个字节,按照比特自高至低排列可以表示如下:
0AABBBBB
其中,AA 用于表示该 NAL 是否可以丢弃(有无被其后的 NAL 参考),00b 表示没有参考作用,可丢弃,如 B slice、SEI 等,非零——包括 01b、10b、11b——表示该 NAL 不可丢弃,如 SPS、PPS、I Slice、P Slice 等。 常用的 NAL 头的取值如:

0x67: SPS 0x68: PPS 0x65: IDR 0x61: non-IDR Slice 0x01: B Slice 0x06: SEI 0x09: AU Delimiter
由于 NAL 的语法中没有给出长度信息,实际的传输、存储系统需要增加额外的头实现各个 NAL 单元的定界。 其中,AVI 文件和 MPEG TS 广播流采取的是字节流的语法格式,即在 NAL 单元之前增加 0x00000001 的同步 码,则从 AVI 文件或 MPEG TS PES 包中读出的一个 H.264 视频帧以下面的形式存在:

00 00 00 01 06 ... 00 00 00 01 67 ... 00 00 00 01 68 ... 00 00 00 01 65 ... SEI 信息 SPS PPS IDR Slice

而对于 MP4 文件,NAL 单元之前没有同步码,却有若干字节的长度码,来表示 NAL 单元的长度,这个长度 码所占用的字节数由 MP4 文件头给出;此外,从 MP4 读出来的视频帧不包含 PPS 和 SPS,这些信息位于 MP4 的文件头中,解析器必须在打开文件的时候就获取它们。从 MP4 文件读出的一个 H.264 帧往往是下面的形式 (假设长度码为 2 字节):

00 19 06 [... 25 字节...] 24 aa 65 [... 9386 字节...] SEI 信息 IDR Slice

ffmpeg一些转码命令

1.分离视频音频流

ffmpeg -i input_file -vcodec copy -an output_file_video  //分离视频流
ffmpeg -i input_file -acodec copy -vn output_file_audio  //分离音频流

2.视频解复用

ffmpeg –i test.mp4 –vcodec copy –an –f m4v test.264
ffmpeg –i test.avi –vcodec copy –an –f m4v test.264

3.视频转码

ffmpeg –i test.mp4 –vcodec h264 –s 352*278 –an –f m4v test.264              //转码为码流原始文件
ffmpeg –i test.mp4 –vcodec h264 –bf 0 –g 25 –s 352*278 –an –f m4v test.264  //转码为码流原始文件
ffmpeg –i test.avi -vcodec mpeg4 –vtag xvid –qsame test_xvid.avi            //转码为封装文件
//-bf B帧数目控制,-g 关键帧间隔控制,-s 分辨率控制

4.视频封装

ffmpeg –i video_file –i audio_file –vcodec copy –acodec copy output_file

5.视频剪切

ffmpeg –i test.avi –r 1 –f image2 image-%3d.jpeg        //提取图片
ffmpeg -ss 0:1:30 -t 0:0:20 -i input.avi -vcodec copy -acodec copy output.avi    //剪切视频
//-r 提取图像的频率,-ss 开始时间,-t 持续时间

6.视频录制

ffmpeg –i rtsp://192.168.3.205:5555/test –vcodec copy out.avi

7.YUV序列播放

ffplay -f rawvideo -video_size 1920x1080 input.yuv

8.YUV序列转AVI

ffmpeg –s w*h –pix_fmt yuv420p –i input.yuv –vcodec mpeg4 output.avi
几个流媒体视频传输协议

如果要使用QuickTime流媒体服务器的编程接口,您应该熟悉该服务器实现的互联网工程组织(Internet Engineering Task Force,简称IETF)协议,列举如下:

  • 实时流媒体协议(Real Time Streaming Protocol,简称RTSP)
  • 实时传输协议(Real Time Transport Protocol,简称RTP)
  • 实时传输控制协议(Real Time Transport Control Protocol,简称RTCP)
  • 对话描述协议(Session Description Protocol,简称SDP)
用rtmp实现推流

1.用homebrew下载nginx到本地

brew tap homebrew/nginx

2.安装nginx和rtmp模块

brew install nginx-full --with-rtmp-module

3.查看和启动nginx模块

nginx

打开浏览器http://localhost:8080 如果出现welecome说明安装并启动成功

4.配置rtmp并刷新配置
到/usr/local/etc/nginx目录下找到ngxin.conf文件,在末尾加上代码

rtmp {
    server {
        listen 1991;// 端口
        application markLive {// 应用名称
            live on;// 开启实时
            record off;// 不记录数据
        }
    }
}
nginx -s reload

5.安装ffmpeg

brew install ffmpeg

6.利用ffempg推流到nginx

ffmpeg -re -i (视频全路径) -vcodec copy -f flv (rtmp路径

ffmpeg -re -i /Users/maxiao/Desktop/theme.mp4 -vcodec copy -f flv rtmp://localhost:1991/markLive/room
  • -re 按实际帧率发送,否则ffmpeg会按最高效率发送给服务器,而导致服务器无法负载
  • -vcodec 强制使用codec编解码方式,否则ffmpeg会重新编码输入的H.264裸流
  • -i 输入文件
  • -f 强制格式转换

7.使用VLC播放flv流
一张图片

8.利用摄像头进行推流直播

  • 用ffmpeg查看mac下支持的设备,在mac下Video和Audio设备使用的是avfoundation,所以可以使用avfoundation来查看
ffmpeg -f avfoundation -list_devices true -i ""

一张图片

  • 抓取桌面和摄像头进行推流
ffmpeg -f avfoundation -framerate 30 -i "1:0" -f avfoundation -framerate 30 -video_size 640x480 -i "0" -c:v libx264 -preset slow -filter_complex 'overlay=main_w-overlay_w-10:main_h-overlay_h-10' -acodec libmp3lame -ar 44100 -ac 1  -f flv rtmp://localhost:1991/markLive/room

-f avfoundation 转换为avfoundation
-framerate 30 : 设置帧率 30
-i "1:0" : 设置输出,视频:Capture screen 音频:Built-in Microphone
-f avfoundation -framerate 30 -video_size 640x480 : 设置帧率和视频尺寸
-c:v libx264 设置视频编码,H.264编码 优点是同等清晰度,视频文件更小 缺点就是转换慢
-f flv 标准FLV编码 这个好处是速度快 清晰度高的话 视频文件会比较大
-preset slow 使用慢速模式 延迟长 清晰度高
-filter_complex 'overlay=main_w-overlay_w-10:main_h-overlay_h-10':给视频打水印
-acodec libmp3lame 強制指定音频处理模式
-ac 1 声道选择
-ar 44100 音频赫兹

ffmpeg的转码延时测试与设置优化
一张图片

http://dss.macosforge.org/