teleport/client/tp-player/thr_play.cpp

192 lines
5.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include "thr_play.h"
#include "thr_data.h"
#include "mainwindow.h"
#include "record_format.h"
#include "util.h"
/*
* 录像播放流程:
* - 数据处理线程,该线程负责(下载)文件、解析文件,将数据准备成待播放队列;
* + 数据处理线程维护待播放队列少于500个则填充至1000个每20ms检查一次队列是否少于500个。
* - 播放线程从队列中取出一个数据判断当前时间是否应该播放此数据如果应该则将此数据发送给主UI
* + if( 播放速率 * (当前时间 - 播放时间) >= (当前数据包偏移时间 - 上个数据包偏移时间)) 则 播放
* + 如选择“跳过无操作时间”则数据包偏移时间差超过3秒的视为3秒。
*/
ThrPlay::ThrPlay(MainWindow* mainwnd) {
m_mainwnd = mainwnd;
m_need_stop = false;
m_need_pause = false;
m_speed = 1;
m_skip = false;
m_start_ms = 0;
}
ThrPlay::~ThrPlay() {
stop();
}
void ThrPlay::stop() {
if(!isRunning())
return;
// warning: never call stop() inside thread::run() loop.
m_need_stop = true;
wait();
qDebug() << "play-thread end.";
// if(m_thr_data) {
// m_thr_data->stop();
// qDebug("delete thrData.");
// //m_thr_download->wait();
// delete m_thr_data;
// m_thr_data = nullptr;
// }
}
void ThrPlay::_notify_message(const QString& msg) {
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
_msg->message(msg);
emit signal_update_data(_msg);
}
void ThrPlay::_notify_error(const QString& msg) {
UpdateData* _msg = new UpdateData(TYPE_ERROR);
_msg->message(msg);
emit signal_update_data(_msg);
}
void ThrPlay::resume(bool relocate, uint32_t start_ms) {
if(relocate) {
m_start_ms = start_ms;
m_first_run = true;
}
m_need_pause = false;
}
void ThrPlay::run() {
ThrData* thr_data = m_mainwnd->get_thr_data();
m_first_run = true;
uint32_t last_time_ms = 0;
uint32_t last_pass_ms = 0;
UpdateData* dat = nullptr;
for(;;) {
if(m_need_stop)
break;
// 1. 从ThrData的待播放队列中取出一个数据
dat = thr_data->get_data();
if(dat == nullptr) {
msleep(20);
continue;
}
if(m_first_run) {
m_first_run = false;
_notify_message("");
}
if(m_start_ms > 0) {
if(dat->get_time() < m_start_ms) {
emit signal_update_data(dat);
continue;
}
last_time_ms = m_start_ms;
m_start_ms = 0;
UpdateData* _enable = new UpdateData(TYPE_ENABLE_DRAW);
emit signal_update_data(_enable);
}
// 2. 根据数据包的信息,等待到播放时间点
uint32_t need_wait_ms = 0;
uint32_t this_time_ms = dat->get_time();
uint32_t this_pass_ms = last_time_ms;
if(this_time_ms > 0) {
if(this_time_ms >= last_time_ms)
need_wait_ms = this_time_ms - last_time_ms;
else
need_wait_ms = 0;
if(need_wait_ms > 0) {
uint32_t time_wait = 0;
// 如果设置了跳过无操作区间将超过1秒的等待时间压缩至1秒。
if(m_skip) {
if(need_wait_ms > 1000)
need_wait_ms = 1000;
}
for(;;) {
time_wait = need_wait_ms > 10 ? 10 : need_wait_ms;
msleep(time_wait);
if(m_need_pause) {
while(m_need_pause) {
msleep(50);
if(m_need_stop)
break;
}
}
if(m_need_stop)
break;
if(m_start_ms > 0) {
delete dat;
dat = nullptr;
UpdateData* _disable = new UpdateData(TYPE_DISABLE_DRAW);
emit signal_update_data(_disable);
break;
}
time_wait *= m_speed;
// 如果已经在等待长时间无操作区间内用户设置了跳过无操作区间则将超过0.5秒的等待时间压缩至0.5秒。
if(m_skip) {
if(need_wait_ms > 500)
need_wait_ms = 500;
}
this_pass_ms += time_wait;
if(this_pass_ms - last_pass_ms > 100) {
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
_passed_ms->played_ms(this_pass_ms);
emit signal_update_data(_passed_ms);
last_pass_ms = this_pass_ms;
}
if(need_wait_ms <= time_wait)
break;
else
need_wait_ms -= time_wait;
}
if(m_need_stop)
break;
}
}
last_time_ms = this_time_ms;
// 3. 将数据包发送给主UI界面进行显示
if(dat != nullptr) {
if(dat->data_type() == TYPE_END) {
_notify_message(LOCAL8BIT("播放结束"));
}
emit signal_update_data(dat);
}
}
if(dat != nullptr)
delete dat;
}