video_dialog.cpp
Go to the documentation of this file.
1 #include "video_dialog.h"
2 #include <QFileDialog>
3 #include <QDir>
4 #include <QFileInfo>
5 #include <QLineEdit>
6 #include <QDebug>
7 #include <QMessageBox>
8 #include <QDragEnterEvent>
9 #include <QMimeData>
10 #include <QSettings>
11 #include <cmath>
12 #include <QPixmap>
13 #include <QImage>
14 #include <QProgressDialog>
15 
16 #include "PlotJuggler/svg_util.h"
17 
18 #define QOI_IMPLEMENTATION
19 #include "qoi.h"
20 
21 ImageLabel::ImageLabel(QWidget* parent) : QWidget(parent)
22 {
23 }
24 
25 const QPixmap* ImageLabel::pixmap() const
26 {
27  return &pix;
28 }
29 
30 void ImageLabel::setPixmap(const QPixmap& pixmap)
31 {
32  pix = pixmap;
33 }
34 
35 void ImageLabel::paintEvent(QPaintEvent* event)
36 {
37  QWidget::paintEvent(event);
38 
39  if (pix.isNull())
40  {
41  return;
42  }
43 
44  QPainter painter(this);
45  painter.setRenderHint(QPainter::Antialiasing);
46 
47  QSize rect_size = event->rect().size();
48  QSize pix_size = pix.size();
49  pix_size.scale(event->rect().size(), Qt::KeepAspectRatio);
50 
51  QPoint corner((rect_size.width() - pix_size.width()) / 2,
52  (rect_size.height() - pix_size.height()) / 2);
53 
54  QPixmap scaled_pix =
55  pix.scaled(pix_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
56  painter.drawPixmap(corner, scaled_pix);
57 }
58 
59 VideoDialog::VideoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::VideoDialog)
60 {
61  using namespace QtAV;
62 
63  ui->setupUi(this);
64  _media_player = new AVPlayer(this);
65  _media_player->audio()->setBackends(QStringList() << "null");
66  _video_output = new VideoOutput(this);
67 
68  if (!_video_output->widget())
69  {
70  QMessageBox::warning(this, QString::fromLatin1("QtAV error"),
71  tr("Can not create video renderer"));
72  return;
73  }
74  _media_player->setRenderer(_video_output);
75  ui->verticalLayoutMain->addWidget(_video_output->widget(), 1.0);
76 
77  connect(_media_player, &AVPlayer::started, this, &VideoDialog::updateSlider);
78 
79  ui->lineEditReference->installEventFilter(this);
80 
81  QSettings settings;
82  QString theme = settings.value("Preferences::theme", "light").toString();
83  ui->clearButton->setIcon(LoadSvg(":/resources/svg/trash.svg", theme));
84 
85  _label = new ImageLabel(this);
86  ui->verticalLayoutMain->addWidget(_label, 1.0);
87  _label->setHidden(true);
88 }
89 
91 {
92  delete ui;
93 }
94 
95 bool VideoDialog::loadFile(QString filename)
96 {
97  if (!filename.isEmpty() && QFileInfo::exists(filename))
98  {
99  _media_player->play(filename);
100  _media_player->pause(true);
101  ui->lineFilename->setText(filename);
102 
103  _frame_reader = std::make_unique<QtAV::FrameReader>();
104  _frame_reader->setMedia(filename);
105  _compressed_frames.clear();
106  ui->decodeButton->setEnabled(true);
107 
108  _decoded = false;
109 
110  _video_output->widget()->setHidden(false);
111  _label->setHidden(true);
112  return true;
113  }
114  return false;
115 }
116 
118 {
119  return ui->lineEditReference->text();
120 }
121 
122 void VideoDialog::pause(bool paused)
123 {
124  _media_player->pause(paused);
125 }
126 
128 {
129  return _media_player->isPaused();
130 }
131 
133 {
134  QSettings settings;
135 
136  QString directory_path =
137  settings.value("VideoDialog.loadDirectory", QDir::currentPath()).toString();
138 
139  QString filename =
140  QFileDialog::getOpenFileName(this, tr("Load Video"), directory_path, tr("(*.*)"));
141  if (!loadFile(filename))
142  {
143  return;
144  }
145  directory_path = QFileInfo(filename).absolutePath();
146  settings.setValue("VideoDialog.loadDirectory", directory_path);
147 }
148 
150 {
151  const auto& fps = _media_player->statistics().video.frame_rate;
152  qint64 duration_ms = _media_player->duration();
153  int num_frames = static_cast<int>(qreal(duration_ms) * fps / 1000.0);
154  ui->timeSlider->setRange(0, num_frames);
155  _media_player->setNotifyInterval(static_cast<int>(1000 / fps));
156  _media_player->pause(true);
157 
158  ui->timeSlider->setEnabled(true);
159 
160  if (_media_player->isSeekable() == false || duration_ms == 0)
161  {
162  QMessageBox msgBox(this);
163  msgBox.setWindowTitle("Video is not seekable");
164  msgBox.setText(tr("Video is not seekable. You will need to decode the video into "
165  "individual frames.\n"));
166  msgBox.addButton(QMessageBox::Cancel);
167  QPushButton* button = msgBox.addButton(tr("Decode!"), QMessageBox::YesRole);
168  msgBox.setDefaultButton(button);
169 
170  int res = msgBox.exec();
171 
172  if (res < 0 || res == QMessageBox::Cancel)
173  {
174  ui->timeSlider->setEnabled(false);
175  }
176  else
177  {
179  }
180  }
181 }
182 
184 {
185  double fps = _media_player->statistics().video.frame_rate;
186  double period = 1000 / fps;
187  qint64 frame_pos = static_cast<qint64>(qreal(num) * period);
188 
189  if (_decoded)
190  {
191  num = std::max(0, num);
192  num = std::min(int(_compressed_frames.size() - 1), num);
193 
194  auto& frame = _compressed_frames[num];
195  void* data = qoi_decode(frame.data, frame.length, &frame.info, 3);
196  QImage image(static_cast<uchar*>(data), frame.info.width, frame.info.height,
197  QImage::Format_RGB888);
198 
199  // qDebug() << "ratio: " << double(3*frame.info.width*frame.info.height) /
200  // double(frame.length);
201 
202  _label->setPixmap(QPixmap::fromImage(image));
203  _label->repaint();
204  free(data);
205  }
206  else
207  {
208  _media_player->setSeekType(QtAV::SeekType::AccurateSeek);
209  _media_player->seek(frame_pos);
210  }
211 }
212 
213 void VideoDialog::seekByValue(double value)
214 {
215  if (ui->radioButtonFrame->isChecked())
216  {
217  ui->timeSlider->setValue(static_cast<int>(value));
218  }
219  else if (ui->radioButtonTime->isChecked())
220  {
221  const auto& fps = _media_player->statistics().video.frame_rate;
222  ui->timeSlider->setValue(static_cast<int>(value * 1000 / fps));
223  }
224 }
225 
226 bool VideoDialog::eventFilter(QObject* obj, QEvent* ev)
227 {
228  if (obj != ui->lineEditReference)
229  {
230  return false;
231  }
232  if (ev->type() == QEvent::DragEnter)
233  {
234  auto event = static_cast<QDragEnterEvent*>(ev);
235  const QMimeData* mimeData = event->mimeData();
236  QStringList mimeFormats = mimeData->formats();
237 
238  QString& format = mimeFormats.front();
239 
240  QByteArray encoded = mimeData->data(format);
241  QDataStream stream(&encoded, QIODevice::ReadOnly);
242 
243  if (format != "curveslist/add_curve")
244  {
245  return false;
246  }
247 
248  QStringList curves;
249  while (!stream.atEnd())
250  {
251  QString curve_name;
252  stream >> curve_name;
253  if (!curve_name.isEmpty())
254  {
255  curves.push_back(curve_name);
256  }
257  }
258  if (curves.size() != 1)
259  {
260  return false;
261  }
262 
263  _dragging_curve = curves.front();
264  event->acceptProposedAction();
265  return true;
266  }
267  else if (ev->type() == QEvent::Drop)
268  {
269  auto lineEdit = qobject_cast<QLineEdit*>(obj);
270  lineEdit->setText(_dragging_curve);
271  }
272  return false;
273 }
274 
276 {
277  _media_player->stop();
278  ui->lineFilename->setText("");
279  ui->lineEditReference->setText("");
280  ui->timeSlider->setEnabled(false);
281  ui->timeSlider->setValue(0);
282  ui->decodeButton->setEnabled(false);
283 
284  _decoded = false;
285  _video_output->widget()->setHidden(false);
286  _label->setHidden(true);
287  _compressed_frames.clear();
288 }
289 
291 {
292  if (_decoded)
293  {
294  return;
295  }
296 
297  double fps = _media_player->statistics().video.frame_rate;
298  QProgressDialog progress_dialog;
299  progress_dialog.setWindowTitle("PlotJuggler Video");
300  progress_dialog.setLabelText("Decoding file");
301  progress_dialog.setWindowModality(Qt::ApplicationModal);
302  progress_dialog.setRange(0, _media_player->duration() * fps / 1000);
303  progress_dialog.setAutoClose(true);
304  progress_dialog.setAutoReset(true);
305  progress_dialog.show();
306 
307  int count = 0;
308  while (_frame_reader->readMore())
309  {
310  while (_frame_reader->hasEnoughVideoFrames())
311  {
312  const QtAV::VideoFrame frame = _frame_reader->getVideoFrame();
313  if (!frame)
314  {
315  continue;
316  }
317 
318  QImage image = frame.toImage(QImage::Format_RGB888);
319 
320  CompressedFrame compressed_frame;
321  compressed_frame.info.width = frame.width();
322  compressed_frame.info.height = frame.height();
323  compressed_frame.info.channels = 3;
324  compressed_frame.info.colorspace = QOI_LINEAR;
325  compressed_frame.data =
326  qoi_encode(image.bits(), &compressed_frame.info, &compressed_frame.length);
327 
328  // _frames.push_back( std::move(image) );
329  _compressed_frames.push_back(std::move(compressed_frame));
330 
331  if (++count % 10 == 0)
332  {
333  progress_dialog.setValue(count);
334  QApplication::processEvents();
335  if (progress_dialog.wasCanceled())
336  {
337  _compressed_frames.clear();
338  return;
339  }
340  }
341  }
342  }
343  _decoded = true;
344  _video_output->widget()->hide();
345  _label->setHidden(false);
346 
347  ui->decodeButton->setEnabled(false);
348  ui->timeSlider->setRange(0, _compressed_frames.size() - 1);
349  on_timeSlider_valueChanged(ui->timeSlider->value());
350 }
VideoDialog::CompressedFrame::length
int length
Definition: video_dialog.h:101
VideoDialog::seekByValue
void seekByValue(double value)
Definition: video_dialog.cpp:213
VideoDialog::isPaused
bool isPaused() const
Definition: video_dialog.cpp:127
LoadSvg
const QPixmap & LoadSvg(QString filename, QString style_name="light")
Definition: svg_util.h:26
VideoDialog::updateSlider
void updateSlider()
Definition: video_dialog.cpp:149
VideoDialog::ui
Ui::VideoDialog * ui
Definition: video_dialog.h:47
qoi_desc::width
unsigned int width
Definition: qoi.h:257
VideoDialog::on_timeSlider_valueChanged
void on_timeSlider_valueChanged(int value)
Definition: video_dialog.cpp:183
VideoDialog::_compressed_frames
std::vector< CompressedFrame > _compressed_frames
Definition: video_dialog.h:105
qoi_desc::colorspace
unsigned char colorspace
Definition: qoi.h:260
VideoDialog::_label
ImageLabel * _label
Definition: video_dialog.h:110
VideoDialog::on_clearButton_clicked
void on_clearButton_clicked()
Definition: video_dialog.cpp:275
VideoDialog::CompressedFrame::data
void * data
Definition: video_dialog.h:103
VideoDialog::_decoded
bool _decoded
Definition: video_dialog.h:112
ImageLabel::paintEvent
void paintEvent(QPaintEvent *)
Definition: video_dialog.cpp:35
VideoDialog::_dragging_curve
QString _dragging_curve
Definition: video_dialog.h:108
ImageLabel::setPixmap
void setPixmap(const QPixmap &)
Definition: video_dialog.cpp:30
VideoDialog::_video_output
QtAV::VideoOutput * _video_output
Definition: video_dialog.h:79
detail::count
constexpr auto count() -> size_t
Definition: core.h:1222
VideoDialog::_frame_reader
std::unique_ptr< QtAV::FrameReader > _frame_reader
Definition: video_dialog.h:81
ImageLabel::ImageLabel
ImageLabel(QWidget *parent=nullptr)
Definition: video_dialog.cpp:21
VideoDialog::VideoDialog
VideoDialog(QWidget *parent=nullptr)
Definition: video_dialog.cpp:59
Ui
Definition: cheatsheet_dialog.h:6
VideoDialog::referenceCurve
QString referenceCurve() const
Definition: video_dialog.cpp:117
ImageLabel::pix
QPixmap pix
Definition: video_dialog.h:30
qoi.h
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:394
qoi_desc::channels
unsigned char channels
Definition: qoi.h:259
qoi_decode
void * qoi_decode(const void *data, int size, qoi_desc *desc, int channels)
VideoDialog::pause
void pause(bool paused)
Definition: video_dialog.cpp:122
VideoDialog
Definition: video_dialog.h:33
VideoDialog::on_decodeButton_clicked
void on_decodeButton_clicked()
Definition: video_dialog.cpp:290
VideoDialog::CompressedFrame
Definition: video_dialog.h:83
VideoDialog::_media_player
QtAV::AVPlayer * _media_player
Definition: video_dialog.h:80
ImageLabel::pixmap
const QPixmap * pixmap() const
Definition: video_dialog.cpp:25
format
auto format(const text_style &ts, const S &format_str, const Args &... args) -> std::basic_string< Char >
Definition: color.h:543
video_dialog.h
qoi_encode
void * qoi_encode(const void *data, const qoi_desc *desc, int *out_len)
VideoDialog::CompressedFrame::info
qoi_desc info
Definition: video_dialog.h:102
ImageLabel
Definition: video_dialog.h:15
QOI_LINEAR
#define QOI_LINEAR
Definition: qoi.h:253
mqtt_test.data
dictionary data
Definition: mqtt_test.py:22
VideoDialog::~VideoDialog
~VideoDialog()
Definition: video_dialog.cpp:90
qoi_desc::height
unsigned int height
Definition: qoi.h:258
VideoDialog::on_loadButton_clicked
void on_loadButton_clicked()
Definition: video_dialog.cpp:132
VideoDialog::loadFile
bool loadFile(QString filename)
Definition: video_dialog.cpp:95
uchar
#define uchar(c)
Definition: lstrlib.c:40
VideoDialog::eventFilter
bool eventFilter(QObject *obj, QEvent *ev)
Definition: video_dialog.cpp:226
svg_util.h


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Aug 11 2024 02:24:26