跟着雷神学音视频编解码
1,flv文件结构
2,注意
1),结构体的定义:注意这两个结构体一定要是unsigned char的,之前定义成char的,换成int的时候,会出问题。
typedef struct tag_flvHeader
{
unsigned char pchSignature[3];
unsigned char chVersion;
unsigned char chFlag;
uint32_t ui32DataOffset;
}FlvHeader;
typedef struct tag_TagHeader
{
unsigned char chTag;
unsigned char chDataSize[3];
unsigned char chTimestamp[3];
uint32_t Reserved;
}TagHeader;
//reverse_bytes - turn a BigEndian byte array into a LittleEndian integer
int reverse_bytes(unsigned char * p, char c) {
int r = 0;
int i;
for (i = 0; i < c; i++)
r |= (*(p + i) << (((c - 1) * 8) - 8 * i));
return r;
}
3,代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdint>
//Important!
#pragma pack(1)
#define TAG_TYPE_SCRIPT 18
#define TAG_TYPE_AUDIO 8
#define TAG_TYPE_VIDEO 9
typedef struct tag_flvHeader
{
unsigned char pchSignature[3];
unsigned char chVersion;
unsigned char chFlag;
uint32_t ui32DataOffset;
}FlvHeader;
typedef struct tag_TagHeader
{
unsigned char chTag;
unsigned char chDataSize[3];
unsigned char chTimestamp[3];
uint32_t Reserved;
}TagHeader;
//reverse_bytes - turn a BigEndian byte array into a LittleEndian integer
int reverse_bytes(unsigned char * p, char c) {
int r = 0;
int i;
for (i = 0; i < c; i++)
r |= (*(p + i) << (((c - 1) * 8) - 8 * i));
return r;
}
int flv_parser(char* url)
{
FILE* hInFile = fopen(url, "rb+");
FILE* hOutFileFlv = NULL;
FILE* hOutFileMp3 = NULL;
if (hInFile == NULL)
return -1;
FlvHeader flvHeader;
fread(&flvHeader, 1, sizeof(FlvHeader), hInFile);
TagHeader tagHeader;
fseek(hInFile, reverse_bytes((unsigned char*)&flvHeader.ui32DataOffset, sizeof(flvHeader.ui32DataOffset)), SEEK_SET);
while (!feof(hInFile))
{
uint32_t ui32PreviousTagSize = _getw(hInFile);
int size1 = sizeof(TagHeader);
fread((void*)&tagHeader, sizeof(TagHeader), 1, hInFile);
if (feof(hInFile))
break;
switch (tagHeader.chTag)
{
case TAG_TYPE_AUDIO:
{
char tagdata_first_byte;
tagdata_first_byte = fgetc(hInFile);
if (hOutFileMp3 == NULL)
hOutFileMp3 = fopen("myMp3.mp3", "wb");
uint32_t iTagDataSize = reverse_bytes((unsigned char*)&tagHeader.chDataSize, sizeof(tagHeader.chDataSize))-1;
for (int i = 0; i < iTagDataSize; i++)
{
fputc(fgetc(hInFile), hOutFileMp3);
}
}
break;
case TAG_TYPE_VIDEO:
{
if (hOutFileFlv == NULL)
{
hOutFileFlv = fopen("myFlv.flv", "wb");
fwrite(&flvHeader, 1, sizeof(FlvHeader), hOutFileFlv);
fwrite(&ui32PreviousTagSize, 1, 4, hOutFileFlv);
}
fwrite((char*)&tagHeader, 1, sizeof(tagHeader), hOutFileFlv);
int data_size = reverse_bytes((unsigned char*)&tagHeader.chDataSize, sizeof(tagHeader.chDataSize)) + 4;
for (int j = 0; j <data_size; j++)
{
fputc(fgetc(hInFile), hOutFileFlv);
}
fseek(hInFile, -4, SEEK_CUR);
}
break;
default:
{
//skip the data of this tag
fseek(hInFile, reverse_bytes((unsigned char*)&tagHeader.chDataSize, sizeof(tagHeader.chDataSize)), SEEK_CUR);
}
break;
}
}
return 1;
}