背景描述

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

实现流程

  • 将解码后的帧进行格式转换(目标格式为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. android studio 按钮运行按钮后,不弹出选择运行模拟器的对话框

    这个问题实际上很简单,奈何碰到的时候做了很多无用功.clean,rebulid... 特此记录,方便后来人. 解决步骤: 1.关闭AndroidStudio,并重启. 2. 把截图中的地方的勾去掉.检 ...

  2. 洛谷——1508 Likecloud-吃、吃、吃

    题目背景 问世间,青春期为何物? 答曰:“甲亢,甲亢,再甲亢:挨饿,挨饿,再挨饿!” 题目描述 正处在某一特定时期之中的李大水牛由于消化系统比较发达,最近一直处在饥饿的状态中.某日上课,正当他饿得头昏 ...

  3. java 之webmagic 网络爬虫

    webmagic简介: WebMagic是一个简单灵活的Java爬虫框架.你可以快速开发出一个高效.易维护的爬虫. http://webmagic.io/ 准备工作: Maven依赖(我这里用的Mav ...

  4. Ubuntu 16.04安装深度的Wine(deepin-wine 1.9.0)

    说明: 1.使用的Wine版本是深度出品(Deepin),已经精简了很多没用的配置,使启动能非常快,占用资源小. 2.提取自QQ和迅雷安装包,如果安装了这个Wine不成功,可能是依赖问题,再试多几次, ...

  5. mysql-实现远程连接(授权法)

    远程连接阿里云主机的mysql,遇到以下问题: 1.连接被拒,无法连接 可能原因:1.3306(默认)端口未开放,在控制台设置防火墙规则: 2. host字段的值改为%就表示在任何客户端机器上能以ro ...

  6. ASIHTTPRequest, request sent twice

    ´ve just started using ASIHTTPRequest for iOs and I have a small issue with it. All requests are sen ...

  7. Android Spinner In Toolbar

    As the title of the post suggest in this tutorial we will see how to have spinner widget inside the ...

  8. 处理类型(typedef,uisng,auto,decltype)

    一:类型别名是一个名字,它是某种类型的定价.有两种方法定义类型别名: 1.使用typedef关键字,如: typedef int *Int_Ptr Int_Ptr p=nullptr;   //Int ...

  9. nginx 配置静态目录 访问bootstrap

    location /static/ { alias /Users/wangziqiang/djangoprojects/bpmTest/static/; } 注意  /static/   中 /的完整 ...

  10. php 报错等级

    定义和用法:    error_reporting() 设置 PHP 的报错级别并返回当前级别. 函数语法:    error_reporting(report_level) 如果参数 level 未 ...