FLV是一个二进制文件,由文件头(FLV header)和很多tag组成。
tag又可以分成三类:audio,video,script,分别代表音频流,视频流,脚本流。
FLV Header
文件类型3bytes 总是FLV(0x46 0x4C 0x56)
版本1byte
流信息1byte
header长度4bytes (一般是9)
FLV Body
FLV body就是由很多tag组成的,
一个tag包括下列信息:
previoustagsize 4bytes 前一个tag的长度,第一个tag就是0
tag类型1byte
三类:
* 8 -- 音频tag
* 9 -- 视频tag
* 18 -- 脚本tag
数据区长度3bytes 时间戳3bytes 单位毫秒
扩展时间戳1byte 作为时间戳的高位
streamsID 3bytes 一般是0
数据区 大小为之前获取的数据区大小
音频(视频)数据区的第一个字节包含音频(视频)的编码格式信息
audio信息1byte
前四位bits表示音频格式:
* 0 -- 未压缩
* 1 -- ADPCM
* 2 -- MP3
* 5 -- Nellymoser 8kHz momo
* 6 -- Nellymoser
*10 -- HE-AAC
下面两位bits表示samplerate:
* 0 -- 5.5kHz
* 1 -- 11kHz
* 2 -- 22kHz
* 3 -- 44kHz
下面一位bit表示每个采样的长度:
* 0 -- snd8Bit
* 1 -- snd16Bit
下面一位bit表示类型:
* 0 -- sndMomo
* 1 -- sndStereo
video信息1byte
前四位bits表示类型:
* 1 -- keyframe
* 2 -- inner frame
* 3 -- disposable inner frame (H.263 only)
后四位bits表示编码器:
* 2 -- Seronson H.263
* 3 -- Screen video
* 4 -- On2 VP6
* 5 -- On2 VP6 without channel
* 6 -- Screen video version 2
* 7 -- H.264
video数据区
格式还是挺简单的,知道后可以自己进行剪切,合并操作
代码:
#include <CSTDIO>
#include <CSTDLIB>
#include <CSTRING>
#include <STRING>
#include <IOSTREAM>
using namespace std;
#define HTON16(x) ((x>>8&0xff)|(x<<8&0xff00))
#define HTON24(x) ((x>>16&0xff)|(x<<16&0xff0000)|x&0xff00)
#define HTON32(x) ((x>>24&0xff)|(x>>8&0xff00)|\
(x<<8&0xff0000)|(x<<24&0xff000000))
#define STR(x) (x.c_str())
#define FCUR(x) (ftell(x))
#define FSEEK(x,f) (fseek(f,x,SEEK_CUR))
#define FSET(x,f) (fseek(f,x,SEEK_SET))
#define LOG(x,f) (fprintf(f,STR(x)))
FILE *ffile=NULL;
FILE *flog=NULL;
int audionum=0;
int videonum=0;
int lasttime=0;
unsigned int size;
bool Init();
void Clear();
bool Read8(int &i8,FILE*f);
bool Read16(int &i16,FILE*f);
bool Read24(int &i24,FILE*f);
bool Read32(int &i32,FILE*f);
bool ReadTime(int &itime,FILE*f);
bool Peek8(int &i8,FILE*f);
bool ReadHead();
void ReadBody();
string GetAudioInfo(int info);
string GetVideoInfo(int info);
char filename[256]={0};
char logfilename[256]={0};
bool hasname=false;
int main(int argc,char**argv)
{
if (argc>1)
{
sprintf(filename,"%s",argv[1]);
sprintf(logfilename,"%sinfo.txt",argv[1]);
hasname=true;
}
if(!Init())
{
cout<<"Init Err"<<endl;
return -1;
}
if(!ReadHead())
{
cout<<"ReadHead Err"<<endl;
return -1;
}
ReadBody();
printf("time:%.4f s Audio num:%d Video num:%d\n",lasttime*1.0/1000,audionum,videonum);
fprintf(flog,"time:%.4f s Audio num:%d Video num:%d\n",lasttime*1.0/1000,audionum,videonum);
cout<<"read over"<<endl;
void Clear();
return 0;
}
bool Init()
{
if (!hasname)
{
printf("Please input filename:\n");
scanf(" %s",filename);
sprintf(logfilename,"%slog.txt",filename);
}
ffile=fopen(filename,"rb");
flog=fopen(logfilename,"wb");
if(ffile==NULL||flog==NULL)
{
return false;
}
fseek(ffile,0,SEEK_END);
size=FCUR(ffile);
fseek(ffile,0,SEEK_SET);
return true;
}
void Clear()
{
fclose(ffile);
fclose(flog);
}
bool Read8(int &i8,FILE*f)
{
if(fread(&i8,1,1,f)!=1)
return false;
return true;
}
bool Read16(int &i16,FILE*f)
{
if(fread(&i16,2,1,f)!=1)
return false;
i16=HTON16(i16);
return true;
}
bool Read24(int &i24,FILE*f)
{
if(fread(&i24,3,1,f)!=1)
return false;
i24=HTON24(i24);
return true;
}
bool Read32(int &i32,FILE*f)
{
if(fread(&i32,4,1,f)!=1)
return false;
i32=HTON32(i32);
return true;
}
bool Peek8(int &i8,FILE*f)
{
if(fread(&i8,1,1,f)!=1)
return false;
fseek(f,-1,SEEK_CUR);
return true;
}
bool ReadTime(int &itime,FILE*f)
{
int temp=0;
if(fread(&temp,4,1,f)!=1)
return false;
itime=HTON24(temp);
itime|=(temp&0xff000000);
return true;
}
bool ReadHead()
{
int headlength=0;
int filetype=0;
if(!Read24(filetype,ffile))
return false;
int typel='flv';
int typeh='FLV';
if (filetype!=typeh&&filetype!=typel)
{
printf("not flv file\n");
return false;
}
FSEEK(2,ffile);
if (!Read32(headlength,ffile))
return false;
printf("headlength:%d\n",headlength);
/跳过头部长度/
fseek(ffile,0,SEEK_SET);
FSEEK(headlength,ffile);
return true;
}
void ReadBody()
{
while(true)
{
string temp="";
char m_tt[200]={0};
sprintf(m_tt,"fseek:%d ",FCUR(,ffile));
temp+=m_tt;
FSEEK(4,ffile);
int type=0;
int time=0;
int htime=0;
int datelength=0;
int info=0;
char buff[256]={0};
if (!Read8(type,ffile))
break;
if (!Read24(datelength,ffile))
break;
if(!ReadTime(time,ffile))
break;
/*
if (!Read24(time))
break;
//时间高位///
if (!Read8(htime))
break;
*/
跳过StreamID/
FSEEK(3,ffile);
if(!Peek8(info,ffile))
break;
lasttime=time;
switch(type)
{
case 8:
audionum++;
sprintf(buff,"Type:Audio time:%d length:%d ",time,datelength);
temp+=buff;
temp+=GetAudioInfo(info);
break;
case 9:
videonum++;
sprintf(buff,"Type:Video time:%d length:%d ",time,datelength);
temp+=buff;
temp+=GetVideoInfo(info);
break;
case 18:
sprintf(buff,"Type:script length:%d ",datelength);
temp+=buff;
break;
default:
sprintf(buff,"UnKnowType:%hd length:%d ",type,datelength);
temp+=buff;
}
temp+="\n";
LOG(temp,flog);
FSEEK(datelength,ffile);
}
}
string GetAudioInfo(int info)
{
string temp="";
char buff[100]={0};
int temptype=0;
temptype=info>>4&0xf;
switch (temptype)
{
case 0:
temp="0-未压缩 ";
break;
case 1:
temp="1-ADPCM ";
break;
case 2:
temp="2-MP3 ";
break;
case 5:
temp="5-Nellymoser 8kHz momo ";
break;
case 6:
temp="6-Nellymoser ";
break;
case 10:
temp="10-HE-AAC ";
break;
default:
sprintf(buff,"UnKnow:%hd ",temptype);
temp=buff;
}
temptype=0;
temptype=info>>2&0x3;
switch (temptype)
{
case 0:
temp+="0-5.5kHz ";
break;
case 1:
temp+="1-11kHz ";
break;
case 2:
temp+="2-22kHz ";
break;
case 3:
temp+="3-44kHz ";
break;
}
temptype=0;
temptype=info>>1&0x1;
switch (temptype)
{
case 0:
temp+="0-8Bit ";
break;
case 1:
temp+="1-16Bit ";
break;
}
temptype=0;
temptype=info&0x1;
switch (temptype)
{
case 0:
temp+="0-Momo ";
break;
case 1:
temp+="1-Stereo ";
break;
}
return temp;
}
string GetVideoInfo(int info)
{
string temp="";
char buff[100]={0};
int temptype=0;
temptype=info>>4&0xf;
switch (temptype)
{
case 1:
temp="1-keyframe ";
break;
case 2:
temp="2-inner frame ";
break;
case 3:
temp="3-disposable inner frame (H.263 only) ";
break;
default:
sprintf(buff,"UnKnow:%hd ",temptype);
temp=buff;
}
memset(buff,0,100);
temptype=0;
temptype=info&0xf;
switch (temptype)
{
case 2:
temp+="2-Seronson H.263 ";
break;
case 3:
temp+="3-Screen video ";
break;
case 4:
temp+="4-On2 VP6 ";
break;
case 5:
temp+="5-On2 VP6 without channel ";
break;
case 6:
temp+="6-Screen video version 2 ";
break;
case 7:
temp+="7-H.264 ";
break;
default:
sprintf(buff,"UnKnow:%hd ",temptype);
temp+=buff;
}
return temp;
}
效果:
![flv文件解析 - 幻想少佳 - 我的博客](http://img1.ph.126.net/oyF601pp4_aRDpS3-08FRQ==/632474272686654181.jpg)