EasyPlayerPro Windows播放器实时流进行本地缓冲区即时回放功能实现
背景描述
参照国内视频监控行业监控软件,实现当前视频的即时回放功能,例如: 监控人员发现刚刚的某个视频点有可疑,就像录像回放一样,想倒回去看一下,但又不想切换到录像回放界面, 此处就体现即时回放的价值了,还可将回放片断保存为录像文件;
实现流程
- 在视频播放时, 将收到的帧数据写入待解码播放队列;
- 当用户切换到即时回放功能, 则停止解码当前的帧;
- 在解码线程中修改用者ID(涉及到缓冲队列的设计);
- 解码线程一直读取历史队列中的帧进行解码显示;
- 当读到队列的最后一帧时,再从头开始循环;
代码实现
//即时回放处理: 将当前正在播放的缓冲队列中的数据,拷贝到即时回放队列, 然后从即时回放队列中读取数据进行回放
int ChannelManager::InstantReplayProcess(MEDIA_VIDEO_CHANNEL_OBJ_T *pMediaChannel, CONSUMER_HANDLE *handle,
BUFFER_TYPE_ENUM *bufferType, int *headerSize, char *headerData, int *payloadSize, char *payloadData)
{
if (NULL == pMediaChannel) return -1;
int ret = -1;
CONSUMER_HANDLE consumerHandle = *handle;
if (NULL == pMediaChannel->pInstantReplay) return -1;
if ( pMediaChannel->pInstantReplay->instantReplay == 0x01 )
{
if (NULL == pMediaChannel->pInstantReplay->bufQueueHandle) //创建即时回放缓冲队列
{
//创建即时回放缓冲区
int queueSize = pMediaChannel->pSourcePtr->GetQueueSize();
BUFQUE_Create(&pMediaChannel->pInstantReplay->bufQueueHandle, 0, NULL, queueSize, MAX_PRE_RECORDING_SECS, 0, 1);
//此处将sourcePtr中的bufqueue拷贝到 即时回放中的缓冲区
CONSUMER_HANDLE consumerHandleInstantReplay = BUFQUE_RegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle,
(unsigned int)pMediaChannel, 0x00);
if (NULL == consumerHandleInstantReplay)
{
_TRACE(TRACE_LOG_DEBUG, "channel[%d]注册即时回放调用者失败.\n", pMediaChannel->id);
BUFQUE_Release(&pMediaChannel->pInstantReplay->bufQueueHandle);
return ret;
}
*handle = consumerHandleInstantReplay;
consumerHandle = consumerHandleInstantReplay;
pMediaChannel->pInstantReplay->consumerHandle = BUFQUE_RegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle,
(unsigned int)pMediaChannel->pInstantReplay,
0x00); //再注册一个,用于和consumerHandleInstantReplay循环使用
pMediaChannel->pInstantReplay->frameNum = 0;
pMediaChannel->pInstantReplay->frameNo = 0;
BUFFER_TYPE_ENUM bufferType = BUFFER_TYPE_UNKNOWN;
CONSUMER_HANDLE consumerHandleTmp = NULL;
consumerHandleTmp = pMediaChannel->pSourcePtr->RegisterConsumer((unsigned int)&pMediaChannel->pInstantReplay, 0x01);
//从当前正在播放的缓冲队列中,拷贝数据到即时回放队列
if (NULL != consumerHandleTmp)
{
int headerSize = 0;
EASY_FRAME_INFO tmpFrameInfo;
memset(&tmpFrameInfo, 0x00, sizeof(EASY_FRAME_INFO));
BUFF_T buffSource;
memset(&buffSource, 0x00, sizeof(BUFF_T));
BUFF_MALLOC(&buffSource, MAX_ENCODE_FRAME_SIZE); //最大编码帧大小为MAX_ENCODE_FRAME_SIZE(1024*1024)
int writeKeyFrame = 0x00;
int bufferId = 0;
do
{
//从队列中获取音视频和事件数据
bufferType = BUFFER_TYPE_UNKNOWN;
if (0 != pMediaChannel->pSourcePtr->GetSourceData(consumerHandleTmp, NULL, &bufferType,
&headerSize, (char *)&tmpFrameInfo, &buffSource.bufpos, buffSource.pbuf, 0x01))
{
break;
}
//保证第一帧为视频关键帧
if (writeKeyFrame == 0x01 || ( BUFFER_TYPE_VIDEO == bufferType && tmpFrameInfo.type == FRAME_TYPE_I) )
{
BUFQUE_AddData(pMediaChannel->pInstantReplay->bufQueueHandle, ++bufferId, bufferType, headerSize, (char *)&tmpFrameInfo, buffSource.bufpos, buffSource.pbuf);
writeKeyFrame = 0x01;
pMediaChannel->pInstantReplay->frameNum ++;
//pMediaChannel->pInstantReplay->frameNo = 0;
}
}while (1);
BUFF_FREE(&buffSource);
pMediaChannel->pSourcePtr->UnRegisterConsumer(&consumerHandleTmp);
}
}
//当前对即时回放队列进行录像
if (pMediaChannel->pInstantReplay->recording == 0x01)
{
pMediaChannel->pInstantReplay->recording = 0x00;
InstantReplayRecording(pMediaChannel); //即时回放录像
}
if (pMediaChannel->pInstantReplay->status==PLAY_SPEED_PAUSED)
{
if (pMediaChannel->pInstantReplay->instantReplay == 0x00) //暂停状态时, 上层已调用关闭即时回放
{
if (NULL != pMediaChannel->pInstantReplay->bufQueueHandle)
{
if (NULL != consumerHandle)
{
BUFQUE_UnRegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle, &consumerHandle);
*handle = NULL;
}
if (NULL != pMediaChannel->pInstantReplay->consumerHandle)
{
BUFQUE_UnRegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle, &pMediaChannel->pInstantReplay->consumerHandle);
}
BUFQUE_Release(&pMediaChannel->pInstantReplay->bufQueueHandle);
}
delete pMediaChannel->pInstantReplay;
pMediaChannel->pInstantReplay = NULL;
}
return 0;
}
ret = BUFQUE_GetData(pMediaChannel->pInstantReplay->bufQueueHandle, consumerHandle, NULL, bufferType, headerSize, headerData, payloadSize, payloadData, 0x01);
if (ret < 0)
{
BUFQUE_CopyConsumer(pMediaChannel->pInstantReplay->bufQueueHandle, consumerHandle, pMediaChannel->pInstantReplay->consumerHandle);
ret = BUFQUE_GetData(pMediaChannel->pInstantReplay->bufQueueHandle, consumerHandle, NULL, bufferType, headerSize, headerData, payloadSize, payloadData, 0x01);
if (ret == 0x00) pMediaChannel->pInstantReplay->frameNo = 1;
else pMediaChannel->pInstantReplay->frameNo = 0;
}
else if (ret == 0 && *bufferType==BUFFER_TYPE_VIDEO)
{
pMediaChannel->pInstantReplay->frameNo ++;
}
}
else if (pMediaChannel->pInstantReplay->instantReplay == 0x00) //关闭即时回放
{
if (NULL != pMediaChannel->pInstantReplay->bufQueueHandle)
{
if (NULL != consumerHandle)
{
BUFQUE_UnRegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle, &consumerHandle);
*handle = NULL;
}
if (NULL != pMediaChannel->pInstantReplay->consumerHandle)
{
BUFQUE_UnRegisterConsumer(pMediaChannel->pInstantReplay->bufQueueHandle, &pMediaChannel->pInstantReplay->consumerHandle);
}
BUFQUE_Release(&pMediaChannel->pInstantReplay->bufQueueHandle);
}
delete pMediaChannel->pInstantReplay;
pMediaChannel->pInstantReplay = NULL;
ret = 100;
}
return ret;
}
关于EasyPlayerPro
EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP、RTMP、HTTP、HLS、UDP、RTP、File等多种流媒体协议播放、支持本地文件播放,支持本地抓拍、本地录像、播放旋转、多屏播放、倍数播放等多种功能特性,核心基于ffmpeg,稳定、高效、可靠、可控,支持Windows、Android、iOS三个平台,目前在多家教育、安防、行业型公司,都得到的应用,广受好评!
EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro
点击链接加入群【EasyPlayer & EasyPlayerPro】:544917793
获取更多信息
EasyDarwin开源流媒体服务器:www.EasyDarwin.org
EasyDSS商用流媒体解决方案:www.EasyDSS.com
EasyNVR无插件直播方案:www.EasyNVR.com
Copyright © EasyDarwin Team 2012-2017

EasyPlayerPro Windows播放器实时流进行本地缓冲区即时回放功能实现的更多相关文章
- EasyPlayerPro windows播放器本地配置文件配置方法介绍
需求背景 应EasyPlayerPro某客户需求,在EasyPlayerPro启动时,自动播放指定的url源, 不需要每次都去手动填写, 且实现自动播放,不需要手动的单击播放按钮: 为响应该需求,特增 ...
- EasyPlayerPro windows播放器本地音频播放音量控制实现
背景描述 作为一个播放器, 除了能播放视频和声音外,音量控制是绝对不能缺少的功能; 本文在音视频播放的基础上,增加对音量的控制: 实现流程 调用mixerGetDevCaps获取音频输出设备列表; 打 ...
- EasyPlayerPro Windows播放器进行本地对讲喊话音频采集功能实现
需求 在安防行业应用中,除了在本地看到摄像机的视频和进行音频监听外,还有一个重要的功能,那就是对讲. EasyPlayerPro-win为了减轻二次开发者的工作量,将本地音频采集也进行了集成: 功能特 ...
- EasyPlayerPro Windows播放器本地快照抓拍截图功能实现方法
背景描述 作为一个播放器,截图功能必不可少; 下面主要记录一下截图功能的实现: 实现流程 将解码后的帧进行格式转换(目标格式为RGB24); 采用独立的线程进行截图处理; 截图可保存为BMP或JPG两 ...
- EasyPlayerPro Windows播放器读取xml配置文件中的特殊字符问题
问题被反馈 今日一客户反馈说播放不了带用户名密码的流, 奇怪,这个问题不存在啊-,按照客户的说法, 是将url地址保存在配置文件中,然后再打开EasyPlayerPro运行: 问题复现 在EasyPl ...
- EasyPlayerPro windows播放器在播放RTMP视频显示重复异常问题解决
问题来源 2017.12.18 今日有杭州某教育领域客户反馈EasyPlayerPro在播放一个rtmp源时,画面显示异常的问题.截图如下: 问题复现 一番思考, 将显示格式改为D3D显示, 正常, ...
- EasyPlayerPro Windows播放器电子放大/局部放大播放功能实现
背景描述 在视频监控软件中,我们看到很多的软件都有电子放大功能, 按住鼠标左键不放,框选一个区域,再松开鼠标左键,即对选中的区域进行放大显示, 且可以重复该操作,逐步放大所需显示的区域, 有没有觉得, ...
- EasyPlayerPro Windows播放器全屏模式下GDI显示出现黑屏问题解决
问题来源 2017.12.21 前天有杭州某教育领域客户反馈有部分视频源在全屏模式下显示黑屏: 问题复现 EasyPlayerPro由于没有实现单个窗口完全全屏,故没有暴露该问题,晚上加班,加上单个窗 ...
- Android、iOS平台RTMP/RTSP播放器实时音量调节
介绍移动端RTMP.RTSP播放器实时音量调节之前,我们之前也写过,为什么windows播放端加这样的接口,windows端播放器在多窗口大屏显示的场景下尤其需要,尽管我们老早就有了实时静音接口,相对 ...
随机推荐
- nodejs编写实例基础操作
学习视频地址 https://cnodejs.org/topic/5a72c66ace45d440451465c3 初始化项目 首先查看项目中是否有package.json 文件,如果有可执行np ...
- IOS view的圆角和阴影并存
记录一下这个简单但又难搞的问题,如何设置 view的圆角和阴影并存 UIView *v=[[UIView alloc]initWithFrame:CGRectMake(10, 10, 100, 100 ...
- ASP.NET MVC生成静态页面
1.先付上封装好生成静态页的原代码: public class Common { #region 获取模板页的Html代码 /// <summary> /// 获取页面的Html代码 // ...
- 洛谷 P1618 三连击(升级版)【DFS/next_permutation()/技巧性枚举/sprintf】
[链接]:https://www.luogu.org/problemnew/show/P1618 题目描述 将1,2,…,9共9个数分成三组,分别组成三个三位数,且使这三个三位数的比例是A:B:C,试 ...
- 好用的 HTTP模块SuperAgent
SuperAgent 最近在写爬虫,看了下node里面有啥关于ajax的模块,发现superagent这个模块灰常的好用.好东西要和大家分享,话不多说,开始吧- 什么是SuperAgent super ...
- PCA原理
http://blog.csdn.net/shizhixin/article/details/51181379
- dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito)
转:http://blog.csdn.net/yys79/article/details/66472797 最近,项目中频繁用到dubbo,而且java工程用引用了几十个关联系统的服务(如用户认证,基 ...
- POJ 题目3264 Balanced Lineup(RMQ)
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 39046 Accepted: 18291 ...
- PyInstaller把.py转为.exe
http://www.pyinstaller.org/ http://blog.csdn.net/hmy1106/article/details/45151409 python pyinstaller ...
- Android fragment (二)
怎样使用fragment? 1.首先你要确定下你有多少个fragment要使用在一个activity里. 2.依据你的fragment的数量,创建继承自fragment的class.然后依据实际需求重 ...