jpeg序列转avi

#ifndef AVI_H
#define AVI_H

//#include <unistd.h>

#include <string.h>
#include <stdio.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

	void bzero(void *s, int n);

	typedef unsigned char u8;
	typedef unsigned short u16;
	typedef unsigned u32;



	// function prototypes

	__declspec(dllexport) void __stdcall avi_start(FILE * fp/*, int frame*/);
	__declspec(dllexport) void __stdcall avi_add(FILE * fp, u8 *buf, int size);
	__declspec(dllexport) void __stdcall avi_end(FILE * fp, int width, int height, int fps);
	void fprint_quartet(FILE * fp, unsigned int i);

	// the following structures are ordered as they appear in a typical AVI

	struct riff_head {
		char riff[4];               // chunk type = "RIFF"
		u32 size;                   // chunk size
		char avistr[4];             // avi magic = "AVI "
	};

	// the avih chunk contains a number of list chunks

	struct avi_head {
		char avih[4];               // chunk type = "avih"
		u32 size;                   // chunk size
		u32 time;                   // microsec per frame == 1e6 / fps
		u32 maxbytespersec;         // = 1e6*(total size/frames)/per_usec)
		u32 pad;                    // pad = 0
		u32 flags;                  // e.g. AVIF_HASINDEX
		u32 nframes;                // total number of frames
		u32 initialframes;          // = 0
		u32 numstreams;             // = 1 for now (later = 2 because of audio)
		u32 suggested_bufsize;      // = 0 (no suggestion)
		u32 width;                  // width
		u32 height;                 // height
		u32 reserved[4];            // reserved for future use = 0
	};


	// the LIST chunk contains a number (==#numstreams) of stream chunks

	struct list_head {
		char list[4];               // chunk type = "LIST"
		u32 size;
		char type[4];
	};


	struct dmlh_head {
		char dmlh[4];               // chunk type dmlh
		u32 size;                   // 4
		u32 nframes;                // number of frames
	};


	struct stream_head {
		char strh[4];               // chunk type = "strh"
		u32 size;                   // chunk size
		char vids[4];               // stream type = "vids"
		char codec[4];              // codec name (for us, = "MJPG")
		u32 flags;                  // contains AVIT_F* flags
		u16 priority;               // = 0
		u16 language;               // = 0
		u32 initialframes;          // = 0
		u32 scale;                  // = usec per frame
		u32 rate;                   // 1e6
		u32 start;                  // = 0
		u32 length;                 // number of frames
		u32 suggested_bufsize;      // = 0
		u32 quality;                // = 0 ?
		u32 samplesize;             // = 0 ?
	};


	struct db_head {
		char db[4];                 // "00db"
		u32 size;
	};

	// a frame chunk contains one JPEG image

	struct frame_head {
		char strf[4];               // chunk type = "strf"
		u32 size;                   // sizeof chunk (big endian)    ?
		u32 size2;                  // sizeof chunk (little endian) ?
		u32 width;
		u32 height;
		u16 planes;                 // 1 bitplane
		u16 bitcount;               // 24 bpl
		char codec[4];              // MJPG (for us)
		u32 unpackedsize;           // = 3*w*h
		u32 r1;                     // reserved
		u32 r2;                     // reserved
		u32 clr_used;               // reserved
		u32 clr_important;          // reserved
	};

	struct idx1_head {
		char idx1[4];               // chunk type = "idx1"
		u32 size;                   // chunk size
	};

#ifdef __cplusplus
}
#endif

#endif


直接上代码

#include "stdafx.h"
#include "avi.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <vector>
using namespace std;

// header flags

const u32 AVIF_HASINDEX = 0x00000010;    /* index at end of file */
const u32 AVIF_MUSTUSEINDEX=0x00000020;
const u32 AVIF_ISINTERLEAVED=0x00000100;
const u32 AVIF_TRUSTCKTYPE=0x00000800;
const u32 AVIF_WASCAPTUREFILE=0x00010000;
const u32 AVIF_COPYRIGHTED=0x00020000;

int nframes;
int totalsize;
unsigned int* sizes;
vector<unsigned int>jpegSize;

void bzero(void *s, int n)
{
	memset(s,0,n);
}


void fprint_quartet(FILE * fp, unsigned int i)
{
	char data[4];
	int rt = 0;

	data[0] = (char) i%0x100;
	i /= 0x100;
	data[1] = (char) i%0x100;
	i /= 0x100;
	data[2] = (char) i%0x100;
	i /= 0x100;
	data[3] = (char) i%0x100;

	/*write( fd, &data, 4 );*/
	rt = fwrite(&data, 4, 1, fp);
	if(rt != 1)
	{
		printf(" fprintf_quartet failed!\n ");
	}
}

// start writing an AVI file

void __stdcall avi_start(FILE * fp/*, int frames*/)
{
	int ofs = sizeof(struct riff_head)+
		sizeof(struct list_head)+
		sizeof(struct avi_head)+
		sizeof(struct list_head)+
		sizeof(struct stream_head)+
		sizeof(struct frame_head)+
		sizeof(struct list_head)+
		sizeof(struct dmlh_head)+
		sizeof(struct list_head);

//	printf( "avi_start: frames = %d\n", frames );
	printf( "avi_start: ofs = %d\n", ofs );

	/* lseek(fd, ofs, SEEK_SET);*/
	fseek(fp,ofs, SEEK_SET);

	nframes = 0;
	totalsize = 0;

	//sizes = (unsigned int*) calloc( frames, sizeof(unsigned int) );   // hold size of each frame
	jpegSize.clear();
}

// add a jpeg frame to an AVI file
void __stdcall avi_add(FILE * fp, u8 *buf, int size)
{
	struct db_head db = {{'0','0','d','b'}, 0};

	printf( "avi_add: nframes = %d, totalsize = %d, size = %d\n", nframes, totalsize, size );

	db.size = size;

	/*write( fd, &db, sizeof(db) );*/
	fwrite( &db, sizeof(db),1, fp);

	/*write( fd, buf, size );*/
	fwrite( buf, size,1, fp);

	//sizes[nframes] = size;
	jpegSize.push_back(size);

	nframes++;
	totalsize += size;  // total frame size
}

// finish writing the AVI file - filling in the header
void __stdcall avi_end(FILE * fp, int width, int height, int fps)
{
	struct idx1_head idx = {{'i','d','x','1'}, 16*nframes };

	struct db_head db = {{'0','0','d','b'}, 0};

	//AVI 是空格还是0
	struct riff_head rh = { {'R','I','F','F'}, 0, {'A','V','I',' '}};
	struct list_head lh1 = {{'L','I','S','T'}, 0, {'h','d','r','l'}};

	struct avi_head ah;
	struct list_head lh2 = {{'L','I','S','T'}, 0, {'s','t','r','l'}};

	struct stream_head sh;
	struct frame_head fh;
	struct list_head lh3 = {{'L','I','S','T'}, 0, {'o','d','m','l'} };

	struct dmlh_head dh = {{'d','m','l','h'}, 4, nframes };
	struct list_head lh4 = {{'L','I','S','T'}, 0, {'m','o','v','i'}};
	int i;
	unsigned int offset = 4;

	printf( "avi_end: nframes = %d, fps = %d/n", nframes, fps );

	// write index

	/*write(fd, &idx, sizeof(idx));*/
	fwrite(&idx, sizeof(idx), 1, fp);

	for ( i = 0; i < nframes; i++ )
	{
		//write(fd, &db, 4 ); // only need the 00db
		fwrite(&db, 4, 1, fp);
		fprint_quartet( fp, 18 );       // 
		fprint_quartet( fp, offset );
		//fprint_quartet( fp, sizes[i] );
		fprint_quartet(fp,jpegSize[i]);

		//offset += sizes[i] + 8; //+8 (for the additional header)
		offset += jpegSize[i] + 8; //+8 (for the additional header)
	}

	//free( sizes );
	jpegSize.clear();

	bzero( &ah, sizeof(ah) );
	strcpy(ah.avih, "avih");
	ah.time = 1000000 / fps;
	ah.maxbytespersec = 1000000.0*(totalsize/nframes)/ah.time;
	ah.nframes = nframes;
	ah.numstreams = 1;
	ah.flags = AVIF_HASINDEX;
	ah.width = width;
	ah.height = height;

	bzero(&sh, sizeof(sh));
	strcpy(sh.strh, "strh");
	strcpy(sh.vids, "vids");
	strcpy(sh.codec, "MJPG");
	sh.scale = ah.time;
	sh.rate = 1000000;
	sh.length = nframes;

	bzero(&fh, sizeof(fh));
	strcpy(fh.strf, "strf");
	fh.width = width;
	fh.height = height;
	fh.planes = 1;
	fh.bitcount = 24;
	strcpy(fh.codec,"MJPG");
	fh.unpackedsize = 3*width*height;

	rh.size = sizeof(lh1)+sizeof(ah)+sizeof(lh2)+sizeof(sh)+
		sizeof(fh)+sizeof(lh3)+sizeof(dh)+sizeof(lh4)+
		nframes*sizeof(struct db_head)+
		totalsize + sizeof(struct idx1_head)+ (16*nframes) +4; // FIXME:16 bytes per nframe // the '4' - what for???

	lh1.size = 4+sizeof(ah)+sizeof(lh2)+sizeof(sh)+sizeof(fh)+sizeof(lh3)+sizeof(dh);
	ah.size = sizeof(ah)-8;
	lh2.size = 4+sizeof(sh)+sizeof(fh)+sizeof(lh3)+sizeof(dh);     //4+sizeof(sh)+sizeof(fh);
	sh.size = sizeof(sh)-8;
	fh.size = sizeof(fh)-8;
	fh.size2 = fh.size;
	lh3.size = 4+sizeof(dh);
	lh4.size = 4+ nframes*sizeof(struct db_head)+ totalsize;

	fseek(fp,0, SEEK_SET);

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

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

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

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

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

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

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

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

	fwrite(&lh4, sizeof(lh4), 1, fp);
}


调用例子:

// testJpegToAvi.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "windows.h"
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

#include "../JpegToAvi/Avi.h"

bool ReadJpeg(const std::string JpegPath,unsigned char *pJpegBuff,unsigned int &JpegLen)
{

	if (pJpegBuff==NULL)
	{
		return false;
	}

	FILE *fp = NULL;
	errno_t err;
	if ((err = fopen_s(&fp, JpegPath.c_str(), "rb")) != 0) {
		printf("open file for write error\n");
		if (fp!=NULL)
		{
			fclose(fp);
			fp=NULL;
		}

		return false;
	}

	fseek(fp, 0, SEEK_END);
	unsigned int len = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	fread(pJpegBuff,len,1,fp);
	JpegLen=len;

	if (fp!=NULL)
	{
		fclose(fp);
		fp=NULL;
	}

	return true;
	
}

static bool CmpFileName(const string& a, const string& b)
{
	return a.length() == b.length() ? a < b : a.length() < b.length();
}

//
//枚举Jpeg图片
void EnumerateImageFile( string imgPath, vector<string>& fileNames, bool bRecursive = false )
{
	fileNames.clear();

	WIN32_FIND_DATA		findData;

	string path = imgPath;
	if ( path[path.length()-1] != '\\' )
		path += "\\";
	path += "*.*";

	HANDLE  hFirstFile = ::FindFirstFile( path.c_str(), &findData );
	if( hFirstFile != INVALID_HANDLE_VALUE )
	{
		do
		{
			if( (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 )
			{
				if( bRecursive && strcmp( findData.cFileName, "." ) != 0 &&
					strcmp( findData.cFileName, ".." ) != 0 )
					EnumerateImageFile( (imgPath+"\\"+findData.cFileName).c_str(), fileNames, bRecursive );
			}
			else
			{
				string fileName( findData.cFileName );
				int pos = fileName.find_last_of( '.' );
				if( pos != -1 )
				{
					string ext = fileName.substr(pos+1, fileName.length()-pos);
					/// 寻找jpeg文件
					if( ext == "jpg" || ext == "JPG" || ext == "jpeg" || ext == "JPEG")
					{
						fileNames.push_back( imgPath  + findData.cFileName );
					}
				}
			}

		}while( FindNextFile( hFirstFile, &findData ) );

		::FindClose( hFirstFile );
	}

	std::sort(fileNames.begin(), fileNames.end(), CmpFileName);
}


//
int _tmain(int argc, _TCHAR* argv[])
{
	vector<string>	m_vecFilePic;	//jpeg目录
	int	m_nFilePicID=0;				//jpeg图片序列第几帧
	std::string imgPath="../jpeg/";

	EnumerateImageFile(imgPath, m_vecFilePic);

	
	FILE *Fp = NULL;
	errno_t err;
	if ((err = fopen_s(&Fp, "../jpeg/1.avi", "wb")) != 0) {
		printf("open file for write error\n");
		if (Fp!=NULL)
		{
			fclose(Fp);
			Fp=NULL;
		}

		return -1;
	}


	avi_start(Fp);

	unsigned char *pBuff=new unsigned char [1024*1024];
	memset(pBuff,0,1024*1024);
	unsigned int len=0;

	for(unsigned int i=0;i<m_vecFilePic.size();i++)
	{
		//
		ReadJpeg(m_vecFilePic[i].c_str(),pBuff,len);

		avi_add(Fp,pBuff,len);
	}

	   avi_end(Fp,1920,1080,25);

	if (Fp!=NULL)
	{
		fclose(Fp);
		Fp=NULL;
	}


	return 0;
}


 

你可能感兴趣的:(jpeg序列转avi)