不清楚原理的看上篇文章《用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;
}