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端播放器在多窗口大屏显示的场景下尤其需要,尽管我们老早就有了实时静音接口,相对 ...
随机推荐
- Codeforces 897 C.Nephren gives a riddle-递归
C. Nephren gives a riddle time limit per test 2 seconds memory limit per test 256 megabytes input ...
- Java中Properties配置文件读取
以下实践的是Properties配置文件的基本操作方法.像spring使用xml做依赖注入时,这个配置文件起到非常实用的作用. 一.格式规范 参考wiki百科的格式简介:https://zh.wiki ...
- eclipse中mybatis generator插件的安装与使用,实现自动生成代码
git地址:https://github.com/mybatis/generator 下载后解压: 选择任意一个版本的jar放到eclipse的features目录下即可 选择任意一个版本的jar放到 ...
- Picasso,Glide,Fresco那个好?
前言:在Android开发中,图片加载OOM一直困扰着很多开发者,在各种不合理的设计之下也容易导致图片加载OOM的问题,目前开源的比较常用的图片加载库也很多,比如老牌的UIL,Volley,AQuer ...
- Learn How To Create Trigger In Oracle Forms
I have written many posts related to triggers in Oracle Forms, I have given examples for Form Level ...
- linux命令lsattr、chattr、man
1.man命令,可以查看手册 配置位置/etc/man.conf MANPATH决定手册查询位置 MANSECT决定man查询的顺序 man的查询 linux man的常用用法: man sectio ...
- VS中Debug模式和Release模式的区别
一.Debug 和 Release 编译方式的本质区别 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使得程 ...
- Cocos2d-x中Vector<T>容器以及实例介绍
Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容纳的是Ref及子类所创建的对象指针,其中的T是模板,表示能够放入到容器中的类型,在Cocos2d-x 3.x中T ...
- 【Python】合并(拼接)字符串
在很多情况下,我们都需要合并字符串.例如:需要将姓氏与名字存储在不同的变量中,然后显示的时候再将他们合二为一 first_name = 'oliver' last_name = 'smith' ful ...
- 面试宝典之预处理、const与sizeof
#include <stdio.h> #define SUB(x, y) x - y #define ACCESS_BEFORE(element, offset, value) *SUB( ...