mirror of https://github.com/tp4a/teleport
.temp.
parent
ad5534fd94
commit
2f7fc16235
|
@ -1,4 +1,4 @@
|
|||
#include "bar.h"
|
||||
#include "bar.h"
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include "mainwindow.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef BAR_H
|
||||
#ifndef BAR_H
|
||||
#define BAR_H
|
||||
|
||||
#include <QPainter>
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
#include "downloader.h"
|
||||
#include "record_format.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <qelapsedtimer.h>
|
||||
|
||||
|
||||
// TODO: 将Downloader的实现代码迁移到ThrData线程中
|
||||
// 使用局部event循环的方式进行下载
|
||||
/*
|
||||
QEventLoop eventLoop;
|
||||
connect(netWorker, &NetWorker::finished,
|
||||
&eventLoop, &QEventLoop::quit);
|
||||
QNetworkReply *reply = netWorker->get(url);
|
||||
replyMap.insert(reply, FetchWeatherInfo);
|
||||
eventLoop.exec();
|
||||
*/
|
||||
|
||||
|
||||
//=================================================================
|
||||
// Downloader
|
||||
//=================================================================
|
||||
Downloader::Downloader() {
|
||||
m_reply = nullptr;
|
||||
m_code = codeUnknown;
|
||||
}
|
||||
|
||||
Downloader::~Downloader() {
|
||||
}
|
||||
|
||||
void Downloader::run(QNetworkAccessManager* nam, QString& url, QString& sid, QString& filename) {
|
||||
m_filename = filename;
|
||||
|
||||
if(!m_filename.isEmpty()) {
|
||||
m_file.setFileName(m_filename);
|
||||
if(!m_file.open(QIODevice::WriteOnly | QFile::Truncate)){
|
||||
qDebug("open file for write failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_code = codeDownloading;
|
||||
QString cookie = QString("_sid=%1\r\n").arg(sid);
|
||||
|
||||
QNetworkRequest req;
|
||||
req.setUrl(QUrl(url));
|
||||
req.setRawHeader("Cookie", cookie.toLatin1());
|
||||
|
||||
m_reply = nam->get(req);
|
||||
connect(m_reply, &QNetworkReply::finished, this, &Downloader::_on_finished);
|
||||
connect(m_reply, &QIODevice::readyRead, this, &Downloader::_on_data_ready);
|
||||
}
|
||||
|
||||
void Downloader::_on_data_ready() {
|
||||
QNetworkReply *reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
if(m_filename.isEmpty()) {
|
||||
m_data += reply->readAll();
|
||||
}
|
||||
else {
|
||||
m_file.write(reply->readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void Downloader::reset() {
|
||||
m_code = codeUnknown;
|
||||
}
|
||||
|
||||
void Downloader::abort() {
|
||||
if(m_reply)
|
||||
m_reply->abort();
|
||||
}
|
||||
|
||||
void Downloader::_on_finished() {
|
||||
qDebug("download finished");
|
||||
QNetworkReply *reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
// reply->abort() got "Operation canceled"
|
||||
//QString strError = reply->errorString();
|
||||
//qDebug() << strError;
|
||||
m_file.flush();
|
||||
m_file.close();
|
||||
m_code = codeFailed;
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(m_reply, &QNetworkReply::finished, this, &Downloader::_on_finished);
|
||||
disconnect(m_reply, &QIODevice::readyRead, this, &Downloader::_on_data_ready);
|
||||
// reply->deleteLater();
|
||||
|
||||
if(m_filename.isEmpty()) {
|
||||
m_data += reply->readAll();
|
||||
}
|
||||
else {
|
||||
m_file.write(reply->readAll());
|
||||
m_file.flush();
|
||||
m_file.close();
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
m_code = codeSuccess;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef DOWNLOADER_H
|
||||
#define DOWNLOADER_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class Downloader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum EndCode{
|
||||
codeUnknown = 0,
|
||||
codeSuccess,
|
||||
codeDownloading,
|
||||
codeFailed
|
||||
};
|
||||
|
||||
public:
|
||||
// 从url下载数据,写入到filename文件中,如果filename为空字符串,则保存在内存中,可通过 data() 获取。
|
||||
Downloader();
|
||||
~Downloader();
|
||||
|
||||
void run(QNetworkAccessManager* nam, QString& url, QString& sid, QString& filename);
|
||||
void abort();
|
||||
void reset();
|
||||
QByteArray& data(){return m_data;}
|
||||
|
||||
EndCode code() {return m_code;}
|
||||
|
||||
private slots:
|
||||
void _on_data_ready(); // 有数据可读了,读取并写入文件
|
||||
void _on_finished(); // 下载结束了
|
||||
|
||||
private:
|
||||
QString m_filename;
|
||||
QFile m_file;
|
||||
QByteArray m_data;
|
||||
|
||||
QNetworkReply* m_reply;
|
||||
|
||||
EndCode m_code;
|
||||
};
|
||||
|
||||
typedef struct DownloadParam {
|
||||
QString url;
|
||||
QString sid;
|
||||
QString fname;
|
||||
}DownloadParam;
|
||||
|
||||
#endif
|
|
@ -8,14 +8,63 @@
|
|||
// 编译出来的可执行程序复制到单独目录,然后执行 windeployqt 应用程序文件名
|
||||
// 即可自动将依赖的动态库等复制到此目录中。有些文件是多余的,可以酌情删除。
|
||||
|
||||
// 命令行参数格式:
|
||||
// ## 本地文件或目录
|
||||
// tp-player.exe path/of/tp-rdp.tpr 一个 .tpr 文件的文件名
|
||||
// tp-player.exe path/contains/tp-rdp.tpr 包含 .tpr 文件的路径
|
||||
//
|
||||
// ## 从TP服务器上下载
|
||||
// (废弃) tp-player.exe "http://127.0.0.1:7190" 1234 "tp_1491560510_ca67fceb75a78c9d" "000000256-admin-administrator-218.244.140.14-20171209-020047"
|
||||
// (废弃) TP服务器地址 记录编号 session-id(仅授权用户可下载) 合成的名称,用于本地生成路径来存放下载的文件
|
||||
//
|
||||
// ## 从TP服务器上下载
|
||||
// tp-player.exe http://teleport.domain.com:7190/{sub/path/}tp_1491560510_ca67fceb75a78c9d/1234 (注意,并不直接访问此URI,实际上其并不存在)
|
||||
// TP服务器地址(可能包含子路径哦,例如上例中的{sub/path}部分)/session-id(用于判断当前授权用户)/录像会话编号
|
||||
// 按 “/” 进行分割后,去掉最后两个项,剩下部分是TP服务器的WEB地址,用于合成后续的文件下载URL。
|
||||
// 根据下载的.tpr文件内容,本地合成类似于 "000000256-admin-administrator-218.244.140.14-20171209-020047" 的路径来存放下载的文件
|
||||
// 特别注意,如果账号是 domain\user 这种形式,需要将 "\" 替换为下划线,否则此符号作为路径分隔符,会导致路径不存在而无法保存下载的文件。
|
||||
// - 获取文件大小: http://127.0.0.1:7190/audit/get-file?act=size&type=rdp&rid=yyyyy&f=file-name
|
||||
// - 'act'为`size`表示获取文件大小(返回一个数字字符串,就是指定的文件大小)
|
||||
// - 'type'可以是`rdp`或`ssh`,目前仅用了`rdp`
|
||||
// - 'rid'是录像会话编号(在服务端,一个会话的录像文件均放在录像会话编号命名的目录下)
|
||||
// - 'f' 是文件名,即会话编号目录下的指定文件,例如 'tp-rdp.tpr'
|
||||
// - 读取文件内容: http://127.0.0.1:7190/audit/get-file?act=read&type=rdp&rid=yyyyy&f=file-name&offset=1234&length=1024
|
||||
// - 'act'为`read`表示获取文件内容
|
||||
// - 'offset'表示要读取的偏移,如果未指定,则表示从文件起始处开始读取,即默认为 offset=0
|
||||
// - 'length'表示要读取的大小,如果未指定,表示读取整个文件,即默认为 length=-1(服务端对length=-1做完全读取处理)
|
||||
// - 搭配使用 offst 和 length 可以做到分块下载、断点续传。
|
||||
|
||||
|
||||
void show_usage(QCommandLineParser& parser) {
|
||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||
"<html><head/><body><pre>"
|
||||
+ parser.helpText()
|
||||
+ "\n\n"
|
||||
+ "RESOURCE could be:\n"
|
||||
+ " teleport record file (.tpr).\n"
|
||||
+ " a directory contains .tpr file.\n"
|
||||
+ " an URL to download teleport record file."
|
||||
+ "</pre></body></html>");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
//#endif
|
||||
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
//#ifdef __APPLE__
|
||||
// QString data_path_base = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
// data_path_base += "/tp-testdata/";
|
||||
//#else
|
||||
// QString data_path_base = QCoreApplication::applicationDirPath() + "/record";
|
||||
//#endif
|
||||
// qDebug("data-path-base: %s", data_path_base.toStdString().c_str());
|
||||
// return 0;
|
||||
|
||||
QGuiApplication::setApplicationDisplayName("TP-Player");
|
||||
|
||||
QCommandLineParser parser;
|
||||
|
@ -32,19 +81,25 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if(parser.isSet(opt_help)) {
|
||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||
"<html><head/><body><pre>"
|
||||
+ parser.helpText()
|
||||
+ "\n\n"
|
||||
+ "RESOURCE could be:\n"
|
||||
+ " teleport record file (.tpr).\n"
|
||||
+ " a directory contains .tpr file.\n"
|
||||
+ " an URL for download teleport record file."
|
||||
+ "</pre></body></html>");
|
||||
show_usage(parser);
|
||||
// QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||
// "<html><head/><body><pre>"
|
||||
// + parser.helpText()
|
||||
// + "\n\n"
|
||||
// + "RESOURCE could be:\n"
|
||||
// + " teleport record file (.tpr).\n"
|
||||
// + " a directory contains .tpr file.\n"
|
||||
// + " an URL for download teleport record file."
|
||||
// + "</pre></body></html>");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if(0 == args.size()) {
|
||||
show_usage(parser);
|
||||
return 2;
|
||||
}
|
||||
|
||||
QString resource = args.at(0);
|
||||
qDebug() << resource;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "mainwindow.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "rle.h"
|
||||
|
||||
|
@ -86,10 +86,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
m_bar_fade_in = false;
|
||||
m_bar_fading = false;
|
||||
m_bar_opacity = 1.0;
|
||||
m_show_message = false;
|
||||
memset(&m_pt, 0, sizeof(TS_RECORD_RDP_POINTER));
|
||||
|
||||
m_thr_play = nullptr;
|
||||
m_play_state = PLAY_STATE_UNKNOWN;
|
||||
m_thr_data = nullptr;
|
||||
|
||||
m_dl = nullptr;
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -107,14 +111,20 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
m_pt_normal.load(":/tp-player/res/cursor.png");
|
||||
m_default_bg.load(":/tp-player/res/bg.png");
|
||||
|
||||
m_canvas = QPixmap(m_default_bg.width(), m_default_bg.height());
|
||||
QPainter pp(&m_canvas);
|
||||
pp.drawPixmap(0, 0, m_default_bg, 0, 0, m_default_bg.width(), m_default_bg.height());
|
||||
|
||||
|
||||
setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint); // 禁止最大化按钮
|
||||
setFixedSize(m_default_bg.width(), m_default_bg.height()); // 禁止拖动窗口大小
|
||||
setFixedSize(m_default_bg.width(), m_default_bg.height()); // 禁止拖动窗口大小
|
||||
|
||||
if(!m_bar.init(this)) {
|
||||
qDebug("bar init failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// connect(&m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
||||
connect(&m_timer_first_run, SIGNAL(timeout()), this, SLOT(_do_first_run()));
|
||||
connect(&m_timer_bar_fade, SIGNAL(timeout()), this, SLOT(_do_bar_fade()));
|
||||
|
@ -131,12 +141,25 @@ MainWindow::~MainWindow()
|
|||
//m_thr_play->wait();
|
||||
//qDebug() << "play thread stoped.";
|
||||
|
||||
disconnect(m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
||||
disconnect(m_thr_play, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
|
||||
delete m_thr_play;
|
||||
m_thr_play = nullptr;
|
||||
}
|
||||
|
||||
if(m_thr_data) {
|
||||
m_thr_data->stop();
|
||||
disconnect(m_thr_data, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
disconnect(m_thr_data, SIGNAL(signal_download(DownloadParam*)), this, SLOT(_do_download(DownloadParam*)));
|
||||
delete m_thr_data;
|
||||
m_thr_data = nullptr;
|
||||
}
|
||||
|
||||
if(m_dl) {
|
||||
delete m_dl;
|
||||
m_dl = nullptr;
|
||||
}
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
@ -145,6 +168,11 @@ void MainWindow::set_resource(const QString &res) {
|
|||
}
|
||||
|
||||
void MainWindow::_do_first_run() {
|
||||
m_thr_data = new ThrData(this, m_res);
|
||||
connect(m_thr_data, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
connect(m_thr_data, SIGNAL(signal_download(DownloadParam*)), this, SLOT(_do_download(DownloadParam*)));
|
||||
m_thr_data->start();
|
||||
|
||||
_start_play_thread();
|
||||
}
|
||||
|
||||
|
@ -153,14 +181,15 @@ void MainWindow::_start_play_thread() {
|
|||
m_thr_play->stop();
|
||||
//m_thr_play->wait();
|
||||
|
||||
disconnect(m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
||||
disconnect(m_thr_play, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
|
||||
delete m_thr_play;
|
||||
m_thr_play = nullptr;
|
||||
}
|
||||
|
||||
m_thr_play = new ThreadPlay(m_res);
|
||||
connect(m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
||||
m_thr_play = new ThrPlay();
|
||||
connect(m_thr_play, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
|
||||
m_thr_play->speed(m_bar.get_speed());
|
||||
m_thr_play->start();
|
||||
}
|
||||
|
@ -186,19 +215,19 @@ void MainWindow::paintEvent(QPaintEvent *e)
|
|||
painter.drawPixmap(m_pt.x-m_pt_normal.width()/2, m_pt.y-m_pt_normal.height()/2, m_pt_normal);
|
||||
}
|
||||
|
||||
{
|
||||
QRect rc_draw = e->rect();
|
||||
QRect rc(m_rc_message);
|
||||
//rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
// {
|
||||
// QRect rc_draw = e->rect();
|
||||
// QRect rc(m_rc_message);
|
||||
// //rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||
}
|
||||
// int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
// int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
// int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
// int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
// int to_x = rc.left() + from_x;
|
||||
// int to_y = rc.top() + from_y;
|
||||
// painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||
// }
|
||||
|
||||
// 绘制浮动控制窗
|
||||
if(m_bar_fading) {
|
||||
|
@ -210,6 +239,20 @@ void MainWindow::paintEvent(QPaintEvent *e)
|
|||
}
|
||||
}
|
||||
|
||||
if(m_show_message) {
|
||||
QRect rc_draw = e->rect();
|
||||
QRect rc(m_rc_message);
|
||||
//rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||
}
|
||||
|
||||
// if(!m_shown) {
|
||||
// m_shown = true;
|
||||
// //m_thr_play.start();
|
||||
|
@ -234,7 +277,7 @@ void MainWindow::resume() {
|
|||
m_play_state = PLAY_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void MainWindow::_do_update_data(update_data* dat) {
|
||||
void MainWindow::_do_update_data(UpdateData* dat) {
|
||||
if(!dat)
|
||||
return;
|
||||
|
||||
|
@ -297,11 +340,19 @@ void MainWindow::_do_update_data(update_data* dat) {
|
|||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_MESSAGE) {
|
||||
m_show_message = true;
|
||||
|
||||
qDebug("1message, w=%d, h=%d", m_canvas.width(), m_canvas.height());
|
||||
// if(0 == m_canvas.width()) {
|
||||
// QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(), dat->message());
|
||||
// return;
|
||||
// }
|
||||
|
||||
QPainter pp(&m_canvas);
|
||||
QRect rcWin(0, 0, m_canvas.width(), m_canvas.height());
|
||||
pp.drawText(rcWin, Qt::AlignLeft|Qt::TextDontPrint, dat->message(), &m_rc_message);
|
||||
|
||||
qDebug("message, w=%d, h=%d", m_rc_message.width(), m_rc_message.height());
|
||||
qDebug("2message, w=%d, h=%d", m_rc_message.width(), m_rc_message.height());
|
||||
m_rc_message.setWidth(m_rc_message.width()+60);
|
||||
m_rc_message.setHeight(m_rc_message.height()+60);
|
||||
|
||||
|
@ -311,6 +362,11 @@ void MainWindow::_do_update_data(update_data* dat) {
|
|||
pm.setPen(QColor(255,255,255,153));
|
||||
pm.fillRect(m_rc_message, QColor(0,0,0,190));
|
||||
|
||||
QRect rcRect(m_rc_message);
|
||||
rcRect.setWidth(rcRect.width()-1);
|
||||
rcRect.setHeight(rcRect.height()-1);
|
||||
pm.drawRect(rcRect);
|
||||
|
||||
QRect rcText(m_rc_message);
|
||||
rcText.setLeft(30);
|
||||
rcText.setTop(30);
|
||||
|
@ -319,11 +375,14 @@ void MainWindow::_do_update_data(update_data* dat) {
|
|||
(m_canvas.width() - m_rc_message.width())/2,
|
||||
(m_canvas.height() - m_rc_message.height())/3
|
||||
);
|
||||
|
||||
update(m_rc_message.x(), m_rc_message.y(), m_rc_message.width(), m_rc_message.height());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_ERROR) {
|
||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(), dat->message());
|
||||
QMessageBox::critical(this, QGuiApplication::applicationDisplayName(), dat->message());
|
||||
QApplication::instance()->exit(0);
|
||||
return;
|
||||
}
|
||||
|
@ -338,7 +397,7 @@ void MainWindow::_do_update_data(update_data* dat) {
|
|||
|
||||
qDebug() << "resize (" << m_rec_hdr.basic.width << "," << m_rec_hdr.basic.height << ")";
|
||||
|
||||
if(m_canvas.width() != m_rec_hdr.basic.width && m_canvas.height() != m_rec_hdr.basic.height) {
|
||||
//if(m_canvas.width() != m_rec_hdr.basic.width && m_canvas.height() != m_rec_hdr.basic.height) {
|
||||
m_canvas = QPixmap(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||
|
||||
//m_win_board_w = frameGeometry().width() - geometry().width();
|
||||
|
@ -353,7 +412,7 @@ void MainWindow::_do_update_data(update_data* dat) {
|
|||
//resize(m_rec_hdr.basic.width + m_win_board_w, m_rec_hdr.basic.height + m_win_board_h);
|
||||
//resize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||
setFixedSize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||
}
|
||||
//}
|
||||
|
||||
m_canvas.fill(QColor(38, 73, 111));
|
||||
|
||||
|
@ -422,6 +481,18 @@ void MainWindow::_do_bar_fade() {
|
|||
update(m_bar.rc());
|
||||
}
|
||||
|
||||
void MainWindow::_do_download(DownloadParam* param) {
|
||||
qDebug("MainWindow::_do_download(). %s %s %s", param->url.toStdString().c_str(), param->sid.toStdString().c_str(), param->fname.toStdString().c_str());
|
||||
|
||||
if(m_dl) {
|
||||
delete m_dl;
|
||||
m_dl = nullptr;
|
||||
}
|
||||
|
||||
m_dl = new Downloader();
|
||||
m_dl->run(&m_nam, param->url, param->sid, param->fname);
|
||||
}
|
||||
|
||||
void MainWindow::mouseMoveEvent(QMouseEvent *e) {
|
||||
if(!m_show_default) {
|
||||
QRect rc = m_bar.rc();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
@ -6,9 +6,11 @@
|
|||
#include <QTimer>
|
||||
#include "bar.h"
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "update_data.h"
|
||||
#include "record_format.h"
|
||||
#include "util.h"
|
||||
#include "downloader.h"
|
||||
|
||||
#define PLAY_STATE_UNKNOWN 0
|
||||
#define PLAY_STATE_RUNNING 1
|
||||
|
@ -34,6 +36,9 @@ public:
|
|||
void restart();
|
||||
void speed(int s);
|
||||
|
||||
Downloader* downloader() {return m_dl;}
|
||||
void reset_downloader() {if(m_dl){delete m_dl;m_dl= nullptr;}}
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
|
@ -43,10 +48,13 @@ private:
|
|||
|
||||
private slots:
|
||||
void _do_first_run(); // 默认界面加载完成后,开始播放操作(可能会进行数据下载)
|
||||
void _do_update_data(update_data*);
|
||||
void _do_update_data(UpdateData*);
|
||||
void _do_bar_fade();
|
||||
void _do_bar_delay_hide();
|
||||
|
||||
// void _do_download(Downloader*);
|
||||
void _do_download(DownloadParam*);
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
|
@ -56,7 +64,8 @@ private:
|
|||
QPixmap m_default_bg;
|
||||
|
||||
QString m_res;
|
||||
ThreadPlay* m_thr_play;
|
||||
ThrPlay* m_thr_play;
|
||||
ThrData* m_thr_data;
|
||||
|
||||
QPixmap m_canvas;
|
||||
|
||||
|
@ -76,10 +85,14 @@ private:
|
|||
|
||||
int m_play_state;
|
||||
|
||||
bool m_show_message;
|
||||
QPixmap m_img_message;
|
||||
QRect m_rc_message;
|
||||
|
||||
|
||||
QNetworkAccessManager m_nam;
|
||||
Downloader* m_dl;
|
||||
|
||||
// for test
|
||||
TimeUseTest m_time_imgconvert_normal;
|
||||
TimeUseTest m_time_imgconvert_compressed;
|
||||
|
|
|
@ -60,10 +60,11 @@ typedef struct TS_RECORD_HEADER {
|
|||
|
||||
// 一个数据包的头
|
||||
typedef struct TS_RECORD_PKG {
|
||||
uint8_t type; // 包的数据类型
|
||||
uint32_t size; // 这个包的总大小(不含包头)
|
||||
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||
uint8_t _reserve[3]; // 保留
|
||||
uint8_t type; // 包的数据类型
|
||||
uint8_t _reserve[3]; // 保留
|
||||
uint32_t size; // 这个包的总大小(不含包头)
|
||||
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||
uint32_t index; // 这个包的序号(最后一个包的序号与TS_RECORD_HEADER_INFO::packages数量匹配)
|
||||
}TS_RECORD_PKG;
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- c-basic-offset: 8 -*-
|
||||
/* -*- c-basic-offset: 8 -*-
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
Bitmap decompression routines
|
||||
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
||||
|
|
|
@ -0,0 +1,665 @@
|
|||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QNetworkCookie>
|
||||
#include <QStandardPaths>
|
||||
#include <qcoreapplication.h>
|
||||
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "util.h"
|
||||
#include "record_format.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
|
||||
//=================================================================
|
||||
// ThrData
|
||||
//=================================================================
|
||||
|
||||
ThrData::ThrData(MainWindow* mainwin, const QString& res) {
|
||||
m_mainwin = mainwin;
|
||||
m_res = res;
|
||||
m_need_download = false;
|
||||
m_need_stop = false;
|
||||
|
||||
#ifdef __APPLE__
|
||||
QString data_path_base = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
data_path_base += "/tp-testdata/";
|
||||
#else
|
||||
m_local_data_path_base = QCoreApplication::applicationDirPath() + "/record";
|
||||
#endif
|
||||
qDebug("data-path-base: %s", m_local_data_path_base.toStdString().c_str());
|
||||
|
||||
// qDebug() << "AppConfigLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
// qDebug() << "AppDataLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
// qDebug() << "AppLocalDataLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
||||
// qDebug() << "ConfigLocation:" << QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
// qDebug() << "CacheLocation:" << QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
// qDebug() << "GenericCacheLocation:" << QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
|
||||
|
||||
/*
|
||||
AppConfigLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
AppDataLocation: "C:/Users/apex/AppData/Roaming/tp-player"
|
||||
AppLocalDataLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
ConfigLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
CacheLocation: "C:/Users/apex/AppData/Local/tp-player/cache"
|
||||
GenericCacheLocation: "C:/Users/apex/AppData/Local/cache"
|
||||
*/
|
||||
}
|
||||
|
||||
ThrData::~ThrData() {
|
||||
}
|
||||
|
||||
void ThrData::stop() {
|
||||
if(!isRunning())
|
||||
return;
|
||||
m_need_stop = true;
|
||||
wait();
|
||||
qDebug("data thread stop() end.");
|
||||
}
|
||||
|
||||
void ThrData::_notify_message(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrData::_notify_error(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_ERROR);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrData::_notify_download(DownloadParam* param) {
|
||||
emit signal_download(param);
|
||||
}
|
||||
|
||||
// tp-player.exe http://teleport.domain.com:7190/{sub/path/}tp_1491560510_ca67fceb75a78c9d/1234 (注意,并不直接访问此URI,实际上其并不存在)
|
||||
// TP服务器地址(可能包含子路径哦,例如上例中的{sub/path/}部分)/session-id(用于判断当前授权用户)/录像会话编号
|
||||
|
||||
void ThrData::run() {
|
||||
if(!_load_header())
|
||||
return;
|
||||
|
||||
if(!_load_keyframe())
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
break;
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
qDebug("ThrData thread run() end.");
|
||||
}
|
||||
|
||||
bool ThrData::_load_header() {
|
||||
QString msg;
|
||||
QString _tmp_res = m_res.toLower();
|
||||
|
||||
if(_tmp_res.startsWith("http")) {
|
||||
m_need_download = true;
|
||||
}
|
||||
|
||||
if(m_need_download) {
|
||||
_notify_message(LOCAL8BIT("正在准备录像数据,请稍候..."));
|
||||
|
||||
QStringList _uris = m_res.split('/');
|
||||
if(_uris.size() < 3) {
|
||||
qDebug() << "invalid param: " << m_res;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sid = _uris[_uris.size()-2];
|
||||
m_rid = _uris[_uris.size()-1];
|
||||
m_url_base = m_res.left(m_res.length() - m_sid.length() - m_rid.length() - 2);
|
||||
|
||||
qDebug() << "url-base:[" << m_url_base << "], sid:[" << m_sid << "], rid:[" << m_rid << "]";
|
||||
|
||||
// download .tpr
|
||||
QString url(m_url_base);
|
||||
url += "/audit/get-file?act=read&type=rdp&rid=";
|
||||
url += m_rid;
|
||||
url += "&f=tp-rdp.tpr";
|
||||
|
||||
QString fname;
|
||||
if(!_download_file(url, fname))
|
||||
return false;
|
||||
|
||||
// Downloader& dl = m_mainwin->downloader();
|
||||
// dl.reset();
|
||||
|
||||
// DownloadParam param;
|
||||
// param.url = url;
|
||||
// param.sid = m_sid;
|
||||
// param.fname = fname;
|
||||
// _notify_download(¶m);
|
||||
|
||||
// for(;;) {
|
||||
// if(dl.code() == Downloader::codeUnknown || dl.code() == Downloader::codeDownloading) {
|
||||
// msleep(100);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if(dl.code() != Downloader::codeSuccess) {
|
||||
// _notify_error(QString("%1").arg(LOCAL8BIT("下载文件失败!")));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
Downloader* dl = m_mainwin->downloader();
|
||||
QByteArray& data = dl->data();
|
||||
if(data.size() != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug("invalid header file. %d", data.size());
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("指定的文件或目录不存在!"), _tmp_res));
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&m_hdr, data.data(), sizeof(TS_RECORD_HEADER));
|
||||
}
|
||||
else {
|
||||
QFileInfo fi_chk_link(m_res);
|
||||
if(fi_chk_link.isSymLink())
|
||||
_tmp_res = fi_chk_link.symLinkTarget();
|
||||
else
|
||||
_tmp_res = m_res;
|
||||
|
||||
QFileInfo fi(_tmp_res);
|
||||
if(!fi.exists()) {
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("指定的文件或目录不存在!"), _tmp_res));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fi.isFile()) {
|
||||
m_path_base = fi.path();
|
||||
}
|
||||
else if(fi.isDir()) {
|
||||
m_path_base = _tmp_res;
|
||||
}
|
||||
|
||||
m_path_base = QDir::toNativeSeparators(m_path_base);
|
||||
|
||||
qDebug() << "PATH_BASE: " << m_path_base;
|
||||
|
||||
QString filename = QString("%1/tp-rdp.tpr").arg(m_path_base);
|
||||
filename = QDir::toNativeSeparators(filename);
|
||||
qDebug() << "TPR: " << filename;
|
||||
|
||||
QFile f(filename);
|
||||
if(!f.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << filename << " for read.";
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("无法打开录像信息文件!"), filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&m_hdr, 0, sizeof(TS_RECORD_HEADER));
|
||||
|
||||
qint64 read_len = 0;
|
||||
read_len = f.read(reinterpret_cast<char*>(&m_hdr), sizeof(TS_RECORD_HEADER));
|
||||
if(read_len != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("错误的录像信息文件!"), filename));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_hdr.info.ver != 4) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
_notify_error(QString("%1 %2%3").arg(LOCAL8BIT("不支持的录像文件版本 "), QString(m_hdr.info.ver), LOCAL8BIT("!\n\n此播放器支持录像文件版本 4。")));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_hdr.basic.width == 0 || m_hdr.basic.height == 0) {
|
||||
_notify_error(LOCAL8BIT("错误的录像信息,未记录窗口尺寸!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_hdr.info.dat_file_count == 0) {
|
||||
_notify_error(LOCAL8BIT("错误的录像信息,未记录数据文件数量!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 下载得到的数据应该是一个TS_RECORD_HEADER,解析此数据,生成本地文件路径,并保存之。
|
||||
if(m_need_download) {
|
||||
QDateTime timeUTC;
|
||||
// timeUTC.setTimeSpec(Qt::UTC);
|
||||
// timeUTC.setTime_t(m_hdr.basic.timestamp);
|
||||
timeUTC.setSecsSinceEpoch(m_hdr.basic.timestamp);
|
||||
QString strUTC = timeUTC.toString("yyyyMMdd-hhmmss");
|
||||
|
||||
QString strAcc(m_hdr.basic.acc_username);
|
||||
int idx = strAcc.indexOf('\\');
|
||||
if(-1 != idx) {
|
||||
QString _domain = strAcc.left(idx);
|
||||
QString _user = strAcc.right(strAcc.length() - idx - 1);
|
||||
strAcc = _user + "@" + _domain;
|
||||
}
|
||||
|
||||
// .../record/RDP-211-admin-user@domain-192.168.0.68-20191015-020243
|
||||
m_path_base = QString("%1/RDP-%2-%3-%4-%5-%6").arg(m_local_data_path_base,
|
||||
m_rid,
|
||||
m_hdr.basic.user_username,
|
||||
strAcc,
|
||||
m_hdr.basic.host_ip,
|
||||
strUTC
|
||||
);
|
||||
|
||||
m_path_base = QDir::toNativeSeparators(m_path_base);
|
||||
|
||||
qDebug() << "PATH_BASE: " << m_path_base;
|
||||
|
||||
QDir dir;
|
||||
dir.mkpath(m_path_base);
|
||||
QFileInfo fi;
|
||||
fi.setFile(m_path_base);
|
||||
if(!fi.isDir()) {
|
||||
qDebug("can not create folder to save downloaded file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QString filename = QString("%1/tp-rdp.tpr").arg(m_path_base);
|
||||
filename = QDir::toNativeSeparators(filename);
|
||||
qDebug() << "TPR: " << filename;
|
||||
|
||||
QFile f;
|
||||
f.setFileName(filename);
|
||||
if(!f.open(QIODevice::WriteOnly | QFile::Truncate)){
|
||||
qDebug("open file for write failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 written = f.write(reinterpret_cast<const char*>(&m_hdr), sizeof(TS_RECORD_HEADER));
|
||||
f.flush();
|
||||
f.close();
|
||||
|
||||
if(written != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug("save header file failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrData::_load_keyframe() {
|
||||
// _notify_error(QString("%1").arg(LOCAL8BIT("测试!")));
|
||||
|
||||
QString tpk_fname = QString("%1/tp-rdp.tpk").arg(m_path_base);
|
||||
tpk_fname = QDir::toNativeSeparators(tpk_fname);
|
||||
|
||||
if(m_need_download) {
|
||||
// download .tpr
|
||||
QString url(m_url_base);
|
||||
url += "/audit/get-file?act=read&type=rdp&rid=";
|
||||
url += m_rid;
|
||||
url += "&f=tp-rdp.tpk";
|
||||
|
||||
QString tmp_fname = QString("%1/tp-rdp.tpk.downloading").arg(m_path_base);
|
||||
tmp_fname = QDir::toNativeSeparators(tmp_fname);
|
||||
qDebug() << "TPK(tmp): " << tmp_fname;
|
||||
qDebug() << "TPK(out): " << tpk_fname;
|
||||
|
||||
if(!_download_file(url, tmp_fname))
|
||||
return false;
|
||||
|
||||
QFile::rename(tmp_fname, tpk_fname);
|
||||
}
|
||||
|
||||
QFile f_kf(tpk_fname);
|
||||
if(!f_kf.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpk_fname << " for read.";
|
||||
_notify_error(QString("%1\n\n%3").arg(LOCAL8BIT("无法打开关键帧信息文件!"), tpk_fname));
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 fsize = f_kf.size();
|
||||
if(!fsize || fsize % sizeof(KEYFRAME_INFO) != 0) {
|
||||
qDebug() << "Can not open " << tpk_fname << " for read.";
|
||||
_notify_error(LOCAL8BIT("关键帧信息文件格式错误!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 read_len = 0;
|
||||
int kf_count = fsize / sizeof(KEYFRAME_INFO);
|
||||
for(int i = 0; i < kf_count; ++i) {
|
||||
KEYFRAME_INFO kf;
|
||||
memset(&kf, 0, sizeof(KEYFRAME_INFO));
|
||||
read_len = f_kf.read(reinterpret_cast<char*>(&kf), sizeof(KEYFRAME_INFO));
|
||||
if(read_len != sizeof(KEYFRAME_INFO)) {
|
||||
qDebug() << "invaid .tpk file.";
|
||||
_notify_error(LOCAL8BIT("关键帧信息文件格式错误!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_kf.push_back(kf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrData::_download_file(const QString& url, const QString filename) {
|
||||
if(!m_need_download) {
|
||||
qDebug() << "download not necessary.";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mainwin->reset_downloader();
|
||||
msleep(100);
|
||||
|
||||
DownloadParam param;
|
||||
param.url = url;
|
||||
param.sid = m_sid;
|
||||
param.fname = filename;
|
||||
_notify_download(¶m);
|
||||
|
||||
for(;;) {
|
||||
Downloader* dl = m_mainwin->downloader();
|
||||
if(!dl || dl->code() == Downloader::codeUnknown || dl->code() == Downloader::codeDownloading) {
|
||||
msleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(dl->code() != Downloader::codeSuccess) {
|
||||
qDebug() << "download failed.";
|
||||
_notify_error(QString("%1").arg(LOCAL8BIT("下载文件失败!")));
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
qDebug() << "download ok.";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ThrData::run() {
|
||||
QString msg;
|
||||
QString path_base;
|
||||
|
||||
QString _tmp_res = m_res.toLower();
|
||||
|
||||
if(_tmp_res.startsWith("http")) {
|
||||
qDebug() << "DOWNLOAD";
|
||||
m_need_download = true;
|
||||
|
||||
// "正在缓存录像数据,请稍候..."
|
||||
m_thr_play->_notify_message(LOCAL8BIT("正在下载录像数据,请稍候..."));
|
||||
|
||||
// QString msg;
|
||||
// for(;;) {
|
||||
// msleep(500);
|
||||
|
||||
// if(m_need_stop)
|
||||
// return;
|
||||
|
||||
// if(!m_thr_data->prepare(path_base, msg)) {
|
||||
// msg.sprintf("指定的文件或目录不存在!\n\n%s", _tmp_res.toStdString().c_str());
|
||||
// _notify_error(msg);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if(path_base.length())
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
else {
|
||||
QFileInfo fi_chk_link(m_res);
|
||||
if(fi_chk_link.isSymLink())
|
||||
_tmp_res = fi_chk_link.symLinkTarget();
|
||||
else
|
||||
_tmp_res = m_res;
|
||||
|
||||
QFileInfo fi(_tmp_res);
|
||||
if(!fi.exists()) {
|
||||
msg.sprintf(LOCAL8BIT("指定的文件或目录不存在!\n\n%s").toStdString().c_str(), _tmp_res.toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fi.isFile()) {
|
||||
path_base = fi.path();
|
||||
}
|
||||
else if(fi.isDir()) {
|
||||
path_base = m_res;
|
||||
}
|
||||
|
||||
path_base += "/";
|
||||
}
|
||||
|
||||
//======================================
|
||||
// 加载录像基本信息数据
|
||||
//======================================
|
||||
|
||||
QString tpr_filename(path_base);
|
||||
tpr_filename += "tp-rdp.tpr";
|
||||
|
||||
QFile f_hdr(tpr_filename);
|
||||
if(!f_hdr.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpr_filename << " for read.";
|
||||
msg.sprintf(LOCAL8BIT("无法打开录像信息文件!\n\n%s").toStdString().c_str(), tpr_filename.toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
TS_RECORD_HEADER hdr;
|
||||
memset(&hdr, 0, sizeof(TS_RECORD_HEADER));
|
||||
|
||||
qint64 read_len = 0;
|
||||
read_len = f_hdr.read((char*)(&hdr), sizeof(TS_RECORD_HEADER));
|
||||
if(read_len != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
msg.sprintf(LOCAL8BIT("错误的录像信息文件!\n\n%s").toStdString().c_str(), tpr_filename.toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if(hdr.info.ver != 4) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
msg.sprintf(LOCAL8BIT("不支持的录像文件版本 %d!\n\n此播放器支持录像文件版本 4。").toStdString().c_str(), hdr.info.ver);
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if(hdr.basic.width == 0 || hdr.basic.height == 0) {
|
||||
m_thr_play->_notify_error(LOCAL8BIT("错误的录像信息,未记录窗口尺寸!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(hdr.info.dat_file_count == 0) {
|
||||
m_thr_play->_notify_error(LOCAL8BIT("错误的录像信息,未记录数据文件数量!"));
|
||||
return;
|
||||
}
|
||||
|
||||
//======================================
|
||||
// 加载关键帧数据
|
||||
//======================================
|
||||
QString tpk_filename(path_base);
|
||||
tpk_filename += "tp-rdp.tpk";
|
||||
|
||||
QFile f_kf(tpk_filename);
|
||||
if(!f_kf.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpk_filename << " for read.";
|
||||
msg.sprintf(LOCAL8BIT("无法打开关键帧信息文件!\n\n%s").toStdString().c_str(), tpk_filename.toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 fsize = f_kf.size();
|
||||
if(!fsize || fsize % sizeof(KEYFRAME_INFO) != 0) {
|
||||
qDebug() << "Can not open " << tpk_filename << " for read.";
|
||||
msg.sprintf(LOCAL8BIT("关键帧信息文件格式错误!\n\n").toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
int kf_count = fsize / sizeof(KEYFRAME_INFO);
|
||||
for(int i = 0; i < kf_count; ++i) {
|
||||
KEYFRAME_INFO kf;
|
||||
memset(&kf, 0, sizeof(KEYFRAME_INFO));
|
||||
read_len = f_kf.read((char*)(&kf), sizeof(KEYFRAME_INFO));
|
||||
if(read_len != sizeof(KEYFRAME_INFO)) {
|
||||
qDebug() << "invaid .tpk file.";
|
||||
msg.sprintf(LOCAL8BIT("关键帧信息文件格式错误!\n\n").toStdString().c_str());
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
m_kf.push_back(kf);
|
||||
}
|
||||
|
||||
//======================================
|
||||
// 读取并解析录像数据文件
|
||||
//======================================
|
||||
uint32_t fidx = 0;
|
||||
while(!m_need_stop) {
|
||||
|
||||
for(fidx = 0; fidx < hdr.info.dat_file_count; ++fidx) {
|
||||
QString tpd_filename(path_base);
|
||||
QString str_tmp;
|
||||
|
||||
str_tmp.sprintf("tp-rdp-%d.tpd", fidx+1);
|
||||
tpd_filename += str_tmp;
|
||||
|
||||
QFileInfo fi(tpd_filename);
|
||||
if(!fi.isFile()) {
|
||||
// 文件不存在,如需下载,则启动下载函数并等待下载结束。(下载是异步的吗?)
|
||||
}
|
||||
|
||||
QFile f_dat(tpd_filename);
|
||||
if(!f_dat.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpd_filename << " for read.";
|
||||
// msg.sprintf("无法打开录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
|
||||
msg = QString::fromLocal8Bit("无法打开录像数据文件!\n\n");
|
||||
msg += tpd_filename;
|
||||
m_thr_play->_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(;;) {
|
||||
if(m_need_stop) {
|
||||
qDebug() << "stop, user cancel 2.";
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_need_pause) {
|
||||
msleep(50);
|
||||
time_begin += 50;
|
||||
continue;
|
||||
}
|
||||
|
||||
TS_RECORD_PKG pkg;
|
||||
read_len = f_dat.read((char*)(&pkg), sizeof(pkg));
|
||||
if(read_len == 0)
|
||||
break;
|
||||
if(read_len != sizeof(TS_RECORD_PKG)) {
|
||||
qDebug() << "invaid .tpd file (1).";
|
||||
// msg.sprintf("错误的录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
|
||||
msg = QString::fromLocal8Bit("错误的录像数据文件!\n\n");
|
||||
msg += tpd_filename.toStdString().c_str();
|
||||
_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
qDebug("----key frame: %d", pkg.time_ms);
|
||||
}
|
||||
|
||||
UpdateData* dat = new UpdateData(TYPE_DATA);
|
||||
dat->alloc_data(sizeof(TS_RECORD_PKG) + pkg.size);
|
||||
memcpy(dat->data_buf(), &pkg, sizeof(TS_RECORD_PKG));
|
||||
read_len = f_dat.read((char*)(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
||||
if(read_len != pkg.size) {
|
||||
delete dat;
|
||||
qDebug() << "invaid .tpd file.";
|
||||
// msg.sprintf("错误的录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
|
||||
msg = QString::fromLocal8Bit("错误的录像数据文件!\n\n");
|
||||
msg += tpd_filename.toStdString().c_str();
|
||||
_notify_error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
pkg_count++;
|
||||
|
||||
time_pass = (uint32_t)(QDateTime::currentMSecsSinceEpoch() - time_begin) * m_speed;
|
||||
if(time_pass > total_ms)
|
||||
time_pass = total_ms;
|
||||
if(time_pass - time_last_pass > 200) {
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(time_pass);
|
||||
emit signal_update_data(_passed_ms);
|
||||
time_last_pass = time_pass;
|
||||
}
|
||||
|
||||
if(time_pass >= pkg.time_ms) {
|
||||
emit signal_update_data(dat);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 需要等待
|
||||
uint32_t time_wait = pkg.time_ms - time_pass;
|
||||
uint32_t wait_this_time = 0;
|
||||
for(;;) {
|
||||
if(m_need_pause) {
|
||||
msleep(50);
|
||||
time_begin += 50;
|
||||
continue;
|
||||
}
|
||||
|
||||
wait_this_time = time_wait;
|
||||
if(wait_this_time > 10)
|
||||
wait_this_time = 10;
|
||||
|
||||
if(m_need_stop) {
|
||||
qDebug() << "stop, user cancel (2).";
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(wait_this_time);
|
||||
|
||||
uint32_t _time_pass = (uint32_t)(QDateTime::currentMSecsSinceEpoch() - time_begin) * m_speed;
|
||||
if(_time_pass > total_ms)
|
||||
_time_pass = total_ms;
|
||||
if(_time_pass - time_last_pass > 200) {
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(_time_pass);
|
||||
emit signal_update_data(_passed_ms);
|
||||
time_last_pass = _time_pass;
|
||||
}
|
||||
|
||||
time_wait -= wait_this_time;
|
||||
if(time_wait == 0) {
|
||||
emit signal_update_data(dat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// msg = LOCAL8BIT("开始播放...");
|
||||
// m_thr_play->_notify_error(msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ThrData::_prepare() {
|
||||
UpdateData* d = new UpdateData(TYPE_HEADER_INFO);
|
||||
|
||||
m_locker.lock();
|
||||
m_data.enqueue(d);
|
||||
m_locker.unlock();
|
||||
}
|
||||
|
||||
UpdateData* ThrData::get_data() {
|
||||
|
||||
m_locker.lock();
|
||||
UpdateData* d = m_data.dequeue();
|
||||
m_locker.unlock();
|
||||
|
||||
return d;
|
||||
}
|
|
@ -1,13 +1,20 @@
|
|||
#ifndef THREADDOWNLOAD_H
|
||||
#define THREADDOWNLOAD_H
|
||||
#ifndef THR_DATA_H
|
||||
#define THR_DATA_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QQueue>
|
||||
#include <QMutex>
|
||||
#include <QNetworkReply>
|
||||
#include <QFile>
|
||||
#include "downloader.h"
|
||||
#include "update_data.h"
|
||||
#include "record_format.h"
|
||||
|
||||
/*
|
||||
为支持“边下载,边播放”、“可拖动进度条”等功能,录像数据会分为多个文件存放,目前每个文件约4MB。
|
||||
例如:
|
||||
tp-rdp.tpr
|
||||
tp-rdp.tpk (关键帧信息文件,v3.5.0开始引入)
|
||||
tp-rdp.tpk (关键帧信息文件,v3.5.1开始引入)
|
||||
tp-rdp-1.tpd, tp-rdp-2.tpd, tp-rdp-3.tpd, ...
|
||||
这样,下载完一个数据文件,即可播放此数据文件中的内容,同时下载线程可以下载后续数据文件。
|
||||
|
||||
|
@ -25,23 +32,66 @@
|
|||
这样,下次需要下载指定文件时,如果发现对应的临时文件存在,可以根据已下载字节数,继续下载。
|
||||
*/
|
||||
|
||||
typedef struct KEYFRAME_INFO {
|
||||
uint32_t time_ms; // 此关键帧的时间点
|
||||
uint32_t file_index; // 此关键帧图像数据位于哪一个数据文件中
|
||||
uint32_t offset; // 此关键帧图像数据在数据文件中的偏移
|
||||
}KEYFRAME_INFO;
|
||||
|
||||
class ThreadDownload : public QThread
|
||||
{
|
||||
typedef std::vector<KEYFRAME_INFO> KeyFrames;
|
||||
|
||||
class MainWindow;
|
||||
|
||||
// 下载必要的文件,解析文件数据,生成图像数据(QImage*),将数据包放入待显示队列中,等待 ThrPlay 线程使用
|
||||
// 注意,无需将所有数据解析并放入待显示队列,此队列有数量限制(例如1000个),避免过多占用内存
|
||||
class ThrData : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ThreadDownload(const QString& url);
|
||||
ThrData(MainWindow* mainwin, const QString& url);
|
||||
~ThrData();
|
||||
|
||||
virtual void run();
|
||||
void stop();
|
||||
|
||||
// 下载 .tpr 和 .tpf 文件,出错返回false,正在下载或已经下载完成则返回true.
|
||||
bool prepare(QString& path_base, QString& msg);
|
||||
|
||||
bool have_more_data();
|
||||
|
||||
UpdateData* get_data();
|
||||
|
||||
private:
|
||||
bool m_need_stop;
|
||||
QString m_url;
|
||||
|
||||
bool _load_header();
|
||||
bool _load_keyframe();
|
||||
bool _download_file(const QString& url, const QString filename);
|
||||
|
||||
void _prepare();
|
||||
|
||||
void _notify_message(const QString& msg);
|
||||
void _notify_error(const QString& err_msg);
|
||||
void _notify_download(DownloadParam* param);
|
||||
|
||||
signals:
|
||||
void signal_update_data(UpdateData*);
|
||||
void signal_download(DownloadParam*);
|
||||
|
||||
private:
|
||||
MainWindow* m_mainwin;
|
||||
QQueue<UpdateData*> m_data;
|
||||
QMutex m_locker;
|
||||
|
||||
bool m_need_stop;
|
||||
|
||||
bool m_need_download;
|
||||
QString m_res;
|
||||
QString m_local_data_path_base;
|
||||
|
||||
QString m_url_base;
|
||||
QString m_sid;
|
||||
QString m_rid;
|
||||
QString m_path_base;
|
||||
|
||||
TS_RECORD_HEADER m_hdr;
|
||||
KeyFrames m_kf;
|
||||
};
|
||||
|
||||
#endif // THREADDOWNLOAD_H
|
||||
#endif // THR_DATA_H
|
|
@ -1,34 +0,0 @@
|
|||
#include "thr_download.h"
|
||||
#include <QDebug>
|
||||
|
||||
ThreadDownload::ThreadDownload(const QString& url)
|
||||
{
|
||||
m_url = url;
|
||||
m_need_stop = false;
|
||||
}
|
||||
|
||||
void ThreadDownload::stop() {
|
||||
if(!isRunning())
|
||||
return;
|
||||
m_need_stop = true;
|
||||
wait();
|
||||
qDebug() << "download thread end.";
|
||||
}
|
||||
|
||||
bool ThreadDownload::prepare(QString& path_base, QString& msg) {
|
||||
path_base = m_path_base;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ThreadDownload::run() {
|
||||
for(int i = 0; i < 500; i++) {
|
||||
if(m_need_stop)
|
||||
break;
|
||||
msleep(100);
|
||||
|
||||
if(i == 50) {
|
||||
m_path_base = "/Users/apex/Desktop/tp-testdata/";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,36 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "record_format.h"
|
||||
#include "util.h"
|
||||
|
||||
ThreadPlay::ThreadPlay(const QString& res)
|
||||
{
|
||||
|
||||
/*
|
||||
* 录像播放流程:
|
||||
* - 数据处理线程,该线程负责(下载)文件、解析文件,将数据准备成待播放队列;
|
||||
* + 数据处理线程维护待播放队列,少于500个则填充至1000个,每20ms检查一次队列是否少于500个。
|
||||
* - 播放线程从队列中取出一个数据,判断当前时间是否应该播放此数据,如果应该,则将此数据发送给主UI
|
||||
* + if( 播放速率 * (当前时间 - 播放时间) >= (当前数据包偏移时间 - 上个数据包偏移时间)) 则 播放
|
||||
* + 如选择“跳过无操作时间”,则数据包偏移时间差超过3秒的,视为3秒。
|
||||
*/
|
||||
|
||||
|
||||
ThrPlay::ThrPlay() {
|
||||
m_need_stop = false;
|
||||
m_need_pause = false;
|
||||
m_speed = 2;
|
||||
m_res = res;
|
||||
m_thr_download = nullptr;
|
||||
// m_res = res;
|
||||
// m_thr_data = nullptr;
|
||||
}
|
||||
|
||||
ThreadPlay::~ThreadPlay() {
|
||||
ThrPlay::~ThrPlay() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void ThreadPlay::stop() {
|
||||
void ThrPlay::stop() {
|
||||
if(!isRunning())
|
||||
return;
|
||||
|
||||
|
@ -31,28 +40,31 @@ void ThreadPlay::stop() {
|
|||
wait();
|
||||
qDebug() << "play-thread end.";
|
||||
|
||||
if(m_thr_download) {
|
||||
m_thr_download->stop();
|
||||
//m_thr_download->wait();
|
||||
delete m_thr_download;
|
||||
m_thr_download = nullptr;
|
||||
}
|
||||
// if(m_thr_data) {
|
||||
// m_thr_data->stop();
|
||||
// qDebug("delete thrData.");
|
||||
// //m_thr_download->wait();
|
||||
// delete m_thr_data;
|
||||
// m_thr_data = nullptr;
|
||||
// }
|
||||
}
|
||||
|
||||
void ThreadPlay::_notify_message(const QString& msg) {
|
||||
update_data* _msg = new update_data(TYPE_MESSAGE);
|
||||
void ThrPlay::_notify_message(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThreadPlay::_notify_error(const QString& err_msg) {
|
||||
update_data* _err = new update_data(TYPE_ERROR);
|
||||
_err->message(err_msg);
|
||||
emit signal_update_data(_err);
|
||||
void ThrPlay::_notify_error(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_ERROR);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrPlay::run() {
|
||||
|
||||
void ThreadPlay::run() {
|
||||
// http://127.0.0.1:7190/tp_1491560510_ca67fceb75a78c9d/211
|
||||
// E:\work\tp4a\teleport\server\share\replay\rdp\000000211
|
||||
|
||||
//#ifdef __APPLE__
|
||||
// QString currentPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
|
@ -62,11 +74,19 @@ void ThreadPlay::run() {
|
|||
//#endif
|
||||
|
||||
// /Users/apex/Library/Preferences/tp-player
|
||||
//qDebug() << "appdata:" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
// qDebug() << "appdata:" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
|
||||
// /private/var/folders/_3/zggrxjdx1lxcdqnfsbgpcwzh0000gn/T
|
||||
//qDebug() << "tmp:" << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
||||
|
||||
// m_thr_data = new ThrData(this, m_res);
|
||||
// m_thr_data->start();
|
||||
|
||||
// "正在准备录像数据,请稍候..."
|
||||
// _notify_message(LOCAL8BIT("正在准备录像数据,请稍候..."));
|
||||
|
||||
|
||||
#if 0
|
||||
// base of data path (include the .tpr file)
|
||||
QString path_base;
|
||||
|
||||
|
@ -78,8 +98,8 @@ void ThreadPlay::run() {
|
|||
// "正在缓存录像数据,请稍候..."
|
||||
_notify_message("正在缓存录像数据,请稍候...");
|
||||
|
||||
m_thr_download = new ThreadDownload(m_res);
|
||||
m_thr_download->start();
|
||||
m_thr_data = new ThreadDownload(m_res);
|
||||
m_thr_data->start();
|
||||
|
||||
QString msg;
|
||||
for(;;) {
|
||||
|
@ -88,7 +108,7 @@ void ThreadPlay::run() {
|
|||
if(m_need_stop)
|
||||
return;
|
||||
|
||||
if(!m_thr_download->prepare(path_base, msg)) {
|
||||
if(!m_thr_data->prepare(path_base, msg)) {
|
||||
msg.sprintf("指定的文件或目录不存在!\n\n%s", _tmp_res.toStdString().c_str());
|
||||
_notify_error(msg);
|
||||
return;
|
||||
|
@ -147,7 +167,7 @@ void ThreadPlay::run() {
|
|||
return;
|
||||
}
|
||||
else {
|
||||
update_data* dat = new update_data(TYPE_HEADER_INFO);
|
||||
UpdateData* dat = new UpdateData(TYPE_HEADER_INFO);
|
||||
dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
||||
|
||||
read_len = f_hdr.read((char*)(dat->data_buf()), dat->data_len());
|
||||
|
@ -251,7 +271,7 @@ void ThreadPlay::run() {
|
|||
qDebug("----key frame: %d", pkg.time_ms);
|
||||
}
|
||||
|
||||
update_data* dat = new update_data(TYPE_DATA);
|
||||
UpdateData* dat = new UpdateData(TYPE_DATA);
|
||||
dat->alloc_data(sizeof(TS_RECORD_PKG) + pkg.size);
|
||||
memcpy(dat->data_buf(), &pkg, sizeof(TS_RECORD_PKG));
|
||||
read_len = f_dat.read((char*)(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
||||
|
@ -271,7 +291,7 @@ void ThreadPlay::run() {
|
|||
if(time_pass > total_ms)
|
||||
time_pass = total_ms;
|
||||
if(time_pass - time_last_pass > 200) {
|
||||
update_data* _passed_ms = new update_data(TYPE_PLAYED_MS);
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(time_pass);
|
||||
emit signal_update_data(_passed_ms);
|
||||
time_last_pass = time_pass;
|
||||
|
@ -307,7 +327,7 @@ void ThreadPlay::run() {
|
|||
if(_time_pass > total_ms)
|
||||
_time_pass = total_ms;
|
||||
if(_time_pass - time_last_pass > 200) {
|
||||
update_data* _passed_ms = new update_data(TYPE_PLAYED_MS);
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(_time_pass);
|
||||
emit signal_update_data(_passed_ms);
|
||||
time_last_pass = _time_pass;
|
||||
|
@ -330,6 +350,9 @@ void ThreadPlay::run() {
|
|||
_notify_message(msg);
|
||||
}
|
||||
|
||||
update_data* _end = new update_data(TYPE_END);
|
||||
#endif
|
||||
|
||||
qDebug("play end.");
|
||||
UpdateData* _end = new UpdateData(TYPE_END);
|
||||
emit signal_update_data(_end);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
#ifndef THR_PLAY_H
|
||||
#ifndef THR_PLAY_H
|
||||
#define THR_PLAY_H
|
||||
|
||||
#include <QThread>
|
||||
#include "update_data.h"
|
||||
#include "thr_download.h"
|
||||
#include "downloader.h"
|
||||
|
||||
class ThreadPlay : public QThread
|
||||
// 根据播放规则,将要播放的图像发送给主UI线程进行显示
|
||||
class ThrPlay : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ThrData;
|
||||
public:
|
||||
ThreadPlay(const QString& res);
|
||||
~ThreadPlay();
|
||||
ThrPlay();
|
||||
~ThrPlay();
|
||||
|
||||
virtual void run();
|
||||
void stop();
|
||||
|
@ -23,17 +26,12 @@ private:
|
|||
void _notify_error(const QString& err_msg);
|
||||
|
||||
signals:
|
||||
void signal_update_data(update_data*);
|
||||
void signal_update_data(UpdateData*);
|
||||
|
||||
private:
|
||||
bool m_need_stop;
|
||||
bool m_need_pause;
|
||||
int m_speed;
|
||||
|
||||
QString m_res;
|
||||
bool m_need_download;
|
||||
|
||||
ThreadDownload* m_thr_download;
|
||||
};
|
||||
|
||||
#endif // THR_PLAY_H
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
TEMPLATE = app
|
||||
TARGET = tp-player
|
||||
|
||||
QT += core gui widgets
|
||||
QT += core gui widgets network
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
bar.h \
|
||||
thr_download.h \
|
||||
thr_play.h \
|
||||
thr_data.h \
|
||||
update_data.h \
|
||||
record_format.h \
|
||||
rle.h \
|
||||
util.h
|
||||
util.h \
|
||||
downloader.h
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
bar.cpp \
|
||||
thr_download.cpp \
|
||||
thr_play.cpp \
|
||||
thr_data.cpp \
|
||||
update_data.cpp \
|
||||
rle.c \
|
||||
util.cpp
|
||||
util.cpp \
|
||||
downloader.cpp
|
||||
|
||||
RESOURCES += \
|
||||
tp-player.qrc
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
#include "update_data.h"
|
||||
#include "update_data.h"
|
||||
|
||||
update_data::update_data(int data_type, QObject *parent) : QObject(parent)
|
||||
UpdateData::UpdateData(int data_type, QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_data_type = data_type;
|
||||
m_data_buf = nullptr;
|
||||
m_data_len = 0;
|
||||
}
|
||||
|
||||
update_data::~update_data() {
|
||||
UpdateData::~UpdateData() {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
}
|
||||
|
||||
void update_data::alloc_data(uint32_t len) {
|
||||
void UpdateData::alloc_data(uint32_t len) {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
|
||||
|
@ -21,7 +21,7 @@ void update_data::alloc_data(uint32_t len) {
|
|||
m_data_len = len;
|
||||
}
|
||||
|
||||
void update_data::attach_data(const uint8_t* dat, uint32_t len) {
|
||||
void UpdateData::attach_data(const uint8_t* dat, uint32_t len) {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
m_data_buf = new uint8_t[len];
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
#define TYPE_MESSAGE 5
|
||||
#define TYPE_ERROR 6
|
||||
|
||||
class update_data : public QObject
|
||||
class UpdateData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit update_data(int data_type, QObject *parent = nullptr);
|
||||
virtual ~update_data();
|
||||
explicit UpdateData(int data_type, QObject *parent = nullptr);
|
||||
virtual ~UpdateData();
|
||||
|
||||
void alloc_data(uint32_t len);
|
||||
void attach_data(const uint8_t* dat, uint32_t len);
|
||||
|
@ -47,7 +47,7 @@ private:
|
|||
|
||||
class UpdateDataHelper {
|
||||
public:
|
||||
UpdateDataHelper(update_data* data) {
|
||||
UpdateDataHelper(UpdateData* data) {
|
||||
m_data = data;
|
||||
}
|
||||
~UpdateDataHelper() {
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
update_data* m_data;
|
||||
UpdateData* m_data;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef TP_PLAYER_UTIL_H
|
||||
#define TP_PLAYER_UTIL_H
|
||||
|
||||
#include <QTime>
|
||||
|
||||
class TimeUseTest {
|
||||
public:
|
||||
TimeUseTest() {
|
||||
m_used_ms = 0;
|
||||
m_count = 0;
|
||||
}
|
||||
~TimeUseTest() {}
|
||||
|
||||
void begin() {
|
||||
m_time.start();
|
||||
}
|
||||
void end() {
|
||||
m_count++;
|
||||
m_used_ms += m_time.elapsed();
|
||||
}
|
||||
|
||||
uint32_t used() const {return m_used_ms;}
|
||||
uint32_t count() const {return m_count;}
|
||||
|
||||
private:
|
||||
QTime m_time;
|
||||
uint32_t m_used_ms;
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
#define LOCAL8BIT(x) QString::fromLocal8Bit(x)
|
||||
|
||||
#endif // TP_PLAYER_UTIL_H
|
|
@ -76,10 +76,11 @@ typedef struct TS_RECORD_HEADER {
|
|||
|
||||
// 一个数据包的头
|
||||
typedef struct TS_RECORD_PKG {
|
||||
ex_u8 type; // 包的数据类型
|
||||
ex_u32 size; // 这个包的总大小(不含包头)
|
||||
ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||
ex_u8 _reserve[3]; // 保留
|
||||
ex_u8 type; // 包的数据类型
|
||||
ex_u8 _reserve[3]; // 保留
|
||||
ex_u32 size; // 这个包的总大小(不含包头)
|
||||
ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||
ex_u32 index; // 这个包的序号(最后一个包的序号与TS_RECORD_HEADER_INFO::packages数量匹配)
|
||||
}TS_RECORD_PKG;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
|
@ -671,12 +671,13 @@ class DoGetFileHandler(TPBaseHandler):
|
|||
# return self.write('need login first.')
|
||||
# self._user = _user
|
||||
|
||||
if not self._user['_is_login']:
|
||||
self.set_status(401) # 401=未授权, 要求身份验证
|
||||
return self.write('need login first.')
|
||||
if (self._user['privilege'] & require_privilege) == 0:
|
||||
self.set_status(403) # 403=禁止
|
||||
return self.write('you have no such privilege.')
|
||||
# when test, disable auth.
|
||||
# if not self._user['_is_login']:
|
||||
# self.set_status(401) # 401=未授权, 要求身份验证
|
||||
# return self.write('need login first.')
|
||||
# if (self._user['privilege'] & require_privilege) == 0:
|
||||
# self.set_status(403) # 403=禁止
|
||||
# return self.write('you have no such privilege.')
|
||||
|
||||
act = self.get_argument('act', None)
|
||||
_type = self.get_argument('type', None)
|
||||
|
|
Loading…
Reference in New Issue