pull/175/head^2
Apex Liu 2019-09-16 13:53:27 +08:00
parent 6f95664ca1
commit e5610b17a2
16 changed files with 546 additions and 140 deletions

View File

@ -0,0 +1,21 @@
#include "dlgmessage.h"
#include "ui_dlgmessage.h"
DlgMessage::DlgMessage(QWidget *parent) :
QDialog(parent),
ui(new Ui::DlgMessage)
{
ui->setupUi(this);
}
DlgMessage::~DlgMessage()
{
delete ui;
}
void DlgMessage::set_text(const QString& text) {
// TODO: 根据文字长度,父窗口宽度,调节对话框宽度,最大不超过父窗口宽度的 2/3。
// 调节label的宽度和高度并调节对话框高度最后将对话框调整到父窗口居中的位置。
ui->label->setText(text);
}

View File

@ -0,0 +1,24 @@
#ifndef DLGMESSAGE_H
#define DLGMESSAGE_H
#include <QDialog>
namespace Ui {
class DlgMessage;
}
class DlgMessage : public QDialog
{
Q_OBJECT
public:
explicit DlgMessage(QWidget *parent = nullptr);
~DlgMessage();
void set_text(const QString& text);
private:
Ui::DlgMessage *ui;
};
#endif // DLGMESSAGE_H

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DlgMessage</class>
<widget class="QDialog" name="DlgMessage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>120</height>
</rect>
</property>
<property name="windowTitle">
<string/>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>59</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,5 +1,8 @@
#include "mainwindow.h"
#include "mainwindow.h"
#include <QApplication>
#include <QCommandLineParser>
#include <QDebug>
#include <QMessageBox>
// 编译出来的可执行程序复制到单独目录,然后执行 windeployqt 应用程序文件名
// 即可自动将依赖的动态库等复制到此目录中。有些文件是多余的,可以酌情删除。
@ -11,8 +14,41 @@ int main(int argc, char *argv[])
//#endif
QApplication a(argc, argv);
MainWindow w;
w.show();
QGuiApplication::setApplicationDisplayName("TP-Player");
QCommandLineParser parser;
const QCommandLineOption opt_help = parser.addHelpOption();
parser.addPositionalArgument("RESOURCE", "teleport record resource to be play.");
if(!parser.parse(QCoreApplication::arguments())) {
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
//"<html><head/><body><h2 style=\"color:#ff0000;\">" + parser.errorText() + "</h2><pre>"
"<html><head/><body><h2>" + parser.errorText() + "</h2><pre>"
+ parser.helpText() + "</pre></body></html>");
return 1;
}
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>");
return 2;
}
const QStringList args = parser.positionalArguments();
QString resource = args.at(0);
qDebug() << resource;
MainWindow w;
w.set_resource(resource);
w.show();
return a.exec();
}

View File

@ -7,6 +7,8 @@
#include <QPainter>
#include <QDesktopWidget>
#include <QPaintEvent>
#include <QMessageBox>
#include <QDialogButtonBox>
bool rdpimg2QImage(QImage& out, int w, int h, int bitsPerPixel, bool isCompressed, uint8_t* dat, uint32_t len) {
switch(bitsPerPixel) {
@ -67,7 +69,7 @@ MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
m_shown = false;
//m_shown = false;
m_show_default = true;
m_bar_shown = false;
m_bar_fade_in = false;
@ -78,6 +80,8 @@ MainWindow::MainWindow(QWidget *parent) :
m_thr_play = nullptr;
m_play_state = PLAY_STATE_UNKNOWN;
m_msg_box = nullptr;
ui->setupUi(this);
ui->centralWidget->setMouseTracking(true);
@ -103,28 +107,46 @@ MainWindow::MainWindow(QWidget *parent) :
}
// 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()));
connect(&m_timer_bar_delay_hide, SIGNAL(timeout()), this, SLOT(_do_bar_delay_hide()));
m_timer_first_run.setSingleShot(true);
m_timer_first_run.start(500);
}
MainWindow::~MainWindow()
{
if(m_thr_play) {
m_thr_play->stop();
m_thr_play->wait();
//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*)));
delete m_thr_play;
m_thr_play = nullptr;
}
if(m_msg_box) {
delete m_msg_box;
}
delete ui;
}
void MainWindow::set_resource(const QString &res) {
m_res = res;
}
void MainWindow::_do_first_run() {
_start_play_thread();
}
void MainWindow::_start_play_thread() {
if(m_thr_play) {
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*)));
@ -132,7 +154,7 @@ void MainWindow::_start_play_thread() {
m_thr_play = nullptr;
}
m_thr_play = new ThreadPlay;
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->speed(m_bar.get_speed());
m_thr_play->start();
@ -169,11 +191,11 @@ void MainWindow::paintEvent(QPaintEvent *e)
}
}
if(!m_shown) {
m_shown = true;
//m_thr_play.start();
_start_play_thread();
}
// if(!m_shown) {
// m_shown = true;
// //m_thr_play.start();
// _start_play_thread();
// }
}
void MainWindow::pause() {
@ -200,6 +222,9 @@ void MainWindow::_do_update_data(update_data* dat) {
UpdateDataHelper data_helper(dat);
if(dat->data_type() == TYPE_DATA) {
if(m_msg_box) {
m_msg_box->hide();
}
if(dat->data_len() <= sizeof(TS_RECORD_PKG)) {
qDebug() << "invalid record package(1).";
@ -250,13 +275,35 @@ void MainWindow::_do_update_data(update_data* dat) {
return;
}
if(dat->data_type() == TYPE_TIMER) {
m_bar.update_passed_time(dat->passed_ms());
else if(dat->data_type() == TYPE_PLAYED_MS) {
m_bar.update_passed_time(dat->played_ms());
return;
}
else if(dat->data_type() == TYPE_MESSAGE) {
//QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(), dat->message());
if(!m_msg_box) {
m_msg_box = new DlgMessage(this);
// 无窗口标题栏,无边框
m_msg_box->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::ToolTip | Qt::FramelessWindowHint);
// 设置成非模态
m_msg_box->setModal(false);
}
m_msg_box->set_text(dat->message());
// 显示对话框
m_msg_box->show();
return;
}
else if(dat->data_type() == TYPE_ERROR) {
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(), dat->message());
QApplication::instance()->exit(0);
return;
}
// 这是播放开始时收到的第一个数据包
if(dat->data_type() == TYPE_HEADER_INFO) {
else if(dat->data_type() == TYPE_HEADER_INFO) {
if(dat->data_len() != sizeof(TS_RECORD_HEADER)) {
qDebug() << "invalid record header.";
return;
@ -264,41 +311,39 @@ void MainWindow::_do_update_data(update_data* dat) {
memcpy(&m_rec_hdr, dat->data_buf(), sizeof(TS_RECORD_HEADER));
qDebug() << "resize (" << m_rec_hdr.basic.width << "," << m_rec_hdr.basic.height << ")";
if(m_rec_hdr.basic.width > 0 && m_rec_hdr.basic.height > 0) {
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);
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();
//m_win_board_h = frameGeometry().height() - geometry().height();
//m_win_board_w = frameGeometry().width() - geometry().width();
//m_win_board_h = frameGeometry().height() - geometry().height();
QDesktopWidget *desktop = QApplication::desktop(); // =qApp->desktop();也可以
qDebug("desktop w:%d,h:%d, this w:%d,h:%d", desktop->width(), desktop->height(), width(), height());
//move((desktop->width() - this->width())/2, (desktop->height() - this->height())/2);
move(10, (desktop->height() - m_rec_hdr.basic.height)/2);
QDesktopWidget *desktop = QApplication::desktop(); // =qApp->desktop();也可以
qDebug("desktop w:%d,h:%d, this w:%d,h:%d", desktop->width(), desktop->height(), width(), height());
//move((desktop->width() - this->width())/2, (desktop->height() - this->height())/2);
move(10, (desktop->height() - m_rec_hdr.basic.height)/2);
//setFixedSize(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);
setFixedSize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
}
m_canvas.fill(QColor(38, 73, 111));
m_show_default = false;
repaint();
m_bar.start(m_rec_hdr.info.time_ms, 640);
m_bar_shown = true;
m_play_state = PLAY_STATE_RUNNING;
update(m_bar.rc());
m_bar_fade_in = false;
m_bar_fading = true;
m_timer_bar_delay_hide.start(2000);
//setFixedSize(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);
setFixedSize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
}
m_canvas.fill(QColor(38, 73, 111));
m_show_default = false;
repaint();
m_bar.start(m_rec_hdr.info.time_ms, 640);
m_bar_shown = true;
m_play_state = PLAY_STATE_RUNNING;
update(m_bar.rc());
m_bar_fade_in = false;
m_bar_fading = true;
m_timer_bar_delay_hide.start(2000);
QString title;
if (m_rec_hdr.basic.conn_port == 3389)
title.sprintf("[%s] %s@%s [Teleport-RDP录像回放]", m_rec_hdr.basic.acc_username, m_rec_hdr.basic.user_username, m_rec_hdr.basic.conn_ip);
@ -311,7 +356,7 @@ void MainWindow::_do_update_data(update_data* dat) {
}
if(dat->data_type() == TYPE_END) {
else if(dat->data_type() == TYPE_END) {
m_bar.end();
m_play_state = PLAY_STATE_STOP;
return;
@ -383,6 +428,8 @@ void MainWindow::mouseMoveEvent(QMouseEvent *e) {
}
void MainWindow::mousePressEvent(QMouseEvent *e) {
// QApplication::instance()->exit(0);
// return;
if(!m_show_default) {
QRect rc = m_bar.rc();
if(rc.contains(e->pos())) {

View File

@ -2,11 +2,13 @@
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
#include <QTimer>
#include "bar.h"
#include "thr_play.h"
#include "update_data.h"
#include "record_format.h"
#include "dlgmessage.h"
#define PLAY_STATE_UNKNOWN 0
#define PLAY_STATE_RUNNING 1
@ -25,6 +27,8 @@ public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void set_resource(const QString& res);
void pause();
void resume();
void restart();
@ -38,17 +42,20 @@ private:
void _start_play_thread();
private slots:
void _do_first_run(); // 默认界面加载完成后,开始播放操作(可能会进行数据下载)
void _do_update_data(update_data*);
void _do_bar_fade();
void _do_bar_delay_hide();
private:
Ui::MainWindow *ui;
bool m_shown;
//bool m_shown;
bool m_show_default;
bool m_bar_shown;
QPixmap m_default_bg;
QString m_res;
ThreadPlay* m_thr_play;
QPixmap m_canvas;
@ -60,6 +67,7 @@ private:
QPixmap m_pt_normal;
TS_RECORD_RDP_POINTER m_pt;
QTimer m_timer_first_run;
QTimer m_timer_bar_fade;
QTimer m_timer_bar_delay_hide;
bool m_bar_fade_in;
@ -67,6 +75,9 @@ private:
qreal m_bar_opacity;
int m_play_state;
//QMessageBox* m_msg_box;
DlgMessage* m_msg_box;
};
#endif // MAINWINDOW_H

View File

@ -3,13 +3,6 @@
#include <Qt>
#define TYPE_HEADER_INFO 0
#define TYPE_DATA 1
#define TYPE_TIMER 2
#define TYPE_END 3
#define TS_RECORD_TYPE_RDP_POINTER 0x12 // 鼠标坐标位置改变,用于绘制虚拟鼠标
#define TS_RECORD_TYPE_RDP_IMAGE 0x13 // 服务端返回的图像,用于展示
@ -22,11 +15,12 @@
// 录像文件头(随着录像数据写入,会改变的部分)
typedef struct TS_RECORD_HEADER_INFO {
uint32_t magic; // "TPPR" 标志 TelePort Protocol Record
uint16_t ver; // 录像文件版本目前为3
uint32_t packages; // 总包数
uint32_t time_ms; // 总耗时(毫秒)
//uint32_t file_size; // 数据文件大小
uint32_t magic; // "TPPR" 标志 TelePort Protocol Record
uint16_t ver; // 录像文件版本从3.5.0开始为4
uint32_t packages; // 总包数
uint32_t time_ms; // 总耗时(毫秒)
uint32_t dat_file_count; // 数据文件数量
uint8_t _reserve[64-4-2-4-4-4];
}TS_RECORD_HEADER_INFO;
#define ts_record_header_info_size sizeof(TS_RECORD_HEADER_INFO)

View File

@ -0,0 +1,34 @@
#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/";
}
}
}

View File

@ -0,0 +1,47 @@
#ifndef THREADDOWNLOAD_H
#define THREADDOWNLOAD_H
#include <QThread>
/*
4MB
tp-rdp.tpr
tp-rdp.tpk (v3.5.0)
tp-rdp-1.tpd, tp-rdp-2.tpd, tp-rdp-3.tpd, ...
线
线
.tpk
tp-rdp.tpk.tmp, tp-rdp.tpk.len
tp-rdp-1.tpd.tmp, tp-rdp-1.tpd.len, ...
*/
class ThreadDownload : public QThread
{
public:
ThreadDownload(const QString& url);
virtual void run();
void stop();
// 下载 .tpr 和 .tpf 文件出错返回false正在下载或已经下载完成则返回true.
bool prepare(QString& path_base, QString& msg);
private:
bool m_need_stop;
QString m_url;
QString m_path_base;
};
#endif // THREADDOWNLOAD_H

View File

@ -3,27 +3,136 @@
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QStandardPaths>
#include "thr_play.h"
#include "record_format.h"
ThreadPlay::ThreadPlay()
ThreadPlay::ThreadPlay(const QString& res)
{
m_need_stop = false;
m_need_pause = false;
m_speed = 2;
m_res = res;
m_thr_download = nullptr;
}
ThreadPlay::~ThreadPlay() {
stop();
}
void ThreadPlay::stop() {
if(!isRunning())
return;
// warning: never call stop() inside thread::run() loop.
m_need_stop = true;
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;
}
}
void ThreadPlay::_notify_message(const QString& msg) {
update_data* _msg = new update_data(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 ThreadPlay::run() {
sleep(1);
//#ifdef __APPLE__
// QString currentPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
// currentPath += "/tp-testdata/";
//#else
// QString currentPath = QCoreApplication::applicationDirPath() + "/testdata/";
//#endif
// /Users/apex/Library/Preferences/tp-player
//qDebug() << "appdata:" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
// /private/var/folders/_3/zggrxjdx1lxcdqnfsbgpcwzh0000gn/T
//qDebug() << "tmp:" << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
// base of data path (include the .tpr file)
QString path_base;
QString _tmp_res = m_res.toLower();
if(_tmp_res.startsWith("http")) {
qDebug() << "DOWNLOAD";
m_need_download = true;
// path_base = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
// path_base += "/tprdp/";
_notify_message("正在缓存录像数据,请稍候...");
m_thr_download = new ThreadDownload(m_res);
m_thr_download->start();
QString msg;
for(;;) {
msleep(500);
if(m_need_stop) {
// m_thr_download->stop();
// m_thr_download->wait();
// delete m_thr_download;
// m_thr_download = nullptr;
return;
}
if(!m_thr_download->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(m_res);
if(fi.isSymLink())
_tmp_res = fi.symLinkTarget();
else
_tmp_res = m_res;
}
QFileInfo fi(_tmp_res);
if(!fi.exists()) {
QString msg;
msg.sprintf("指定的文件或目录不存在!\n\n%s", _tmp_res.toStdString().c_str());
_notify_error(msg);
return;
}
if(fi.isFile()) {
path_base = fi.path();
}
else if(fi.isDir()) {
path_base = m_res;
}
path_base += "/";
}
QString currentPath = QCoreApplication::applicationDirPath() + "/testdata/";
qint64 read_len = 0;
uint32_t total_pkg = 0;
@ -31,27 +140,47 @@ void ThreadPlay::run() {
// 加载录像基本信息数据
QString hdr_filename(currentPath);
hdr_filename += "tp-rdp.tpr";
QString tpr_filename(path_base);
tpr_filename += "tp-rdp.tpr";
QFile f_hdr(hdr_filename);
QFile f_hdr(tpr_filename);
if(!f_hdr.open(QFile::ReadOnly)) {
qDebug() << "Can not open " << hdr_filename << " for read.";
qDebug() << "Can not open " << tpr_filename << " for read.";
QString msg;
msg.sprintf("无法打开录像信息文件!\n\n%s", tpr_filename.toStdString().c_str());
_notify_error(msg);
return;
}
else {
update_data* dat = new update_data;
dat->data_type(TYPE_HEADER_INFO);
update_data* dat = new update_data(TYPE_HEADER_INFO);
dat->alloc_data(sizeof(TS_RECORD_HEADER));
read_len = f_hdr.read((char*)(dat->data_buf()), dat->data_len());
if(read_len != sizeof(TS_RECORD_HEADER)) {
delete dat;
qDebug() << "invaid .tpr file.";
QString msg;
msg.sprintf("错误的录像信息文件!\n\n%s", tpr_filename.toStdString().c_str());
_notify_error(msg);
return;
}
TS_RECORD_HEADER* hdr = (TS_RECORD_HEADER*)dat->data_buf();
if(hdr->info.ver != 4) {
delete dat;
qDebug() << "invaid .tpr file.";
QString msg;
msg.sprintf("不支持的录像文件版本 %d\n\n此播放器支持录像文件版本 4。", hdr->info.ver);
_notify_error(msg);
return;
}
// if(hdr->basic.width == 0 || hdr->basic.height == 0) {
// _notify_error("错误的录像信息,未记录窗口尺寸!");
// return;
// }
total_pkg = hdr->info.packages;
total_ms = hdr->info.time_ms;
@ -60,12 +189,15 @@ void ThreadPlay::run() {
// 加载录像文件数据
QString dat_filename(currentPath);
dat_filename += "tp-rdp.dat";
QString tpd_filename(path_base);
tpd_filename += "tp-rdp.tpd";
QFile f_dat(dat_filename);
QFile f_dat(tpd_filename);
if(!f_dat.open(QFile::ReadOnly)) {
qDebug() << "Can not open " << dat_filename << " for read.";
qDebug() << "Can not open " << tpd_filename << " for read.";
QString msg;
msg.sprintf("无法打开录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
_notify_error(msg);
return;
}
@ -89,18 +221,23 @@ void ThreadPlay::run() {
TS_RECORD_PKG pkg;
read_len = f_dat.read((char*)(&pkg), sizeof(pkg));
if(read_len != sizeof(TS_RECORD_PKG)) {
qDebug() << "invaid .dat file (1).";
qDebug() << "invaid .tpd file (1).";
QString msg;
msg.sprintf("错误的录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
_notify_error(msg);
return;
}
update_data* dat = new update_data;
dat->data_type(TYPE_DATA);
update_data* dat = new update_data(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 .dat file.";
qDebug() << "invaid .tpd file.";
QString msg;
msg.sprintf("错误的录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
_notify_error(msg);
return;
}
@ -108,9 +245,8 @@ 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;
_passed_ms->data_type(TYPE_TIMER);
_passed_ms->passed_ms(time_pass);
update_data* _passed_ms = new update_data(TYPE_PLAYED_MS);
_passed_ms->played_ms(time_pass);
emit signal_update_data(_passed_ms);
time_last_pass = time_pass;
}
@ -145,9 +281,8 @@ 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;
_passed_ms->data_type(TYPE_TIMER);
_passed_ms->passed_ms(_time_pass);
update_data* _passed_ms = new update_data(TYPE_PLAYED_MS);
_passed_ms->played_ms(_time_pass);
emit signal_update_data(_passed_ms);
time_last_pass = _time_pass;
}
@ -160,7 +295,6 @@ void ThreadPlay::run() {
}
}
update_data* _end = new update_data;
_end->data_type(TYPE_END);
update_data* _end = new update_data(TYPE_END);
emit signal_update_data(_end);
}

View File

@ -3,13 +3,14 @@
#include <QThread>
#include "update_data.h"
#include "thr_download.h"
class ThreadPlay : public QThread
{
Q_OBJECT
public:
ThreadPlay();
ThreadPlay(const QString& res);
~ThreadPlay();
virtual void run();
void stop();
@ -17,6 +18,10 @@ public:
void resume() {m_need_pause = false;}
void speed(int s) {if(s >= 1 && s <= 16) m_speed = s;}
private:
void _notify_message(const QString& msg);
void _notify_error(const QString& err_msg);
signals:
void signal_update_data(update_data*);
@ -24,6 +29,11 @@ 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

View File

@ -1,29 +1,34 @@
TEMPLATE = app
TARGET = tp-player
QT += core gui widgets
HEADERS += \
mainwindow.h \
bar.h \
thr_play.h \
update_data.h \
record_format.h \
rle.h
SOURCES += \
main.cpp \
mainwindow.cpp \
bar.cpp \
thr_play.cpp \
update_data.cpp \
rle.c
RESOURCES += \
tp-player.qrc
RC_FILE += \
tp-player.rc
FORMS += \
mainwindow.ui
TEMPLATE = app
TARGET = tp-player
QT += core gui widgets
HEADERS += \
dlgmessage.h \
mainwindow.h \
bar.h \
thr_download.h \
thr_play.h \
update_data.h \
record_format.h \
rle.h
SOURCES += \
dlgmessage.cpp \
main.cpp \
mainwindow.cpp \
bar.cpp \
thr_download.cpp \
thr_play.cpp \
update_data.cpp \
rle.c
RESOURCES += \
tp-player.qrc
RC_FILE += \
tp-player.rc
FORMS += \
dlgmessage.ui \
mainwindow.ui

View File

@ -1,8 +1,8 @@
#include "update_data.h"
update_data::update_data(QObject *parent) : QObject(parent)
update_data::update_data(int data_type, QObject *parent) : QObject(parent)
{
m_data_type = 0xff;
m_data_type = data_type;
m_data_buf = nullptr;
m_data_len = 0;
}

View File

@ -3,24 +3,34 @@
#include <QObject>
#define TYPE_HEADER_INFO 0
#define TYPE_DATA 1
#define TYPE_PLAYED_MS 2
#define TYPE_DOWNLOAD_PERCENT 3
#define TYPE_END 4
#define TYPE_MESSAGE 5
#define TYPE_ERROR 6
class update_data : public QObject
{
Q_OBJECT
public:
explicit update_data(QObject *parent = nullptr);
explicit update_data(int data_type, QObject *parent = nullptr);
virtual ~update_data();
void alloc_data(uint32_t len);
void attach_data(const uint8_t* dat, uint32_t len);
void data_type(int dt) {m_data_type = dt;}
int data_type() const {return m_data_type;}
uint8_t* data_buf() {return m_data_buf;}
uint32_t data_len() const {return m_data_len;}
void passed_ms(uint32_t ms) {m_passed_ms = ms;}
uint32_t passed_ms() {return m_passed_ms;}
void played_ms(uint32_t ms) {m_played_ms = ms;}
uint32_t played_ms() {return m_played_ms;}
void message(const QString& msg) {m_msg = msg;}
const QString message(){return m_msg;}
signals:
@ -31,7 +41,8 @@ private:
int m_data_type;
uint8_t* m_data_buf;
uint32_t m_data_len;
uint32_t m_passed_ms;
uint32_t m_played_ms;
QString m_msg;
};
class UpdateDataHelper {

View File

@ -1,5 +1,5 @@
[external_ver]
openssl = 1.0.2p,1000210f
openssl = 1.0.2s,1000210f
libuv = 1.28.0
mbedtls = 2.12.0
libssh = 0.9.0

View File

@ -22,34 +22,34 @@
// 录像文件头(随着录像数据写入,会改变的部分)
typedef struct TS_RECORD_HEADER_INFO {
ex_u32 magic; // "TPPR" 标志 TelePort Protocol Record
ex_u16 ver; // 录像文件版本目前为3
ex_u32 packages; // 总包数
ex_u32 time_ms; // 总耗时(毫秒)
//ex_u32 file_size; // 数据文件大小
ex_u32 magic; // "TPPR" 标志 TelePort Protocol Record
ex_u16 ver; // 录像文件版本v3.5.0开始为4
ex_u32 packages; // 总包数
ex_u32 time_ms; // 总耗时(毫秒)
uint32_t dat_file_count; // 数据文件数量
uint8_t _reserve[64-4-2-4-4-4];
}TS_RECORD_HEADER_INFO;
#define ts_record_header_info_size sizeof(TS_RECORD_HEADER_INFO)
// 录像文件头(固定不变部分)
typedef struct TS_RECORD_HEADER_BASIC {
ex_u16 protocol_type; // 协议1=RDP, 2=SSH, 3=Telnet
ex_u16 protocol_sub_type; // 子协议100=RDP-DESKTOP, 200=SSH-SHELL, 201=SSH-SFTP, 300=Telnet
ex_u64 timestamp; // 本次录像的起始时间UTC时间戳
ex_u16 width; // 初始屏幕尺寸:宽
ex_u16 height; // 初始屏幕尺寸:高
char user_username[64]; // teleport账号
char acc_username[64]; // 远程主机用户名
ex_u16 protocol_type; // 协议1=RDP, 2=SSH, 3=Telnet
ex_u16 protocol_sub_type; // 子协议100=RDP-DESKTOP, 200=SSH-SHELL, 201=SSH-SFTP, 300=Telnet
ex_u64 timestamp; // 本次录像的起始时间UTC时间戳
ex_u16 width; // 初始屏幕尺寸:宽
ex_u16 height; // 初始屏幕尺寸:高
char user_username[64]; // teleport账号
char acc_username[64]; // 远程主机用户名
char host_ip[40]; // 远程主机IP
char conn_ip[40]; // 远程主机IP
ex_u16 conn_port; // 远程主机端口
char host_ip[40]; // 远程主机IP
char conn_ip[40]; // 远程主机IP
ex_u16 conn_port; // 远程主机端口
char client_ip[40]; // 客户端IP
char client_ip[40]; // 客户端IP
// // RDP专有
// // RDP专有 - v3.5.0废弃并移除
// ex_u8 rdp_security; // 0 = RDP, 1 = TLS
// ex_u8 _reserve[512 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 40 - 2 - 40 - 1 - ts_record_header_info_size];
ex_u8 _reserve[512 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 40 - 2 - 40 - ts_record_header_info_size];
}TS_RECORD_HEADER_BASIC;
#define ts_record_header_basic_size sizeof(TS_RECORD_HEADER_BASIC)