// 提取FLV视频文件中的音频到MP3文件
// FLV2MP3.cpp, visual c++ 6.0
// Usage: FLV2mp3 filename.flv
// 江岳华 2010,5 本程序只说明原理,未注意代码风格
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <conio.h>
#include <string.h>
#pragma comment(lib,"ws2_32")
typedef struct tagTAG
{
UINT prelen;
BYTEtype;//video=0x09,audio=0x08,metadata=0x12
BYTE size24[3];
BYTE ts24[3];
BYTE tshigh;
BYTE sid[3];//0x000000
}
TAG;
typedef struct tagTAG2
{
UINT prelen;
BYTEtype;//video=0x09,audio=0x08,metadata=0x12
UINT size;
UINT ts;
UINT sid;
}
TAG2;
void tag_to_tag2(TAG* a, TAG2* b)
{
if(!a || !b)return;
memset(b,0,sizeof(TAG2));
b->prelen =htonl(a->prelen);
b->type =a->type;
BYTE* p =(BYTE*)(a->size24);
b->size =(p[0]<<16)|(p[1]<<8)|p[2];
p = (BYTE*)(a->ts24);
b->ts =(a->tshigh<<24)|(p[0]<<16)|(p[1]<<8)|p[2];
p = (BYTE*)(a->sid);
b->sid =(p[0]<<16)|(p[1]<<8)|p[2];
}
int main(int argc, char* argv[])
{
if(argc<2)
{
puts("Usage: FLV2mp3filename.flv");
return 0;
}
if(strlen(argv[1])>=256)
{
printf("File name lengtherror!\n");
return 0;
}
FILE* fp = fopen(argv[1],"rb");
if(!fp)
{
printf("Open file %sfailed!\n",argv[1]);
return 0;
}
long flen = filelength(fileno(fp));
if(flen<24)
{
printf("File lengtherror!\n");
fclose(fp);
return 0;
}
fseek(fp,0,0);
unsigned char* buf = new unsignedchar[flen];
if(!buf)
{
printf("Memory overerror!\n");
fclose(fp);
return 0;
}
long pos=0;
while (pos < flen)
{
printf("\r%d",pos);
int ret =fread(buf+pos,1,flen-pos,fp);
if(ret <1)break;
pos += ret;
printf("\r%d",pos);
if(pos >=flen)break;
}
if(pos != flen)
{
printf("Read file lengtherror!\n");
delete[] buf;
fclose(fp);
return 0;
}
puts("\nRead file OK!\n");
unsigned char* h = (unsigned char*)buf;
if(memcmp(h,"FLV",3)!=0)
{
printf("Not flvfile!\n");
delete[] buf;
fclose(fp);
return 0;
}
if(h[3]!=1)
{
printf("Not flv ver1.0!\n");
delete[] buf;
fclose(fp);
return 0;
}
if(h[4] > 0x07)
{
printf("Flv header avbyteerror!\n");
delete[] buf;
fclose(fp);
return 0;
}
if(h[4] & 0x02)
{
printf("Flv header avbyte error2!\n");
delete[] buf;
fclose(fp);
return 0;
}
if(h[4] & 0x04)
puts("has audio.");
if(h[4] & 0x01)
puts("has video.");
UINT offset =(h[5]<<24)|(h[6]<<16)|(h[7]<<8)|h[8];
printf("body offset = %d\n",offset);
if(offset!=9)
puts("warring: body offset !=9!!!\n");
h += offset;
#define WRITE_AUDIO
#ifdef WRITE_AUDIO
FILE *fw = NULL;
char name[512];
memset(name,0,sizeof(name));
strncpy(name,argv[1],strlen(argv[1]));
name[sizeof(name)-5]='\0';
strcat(name,".mp3");
fw = fopen(name,"wb");
#endif
while ((h+15)<(buf+pos))
{
TAG* t = (TAG*)h;
TAG2 t2;
memset(&t2,0,sizeof(TAG2));
tag_to_tag2(t,&t2);
printf("prelen=%08lx,type=%x,size=%08lx,ts=%08lx\n",t2.prelen,t2.type,t2.size,t2.ts);
BYTE *d = h+15;
if(t2.type ==0x08)//audio
{
int len =t2.size-1;
intsoundfmt=(d[0]>>4)&0x0f;
//0= Linear PCM, platform endian
//1= ADPCM Formats 7, 8, 14, and 15are
//2= MP3 reserved for internaluse
//3= Linear PCM, little endian
//4= Nellymoser 16-kHz mono AAC is supported in Flash
//5= Nellymoser 8-kHz mono Player9,0,115,0 and higher.
//6= Nellymoser
//7= G.711 A-law logarithmic PCM Speex is supported in Flash
//8= G.711 mu-law logarithmic PCM Player10 and higher.
//9= reserved
//10= AAC
//11= Speex
//14= MP3 8-Khz
//15= Device-specific sound
intsoundrate=(d[0]>>2)&0x03;
//0= 5.5-kHz For AAC: always 3
//1= 11-kHz
//2= 22-kHz
//3= 44-kHz
intsoundsize=(d[0]>>1)&0x01;
//0= snd8Bit parameter only pertains to
//1= snd16Bit uncompressed formats.
// Compressedformats always
// decodeto 16 bits internally.
// 0= snd8Bit
// 1= snd16Bit
intsoundtype=d[0]&0x01;
//0= sndMono For Nellymoser: always 0
//1= sndStereo For AAC: always 1
printf("soundfmt=%d,soundrate=%d,soundsize=%d,soundtype=%d\n",
soundfmt,soundrate,soundsize,soundtype);
#ifdef WRITE_AUDIO
if(soundfmt==2)//MP3
if(fw)fwrite(d+1,1,len,fw);
#endif
}
else if(t2.type ==0x09)//video
{
}
else if(t2.type ==0x12)//metadata
{
}
//准备下次
h += (15+t2.size);
}
#ifdef WRITE_AUDIO
if(fw)fclose(fw);
fw = NULL;
#endif
delete[] buf;
fclose(fp);
return 0;
}