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

来源:互联网 发布:如何新建数据库表 编辑:程序博客网 时间:2024/06/05 03:09

背景描述

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

实现流程

  • 在视频播放时, 将收到的帧数据写入待解码播放队列;
  • 当用户切换到即时回放功能, 则停止解码当前的帧;
  • 在解码线程中修改用者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

获取更多信息

邮件:support@easydarwin.org

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

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

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

Copyright © EasyDarwin Team 2012-2017

EasyDarwin

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 四轴撕碎机 四线锁边机穿线图示 四齿辊破碎机 2018年前后驱钦机福达四驱四缸 四杀英文 英雄杀免费领四星英雄 英雄杀四星林冲免费送 一诺四杀队友 一诺关羽四杀队友 一诺关羽杀队友 杀杀手娘亲一胎四宝贝 刘金定力杀四门 英雄杀三宝四废是什么意思 双杀三杀四杀五杀英文 一杀二杀三杀四杀五杀英文 烬为什么杀四个英雄 戏命师杀了哪四个英雄 龙小羽为什么杀祝四萍 中国象棋开局四步杀 夏侯四杰 许氏四杰 唐初四杰 盛唐四杰 建筑四杰 许氏四杰现状 宇智波狂笑四杰 初唐四杰集是谁 宇都紫宫苑四虎新板 新四板上市条件 新三板与新四板的区别 新四板是什么 四板市场 四柱预l测 四柱预测学 四柱预 排四柱 四柱暖气片 四柱测算 四柱推命 四柱查询 四柱十神