背景描述

在视频监控软件中,我们看到很多的软件都有电子放大功能, 按住鼠标左键不放,框选一个区域,再松开鼠标左键,即对选中的区域进行放大显示, 且可以重复该操作,逐步放大所需显示的区域, 有没有觉得,这个功能在视频监控软件中还是有他的用武地. 今天我们就来实现该功能;

实现流程

//设置电子放大起起始点
int SetElectronicZoomStartPoint(int channelId, float fXPercent, float fYPercent, unsigned char showBox);
//设置电子放大结束点(在鼠标移动过程中可一直调用该函数)
int SetElectronicZoomEndPoint(int channelId, float fXPercent, float fYPercent);
//设置是否放大显示
int SetElectronicZoom(int channelId, int zoomIn);
//复位
void ResetElectronicZoom(int channelId);
//直接设置显示区域,用于电子放大, 在某些场合, 需要直接进行缩放显示, 即可调用该函数实现
int SetRenderRect(int channelId, LPRECT lpSrcRect);

代码实现

int ChannelManager::ElectronicZoomProcess(MEDIA_VIDEO_CHANNEL_OBJ_T *pMediaChannel, EASY_FRAME_INFO *frameInfo)
{
if (NULL == pMediaChannel) return 0;
if (NULL == frameInfo) return 0; ELECTRONIC_ZOOM_T *pElectoricZoom = pMediaChannel->pElectoricZoom;
if (NULL == pElectoricZoom) return 0; int nLeft = 0, nTop = 0, nRight = 0, nBottom = 0;
if (pElectoricZoom->zoomIn >= 0x01)
{
RECT rcClient;
GetClientRect(pMediaChannel->mediaDisplay.hWnd, &rcClient); float fLeftPercent = pElectoricZoom->fStartPointX;
float fTopPercent = pElectoricZoom->fStartPointY;
float fRightPercent = pElectoricZoom->fEndPointX;
float fBottomPercent = pElectoricZoom->fEndPointY; if (fRightPercent > fLeftPercent && fBottomPercent > fTopPercent) //逐步放大
{
if (pElectoricZoom->fVideoWidth > 0)
{
int video_width = (int)pElectoricZoom->fVideoWidth;
int video_height= (int)pElectoricZoom->fVideoHeight;
nLeft = (int)((float)video_width / 100.0f * fLeftPercent);
nTop = (int)((float)video_height/ 100.0f * fTopPercent);
nRight = (int)((float)video_width / 100.0f * fRightPercent);
nBottom = (int)((float)video_height/ 100.0f * fBottomPercent); if (nRight > nLeft && nBottom > nTop)
{
pElectoricZoom->fVideoWidth = (float)(nRight - nLeft);
pElectoricZoom->fVideoHeight = (float)(nBottom - nTop); nLeft = pElectoricZoom->startVideoLeft + nLeft;
nTop = pElectoricZoom->startVideoTop + nTop;
nRight = pElectoricZoom->startVideoLeft + nRight;
nBottom = pElectoricZoom->startVideoTop + nBottom; pElectoricZoom->startVideoLeft = nLeft;
pElectoricZoom->startVideoTop = nTop; if (pElectoricZoom->zoomIndex + 1 <MAX_ZOOM_IN_TIMES)
{
SetRect(&pElectoricZoom->zoomParam[pElectoricZoom->zoomIndex].rect, nLeft, nTop, nRight, nBottom);
pElectoricZoom->zoomParam[pElectoricZoom->zoomIndex].fVideoWidth = pElectoricZoom->fVideoWidth;
pElectoricZoom->zoomParam[pElectoricZoom->zoomIndex].fVideoHeight = pElectoricZoom->fVideoHeight;
pElectoricZoom->zoomParam[pElectoricZoom->zoomIndex].startVideoLeft = pElectoricZoom->startVideoLeft;
pElectoricZoom->zoomParam[pElectoricZoom->zoomIndex].startVideoTop = pElectoricZoom->startVideoTop;
pElectoricZoom->zoomIndex ++;
}
}
else
{
int idx = pElectoricZoom->zoomIndex-2;
if (idx > 0)
{
nLeft = pElectoricZoom->zoomParam[idx].rect.left;
nTop = pElectoricZoom->zoomParam[idx].rect.top;
nRight = pElectoricZoom->zoomParam[idx].rect.right;
nBottom = pElectoricZoom->zoomParam[idx].rect.bottom; pElectoricZoom->fVideoWidth = pElectoricZoom->zoomParam[idx].fVideoWidth;
pElectoricZoom->fVideoHeight = pElectoricZoom->zoomParam[idx].fVideoHeight;
pElectoricZoom->startVideoLeft = pElectoricZoom->zoomParam[idx].startVideoLeft;
pElectoricZoom->startVideoTop = pElectoricZoom->zoomParam[idx].startVideoTop;
}
}
}
else
{
int video_width = frameInfo->width;
int video_height= frameInfo->height;
nLeft = (int)((float)video_width / 100.0f * fLeftPercent);
nTop = (int)((float)video_height/ 100.0f * fTopPercent);
nRight = (int)((float)video_width / 100.0f * fRightPercent);
nBottom = (int)((float)video_height/ 100.0f * fBottomPercent); pElectoricZoom->startVideoLeft = nLeft;
pElectoricZoom->startVideoTop = nTop;
pElectoricZoom->fVideoWidth = (float)(nRight - nLeft);
pElectoricZoom->fVideoHeight = (float)(nBottom - nTop); SetRect(&pElectoricZoom->zoomParam[0].rect, nLeft, nTop, nRight, nBottom);
pElectoricZoom->zoomParam[0].fVideoWidth = pElectoricZoom->fVideoWidth;
pElectoricZoom->zoomParam[0].fVideoHeight = pElectoricZoom->fVideoHeight;
pElectoricZoom->zoomParam[0].startVideoLeft = pElectoricZoom->startVideoLeft;
pElectoricZoom->zoomParam[0].startVideoTop = pElectoricZoom->startVideoTop;
pElectoricZoom->zoomIndex ++;
}
}
else
{
if (pElectoricZoom->zoomIndex > 1)
{
int idx = pElectoricZoom->zoomIndex-2; nLeft = pElectoricZoom->zoomParam[idx].rect.left;
nTop = pElectoricZoom->zoomParam[idx].rect.top;
nRight = pElectoricZoom->zoomParam[idx].rect.right;
nBottom = pElectoricZoom->zoomParam[idx].rect.bottom; pElectoricZoom->fVideoWidth = pElectoricZoom->zoomParam[idx].fVideoWidth;
pElectoricZoom->fVideoHeight = pElectoricZoom->zoomParam[idx].fVideoHeight;
pElectoricZoom->startVideoLeft = pElectoricZoom->zoomParam[idx].startVideoLeft;
pElectoricZoom->startVideoTop = pElectoricZoom->zoomParam[idx].startVideoTop; pElectoricZoom->zoomIndex --;
}
else
{
pElectoricZoom->fVideoWidth = 0.0f; nLeft = 0;
nTop = 0;
nRight = frameInfo->width;
nBottom = frameInfo->height; pElectoricZoom->zoomIndex = 0;
}
} RECT rcSrc;
SetRect(&rcSrc, nLeft, nTop, nRight, nBottom);
CopyRect(&pMediaChannel->mediaDisplay.rcSrcRender, &rcSrc); pElectoricZoom->zoomIn --;
} return 0;
}

关于EasyPlayerPro

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

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

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

技术支持

EasyPlayerPro是一款非常稳定的全协议/全功能播放器组件,各平台版本需要经过授权才能商业使用,商业授权方案可以通过以上渠道进行更深入的技术与合作咨询;

获取更多信息

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-win为了减轻二次开发者的工作量,将本地音频采集也进行了集成: 功能特 ...

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

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

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

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

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

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

  6. EasyPlayerPro Windows播放器本地快照抓拍截图功能实现方法

    背景描述 作为一个播放器,截图功能必不可少; 下面主要记录一下截图功能的实现: 实现流程 将解码后的帧进行格式转换(目标格式为RGB24); 采用独立的线程进行截图处理; 截图可保存为BMP或JPG两 ...

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

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

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

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

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

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

随机推荐

  1. Educational Codeforces Round 34 D. Almost Difference【模拟/stl-map/ long double】

    D. Almost Difference time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  2. cdq分治解决区间问题

    如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含 ...

  3. Hdoj 5181 numbers

    numbers Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 196608/196608 K (Java/Others)Total ...

  4. 2016北京集训测试赛(十六)Problem B: river

    Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...

  5. path.join 与 path.resolve 的区别

    1. 对于以/开始的路径片段,path.join只是简单的将该路径片段进行拼接,而path.resolve将以/开始的路径片段作为根目录,在此之前的路径将会被丢弃,就像是在terminal中使用cd命 ...

  6. 原生js获取元素的样式信息

    工作中经常会需要获取DOM元素的样式,之前都是通过jquery的css()方法,现在总结一下通过原生js获取元素样式的方法. obj.style js var _width = obj.style.w ...

  7. Android Gradle 经验总结

    用过android studio的对gradle应该都不陌生了,gradle文件的基本配置大同小异,略做了解使用应该是没什么问题了.但是深入细致的了解一下对于理解项目还是很有帮助的,尤其是遇到一些配置 ...

  8. ORACLE中SID和SERVICE_NAME的区别

      先来讲一个小故事,2015年6月份,有个客户迁移了数据库,由单实例数据库变成了RAC.JAVA应用程序出现了无法连接数据库的情况,但是PL/SQL能连接上数据库.由于项目比较庞大,虽然在半夜切换的 ...

  9. 每天学一点Python(2)

    9月16日(python扩展的安装和使用) 接着上一篇继续.按照之前计划,先分析导出的数据,再做进一步统计. 导出的数据是html类型的,想到的处理方法有: 1.直接readlines然后一行一行找我 ...

  10. php分页显示文章列表

    <div class="content"> <ul> <?php $querySel = "select * from news where ...