首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于截取第三方视频播放器的图片,截出来是黑色的

2012-09-27 
【求助】关于截取第三方视频播放器的图片,截出来是黑色的我用一般的截图工具截qq播放器播放的视频时,截出来

【求助】关于截取第三方视频播放器的图片,截出来是黑色的
我用一般的截图工具截qq播放器播放的视频时,截出来是黑色的,关闭了硬件加速的时候播放截出来的是正常的,但是可怜画面太粗糙了。
我用qq的“捕捉视频图像”插件截取视频的时候就能正常截图,我不知道这个是什么原理哦。
我这在写一个截图工具,能够截取到动态播放的播放器的图片,有哪位大虾可以指点一下?
论坛上的方法工具只能提供一般的截图功能,对于我上述的截取qq播放器出现黑色图片的问题没能解决。
请指教。谢谢。
有什么参考api或者代码可以参考下吗?

[解决办法]
或者参考下面

C/C++ code
//GDI与DX截屏API操作LPDIRECTDRAW        lpDD       = NULL;LPDIRECTDRAWSURFACE lpDDSPrime = NULL;LPDIRECTDRAWSURFACE lpDDSBack  = NULL;LPDIRECTDRAWSURFACE lpDDSGdi   = NULL;LPDIRECTDRAWSURFACE lpSurf     = NULL;DDSURFACEDESC DDSdesc;BOOL m_b24=TRUE;//rfbServerInitMsg m_scrinfo;RECT    m_bmrect;struct _BMInfo {    BITMAPINFO bmi       ;    BOOL       truecolour;    RGBQUAD    cmap[256] ;} m_bminfo; // 用来保存位图信息的结构int DX_Init() {// DirectX初始化。返回当前表面获取一张屏幕位图的存储空间大小    HRESULT hr;    // 初始化directX    hr = DirectDrawCreate(0, &lpDD, 0);    if (FAILED(hr)) return FALSE;    hr = lpDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);    if (FAILED(hr)) return FALSE;    ZeroMemory(&DDSdesc, sizeof(DDSdesc));    DDSdesc.dwSize  = sizeof(DDSdesc);    DDSdesc.dwFlags = DDSD_CAPS;    DDSdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;    hr = lpDD->CreateSurface(&DDSdesc, &lpDDSPrime, 0);    if (FAILED(hr)) return FALSE;    hr = lpDD->GetGDISurface(&lpDDSGdi);    if (FAILED(hr)) return FALSE;    ZeroMemory(&DDSdesc, sizeof(DDSdesc));    DDSdesc.dwSize  = sizeof(DDSdesc);    DDSdesc.dwFlags = DDSD_ALL;    hr = lpDDSPrime->GetSurfaceDesc(&DDSdesc);    if (FAILED(hr)) return FALSE;    // 初始化位图信息    if ((DDSdesc.dwFlags & DDSD_WIDTH) && (DDSdesc.dwFlags & DDSD_HEIGHT)) {        m_bmrect.left = m_bmrect.top = 0;        m_bmrect.right = DDSdesc.dwWidth;        m_bmrect.bottom = DDSdesc.dwHeight;    } else return FALSE;    m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;//BI_BITFIELDS;    m_bminfo.bmi.bmiHeader.biBitCount = DDSdesc.ddpfPixelFormat.dwRGBBitCount;    // m_bminfo.truecolour = DDSdesc.ddpfPixelFormat.dwFlags & DDPF_RGB;    if (m_bminfo.bmi.bmiHeader.biBitCount > 8)        m_bminfo.truecolour = TRUE;    else        m_bminfo.truecolour = FALSE;    ZeroMemory(&DDSdesc, sizeof(DDSdesc));    DDSdesc.dwSize = sizeof(DDSdesc);    DDSdesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;    DDSdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;    DDSdesc.dwHeight = m_bmrect.bottom - m_bmrect.top;    DDSdesc.dwWidth  = m_bmrect.right  - m_bmrect.left;    hr = lpDD->CreateSurface(&DDSdesc, &lpDDSBack, 0);    if (FAILED(hr)) return FALSE;//  hr = lpDDSPrime->QueryInterface( IID_IDirectDrawSurface3, (LPVOID *)&lpSurf);//  if (FAILED(hr)) return FALSE;    switch (m_bminfo.bmi.bmiHeader.biBitCount) {    case 32:    case 24:       // Update the bitmapinfo header       m_b24 = TRUE;       m_bminfo.bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );       m_bminfo.bmi.bmiHeader.biWidth = 1024;       m_bminfo.bmi.bmiHeader.biHeight = 768;       m_bminfo.bmi.bmiHeader.biPlanes = 1;//     m_bminfo.bmi.bmiHeader.biBitCount = 24;       m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;       m_bminfo.bmi.bmiHeader.biSizeImage = abs((m_bminfo.bmi.bmiHeader.biWidth * m_bminfo.bmi.bmiHeader.biHeight * m_bminfo.bmi.bmiHeader.biBitCount)/8);       m_bminfo.bmi.bmiHeader.biXPelsPerMeter = (1024*1000)/1024;       m_bminfo.bmi.bmiHeader.biYPelsPerMeter = (768*1000)/768;       m_bminfo.bmi.bmiHeader.biClrUsed   = 0;       m_bminfo.bmi.bmiHeader.biClrImportant = 0;       break;    }    return m_bminfo.bmi.bmiHeader.biSizeImage;}BOOL CaptureScreen(RECT &rect, BYTE *scrBuff, UINT scrBuffSize) {// 捕捉屏幕。rect: 区域。scrBuff: 输出缓冲。scrBuffSize: 缓冲区大小    HRESULT hr=0;    hr = lpDDSBack->BltFast(rect.left,rect.top,lpDDSPrime,&rect,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);    if (FAILED(hr)) return FALSE;    DDSURFACEDESC surfdesc;    ZeroMemory(&surfdesc, sizeof(surfdesc));    surfdesc.dwSize = sizeof(surfdesc);    hr = lpDDSBack->Lock(&rect, &surfdesc, DDLOCK_READONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR /*|DDLOCK_NOSYSLOCK*/, NULL);//  hr = lpDDSPrime->Lock(&rect, &surfdesc, DDLOCK_READONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR /*|DDLOCK_NOSYSLOCK*/, NULL);    if (FAILED(hr)) return FALSE;    // copy the data into our buffer    BYTE * destbuffpos, * srcbuffpos;//  m_scrinfo.format.bitsPerPixel = 24;    srcbuffpos = (BYTE *) surfdesc.lpSurface;    destbuffpos = scrBuff;    memcpy( destbuffpos, srcbuffpos,m_bminfo.bmi.bmiHeader.biSizeImage);    // unlock the primary surface//  lpDDSPrime->Unlock(surfdesc.lpSurface);    lpDDSBack->Unlock(surfdesc.lpSurface);    return TRUE;}int SaveBitmapToFile(BITMAP *bitmap, LPSTR lpFileName,char *lpBuf) {   DWORD dwWritten;   BITMAPFILEHEADER   bmfHdr;   BITMAPINFOHEADER   bi;   HANDLE          fh=NULL;   bi.biSize = sizeof(BITMAPINFOHEADER);   bi.biWidth= bitmap->bmWidth;   bi.biHeight = bitmap->bmHeight;   bi.biPlanes = 1;   bi.biBitCount      = bitmap->bmBitsPixel*8;   bi.biCompression   = BI_RGB;   bi.biSizeImage     = 0;   bi.biXPelsPerMeter = 0;   bi.biYPelsPerMeter = 0;   bi.biClrUsed       = 0;   bi.biClrImportant  = 0;   fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);   if (fh == INVALID_HANDLE_VALUE) return FALSE;   bmfHdr.bfType = 0x4D42; // "BM"   bmfHdr.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+bitmap->bmWidth*bitmap->bmHeight*bitmap->bmBitsPixel;   bmfHdr.bfReserved1 = 0;   bmfHdr.bfReserved2 = 0;   bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);   WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);   WriteFile(fh, (char *)&bi,sizeof(BITMAPINFOHEADER), &dwWritten, NULL);   WriteFile(fh, (char *)lpBuf,bitmap->bmWidth*bitmap->bmHeight*bitmap->bmBitsPixel, &dwWritten, NULL);   FlushFileBuffers(fh);   CloseHandle(fh);   return true;}//(1)获取屏幕绘图设备//(2)创建一个与屏幕绘图设备相兼容的内存绘图设备//(2)在内存中创建一个与屏幕绘图设备相兼容的图像对象//(3)将屏幕设备中的图像复制到内存绘图设备中//(4)将内存图像保存到文件中//相关函数://GetDIBits:按位的方式返回指定的BITMAP,并按指定的格式存储到内存中int GetBitmapFromScreen(char *lpFileName) {    char *lpBuf;    HBITMAP hBitmap,hOld ;    HDC hDC,hcDC;    BITMAP bb;    BITMAPINFO b;    HANDLE hp,fh=NULL;    DWORD dwX,dwY;    dwX=GetSystemMetrics(SM_CXSCREEN);    dwY=GetSystemMetrics(SM_CYSCREEN);    hDC=GetDC(NULL);    hcDC=CreateCompatibleDC(hDC);    hBitmap=CreateCompatibleBitmap(hDC,dwX,dwY);    hOld=(HBITMAP)SelectObject(hcDC,hBitmap);    BitBlt(hcDC,0, 0,dwX,dwY, hDC, 0, 0, SRCCOPY);    bb.bmWidth=dwX;    bb.bmHeight =dwY;    bb.bmPlanes = 1;    bb.bmWidthBytes=bb.bmWidth*3;    bb.bmBitsPixel=3;    bb.bmType=0;    b.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);    b.bmiHeader.biWidth        =dwX;    b.bmiHeader.biHeight       =dwY;    b.bmiHeader.biPlanes       =1;    b.bmiHeader.biBitCount     =3*8;    b.bmiHeader.biCompression  =BI_RGB;    b.bmiHeader.biSizeImage    =0;    b.bmiHeader.biXPelsPerMeter=0;    b.bmiHeader.biYPelsPerMeter=0;    b.bmiHeader.biClrUsed      =0;    b.bmiHeader.biClrImportant =0;    b.bmiColors[0].rgbBlue     =8;    b.bmiColors[0].rgbGreen    =8;    b.bmiColors[0].rgbRed      =8;    b.bmiColors[0].rgbReserved =0;    hp=GetProcessHeap();    lpBuf=(char *)HeapAlloc(hp,HEAP_ZERO_MEMORY,bb.bmHeight*bb.bmWidth*4);    GetDIBits(hcDC,hBitmap,0,dwY,lpBuf,&b,DIB_RGB_COLORS);    SaveBitmapToFile(&bb,lpFileName,lpBuf);    ReleaseDC(NULL,hDC);    DeleteDC(hcDC);    DeleteObject(hBitmap);    DeleteObject(hOld);    HeapFree(hp,0,lpBuf);    return true;} 


[解决办法]

探讨

没有大侠出手相助了么??我越来越感觉csdn好像高手越来越少了,不知道是不是跑到别的论坛去了?有哪些比较好的论坛呢?

[解决办法]
只猜想一下原理

操作系统在将图像显示到硬件显示器上之前,会先在内存中生成这个图像,以提高处理速度
截图软件的一般原理就是取出这个图像
而硬件加速,就是操作系统不管“视频输出”了,而是由视频播放软件直接调用显示器的硬件驱动来提升速度,因此取出操作系统生成的图像,所得到的就是没有任何显示的黑屏

qq的插件能够捕捉qq的视频图像,很容易理解,没啥意义,人家自己家的东西,想在哪一步留个后门都简单
如果有别的软件能够捕捉到,对楼主来说才有参考价值
[解决办法]
探讨
首先谢谢你的指点,我就是想既然在我们屏幕上已经显示出一副图像了,我们可否直接读取显卡上的像素呢?

[解决办法]
尽管可以通过直接读显存截图,但某些显卡overlayer显示的内容可能不在显存中。
[解决办法]
DWORD ctrl;
DWORD dwValue = -1;
HKEY hKey;
WCHAR SubKeyName[] =_T("SOFTWARE\\Microsoft\\DirectDraw"); 
WCHAR ValueName[] = _T("EmulationOnly"); 

DWORD dwBufLen =sizeof(DWORD);

if( ERROR_SUCCESS== RegOpenKeyEx(HKEY_LOCAL_MACHINE,SubKeyName,0,KEY_ALL_ACCESS,&hKey) ) 
{
RegQueryValueEx(hKey,ValueName,0,NULL,(BYTE*)&dwValue,&dwBufLen); 
if(dwValue!=ctrl)
{
RegSetValueEx(hKey,ValueName,0,REG_DWORD,(LPBYTE)&ctrl,sizeof(DWORD)); 
}
RegCloseKey(hKey); 
}
抓屏前运行这个代码,通过修改注册表的方式来关闭dxdiag中的显示加速,ctrl是传入的修改值,1为关闭,0为开启,dwValue保存的是修改前的状态值,你退出抓屏之后要恢复用户之前的状态,不能做出流氓软件给用户留下隐患。此方法在XP系统下使用,vista系统下应该可以抓到,不用修改任何值。希望能帮到你~
[解决办法]
播放器播放都是通过硬件加速的方式,directx,将解码的数据送给显卡,自己做的播放器可以实现一个filter(directshow),加到graph里面去,截图很简单。。。
你可以试试HOOK COM的方式,具体参照这篇帖子
http://topic.csdn.net/u/20120716/16/4ed9b7b7-0e79-424e-8588-74e066dc9edc.html?seed=1882368135&r=79141637

热点排行