您的位置:首页 > 其它

windows下使用ffmpeg + DDRAW 截屏,并保存为图片

2012-10-31 17:14 387 查看
不清楚原理的看上篇文章《用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;
}

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐