多路h265监控录放开发-(15)回放页面中的三个槽函数进行视频的录放(0.1版本项目完结篇)

xviewer.h 中的回放页面的三个槽函数:

    void SelectCamera(QModelIndex index);//选择摄像机129void SelectDate(QDate date);        //选择日期129void PlayVideo(QModelIndex index);  //选择时间播放视频129

SelectCamera槽函数解析:

点击相机列表日历显示该相机所录制的视频,如有则日期标为红色并放大字体,如四号有录制的视频那么四号变红放大点击进去可以回放视频


void XViewer::SelectCamera(QModelIndex index)//选择摄像机
{qDebug() << "SelectCamera" << index.row();auto conf = XCameraConfig::Instance();XCameraData cam = conf->GetCam(index.row()); //获取相机参数if (cam.name[0] == '\0'){return;}//相机视频存储路径stringstream ss;ss << cam.save_path << "/" << index.row() << "/";//遍历此目录QDir dir(C(ss.str().c_str()));if (!dir.exists())return;//获取目录下文件列表QStringList filters;filters << "*.mp4" << "*.avi";dir.setNameFilters(filters);//筛选ui.cal->ClearDate();//所有文件列表auto files = dir.entryInfoList();for (auto file : files){//"cam_2020_09_04_17_54_58.mp4"QString filename = file.fileName();//去掉cam_ 和 .mp4auto tmp = filename.left(filename.size() - 4);tmp = tmp.right(tmp.length() - 4);//2020_09_04_17_54_58auto dt = QDateTime::fromString(tmp, "yyyy_MM_dd_hh_mm_ss");qDebug() << dt.date();//yyyy_MM_dd形式ui.cal->AddDate(dt.date());//qDebug() << file.fileName();
130XCamVideo video;video.datetime = dt;video.filepath = file.absoluteFilePath();cam_videos[dt.date()].push_back(video);130}//重新显示日期ui.cal->showNextMonth();ui.cal->showPreviousMonth();}上面用到的结构体 和数据结构map
struct XCamVideo
{QString filepath;QDateTime datetime;
};
static map<QDate, vector<XCamVideo> > cam_videos;//通过点击QDate来索引一组数据
  • qDebug() << "SelectCamera" << index.row();

    • 打印调试信息,显示被选中的摄像机的行号。
  • auto conf = XCameraConfig::Instance();

    • 获取 XCameraConfig 类的单例实例,假设这是一个配置管理器。
  • XCameraData cam = conf->GetCam(index.row());

    • 通过行号获取对应的摄像机数据 XCameraData
  • if (cam.name[0] == '\0') { return; }

    • 检查摄像机的名称是否为空,如果是,则返回,终止函数执行。
  • stringstream ss; ss << cam.save_path << "/" << index.row() << "/";
  •  创建一个 stringstream 对象,将摄像机视频存储路径和行号组合成一个完整的目录路径。
  • QDir dir(C(ss.str().c_str()));
    • 创建一个 QDir 对象,表示生成的目录路径。
  • if (!dir.exists()) return;
    • 检查目录是否存在,如果不存在,返回,终止函数执行
    • QStringList filters; filters << "*.mp4" << "*.avi";
      • 创建一个 QStringList 对象,并添加视频文件的扩展名过滤器。
    • dir.setNameFilters(filters);
      • 设置 QDir 对象的名称过滤器,使其只包含指定扩展名的文件。
  • ui.cal->ClearDate();
    • 清除日历控件中的所有日期。
  • auto files = dir.entryInfoList();
    • 获取目录中的所有文件列表
  • for (auto file : files)
    • 遍历所有文件。
  • QString filename = file.fileName();
    • 获取文件名。
  • auto tmp = filename.left(filename.size() - 4);
    • 去掉文件名的扩展名部分(后四个字符)。
  • tmp = tmp.right(tmp.length() - 4);
    • 去掉文件名前缀部分(前四个字符)。
  • auto dt = QDateTime::fromString(tmp, "yyyy_MM_dd_hh_mm_ss");
    • 将处理后的文件名转换为 QDateTime 对象。
  • qDebug() << dt.date();
    • 打印调试信息,显示日期部分。
  • ui.cal->AddDate(dt.date());
    • 将日期添加到日历控件中。
  • XCamVideo video;
    • 创建一个 XCamVideo 对象。
  • video.datetime = dt; video.filepath = file.absoluteFilePath();
    • 设置 XCamVideo 对象的日期时间和文件路径。
  • cam_videos[dt.date()].push_back(video);
    • 将视频对象添加到以日期为键的 cam_videos 映射中,该映射在vector中
  • ui.cal->showNextMonth(); ui.cal->showPreviousMonth();
  • 重新显示日历控件的日期,确保更新后的日期显示正确。

总结

这个槽函数 SelectCamera(QModelIndex index) 主要完成以下任务:

  1. 获取选中的摄像机的配置信息。
  2. 构造摄像机视频文件存储路径。
  3. 检查路径是否存在,并筛选出 .mp4.avi 文件。
  4. 清除日历控件中的日期。
  5. 遍历筛选出的文件列表,提取文件名中的日期信息并转换为 QDateTime 对象。
  6. 将日期添加到日历控件中,并将视频文件的信息保存到 cam_videos 映射中。
  7. 重新显示日历控件,以反映更新后的日期。

SelectDate槽函数解析: 

点击日历上的日期显示该日期录制的视频时间列表

void XViewer::SelectDate(QDate date)        //选择日期
{qDebug() << "SelectDate" << date.toString();vector<XCamVideo> dates = cam_videos[date];//dates存的以下数据//struct XCamVideo//{//    QString filepath;//    QDateTime datetime;//};ui.time_list->clear();for (auto d : dates){//再QListwidget控件上添加项,显示的是具体时间QTime类型QListWidgetItem* item = new QListWidgetItem(d.datetime.time().toString());//将视频文件的路径存储在列表项的用户角色数据中。//Qt::UserRole 是一个预定义的角色值,用于存储用户自定义的数据。//在点击QListwidget列表项的时候会用到(PlayVideo槽函数中)item->setData(Qt::UserRole, d.filepath);ui.time_list->addItem(item);}
}

  • auto dates = cam_videos[date];
    • cam_videos 映射中获取与选定日期相关的视频数据列表。cam_videos 是一个以日期为键、以视频数据列表为值的映射。
  • ui.time_list->clear();
    • 清空 time_list 列表控件,以便重新填充新的数据。
  • for (auto d : dates)

    • 遍历选定日期的视频数据列表。
  • auto item = new QListWidgetItem(d.datetime.time().toString());

    • 创建一个新的 QListWidgetItem 项目,将视频文件的时间信息(提取自 d.datetime)设置为列表项的显示文本。
  • item->setData(Qt::UserRole, d.filepath);
    • 将视频文件的路径存储在列表项的用户角色数据中。Qt::UserRole 是一个预定义的角色值,用于存储用户自定义的数据。
  • ui.time_list->addItem(item);
    • 将创建的列表项添加到 time_list 列表控件中。

总结

槽函数 SelectDate(QDate date) 的主要功能是:

  1. 获取选定日期的视频文件数据列表。
  2. 清空当前时间列表控件。
  3. 遍历视频数据列表,为每个视频创建一个列表项,显示视频的时间信息。
  4. 将视频文件路径作为自定义数据存储在列表项中。
  5. 将列表项添加到时间列表控件中。

PlayVideo槽函数解析: 

void XViewer::PlayVideo(QModelIndex index)  //选择时间播放视频
{qDebug() << "PlayVideo" << index.row();auto item = ui.time_list->currentItem();if (!item)return;QString path = item->data(Qt::UserRole).toString();qDebug() << path;//建一个新的QT类 XPlayVideo,一个新的UI视图用于渲染录像播放录像static XPlayVideo play;play.Open(path.toLocal8Bit());play.show();
}

 其中XPlayVideo类的Open函数在 XplayVideo.cpp文件中:

XplayVideo.cpp

#include "xplayvideo.h"
void XPlayVideo::timerEvent(QTimerEvent* ev)
{if (!view_)return;auto f = decode_.GetFrame();if (!f)return;view_->DrawFrame(f);XFreeFrame(&f);
}
void XPlayVideo::Close()
{//关闭上次数据demux_.Stop();decode_.Stop();if (view_){view_->Close();delete view_;view_ = nullptr;}
}void XPlayVideo::closeEvent(QCloseEvent* ev)
{Close();
}bool XPlayVideo::Open(const char* url)
{if (!demux_.Open(url)) //解封装{return false;}auto vp = demux_.CopyVideoPara();if (!vp)return false;if (!decode_.Open(vp->para))//解码{return false;}demux_.set_next(&decode_);if (!view_)view_ = XVideoView::Create();view_->set_win_id((void*)winId());if (!view_->Init(vp->para)) //SDL渲染return false;//demux_.set_syn_type(XSYN_VIDEO);demux_.Start();decode_.Start();return true;
}
XPlayVideo::XPlayVideo(QWidget* parent): QWidget(parent)
{ui.setupUi(this);startTimer(10);
}XPlayVideo::~XPlayVideo()
{Close();
}

XPlayVideo::Open函数解析 

if (!demux_.Open(url))

  • 尝试打开并解封装(demux)视频流。如果失败,返回 false 终止操作。

auto vp = demux_.CopyVideoPara();

  • 复制视频参数。如果获取视频参数失败,返回 false 终止操作。
  • vp 是一个包含视频流参数的对象。

if (!decode_.Open(vp->para))

  • 尝试使用视频参数打开解码器。如果失败,返回 false 终止操作。

demux_.set_next(&decode_);

  • 设置解封装器的下一个处理模块为解码器。可能意味着解封装器在解封装出数据后会将其传递给解码器进行解码。

if (!view_) view_ = XVideoView::Create();

  • 如果渲染视图对象 view_ 尚未创建,则创建一个新的渲染视图对象。

view_->set_win_id((void*)winId());

  • 设置渲染视图对象的窗口 ID,以便渲染图像。winId() 可能是一个返回窗口 ID 的方法。

if (!view_->Init(vp->para))

  • 初始化渲染视图对象。如果初始化失败,返回 false 终止操作。
  • vp->para 传递视频参数用于初始化。
  • demux_.Start();decode_.Start();

    • 启动解封装器和解码器。
    • demux_.Start() 开始解封装过程。
    • decode_.Start() 开始解码过程。
  • return true;

    • 如果所有步骤成功,返回 true 表示打开视频流成功。

执行上面代码的Open函数中的demux_.start启动主线程后有一个控制播放速度的功能模块,如果不进行控制播放速度,播放录像的视频速度非常快,以下是解封装的主线程函数代码:

demux_task.cpp 

void XDemuxTask::Main()
{AVPacket pkt;while (!is_exit_){if (!demux_.Read(&pkt)){//读取失败cout << "-" << flush;if (!demux_.is_connected())//如果断开连接,需要重新连接{Open(url_, timeout_ms_);}this_thread::sleep_for(1ms);continue;}cout << "." << flush;//播放速度控制132 132 132 132 132 132if (syn_type_ == XSYN_VIDEO &&pkt.stream_index == demux_.video_index()){auto dur = demux_.RescaleToMs(pkt.duration, pkt.stream_index);if (dur <= 0)dur = 40;//pkt.durationMSleep(dur);}Next(&pkt);av_packet_unref(&pkt);this_thread::sleep_for(1ms);}
}

其中调用了RescaleToMs:把duration转成毫秒的函数位于xformat.cpp中 

xformat.cpp

//把pts dts duration 值转为毫秒  132  132
long long XFormat::RescaleToMs(long long pts, int index)
{unique_lock<mutex> lock(mux_);if (!c_ || index <0 || index > c_->nb_streams)return 0;auto in_timebase = c_->streams[index]->time_base;AVRational out_timebase = { 1,1000 };//输出timebase 毫秒return av_rescale_q(pts, in_timebase, out_timebase);
}

该函数将转换时间基数调整播放速度

运行结果: 

没设置XplayVideo窗口的可拖动功能所以这个窗口固定的 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/34890.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

乐鑫ESP32-WROOM-32E模组设备低功耗控制方案,启明云端乐鑫代理商

在数字化浪潮的推动下&#xff0c;物联网&#xff08;IoT&#xff09;正迅速成为我们日常生活的一部分。而在这个领域中&#xff0c;ESP32-WROOM-32E模组以其卓越的性能和多功能性&#xff0c;成为了开发者和制造商的选择。 ESP32-WROOM-32E模组集成了ESP32-D0WD-V3芯片&#…

项目maven标志消失,pom文件显示为橙色/橘色标志

背景&#xff1a; 公司开发新的项目&#xff0c;我要拉一下item服务的工程进行开发&#xff0c;等我把代码拉下来发现我idea右侧边栏的maven没了&#xff0c;pox.xml文件也变成了这种橙色/橘色的标志。 分析&#xff1a; 这个是一个不正常的maven项目pom&#xff0c;可能是由于…

OpenVINO在iGPU上加载模型比CPU慢

官方解答地址&#xff1a; 为什么模型加载时间比 CPU 长&#xff1f; (intel.cn) 总结 快速步骤以改善 GPU 上的模型加载时间 说明 将输入模型的中间表示 &#xff08;IR&#xff09; 加载到 GPU 需要的时间比将相同模型加载到 CPU 还要长。 解决方法 在应用程序的工作目…

Springboot3+微服务实战12306高性能售票系统

yangzz 分享于 2023-08-14 查看次数&#xff1a; 170 次 所需&#xff1a; 10 积分 1-1 课前必读&#xff08;不读错过一个亿&#xff09; 视频&#xff1a; 1-2 课程导学 (14:21) 试看 视频&#xff1a; 1-3 为什么要选择最新版本SpringBoot3和JDK17&#xff1f; (07:0…

哪种领夹麦性价比高,哪款领夹麦克风好用,无线领夹麦克风推荐

​在这个多媒体时代&#xff0c;无线麦克风已经成为我们日常生活的一部分。无论是自媒体创作者、直播主播&#xff0c;还是日常拍摄记录&#xff0c;无线麦克风都扮演着重要角色。挑选无线麦克风时&#xff0c;收音效果和性价比是两大核心考量因素。因此&#xff0c;我特意为大…

html5+css简易实现图书网联系我们页面

html5css简易实现图书网联系我们页面 完整代码已资源绑定

毕业生离校系统

摘 要 随着信息技术的快速发展和普及&#xff0c;越来越多的高校开始利用信息化手段来提升管理和服务效率。毕业生离校是高校管理工作中的一个重要环节&#xff0c;涉及到毕业生的个人信息、学业成绩、离校手续等多个方面。传统的离校流程往往繁琐、耗时&#xff0c;且容易出现…

stm32学习笔记---TIM输出比较(代码部分)定时器定时中断/定时器外部时钟

目录 第一个代码&#xff1a;定时器定时中断 Timer.c 初始化函数 初始化定时器的步骤 定时器的库函数 TIM_DeInit TIM_TimeBaseInit TIM_TimeBaseStructInit TIM_Cmd TIM_ITConfig TIM_InternalClockConfig TIM_ITRxExternalClockConfig TIM_InputTriggerSource …

淘宝扭蛋机小程序开发,探索市场新的发展方向

如今&#xff0c;潮玩已经成为了年轻人娱乐消费的首选方式之一&#xff0c;发展态势也在不断上升&#xff0c;吸引了众多年轻人的关注。在小程序的发展下&#xff0c;也推动了扭蛋机市场的创新&#xff0c;淘宝扭蛋机小程序就是一个新的模式&#xff0c;为扭蛋机市场带来了新的…

时钟的抖动(Jitter)与偏移(Skew)

时钟的抖动&#xff08;Jitter&#xff09;与偏移&#xff08;Skew&#xff09;是数字系统时序分析中的两个重要概念&#xff0c;它们对系统的性能和稳定性有着显著的影响。以下是关于时钟抖动和偏移的详细解释&#xff1a; 时钟抖动&#xff08;Jitter&#xff09; 定义&…

VB求高于平均成绩的分数

有3个学生&#xff0c;每个学生4门课。 先求每个学生的平均成绩&#xff0c;然后展示高于平均成绩的分数。 Public Class Form1Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.ClickDim pj%, i%, n%, sum%, say$Dim cj(0 To 3) As Integeri 1…

Linux—LVM与磁盘配额

目录 一、LVM 1、LVM概念 2、LVM逻辑卷核心组件 3、LVM管理命令 二、LVM操作主要命令步骤 1、添加硬盘 2、新建分区&#xff0c;并修改分区类型 3、新建物理卷&#xff08;PV&#xff09; 4、新建卷组&#xff08;VG&#xff09; 5、新建逻辑卷&#xff08;LV&#xff0…

帮您理解PostgreSQL(WAL、XLOG、CheckPoint进程、LSN、PITR、SR)

文章目录 一、WAL、XLOG、LSN二、检查点进程与pg_control文件-负责脏页刷盘、数据库恢复三、基础备份与时间点恢复PITR四、原生复制功能与流复制&#xff08;SR Streaming Replication&#xff09; 一、WAL、XLOG、LSN 在计算机领域&#xff0c;WAL是Write Ahead Logging的缩写…

Typora配置自建的兰空图床

文章目录 Typora配置自建的兰空图床 - 前言先看效果1、搭建兰空图床 - docker2、配置兰空图床3、登录进入兰空图床后台4、Typora配置兰空图床安装兰空插件获取兰空图床的Token编辑PigGO的配置文件 使用 Typora配置自建的兰空图床 - 前言 Typora插入的图片默认存储在本地&#…

仓库管理系统07--顶部标题设计

1、创建全局变量 2、应用全局变量 1&#xff09;主窗体应用 2&#xff09;登录窗体应用 3、自定义弹窗 弹窗中各按钮的事件代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows…

odoo17 tree视图添加按钮

需求描述 点击下图中tree视图上的同步退货单按钮&#xff0c;弹出相应的form视图进行退货单同步&#xff0c;然后点击同步按钮调用后端python代码处理。 实现步骤 主要文件目录结构 js文件的创建 /** odoo-module **/ import { registry } from "web/core/registry&quo…

证件照制作工具有哪些?分享当下热门的证件照制作工具

无论是考证、出国旅游还是应聘&#xff0c;一张符合标准的证件照成了必备之物。 如果手头的证件照尺寸不符合要求&#xff0c;不必惊慌&#xff0c;现在有多种证件照制作软件可以帮助你迅速解决问题。 今天&#xff0c;本文就为大家分享几个证件照制作教程&#xff0c;让你的…

基于单片机的智能温控风扇设计

摘 要 : 本次设计是基于单片机的智能温控风扇 。 以 STC89C52 单片机为核心 &#xff0c; 可以实现对风扇的有效控制 。 可以根据需要设置不同的温度 &#xff0c;如果温度在设定值最大值和最小值之间时则启动风扇弱风档&#xff0c; 如果温度超过设定的数值时将会变到大风档…

一文学会用Helm部署rancher 高可用集群

rancher集群架构图 Helm部署rancher 高可用集群 Helm简介 Helm是Kubernetes的一个包管理工具,用来简化Kubernetes应用的部署和管理。可以把Helm比作CentOS的yum工具。 Helm有如下几个基本概念: Chart: 是Helm管理的安装包,里面包含需要部署的安装包资源。可以把Chart比作C…

什么牌子的开放式耳机好?五大优质机型,新手必看!小白闭眼入系列

音乐技术的不断进步为耳机市场的发展有了更多的选择&#xff0c;开放式耳机成为音乐爱好者们新的一个选择。从最初的基础音质到如今的高解析度音频&#xff0c;开放式耳机经历了一次次的技术革新和升级。这类耳机以开放式不入耳的设计&#xff0c;舒适的佩戴体验著称&#xff0…