flv格式

来源:互联网 发布:linux vi 光标移动 编辑:程序博客网 时间:2024/05/04 04:44

本来是应该先写一个媒体文件格式的简单讲解的,还没来得及写,以后再写。今天就先根据ffmpegflv.cflv_demux这个结构体来讲解一下当前比较流行的媒体格式flv.

FLVFLASH VIDEO的简称,FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能.当前主流的媒体网站像国内的优酷、国外youtube其标清格式的文件均采用flv的格式。

FLV文件结构解析

FLV是一个二进制文件,其文件格式如下图,由文件头(FLV header)和很多tag组成。tag又可以分成三类:audio,video,script,分别代表音频流,视频流,脚本流(关键字或者文件信息之类)。


结构如下:

整个的flv文件其实是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。


FLV Header

FLVHeader信息一般比较简单,包括文件类型之类的全局信息。如下图中解析:

文件类型3bytes总是FLV0x46 0x4C 0x56),否则就不是在ffmpeg中在没有指定文件格式的情况下,也是通过这个字段来探测文件是否属于FLV格式的。

版本1byte一般是0x01,表示FLV version 1

流信息1byte倒数第一bit1表示有视频,倒数第三bit1表示有音频,其他都应该是0(有些软件如flvtool2可能造成倒数第四bit1,不过也没发现有什么不对)

header长度4bytes整个文件头的长度,一般是93+1+1+4),当然头部字段也有可能包含其它信息这个时间其长度就不是9了。

FLV Body

FLV body就是由很多tag组成的。

tag header

        一个tag第一部分是tag header,tag header长度为11bytes,但是每个tag header前面有4bytes记录着上一个tag的长度,此待会儿再说。tag header的第1个byte为记录着tag的类型,音频(0x8),视频(0x9),脚本(0x12);第2到4bytes是数据区的长度,也就是tag data的长度;再后面3个bytes是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;时间戳后面一个byte是扩展时间戳,时间戳不够长的时候用;最后3bytes是streamID,但是总为0,再后面就是数据区了(tag data),也即是h264的裸流,tag header 长度为1+3+3+1+3=11。

数据区:根据不同的tag类型就有不同的数据区。

脚本tag

        如果tag data是脚本数据,Script Tag Data,该类型Tag又通常被称为Metadata(元数据) Tag,会放一些关于FLV视频和音频的参数信息,如duration、width、height等。通常该类型Tag会跟在File Header后面作为第一个Tag出现,而且只有一个。一般来说,该Tag Data结构包含两个AMF包。AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。第一个 AMF包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与Adobe的一些API调用有,在此不细述。第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。具体说明如下,大家可以参照图片上的数据进行理解。

第一个AMF包:

 第1个字节表示AMF包类型,一般总是0x02,表示字符串,其他值表示意义请查阅文档。

  第2-3个字节为UI16类型值,表示字符串的长度,一般总是0x000A(“onMetaData”长度)。

  后面字节为字符串数据,一般总为“onMetaData”。

第二个AMF包:

 第1个字节表示AMF包类型,一般总是0x08,表示数组。

  第2-5个字节为UI32类型值,表示数组元素的个数。

  后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下:

   第1-2个字节表示元素名称的长度,假设为L。

     后面跟着为长度为L的字符串。

     第L+3个字节表示元素值的类型。

   后面跟着为对应值,占用字节数取决于值的类型。

脚本tag一般是用文本方式表示,如下图flvmetadata信息:

从中可以看出是通过文本的方式来标记的,其解析后其header信息为:

从中可以看出其type18time stamp0.data size33638.

metadata tag data信息解析后为:

其中有一些媒体信息:

例如视频的:高和宽它的codec id。帧率。音频的信息例如:音频的sample ratecodec id,sample size及是否立体声。还有整个文件的大小等等。

音频的tag信息:

tag data如果是音频数据,第一个字节记录audio信息:

前4bits表示音频格式(全部格式请看官方文档):

·0 -- 未压缩·1 -- ADPCM·2 -- MP3·4 -- Nellymoser 16-kHz mono·5 -- Nellymoser 8-kHz mono·10 -- AAC

下面两个bits表示samplerate:·0 -- 5.5KHz·1 -- 11kHz·2 -- 22kHz·3 -- 44kHz

下面1bit表示采样长度:·0 -- snd8Bit·1 -- snd16Bit

下面1bit表示类型:·0 -- sndMomo·1 -- sndStereo

之后是数据。

视频tag

如果是视频数据,第一个byte记录video信息:

前4bits表示类型:·1-- keyframe·2 -- inner frame·3 -- disposable inner frame (h.263 only)·4 -- generated keyframe

后4bits表示解码器ID:

·2 -- seronson h.263·3 -- screen video·4 -- On2 VP6·5 -- On2 VP6 with alpha channel·6 -- Screen video version 2·7 -- AVC (h.264)

当后面为AVC的时候,后面AVCVIDEOPACKET,格式如下:


 

常用的FLV封装命令

MP4封装为FLV

ffmpeg -vcodec copy -acodec copy -i *.mp4 -f flv test.flv

aac音频和h264视频混流封装FLV
ffmpeg -i <video file> -vcodec copy -i <audio file> -acodec copy test.flv

分析FLV数据


 我们对照flv标准文档来逐个分析
    17:1-keyframe  7-avc
    00:AVC sequence header -- AVC packet type
    00 00 00:composition time,AVC时,全0,无意义
    因为AVC packet type=AVC sequence header,接下来就是AVCDecoderConfigurationRecord的内容


    configurationVersion = 01
    AVCProfileIndication = 42
    profile_compatibility = 00
    AVCLevelIndication = 1f
    lengthSizeMinusOne = ff -- FLV中NALU包长数据所使用的字节数,(lengthSizeMinusOne & 3)+1,实际测试时发现总为ff,计算结果为4,下文还会提到这个数据
    numOfSequenceParameterSets = E1 -- SPS 的个数,numOfSequenceParameterSets & 0x1F,实际测试时发现总为E1,计算结果为1
    sequenceParameterSetLength = 00 31 -- SPS 的长度,2个字节,计算结果49
    sequenceParameterSetNALUnits = 67 42 80 1f 96 54 05 01 ed 80 a8 40 00 00 03 00 40 00 00 07 b8 00 00 20 00 00 03 01 00 01 fc 63 8c 00 00 10 00                     00 03 00 80 00 fe 31 c3 b4 24 4d 40 -- SPS,为刚才计算的49个字节, SPS中包含了视频长、宽的信息
    numOfPictureParameterSets = 01 -- PPS 的个数,实际测试时发现总为E1,计算结果为1
    pictureParameterSetLength = 00 04 -- PPS 的长度
    pictureParameterSetNALUnits = 68 ce 35 20 -- PPS
    接下来又是新的一包videotag数据了(如上图,第二个箭头所示),
    17:1-keyframe  7-avc
    01:AVC NALU
    00 00 00:composition time,AVC时,全0,无意义
    因为AVCPacket type = AVC NALU,接下来就是一个或多个NALU
    每个NALU包前面都有(lengthSizeMinusOne & 3)+1个字节的NAL包长度描述(前文提到的,还记得吗),前面计算结果为4个字节
    00 00 00 02 :2 -- NALU length
    09 10:NAL包,09&0x1f=9,访问单元分隔符,前面我们解析的sps头字节为67,67&0x1f = 7,pps头字节为68,68&0x1f=8,正好能对应上。
    00 00 00 29:说明接下来的NAL包长度为41
    06 00 11 80 00 af c8 00 00 03 00 00 03 00 00 af c8 00 00 03 00 00 40 01 0c 00 00 03 00 00 03 00 90 80 08 00 00 03 00 08 80:06&0x1f=6 -- SEI
    00 00 3c d0:接下来的NAL包长度
    65 88 80……:65&0x1f=5 -- I帧数据
    这包video tag分析到此结束了。

   音频的解析类似,音频头的解析如下:

代码:

ffmpeg默认的flv打包输出aac的音频是44100的采样率、双声道、16位数据格式,但flv格式是可以支持其它参数的,因此需要修改flvenc.c
在get_audio_flags函数中,有这段代码:
if (enc->codec_id == AV_CODEC_ID_AAC) // specs force these parameters
        return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ |
               FLV_SAMPLESSIZE_16BIT | FLV_STEREO;
其所作的工作是一旦确认是aac音频,就强制指定aac的声音参数,如果有其它配置的aac需要打包,就必须屏蔽该段判断和处理,在随后的switch (enc->codec_id)中加入
case AV_CODEC_ID_AAC:
       {
         flags |= FLV_CODECID_AAC | FLV_SAMPLESSIZE_16BIT;
        switch (enc->sample_rate) 
        {
          case 44100:
            flags |= FLV_SAMPLERATE_44100HZ;
                break;
              case 22050:
                flags |= FLV_SAMPLERATE_22050HZ;
                  break;
              case 11025:
                  flags |= FLV_SAMPLERATE_11025HZ;
                  break;
                case 16000: // nellymoser only
                case  8000: // nellymoser only
                case  5512: // not MP3
                  flags |= FLV_SAMPLERATE_SPECIAL;
                  break;
                default:
                  av_log(s, AV_LOG_ERROR,
                      "FLV does not support sample rate %d, "
                      "choose from (44100, 22050, 11025)\n", enc->sample_rate);
                   return AVERROR(EINVAL);
      }
    }
    break;
上面这部分代码,是依据不同类型的声音参数设置声音标志。