关于 AVI 的一些代码
#ifndef __HSS_AUTO_REVISE_AVI_FRAMERATE_HSS__ #define __HSS_AUTO_REVISE_AVI_FRAMERATE_HSS__ /**************************************************************************************************\ * 2012-05-31 关于avi的一些功能。 (1) 由于丢帧等问题,导致录像长度不对,根据录像时间和帧数,修正avi文件中的帧率信息 auto_avi::ReviseAviFrameRate(sec, frame, file); auto_avi::ReviseAviFrameRate_ms(millsec, frame, file); \**************************************************************************************************/ #include <auto_file.h> #include <__time.h> class auto_avi { public: auto_avi() { }; ~auto_avi() { } public: /**************************************************************************************************\ * static void : * ReviseAviFrameRate : 修正avi录像的长度(修改文件头里面的信息,把帧率修改为实际的帧率) * DWORD nSeconds : 录像长度 * DWORD nFrame : 总帧数 * LPCTSTR pszFile : \**************************************************************************************************/ static void ReviseAviFrameRate(DWORD nSeconds, DWORD nFrame, LPCTSTR pszFile) { auto_file f; if (!f.Open(pszFile, GENERIC_WRITE, FILE_SHARE_READ, OPEN_EXISTING, 0)) return; SetFilePointer(f.m_hFile, 0x80, 0, FILE_BEGIN); DWORD scale = 1000; DWORD rate = nFrame * 1000 / nSeconds; f.OverWrite((LPBYTE)&scale, 4); f.OverWrite((LPBYTE)&rate, 4); } /**************************************************************************************************\ * static void : * ReviseAviFrameRate_ms : 指定毫秒的版本 * DWORD nMilliSeconds : 录像长度毫秒 * DWORD nFrame : 帧率 * LPCTSTR pszFile : 录像文件 \**************************************************************************************************/ static void ReviseAviFrameRate_ms(DWORD nMilliSeconds, DWORD nFrame, LPCTSTR pszFile) { auto_file f; if (!f.Open(pszFile, GENERIC_READ | GENERIC_WRITE, 0, OPEN_EXISTING, 0)) { return; } if (nFrame == 0) { SetFilePointer(f.m_hFile, 0x8c, 0, FILE_BEGIN); if (!f.Read((LPBYTE)&nFrame, 4)) return; } SetFilePointer(f.m_hFile, 0x80, 0, FILE_BEGIN); DWORD scale = 1000; ULONGLONG a = nFrame; a *= 1000000; a /= nMilliSeconds; DWORD rate = (DWORD)a; f.OverWrite((LPBYTE)&scale, 4); f.OverWrite((LPBYTE)&rate, 4); } }; #endif
#ifndef __HSS_AUTO_AVI_HSS__ #define __HSS_AUTO_AVI_HSS__ #include <StringN.h> #include <HBuffer.H> class auto_avi_icc { public: auto_avi_icc() { __memzero(m_Com); __memzero(param): __memzero(strhdr); m_pFile = 0; tStartTime = 0; psz = 0; } ~auto_avi_icc() { } struct { BITMAPINFOHEADER bmi; BITMAPINFOHEADER bmo; }param; private: BOOL InitCompress() { //利用代码选择压缩器 __memzero(m_Com); m_Com.cbSize = sizeof(m_Com); m_Com.dwFlags = ICMF_COMPVARS_VALID; m_Com.fccType = ICTYPE_VIDEO; m_Com.lFrame = 0; m_Com.lKey = 3; //关键帧 m_Com.lKeyCount = 3; m_Com.lDataRate = 780; m_Com.lpbiOut = (BITMAPINFO*)&m_OutInfo; //压缩MPG4格式 //m_Com.hic = ICOpen(ICTYPE_VIDEO, mmioFOURCC('M', 'P', '4', '2'), ICMODE_COMPRESS); //压缩DIVX //m_Com.hic = ICOpen(ICTYPE_VIDEO, mmioFOURCC('D', 'I', 'V', 'X'), ICMODE_COMPRESS); //压缩H264 m_Com.hic = ICOpen(ICTYPE_VIDEO, mmioFOURCC('X', '2', '6', '4'), ICMODE_COMPRESS); m_Com.cbState = 1180; //ICCompressorChoose(NULL,ICMF_CHOOSE_ALLCOMPRESSORS ,(LPVOID)&m_InInfo,NULL,&m_Com,"选择压缩类型"); ICCompressGetFormat(m_Com.hic, (LPBITMAPINFO)¶m.bmi, (LPBITMAPINFO)¶m.bmo); int ret = ICCompressBegin(m_Com.hic, (LPBITMAPINFO)¶m.bmi, (LPBITMAPINFO)¶m.bmo); if(ret != ICERR_OK ) { //MessageBox(NULL, "视频压缩器无法启动!", "系统提示", MB_ICONSTOP); return FALSE; } return TRUE; } BOOL CreateAviFile(LPCTSTR pszFileName, LPBITMAPINFOHEADER pbi, LPBITMAPINFOHEADER pbo) { param.bmi = *pbi; param.bmo = *pbo; m_IndexFrame = 0 ; //AVI文件初始化 AVIFileInit(); //设置压缩参数 if(!InitCompress()) { AVIFileExit(); return FALSE; } //打开文件 m_pFile = NULL; HRESULT hr = ::AVIFileOpen(&m_pFile, pszFileName, OF_WRITE|OF_CREATE, NULL); if(hr != 0) { AVIFileExit(); //MessageBox(NULL, "无法创建视频文件!", "系统提示", MB_ICONSTOP); return 0; } memset(&strhdr, 0, sizeof(strhdr)) ; strhdr.fccType = streamtypeVIDEO;// stream type strhdr.fccHandler = 0; strhdr.dwScale = 1; strhdr.dwRate = iLuxFrameRate; // 25 fps //int WIDTH = (m_InInfo.bmiHeader.biWidth * m_InInfo.bmiHeader.biBitCount + 31) / 32 * 4; //strhdr.dwSuggestedBufferSize = WIDTH * m_InInfo.bmiHeader.biHeight; strhdr.dwSuggestedBufferSize = m_InInfo.bmiHeader.biWidth * m_InInfo.bmiHeader.biHeight * 3; SetRect(&strhdr.rcFrame, 0, 0, m_InInfo.bmiHeader.biWidth, m_InInfo.bmiHeader.biHeight); hr = AVIFileCreateStream(m_pFile, &ps, &strhdr); if (hr != AVIERR_OK) { AVIFileExit(); //MessageBox(NULL, "无法创建视频文件!", "系统提示", MB_ICONSTOP); return 0; } tStartTime = GetTickCount(); return true; } void CloseAviFile() { //结束数据压缩 if (m_Com.hic) { ICCompressEnd(m_Com.hic); //关闭压缩句柄 ICClose(m_Com.hic); if(ps) AVIStreamClose(ps); if(m_pFile) AVIFileClose(m_pFile); AVIFileExit(); } } BOOL AddFrame(LPBITMAPINFOHEADER pbih, LPBYTE pBits) { char* buffer = new char [NWIDTH * NHEIGHT * 3 + 1]; memset(buffer, 0, NWIDTH * NHEIGHT * 3 + 1); DWORD dwCkID = 0; DWORD dwCompFlags = 0; DWORD dwQuality = 100; iLuxFrameRate = 25; DWORD m_RealFrame = ((GetTickCount() - tStartTime) * iLuxFrameRate + 500) / 1000; long cj = m_RealFrame - m_IndexFrame; for(long i = 0; i < cj + 1; i ++) { //视频压缩 memset(buffer, 0, NWIDTH * NHEIGHT * 3 + 1); if(ICCompress(m_Com.hic, 0, &m_OutInfo.bmiHeader, buffer, &m_InInfo.bmiHeader, (unsigned char *)pBuffer, &dwCkID, &dwCompFlags, m_IndexFrame ++, 0, dwQuality, NULL, NULL) == ICERR_OK) { AVIStreamSetFormat(ps, m_IndexFrame, &m_OutInfo.bmiHeader, sizeof(m_OutInfo.bmiHeader)); VERIFY(0 == AVIStreamWrite(ps, //stream pointer m_IndexFrame , //time of this frame 1, //number to write (LPBYTE) buffer, //pBuffer, m_OutInfo.bmiHeader.biSizeImage, //size of this frame AVIIF_KEYFRAME, // flags.... NULL, NULL)); OutputDebugString("."); } else { VERIFY(0); } } delete []buffer; } private: COMPVARS m_Com; PAVIFILE m_pFile; //AVI文件 AVISTREAMINFO strhdr; //AVI流信息 PAVISTREAM ps; //AVI流指针 DWORD tStartTime; HBuffer m_BufFrame; }; #endif
#ifndef __HSS_AVI_STREAM_HSS__ #define __HSS_AVI_STREAM_HSS__ /**************************************************************************************************\ * 2013-09-08 新的监控录像类,自动持续录像,改变录像大小,叠加文字等,但是没有图像缓冲区 auto_avi_stream avi; avi.SetConfigFile avi.Open(... avi.AddFrame avi.Close( \**************************************************************************************************/ #include <auto_x264.h> #include <rjpeg.h> #include <auto_IplImage.h> #include <HBuffer.h> #include <timemath.h> #include <overtext.h> #include <StringN.h> #define FCCX264 (*(DWORD*)"X264") class auto_avi_stream { public: struct { }param; struct { char szFileName[_MAX_PATH]; DWORD fccHandler; RJPEG_OPEN Param; BITMAPINFOHEADER bih; ULONGLONG lTickBegin; SYSTEMTIME stBegin; ULONGLONG lFrameIndex; //下一帧的索引 ULONGLONG lFrameCount; ULONGLONG lTickEnd; SYSTEMTIME stEnd; BOOL fFirstRun; }info; auto_x264 m_264; HBuffer m_BufResized; HBuffer m_BufOverlayText; public: auto_avi_stream() { __memzero(param); __memzero(info); } ~auto_avi_stream() { } /**************************************************************************************************\ * void : 2013年9月8日 设置配置文件,x264会自动把后缀修改为 .x264.cfg * SetConfigFile : * LPCTSTR pszFile : \**************************************************************************************************/ void SetConfigFile(LPCTSTR pszFile) { __strcpy(m_264.param.szConfigFile, pszFile); } /**************************************************************************************************\ * BOOL : 2013年9月8日 是否打开 * IsOpen : \**************************************************************************************************/ BOOL IsOpen() { if (info.fccHandler == FCCX264) return m_264.IsOpen(); return FALSE; } /**************************************************************************************************\ * BOOL : 2013年9月8日 打开录像 * Open : * LPCTSTR pszFile : 文件名(可以是模板) * DWORD fccHandler : 编码,*(DWORD*)"X264"(FCCX264) * RJPEG_OPEN* param : 录像参数 * DWORD dwTick = 0 : 开始时刻 * SYSTEMTIME* pst = 0 : 开始时间 \**************************************************************************************************/ BOOL Open(LPCTSTR pszFile, DWORD fccHandler, RJPEG_OPEN* param, DWORD dwTick = 0, SYSTEMTIME* pst = 0) { if (param->Format.nFrameRate <= 0) return FALSE; info.Param = *param; info.fccHandler = fccHandler; __strcpy(info.szFileName, pszFile); if (dwTick == 0 || pst == 0) { info.lTickBegin = ::GetTickCount(); GetLocalTime(&info.stBegin); } else { info.lTickBegin = dwTick; info.stBegin = *pst; } info.lTickEnd = info.lTickBegin; info.stEnd = info.stBegin; info.lFrameCount = 0; BITMAPINFOHEADER bih = {0}; info.bih.biBitCount = 24; info.bih.biWidth = info.Param.Format.biWidth; info.bih.biHeight = info.Param.Format.biHeight; info.bih.biPlanes = 1; info.bih.biSize = sizeof(info.bih); info.bih.biSizeImage = (info.bih.biWidth * info.bih.biBitCount + 31) / 32 * 4 * info.bih.biHeight; char szf[_MAX_PATH] = {0}; GetFileName(szf, info.szFileName, &info.stBegin); return Open(szf); } /**************************************************************************************************\ * BOOL : 2013年9月8日 增加帧 * AddFrame : 会自动停止等 * DWORD dwTick : * LPBITMAPINFOHEADER pbih : * LPBYTE pBits : \**************************************************************************************************/ BOOL AddFrame(DWORD dwTick, LPBITMAPINFOHEADER pbih, LPBYTE pBits) { if (pbih->biBitCount != 24) return FALSE; ULONGLONG tick = GetTickCount(dwTick); //帧率控制 double sec = (double)(LONGLONG)(tick - info.lTickBegin) / 1000.0; ULONGLONG index = (ULONGLONG)(LONGLONG)(sec * info.Param.Format.nFrameRate + 0.5); if (index <= info.lFrameIndex && info.lTickEnd != info.lTickBegin) return TRUE; info.lFrameIndex = index; info.lTickEnd = tick; SYSTEMTIME stold = info.stEnd; SYSTEMTIME st = info.stBegin; SystemTimeAdd(&st, (int)(LONGLONG)(tick - info.lTickBegin)); info.stEnd = st; //先看看是否需要改变大小 if (pbih->biWidth != info.bih.biWidth || pbih->biHeight != info.bih.biHeight ) { int size = info.bih.biSizeImage; LPBYTE p = m_BufResized.GetBuffer(size); if (p == 0) return FALSE; auto_IplImage src(pbih, pBits); if (!src) return FALSE; auto_IplImage dst(&info.bih, p); if (!dst) return FALSE; cvResize(src, dst, CV_INTER_LINEAR ); pbih = &info.bih; pBits = p; } //叠加文字 if (info.Param.oiText[0]) { //第一步,如果没有改变大小,则要复制一下内存,防止改变了原始内存 if (pBits != m_BufResized.m_pBuffer) { int size = info.bih.biSizeImage; LPBYTE p = m_BufResized.GetBuffer(size); if (p == 0) return FALSE; ASSERT(info.bih.biSizeImage == pbih->biSizeImage); memcpy(p, pBits, pbih->biSizeImage); pBits = p; pbih = &info.bih; } //下面做实际的叠加文字 Overlay(pbih, pBits, info.stEnd, info.lFrameIndex); } //增加到录像 if (!CompressFrame(tick, pbih, pBits)) return FALSE; info.lFrameCount ++; BOOL bStop = 0; if (info.Param.dwFileEveryMinutes) { if (info.Param.dwFileEveryMinutes == 1) { if (info.stEnd.wSecond < stold.wSecond) { double sec = GetSeconds(); if (sec > 30) { bStop = TRUE; } } } else if ((info.stEnd.wMinute % info.Param.dwFileEveryMinutes) == 0) { double sec = GetSeconds(); if (sec > info.Param.dwFileEveryMinutes * 60.0 / 2.0) { bStop = TRUE; } } } else if (info.Param.dwSecondsLimit) { double sec = GetSeconds(); if (sec >= info.Param.dwSecondsLimit) { bStop = TRUE; } } if (bStop) { //停止录像,开始新录像 Stop(); char szf[_MAX_PATH] = {0}; if (0 == GetFileName(szf, info.szFileName, &info.stEnd)) { //非模板,直接关闭 return TRUE; } info.lTickBegin = tick; info.lTickEnd = tick; info.stBegin = info.stEnd; return Open(szf); } return TRUE; } /**************************************************************************************************\ * double : 2013年9月8日 录像时间长度 * GetSeconds : \**************************************************************************************************/ double GetSeconds() { double sec = (double)(LONGLONG)(info.lTickEnd - info.lTickBegin) / 1000.0; if (sec < 1.0) sec = 1.0; return sec; } /**************************************************************************************************\ * DWORD : 2013年9月8日 录像多少帧 * GetFrames : \**************************************************************************************************/ DWORD GetFrames() { return (DWORD)info.lFrameCount; } /**************************************************************************************************\ * void : 2013年9月8日 关闭 * Close : \**************************************************************************************************/ void Close() { Stop(); } /**************************************************************************************************\ * void : 2013年9月8日 配置 * Config : * HWND hwnd : \**************************************************************************************************/ void Config(HWND hwnd) { if (info.fccHandler == FCCX264) { m_264.Config(hwnd); } } /**************************************************************************************************\ * LPCTSTR : 2013年9月8日 获取文件名 * GetFileName : \**************************************************************************************************/ LPCTSTR GetFileName() { if (info.fccHandler == FCCX264) { return m_264.info.szFile; } return ""; } /**************************************************************************************************\ * double : 2013年9月8日 获取实际的帧率 * GetFrameRate : \**************************************************************************************************/ double GetFrameRate() { return GetFrames() / GetSeconds(); } /**************************************************************************************************\ * void : 2013年9月8日 获取当前录像的信息 * GetInfo : * char* psz : * int cb : * int& n : \**************************************************************************************************/ void GetInfo(char* psz, int cb, int& n, int mode = 0) { double sec = GetSeconds(); LPCTSTR stm = "秒"; if (sec > 3600.0) { sec /= 3600.0; stm = "时"; } else if (sec > 60.0) { sec /= 60.0; stm = "分"; } if (mode == 0) { if (info.fccHandler == FCCX264) { __snprintcat2(psz, cb, n), "%.1lf%s, 帧%d, 帧率%.1lf\n#录像文件:%s%s%s", sec, stm, GetFrames(), GetFrameRate(), GetFileName(), m_264.info.szAsciiFile[0] ? "\n#临时文件:" : "", m_264.info.szAsciiFile ); } else { __snprintcat2(psz, cb, n), "%s, %.1lf%s, 帧%d, 帧率%.1lf", GetFileName(), sec, stm, GetFrames(), GetFrameRate() ); } } } private: /**************************************************************************************************\ * void : 2013年9月8日 停止 * Stop : \**************************************************************************************************/ void Stop() { if (info.fccHandler == FCCX264) { m_264.Close(); } } /**************************************************************************************************\ * BOOL : 2013年9月8日 压缩一帧 * CompressFrame : * ULONGLONG dwTick : * LPBITMAPINFOHEADER pbih : * LPBYTE pBits : \**************************************************************************************************/ BOOL CompressFrame(ULONGLONG dwTick, LPBITMAPINFOHEADER pbih, LPBYTE pBits) { BOOL retval = 0; if (info.fccHandler == FCCX264) { retval = m_264.AddFrame(dwTick, pbih, pBits); } return retval; } /**************************************************************************************************\ * ULONGLONG : 2013年9月8日 防止毫秒时刻转回来 * GetTickCount : * DWORD dwTick : \**************************************************************************************************/ ULONGLONG GetTickCount(DWORD dwTick) { ULONGLONG t = dwTick; if (dwTick < info.lTickEnd) { t += 0x100000000; } return t; } /**************************************************************************************************\ * BOOL : 2013年9月8日 内部使用打开录像文件 * Open : * LPCTSTR pszFile : \**************************************************************************************************/ BOOL Open(LPCTSTR pszFile) { if (info.fccHandler == FCCX264) return m_264.Open(pszFile, &info.bih); return FALSE; } /**************************************************************************************************\ * int : 2013年9月8日 把文件模板转成真正的文件名 * GetFileName : 返回替换的模板个数 * char* pszFile : * LPCTSTR pszTemplate : * SYSTEMTIME* pst : \**************************************************************************************************/ int GetFileName(char* pszFile, LPCTSTR pszTemplate, SYSTEMTIME* pst) { CString szf(pszTemplate); int nr = 0; char szi[8] = {0}; __sprintf(szi), "%04d", pst->wYear); nr += szf.Replace("{y}", szi); __sprintf(szi), "%02d", pst->wMonth); nr += szf.Replace("{m}", szi); __sprintf(szi), "%02d", pst->wDay); nr += szf.Replace("{d}", szi); __sprintf(szi), "%02d", pst->wHour); nr += szf.Replace("{h}", szi); __sprintf(szi), "%d", pst->wHour); nr += szf.Replace("{H}", szi); __sprintf(szi), "%02d", pst->wMinute); nr += szf.Replace("{M}", szi); __sprintf(szi), "%02d", pst->wSecond); nr += szf.Replace("{s}", szi); __strncpy(pszFile, (LPCTSTR)szf, _MAX_PATH); return nr; } /**************************************************************************************************\ * LPBYTE : 2013年9月8日 叠加文字 * Overlay : * LPBITMAPINFOHEADER pdbih : * LPBYTE pdBits : * SYSTEMTIME st : * DWORD lFrameIndex : \**************************************************************************************************/ LPBYTE Overlay(LPBITMAPINFOHEADER pdbih, LPBYTE pdBits, SYSTEMTIME st, DWORD lFrameIndex) { //叠加文字 if (info.Param.oiText[0]) { //计算时间 //把[T]替换为时间,把[F]替换为帧号[t]为简写时间 char szt[64] = {0}; char szT[64] = {0}; char szm[64] = {0}; __sprintf(szT), "%04d年%02d月%02d日 %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); __sprintf(szt), "%04d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); __sprintf(szm), "%03d", st.wMilliseconds); char szf[32] = {0}; __sprintf(szf), "%d", lFrameIndex); CString szOverlay(info.Param.oiText); szOverlay.Replace("[T]", szT); szOverlay.Replace("[t]", szt); szOverlay.Replace("[F]", szf); szOverlay.Replace("[m]", szm); szOverlay.Replace("[N]", "\r\n"); if (_OT_GetTextBitmap(&m_BufOverlayText, &info.Param.oiFormat.lfFont, szOverlay, pdbih->biWidth)) { OT_FLAGS of = {0}; of.nPositionType = 0; //0 位置 1 下面水平条 of.nPositionX = info.Param.oiFormat.nPosX; //位置坐标 of.nPositionY = info.Param.oiFormat.nPosY; //位置坐标 of.lfFont.lfFont = info.Param.oiFormat.lfFont; //字体和颜色(前景) of.lfFont.rgbFont = info.Param.oiFormat.crColor; of.nBkTransparent = 100 - info.Param.oiFormat.nBackGround * 25; of.nEdgeWidth = info.Param.oiFormat.nEdgeWidth; //边框宽度(用背景颜色)边框 of.crBackground = RGB(0, 0, 0); of.nTransparent = 0; //100 全透明 0 背景颜色(背景) of.bAutoWhiteBlack = info.Param.oiFormat.bAutoWhiteBlack; //2011年11月29日 自动黑白字 _OT_OverTextBitmap4(&m_BufOverlayText, pdbih, pdBits, pdbih->biSizeImage, FALSE, 0, 0, &of); } } return pdBits; } }; #endif
#ifndef __HSS_AVI_ENC_HSS__ #define __HSS_AVI_ENC_HSS__ /**************************************************************************************************\ * 2013-08-31 新的压缩avi类,更简单,并且支持数据流(但是可能不理想,先展示不管了) 关于配置文件的处理: 可以设置配置文件,若没有设置配置文件,则使用缺省的配置,不进行配置的相关处理和调用 因为很多编码器都可以保存配置,保存为缺省 现在必须处理配置,是因为保存的位置可能被写保护,所以必须保存到其他地方 (1) 若指定了配置文件,则自动装载配置文件,并检查配置文件是否匹配,如果匹配则使用,如果不匹配,则不使用 (2) 若没有指定配置文件,则使用缺省 (3) 若指定了配置文件,必须显式调用配置函数,否则不进行自动的配置 配置: m_enc.param.fccHandler = *(DWORD*)"X264";//"XVID"; m_enc.param.lKey = 3; m_enc.param.lFrameRate = 12; m_enc.param.szConfigFile... m_enc.Config(GetSafeHwnd()); 用法: m_enc.param.fccHandler = *(DWORD*)"X264";//"XVID"; m_enc.param.lKey = 3; m_enc.param.lFrameRate = 12; m_enc.Open(pbih); m_enc.AddFrame(tick, pbih, pbits, &Buf); if (!Buf.IsEmpty()) { //写入avi文件 } \**************************************************************************************************/ #include <StringN.h> #include <auto_file.h> #include <mmsystem.h> #include <vfw.h> #include <__dbg.h> #include <HBuffer.h> #include <auto_folder.h> #include <auto_buffer.h> #pragma comment(lib, "vfw32.lib") typedef struct _AVIENC_CONFIGFILE { DWORD mask; //acfg COMPVARS cv; }AVIENC_CONFIGFILE; class auto_avienc { public: struct { DWORD fccHandler; // handler of chosen compressor or long lFrameRate; // 帧率 long lKey; // 关键帧数量 long lDataRate; //码率 long lQ; //质量 char szConfigFile[_MAX_PATH]; //文件 DWORD bChooseFccHandler : 1; // 选择压缩编码器 }param; struct { ULONGLONG uTickBegin; //开始帧的时刻 ULONGLONG uTickEnd; //最后一帧时刻 LONG lFrameIndex; //最后一帧索引 BITMAPINFO in; BITMAPINFO out; }info; auto_buffer m_Buf; //压缩和状态内存, ICINFO, STATE HIC m_hic; BOOL m_bLoaded; //是否装载过配置 public: auto_avienc() { __memzero(param); __memzero(info); m_hic = 0; m_bLoaded = 0; param.fccHandler = *(DWORD*)"WMV3"; param.lFrameRate = 15; param.lKey = 20; param.lDataRate = 0; param.bChooseFccHandler = 1; } ~auto_avienc() { Close(); } /**************************************************************************************************\ * BOOL : 2013年9月1日 是否打开 * IsOpen : \**************************************************************************************************/ BOOL IsOpen() { return m_hic != 0; } /**************************************************************************************************\ * void : 2013年9月1日 是否成功没有关系 * LoadConfig : \**************************************************************************************************/ void LoadConfig() { if (param.szConfigFile[0] == 0 || m_bLoaded) return; if (!auto_file::Read(param.szConfigFile, &m_Buf)) return; if (m_Buf.m_p == 0 || m_Buf.m_size == 0 || m_Buf.m_size < sizeof(ICINFO)) { m_Buf.free(); return; } ICINFO* pi = (ICINFO*)m_Buf.m_p; if (pi->dwSize != sizeof(ICINFO)) { m_Buf.free(); return; } if (param.fccHandler == 0 || param.bChooseFccHandler) //使用保存的编码器类型 { param.fccHandler = pi->fccHandler; __trace_file "usering %X", param.fccHandler);__trace_end; } m_bLoaded = TRUE; } /**************************************************************************************************\ * BOOL : 2013年8月31日 这个检查是否配置正确,如果配置正确,则使用,不正确则不使用 * CheckConfig : \**************************************************************************************************/ BOOL CheckConfig() { if (m_hic == 0) return FALSE; if (!m_Buf) return FALSE; ICINFO in = {0}; if (0 == ICGetInfo(m_hic, &in, sizeof(in))) { __trace_file "");__trace_end; return FALSE; } ICINFO* pi = (ICINFO*)(LPBYTE)m_Buf; if (memcmp(pi, &in, sizeof(in)) != 0) { __trace_file "");__trace_end; return FALSE; } DWORD size = ICGetStateSize(m_hic); if (size != m_Buf.m_size - sizeof(ICINFO)) { __trace_file "");__trace_end; return FALSE; } LPBYTE pState = (LPBYTE)(m_Buf.m_p) + sizeof(ICINFO); if (0 == ICSetState(m_hic, pState, size)) { __trace_file "");__trace_end; return FALSE; } __trace_file "");__trace_end; return TRUE; } /**************************************************************************************************\ * BOOL : 2013年8月31日 配置信息,导入以前保存的配置,如果导入的配置不对,则重新显示对话框配置 * Config : * HWND hwnd : 2013年9月1日 修改,如果fccHandler是0,则显示配置也选择的对话框。 如果fccHandler指定,则只配置指定的 \**************************************************************************************************/ BOOL Config(HWND hwnd) { LoadConfig(); //可能没装载就调用了Config //2013年9月1日 HIC hic = 0; if (param.fccHandler == 0 || param.bChooseFccHandler) { COMPVARS cv = {0}; cv.cbSize = sizeof(cv); cv.fccType = ICTYPE_VIDEO; cv.fccHandler = param.fccHandler; cv.dwFlags = ICMF_COMPVARS_VALID; if (!ICCompressorChoose(hwnd, ICMF_CHOOSE_ALLCOMPRESSORS|ICMF_CHOOSE_KEYFRAME|ICMF_CHOOSE_DATARATE, 0, 0, &cv, 0)) { __trace_file "%X", param.fccHandler);__trace_end; return FALSE; } hic = cv.hic; param.fccHandler = cv.fccHandler; if (cv.lKey) param.lKey = cv.lKey; if (cv.lDataRate) param.lDataRate = cv.lDataRate; } else { hic = ICOpen(ICTYPE_VIDEO, param.fccHandler, ICMODE_COMPRESS|ICMODE_FASTCOMPRESS); if (hic == 0) return FALSE; //下面这句话可能不对,因为XVID这个返回没有,但是实际上有对话框 //if (ICERR_OK != ICQueryConfigure(hic)) // goto LABLE_CLOSE_HIC; if (ICERR_OK != ICConfigure(hic, hwnd)) { ICClose(hic); return FALSE; } } //保存配置,用于下次使用 BOOL bSucc = 0; int size = ICGetStateSize(hic); LPBYTE p = m_Buf.alloc(size + sizeof(ICINFO)); if (p) { m_Buf.zero(); if (0 != ICGetInfo(hic, (ICINFO*)p, sizeof(ICINFO))) { p += sizeof(ICINFO); if (ICERR_OK == ICGetState(hic, p, size)) { if (param.szConfigFile[0]) { auto_folder af(param.szConfigFile); if (auto_file::Write(param.szConfigFile, &m_Buf)) { bSucc = TRUE; } } else { bSucc = TRUE; } } } } ICClose(hic); if (!bSucc) { m_Buf.free(); } return bSucc; } /**************************************************************************************************\ * BOOL : 2013年8月31日 打开指定格式的录像,准备录像 * Open : * LPBITMAPINFOHEADER pbih : \**************************************************************************************************/ BOOL Open(LPBITMAPINFOHEADER pbih) { //关闭 Close(); info.in.bmiHeader = *pbih; info.out.bmiHeader = *pbih; //初始化压缩类型 if (param.fccHandler == 0) param.fccHandler = *(DWORD*)"XVID"; //装载配置,如果设置了 ,则自动更新为保存中的fccHandler //LoadConfig(); m_hic = ICOpen(ICTYPE_VIDEO, param.fccHandler, ICMODE_COMPRESS|ICMODE_FASTCOMPRESS); if (m_hic == 0) return FALSE; __trace_file "fcc = %X", param.fccHandler);__trace_end; CheckConfig(); if (ICERR_OK != ICCompressGetFormat(m_hic, &info.in, &info.out)) return FALSE; if (ICERR_OK != ICCompressBegin(m_hic, &info.in, &info.out)) return FALSE; return TRUE; } /**************************************************************************************************\ * BOOL : 增添一帧,根据时刻判断帧率,及是否抛弃 * AddFrame : * DWORD dwTick : * LPBITMAPINFOHEADER pbih : * LPBYTE pBits : * HBuffer* pBufOut : \**************************************************************************************************/ BOOL AddFrame(DWORD dwTick, LPBITMAPINFOHEADER pbih, LPBYTE pBits, HBuffer* pBufOut) { if (m_hic == 0) return FALSE; if (pbih->biWidth != info.in.bmiHeader.biWidth || pbih->biHeight != info.in.bmiHeader.biHeight || pbih->biBitCount != info.in.bmiHeader.biBitCount ) { return FALSE; } if (dwTick == 0) { if (info.uTickBegin == 0) { info.uTickBegin = GetTickCount(); info.uTickEnd = info.uTickBegin; info.lFrameIndex = 0; } else { info.lFrameIndex ++; } } else { ULONGLONG tick_end = 0; if (info.uTickBegin == 0) { info.uTickBegin = dwTick; tick_end = dwTick; } else if (dwTick < info.uTickEnd) { //循环了 tick_end = dwTick + 0x100000000; } else { tick_end = dwTick; } int dIndex = (int)(double((LONGLONG)(tick_end - info.uTickBegin)) / 1000.0 * param.lFrameRate + 0.5); if (dIndex && dIndex <= info.lFrameIndex) { return TRUE; } info.uTickEnd = tick_end; info.lFrameIndex = dIndex; } LPBYTE pOut = pBufOut->GetBuffer(__max(info.out.bmiHeader.biSizeImage, info.in.bmiHeader.biSizeImage)); if (pOut == 0) return FALSE; DWORD dwCkID = 0; DWORD dwCompFlags = 0; DWORD dwQuality = 0; if(ICCompress(m_hic, ((info.lFrameIndex % param.lKey) == 0 ? ICCOMPRESS_KEYFRAME : 0), &info.out.bmiHeader, pOut, pbih, (unsigned char *)pBits, &dwCkID, &dwCompFlags, (LONG)info.lFrameIndex, 0, dwQuality, NULL, NULL ) != ICERR_OK) { return FALSE; } //__trace_file "size=%d\r\n", info.out.bmiHeader.biSizeImage);__trace_end; pBufOut->m_nBuffer = info.out.bmiHeader.biSizeImage; return TRUE; } /**************************************************************************************************\ * void : 2013年8月31日 关闭 * Close : \**************************************************************************************************/ void Close() { if (m_hic) { ICCompressEnd(m_hic); ICClose(m_hic); m_hic = 0; } } }; #endif