从flv格式中分离出裸h264

自己测试可以用,原文链接http://blog.163.com/zhujiatc@126/blog/static/18346382013413112230525/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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 *flvfile = NULL;
FILE *h264file = NULL;

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();


char flvfilename[256] = { 0 };
char h264filename[256] = { 0 };
bool hasname = false;
int main(int argc, char**argv)
{
	strncpy(flvfilename, "savename.flv", sizeof(flvfilename));
	strncpy(h264filename, "savename.h264", sizeof(h264filename));
	hasname = true;

	if (!Init())
	{
		cout << "Init Err" << endl;
		return -1;
	}
	if (!ReadHead())
	{
		cout << "ReadHead Err" << endl;
		return -1;
	}
	ReadBody();
	cout << "read over" << endl;
	Clear();
	return 0;
}
bool Init()
{
	flvfile = fopen(flvfilename, "rb");
	h264file = fopen(h264filename, "wb");
	if (flvfile == NULL || h264file == NULL)
	{
		return false;
	}
	fseek(flvfile, 0, SEEK_END);
	size = FCUR(flvfile);
	fseek(flvfile, 0, SEEK_SET);
	return true;
}
void Clear()
{
	fclose(flvfile);
	fclose(h264file);
}


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, flvfile))
		return false;
	int typel = 'flv';
	int typeh = 'FLV';
	if (filetype != typeh&&filetype != typel)
	{
		printf("not flv file\n");
		return false;
	}
	FSEEK(2, flvfile);
	if (!Read32(headlength, flvfile))
		return false;
	printf("headlength:%d\n", headlength);
	/跳过头部长度/
	fseek(flvfile, 0, SEEK_SET);
	FSEEK(headlength, flvfile);
	return true;
}

void H264JIEXI(int datelength);
void ReadBody()
{

	while (true)
	{
		FSEEK(4, flvfile);
		int type = 0;
		int time = 0;
		int htime = 0;
		int datelength = 0;
		int info = 0;

		char buff[256] = { 0 };
		if (!Read8(type, flvfile))
			break;
		if (!Read24(datelength, flvfile))
			break;
		if (!ReadTime(time, flvfile))
			break;
		跳过StreamID/
		FSEEK(3, flvfile);
		if (!Peek8(info, flvfile))
			break;

		int pos = FCUR(flvfile);
		if (type == 9)
			H264JIEXI(datelength);
		FSET(pos + datelength, flvfile);
	}
}

int h264space = 0x01000000;//H264内容间隔标识00000001

void H264JIEXI(int datelength)//关键
{
	int info = 0;
	Read8(info, flvfile);
	int avctype = 0;
	Read8(avctype, flvfile);
	FSEEK(3, flvfile);
	int templength = 0;
	char*tempbuff = NULL;
	if (avctype == 0)
	{
		FSEEK(6, flvfile);

		Read16(templength, flvfile);
		printf("sssize:%d\n", templength);

		tempbuff = (char*)malloc(templength);
		fread(tempbuff, 1, templength, flvfile);
		fwrite(&h264space, 1, 4, h264file);
		fwrite(tempbuff, 1, templength, h264file);
		free(tempbuff);

		Read8(templength, flvfile);//ppsnum

		Read16(templength, flvfile);//ppssize
		printf("ppsize:%d\n", templength);

		tempbuff = (char*)malloc(templength);
		fread(tempbuff, 1, templength, flvfile);
		fwrite(&h264space, 1, 4, h264file);
		fwrite(tempbuff, 1, templength, h264file);
		free(tempbuff);
	}
	else
	{
		//	Read32(templength,flvfile);
		//	tempbuff=(char*)malloc(templength);
		//	fread(tempbuff,1,templength,flvfile);
		//	fwrite(&h264space,1,4,h264file);
		//	fwrite(tempbuff,1,templength,h264file);
		//	free(tempbuff);
		//可能存在多个nal,需全部读取
		int countsize = 2 + 3;
		while (countsize<datelength)
		{
			Read32(templength, flvfile);
			tempbuff = (char*)malloc(templength);
			fread(tempbuff, 1, templength, flvfile);
			fwrite(&h264space, 1, 4, h264file);
			fwrite(tempbuff, 1, templength, h264file);
			free(tempbuff);
			countsize += (templength + 4);
		}
	}
}



  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封装H.264/H.265裸流FLV格式,需要进行以下几个步骤: 1. 准备好H.264/H.265裸流数据,注意需要满足FLV的封装规范。FLV格式将视频数据和音频数据分别封装在不同的Tag内。 2. 构造FLV文件头,设置FLV的版本号、是否包含音频/视频、数据偏移量等参数。 3. 构造音频Tag和视频Tag。对于视频Tag,需要设置帧类型(关键帧或非关键帧)、编码ID、时间戳、数据大小等参数;对于音频Tag,需要设置声道数、采样率、采样精度、编码ID、时间戳、数据大小等参数。 4. 将FLV文件头和音视频Tag写入到输出流,即可生成一个FLV格式的媒体文件。 下面是一个Java NIO实现的示例代码: ```java import java.io.File; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FlvPackager { private static final int FLV_HEADER_SIZE = 9; private static final int TAG_HEADER_SIZE = 11; private FileChannel outChannel; private ByteBuffer buffer; private long timestampBase; public FlvPackager(String filename) throws Exception { File file = new File(filename); if (file.exists()) { file.delete(); } this.outChannel = new FileOutputStream(file).getChannel(); this.buffer = ByteBuffer.allocate(1024 * 1024); this.timestampBase = System.currentTimeMillis(); writeFlvHeader(); } public void writeVideoTag(byte[] data, boolean keyframe) throws Exception { int dataSize = data.length; long timestamp = System.currentTimeMillis() - timestampBase; buffer.clear(); buffer.put((byte) 0x09); buffer.putInt(dataSize + TAG_HEADER_SIZE); buffer.putInt((int) timestamp & 0xFFFFFF); buffer.put((byte) ((timestamp >> 24) & 0xFF)); buffer.putInt(0); buffer.put((byte) (keyframe ? 0x10 : 0x17)); buffer.put(data); buffer.flip(); outChannel.write(buffer); } public void writeAudioTag(byte[] data) throws Exception { int dataSize = data.length; long timestamp = System.currentTimeMillis() - timestampBase; buffer.clear(); buffer.put((byte) 0x08); buffer.putInt(dataSize + TAG_HEADER_SIZE); buffer.putInt((int) timestamp & 0xFFFFFF); buffer.put((byte) ((timestamp >> 24) & 0xFF)); buffer.putInt(0); buffer.put((byte) 0xAF); buffer.put(data); buffer.flip(); outChannel.write(buffer); } public void close() throws Exception { outChannel.close(); } private void writeFlvHeader() throws Exception { buffer.clear(); buffer.put((byte) 'F'); buffer.put((byte) 'L'); buffer.put((byte) 'V'); buffer.put((byte) 0x01); buffer.put((byte) 0x05); buffer.putInt(FLV_HEADER_SIZE); buffer.putInt(0); buffer.flip(); outChannel.write(buffer); } } ``` 使用示例: ```java FlvPackager packager = new FlvPackager("test.flv"); byte[] videoData = ...; // H.264/H.265裸流 byte[] audioData = ...; // AAC裸流 packager.writeVideoTag(videoData, true); // 关键帧 packager.writeAudioTag(audioData); ... packager.close(); ``` 以上代码仅提供了一个FLV封装的基本框架,具体的实现要根据业务需求进行相应的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值