项目的代码位于https://github.com/oyz/flvmerge
该项目的源码数量较少,一些控制流程的函数不做分析,只将比较重要的内容进行分析。
判断是否可以被合并函数
int IsSuitableToMerge(FLVContext *flvCtx1, FLVContext *flvCtx2)
{
return (flvCtx1->soundFormat == flvCtx2->soundFormat) &&
(flvCtx1->soundRate == flvCtx2->soundRate) &&
(flvCtx1->soundSize == flvCtx2->soundSize) &&
(flvCtx1->soundType == flvCtx2->soundType) &&
(flvCtx1->videoCodecID == flvCtx2->videoCodecID);
}
该项目中,视频的编码格式需要保持相同,应该是FLV1和FLV2的编码其均为H264,如果一个是H264一个不是H264合并会导致失败,声音格式,声音比特率,音频编码类型等。
没有规定一定需要保持相同的视频分辨率等。经过我测试,不同分辨率FLV的合并可以成功。
//添加文件内容
int AddFileData(
FILE* inputFile,//输入文件
FILE* mergeFile, //合并文件
int isFirstFile, //是否为第一个文件
UInt32* lastTimestamp)//最后的时间戳
{
int readLen;
UInt32 curTimestamp = 0;
UInt32 newTimestamp = 0;
int dataSize;
UInt8 tmp[20];
char *buf;
assert(inputFile != NULL && mergeFile != NULL);
if (NULL == (buf=(char*)malloc(sizeof(char)*MAX_DATA_SIZE)))
{
fprintf(stderr, "malloc error!\n");
return -1;
}
if (inputFile != NULL && mergeFile != NULL)
{
//fseek(stream, 0L, SEEK_SET);流移指针指向文件头
rewind(inputFile);
//如果是第一个文件
if (isFirstFile)
{
//读取flv 头长度+4长度
if ( FLV_HEADER_SIZE+4 == (readLen=fread(tmp, sizeof(UInt8), FLV_HEADER_SIZE+4, inputFile)) )
{
rewind(mergeFile);
if (readLen != fwrite(tmp, sizeof(char),readLen, mergeFile))
{
goto failed;
}
}
else
{
goto failed;
}
}
else
{
if (fseek(inputFile, FLV_HEADER_SIZE+4, SEEK_CUR) != 0)
goto failed;
}
//读取FLV TAG
while (ReadFromFile(inputFile, (char*)tmp, FLV_TAG_HEADER_SIZE) > 0)
{
//读取数据长度
dataSize = FromInt24StringBe(&tmp[1]);
//获得当前时间戳
curTimestamp = GetTimestamp(&tmp[4]);
//获得新的时间戳
newTimestamp = curTimestamp + *lastTimestamp;
//设置新的时间戳
SetTimestamp(&tmp[4], newTimestamp);
//写入TAG
if (WriteToFile(mergeFile, (char*)tmp, FLV_TAG_HEADER_SIZE) < 0)
goto failed;
readLen = dataSize+4;
if (ReadFromFile(inputFile, buf, readLen) > 0)
{
if (WriteToFile(mergeFile, buf, readLen) < 0)
goto failed;
}
else
{
goto failed;
}
}
// update the timestamp and return
*lastTimestamp = newTimestamp;
free(buf);
buf = NULL;
return 0;
}
failed:
free(buf);
buf = NULL;
return -1;
}
这段代码中用于将需要合并的FLV文件的TAG提取出来,接着上一个文件的TAG重新计算时间戳。
我在使用的时候将IsSuitableToMerge代码注释掉了
该项目的源码数量较少,一些控制流程的函数不做分析,只将比较重要的内容进行分析。
判断是否可以被合并函数
int IsSuitableToMerge(FLVContext *flvCtx1, FLVContext *flvCtx2)
{
return (flvCtx1->soundFormat == flvCtx2->soundFormat) &&
(flvCtx1->soundRate == flvCtx2->soundRate) &&
(flvCtx1->soundSize == flvCtx2->soundSize) &&
(flvCtx1->soundType == flvCtx2->soundType) &&
(flvCtx1->videoCodecID == flvCtx2->videoCodecID);
}
该项目中,视频的编码格式需要保持相同,应该是FLV1和FLV2的编码其均为H264,如果一个是H264一个不是H264合并会导致失败,声音格式,声音比特率,音频编码类型等。
没有规定一定需要保持相同的视频分辨率等。经过我测试,不同分辨率FLV的合并可以成功。
//添加文件内容
int AddFileData(
FILE* inputFile,//输入文件
FILE* mergeFile, //合并文件
int isFirstFile, //是否为第一个文件
UInt32* lastTimestamp)//最后的时间戳
{
int readLen;
UInt32 curTimestamp = 0;
UInt32 newTimestamp = 0;
int dataSize;
UInt8 tmp[20];
char *buf;
assert(inputFile != NULL && mergeFile != NULL);
if (NULL == (buf=(char*)malloc(sizeof(char)*MAX_DATA_SIZE)))
{
fprintf(stderr, "malloc error!\n");
return -1;
}
if (inputFile != NULL && mergeFile != NULL)
{
//fseek(stream, 0L, SEEK_SET);流移指针指向文件头
rewind(inputFile);
//如果是第一个文件
if (isFirstFile)
{
//读取flv 头长度+4长度
if ( FLV_HEADER_SIZE+4 == (readLen=fread(tmp, sizeof(UInt8), FLV_HEADER_SIZE+4, inputFile)) )
{
rewind(mergeFile);
if (readLen != fwrite(tmp, sizeof(char),readLen, mergeFile))
{
goto failed;
}
}
else
{
goto failed;
}
}
else
{
if (fseek(inputFile, FLV_HEADER_SIZE+4, SEEK_CUR) != 0)
goto failed;
}
//读取FLV TAG
while (ReadFromFile(inputFile, (char*)tmp, FLV_TAG_HEADER_SIZE) > 0)
{
//读取数据长度
dataSize = FromInt24StringBe(&tmp[1]);
//获得当前时间戳
curTimestamp = GetTimestamp(&tmp[4]);
//获得新的时间戳
newTimestamp = curTimestamp + *lastTimestamp;
//设置新的时间戳
SetTimestamp(&tmp[4], newTimestamp);
//写入TAG
if (WriteToFile(mergeFile, (char*)tmp, FLV_TAG_HEADER_SIZE) < 0)
goto failed;
readLen = dataSize+4;
if (ReadFromFile(inputFile, buf, readLen) > 0)
{
if (WriteToFile(mergeFile, buf, readLen) < 0)
goto failed;
}
else
{
goto failed;
}
}
// update the timestamp and return
*lastTimestamp = newTimestamp;
free(buf);
buf = NULL;
return 0;
}
failed:
free(buf);
buf = NULL;
return -1;
}
这段代码中用于将需要合并的FLV文件的TAG提取出来,接着上一个文件的TAG重新计算时间戳。
我在使用的时候将IsSuitableToMerge代码注释掉了