你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
AVI文件格式动画生成技术(上)
 

随着多媒体技术的飞速发展,多媒体技术广泛应用于信息邻域中,出现了各种各样的多媒体数据文件,AVI文件就是常见的一种。比起Windows其它的资源性数据文件,AVI文件的结构要复杂得多。本文探讨编程实现生成256色压缩和非压缩的AVI动画文件。

一、AVI文件格式分析

AVI文件是Microsoft公司制定的一种RIFF(Resource Interchange File Format)文件格式,主要由各种各样的块(chunk)构成,块包括块头和块体两部分,块头的结构如下:

struct chunkhead   {

  unsigned char type[4];

  unsigned long size;

 }

4个字节标识块的类型,后一个无符号长整型数记载块体的长度;而块体可能是基本数据,也可能是一个具有块头和块体结构的子块。但最底层子块的块体必须是基本数据,称为数据块,而称非底层子块为构造块。数据块的块标识指明数据的性质,例如:

块标识

    数据性质

“avih”

AVI

“strh”

数据流头

“strf”

数据流格式

“00db”

非压缩视频数据

“00dc”

压缩视频数据

“00dx”

压缩视频数据

“01wb”

音频数据

而构造块的标识一律都是“LIST”,故也称为LIST块,为进一步区别其属性,在块体的前面,用4个字节来标识其类型,例如:

标识字节

      类型

“hdrl”

AVI总参数头构造

“strl”

流参数构造

“movi”

流数据构造

整个AVI文件就是一个以“RIFF”为标识的构造块,其构造类型为“AVI ”,它包括两个必备的LIST块和一个可选的索引块。索引块的标识为“idx1”,其作用是在播放时可以随机地访问任一幅画面或任一段声音。第一个LIST块为参数块,其底层块记载视频音频格式参数,分别采用BMPWAV文件的格式规范。限于篇幅,本文只讨论不含音频数据的256AVI动画文件的生成。第一个LIST块的层次结构描述如下:

偏址

       内容

长度

0xc

LIST块头1

  8

0x14

“hdrl”, LIST块标识

  4

0x18

avih块头

  8

0x20

avih块体

0x38

0x58

LIST块头2

  8

0x60

“strl”, LIST块标识

  4

0x64

strh块头

  8

0x6c

strh块体

0x38

0xa4

strf块头

  8

0xac

bmp

0x28

0xd4

调色板数据

 4*n

其中n为实际使用的颜色数(n256),LIST块头2记载块体的长度为116+4*nLIST块头1记载块体的长度为192+4*n。至于avih块体、strh块体、bmp头的结构,请参阅程序。

第二个LIST块为记录块,其底层块记载视频数据,视频数据块的块标识可能是“00db”或“00dc”等等,而视频数据可能是非压缩的或压缩的。第二个LIST块的层次结构描述如下:

         内容

 长度

第二个LIST块块头

   8

“movi”,第二个LIST块标识

   4

第一个视频数据块块头

   8

第一帧视频数据

size1

         

 

N个视频数据块块头

   8

N帧视频数据

sizeN

第二个LIST块块头记载块体的长度为4+8*N+size1+size2+sizeN

    AVI文件中还可以有一种“废块”,标识为“JUNK”,是数据块格式,其作用是便于在文件中随机地增删新旧视频音频记录,而不致于造成AVI文件写操作中定位的困难。本文在生成AVI动画时不考虑JUNK块。

二、RLE8压缩方法

视频数据采用BMP格式,对于非压缩情形,它是以图像的左下角为起点,按照从左至右,由下而上的次序,将图像数据存入文件,256色图像是一个字节记录一点;采用压缩方式处理数据也是按照上述次序,而压缩方法有多种。本文介绍Microsoft Windows的游程编码RLE8(Run Length Encodeing)压缩方法:对数据流中同一数据游程进行压缩,即以两个字节代表一串相同数值的数据,第一个字节表示有多少个相同的数据,第二个字节表示此相同的数据,这两个字节最多能代替255个连续重复出现的数据,如果连续重复出现的数据的个数超过255个,则必须两组或两组以上的压缩码来代表,这就是RLE8的计数方式;对于一串互不相同的数据,则采用识别码,识别码共有4种,其第一个字节必须是0,如下定义:

l    0x00 0x00表示一行图像数据的结束。RLE8压缩法以行为压缩单元,每行数据经压缩后,在末端加入0x00 0x00两个字节。

l    0x00 0x01表示所有图像数据的结束。当所有的行都压缩处理后,就加入0x00 0x01两个字节,作为结束标志。

l    0x00 0x02 X Y 表示向右移X点,向下移Y点。

l    0x00 N…表示有N点不同值的图像数据。如果不同值的图像数据为奇数个,则必须在数据末端加入0x00 ,以维持压缩数据长度为偶数个字节。

例如:有一串原始数据为0x16 0x16 0x16 0x16 0x42 0x36 0x04 ,用RLE8压缩数据为0x04 0x16 0x00 0x03 0x42 0x36 0x04 0x00

注意:当不同点的个数为12时,应视为相同(个数为1)的情形来处理。

三、AVI动画生成

本程序用Turbo C2.0在标准模式下开发而成。在屏幕上显示“AVI Animator!”的动画,然后按照AVI动画的文件格式生成动画文件animator.avi。程序中compression的值为0,则生成256色非压缩的动画文件;compression的值为1,则应用Microsoft WindowsRLE8压缩法压缩生成256色压缩格式的动画文件。生成的动画文件animator. avi可直接在Windows下播放。本程序在Turbo C2.0 Small模式下编译通过。程序代码如下:

#include <stdio.h>

#include <io.h>

#include <math.h>

#include <alloc.h>

#include <stdlib.h>

#include <graphics.h>

 

#define widthbytes(i) ((i+31)/32*4)

 

int frames,colors,linebytes,color,bkcolor;

int left,top,right,bottom,bmpwidth,bmpheight;

unsigned long compression,imagebytes,

             offset,*bmpsize;

 

struct chunkhead

 {

  unsigned char type[4];

  unsigned long size;

 }riff,list,block,subblock;

 

struct aviheader

 {

  unsigned long microsecperframe,

           maxbytespersec,reserved1;

  unsigned long flags,totalframes,

           initialframes,streams;

  unsigned long suggestedbuffersize,width,

           height,reserved[4];

 }avih;

 

struct avistreamheader

 {

  unsigned char type[4];

  unsigned long compression,reserved1,

           reserved2,reserved3;

  unsigned long streams,quality,

           initialframes,totalframes;

  unsigned long suggestedbuffersize,

           samplesize,reserved[2];

  unsigned int width,height;

 }strh;

 

struct bitmapinfo

 {

  unsigned long size,width,height;

  unsigned int plane,bitsperpixel;

  unsigned long compression,imagesize,

           xpels,ypels;

  unsigned long colorused,colorimportant;

 }bmp;

 

struct idxchunk

 {

  unsigned char type[4];

  unsigned long flags,offset,length;

 }idx;

 

void getacolor(int k,int acolor[3])

 {

  int j,color[16]={0,1,2,3,4,5,22,7,56,57,58,

        59,60,61,62,63};

  j=color[k];

  if(j==22) j=20;

  outportb(0x3c7,((unsigned char)j));

  acolor[0]=inportb(0x3c9);

  acolor[1]=inportb(0x3c9);

  acolor[2]=inportb(0x3c9);

 }

 

void getcolortable(int colortable[16][3])

 {

  int i,j;

  int color[16]={0,1,2,3,4,5,22,7,56,57,58,

        59,60,61,62,63};

  for(i=0;i<16;i++)    {

   j=color[i];

   if(i==6) j=20;

   outportb(0x3c7,((unsigned char)j));

   colortable[i][0]=inportb(0x3c9);

   colortable[i][1]=inportb(0x3c9);

   colortable[i][2]=inportb(0x3c9);

  }

 }

 

void createchunkhead(FILE *fp)

 {

  int i,colortable[16][3];

  unsigned char pal[16][4],type[4]="    ";

  linebytes=widthbytes(8*bmpwidth);

  memcpy(riff.type,"RIFF",4);

  riff.size=224L+4*colors+24*frames

   +(unsigned long)linebytes*bmpheight*frames;

  fwrite(&riff,sizeof(riff),1,fp);

  memcpy(type,"AVI ",4);

  fwrite(type,4,1,fp);

  memcpy(list.type,"LIST",4);

  list.size=(unsigned long)192+4*colors;

  fwrite(&list,sizeof(list),1,fp);

  memcpy(type,"hdrl",4);

  fwrite(type,4,1,fp);

  memcpy(block.type,"avih",4);

  block.size=0x38;

  fwrite(&block,sizeof(block),1,fp);

  avih.microsecperframe=0x1046b;

  avih.maxbytespersec=0x640;

  avih.reserved1=0;

  avih.flags=0x810;avih.totalframes=frames;

  avih.initialframes=0;avih.streams=1;

  avih.suggestedbuffersize=(unsigned

      long)linebytes*bmpheight;

  avih.width=bmpwidth;avih.height=bmpheight;

  avih.reserved[0]=0;avih.reserved[1]=0;

  avih.reserved[2]=0;avih.reserved[3]=0;

  fwrite(&avih,sizeof(avih),1,fp);

  memcpy(block.type,"LIST",4);

  block.size=(unsigned long)116+4*colors;

  fwrite(&block,sizeof(block),1,fp);

  memcpy(type,"strl",4);

  fwrite(type,4,1,fp);

  memcpy(subblock.type,"strh",4);

  subblock.size=0x38;

  fwrite(&subblock,sizeof(subblock),1,fp);

  memcpy(strh.type,"vids",4);

  strh.compression=0;strh.reserved1=0;

  strh.reserved2=0;strh.reserved3=0;

  strh.streams=1;strh.quality=15;

  strh.initialframes=0;strh.totalframes=frames;

  strh.suggestedbuffersize=(unsigned       long)linebytes*bmpheight;

  strh.samplesize=0;

  strh.reserved[0]=0;strh.reserved[1]=0;

  strh.width=bmpwidth;strh.height=bmpheight;

  fwrite(&strh,sizeof(strh),1,fp);

  memcpy(subblock.type,"strf",4);

  subblock.size=0x28+4*colors;

  fwrite(&subblock,sizeof(subblock),1,fp);

  bmp.size=0x28;

  bmp.width=bmpwidth;

  bmp.height=bmpheight;

  bmp.plane=1;bmp.bitsperpixel=8;

  bmp.compression=compression;

  bmp.imagesize=(unsigned

      long)linebytes*bmpheight;

  bmp.xpels=0x0ece;bmp.ypels=0xec4;

  bmp.colorused=colors;

  bmp.colorimportant=colors;

  fwrite(&bmp,sizeof(bmp),1,fp);

  getcolortable(colortable);

  for(i=0;i<colors;i++) {

   pal[i][0]=(unsigned char)colortable[i][2]<<2;

   pal[i][1]=(unsigned char)colortable[i][1]<<2;

   pal[i][2]=(unsigned char)colortable[i][0]<<2;

   pal[i][3]=0;

   }

  fwrite(pal,1,4*colors,fp);

  memcpy(list.type,"LIST",4);

  list.size=4L+8*frames+

   (unsigned long)linebytes*bmpheight*frames;

  fwrite(&list,sizeof(list),1,fp);

  memcpy(type,"movi",4);

  fwrite(type,4,1,fp);

 }

  推荐精品文章

·2024年12月目录 
·2024年11月目录 
·2024年10月目录 
·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089