mirror of https://github.com/tp4a/teleport
播放器流畅工作,还缺重播和进度条拖动功能。
parent
3aa4755876
commit
1bbc109ae9
|
@ -423,7 +423,7 @@ void Bar::onMousePress(int x, int y) {
|
|||
if(m_speed_selected != speed_sel && speed_sel != speed_count) {
|
||||
int old_sel = m_speed_selected;
|
||||
m_speed_selected = speed_sel;
|
||||
m_owner->speed(get_speed());
|
||||
m_owner->set_speed(get_speed());
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[old_sel].left(), m_rc.top()+m_rc_btn_speed[old_sel].top(), m_rc_btn_speed[old_sel].width(), m_rc_btn_speed[old_sel].height());
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[m_speed_hover].left(), m_rc.top()+m_rc_btn_speed[m_speed_hover].top(), m_rc_btn_speed[m_speed_hover].width(), m_rc_btn_speed[m_speed_hover].height());
|
||||
return;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "rle.h"
|
||||
|
||||
#include <QMatrix>
|
||||
#include <QDebug>
|
||||
|
@ -10,64 +9,6 @@
|
|||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
bool rdpimg2QImage(QImage& out, int w, int h, int bitsPerPixel, bool isCompressed, uint8_t* dat, uint32_t len) {
|
||||
switch(bitsPerPixel) {
|
||||
case 15:
|
||||
if(isCompressed) {
|
||||
uint8_t* _dat = (uint8_t*)calloc(1, w*h*2);
|
||||
if(!bitmap_decompress1(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
return false;
|
||||
}
|
||||
out = QImage(_dat, w, h, QImage::Format_RGB555);
|
||||
free(_dat);
|
||||
}
|
||||
else {
|
||||
out = QImage(dat, w, h, QImage::Format_RGB555).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) ;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if(isCompressed) {
|
||||
|
||||
uint8_t* _dat = (uint8_t*)calloc(1, w*h*2);
|
||||
if(!bitmap_decompress2(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: 这里需要进一步优化,直接操作QImage的buffer。
|
||||
// QTime t1;
|
||||
// t1.start();
|
||||
|
||||
out = QImage(w, h, QImage::Format_RGB16);
|
||||
for(int y = 0; y < h; y++) {
|
||||
for(int x = 0; x < w; x++) {
|
||||
uint16 a = ((uint16*)_dat)[y * w + x];
|
||||
uint8 r = ((a & 0xf800) >> 11) * 255 / 31;
|
||||
uint8 g = ((a & 0x07e0) >> 5) * 255 / 63;
|
||||
uint8 b = (a & 0x001f) * 255 / 31;
|
||||
out.setPixelColor(x, y, QColor(r,g,b));
|
||||
}
|
||||
}
|
||||
// qDebug("parse: %dB, %dms", len, t1.elapsed());
|
||||
|
||||
free(_dat);
|
||||
}
|
||||
else {
|
||||
out = QImage(dat, w, h, QImage::Format_RGB16).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) ;
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
qDebug() << "--------NOT support 24";
|
||||
break;
|
||||
case 32:
|
||||
qDebug() << "--------NOT support 32";
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int min(int a, int b){
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
@ -80,7 +21,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
//m_shown = false;
|
||||
m_show_default = true;
|
||||
m_bar_shown = false;
|
||||
m_bar_fade_in = false;
|
||||
|
@ -93,8 +33,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
m_play_state = PLAY_STATE_UNKNOWN;
|
||||
m_thr_data = nullptr;
|
||||
|
||||
// m_dl = nullptr;
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->centralWidget->setMouseTracking(true);
|
||||
|
@ -125,7 +63,6 @@ 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()));
|
||||
|
@ -194,11 +131,16 @@ void MainWindow::_start_play_thread() {
|
|||
m_thr_play->start();
|
||||
}
|
||||
|
||||
void MainWindow::speed(int s) {
|
||||
void MainWindow::set_speed(int s) {
|
||||
if(m_thr_play)
|
||||
m_thr_play->speed(s);
|
||||
}
|
||||
|
||||
void MainWindow::set_skip(bool s) {
|
||||
if(m_thr_play)
|
||||
m_thr_play->skip(s);
|
||||
}
|
||||
|
||||
void MainWindow::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
@ -252,12 +194,6 @@ void MainWindow::paintEvent(QPaintEvent *e)
|
|||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||
}
|
||||
|
||||
// if(!m_shown) {
|
||||
// m_shown = true;
|
||||
// //m_thr_play.start();
|
||||
// _start_play_thread();
|
||||
// }
|
||||
}
|
||||
|
||||
void MainWindow::pause() {
|
||||
|
@ -271,7 +207,6 @@ void MainWindow::resume() {
|
|||
if(m_play_state == PLAY_STATE_PAUSE)
|
||||
m_thr_play->resume();
|
||||
else if(m_play_state == PLAY_STATE_STOP)
|
||||
//m_thr_play->start();
|
||||
_start_play_thread();
|
||||
|
||||
m_play_state = PLAY_STATE_RUNNING;
|
||||
|
@ -283,53 +218,28 @@ void MainWindow::_do_update_data(UpdateData* dat) {
|
|||
|
||||
UpdateDataHelper data_helper(dat);
|
||||
|
||||
if(dat->data_type() == TYPE_DATA) {
|
||||
if(dat->data_type() == TYPE_POINTER) {
|
||||
TS_RECORD_RDP_POINTER pt;
|
||||
memcpy(&pt, &m_pt, sizeof(TS_RECORD_RDP_POINTER));
|
||||
|
||||
if(dat->data_len() <= sizeof(TS_RECORD_PKG)) {
|
||||
qDebug() << "invalid record package(1).";
|
||||
// 更新虚拟鼠标信息,这样下一次绘制界面时就会在新的位置绘制出虚拟鼠标
|
||||
memcpy(&m_pt, dat->get_pointer(), sizeof(TS_RECORD_RDP_POINTER));
|
||||
update(m_pt.x - m_pt_normal.width()/2, m_pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
|
||||
update(pt.x - m_pt_normal.width()/2, pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
|
||||
return;
|
||||
}
|
||||
else if(dat->data_type() == TYPE_IMAGE) {
|
||||
QImage* img_update = nullptr;
|
||||
int x, y, w, h;
|
||||
if(!dat->get_image(&img_update, x, y, w, h))
|
||||
return;
|
||||
}
|
||||
|
||||
TS_RECORD_PKG* pkg = (TS_RECORD_PKG*)dat->data_buf();
|
||||
QPainter pp(&m_canvas);
|
||||
pp.drawImage(x, y, *img_update, 0, 0, w, h, Qt::AutoColor);
|
||||
|
||||
if(pkg->type == TS_RECORD_TYPE_RDP_POINTER) {
|
||||
if(dat->data_len() != sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_POINTER)) {
|
||||
qDebug() << "invalid record package(2).";
|
||||
return;
|
||||
}
|
||||
|
||||
TS_RECORD_RDP_POINTER pt;
|
||||
memcpy(&pt, &m_pt, sizeof(TS_RECORD_RDP_POINTER));
|
||||
|
||||
// 更新虚拟鼠标信息,这样下一次绘制界面时就会在新的位置绘制出虚拟鼠标
|
||||
memcpy(&m_pt, dat->data_buf() + sizeof(TS_RECORD_PKG), sizeof(TS_RECORD_RDP_POINTER));
|
||||
update(m_pt.x - m_pt_normal.width()/2, m_pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
|
||||
update(pt.x - m_pt_normal.width()/2, pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
}
|
||||
else if(pkg->type == TS_RECORD_TYPE_RDP_IMAGE) {
|
||||
if(dat->data_len() <= sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_IMAGE_INFO)) {
|
||||
qDebug() << "invalid record package(3).";
|
||||
return;
|
||||
}
|
||||
|
||||
TS_RECORD_RDP_IMAGE_INFO* info = (TS_RECORD_RDP_IMAGE_INFO*)(dat->data_buf() + sizeof(TS_RECORD_PKG));
|
||||
uint8_t* img_dat = dat->data_buf() + sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||
uint32_t img_len = dat->data_len() - sizeof(TS_RECORD_PKG) - sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||
|
||||
QImage img_update;
|
||||
rdpimg2QImage(img_update, info->width, info->height, info->bitsPerPixel, (info->format == TS_RDP_IMG_BMP) ? true : false, img_dat, img_len);
|
||||
|
||||
int x = info->destLeft;
|
||||
int y = info->destTop;
|
||||
int w = info->destRight - info->destLeft + 1;
|
||||
int h = info->destBottom - info->destTop + 1;
|
||||
|
||||
QPainter pp(&m_canvas);
|
||||
pp.drawImage(x, y, img_update, 0, 0, w, h, Qt::AutoColor);
|
||||
|
||||
update(x, y, w, h);
|
||||
}
|
||||
update(x, y, w, h);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -394,11 +304,10 @@ void MainWindow::_do_update_data(UpdateData* dat) {
|
|||
|
||||
// 这是播放开始时收到的第一个数据包
|
||||
else if(dat->data_type() == TYPE_HEADER_INFO) {
|
||||
if(dat->data_len() != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug() << "invalid record header.";
|
||||
TS_RECORD_HEADER* hdr = dat->get_header();
|
||||
if(hdr == nullptr)
|
||||
return;
|
||||
}
|
||||
memcpy(&m_rec_hdr, dat->data_buf(), sizeof(TS_RECORD_HEADER));
|
||||
memcpy(&m_rec_hdr, hdr, sizeof(TS_RECORD_HEADER));
|
||||
|
||||
qDebug() << "resize (" << m_rec_hdr.basic.width << "," << m_rec_hdr.basic.height << ")";
|
||||
|
||||
|
@ -490,18 +399,6 @@ void MainWindow::_do_bar_fade() {
|
|||
update(m_bar.rc());
|
||||
}
|
||||
|
||||
//void MainWindow::_do_download(DownloadParam* param) {
|
||||
// qDebug("MainWindow::_do_download(). %s %s %s", param->url.toStdString().c_str(), param->sid.toStdString().c_str(), param->fname.toStdString().c_str());
|
||||
|
||||
// if(m_dl) {
|
||||
// delete m_dl;
|
||||
// m_dl = nullptr;
|
||||
// }
|
||||
|
||||
// m_dl = new Downloader();
|
||||
// m_dl->run(&m_nam, param->url, param->sid, param->fname);
|
||||
//}
|
||||
|
||||
void MainWindow::mouseMoveEvent(QMouseEvent *e) {
|
||||
if(!m_show_default) {
|
||||
QRect rc = m_bar.rc();
|
||||
|
|
|
@ -34,10 +34,8 @@ public:
|
|||
void pause();
|
||||
void resume();
|
||||
void restart();
|
||||
void speed(int s);
|
||||
|
||||
// Downloader* downloader() {return m_dl;}
|
||||
// void reset_downloader() {if(m_dl){delete m_dl;m_dl= nullptr;}}
|
||||
void set_speed(int s);
|
||||
void set_skip(bool s);
|
||||
|
||||
// TODO: 将thr_data移动到thr_play线程,由play线程进行管理
|
||||
ThrData* get_thr_data() {return m_thr_data;}
|
||||
|
@ -55,13 +53,9 @@ private slots:
|
|||
void _do_bar_fade();
|
||||
void _do_bar_delay_hide();
|
||||
|
||||
// void _do_download(Downloader*);
|
||||
// void _do_download(DownloadParam*);
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
//bool m_shown;
|
||||
bool m_show_default;
|
||||
bool m_bar_shown;
|
||||
QPixmap m_default_bg;
|
||||
|
@ -91,14 +85,6 @@ private:
|
|||
bool m_show_message;
|
||||
QPixmap m_img_message;
|
||||
QRect m_rc_message;
|
||||
|
||||
|
||||
// QNetworkAccessManager m_nam;
|
||||
// Downloader* m_dl;
|
||||
|
||||
// for test
|
||||
TimeUseTest m_time_imgconvert_normal;
|
||||
TimeUseTest m_time_imgconvert_compressed;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
|
||||
/* 1 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
|
||||
bitmap_decompress1(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
uint8 *end = input + size;
|
||||
uint8 *prevline = NULL, *line = NULL;
|
||||
|
@ -272,7 +272,7 @@ bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int siz
|
|||
|
||||
/* 2 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
|
||||
bitmap_decompress2(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
uint8 *end = input + size;
|
||||
uint16 *prevline = NULL, *line = NULL;
|
||||
|
@ -471,7 +471,7 @@ bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int siz
|
|||
|
||||
/* 3 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
|
||||
bitmap_decompress3(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
uint8 *end = input + size;
|
||||
uint8 *prevline = NULL, *line = NULL;
|
||||
|
@ -863,7 +863,7 @@ process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
|||
|
||||
/* 4 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size)
|
||||
bitmap_decompress4(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
int code;
|
||||
int bytes_pro;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef RLE_H
|
||||
#ifndef RLE_H
|
||||
#define RLE_H
|
||||
|
||||
#define RD_BOOL int
|
||||
|
@ -13,10 +13,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress4(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
|
||||
int bitmap_decompress_15(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
int bitmap_decompress_16(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
|
|
|
@ -137,9 +137,9 @@ void ThrData::_run() {
|
|||
return;
|
||||
|
||||
|
||||
UpdateData* dat = new UpdateData(TYPE_HEADER_INFO);
|
||||
dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
||||
memcpy(dat->data_buf(), &m_hdr, sizeof(TS_RECORD_HEADER));
|
||||
UpdateData* dat = new UpdateData(m_hdr);
|
||||
// dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
||||
// memcpy(dat->data_buf(), &m_hdr, sizeof(TS_RECORD_HEADER));
|
||||
emit signal_update_data(dat);
|
||||
|
||||
|
||||
|
@ -290,18 +290,34 @@ void ThrData::_run() {
|
|||
qDebug("################## too bad.");
|
||||
}
|
||||
|
||||
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 = fdata->read(reinterpret_cast<char*>(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
||||
if(read_len != pkg.size) {
|
||||
delete dat;
|
||||
QByteArray pkg_data = fdata->read(pkg.size);
|
||||
if(pkg_data.size() != pkg.size) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file, read_len=%" PRId64 " (3).", file_idx+1, read_len);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
file_processed += pkg.size;
|
||||
|
||||
UpdateData* dat = new UpdateData();
|
||||
if(!dat->parse(pkg, pkg_data)) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file (4).", file_idx+1);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 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 = fdata->read(reinterpret_cast<char*>(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
||||
// if(read_len != pkg.size) {
|
||||
// delete dat;
|
||||
// qDebug("invaid tp-rdp-%d.tpd file, read_len=%" PRId64 " (3).", file_idx+1, read_len);
|
||||
// _notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
// return;
|
||||
// }
|
||||
// file_processed += pkg.size;
|
||||
|
||||
// 跳过关键帧
|
||||
// TODO: 拖动滚动条后,需要显示一次关键帧数据,然后跳过后续关键帧。
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
|
@ -315,10 +331,12 @@ void ThrData::_run() {
|
|||
if(dat) {
|
||||
m_locker.lock();
|
||||
m_data.enqueue(dat);
|
||||
qDebug("queue data count: %d", m_data.size());
|
||||
// qDebug("queue data count: %d", m_data.size());
|
||||
m_locker.unlock();
|
||||
}
|
||||
|
||||
msleep(1);
|
||||
|
||||
// 如果此文件已经处理完毕,则关闭文件,这样下次处理一个新的文件
|
||||
// qDebug("C processed: %" PRId64 ", size: %" PRId64, file_processed, file_size);
|
||||
if(file_processed >= file_size) {
|
||||
|
@ -332,7 +350,7 @@ void ThrData::_run() {
|
|||
UpdateData* dat = new UpdateData(TYPE_END);
|
||||
m_locker.lock();
|
||||
m_data.enqueue(dat);
|
||||
qDebug("queue data count: %d", m_data.size());
|
||||
// qDebug("queue data count: %d", m_data.size());
|
||||
m_locker.unlock();
|
||||
}
|
||||
}
|
||||
|
@ -433,8 +451,10 @@ UpdateData* ThrData::get_data() {
|
|||
UpdateData* d = nullptr;
|
||||
|
||||
m_locker.lock();
|
||||
if(m_data.size() > 0)
|
||||
if(m_data.size() > 0) {
|
||||
// qDebug("get_data(), left: %d", m_data.size());
|
||||
d = m_data.dequeue();
|
||||
}
|
||||
m_locker.unlock();
|
||||
|
||||
return d;
|
||||
|
|
|
@ -23,7 +23,8 @@ ThrPlay::ThrPlay(MainWindow* mainwnd) {
|
|||
m_mainwnd = mainwnd;
|
||||
m_need_stop = false;
|
||||
m_need_pause = false;
|
||||
m_speed = 2;
|
||||
m_speed = 1;
|
||||
m_skip = false;
|
||||
// m_res = res;
|
||||
// m_thr_data = nullptr;
|
||||
}
|
||||
|
@ -67,13 +68,16 @@ void ThrPlay::run() {
|
|||
|
||||
ThrData* thr_data = m_mainwnd->get_thr_data();
|
||||
bool first_run = true;
|
||||
uint32_t last_time_ms = 0;
|
||||
uint32_t last_pass_ms = 0;
|
||||
|
||||
UpdateData* dat = nullptr;
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
break;
|
||||
|
||||
// 1. 从ThrData的待播放队列中取出一个数据
|
||||
UpdateData* dat = thr_data->get_data();
|
||||
dat = thr_data->get_data();
|
||||
if(dat == nullptr) {
|
||||
msleep(20);
|
||||
continue;
|
||||
|
@ -85,161 +89,73 @@ void ThrPlay::run() {
|
|||
}
|
||||
|
||||
// 2. 根据数据包的信息,等待到播放时间点
|
||||
uint32_t need_wait_ms = 0;
|
||||
uint32_t this_time_ms = dat->get_time();
|
||||
uint32_t this_pass_ms = last_time_ms;
|
||||
if(this_time_ms > 0) {
|
||||
need_wait_ms = this_time_ms - last_time_ms;
|
||||
|
||||
if(need_wait_ms > 0) {
|
||||
uint32_t time_wait = 0;
|
||||
|
||||
// 如果设置了跳过无操作区间,将超过1秒的等待时间压缩至1秒。
|
||||
if(m_skip) {
|
||||
if(need_wait_ms > 1000)
|
||||
need_wait_ms = 1000;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
time_wait = need_wait_ms > 10 ? 10 : need_wait_ms;
|
||||
msleep(time_wait);
|
||||
|
||||
if(m_need_pause) {
|
||||
while(m_need_pause) {
|
||||
msleep(50);
|
||||
if(m_need_stop)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_need_stop)
|
||||
break;
|
||||
|
||||
time_wait *= m_speed;
|
||||
|
||||
// 如果已经在等待长时间无操作区间内,用户设置了跳过无操作区间,则将超过0.5秒的等待时间压缩至0.5秒。
|
||||
if(m_skip) {
|
||||
if(need_wait_ms > 500)
|
||||
need_wait_ms = 500;
|
||||
}
|
||||
|
||||
this_pass_ms += time_wait;
|
||||
if(this_pass_ms - last_pass_ms > 100) {
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(this_pass_ms);
|
||||
emit signal_update_data(_passed_ms);
|
||||
last_pass_ms = this_pass_ms;
|
||||
}
|
||||
|
||||
if(need_wait_ms <= time_wait)
|
||||
break;
|
||||
else
|
||||
need_wait_ms -= time_wait;
|
||||
}
|
||||
|
||||
if(m_need_stop)
|
||||
break;
|
||||
}
|
||||
|
||||
last_time_ms = this_time_ms;
|
||||
}
|
||||
|
||||
// 3. 将数据包发送给主UI界面进行显示
|
||||
// qDebug("emit one package.");
|
||||
if(dat->data_type() == TYPE_END) {
|
||||
_notify_message(LOCAL8BIT("播放结束"));
|
||||
}
|
||||
|
||||
emit signal_update_data(dat);
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//======================================
|
||||
// 加载录像文件数据并播放
|
||||
//======================================
|
||||
|
||||
uint32_t pkg_count = 0;
|
||||
uint32_t time_pass = 0;
|
||||
uint32_t time_last_pass = 0;
|
||||
qint64 time_begin = QDateTime::currentMSecsSinceEpoch();
|
||||
QString msg;
|
||||
|
||||
for(uint32_t fidx = 0; fidx < file_count; ++fidx) {
|
||||
if(m_need_stop) {
|
||||
qDebug() << "stop, user cancel 1.";
|
||||
break;
|
||||
}
|
||||
|
||||
QString tpd_filename;
|
||||
tpd_filename.sprintf("%stp-rdp-%d.tpd", path_base.toStdString().c_str(), fidx+1);
|
||||
|
||||
// // for test.
|
||||
// msg = QString::fromLocal8Bit("无法打开录像数据文件!\n\n");
|
||||
// //msg.sprintf("无法打开录像数据文件!\n\n%s", tpd_filename.toStdString().c_str());
|
||||
// msg += tpd_filename.toStdString().c_str();
|
||||
// _notify_message(msg);
|
||||
|
||||
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.toStdString().c_str();
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(pkg_count < total_pkg) {
|
||||
qDebug() << "total-pkg:" << total_pkg << ", played:" << pkg_count;
|
||||
// msg.sprintf("录像数据文件有误!\n\n部分录像数据缺失!");
|
||||
msg = QString::fromLocal8Bit("录像数据文件有误!\n\n部分录像数据缺失!");
|
||||
_notify_message(msg);
|
||||
}
|
||||
|
||||
#endif
|
||||
// qDebug("play end.");
|
||||
// UpdateData* _end = new UpdateData(TYPE_END);
|
||||
// emit signal_update_data(_end);
|
||||
if(dat != nullptr)
|
||||
delete dat;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
void pause() {m_need_pause = true;}
|
||||
void resume() {m_need_pause = false;}
|
||||
void speed(int s) {if(s >= 1 && s <= 16) m_speed = s;}
|
||||
void skip(bool s) {m_skip = s;}
|
||||
|
||||
private:
|
||||
void _notify_message(const QString& msg);
|
||||
|
@ -34,6 +35,7 @@ private:
|
|||
bool m_need_stop;
|
||||
bool m_need_pause;
|
||||
int m_speed;
|
||||
bool m_skip;
|
||||
};
|
||||
|
||||
#endif // THR_PLAY_H
|
||||
|
|
|
@ -1,17 +1,157 @@
|
|||
#include "update_data.h"
|
||||
#include "rle.h"
|
||||
|
||||
UpdateData::UpdateData(int data_type, QObject *parent) : QObject(parent)
|
||||
#include <QImage>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
static QImage* _rdpimg2QImage(int w, int h, int bitsPerPixel, bool isCompressed, const uint8_t* dat, uint32_t len) {
|
||||
QImage* out;
|
||||
switch(bitsPerPixel) {
|
||||
case 15:
|
||||
if(isCompressed) {
|
||||
uint8_t* _dat = reinterpret_cast<uint8_t*>(calloc(1, w*h*2));
|
||||
if(!bitmap_decompress1(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
return nullptr;
|
||||
}
|
||||
out = new QImage(_dat, w, h, QImage::Format_RGB555);
|
||||
free(_dat);
|
||||
}
|
||||
else {
|
||||
out = new QImage(QImage(dat, w, h, QImage::Format_RGB555).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)));
|
||||
}
|
||||
return out;
|
||||
|
||||
case 16:
|
||||
if(isCompressed) {
|
||||
uint8_t* _dat = reinterpret_cast<uint8_t*>(calloc(1, w*h*2));
|
||||
if(!bitmap_decompress2(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: 这里需要进一步优化,直接操作QImage的buffer。
|
||||
out = new QImage(w, h, QImage::Format_RGB16);
|
||||
for(int y = 0; y < h; y++) {
|
||||
for(int x = 0; x < w; x++) {
|
||||
uint16 a = ((uint16*)_dat)[y * w + x];
|
||||
uint8 r = ((a & 0xf800) >> 11) * 255 / 31;
|
||||
uint8 g = ((a & 0x07e0) >> 5) * 255 / 63;
|
||||
uint8 b = (a & 0x001f) * 255 / 31;
|
||||
out->setPixelColor(x, y, QColor(r,g,b));
|
||||
}
|
||||
}
|
||||
free(_dat);
|
||||
return out;
|
||||
}
|
||||
else {
|
||||
out = new QImage(QImage(dat, w, h, QImage::Format_RGB16).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)));
|
||||
}
|
||||
return out;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
qDebug() << "--------NOT support UNKNOWN bitsPerPix" << bitsPerPixel;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UpdateData::UpdateData() : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
UpdateData::UpdateData(int data_type) : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
m_data_type = data_type;
|
||||
}
|
||||
|
||||
UpdateData::UpdateData(const TS_RECORD_HEADER& hdr) : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
m_data_type = TYPE_HEADER_INFO;
|
||||
m_hdr = new TS_RECORD_HEADER;
|
||||
memcpy(m_hdr, &hdr, sizeof(TS_RECORD_HEADER));
|
||||
}
|
||||
|
||||
void UpdateData::_init() {
|
||||
m_data_type = TYPE_UNKNOWN;
|
||||
m_hdr = nullptr;
|
||||
m_pointer = nullptr;
|
||||
m_img = nullptr;
|
||||
// m_img_info = nullptr;
|
||||
|
||||
m_data_buf = nullptr;
|
||||
m_data_len = 0;
|
||||
m_time_ms = 0;
|
||||
}
|
||||
|
||||
UpdateData::~UpdateData() {
|
||||
if(m_hdr)
|
||||
delete m_hdr;
|
||||
if(m_pointer)
|
||||
delete m_pointer;
|
||||
if(m_img)
|
||||
delete m_img;
|
||||
// if(m_img_info)
|
||||
// delete m_img_info;
|
||||
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
}
|
||||
|
||||
bool UpdateData::parse(const TS_RECORD_PKG& pkg, const QByteArray& data) {
|
||||
m_time_ms = pkg.time_ms;
|
||||
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_POINTER) {
|
||||
m_data_type = TYPE_POINTER;
|
||||
if(data.size() != sizeof(TS_RECORD_RDP_POINTER))
|
||||
return false;
|
||||
m_pointer = new TS_RECORD_RDP_POINTER;
|
||||
memcpy(m_pointer, data.data(), sizeof(TS_RECORD_RDP_POINTER));
|
||||
return true;
|
||||
}
|
||||
else if(pkg.type == TS_RECORD_TYPE_RDP_IMAGE) {
|
||||
m_data_type = TYPE_IMAGE;
|
||||
if(data.size() <= sizeof(TS_RECORD_RDP_IMAGE_INFO))
|
||||
return false;
|
||||
const TS_RECORD_RDP_IMAGE_INFO* info = reinterpret_cast<const TS_RECORD_RDP_IMAGE_INFO*>(data.data());
|
||||
const uint8_t* img_dat = reinterpret_cast<const uint8_t*>(data.data() + sizeof(TS_RECORD_RDP_IMAGE_INFO));
|
||||
uint32_t img_len = data.size() - sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||
|
||||
QImage* img = _rdpimg2QImage(info->width, info->height, info->bitsPerPixel, (info->format == TS_RDP_IMG_BMP) ? true : false, img_dat, img_len);
|
||||
if(img == nullptr)
|
||||
return false;
|
||||
|
||||
m_img = img;
|
||||
m_img_x = info->destLeft;
|
||||
m_img_y = info->destTop;
|
||||
m_img_w = info->destRight - info->destLeft + 1;
|
||||
m_img_h = info->destBottom - info->destTop + 1;
|
||||
|
||||
|
||||
|
||||
// m_img_info = new TS_RECORD_RDP_IMAGE_INFO;
|
||||
// memcpy(m_img_info, data.data(), sizeof(TS_RECORD_RDP_IMAGE_INFO));
|
||||
// m_data_buf = new uint8_t[img_len];
|
||||
// memcpy(m_data_buf, img_dat, img_len);
|
||||
// m_data_len = img_len;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void UpdateData::alloc_data(uint32_t len) {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
|
|
|
@ -1,23 +1,45 @@
|
|||
#ifndef UPDATE_DATA_H
|
||||
#ifndef UPDATE_DATA_H
|
||||
#define UPDATE_DATA_H
|
||||
|
||||
#include <QObject>
|
||||
#include "record_format.h"
|
||||
|
||||
#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
|
||||
#define TYPE_UNKNOWN 0
|
||||
#define TYPE_HEADER_INFO 1
|
||||
#define TYPE_POINTER 10
|
||||
#define TYPE_IMAGE 11
|
||||
#define TYPE_KEYFRAME 12
|
||||
#define TYPE_PLAYED_MS 20
|
||||
#define TYPE_DOWNLOAD_PERCENT 21
|
||||
#define TYPE_END 50
|
||||
#define TYPE_MESSAGE 90
|
||||
#define TYPE_ERROR 91
|
||||
|
||||
class UpdateData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UpdateData(int data_type, QObject *parent = nullptr);
|
||||
explicit UpdateData();
|
||||
explicit UpdateData(int data_type);
|
||||
explicit UpdateData(const TS_RECORD_HEADER& hdr);
|
||||
virtual ~UpdateData();
|
||||
|
||||
bool parse(const TS_RECORD_PKG& pkg, const QByteArray& data);
|
||||
TS_RECORD_HEADER* get_header() {return m_hdr;}
|
||||
TS_RECORD_RDP_POINTER* get_pointer() {return m_pointer;}
|
||||
bool get_image(QImage** img, int& x, int& y, int& w, int& h) {
|
||||
if(m_img == nullptr)
|
||||
return false;
|
||||
*img = m_img;
|
||||
x = m_img_x;
|
||||
y = m_img_y;
|
||||
w = m_img_w;
|
||||
h = m_img_h;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t get_time() {return m_time_ms;}
|
||||
|
||||
void alloc_data(uint32_t len);
|
||||
void attach_data(const uint8_t* dat, uint32_t len);
|
||||
|
||||
|
@ -32,6 +54,9 @@ public:
|
|||
void message(const QString& msg) {m_msg = msg;}
|
||||
const QString message(){return m_msg;}
|
||||
|
||||
private:
|
||||
void _init(void);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
@ -39,10 +64,24 @@ public slots:
|
|||
|
||||
private:
|
||||
int m_data_type;
|
||||
uint32_t m_time_ms;
|
||||
uint8_t* m_data_buf;
|
||||
uint32_t m_data_len;
|
||||
uint32_t m_played_ms;
|
||||
QString m_msg;
|
||||
|
||||
// for HEADER
|
||||
TS_RECORD_HEADER* m_hdr;
|
||||
// for POINTER
|
||||
TS_RECORD_RDP_POINTER* m_pointer;
|
||||
// for IMAGE
|
||||
QImage* m_img;
|
||||
int m_img_x;
|
||||
int m_img_y;
|
||||
int m_img_w;
|
||||
int m_img_h;
|
||||
|
||||
// TS_RECORD_RDP_IMAGE_INFO* m_img_info;
|
||||
};
|
||||
|
||||
class UpdateDataHelper {
|
||||
|
|
Loading…
Reference in New Issue