截取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文件對照的我的代碼看。
————————————————
版權聲明:本文為CSDN博主「天曉-workspace」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_38697824/article/details/85341049
總結
以上是生活随笔為你收集整理的截取AVI格式的视频C语言代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《码出高效 Java开发手册》书籍源码及
- 下一篇: 其实没事做,写写博客也不错的