截取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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值