📄 avitools.cpp
字号:
// AVITools.cpp : implementation file
//
#include "stdafx.h"
#include "AVITools.h"
/////////////////////////////////////////////////////////////////////////////
// CAVITools
/*
构造函数初始化环境以及数据
*/
CAVITools::CAVITools()
{
// 初始化 AVI 库
::AVIFileInit();
m_strAviFileName = _T(""); // AVI 文件名
m_iCurrentFrameCount = 0; // 当前侦
m_iWidth = -1; // 侦宽度(像素)
m_iHeight = -1; // 侦高度(像素)
m_pAviFile = NULL; // PAVIFILE
m_pAviStream = NULL; // PAVISTREAM
m_pCompressedAviStream = NULL; // PCOMPRESSAVISTREAM
m_pBuffer = NULL; // 缓冲区
m_pFormat = NULL; // 格式指针
// 初始化结构变量
memset(&m_AviStreamInfo, 0, sizeof(AVISTREAMINFO));
memset(&m_AviCompressOptions, 0, sizeof(AVICOMPRESSOPTIONS));
}
/*
析构函数清理内存,退出 AVI 库
*/
CAVITools::~CAVITools()
{
CleanUp();
::AVIFileExit();
}
/*
CREATE A AVI FILE ON DISK
ARGUMENTS:
sFileName - THE PATHNAME OF AVI FILE THAT YOU WANT TO CREATE
RETURN VALUE:
ERR_OK - SUCCESS
ERR_FORMAT_NOT_SET - UNKNOWN AVI STREAM FORMAT, SUCH AS PATTLE,WIDTH AND HEIGHT, ETC.
YOU SHOULD CALL 'SetStreamFormatFromFile' OR 'SetStreamFormatFromMemory'
IN ORDER TO SET STREAM FORMAT BEFORE YOU CALL THIS FUNCTION
ERR_AVI_FILE_ERROR - POSSIBLE RESEAN:
1. AVIFileOpen Error
2. AVIFileCreateStream Error
3. AVISaveOptions Error
4. AVIMakeCompressedStream Error
5. AVIStreamSetFormat Error
*/
HRESULT
CAVITools::CreateAviFile(CHAR *sFileName, DWORD dwRate)
{
m_strAviFileName = sFileName;
HRESULT hr;
if (NULL == m_pFormat)
{
m_iLastErrorNumber = ERR_FORMAT_NOT_SET;
m_sLastErrorDescribe.Format("没有设置 AVI 流格式,例如调色板、图象大小等");
return ERR_FORMAT_NOT_SET;
}
m_iWidth = m_pFormat->biWidth;
m_iHeight = m_pFormat->biHeight;
// 创建 AVI 文件
hr = ::AVIFileOpen(&m_pAviFile, m_strAviFileName, OF_CREATE | OF_WRITE, NULL);
if (AVIERR_OK != hr)
// 创建文件失败
{
CleanUp();
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVIFileOpen 函数出错:%ld",hr);
return ERR_AVI_FILE_ERROR;
}
// 初始化流信息结构
m_AviStreamInfo.fccType = streamtypeVIDEO;
m_AviStreamInfo.fccHandler = 0;
m_AviStreamInfo.dwScale = 1;
m_AviStreamInfo.dwRate = dwRate;
m_AviStreamInfo.dwSuggestedBufferSize = m_pFormat->biSizeImage;
::SetRect(&m_AviStreamInfo.rcFrame, 0, 0, (INT)m_pFormat->biWidth, (INT)m_pFormat->biHeight);
// 创建 AVI 视频流
hr = ::AVIFileCreateStream(m_pAviFile,&m_pAviStream,&m_AviStreamInfo);
if (AVIERR_OK != hr)
// 创建视频流失败
{
CleanUp();
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVIFileCreateStream 函数出错:%ld",hr);
return ERR_AVI_FILE_ERROR;
}
// 创建压缩信息
LPAVICOMPRESSOPTIONS FAR m_pFar[1];
m_pFar[0] = &m_AviCompressOptions;
BOOL bResult;
// bResult = ::AVISaveOptions(NULL, ICMF_CHOOSE_KEYFRAME|ICMF_CHOOSE_DATARATE|ICMF_CHOOSE_PREVIEW, 1, &m_pAviStream, m_pFar);
bResult = TRUE;
m_AviCompressOptions.fccType = 0;
m_AviCompressOptions.fccHandler = 1684633187; // 1668707181;
m_AviCompressOptions.dwKeyFrameEvery = 0;
m_AviCompressOptions.dwQuality = 10000; // 8500;
m_AviCompressOptions.dwBytesPerSecond = 0;
m_AviCompressOptions.dwFlags = 8;
m_AviCompressOptions.lpFormat = NULL; // 0x0;
m_AviCompressOptions.cbFormat = 0;
m_AviCompressOptions.lpParms = (VOID *)(4806108); // (VOID *)(0x00509e60);
m_AviCompressOptions.cbParms = 0;//4
m_AviCompressOptions.dwInterleaveEvery = 0;
/*
CString sInfo;
CHAR sBuf[100];
sprintf(sBuf, "fccType = %ld\r\n", m_AviCompressOptions.fccType);
sInfo += sBuf;
sprintf(sBuf, "fccHandler = %ld\r\n", m_AviCompressOptions.fccHandler);
sInfo += sBuf;
sprintf(sBuf, "dwKeyFrameEvery = %ld\r\n", m_AviCompressOptions.dwKeyFrameEvery);
sInfo += sBuf;
sprintf(sBuf, "dwQuality = %ld\r\n", m_AviCompressOptions.dwQuality);
sInfo += sBuf;
sprintf(sBuf, "dwBytesPerSecond = %ld\r\n", m_AviCompressOptions.dwBytesPerSecond);
sInfo += sBuf;
sprintf(sBuf, "dwFlags = %ld\r\n", m_AviCompressOptions.dwFlags);
sInfo += sBuf;
sprintf(sBuf, "lpFormat = %ld\r\n", (DWORD)(m_AviCompressOptions.lpFormat));
sInfo += sBuf;
sprintf(sBuf, "cbFormat = %ld\r\n", m_AviCompressOptions.cbFormat);
sInfo += sBuf;
sprintf(sBuf, "lpParms = %ld\r\n", (DWORD)(m_AviCompressOptions.lpParms));
sInfo += sBuf;
sprintf(sBuf, "cbParms = %ld\r\n", (DWORD)(m_AviCompressOptions.cbParms));
sInfo += sBuf;
sprintf(sBuf, "dwInterleaveEvery = %ld\r\n", (DWORD)(m_AviCompressOptions.dwInterleaveEvery));
sInfo += sBuf;
FILE *fp = fopen("c:\\bxx\\temp.txt", "w");
if (NULL != fp)
{
fprintf(fp, sInfo.GetBuffer(sInfo.GetLength()));
fclose(fp);
}
*/
//AfxMessageBox(sInfo);
// DWORD fccType; /* stream type, for consistency */
// DWORD fccHandler; /* compressor */
// DWORD dwKeyFrameEvery; /* keyframe rate */
// DWORD dwQuality; /* compress quality 0-10,000 */
// DWORD dwBytesPerSecond; /* bytes per second */
// DWORD dwFlags; /* flags... see below */
// LPVOID lpFormat; /* save format */
// DWORD cbFormat;
// LPVOID lpParms; /* compressor options */
// DWORD cbParms;
// DWORD dwInterleaveEvery; /* for non-video streams only */
if (FALSE == bResult)
// 创建压缩信息失败
{
CleanUp();
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVISaveOptions 函数出错");
return ERR_AVI_FILE_ERROR;
}
// 创建压缩的视频流
hr = ::AVIMakeCompressedStream(&m_pCompressedAviStream, m_pAviStream, &m_AviCompressOptions, NULL);
if (AVIERR_OK != hr)
// 创建压缩视频流失败
{
CleanUp();
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVIMakeCompressedStream 函数出错:%ld", hr);
return ERR_AVI_FILE_ERROR;
}
// 设置视频流格式
hr = ::AVIStreamSetFormat(m_pCompressedAviStream, 0, m_pFormat, m_iFormatLength);
if (AVIERR_OK != hr)
// 设置视频流格式错误
{
CleanUp();
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVIStreamSetFormat 函数出错:%ld", hr);
return ERR_AVI_FILE_ERROR;
}
// 创建 AVI 文件正确
return ERR_OK;
}
/*
APPEND A SAMPLE AT THE END OF THE CREATED AVI STREAM FROM A BITMAP FILE
ARGUMENTS:
sBitmapFilePathName - THE PATHNAME OF A BITMAP FILE THAT YOU WANT TO APPEND TO THE STREAM
RETURN VALUE:
ERR_OK - SUCCESS
ERR_CANNOT_OPEN_FILE - CANNOT OPEN THE SPECIFIED FILE
ERR_READ_FILE_ERROR - READ FILE ERROR
ERR_BAD_FORMAT - FILE FORMAT ERROR, SUCH AS NO BITMAP IDENTITY 'BM'
ERR_OUT_OF_MEMORY - OUT OF MEMORY
ERR_IMAGE_SIZE_ERROR - IMAGE SIZE CONFLICT WITH THE PREDEFINE SIZE IN STREAM FORMAT
ERR_AVI_FILE_ERROR - ERROR OCCUR WHEN WRITE DATA TO STREAM
*/
HRESULT
CAVITools::AddFileFrame(CHAR *sBitmapFilePathName)
{
BITMAPFILEHEADER bfh;
long datasize;
HRESULT hr;
CHAR *pBuffer;
// 没有创建的成功压缩流
if (NULL == m_pCompressedAviStream)
{
m_iLastErrorNumber = ERR_AVI_FILE_NOT_CREATE;
m_sLastErrorDescribe.Format("AVI 文件没有创建");
return ERR_AVI_FILE_NOT_CREATE;
}
// 没有指定正确的位图文件名
if (NULL == sBitmapFilePathName)
{
m_iLastErrorNumber = ERR_ARGUMENTS_ERROR;
m_sLastErrorDescribe.Format("参数错误:文件名指针为空");
return ERR_ARGUMENTS_ERROR;
}
// 打开指定的位图文件
FILE *fp = fopen(sBitmapFilePathName, "rb");
if (NULL == fp)
// 无法正确打开文件
{
m_iLastErrorNumber = ERR_CANNOT_OPEN_FILE;
m_sLastErrorDescribe.Format("无法打开文件 %s",sBitmapFilePathName);
return ERR_CANNOT_OPEN_FILE;
}
// 读取文件头
if (1 != fread(&bfh,sizeof(BITMAPFILEHEADER),1,fp))
{
fclose(fp);
m_iLastErrorNumber = ERR_READ_FILE_ERROR;
m_sLastErrorDescribe.Format("读取文件头出错:%s",sBitmapFilePathName);
return ERR_READ_FILE_ERROR;
}
// Validate File Type
if (0x4d42 != bfh.bfType)
{
fclose(fp);
m_iLastErrorNumber = ERR_BAD_FORMAT;
m_sLastErrorDescribe.Format("文件格式错误:文件 %s 的前两个字节不是 'BM'",sBitmapFilePathName);
return ERR_BAD_FORMAT;
}
// Alloc Memory
datasize = bfh.bfSize - sizeof(BITMAPFILEHEADER);
pBuffer = new CHAR[datasize];
if (NULL == pBuffer)
{
fclose(fp);
m_iLastErrorNumber = ERR_OUT_OF_MEMORY;
m_sLastErrorDescribe.Format("内存溢出");
return ERR_OUT_OF_MEMORY;
}
// Read Entire File
if (1 != fread(m_pBuffer,datasize,1,fp))
{
fclose(fp);
delete pBuffer;
m_iLastErrorNumber = ERR_READ_FILE_ERROR;
m_sLastErrorDescribe.Format("读取文件内容出错:%s",sBitmapFilePathName);
return ERR_READ_FILE_ERROR;
}
// Close File
fclose(fp);
BITMAPINFOHEADER *pbih = NULL;
RGBQUAD *pPattle = NULL;
CHAR *pBits = NULL;
// Init Pointer
pbih = (BITMAPINFOHEADER *)pBuffer;
pBits = pBuffer + bfh.bfOffBits - sizeof(BITMAPFILEHEADER);
if (8 == pbih->biBitCount)
{
pPattle = (RGBQUAD *)(m_pBuffer + pbih->biClrUsed * sizeof(RGBQUAD));
}
else if (16 == pbih->biBitCount || 24 == pbih->biBitCount)
{
pPattle = NULL;
}
else
{
delete pBuffer;
m_iLastErrorNumber = ERR_BAD_FORMAT;
m_sLastErrorDescribe.Format("文件格式错误:不支持 %d 位颜色的图象",(INT)pbih->biBitCount);
return ERR_BAD_FORMAT;
}
// Validate Image Size
if (pbih->biWidth != m_iWidth || pbih->biHeight != m_iHeight)
{
delete pBuffer;
m_iLastErrorNumber = ERR_IMAGE_SIZE_ERROR;
m_sLastErrorDescribe.Format("该图象的大小与预定义的大小不匹配");
return ERR_IMAGE_SIZE_ERROR;
}
// Write Compressed Avi Stream
hr = ::AVIStreamWrite(m_pCompressedAviStream,
m_iCurrentFrameCount,
1,
(LPBYTE)pBits,
pbih->biSizeImage,
AVIIF_KEYFRAME,
NULL,
NULL);
if (AVIERR_OK != hr)
{
delete pBuffer;
m_iLastErrorNumber = ERR_IMAGE_SIZE_ERROR;
m_sLastErrorDescribe.Format("AVIStreamWrite 函数出错:%ld",hr);
return ERR_AVI_FILE_ERROR;
}
delete pBuffer;
m_iCurrentFrameCount++;
m_iLastErrorNumber = ERR_OK;
m_sLastErrorDescribe.Empty();
return ERR_OK;
}
/*
从内存中向 AVI 流中增加一侦
输入参数:
pBits - 位图数据内存地址
返回值:
ERR_OK - 执行成功
ERR_AVI_FILE_NOT_CREATE - 文件没有创建
ERR_ARGUMENTS_ERROR - 参数错误
ERR_AVI_FILE_ERROR - 添加时出现错误
*/
HRESULT
CAVITools::AddMemFrame(CHAR *pBits)
{
HRESULT hr;
// 验证压缩流是否可用
if (NULL == m_pCompressedAviStream)
{
m_iLastErrorNumber = ERR_AVI_FILE_NOT_CREATE;
m_sLastErrorDescribe.Format("AVI 文件没有创建");
return ERR_AVI_FILE_NOT_CREATE;
}
// 验证位图数据是否可能可用
if (NULL == pBits)
{
m_iLastErrorNumber = ERR_ARGUMENTS_ERROR;
m_sLastErrorDescribe.Format("参数错误:指针为空");
return ERR_ARGUMENTS_ERROR;
}
// 增加侦
hr = ::AVIStreamWrite(m_pCompressedAviStream,
m_iCurrentFrameCount,
1,
(LPBYTE)pBits,
m_iFrameSize,
AVIIF_KEYFRAME,
NULL,
NULL);
if (AVIERR_OK != hr)
{
m_iLastErrorNumber = ERR_AVI_FILE_ERROR;
m_sLastErrorDescribe.Format("AVIStreamWrite 函数执行失败:%ld",hr);
return ERR_AVI_FILE_ERROR;
}
// 增加侦数量
m_iCurrentFrameCount++;
// 返回成功标志
m_iLastErrorNumber = ERR_OK;
m_sLastErrorDescribe.Empty();
return ERR_OK;
}
/*
释放资源
*/
BOOL
CAVITools::CleanUp()
{
// 释放压缩流
if (NULL != m_pCompressedAviStream)
{
::AVIStreamRelease(m_pCompressedAviStream);
m_pCompressedAviStream = NULL;
}
// 释放 AVI 流
if (NULL != m_pAviStream)
{
::AVIStreamRelease(m_pAviStream);
m_pAviStream = NULL;
}
// 释放文件
if (NULL != m_pAviFile)
{
::AVIFileRelease(m_pAviFile);
m_pAviFile = NULL;
}
// 释放分配的内存
if (NULL != m_pBuffer)
{
delete m_pBuffer;
m_pBuffer = NULL;
}
// 成员数据初始化
m_strAviFileName = _T("");
m_iCurrentFrameCount = 0;
memset(&m_AviStreamInfo, 0, sizeof(AVISTREAMINFO));
memset(&m_AviCompressOptions, 0, sizeof(AVICOMPRESSOPTIONS));
return (TRUE);
}
/*
从位图文件中读取格式,设置流格式
输入参数:
sBmpFile - 用于设置格式的位图文件磁盘位置
返回值:
*/
HRESULT
CAVITools::SetStreamFormatFromFile(CHAR *sBmpFile)
{
INT needlength;
INT pattlelength;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
CHAR *pattlebuf = NULL;
FILE *fp = NULL;
// 如果曾经设置过格式,将其删除
if (NULL != m_pFormat)
{
delete m_pFormat;
m_pFormat = NULL;
}
// 打开文件
if (NULL == (fp = fopen(sBmpFile,"rb")))
{
m_iLastErrorNumber = ERR_CANNOT_OPEN_FILE;
m_sLastErrorDescribe.Format("无法打开文件:%s",sBmpFile);
return ERR_CANNOT_OPEN_FILE;
}
// 读取文件头数据
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -