.temp.
parent
ad5534fd94
commit
2f7fc16235
|
|
@ -1,4 +1,4 @@
|
||||||
#include "bar.h"
|
#include "bar.h"
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef BAR_H
|
#ifndef BAR_H
|
||||||
#define BAR_H
|
#define BAR_H
|
||||||
|
|
||||||
#include <QPainter>
|
#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 应用程序文件名
|
// 编译出来的可执行程序复制到单独目录,然后执行 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[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
|
|
||||||
QApplication a(argc, argv);
|
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");
|
QGuiApplication::setApplicationDisplayName("TP-Player");
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
|
|
@ -32,19 +81,25 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if(parser.isSet(opt_help)) {
|
if(parser.isSet(opt_help)) {
|
||||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
show_usage(parser);
|
||||||
"<html><head/><body><pre>"
|
// QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||||
+ parser.helpText()
|
// "<html><head/><body><pre>"
|
||||||
+ "\n\n"
|
// + parser.helpText()
|
||||||
+ "RESOURCE could be:\n"
|
// + "\n\n"
|
||||||
+ " teleport record file (.tpr).\n"
|
// + "RESOURCE could be:\n"
|
||||||
+ " a directory contains .tpr file.\n"
|
// + " teleport record file (.tpr).\n"
|
||||||
+ " an URL for download teleport record file."
|
// + " a directory contains .tpr file.\n"
|
||||||
+ "</pre></body></html>");
|
// + " an URL for download teleport record file."
|
||||||
|
// + "</pre></body></html>");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList args = parser.positionalArguments();
|
const QStringList args = parser.positionalArguments();
|
||||||
|
if(0 == args.size()) {
|
||||||
|
show_usage(parser);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
QString resource = args.at(0);
|
QString resource = args.at(0);
|
||||||
qDebug() << resource;
|
qDebug() << resource;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "rle.h"
|
#include "rle.h"
|
||||||
|
|
||||||
|
|
@ -86,10 +86,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
m_bar_fade_in = false;
|
m_bar_fade_in = false;
|
||||||
m_bar_fading = false;
|
m_bar_fading = false;
|
||||||
m_bar_opacity = 1.0;
|
m_bar_opacity = 1.0;
|
||||||
|
m_show_message = false;
|
||||||
memset(&m_pt, 0, sizeof(TS_RECORD_RDP_POINTER));
|
memset(&m_pt, 0, sizeof(TS_RECORD_RDP_POINTER));
|
||||||
|
|
||||||
m_thr_play = nullptr;
|
m_thr_play = nullptr;
|
||||||
m_play_state = PLAY_STATE_UNKNOWN;
|
m_play_state = PLAY_STATE_UNKNOWN;
|
||||||
|
m_thr_data = nullptr;
|
||||||
|
|
||||||
|
m_dl = nullptr;
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
|
@ -107,6 +111,11 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
m_pt_normal.load(":/tp-player/res/cursor.png");
|
m_pt_normal.load(":/tp-player/res/cursor.png");
|
||||||
m_default_bg.load(":/tp-player/res/bg.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); // 禁止最大化按钮
|
setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint); // 禁止最大化按钮
|
||||||
setFixedSize(m_default_bg.width(), m_default_bg.height()); // 禁止拖动窗口大小
|
setFixedSize(m_default_bg.width(), m_default_bg.height()); // 禁止拖动窗口大小
|
||||||
|
|
||||||
|
|
@ -115,6 +124,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// connect(&m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
// 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_first_run, SIGNAL(timeout()), this, SLOT(_do_first_run()));
|
||||||
connect(&m_timer_bar_fade, SIGNAL(timeout()), this, SLOT(_do_bar_fade()));
|
connect(&m_timer_bar_fade, SIGNAL(timeout()), this, SLOT(_do_bar_fade()));
|
||||||
|
|
@ -131,12 +141,25 @@ MainWindow::~MainWindow()
|
||||||
//m_thr_play->wait();
|
//m_thr_play->wait();
|
||||||
//qDebug() << "play thread stoped.";
|
//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;
|
delete m_thr_play;
|
||||||
m_thr_play = nullptr;
|
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;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +168,11 @@ void MainWindow::set_resource(const QString &res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::_do_first_run() {
|
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();
|
_start_play_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,14 +181,15 @@ void MainWindow::_start_play_thread() {
|
||||||
m_thr_play->stop();
|
m_thr_play->stop();
|
||||||
//m_thr_play->wait();
|
//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;
|
delete m_thr_play;
|
||||||
m_thr_play = nullptr;
|
m_thr_play = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_thr_play = new ThreadPlay(m_res);
|
m_thr_play = new ThrPlay();
|
||||||
connect(m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(_do_update_data(update_data*)));
|
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->speed(m_bar.get_speed());
|
||||||
m_thr_play->start();
|
m_thr_play->start();
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +215,31 @@ 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);
|
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());
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
painter.setOpacity(m_bar_opacity);
|
||||||
|
m_bar.draw(painter, e->rect());
|
||||||
|
}
|
||||||
|
else if(m_bar_shown) {
|
||||||
|
m_bar.draw(painter, e->rect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_show_message) {
|
||||||
QRect rc_draw = e->rect();
|
QRect rc_draw = e->rect();
|
||||||
QRect rc(m_rc_message);
|
QRect rc(m_rc_message);
|
||||||
//rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
//rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||||
|
|
@ -200,16 +253,6 @@ void MainWindow::paintEvent(QPaintEvent *e)
|
||||||
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制浮动控制窗
|
|
||||||
if(m_bar_fading) {
|
|
||||||
painter.setOpacity(m_bar_opacity);
|
|
||||||
m_bar.draw(painter, e->rect());
|
|
||||||
}
|
|
||||||
else if(m_bar_shown) {
|
|
||||||
m_bar.draw(painter, e->rect());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if(!m_shown) {
|
// if(!m_shown) {
|
||||||
// m_shown = true;
|
// m_shown = true;
|
||||||
// //m_thr_play.start();
|
// //m_thr_play.start();
|
||||||
|
|
@ -234,7 +277,7 @@ void MainWindow::resume() {
|
||||||
m_play_state = PLAY_STATE_RUNNING;
|
m_play_state = PLAY_STATE_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::_do_update_data(update_data* dat) {
|
void MainWindow::_do_update_data(UpdateData* dat) {
|
||||||
if(!dat)
|
if(!dat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -297,11 +340,19 @@ void MainWindow::_do_update_data(update_data* dat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(dat->data_type() == TYPE_MESSAGE) {
|
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);
|
QPainter pp(&m_canvas);
|
||||||
QRect rcWin(0, 0, m_canvas.width(), m_canvas.height());
|
QRect rcWin(0, 0, m_canvas.width(), m_canvas.height());
|
||||||
pp.drawText(rcWin, Qt::AlignLeft|Qt::TextDontPrint, dat->message(), &m_rc_message);
|
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.setWidth(m_rc_message.width()+60);
|
||||||
m_rc_message.setHeight(m_rc_message.height()+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.setPen(QColor(255,255,255,153));
|
||||||
pm.fillRect(m_rc_message, QColor(0,0,0,190));
|
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);
|
QRect rcText(m_rc_message);
|
||||||
rcText.setLeft(30);
|
rcText.setLeft(30);
|
||||||
rcText.setTop(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.width() - m_rc_message.width())/2,
|
||||||
(m_canvas.height() - m_rc_message.height())/3
|
(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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(dat->data_type() == TYPE_ERROR) {
|
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);
|
QApplication::instance()->exit(0);
|
||||||
return;
|
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 << ")";
|
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_canvas = QPixmap(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||||
|
|
||||||
//m_win_board_w = frameGeometry().width() - geometry().width();
|
//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_win_board_w, m_rec_hdr.basic.height + m_win_board_h);
|
||||||
//resize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
//resize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||||
setFixedSize(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));
|
m_canvas.fill(QColor(38, 73, 111));
|
||||||
|
|
||||||
|
|
@ -422,6 +481,18 @@ void MainWindow::_do_bar_fade() {
|
||||||
update(m_bar.rc());
|
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) {
|
void MainWindow::mouseMoveEvent(QMouseEvent *e) {
|
||||||
if(!m_show_default) {
|
if(!m_show_default) {
|
||||||
QRect rc = m_bar.rc();
|
QRect rc = m_bar.rc();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
@ -6,9 +6,11 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "bar.h"
|
#include "bar.h"
|
||||||
#include "thr_play.h"
|
#include "thr_play.h"
|
||||||
|
#include "thr_data.h"
|
||||||
#include "update_data.h"
|
#include "update_data.h"
|
||||||
#include "record_format.h"
|
#include "record_format.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "downloader.h"
|
||||||
|
|
||||||
#define PLAY_STATE_UNKNOWN 0
|
#define PLAY_STATE_UNKNOWN 0
|
||||||
#define PLAY_STATE_RUNNING 1
|
#define PLAY_STATE_RUNNING 1
|
||||||
|
|
@ -34,6 +36,9 @@ public:
|
||||||
void restart();
|
void restart();
|
||||||
void speed(int s);
|
void speed(int s);
|
||||||
|
|
||||||
|
Downloader* downloader() {return m_dl;}
|
||||||
|
void reset_downloader() {if(m_dl){delete m_dl;m_dl= nullptr;}}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paintEvent(QPaintEvent *e);
|
void paintEvent(QPaintEvent *e);
|
||||||
void mouseMoveEvent(QMouseEvent *e);
|
void mouseMoveEvent(QMouseEvent *e);
|
||||||
|
|
@ -43,10 +48,13 @@ private:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void _do_first_run(); // 默认界面加载完成后,开始播放操作(可能会进行数据下载)
|
void _do_first_run(); // 默认界面加载完成后,开始播放操作(可能会进行数据下载)
|
||||||
void _do_update_data(update_data*);
|
void _do_update_data(UpdateData*);
|
||||||
void _do_bar_fade();
|
void _do_bar_fade();
|
||||||
void _do_bar_delay_hide();
|
void _do_bar_delay_hide();
|
||||||
|
|
||||||
|
// void _do_download(Downloader*);
|
||||||
|
void _do_download(DownloadParam*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
|
|
@ -56,7 +64,8 @@ private:
|
||||||
QPixmap m_default_bg;
|
QPixmap m_default_bg;
|
||||||
|
|
||||||
QString m_res;
|
QString m_res;
|
||||||
ThreadPlay* m_thr_play;
|
ThrPlay* m_thr_play;
|
||||||
|
ThrData* m_thr_data;
|
||||||
|
|
||||||
QPixmap m_canvas;
|
QPixmap m_canvas;
|
||||||
|
|
||||||
|
|
@ -76,10 +85,14 @@ private:
|
||||||
|
|
||||||
int m_play_state;
|
int m_play_state;
|
||||||
|
|
||||||
|
bool m_show_message;
|
||||||
QPixmap m_img_message;
|
QPixmap m_img_message;
|
||||||
QRect m_rc_message;
|
QRect m_rc_message;
|
||||||
|
|
||||||
|
|
||||||
|
QNetworkAccessManager m_nam;
|
||||||
|
Downloader* m_dl;
|
||||||
|
|
||||||
// for test
|
// for test
|
||||||
TimeUseTest m_time_imgconvert_normal;
|
TimeUseTest m_time_imgconvert_normal;
|
||||||
TimeUseTest m_time_imgconvert_compressed;
|
TimeUseTest m_time_imgconvert_compressed;
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,10 @@ typedef struct TS_RECORD_HEADER {
|
||||||
// 一个数据包的头
|
// 一个数据包的头
|
||||||
typedef struct TS_RECORD_PKG {
|
typedef struct TS_RECORD_PKG {
|
||||||
uint8_t type; // 包的数据类型
|
uint8_t type; // 包的数据类型
|
||||||
|
uint8_t _reserve[3]; // 保留
|
||||||
uint32_t size; // 这个包的总大小(不含包头)
|
uint32_t size; // 这个包的总大小(不含包头)
|
||||||
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||||
uint8_t _reserve[3]; // 保留
|
uint32_t index; // 这个包的序号(最后一个包的序号与TS_RECORD_HEADER_INFO::packages数量匹配)
|
||||||
}TS_RECORD_PKG;
|
}TS_RECORD_PKG;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*- c-basic-offset: 8 -*-
|
/* -*- c-basic-offset: 8 -*-
|
||||||
rdesktop: A Remote Desktop Protocol client.
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
Bitmap decompression routines
|
Bitmap decompression routines
|
||||||
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
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
|
#ifndef THR_DATA_H
|
||||||
#define THREADDOWNLOAD_H
|
#define THR_DATA_H
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QFile>
|
||||||
|
#include "downloader.h"
|
||||||
|
#include "update_data.h"
|
||||||
|
#include "record_format.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
为支持“边下载,边播放”、“可拖动进度条”等功能,录像数据会分为多个文件存放,目前每个文件约4MB。
|
为支持“边下载,边播放”、“可拖动进度条”等功能,录像数据会分为多个文件存放,目前每个文件约4MB。
|
||||||
例如:
|
例如:
|
||||||
tp-rdp.tpr
|
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, ...
|
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:
|
public:
|
||||||
ThreadDownload(const QString& url);
|
ThrData(MainWindow* mainwin, const QString& url);
|
||||||
|
~ThrData();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
// 下载 .tpr 和 .tpf 文件,出错返回false,正在下载或已经下载完成则返回true.
|
|
||||||
bool prepare(QString& path_base, QString& msg);
|
bool have_more_data();
|
||||||
|
|
||||||
|
UpdateData* get_data();
|
||||||
|
|
||||||
private:
|
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;
|
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 <QCoreApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
|
|
||||||
#include "thr_play.h"
|
#include "thr_play.h"
|
||||||
|
#include "thr_data.h"
|
||||||
#include "record_format.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_stop = false;
|
||||||
m_need_pause = false;
|
m_need_pause = false;
|
||||||
m_speed = 2;
|
m_speed = 2;
|
||||||
m_res = res;
|
// m_res = res;
|
||||||
m_thr_download = nullptr;
|
// m_thr_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadPlay::~ThreadPlay() {
|
ThrPlay::~ThrPlay() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPlay::stop() {
|
void ThrPlay::stop() {
|
||||||
if(!isRunning())
|
if(!isRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -31,28 +40,31 @@ void ThreadPlay::stop() {
|
||||||
wait();
|
wait();
|
||||||
qDebug() << "play-thread end.";
|
qDebug() << "play-thread end.";
|
||||||
|
|
||||||
if(m_thr_download) {
|
// if(m_thr_data) {
|
||||||
m_thr_download->stop();
|
// m_thr_data->stop();
|
||||||
//m_thr_download->wait();
|
// qDebug("delete thrData.");
|
||||||
delete m_thr_download;
|
// //m_thr_download->wait();
|
||||||
m_thr_download = nullptr;
|
// delete m_thr_data;
|
||||||
}
|
// m_thr_data = nullptr;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPlay::_notify_message(const QString& msg) {
|
void ThrPlay::_notify_message(const QString& msg) {
|
||||||
update_data* _msg = new update_data(TYPE_MESSAGE);
|
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
|
||||||
_msg->message(msg);
|
_msg->message(msg);
|
||||||
emit signal_update_data(_msg);
|
emit signal_update_data(_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPlay::_notify_error(const QString& err_msg) {
|
void ThrPlay::_notify_error(const QString& msg) {
|
||||||
update_data* _err = new update_data(TYPE_ERROR);
|
UpdateData* _msg = new UpdateData(TYPE_ERROR);
|
||||||
_err->message(err_msg);
|
_msg->message(msg);
|
||||||
emit signal_update_data(_err);
|
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__
|
//#ifdef __APPLE__
|
||||||
// QString currentPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
// QString currentPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
|
@ -67,6 +79,14 @@ void ThreadPlay::run() {
|
||||||
// /private/var/folders/_3/zggrxjdx1lxcdqnfsbgpcwzh0000gn/T
|
// /private/var/folders/_3/zggrxjdx1lxcdqnfsbgpcwzh0000gn/T
|
||||||
//qDebug() << "tmp:" << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
//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)
|
// base of data path (include the .tpr file)
|
||||||
QString path_base;
|
QString path_base;
|
||||||
|
|
||||||
|
|
@ -78,8 +98,8 @@ void ThreadPlay::run() {
|
||||||
// "正在缓存录像数据,请稍候..."
|
// "正在缓存录像数据,请稍候..."
|
||||||
_notify_message("正在缓存录像数据,请稍候...");
|
_notify_message("正在缓存录像数据,请稍候...");
|
||||||
|
|
||||||
m_thr_download = new ThreadDownload(m_res);
|
m_thr_data = new ThreadDownload(m_res);
|
||||||
m_thr_download->start();
|
m_thr_data->start();
|
||||||
|
|
||||||
QString msg;
|
QString msg;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
@ -88,7 +108,7 @@ void ThreadPlay::run() {
|
||||||
if(m_need_stop)
|
if(m_need_stop)
|
||||||
return;
|
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());
|
msg.sprintf("指定的文件或目录不存在!\n\n%s", _tmp_res.toStdString().c_str());
|
||||||
_notify_error(msg);
|
_notify_error(msg);
|
||||||
return;
|
return;
|
||||||
|
|
@ -147,7 +167,7 @@ void ThreadPlay::run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
update_data* dat = new update_data(TYPE_HEADER_INFO);
|
UpdateData* dat = new UpdateData(TYPE_HEADER_INFO);
|
||||||
dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
||||||
|
|
||||||
read_len = f_hdr.read((char*)(dat->data_buf()), dat->data_len());
|
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);
|
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);
|
dat->alloc_data(sizeof(TS_RECORD_PKG) + pkg.size);
|
||||||
memcpy(dat->data_buf(), &pkg, sizeof(TS_RECORD_PKG));
|
memcpy(dat->data_buf(), &pkg, sizeof(TS_RECORD_PKG));
|
||||||
read_len = f_dat.read((char*)(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
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)
|
if(time_pass > total_ms)
|
||||||
time_pass = total_ms;
|
time_pass = total_ms;
|
||||||
if(time_pass - time_last_pass > 200) {
|
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);
|
_passed_ms->played_ms(time_pass);
|
||||||
emit signal_update_data(_passed_ms);
|
emit signal_update_data(_passed_ms);
|
||||||
time_last_pass = time_pass;
|
time_last_pass = time_pass;
|
||||||
|
|
@ -307,7 +327,7 @@ void ThreadPlay::run() {
|
||||||
if(_time_pass > total_ms)
|
if(_time_pass > total_ms)
|
||||||
_time_pass = total_ms;
|
_time_pass = total_ms;
|
||||||
if(_time_pass - time_last_pass > 200) {
|
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);
|
_passed_ms->played_ms(_time_pass);
|
||||||
emit signal_update_data(_passed_ms);
|
emit signal_update_data(_passed_ms);
|
||||||
time_last_pass = _time_pass;
|
time_last_pass = _time_pass;
|
||||||
|
|
@ -330,6 +350,9 @@ void ThreadPlay::run() {
|
||||||
_notify_message(msg);
|
_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);
|
emit signal_update_data(_end);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
#ifndef THR_PLAY_H
|
#ifndef THR_PLAY_H
|
||||||
#define THR_PLAY_H
|
#define THR_PLAY_H
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "update_data.h"
|
#include "update_data.h"
|
||||||
#include "thr_download.h"
|
#include "downloader.h"
|
||||||
|
|
||||||
class ThreadPlay : public QThread
|
// 根据播放规则,将要播放的图像发送给主UI线程进行显示
|
||||||
|
class ThrPlay : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class ThrData;
|
||||||
public:
|
public:
|
||||||
ThreadPlay(const QString& res);
|
ThrPlay();
|
||||||
~ThreadPlay();
|
~ThrPlay();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
@ -23,17 +26,12 @@ private:
|
||||||
void _notify_error(const QString& err_msg);
|
void _notify_error(const QString& err_msg);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void signal_update_data(update_data*);
|
void signal_update_data(UpdateData*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_need_stop;
|
bool m_need_stop;
|
||||||
bool m_need_pause;
|
bool m_need_pause;
|
||||||
int m_speed;
|
int m_speed;
|
||||||
|
|
||||||
QString m_res;
|
|
||||||
bool m_need_download;
|
|
||||||
|
|
||||||
ThreadDownload* m_thr_download;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // THR_PLAY_H
|
#endif // THR_PLAY_H
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,29 @@
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
TARGET = tp-player
|
TARGET = tp-player
|
||||||
|
|
||||||
QT += core gui widgets
|
QT += core gui widgets network
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
mainwindow.h \
|
mainwindow.h \
|
||||||
bar.h \
|
bar.h \
|
||||||
thr_download.h \
|
|
||||||
thr_play.h \
|
thr_play.h \
|
||||||
|
thr_data.h \
|
||||||
update_data.h \
|
update_data.h \
|
||||||
record_format.h \
|
record_format.h \
|
||||||
rle.h \
|
rle.h \
|
||||||
util.h
|
util.h \
|
||||||
|
downloader.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
mainwindow.cpp \
|
mainwindow.cpp \
|
||||||
bar.cpp \
|
bar.cpp \
|
||||||
thr_download.cpp \
|
|
||||||
thr_play.cpp \
|
thr_play.cpp \
|
||||||
|
thr_data.cpp \
|
||||||
update_data.cpp \
|
update_data.cpp \
|
||||||
rle.c \
|
rle.c \
|
||||||
util.cpp
|
util.cpp \
|
||||||
|
downloader.cpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
tp-player.qrc
|
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_type = data_type;
|
||||||
m_data_buf = nullptr;
|
m_data_buf = nullptr;
|
||||||
m_data_len = 0;
|
m_data_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_data::~update_data() {
|
UpdateData::~UpdateData() {
|
||||||
if(m_data_buf)
|
if(m_data_buf)
|
||||||
delete 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)
|
if(m_data_buf)
|
||||||
delete m_data_buf;
|
delete m_data_buf;
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ void update_data::alloc_data(uint32_t len) {
|
||||||
m_data_len = 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)
|
if(m_data_buf)
|
||||||
delete m_data_buf;
|
delete m_data_buf;
|
||||||
m_data_buf = new uint8_t[len];
|
m_data_buf = new uint8_t[len];
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@
|
||||||
#define TYPE_MESSAGE 5
|
#define TYPE_MESSAGE 5
|
||||||
#define TYPE_ERROR 6
|
#define TYPE_ERROR 6
|
||||||
|
|
||||||
class update_data : public QObject
|
class UpdateData : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit update_data(int data_type, QObject *parent = nullptr);
|
explicit UpdateData(int data_type, QObject *parent = nullptr);
|
||||||
virtual ~update_data();
|
virtual ~UpdateData();
|
||||||
|
|
||||||
void alloc_data(uint32_t len);
|
void alloc_data(uint32_t len);
|
||||||
void attach_data(const uint8_t* dat, uint32_t len);
|
void attach_data(const uint8_t* dat, uint32_t len);
|
||||||
|
|
@ -47,7 +47,7 @@ private:
|
||||||
|
|
||||||
class UpdateDataHelper {
|
class UpdateDataHelper {
|
||||||
public:
|
public:
|
||||||
UpdateDataHelper(update_data* data) {
|
UpdateDataHelper(UpdateData* data) {
|
||||||
m_data = data;
|
m_data = data;
|
||||||
}
|
}
|
||||||
~UpdateDataHelper() {
|
~UpdateDataHelper() {
|
||||||
|
|
@ -56,7 +56,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
||||||
|
|
@ -77,9 +77,10 @@ typedef struct TS_RECORD_HEADER {
|
||||||
// 一个数据包的头
|
// 一个数据包的头
|
||||||
typedef struct TS_RECORD_PKG {
|
typedef struct TS_RECORD_PKG {
|
||||||
ex_u8 type; // 包的数据类型
|
ex_u8 type; // 包的数据类型
|
||||||
|
ex_u8 _reserve[3]; // 保留
|
||||||
ex_u32 size; // 这个包的总大小(不含包头)
|
ex_u32 size; // 这个包的总大小(不含包头)
|
||||||
ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||||
ex_u8 _reserve[3]; // 保留
|
ex_u32 index; // 这个包的序号(最后一个包的序号与TS_RECORD_HEADER_INFO::packages数量匹配)
|
||||||
}TS_RECORD_PKG;
|
}TS_RECORD_PKG;
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
|
||||||
|
|
@ -671,12 +671,13 @@ class DoGetFileHandler(TPBaseHandler):
|
||||||
# return self.write('need login first.')
|
# return self.write('need login first.')
|
||||||
# self._user = _user
|
# self._user = _user
|
||||||
|
|
||||||
if not self._user['_is_login']:
|
# when test, disable auth.
|
||||||
self.set_status(401) # 401=未授权, 要求身份验证
|
# if not self._user['_is_login']:
|
||||||
return self.write('need login first.')
|
# self.set_status(401) # 401=未授权, 要求身份验证
|
||||||
if (self._user['privilege'] & require_privilege) == 0:
|
# return self.write('need login first.')
|
||||||
self.set_status(403) # 403=禁止
|
# if (self._user['privilege'] & require_privilege) == 0:
|
||||||
return self.write('you have no such privilege.')
|
# self.set_status(403) # 403=禁止
|
||||||
|
# return self.write('you have no such privilege.')
|
||||||
|
|
||||||
act = self.get_argument('act', None)
|
act = self.get_argument('act', None)
|
||||||
_type = self.get_argument('type', None)
|
_type = self.get_argument('type', None)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue