关于 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)&param.bmi, (LPBITMAPINFO)&param.bmo);
        int ret = ICCompressBegin(m_Com.hic, (LPBITMAPINFO)&param.bmi, (LPBITMAPINFO)&param.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
posted @ 2016-11-30 09:47  shansong.huang  阅读(1541)  评论(0编辑  收藏  举报