hur.cn - 华软网

 热门搜索

分只给一个人,高手进,解决了分就是你的,有关avi抓图的问题

  作者:未知    来源:网络    更新时间:2011/9/2
原先也开了个贴,可是没有解决问题,本人做了一个视频采集的程序,现在主要在做录制完后回放的功能,在回放的过程中通过slider控制播放位置,这个我已经实现了,现在要实现的是将当前桢和后面的4桢图像抓取出来保存在内存中,然后在5个picture控件中显示出来,我可以实现将图像保存出bmp,但是如果又保存图片又读取保存后的图片进行显示的话,那样会很卡,效率太低了,所以要直接操作内存中的数据,但是我用IPICTURE接口的时候,用那个保存了的图片数据流OleLoadPicture一直返回负数,纠结了很久的问题啊。我的抓取图片保存到内存中的方法如下
C++">
bool CDXGraph::SnapshotBitmap(const char *outFile)
{

if (mBasicVideo) // 类IBasicVideo
{
long bitmapSize = 0;
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
{
bool pass = false;
unsigned char * buffer = new unsigned char[bitmapSize];
// 得到当前画面的大小bitmapSize和数据buffer
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
{

BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

lpbi = (LPBITMAPINFOHEADER)buffer;

int nColors = 0; //调色板中的颜色个数.(RGB格式在8位以下的,需要用调色板。
//调色板实际上就是定义一些颜色的数组)
if (lpbi->biBitCount <= 8) //biBitCount:每个像素的位数.PS:RGB32每个像素用32位表示,也就是4个字节
nColors = 1 << lpbi->biBitCount;

hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM"
hdr.bfSize = bitmapSize + sizeof( hdr );
hdr.bfReserved1  = 0;
hdr.bfReserved2  = 0;
hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
nColors * sizeof(RGBQUAD));

// szTemp[] = "C:\\mysnapshot.bmp"临时的.bmp文件(outFile指针所指)
/* CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER)); // 设置.bmp格式
bitmapFile.Write(buffer, bitmapSize); // 存入数据(通俗的说就是画图)
bitmapFile.Close(); // Closes the bitmapFile and deletes the object*/

IStream *m_pStream;
IPicture *m_pPicture;
OLE_XSIZE_HIMETRIC m_JPGWidth;
OLE_YSIZE_HIMETRIC m_JPGHeight;
HGLOBAL hMem;
hMem=GlobalAlloc(GMEM_MOVEABLE,bitmapSize);
LPVOID pData=NULL,pPicData;
pData=GlobalLock(hMem);
pPicData=GlobalLock(buffer);
// memcpy(pData, pMemData, len);
memcpy(pData, pPicData, bitmapSize);
GlobalUnlock(hMem);
GlobalUnlock(buffer);
if(SUCCEEDED(CreateStreamOnHGlobal(hMem,true,&m_pStream)))
{
m_pPicture = NULL;

if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(LPVOID*)&(m_pPicture)) == S_OK)
{
m_pPicture->get_Height(&m_JPGHeight);
m_pPicture->get_Width(&m_JPGWidth);
/* CRect lpRec; 
GetDlgItem(IDC_STATIC1)->GetWindowRect(&lpRec); 
ScreenToClient(&lpRec);
m_pPicture->Render(GetDC()->m_hDC,lpRec.left,lpRec.top
,(int)(m_JPGWidth/26.45), (int)(m_JPGHeight/26.45)
,0 ,m_JPGHeight, m_JPGWidth,-m_JPGHeight,NULL);*/

}

}
pass = true;
}
delete [] buffer;
return pass;
}
}
return false;
}

我用的是directshow的抓取当前桢的方法GetCurrentImage将数据保存到buffer中,然后用这个数据流,但是一直在
if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(LPVOID*)&(m_pPicture)) == S_OK)这句话这里报错,我上网查了点资料,说返回负数说明图片无效,可是我的那个可以生成bmp了,为什么会无效呀,而且我调式的时候这些变量都是有值的呀,纠结纠结啊,高手高手来啊
---华软 网友回答---
http://download.csdn.net/source/2487699
---华软网友回复---
引用 1 楼 visualeleven 的回复:
http://download.csdn.net/source/2487699

我可以实现把图抓出来,现在的问题是我就在内存中拦截它为什么就不行了,继续望高手
---华软网友回复---
1,检查IID_IPicture是否为:
    GUID(0) = \x7BF80980        'stdPicture的GUID
    GUID(1) = \x101ABF32
    GUID(2) = \xAA00BB8B
    GUID(3) = \xAB0C3000

2,
if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(LPVOID*)&(m_pPicture)) == S_OK)
似乎应该为:
if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(IPicture*)m_pPicture ) == S_OK)

3,buffer转换为流之后,应该没有再使用,不要重新申请内存,直接使用buffer创建流对象
有点不明白的是:
unsigned char * buffer = new unsigned char[bitmapSize];
该命令返回的是GMEM_FIXED的内存?只有这个选项内存指针和内存句柄才会一样!LZ检查一下
 pPicData=GlobalLock(buffer); 此句,pPicData和buffer执行后,两者是否相等!(我只知道能从内存句柄获得指针,还不知道能从指针获得内存句柄)如果不等,则建议:
unsigned char * buffer = new unsigned char[bitmapSize];
改为:
HANDLE hMem=GlobalAlloc(.....);//直接获取内存句柄
char* buffer =GlobalLock(hMem);
这样就直接获得内存句柄(CreateStreamOnHGlobal(hMem,true,&m_pStream)传入的参数为内存句柄)
不要再使用hMem=GlobalAlloc(GMEM_MOVEABLE,bitmapSize);再申请内存然后又拷贝,浪费CPU周期





---华软网友回复---
                bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));    // 设置.bmp格式
                bitmapFile.Write(buffer, bitmapSize);    // 存入数据(通俗的说就是画图)

你看这个嘛,你的BUFF只是数据,不包含图片格式信息。
你应该在把修改下
C++">
bool CDXGraph::SnapshotBitmap(const char *outFile)
{
    
    if (mBasicVideo)    // 类IBasicVideo
    {
        long bitmapSize = 0;
        if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
        {
            bool pass = false;
            unsigned char * buffer = new unsigned char[bitmapSize];
            // 得到当前画面的大小bitmapSize和数据buffer
            if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
            {
                
                BITMAPFILEHEADER    hdr;
                LPBITMAPINFOHEADER    lpbi;

                lpbi = (LPBITMAPINFOHEADER)buffer;

                int nColors = 0;            //调色板中的颜色个数.(RGB格式在8位以下的,需要用调色板。
                                            //调色板实际上就是定义一些颜色的数组)
                if (lpbi->biBitCount <= 8)    //biBitCount:每个像素的位数.PS:RGB32每个像素用32位表示,也就是4个字节
                    nColors = 1 << lpbi->biBitCount;

                hdr.bfType        = ((WORD) ('M' << 8) | 'B');    //always is "BM"
                hdr.bfSize        = bitmapSize + sizeof( hdr );
                hdr.bfReserved1     = 0;
                hdr.bfReserved2     = 0;
                hdr.bfOffBits        = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
                        nColors * sizeof(RGBQUAD));

                // szTemp[] = "C:\\mysnapshot.bmp"临时的.bmp文件(outFile指针所指)
            /*    CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
                bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));    // 设置.bmp格式
                bitmapFile.Write(buffer, bitmapSize);    // 存入数据(通俗的说就是画图)
                bitmapFile.Close();    // Closes the bitmapFile and deletes the object*/
int nNewBmpSize = sizeof(BITMAPFILEHEADER) + bitmapSize;
byte* pNewBuffer = new byte[nNewBmpSize ];
memset(pNewBuffer, 0 , nNewBmpSize);
memcpy(pNewBuffer, &hdr, sizeof(BITMAPFILEHEADER));
memcpy(pNewBuffer + sizeof(BITMAPFILEHEADER), buffer, bitmapSize);
                
                IStream *m_pStream;
                IPicture *m_pPicture;
                OLE_XSIZE_HIMETRIC m_JPGWidth;
                OLE_YSIZE_HIMETRIC m_JPGHeight;
                HGLOBAL hMem;
                hMem=GlobalAlloc(GMEM_MOVEABLE,nNewBmpSize);
                LPVOID pData=NULL,pPicData;
                pData=GlobalLock(hMem);
                pPicData=GlobalLock(pNewBuffer);
                //    memcpy(pData, pMemData, len);
                memcpy(pData, pPicData, nNewBmpSize);
                GlobalUnlock(hMem);
                GlobalUnlock(buffer);
                if(SUCCEEDED(CreateStreamOnHGlobal(hMem,true,&m_pStream)))
                {
                    m_pPicture = NULL;
                    
                    if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(LPVOID*)&(m_pPicture)) == S_OK)
                    {
                        m_pPicture->get_Height(&m_JPGHeight);
                        m_pPicture->get_Width(&m_JPGWidth);
                    /*    CRect lpRec; 
                        GetDlgItem(IDC_STATIC1)->GetWindowRect(&lpRec); 
                        ScreenToClient(&lpRec);
                        m_pPicture->Render(GetDC()->m_hDC,lpRec.left,lpRec.top
                            ,(int)(m_JPGWidth/26.45), (int)(m_JPGHeight/26.45)
                            ,0 ,m_JPGHeight, m_JPGWidth,-m_JPGHeight,NULL);*/
                    }

    }
                pass = true;
            }
            delete [] buffer;
            delete [] pNewBuffer;
            return pass;
        }
    }
    return false;
}





---华软网友回复---
引用 3 楼 worldy 的回复:
1,检查IID_IPicture是否为:
    GUID(0) = \x7BF80980        'stdPicture的GUID
    GUID(1) = \x101ABF32
    GUID(2) = \xAA00BB8B
    GUID(3) = \xAB0C3000

2,
if(OleLoadPicture(m_pStream,0,FALSE,IID_IPic……

程序在if(OleLoadPicture(m_pStream,0,FALSE,IID_IPicture,(LPVOID*)&(m_pPicture)) == S_OK)就进不去了,这时显示的IID_IPicture值是IID_IPicture,显示的就是这名字。
我把程序改成这样了
C++">
IStream *m_pStream;
IPicture *m_pPicture;
OLE_XSIZE_HIMETRIC m_JPGWidth;
OLE_YSIZE_HIMETRIC m_JPGHeight;
// HGLOBAL hMem;
// hMem=GlobalAlloc(GMEM_MOVEABLE,bitmapSize);
LPVOID pData=NULL;
pData=GlobalLock(hMem);
memcpy(pData, buffer, bitmapSize);
GlobalUnlock(hMem);

在上面修改
HANDLE hMem=GlobalAlloc(GMEM_MOVEABLE,bitmapSize);
char* buffer =GlobalLock(hMem);
则报了错误
error C2440: 'initializing' : cannot convert from 'void *' to 'char *'的
我用这段代码改成获取硬盘中某个bmp图片然后显示都是可以的,但是为什么我用在这个buffer就不行,难道ds这样抓取的图片数据流不能这样用么,奇怪了
---华软网友回复---
问题解决了,确实是按4楼说的那样,结贴,信守若言的时刻到了
---华软网友回复---
我做了修改

AM_MEDIA_TYPE mt;
HRESULT hr = pGrabber->GetConnectedMediaType(&mt);
VIDEOINFOHEADER *pVih;
long bmSize=0;
hr = pGrabber->GetCurrentBuffer(&bmSize,NULL);

long *pBuffer=new long [bmSize];
hr = pGrabber->GetCurrentBuffer(&bmSize,pBuffer);

if ((mt.formattype == FORMAT_VideoInfo) &&
(mt.cbFormat>=sizeof(VIDEOINFOHEADER))&&
(mt.pbFormat!=NULL))
{
pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);

}
else  
{
// Free the format block when you are done:
FreeMediaType(mt);
return VFW_E_INVALIDMEDIATYPE; // Something went wrong
// pVih->bmiHeader is the BITMAPINFOHEADER for the frame.
}

BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

lpbi = (LPBITMAPINFOHEADER)pBuffer;

int nColors = 0; //调色板中的颜色个数.(RGB格式在8位以下的,需要用调色板。
//调色板实际上就是定义一些颜色的数组)
if (lpbi->biBitCount <= 8) //biBitCount:每个像素的位数.PS:RGB32每个像素用32位表示,也就是4个字节
nColors = 1 << lpbi->biBitCount;

hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM"
hdr.bfSize = bmSize + sizeof( hdr );
hdr.bfReserved1  = 0;
hdr.bfReserved2  = 0;
hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
nColors * sizeof(RGBQUAD));

newbitmapSize = sizeof(BITMAPFILEHEADER) + bmSize;
newbuffer = new byte[newbitmapSize ];
memset(newbuffer, 0 , newbitmapSize);
memcpy(newbuffer, &hdr, sizeof(BITMAPFILEHEADER));
memcpy(newbuffer + sizeof(BITMAPFILEHEADER), pBuffer, newbitmapSize);
FreeMediaType(mt);
return hr;

我修改成这样后buffer数据还是不对,我用IPicture无法正确取到图,错误就是buffer数据没有还原出位图格式来      
华软声明:本内容来自网络,如有侵犯您版权请来信指出,本站立即删除。