不清楚原理的看上篇文章《用DirectDraw实现屏幕截图》。
下面直接贴代码
#include <windows.h> #include <stdio.h> #include "ddraw.h" extern "C"{ #include "libavcodec/avcodec.h" #include "libswscale/swscale.h" } void save_bmp(unsigned char * data,int data_size,int w,int h,FILE * out) { // 位图文件头 BITMAPFILEHEADER bmpheader; BITMAPINFO bmpinfo; int bit = 24; bmpheader.bfType = ('M' <<8)|'B'; bmpheader.bfReserved1 = 0; bmpheader.bfReserved2 = 0; bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bmpheader.bfSize = bmpheader.bfOffBits + w*h*bit/8; bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.bmiHeader.biWidth = w; bmpinfo.bmiHeader.biHeight = 0-h; bmpinfo.bmiHeader.biPlanes = 1; bmpinfo.bmiHeader.biBitCount = bit; bmpinfo.bmiHeader.biCompression = BI_RGB; bmpinfo.bmiHeader.biSizeImage = 0; bmpinfo.bmiHeader.biXPelsPerMeter = 100; bmpinfo.bmiHeader.biYPelsPerMeter = 100; bmpinfo.bmiHeader.biClrUsed = 0; bmpinfo.bmiHeader.biClrImportant = 0; fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,out); fwrite(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,out); fwrite(data,data_size,1,out); } int main() { LPDIRECTDRAW7 lpddraw = NULL,ddraw2; // DDraw 对象 DDSURFACEDESC2 ddsd;// ddraw 显示表面 描述结构 LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // ddraw 主显示表面 LPDIRECTDRAWSURFACE7 lpddsoffscr = NULL; // ddraw 离屏表面 if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpddraw, IID_IDirectDraw7, NULL))) { printf("DDraw create failed.\n"); return -1; } if (FAILED( lpddraw ->QueryInterface(IID_IDirectDraw7,(LPVOID *)&ddraw2))) { printf("Couldn't query the interface.\n"); lpddraw ->Release(); return -1; } // 窗口模式(设置协作级别) lpddraw->SetCooperativeLevel( NULL, DDSCL_NORMAL | DDSCL_ALLOWREBOOT ); // 初始化 ddsd ZeroMemory(&ddsd,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); //指定该结构所占的字节数 ddsd.dwFlags = DDSD_CAPS/*使ddsCaps成员有效 *//*|DDSD_BACKBUFFERCOUNT打开后备缓冲标志*/; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE/*|DDSCAPS_COMPLEX|DDSCAPS_FLIP创建一个带后备缓冲的主表面*/; // 创建主显示表面 if (FAILED(lpddraw->CreateSurface(&ddsd, &lpddsprimary, NULL))) { printf("Create primary Surface failed.\n"); lpddraw ->Release(); return -1; } // 锁定surface HRESULT ddRval = DD_OK; do { ddRval = lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL); } while(ddRval == DDERR_WASSTILLDRAWING); printf("Lock Success.\n"); // 获取surface信息 DWORD dwBitDepth = ddsd.ddpfPixelFormat.dwRGBBitCount; DWORD dwWidth = ddsd.dwWidth; DWORD dwHeight = ddsd.dwHeight; LONG lPitch = ddsd.lPitch; BYTE *lpData = (BYTE *)ddsd.lpSurface;//实际数据 DWORD dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask; DWORD dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask; DWORD dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask; int len = dwWidth*dwHeight*dwBitDepth/8; BYTE * lpBuf = (BYTE*)malloc(len);//用于存储surface实际数据 memset(lpBuf,0,len); memcpy(lpBuf,lpData,len); //解锁surface lpddsprimary->Unlock(0); //转换和缩放图片 int dst_img_width = 400; int dst_img_height = 300; struct SwsContext * pSwsCtx = sws_getContext( dwWidth,dwHeight,PIX_FMT_BGRA, dst_img_width,dst_img_height,PIX_FMT_BGR24, SWS_BILINEAR, NULL,NULL,NULL); //先将图片转换为BGR24视频帧 uint8_t * buffer = NULL; AVFrame * rgb_frame = avcodec_alloc_frame(); buffer = (unsigned char *)av_malloc(avpicture_get_size(PIX_FMT_BGR24,dst_img_width,dst_img_height)); avpicture_fill((AVPicture*)rgb_frame,(uint8_t *)buffer,PIX_FMT_BGR24,dst_img_width,dst_img_height); uint8_t *data[4] = {lpBuf,0,0,0}; int linesize[4] = {dwWidth*dwBitDepth/8,0,0,0}; //缩放图片 sws_scale(pSwsCtx,data,linesize,0,dwHeight,rgb_frame ->data,rgb_frame ->linesize); //释放资源 free(lpBuf); sws_freeContext(pSwsCtx); //写文件 FILE * fp = fopen("test.bmp","wb"); save_bmp(rgb_frame ->data[0],rgb_frame ->linesize[0]*dst_img_height,dst_img_width,dst_img_height,fp); fclose(fp); av_free(rgb_frame); av_free(buffer); //释放资源 lpddsprimary ->Release(); lpddraw ->Release(); return 0; }