简单的jpeg转成avi的类

类别:编程语言 点击:0 评论:0 推荐:

    这是笔者写的一个小的类,用于把一系列jpeg文件转换为avi。
    首先把源码帖出来:

//AviFormat.h

#ifndef _AVI_FORMAT_H_
#define _AVI_FORMAT_H_

#include <iostream>

using namespace std;

/* 4 bytes */
typedef int WORD;
typedef unsigned int DWORD;

/* for use in AVI_avih.flags */
const DWORD AVIF_HASINDEX = 0x00000010; /* index at end of file */
const DWORD AVIF_MUSTUSEINDEX = 0x00000020;
const DWORD AVIF_ISINTERLEAVED = 0x00000100;
const DWORD AVIF_TRUSTCKTYPE = 0x00000800;
const DWORD AVIF_WASCAPTUREFILE = 0x00010000;
const DWORD AVIF_COPYRIGHTED = 0x00020000;

struct AVI_avih
{
 DWORD usec_per_frame;   //* frame display rate (or 0L) */
 DWORD max_bytes_per_sec; //* max. transfer rate */
 DWORD padding;    //* pad to multiples of this size; */
 /* normally 2K */
 DWORD flags;
 DWORD tot_frames;   //* # frames in file */
 DWORD init_frames;
 DWORD streams;
 DWORD buff_sz; 
 DWORD width;
 DWORD height;
 DWORD reserved[4];

 AVI_avih () {}
 AVI_avih (DWORD usec, DWORD max, DWORD pad, DWORD flags, DWORD tot, DWORD init, DWORD str, DWORD buff, DWORD w, DWORD h, DWORD* re = NULL)
  :usec_per_frame (usec), max_bytes_per_sec (max), padding (pad), tot_frames (tot)
  ,init_frames (init), streams (str), buff_sz (buff), width (w), height (h) {
  if (re != NULL)
   for (int i = 0; i < 4; ++i)
    reserved[i] = re[i];
  else
   for (int i = 0; i < 4; ++i)
    reserved[i] = 0;
 }
 AVI_avih (AVI_avih const& avih) {
  usec_per_frame = avih.usec_per_frame;
  max_bytes_per_sec = avih.max_bytes_per_sec;
  padding = avih.padding;    

  flags = avih.flags;
  tot_frames = avih.tot_frames; 
  init_frames = avih.init_frames;
  streams = avih.streams;
  buff_sz = avih.buff_sz; 
  width = avih.width;
  height = avih.height;
  for (int i; i < 4; ++i)
   reserved[i] = avih.reserved[i];
 }
 ~AVI_avih (){}

 friend ostream& operator << (ostream& out, AVI_avih const& avih) {
  out << avih.usec_per_frame << avih.max_bytes_per_sec << avih.padding << avih.flags << avih.tot_frames << avih.init_frames;
  out << avih.streams << avih.buff_sz << avih.width << avih.height;
  out << avih.reserved[0] << avih.reserved[1] << avih.reserved[2] << avih.reserved[3];
  return out;
 }
};

struct AVI_strh
{
 unsigned char type[4];      ///* stream type */
 unsigned char handler[4];
 DWORD flags;
 DWORD priority;
 DWORD init_frames;       ///* initial frames (???) */
 DWORD scale;
 DWORD rate;
 DWORD start;
 DWORD length;
 DWORD buff_sz;           ///* suggested buffer size */
 DWORD quality;
 DWORD sample_sz;

 AVI_strh () {}
 AVI_strh (char const* t, char const* h, DWORD f, DWORD p, DWORD in, DWORD sc, DWORD r, DWORD st, DWORD l, DWORD bs, DWORD q, DWORD ss)
  : flags (f), priority (p), init_frames (in), scale (sc)
  , rate (r), start (st), length (l), buff_sz (bs)
  , quality (q) ,sample_sz (ss) {
  for (int i = 0; i < 4; ++i) {
   type[i] = t[i];
   handler[i] = h[i];
  }
 }
 AVI_strh (AVI_strh const& strh) {
  flags = strh.flags;
  priority = strh.priority;
  init_frames = strh.init_frames;
  scale = strh.scale;
  rate = strh.rate;
  start = strh.start;
  length = strh.length;
  buff_sz = strh.buff_sz;
  quality = strh.quality;
  sample_sz = strh.sample_sz;
  for (int i = 0; i < 4; ++i) {
   type[i] = strh.type[i];
   handler[i] = strh.handler[i];
  }
 }
 ~AVI_strh () {}

 friend ostream& operator << (ostream& out, AVI_strh const& strh) {
  out << strh.type[0] << strh.type[1] << strh.type[2] << strh.type[3];
  out << strh.handler[0] << strh.handler[1] << strh.handler[2] << strh.handler[3];
  out << strh.flags << strh.priority << strh.init_frames << strh.scale << strh.rate;
  out << strh.start << strh.length << strh.buff_sz << strh.quality << strh.sample_sz;
  return out;
 }
};

struct AVI_strf
{      
 DWORD sz;
 DWORD width;
 DWORD height;
 DWORD planes_bit_cnt;
 unsigned char compression[4];
 DWORD image_sz;
 DWORD xpels_meter;
 DWORD ypels_meter;
 DWORD num_colors;        // used colors
 DWORD imp_colors;        // important colors
 /*
  may be more for some codecs
 */
 AVI_strf () {}
 AVI_strf (DWORD s, DWORD w, DWORD h, DWORD p, char const* c, DWORD i, DWORD x, DWORD y, DWORD n, DWORD imp)
  :sz (s), width (w), height (h), planes_bit_cnt (p), image_sz (i)
  ,xpels_meter (x), ypels_meter (y), num_colors (n), imp_colors (imp) {
  for (int i = 0; i < 4; ++i)
   compression[i] = c[i];
 }
 AVI_strf (AVI_strf const& strf) {
  sz = strf.sz;
  width = strf.width;
  height = strf.height;
  planes_bit_cnt = strf.planes_bit_cnt;
  image_sz = strf.image_sz;
  xpels_meter = strf.xpels_meter;
  ypels_meter = strf.ypels_meter;
  num_colors = strf.num_colors;
  imp_colors = strf.imp_colors;
  for (int i = 0; i < 4; ++i)
   compression[i] = strf.compression[i];
 }
 ~AVI_strf () {}

 friend ostream& operator << (ostream& out, AVI_strf const& strf) {
  out << strf.sz << out << strf.width << strf.height << strf.planes_bit_cnt;
  out << strf.compression[0] << strf.compression[1] << strf.compression[2] << strf.compression[3];
  out << strf.image_sz << strf.xpels_meter << strf.ypels_meter << strf.num_colors << strf.imp_colors;
  return out;
 }
};

/*
  AVI_list_hdr
  spc: a very ubiquitous AVI struct, used in list structures
       to specify type and length
*/
struct AVI_list_hdr
{
 unsigned char id[4];   /* "LIST" */
 DWORD sz;              /* size of owning struct minus 8 */
 unsigned char type[4]; /* type of list */

 AVI_list_hdr () {}
 AVI_list_hdr (char const* list, DWORD d, char const* value) {
  sz = d;
  for (int i = 0; i < 4; ++i) {
   id[i] = list[i];
   type[i] = value[i];
  }
 }
 AVI_list_hdr (AVI_list_hdr const& hdr) {
  for (int i = 0; i < 4; ++i) {
   id[i] = hdr.id[i];
   type[i] = hdr.type[i];
  }
  sz = hdr.sz;
 }
 ~AVI_list_hdr () {}

 friend ostream& operator<< (ostream& out, AVI_list_hdr const& hdr) {
  out << hdr.id[0] << hdr.id[1] << hdr.id[3] << hdr.id[4] << hdr.sz << hdr.type[0] << hdr.type[1] << hdr.type[2] << hdr.type[3];
  return out;
 }
};

struct AVI_list_odml
{
 struct AVI_list_hdr list_hdr;

 unsigned char id[4];
 DWORD sz;
 DWORD frames;

 AVI_list_odml () {}
 AVI_list_odml (char const* l1, DWORD d1, char const* v1, char const* l2, DWORD d2, DWORD f)
  :list_hdr (l1, d1, v1), sz (d2), frames (f) {
   for (int i = 0; i < 4; ++i)
    id[i] = l2[i];
 }
 AVI_list_odml (AVI_list_hdr const hdr, char const* v, DWORD d2, DWORD f)
  : list_hdr (hdr), sz (d2), frames (f) {
   for (int i = 0; i < 4; ++i)
    id[i] = v[i];
 }
 AVI_list_odml (AVI_list_odml const& odml)
  :list_hdr (odml.list_hdr), sz (odml.sz), frames (odml.frames) {
   for (int i = 0; i < 4; ++i)
    id[i] = odml.id[i];
 }
 ~AVI_list_odml () {}

 friend ostream& operator << (ostream& out, AVI_list_odml const& odml){
  out << odml.list_hdr << odml.id[0] << odml.id[1] << odml.id[2] << odml.id[3];
  out << odml.sz << odml.frames;
  return out;
 }
};

struct AVI_list_strl
{
 struct AVI_list_hdr list_hdr;
 /* chunk strh */
 unsigned char strh_id[4];
 DWORD strh_sz;
 struct AVI_strh strh;
 /* chunk strf */
 unsigned char strf_id[4];
 DWORD strf_sz;
 struct AVI_strf strf;
 /* list odml */
 struct AVI_list_odml list_odml;
};

struct AVI_list_hdrl
{
 struct AVI_list_hdr list_hdr;
 /* chunk avih */
 unsigned char avih_id[4];
 DWORD avih_sz;
 struct AVI_avih avih;
 /* list strl */
 struct AVI_list_hdr strl_hdr;
 /* chunk strh */
 unsigned char strh_id[4];
 DWORD strh_sz;
 struct AVI_strh strh;
 /* chunk strf */
 unsigned char strf_id[4];
 DWORD strf_sz;
 struct AVI_strf strf;
 /* list odml */
 struct AVI_list_odml list_odml;
 
 AVI_list_hdrl (DWORD width = 0, DWORD height = 0, DWORD jpg_sz = 1, DWORD per_usec = 1, DWORD frames = 1)
  :list_hdr ("LIST", sizeof (struct AVI_list_hdrl) - 8, "hdrl")
  //* chunk avih */
  ,avih_sz (sizeof (struct AVI_avih))
  ,avih (per_usec, 1000000 * (jpg_sz/frames) / per_usec, (0)
   ,AVIF_HASINDEX, frames, 0, 1, 0, width, height)
  // list strl
  ,strl_hdr ("LIST", sizeof (struct AVI_list_strl) - 8, "strl")
  // chunk strh
  ,strh_sz (sizeof (struct AVI_strh))
  ,strh ("vids", "MJPG", 0, 0, 0, per_usec, 1000000
   , 0, frames, 0, 0, 0)
  // chunk strf
  ,strf_sz (sizeof (AVI_strf))
  ,strf (sizeof (struct AVI_strf), width, height, 1 + 24*256*256
   ,"MJPG", width * height * 3, 0, 0, 0, 0)
  // list odml
  ,list_odml ("LIST", 16, "odml", "dmlh", 4, frames) {
  avih_id[0] = 'a'; avih_id[1] = 'v'; avih_id[2] = 'i'; avih_id[3] = 'h';
  strh_id[0] = 's'; strh_id[1] = 't'; strh_id[2] = 'r'; strh_id[3] = 'h';
  strf_id[0] = 's'; strf_id[1] = 't'; strf_id[2] = 'r'; strf_id[3] = 'f';
 }
 ~AVI_list_hdrl (){}

 friend ostream& operator << (ostream& out, AVI_list_hdrl const& hdrl) {
  out << hdrl.list_hdr << hdrl.avih_id[0] << hdrl.avih_id[1] << hdrl.avih_id[2] << hdrl.avih_id[3];
  out << hdrl.avih_sz << hdrl.strl_hdr;
  out << hdrl.strh_id[0] << hdrl.strh_id[1] << hdrl.strh_id[2] << hdrl.strh_id[3];
  out << hdrl.strh_sz << hdrl.strh;
  out << hdrl.strf_id[0] << hdrl.strf_id[1] << hdrl.strf_id[2] << hdrl.strf_id[3];
  out << hdrl.strf_sz << hdrl.strf << hdrl.list_odml;
  return out;
 }
};
#endif //_AVI_FORMAT_H_

 

//AviGenerator.h

#ifndef _AVI_GENERATOR_H_
#define _AVI_GENERATOR_H_
#define DEBUG_VERSION

#include <stdio.h>
#include <string>
#include <vector>
#include "AviFormat.h"

using namespace std;
/* 4 bytes */
typedef int WORD;
typedef unsigned int DWORD;
/* 1 byte */
typedef unsigned char BYTE;

class AviGenerator
{
public:
 AviGenerator(void);
 ~AviGenerator(void);
 
 void set_avi_file (string const& file);
 void set_fps (int fps);
 int add_frame (string const& file);
 void set_avi_size (int w, int h);

 int generate_avi ();
private:
 int file_size (string const& file);
 int files_size ();

 int initalize_header ();

 void print_quartet (FILE* file, DWORD i);
public:
 static DWORD const MAX_RIFF_SZ = 2147483648LL; /*Max avi file size, 2 GB limit*/
 static DWORD const JPEG_DATA_SZ = sizeof(DWORD) * 2;

 struct Jpeg_Data
 {
  DWORD size;
  DWORD offset;
  string name; /* i.e. variable length structure */

  Jpeg_Data () {}
  ~Jpeg_Data () {}

  friend bool operator< (Jpeg_Data const& a, Jpeg_Data const& o) {
   return a.name < o.name;
  }
  static bool lestthan (Jpeg_Data const* a, Jpeg_Data const* o) {
   return a->name < o->name;
  }
 };
protected:
 string avi_name_;
 WORD fps_;
 WORD frames_;
 WORD usec_per_frame;
 //file structure
 AVI_list_hdrl list_hdrl;
 //file list
 vector <Jpeg_Data*> jpeg_list;
 //option
 DWORD width;
 DWORD height;
 DWORD frames;
 unsigned int fps;
 long jpg_sz;
 size_t jpg_sz_64;
 size_t riff_sz_64;
 DWORD riff_sz;
};
#endif


//AviGenerator.cpp

#include "AviGenerator.h"
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <algorithm>
#ifdef _WIN32
 #include <io.h>
 #include <errno.h>
#else
 #include <sys/param.h>
 #include <unistd.h>
#endif
using namespace std;

AviGenerator::AviGenerator(void)
 :fps (15) ,frames (1), jpg_sz (1), width (320), height (240)
{
 usec_per_frame = 1000000 / fps;
}

AviGenerator::~AviGenerator(void)
{
 for (vector<Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {
  Jpeg_Data* p = *iter;
  delete p;
 }
 this->jpeg_list.clear ();
}

void AviGenerator::set_avi_file (string const& file)
{
 this->avi_name_ = file;
}

void AviGenerator::set_fps (int fps)
{
 this->fps_ = fps;
 this->usec_per_frame = 1000000 / fps;
}

void AviGenerator::set_avi_size (int w, int h)
{
 this->width = w;
 this->height = h;
}

int AviGenerator::file_size (string const& file)
{
 int ret;
#ifdef _WIN32
 struct __stat64 result;
    if (-1 == _stat64 (file.c_str (), &result))
  return -1;
 ret = result.st_size;
#else
 struct stat s;
 if (-1 == stat(file.c_str (), &s))
  return -1;
 ret = s.st_size;
#endif
#ifdef DEBUG_VERSION
 cerr << file.c_str () << " size is " << ret << endl;
#endif
 return ret;
}

int AviGenerator::files_size ()
{
 int ret = 0;
 int tmp, it;
 for (vector<Jpeg_Data*>::iterator iter = jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {
  it = (*iter)->size;
  tmp = it != 0?it:file_size ((*iter)->name.c_str ());
  ret += tmp;
  ret += (4 - (tmp % 4)) % 4;
 }
 return ret;
}

int AviGenerator::add_frame (string const& file)
{
 int size = file_size (file);
 if (size <= 0)
  return -1;
 struct Jpeg_Data* jpeg= new Jpeg_Data ();
 jpeg->name = file;
 jpeg->size = size;
 jpeg->offset = 0;
 this->jpeg_list.insert (jpeg_list.begin (), jpeg);
 return 0;
}

void AviGenerator::print_quartet (FILE* file, DWORD i)
{
 for (int j = 0; j < 4; ++j) {
  fputc (i % 0x0100, file);
  i /= 0x100;
 }
}

int AviGenerator::initalize_header ()
{
 frames = this->jpeg_list.size ();
 if (frames <= 0)
  return -1;
 /* getting image, and hence, riff sizes */
 jpg_sz_64 = this->files_size ();
 if (-1 == jpg_sz_64) {
  cerr << "couldn't determine size of images" << endl;
  return -2;
 }
 riff_sz_64 = sizeof (struct AVI_list_hdrl) + 4 + 4 + jpg_sz_64 + 8 * frames + 8 + 8 + 16 * frames;

 if (riff_sz_64 >= MAX_RIFF_SZ) {
  cerr << "RIFF would exceed 2 Gb limit" << endl;
  return -3;
 }
 jpg_sz = (long) jpg_sz_64;
 riff_sz = (DWORD) riff_sz_64;

 //update the struct AVI_list_hdrl
 this->list_hdrl.avih.usec_per_frame = LILEND4(usec_per_frame);
 this->list_hdrl.avih.max_bytes_per_sec = LILEND4((int)1000000 * (jpg_sz / frames) / usec_per_frame);
 this->list_hdrl.avih.flags = LILEND4(AVIF_HASINDEX);
 this->list_hdrl.avih.tot_frames = LILEND4(frames);
 this->list_hdrl.avih.width = LILEND4(width);
 this->list_hdrl.avih.height = LILEND4(height);
 this->list_hdrl.strh.scale = LILEND4(usec_per_frame);
 this->list_hdrl.strh.rate = LILEND4(1000000);
 this->list_hdrl.strh.length = LILEND4(frames);
 this->list_hdrl.strf.width = LILEND4(width);
 this->list_hdrl.strf.height = LILEND4(height);
 this->list_hdrl.strf.image_sz = LILEND4(width * height * 3);
 this->list_hdrl.list_odml.frames = LILEND4(frames);

 return 0;
}

int AviGenerator::generate_avi ()
{
 if (this->initalize_header () != 0)
  return -1;

 //open the file
 FILE* fdest = fopen (this->avi_name_.c_str (), "wb");
 if (NULL == fdest) {
  cerr << "Can't create a new file to write (" << this->avi_name_ << ")!" << endl;
  return -2;
 }
 //fwrite (&list_hdrl.avih.max_bytes_per_sec, 4, 1, fdest);
 long nbr;
 long nbw;
 long tnbw = 0;
 long mfsz;
 long remnant;
 char buff[512];

 //write file header
 fwrite ("RIFF", 4, 1, fdest);
 print_quartet (fdest, riff_sz);
 fwrite ("AVI ", 4, 1, fdest);
 fwrite (&list_hdrl, sizeof (struct AVI_list_hdrl), 1, fdest);

 //sort the list by file name
 sort (this->jpeg_list.begin (), this->jpeg_list.end (), AviGenerator::Jpeg_Data::lestthan);
 // list movi
 size_t offset = 4;
 fwrite ("LIST", 4, 1, fdest);
 print_quartet (fdest, jpg_sz + 8 * frames + 4);
 fwrite ("movi", 4, 1, fdest);
 //write video data
 for (vector <Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {
  #ifdef DEBUG_VERSION
  cout << "dealing with " << (*iter)->name << endl;
  #endif
  fwrite ("00db", 4, 1, fdest);
  mfsz = (*iter)->size;
  remnant = (4 - (mfsz % 4)) % 4;
  print_quartet (fdest, mfsz + remnant);
  (*iter)->size += remnant;
  (*iter)->offset = offset;
  offset += (*iter)->size + 8;

  int fd;
  #ifdef _WIN32
   fd = open ((*iter)->name.c_str (), O_RDONLY | O_BINARY);
  #else
   fd = open ((*iter)->name.c_str (), O_RDONLY);
  #endif
  if (fd < 0) {
   cerr << "couldn't open file (" << (*iter)->name << ")!" << endl;
   fclose (fdest);
   return -3;
  }
  nbw = 0;

  if ((nbr = read (fd, buff, 6)) != 6) {
   cerr << "reading error" << endl;
   fclose (fdest);
   close (fd);
   return -4;
  }
  fwrite (buff, nbr, 1, fdest);
  read (fd, buff, 4);
  fwrite ("AVI1", 4, 1, fdest);
  nbw = 10;
  while ((nbr = read (fd, buff, 512)) > 0){
   #ifdef DEBUG_VERSION
    //cout << "read " << nbr << " bytes from " << (*iter)->name << endl;
   #endif
   fwrite (buff, nbr, 1, fdest);
   nbw += nbr;
  }

  if (remnant > 0) {
   fwrite (buff, remnant, 1, fdest);
   nbw += remnant;
  }
  tnbw += nbw;
  close (fd);
 }
 if (tnbw != jpg_sz) {
  cerr << "error writing images (wrote " << tnbw << " bytes, expected " << jpg_sz << " bytes)" << endl;
  fclose (fdest);
  return -5;
 }

 /* indices */
 fwrite ("idx1", 4, 1, fdest);
 print_quartet (fdest, 16 * frames);
 for (vector <Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {
  fwrite ("00db", 4, 1, fdest);
  print_quartet (fdest, 18);
  print_quartet (fdest, (*iter)->offset);
  print_quartet (fdest, (*iter)->size);
 }
 //this->jpeg_list.clear ();
 fclose (fdest);
 return 0;
}

//main.cpp 测试文件
// tmp.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include <fstream>
#include "AviGenerator.h"
using namespace std;

int main(int argc, char* argv[])
{
 //ofstream fout ("temp.txt", ios::out);
 //fout.close ();
 AviGenerator generator;
 for (int i = 1; i <= 38; ++i) {
  char c[32];
  sprintf (c, "mao%02d", i);//加入jpeg文件,我有mao01~38.jpg文件
  strcat (c, ".jpg");
  cout << c << endl;
  generator.add_frame (c);
 }
 cout << "generating avi file......" << endl;
 if (argc >=2)
  generator.set_avi_file (argv[1]);
 else
  generator.set_avi_file ("mao.avi");
 generator.set_fps (15);
 generator.set_avi_size (230, 100);
 generator.generate_avi ();

 //system ("pause");
 return 0;
}

    Makefile文件就不作了,只有两个.cpp文件,对于大家编译应该没有什么问题吧。

    笔者在原有的基础上把原来的C代码改写成了一个类,便于使用(如果不喜欢完全可以去找“原版”的C代码),并加入了Win32平台的支持(其实对于笔者来说没什么用——笔者的程序是在Linux下运行的)。

    笔者在VC2003、VC2005 beta1编译,以及用g++、c++都是没有问题的,生成的avi文件用media player正常播放,但是因为没有进行压缩,所以个头有点大(有空我会考虑进行改进的^_^),但是比个别程序的生成方式还是有优势的。存储和传输的时候大家可以用winrar压缩(作个免费广告,压缩率大得惊人)。
    另外,重载了<<,没用上,因为笔者对标准库不熟悉,没有找到可以写入二进制的办法,所以回到了调用c函数的路上。如果你有办法可以告诉笔者吗?
    不断学习中……,欢迎email交流。
[email protected]

本文地址:http://com.8s8s.com/it/it27028.htm