Qt/C++開發監控GB28181系統/錄像文件回放/自動播放下一個錄像文件/倍速回放/錄像文件下載

一、前言說明

之前錄像文件的回放功能已經是好的,后面用戶提出來一個新的合理的需求,那就是播放完上一個錄像文件,希望自動播放下一個文件,之前是播放完成后就關閉了,需要手動雙擊錄像文件才會再次播放,這個功能和常規的視頻播放器播放列表切換是一樣的要求,實際編碼過程中發現,如果只是在視頻控件的關閉信號中去處理,會出問題,因為每次重新打開錄像文件,會先執行關閉,這就導致了死循環,剛好播放完成,發出來了關閉信號,收到信號又先執行關閉(為什么需要這一步?穩妥點保證先關閉再去打開),導致又收到關閉信號,產生了列表剛剛打開又跳轉到下一個列表,所以需要搞個時間標記規避這個問題,這種需求我相信很多播放器場景都存在,我的處理思路就是在播放開始的時候,記住播放開始的時間,收到關閉信號后,判斷當前時間和播放時間比較,是否超過1s,超過說明不是當前自動播放導致的關閉信號,這樣才需要繼續播放下一個,還有就是先要判斷是否到了末尾,沒到末尾才需要雙擊下一個錄像文件播放。

二、效果圖

在這里插入圖片描述
在這里插入圖片描述

三、相關地址

  1. 國內站點:https://gitee.com/feiyangqingyun
  2. 國際站點:https://github.com/feiyangqingyun
  3. 個人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取碼:01jf 文件名:bin_video_gb28181。

四、功能特點

  1. 支持設備注冊、注銷、心跳、校時、注冊認證、注銷認證等。
  2. 設備上線后可以手動獲取設備狀態、設備信息、配置信息、預置位信息等。
  3. 設備上線后自動獲取設備通道信息,包括中文通道名稱。識別到通道上線離線變化,會重新獲取該設備的所有通道信息。
  4. 支持視頻點播,可以分別點播主碼流和子碼流,內置rtp解包線程,解包后發給視頻播放組件解碼播放。
  5. 每個設備每個通道支持點播多個視頻,通過ssrc區分,支持共用端口和不同端口收流。
  6. 支持對某個設備下面所有通道、某個通道、某個通道對應的某個流分別關閉。
  7. 支持錄像文件查詢和回放,回放控制支持暫停播放、繼續播放、倍速播放、切換播放進度。
  8. 支持錄像文件下載,支持倍速比如8倍速下載,可同時多線程批量下載。
  9. 回放和下載同時支持IPC和NVR,比如攝像頭自帶的SD存儲卡錄像文件回放,NVR上的硬盤錄像文件回放。
  10. 支持云臺控制,向上、向下、向左、向右、左上、右上、左下、右下方位移動,鏡頭放大縮小,光圈放大縮小,鏡頭聚焦放焦。
  11. 支持預置位信息的查詢、調用、添加、修改、刪除等操作。
  12. 自動目錄訂閱功能,通道上線下線都有對應的信號通知。
  13. 內置定時讀取通道信息機制,以保證通道信息是最新的,比如有些NVR是不斷更新的通道信息。
  14. 內置訂閱警情和位置移動功能,訂閱后各種警情事件比如運動目標檢測報警、入侵檢測報警、徘徊檢測報警等自動上報。
  15. 支持語音對講功能,可以直接在視頻窗體的懸浮條上單擊語音對講按鈕,再次單擊關閉對講,對講期間懸浮條常駐顯示。
  16. 支持設備布防撤防,布防后警情信息會主動上報。
  17. 國標服務同時支持udp和tcp方式,可選只監聽一種或者兩種都監聽,tcp方式自動處理粘包問題。
  18. 國標拉流同時支持udp、tcp被動、tcp主動三種方式,每個通道都可以自由選擇何種拉流方式。
  19. 內置拉流端口池,每次拉流從中取出一個,關閉流自動回收端口號,重復利用。
  20. 收流端口自動糾錯,自動跳過被占用的端口,不會出現端口占用導致收流失敗的情況。
  21. 支持三種取流方式自動檢測離線重連,檢測到離線后,自動重啟點播拉流整個流程。
  22. 錄像文件回放,上一個完成后自動切換到下一個繼續回放,直到所有回放完成。支持高達8倍速回放。
  23. 視頻播放自適應硬解碼,極低資源占用,實時性極好,帶懸浮條顯示視頻流信息,可以直接在懸浮條單擊按鈕保存錄像文件到本地。
  24. 支持幾千路國標消息交互并發,實時視頻流支持64路同時顯示,可以拓展更多路數。
  25. 支持阿里云等云服務器,可以分別設置內網監聽地址和外網訪問地址,一般云服務器上是監聽地址用內網,對外訪問用外網地址。
  26. 支持視頻分發,也就是推流,視頻通道打開后可以自動推流到流媒體服務器,其他需要的地方拉流即可,支持rtsp、rtmp、hls、webrtc等方式拉流。
  27. 支持注冊重定向,方便做負載均衡和區域化部署,這樣可以支持幾十萬個設備連接都沒問題。
  28. 支持圖像抓拍,可以設置抓拍最多10張圖片,可設置抓拍間隔,抓拍到的圖片會通過信號通知。
  29. 實時預覽和錄像回放都支持推流,推流支持疊加文字和圖片水印以及各種ffmpeg支持的濾鏡效果,支持多個水印同時疊加。
  30. 同時支持gb28181-2011、gb28181-2016、gb28181-2022以及后續可能的所有協議版本。
  31. SIP解析和交互采用純Qt底層代碼實現,udp/tcp通信交互,祖傳原創代碼解析,不依賴任何第三方。
  32. 代碼量少,gb28181交互部分共幾千行代碼,注釋詳細,接口友好,使用極其簡單,提供非常詳細的使用示例。
  33. 支持海康、大華、宇視、華為、天地偉業等所有國標設備,包括一些沒有ssrc的設備。
  34. 支持所有Qt版本和編譯器以及操作系統,包括但不限于win、linux、mac、android、嵌入式linux、樹莓派香橙派、國產os等。

五、相關代碼

#include "frmvideoplayback.h"
#include "ui_frmvideoplayback.h"
#include "qthelper.h"
#include "videoutil.h"
#include "gb28181server.h"
#include "gb28181helper.h"
#include "gb28181widgetmanage.h"frmVideoPlayback::frmVideoPlayback(QWidget *parent) : QWidget(parent), ui(new Ui::frmVideoPlayback)
{ui->setupUi(this);this->initForm();this->initConfig();
}frmVideoPlayback::~frmVideoPlayback()
{delete ui;
}void frmVideoPlayback::closeAll()
{this->setId("", "");ui->listWidget->clear();ui->btnStop->click();
}void frmVideoPlayback::setServer(GB28181Server *server)
{this->server = server;ui->gb28181Widget->setServer(server);
}void frmVideoPlayback::setId(const QString &deviceId, const QString &channelId)
{this->deviceId = deviceId;this->channelId = channelId;
}void frmVideoPlayback::initForm()
{server = NULL;ui->sliderPosition->setRange(0, 0);ui->gb28181Widget->setBgText("視頻回放");ui->gb28181Widget->setProperty("onSync", AppConfig::RecordOnSync);connect(ui->btnPlay, SIGNAL(clicked(bool)), this, SLOT(playControl()));connect(ui->btnStop, SIGNAL(clicked(bool)), this, SLOT(playControl()));connect(ui->sliderPosition, SIGNAL(clicked()), this, SLOT(playControl()));connect(ui->cboxSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(playControl()));connect(ui->gb28181Widget, SIGNAL(sig_receivePlayStart(int)), this, SLOT(receivePlayStart(int)));connect(ui->gb28181Widget, SIGNAL(sig_receivePlayFinsh()), this, SLOT(receivePlayFinsh()));connect(ui->gb28181Widget, SIGNAL(pushStart(GB28181Widget *, QString)), GB28181WidgetManage::Instance(), SIGNAL(pushStart(GB28181Widget *, QString)));connect(ui->gb28181Widget, SIGNAL(pushStop(QString, QString)), GB28181WidgetManage::Instance(), SIGNAL(pushStop(QString, QString)));//進度定時器timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(setPosition()));timer->setInterval(300);
}void frmVideoPlayback::initConfig()
{//ui->cboxSpeed->setEnabled(false);VideoUtil::loadSpeed(ui->cboxSpeed);ui->cboxSpeed->setCurrentIndex(ui->cboxSpeed->findData(AppConfig::RecordSpeed));connect(ui->cboxSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));ui->dateStart->setDateTime(QDateTime::fromString(AppConfig::RecordStart, "yyyy-MM-ddThh:mm:ss"));connect(ui->dateStart, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(saveConfig()));ui->dateEnd->setDateTime(QDateTime::fromString(AppConfig::RecordEnd, "yyyy-MM-ddThh:mm:ss"));connect(ui->dateEnd, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(saveConfig()));
}void frmVideoPlayback::saveConfig()
{AppConfig::RecordSpeed = ui->cboxSpeed->itemData(ui->cboxSpeed->currentIndex()).toString();AppConfig::RecordStart = ui->dateStart->dateTime().toString("yyyy-MM-ddThh:mm:ss");AppConfig::RecordEnd = ui->dateEnd->dateTime().toString("yyyy-MM-ddThh:mm:ss");AppConfig::writeConfig();
}void frmVideoPlayback::setPosition()
{qint64 pts = ui->gb28181Widget->getPts();VideoUtil::setPosition(ui->labPosition, ui->sliderPosition, pts * 100);
}void frmVideoPlayback::receivePlayStart(int)
{//取出時間QListWidgetItem *item = ui->listWidget->currentItem();QString startTime = item->data(Qt::UserRole + 1).toString();QString endTime = item->data(Qt::UserRole + 2).toString();//計算時長qint64 duration = GB28181Helper::getDuration(startTime, endTime) * 1000;VideoUtil::setDuration(ui->labDuration, ui->sliderPosition, duration);
}void frmVideoPlayback::receivePlayFinsh()
{timer->stop();ui->btnPlay->setText("暫停");VideoUtil::resetDuration(ui->labDuration, ui->labPosition, ui->sliderPosition);//暫停期間不用繼續if (ui->btnPlay->text() == "播放") {return;}//如果還有下一個自動觸發雙擊播放/過濾下剛剛關閉觸發的播放結束int row = ui->listWidget->currentRow();qint64 offset = lastTime.msecsTo(QDateTime::currentDateTime());if (offset > 1000 && row < ui->listWidget->count() - 1) {ui->listWidget->setCurrentRow(row + 1);on_listWidget_itemDoubleClicked(ui->listWidget->currentItem());}
}void frmVideoPlayback::playControl()
{QString ssrc = ui->gb28181Widget->getSsrcVideo();if (!server || ssrc.isEmpty()) {return;}QObject *obj = sender();if (obj == ui->btnPlay) {if (ui->btnPlay->text() == "暫停") {ui->btnPlay->setText("播放");server->playControl(deviceId, channelId, PlayControl_Pause, 0, ssrc);} else {ui->btnPlay->setText("暫停");server->playControl(deviceId, channelId, PlayControl_Play, 0, ssrc);}} else if (obj == ui->btnStop) {lastTime = QDateTime::currentDateTime();ui->gb28181Widget->stop();} else if (obj == ui->sliderPosition) {timer->stop();timer->start();ui->btnPlay->setText("暫停");qint64 sec = ui->sliderPosition->value() / 1000;server->playControl(deviceId, channelId, PlayControl_Position, sec);} else if (obj == ui->cboxSpeed) {float speed = ui->cboxSpeed->itemData(ui->cboxSpeed->currentIndex()).toFloat();server->playControl(deviceId, channelId, PlayControl_Scale, speed, ssrc);}
}void frmVideoPlayback::receiveStatus(GB28181Status status)
{if (status.deviceId != deviceId || status.channelId != channelId || status.notifyType != 121) {return;}//不是當前窗體產生的不用處理if (ui->gb28181Widget->getSsrcVideo() == status.ssrc) {ui->gb28181Widget->stop();}
}void frmVideoPlayback::receiveRecord(const QList<GB28181Record> &records)
{if (!this->isVisible()) {return;}foreach (GB28181Record record, records) {QString startTime = record.startTime;QString endTime = record.endTime;QString date = startTime.mid(0, 10);QString start = startTime.mid(11, 5);QString end = endTime.mid(11, 5);QListWidgetItem *item = new QListWidgetItem;item->setData(Qt::UserRole + 1, startTime);item->setData(Qt::UserRole + 2, endTime);item->setText(QString("%0 %1 - %2").arg(date).arg(start).arg(end));ui->listWidget->addItem(item);}
}void frmVideoPlayback::on_btnQueryRecord_clicked()
{ui->listWidget->clear();QDateTime dateStart = ui->dateStart->dateTime();QDateTime dateEnd = ui->dateEnd->dateTime();if (dateStart >= dateEnd) {QtHelper::showMessageBoxError("開始時間必須小于結束時間, 請重新選擇!");return;}server->queryRecord(deviceId, channelId, dateStart, dateEnd);
}void frmVideoPlayback::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{//取出時間QString startTime = item->data(Qt::UserRole + 1).toString();QString endTime = item->data(Qt::UserRole + 2).toString();//停止播放lastTime = QDateTime::currentDateTime();ui->gb28181Widget->stop();qApp->processEvents();timer->start();//啟動播放ui->gb28181Widget->initPara(AppConfig::ScaleMode, AppConfig::VideoMode, AppConfig::VideoCore, AppConfig::DecodeType, AppConfig::Hardware, AppConfig::ReadTimeout, false, false);ui->gb28181Widget->setPara(AppConfig::RecordSpeed.toFloat(), AppConfig::RecordProfile, (TransmitMode)AppConfig::TransmitMode, AppConfig::ServerIp, AppConfig::RecordPush, GB28181Widget::PlayType_Playback);ui->gb28181Widget->setTime(startTime, endTime);ui->gb28181Widget->openVideo(deviceId, channelId);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919901.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Kali Linux 發布重構版Vagrant鏡像:通過命令行快速部署預配置DebOS虛擬機

Kali Linux團隊宣布對其Vagrant鏡像構建流程進行重大升級&#xff0c;通過改用DebOS系統替代原有的HashiCorp Packer工具&#xff0c;顯著簡化了預配置虛擬機的開發與部署流程。此次更新還附帶實用速查表&#xff0c;幫助安全從業者快速上手。技術架構革新Vagrant box是可通過命…

關于鏈式二叉樹的幾道OJ題目

今天筆者帶領讀者做幾道鏈式二叉樹OJ題目&#xff0c;希望讀者和筆者一起思考&#xff01; 1.965. 單值二叉樹 - 力扣&#xff08;LeetCode&#xff09; 這道題思路不難想&#xff0c;首先知道單值二叉樹的定義&#xff1a;所有結點的值都相同&#xff0c;傳入的是第一個根節…

【ECharts】2. ECharts 性能優化

動態(按需)加載異步子組件 之前說過 ECharts 如何封裝&#xff0c;今天來講一講 ECharts 如何做性能優化。 對于之前 ECharts 的封裝子組件&#xff0c;我們可以使用 component 動態組件的方式進行渲染&#xff0c;并傳參。 并且使用 import 動態導入搭配 defineAsyncCompon…

如何創建自己的 Minecraft 世界

步驟1&#xff1a;準備虛擬服務器運行以下命令來更新系統的軟件包列表并應用所有待處理的升級&#xff1a;sudo apt update sudo apt upgrade -y您的系統已更新完畢&#xff0c;您已準備好進行下一步。第 2 步&#xff1a;安裝依賴項并創建安全用戶LinuxGSM 需要一些軟件才能正…

vue中監聽頁面滾動位置

vue中監聽頁面滾動位置問題描述實現代碼1. 獲取頁面被卷起的高度2. 監聽滾動事件問題描述 頁面滾動到指定位置時&#xff0c;展示側邊欄導航。 實現代碼 1. 獲取頁面被卷起的高度 使用 e.target.scrollTop可以獲取到頁面向上滾動了多少像素&#xff0c;代碼如下&#xff1a;…

docker:compose

docker三劍客&#xff1a;compose、swarm、machinemachine是在不同環境&#xff08;不同的操作系統平臺上安裝&#xff09;下部署docker的compose是做容器編排的swarm是做docker集群管理的Compose 簡介口任務&#xff08; task &#xff09; &#xff1a; 一個容器被稱為一個任…

GaussDB 數據庫架構師修煉(十八) SQL引擎-計劃管理-SQL PATCH

1 業務背景GaussDB的優化器生成計劃不優的情況下&#xff0c;對DBA調優過程中不對業務sql修改場景下&#xff0c;提供3種計劃管理&#xff0c;分別為plan hint,sql patch,spm。2 sql patch的使用場景在發現查詢語句的執行計劃、執行方式未達預期的場景下&#xff0c;可以通過創…

函數式編程從入門到精通

1.概述1.1為什么學&#xff1f;* 能夠看懂公司里的代碼 * 大數量下處理集合效率高 * 代碼可讀性高 * 消滅嵌套地獄//查詢未成年作家評分在70分以上的書籍&#xff0c;由于流的影響所以作家和書籍可能會重復出現&#xff0c;所以要去重public void test1() {List<Book> bo…

Overleaf 中文報錯和中文不顯示問題的解決方案

Overleaf是一個很方便的在線latex編輯工具。但在最初使用Overleaf的時候&#xff0c;是不是有很多小伙伴會遇到模板中中文報錯或者中文不顯示的問題呢&#xff1f; 本文將帶你一步步解決這個問題~ 中文報錯 在點擊重新編譯按鈕后&#xff0c;中文報錯問題一般會有如下圖紅框顯示…

前后端聯調場景以及可能會遇到的問題

一、異地和在一起辦公的方式 首先&#xff0c;在一起辦公&#xff08;同局域網&#xff09;的情況&#xff0c;最常用的應該是直接使用后端的局域網 IP 進行聯調&#xff0c;因為同一網絡內設備可以直接通信。步驟方面&#xff0c;需要后端提供 IP 和端口&#xff0c;前端配置…

【T113自制板卡】1 - 原理圖說明

文章目錄1、前言2、板卡資源總覽3、電源3.1、板卡供電3.2、電源方案4、OTG接口5、調試串口6、用戶LED7、FLASH8、按鍵9、BLE MESH10、Wi-Fi11、MIC12、喇叭接口13、MIPI接口1、前言 這幾天跟著小智學長的課程畫了一塊t113的板子。本文將描述該板卡的硬件說明。 2、板卡資源總…

WiFi有網絡但是電腦連不上網是怎么回事?該怎么解決?

有時候&#xff0c;咱們用電腦上網&#xff0c;打開WiFi一看&#xff0c;信號滿格&#xff0c;狀態欄顯示已連接&#xff0c;本來想著可以愉快地看個番、查個資料、玩個游戲了&#xff0c;結果一打開瀏覽器&#xff0c;直接完犢子了&#xff0c;網頁都打不開。這時候再看狀態&a…

【golang】制作linux環境+golang的Dockerfile | 如何下載golang鏡像源

一、關于如何下載docker images 這里需要大家自行科學上網如果沒有話&#xff0c;下面可以使用我自行打包的golang 的docker images 注意科學上網要開啟TUN模式二、golang鏡像源 1、阿里云公開鏡像 如果找不到golang包的小伙伴可以使用我的公開阿里鏡像docker pull registry.cn…

Day58 Java面向對象13 instanceof 和 類型轉換

Day58 Java面向對象13 instanceof 和 類型轉換 1.instanceof關鍵字 instanceof關鍵字的作用是判斷一個對象是否是某個類或其子類的實例,它返回一個布爾值true/false dog1 instanceof Dog; //返回true dog1 instanceof Animals; //返回true dog1 instanceof Object; //返回…

GEO優化案例:如何通過“知識圖譜+權威信號”提升品牌AI信任度

引言&#xff1a; “在AI日益成為用戶信息入口的今天&#xff0c;品牌信息能否被AI賦予‘權威’標簽&#xff0c;直接決定了其在搜索結果中的可見度和用戶采信度。移山科技正是這方面的專家。” 一、行業趨勢概覽&#xff1a;AI時代的品牌信任與GEO的價值 2025年&#xff0c…

讓數據可視化更簡單:Embedding Atlas使用指南

Embedding Atlas&#xff1a;交互式的嵌入可視化工具 在大數據時代&#xff0c;如何有效地理解和利用高維數據變得愈發重要。Embedding Atlas 是一款致力于提供大型嵌入&#xff08;embeddings&#xff09;交互式可視化的工具&#xff0c;允許用戶對嵌入數據進行可視化、交叉過…

復雜場景魯棒性突破!陌訊自適應融合算法在廠區越界檢測的實戰優化?

一、行業痛點&#xff1a;越界檢測的復雜場景挑戰 工業廠區周界安防中&#xff0c;越界檢測極易受環境干擾。據《2024工業智能安防白皮書》統計&#xff08;注1&#xff09;&#xff0c;強逆光、雨霧天氣導致傳統算法誤報率超35%&#xff0c;而密集設備遮擋造成的漏檢率高達28…

Huggingface入門實踐 Audio-NLP 語音-文字模型調用(一)

吳恩達LLM-Huggingface_嗶哩嗶哩_bilibili 目錄 0. huggingface 根據需求尋找開源模型 1. Whisper模型 語音識別任務 2. blenderbot 聊天機器人 3. 文本翻譯模型translator 4. BART 模型摘要器&#xff08;summarizer&#xff09; 5. sentence-transformers 句子相似度 …

Python-Pandas GroupBy 進階與透視表學習

??一、數據分組&#xff08;GroupBy&#xff09;????核心概念??&#xff1a;將數據按指定字段分組&#xff0c;對每組進行聚合、轉換或過濾操作。??1. 分組聚合&#xff08;Aggregation&#xff09;??將分組數據聚合成單個值&#xff08;如平均值、總和&#xff09…

MQTT 核心概念與協議演進全景解讀(二)

MQTT 在物聯網中的應用實例智能家居中的設備聯動在智能家居系統里&#xff0c;MQTT 協議扮演著至關重要的角色&#xff0c;是實現設備間高效通信與智能聯動的核心樞紐。以常見的智能家居場景為例&#xff0c;當清晨的陽光緩緩升起&#xff0c;光線傳感器檢測到光照強度的變化&a…