背景描述

作为一个播放器,截图功能必不可少; 下面主要记录一下截图功能的实现;

实现流程

  • 将解码后的帧进行格式转换(目标格式为RGB24);

  • 采用独立的线程进行截图处理;

  • 截图可保存为BMP或JPG两种格式;

代码实现

#define _WIDTHBYTES(c)  ((c+31)/32*4)   // c = width * bpp
int Snapshot2File(RENDER_FORMAT renderFormat, SNAPSHOT_IMAGE_T *pSnapshot, char *pbuf)
{
PBYTE pDest = NULL, pDest16 = NULL;
INT nBpp;
DWORD dwW, dwH, dwWB; int ret = 0; int image_format = pSnapshot->imageFormat; if (renderFormat == RENDER_FORMAT_YUY2) nBpp = 16;
else if (renderFormat == RENDER_FORMAT_UYVY) nBpp = 16;
else if (renderFormat == RENDER_FORMAT_X8R8G8B8) nBpp = 32; //ok
else if (renderFormat == RENDER_FORMAT_A8R8G8B8) nBpp = 32; //ok
else if (renderFormat == RENDER_FORMAT_RGB565) nBpp = 16; //ok
else if (renderFormat == RENDER_FORMAT_RGB555) nBpp = 16; //ok
else if (renderFormat == RENDER_FORMAT_RGB24_GDI) nBpp = 24;
else return -1; //格式错误 dwW = pSnapshot->width;
dwH = pSnapshot->height;
dwWB = _WIDTHBYTES( dwW * nBpp ); if (image_format == 0x00)
{
//BMP
int iFilenameLen = (int)strlen(pSnapshot->filename); if ( (0 != memcmp(pSnapshot->filename+iFilenameLen-3, "bmp", 3)) &&
(0 != memcmp(pSnapshot->filename+iFilenameLen-3, "BMP", 3)) &&
(0 != memcmp(pSnapshot->filename+iFilenameLen-3, "Bmp", 3)) )
{
if (pSnapshot->filename[iFilenameLen-4] == '.')
{
for (int i=iFilenameLen-1; i>0; i--)
{
if (pSnapshot->filename[i] == '.')
{
pSnapshot->filename[i] = '\0';
break;
}
else
{
pSnapshot->filename[i] = '\0';
}
}
}
strcat(pSnapshot->filename, ".bmp");
} HANDLE hFile = CreateFile( pSnapshot->filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile == INVALID_HANDLE_VALUE ) return E_HANDLE; // SaveFile to BMP
BITMAPFILEHEADER bfh = {0};
bfh.bfType = 0x4D42;
bfh.bfSize = 0;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if( nBpp == 16 ) {
bfh.bfOffBits += sizeof(RGBQUAD) * 3;
}
else
if( nBpp == 24 ) {
bfh.bfOffBits += sizeof(RGBQUAD) * 1;
}
else
if( nBpp == 32 ) {
bfh.bfOffBits += sizeof(RGBQUAD) * 1;
}
DWORD dwWriteLength = sizeof(BITMAPFILEHEADER);
DWORD dwWrittenLength = 0;
WriteFile( hFile, (PVOID)&bfh, dwWriteLength, &dwWrittenLength, NULL ); BITMAPINFOHEADER bih = {0};
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = dwW;
bih.biHeight = -(INT)dwH;
bih.biPlanes = 1;
bih.biBitCount = nBpp;
bih.biCompression = (nBpp == 16) ? BI_BITFIELDS : BI_RGB;
bih.biSizeImage = dwWB * pSnapshot->height;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0; dwWriteLength = sizeof(BITMAPINFOHEADER);
WriteFile( hFile, (PVOID)&bih, dwWriteLength, &dwWrittenLength, NULL ); if( nBpp == 16 ) { DWORD argbQuad[3] = {0};
if (renderFormat == RENDER_FORMAT_RGB565)
{
argbQuad[0] = 0x00F800; // Red mask
argbQuad[1] = 0x0007E0; // Green mask
argbQuad[2] = 0x00001F; // Blue mask
}
else
{
argbQuad[0] = 0x007C00; // Red mask
argbQuad[1] = 0x0003E0; // Green mask
argbQuad[2] = 0x00001F; // Blue mask
}
dwWriteLength = sizeof(argbQuad);
WriteFile( hFile, (PVOID)&argbQuad[0], dwWriteLength, &dwWrittenLength, NULL );
}
else
if( nBpp == 24 ) {
DWORD rgbQuad = 0;
dwWriteLength = sizeof(rgbQuad);
WriteFile( hFile, (PVOID)&rgbQuad, dwWriteLength, &dwWrittenLength, NULL );
}
else if( nBpp == 32 ) {
DWORD rgbQuad = 0;
dwWriteLength = sizeof(rgbQuad);
WriteFile( hFile, (PVOID)&rgbQuad, dwWriteLength, &dwWrittenLength, NULL );
} dwWriteLength = dwWB * pSnapshot->height;
WriteFile( hFile, (PVOID)pbuf, dwWriteLength, &dwWrittenLength, NULL );
CloseHandle( hFile ); if (dwWrittenLength < 1)
{
DeleteFile(pSnapshot->filename);
}
}
else if (image_format == 0x01)
{
//JPG
int iFilenameLen = (int)strlen(pSnapshot->filename); if ( (0 != memcmp(pSnapshot->filename+iFilenameLen-3, "jpg", 3)) &&
(0 != memcmp(pSnapshot->filename+iFilenameLen-3, "JPG", 3)) &&
(0 != memcmp(pSnapshot->filename+iFilenameLen-3, "Jpg", 3)) )
{
if (pSnapshot->filename[iFilenameLen-4] == '.')
{
for (int i=iFilenameLen-1; i>0; i--)
{
if (pSnapshot->filename[i] == '.')
{
pSnapshot->filename[i] = '\0';
break;
}
else
{
pSnapshot->filename[i] = '\0';
}
}
}
strcat(pSnapshot->filename, ".jpg");
} BOOL bres = TRUE;
IJLERR jerr;
DWORD dibPadBytes;
JPEG_CORE_PROPERTIES jcprops; __try
{
jerr = ijlInit(&jcprops); if (IJL_OK != jerr)
{
bres = FALSE;
__leave;
} dibPadBytes = IJL_DIB_PAD_BYTES(dwW, 3); jcprops.DIBWidth = dwW;
jcprops.DIBHeight = dwH;
jcprops.DIBBytes = (unsigned char*)pbuf;//reinterpret_cast<BYTE *>(&pbi->bmiHeader) + sizeof(BITMAPINFOHEADER); jcprops.DIBPadBytes = dibPadBytes;
jcprops.DIBChannels = 3;
jcprops.DIBColor = IJL_BGR; jcprops.JPGFile = const_cast<LPSTR>(pSnapshot->filename); jcprops.JPGWidth = dwW;
jcprops.JPGHeight = dwH; jcprops.JPGChannels = 3;
jcprops.JPGColor = IJL_YCBCR;
jcprops.JPGSubsampling = IJL_411;
jcprops.jquality = 95; jerr = ijlWrite(&jcprops, IJL_JFILE_WRITEWHOLEIMAGE); if (IJL_OK != jerr)
{
if (IJL_FILE_ERROR == jerr)
{
}
ret = jerr;
bres = FALSE; if (ret == -23)
{
DeleteFile(pSnapshot->filename);
}
}
} __finally
{
ijlFree(&jcprops);
} } if (NULL != pDest)
{
delete []pDest;
pDest = NULL;
} return ret;
}

关于EasyPlayerPro

EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP、RTMP、HTTP、HLS、UDP、RTP、File等多种流媒体协议播放、支持本地文件播放,支持本地抓拍、本地录像、播放旋转、多屏播放、倍数播放等多种功能特性,核心基于ffmpeg,稳定、高效、可靠、可控,支持Windows、Android、iOS三个平台,目前在多家教育、安防、行业型公司,都得到的应用,广受好评!

EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro

点击链接加入群【EasyPlayer & EasyPlayerPro】:544917793

获取更多信息

邮件:support@easydarwin.org

EasyDarwin开源流媒体服务器:www.EasyDarwin.org

EasyDSS商用流媒体解决方案:www.EasyDSS.com

EasyNVR无插件直播方案:www.EasyNVR.com

Copyright © EasyDarwin Team 2012-2017

EasyPlayerPro Windows播放器本地快照抓拍截图功能实现方法的更多相关文章

  1. EasyPlayerPro windows播放器本地音频播放音量控制实现

    背景描述 作为一个播放器, 除了能播放视频和声音外,音量控制是绝对不能缺少的功能; 本文在音视频播放的基础上,增加对音量的控制: 实现流程 调用mixerGetDevCaps获取音频输出设备列表; 打 ...

  2. EasyPlayerPro windows播放器本地配置文件配置方法介绍

    需求背景 应EasyPlayerPro某客户需求,在EasyPlayerPro启动时,自动播放指定的url源, 不需要每次都去手动填写, 且实现自动播放,不需要手动的单击播放按钮: 为响应该需求,特增 ...

  3. EasyPlayerPro Windows播放器进行本地对讲喊话音频采集功能实现

    需求 在安防行业应用中,除了在本地看到摄像机的视频和进行音频监听外,还有一个重要的功能,那就是对讲. EasyPlayerPro-win为了减轻二次开发者的工作量,将本地音频采集也进行了集成: 功能特 ...

  4. EasyPlayerPro windows播放器在播放RTMP视频显示重复异常问题解决

    问题来源 2017.12.18 今日有杭州某教育领域客户反馈EasyPlayerPro在播放一个rtmp源时,画面显示异常的问题.截图如下: 问题复现 一番思考, 将显示格式改为D3D显示, 正常, ...

  5. EasyPlayerPro Windows播放器读取xml配置文件中的特殊字符问题

    问题被反馈 今日一客户反馈说播放不了带用户名密码的流, 奇怪,这个问题不存在啊-,按照客户的说法, 是将url地址保存在配置文件中,然后再打开EasyPlayerPro运行: 问题复现 在EasyPl ...

  6. EasyPlayerPro Windows播放器电子放大/局部放大播放功能实现

    背景描述 在视频监控软件中,我们看到很多的软件都有电子放大功能, 按住鼠标左键不放,框选一个区域,再松开鼠标左键,即对选中的区域进行放大显示, 且可以重复该操作,逐步放大所需显示的区域, 有没有觉得, ...

  7. EasyPlayerPro Windows播放器实时流进行本地缓冲区即时回放功能实现

    背景描述 参照国内视频监控行业监控软件,实现当前视频的即时回放功能,例如: 监控人员发现刚刚的某个视频点有可疑,就像录像回放一样,想倒回去看一下,但又不想切换到录像回放界面, 此处就体现即时回放的价值 ...

  8. EasyPlayerPro Windows播放器全屏模式下GDI显示出现黑屏问题解决

    问题来源 2017.12.21 前天有杭州某教育领域客户反馈有部分视频源在全屏模式下显示黑屏: 问题复现 EasyPlayerPro由于没有实现单个窗口完全全屏,故没有暴露该问题,晚上加班,加上单个窗 ...

  9. EasyPlayer RTSP Windows播放器D3D,GDI的几种渲染方式的选择区别

    EasyPlayer-RTSP windows播放器支持D3D和GDI两种渲染方式,其中D3D支持格式如下: DISPLAY_FORMAT_YV12 DISPLAY_FORMAT_YUY2 DISPL ...

随机推荐

  1. 代码Rework中的反思

    以前编码只是关注能写出来,并让程序运行就完事,这是非常错误的想法. 让我们重新思考软件设计中的一些问题吧! 软件设计就像设计房屋,设计器具,是一个道理.软件的复杂度和bug完全是自己造成的,要设计好的 ...

  2. 基于Java实现的选择排序算法

    选择排序和冒泡排序同样是基础排序算法,现在也做个学习积累. 简述 选择排序算法较为稳定,基本上都是O(n2)的时间复杂度,规模越小排序越快,不需要占用额外空间.其实选择排序原理很简单,就是在未排序序列 ...

  3. 转:Java多线程学习(总结很详细!!!)

    Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程 ...

  4. SecureCRT发送键盘按键对应表(转义字符)

    \r 发送回车(CR) \n 发送换行符(LF) \b 发送退格 \e 发送一个转义 \t 发送一个标签 \\ 发送一个反斜杠字符 \v 将剪贴板的内容粘贴到活动状态会话窗口 \p 暂停一秒钟

  5. Manifest值冲突解决方法

    FBI Warning:欢迎转载,但请标明出处:http://blog.csdn.net/codezjx/article/details/38669939,未经本人同意请勿用于商业用途,感谢支持! 整 ...

  6. Django 创建APP - 简单路由系统案例

    架构图: setting.py: INSTALLED_APPS = [ ... 'bootstrap', ] myapp -> myapp -> urls.py from django.c ...

  7. Oracle递归操作

    需求:找出代理商中没有挂商家的代理商 简单SQL如下: select * from t_proxy tp where tp.id not in (SELECT tp.id as p_id FROM t ...

  8. JAVA Eclipse ActivityManager Warning Activity not started, its current task has been brought to the front怎么办

    Eclipse运行提示Activity not started,因为当前程序已经在运行,需要退出当前程序再测试

  9. Android 百度地图开发(二)

    这一篇文章主要解说的是百度地图的定位功能,然后还有MyLocationOverlay和PopupOverlay两个地图覆盖物的使用.Overlay是"图层"或"覆盖物&q ...

  10. linux驱动开发重点关注内容--摘自《嵌入式Linux驱动模板精讲与项目实践》

    本文摘自本人拙著 <嵌入式Linux驱动模板精讲与项目实践> 初步看起来Linux设备驱动开发涉及内容非常多,而须要实现驱动的设备千差万别.事实上做一段时间驱动之后回首看来主要就是下面几点 ...