截取AVI格式的视频C语言代码

首先在阅读本代码之前百度一下avi,虽然经过我验证上面有部分错误,但是不影响阅读。因为有些变量的注释我没有写,所以请读者自行搜索吧。下面是c语言文件,编译之后能够直接运行,用来截取开始时间(单位s)后指定长度(单位s)的视频流。最后附上一部分视频文件的二进制,方便对照阅读。

 

 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#pragma pack(1)
/*
最开始的4个字节是一个四字符码‘RIFF’,表示这是一个RIFF文件;紧跟着后面用4个字节表示此RIFF文件的大小;
然后又是一个四字符码说明文件的具体类型(比如AVI、WAVE等);最后就是实际的数据。注意文件大小值的计算
方法为:实际数据长度 +4(文件类型域的大小);也就是说,文件大小的值不包括‘RIFF’域和“文件大小”域本身
的大小。
*/
typedef struct RIFF
{
	char riff[4];
	unsigned int size;
	char type[4];


}RIFF;
/*
注意listSize值的计算方法为:实际的列表数据长度 +4(listType域的大小);也就是说listSize值不包括‘LIST’域和listSize域本身的大小。
*/
typedef struct list
{
	char fcc[4];
	unsigned int size;
	char type[4];
}LIST;
/*************avih*********************/
typedef struct _avimainheader
{
	char fcc[4];//'avih'
	int size;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
	int dwMicroSecPerFrame;//视频帧间隔时间(以微秒为单位)
	int dwMaxBytesPerSec;// 这个AVI文件的最大数据率
	int dwPaddingGranularity;// 数据填充的粒度
	int dwFlags;// AVI文件的全局标记,比如是否含有索引块等
	int dwTotalFrames; // 总帧数
	int dwInitialFrames; // 为交互格式指定初始帧数(非交互格式应该指定为0)
	int dwStreams;// 本文件包含的流的个数
	int dwSuggestedBufferSize; // 建议读取本文件的缓存大小(应能容纳最大的块)
	int dwWidth;//视频图像的宽(以像素为单位)
	int dwHeight;//视频图像的高(以像素为单位)
	int dwReserved[4]; // 保留
}AVIMAINHEADER;
/********strh*******/
typedef struct
{
	short int left;
	short int top;
	short int right;
	short int bottom;
}RCFRAME;
typedef struct _avistreamheader
{
	char fcc[4];// 必须为‘strh’
	int size;
	char fccType[4];// 流的类型:‘auds’(音频流)、‘vids’(视频流)、
	char fccHandler[4];// 指定流的处理者,对于音视频来说就是解码器
	int  dwFlags;// 标记:是否允许这个流输出?调色板是否变化?
	int wPriority;// 流的优先级(当有多个相同类型的流时优先级最高的为默认流)
	int wLanguage;
	int dwInitialFrames; // 为交互格式指定初始帧数
	int dwScale;// 这个流使用的时间尺度
	int dwRate;
	int dwStart;// 流的开始时间
	int dwLength;// 流的长度(单位与dwScale和dwRate的定义有关)
	int dwQuality;// 流数据的质量指标(0 ~ 10,000)
	int dwSampleSize;// Sample的大小
	RCFRAME rcFrame;// 指定这个流(视频流或文字流)在视频主窗口中的显示位置
}AVISTREAMHEADER;
/**************strf_vids********************/
typedef struct tagBITMAPINFOHEADER
{
	char fcc[4];
	int biSize;
	int biWidth;
	int biHeight;
	short int biPlanes;
	short int biBitCount;
	int biCompression;
	int biSizeImage;
	int biXPelsPerMeter;
	int biYPelsPerMeter;
	int biClrUsed;
	int biClrImportant;
}BITMAPINFOHEADER;
typedef struct tagBITMAPINFO
{
	BITMAPINFOHEADER bmiHeader;
	int  bimColors[1];
}BITMAPINFO;
/***************strf_auds*********************/
//#define WAVEFORMAT __attribute__((packed))
typedef struct
{
	char fcc[4];
	int size;
	short int wFormatTag;
	short int nChannels;
	int nSamplesPerSec;
	int nAvgBytesPerSec;
	short int nBlockAlign;
	short int wBitsPerSample;
	short int biSize;


}WAVEFORMAT;

typedef struct strl_vids
{
	LIST list;
	AVISTREAMHEADER strh;

	BITMAPINFO strf;
}STRL_VIDS;
typedef struct strl_auds
{
	LIST list;
	AVISTREAMHEADER strh;
	WAVEFORMAT strf;

}STRL_AUDS;
typedef struct junk
{

	char fcc[4];
	int size;
}JUNK;
typedef struct HDRL
{
	AVIMAINHEADER avih;
	STRL_VIDS strl_vids;
	STRL_AUDS strl_auds;
	JUNK junk;
}HDRL;
typedef struct movi
{
	char id[4];
	int length;

}MOVI;
typedef struct data
{
	LIST list;
	MOVI chunk;
}DATA;
typedef struct aindex
{
	char dwChunkId[4];
	int dwFlags;
	int dwOffset;
	int dwSize;
}AINDEX;
typedef struct avi_idxl
{
	char fcc[4];
	AINDEX aindex[10];
}AVI_IDXL;
void print_avihead(RIFF riff,LIST list,HDRL hdrl)
{	
	printf("riff.size=%d\n",riff.size);
	printf("list.size=%d\n",list.size);
	printf("hdrl.avih.fcc=%s\n",hdrl.avih.fcc);
	printf("hdrl.avih.dwTotalFrames=%d\n",hdrl.avih.dwTotalFrames);
	printf("hdrl.avih.dwMicroSecPerFrame=%dms\n",hdrl.avih.dwMicroSecPerFrame/1000);
	printf("hdrl.strl_vids.strh.fcc=%s\n",hdrl.strl_vids.strh.fcc);
	printf("hdrl.strl_auds.strh.fcc=%s\n",hdrl.strl_auds.strh.fcc);
	printf("hdrl.junk.fcc=%c\n",hdrl.junk.fcc[3]);
	printf("hdrl.junk.size=%d\n",hdrl.junk.size);
	
}

void get_aviidxl(AVI_IDXL*idxl,char*src_buf,int off_set)
{
	char*p;
	p=src_buf+off_set;
	memcpy(idxl,p,sizeof(AVI_IDXL));
	printf("idxl.fcc:%s\n",idxl->fcc);

}
long get_file_size(const char *path)
{
	unsigned long filesize = -1;
	FILE*fp;
	fp = fopen(path,"r");
	if(fp==NULL)
	{
		return filesize;
	}
	fseek(fp,0,SEEK_END);
	filesize = ftell(fp);
	fclose(fp);
	return filesize;
}
int main(int argc ,char*argv[])
{
	unsigned long size;
	int count=0,i;
	int begin_s=60;//开始时间s
	int t_s=20;//截取间隔s
	int fd_src,fd_dst;
	int off_set;
	char*buf,*readbuf;
	char*src_buf,*tmp;
	
	RIFF riff;
	LIST lhdrl;
	HDRL hdrl;
	LIST lmovi;
	MOVI movi;
	/*******************打开源文件与目的文件*****************************/
	fd_src = open("H264.avi",O_RDONLY);
	fd_dst = open("out.avi",O_CREAT|O_RDWR,0777);
	/************将源文件内容读入缓存区***********************/
	lseek(fd_src,0,SEEK_SET);
	read(fd_src,&riff,sizeof(riff));
	read(fd_src,&lhdrl,sizeof(lhdrl));
	read(fd_src,&hdrl,lhdrl.size+4);
//	print_avihead(riff,lhdrl,hdrl);

	/*********建立JUNK缓存区存储0************/
	buf=malloc(hdrl.junk.size);
	memset(buf,0,hdrl.junk.size);
	/**********将文件头与JUNK区写入目标文件***********/
	lseek(fd_dst,sizeof(riff),SEEK_CUR);
	lseek(fd_dst,sizeof(lhdrl),SEEK_CUR);
	lseek(fd_dst,sizeof(hdrl),SEEK_CUR);
	//write(fd_dst,&riff,sizeof(riff));
	//write(fd_dst,&list,sizeof(list));
	//write(fd_dst,&hdrl,sizeof(hdrl));
	write(fd_dst,buf,hdrl.junk.size);
	free(buf);

	/***********偏移至movi区获取实际数据***************/
	lseek(fd_src,hdrl.junk.size,SEEK_CUR);
	read(fd_src,&lmovi,sizeof(lmovi));
	write(fd_dst,&lmovi,sizeof(lmovi));
	/******写数据*****/
	while(1)//for(i =0 ;i < 20;i++)
	{
		read(fd_src,&movi,sizeof(movi));
		if(movi.length%2!=0)
		{
			movi.length+=1;
		}
		buf = malloc(movi.length);
		read(fd_src,buf,movi.length);
//		 printf("%d\tmovi.id=%s\n",count,movi.id); 
		if(((strncmp(movi.id+2,"db",2)==0)||(strncmp(movi.id+2,"dc",2)==0))&&(count<begin_s*25))//25帧是1秒
		{
			free(buf);
			count++;
		//	printf("%d\tmovi.id=%s\n",count,movi.id); 
		
			continue;
		}
		if(((strncmp(movi.id+2,"pc",2)==0)||(strncmp(movi.id+2,"wb",2)==0))&&((count-1)<begin_s*25))//音频帧不计算在内,时间只用视频帧计算
		{
			free(buf);

			continue;
		}
		if(((strncmp(movi.id+2,"db",2)==0)||(strncmp(movi.id+2,"dc",2)==0))&&(count>=begin_s*25))
		{
			count++;
			 printf("%d\tmovi.id=%s\tmovi.size=%x\n",count,movi.id,movi.length);    
			
		}
		write(fd_dst,&movi,sizeof(movi));
		write(fd_dst,buf,movi.length);
		size=size+movi.length+8; 
		free(buf); 

		if(count>(begin_s+t_s)*25)
		{
			break;
		}
		//free(buf);
		//size=size+movi.length+8;
	}
	
	riff.size=12+12+lhdrl.size+4+hdrl.junk.size+12+size;//计算数据大小,用来填充报头
	hdrl.avih.dwTotalFrames=count;//大小字节
	lseek(fd_dst,0,SEEK_SET);
	write(fd_dst,&riff,sizeof(riff));
	write(fd_dst,&lhdrl,sizeof(lhdrl));
	write(fd_dst,&hdrl,sizeof(hdrl));

//	off_set=off_set+8+data.list.size;
//	get_aviidxl(&idxl,src_buf,off_set);
//	write(fd_dst,src_buf,size);

	close(fd_src);
	close(fd_dst);

}

报头的图片

中间是JUNK的填充

这是一部分数据,都不到一帧,所以最好自己找个avi文件对照的我的代码看。

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值