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) :
22  QWidget(parent)
23 {
24 }
25 
26 const QPixmap* ImageLabel::pixmap() const {
27  return &pix;
28 }
29 
30 void ImageLabel::setPixmap (const QPixmap &pixmap){
31  pix = pixmap;
32 }
33 
34 void ImageLabel::paintEvent(QPaintEvent *event)
35 {
36  QWidget::paintEvent(event);
37 
38  if (pix.isNull())
39  {
40  return;
41  }
42 
43  QPainter painter(this);
44  painter.setRenderHint(QPainter::Antialiasing);
45 
46  QSize rect_size = event->rect().size();
47  QSize pix_size = pix.size();
48  pix_size.scale(event->rect().size(), Qt::KeepAspectRatio);
49 
50  QPoint corner((rect_size.width() - pix_size.width()) / 2,
51  (rect_size.height() - pix_size.height()) / 2);
52 
53  QPixmap scaled_pix = pix.scaled(pix_size,
54  Qt::KeepAspectRatio,
55  Qt::SmoothTransformation);
56  painter.drawPixmap(corner, scaled_pix);
57 }
58 
59 VideoDialog::VideoDialog(QWidget *parent) :
60  QDialog(parent),
61  ui(new Ui::VideoDialog)
62 {
63  using namespace QtAV;
64 
65  ui->setupUi(this);
66  _media_player = new AVPlayer(this);
67  _media_player->audio()->setBackends(QStringList() << "null");
68  _video_output = new VideoOutput(this);
69 
70  if (!_video_output->widget())
71  {
72  QMessageBox::warning(this, QString::fromLatin1("QtAV error"),
73  tr("Can not create video renderer"));
74  return;
75  }
76  _media_player->setRenderer(_video_output);
77  ui->verticalLayoutMain->addWidget(_video_output->widget(), 1.0);
78 
79  connect(_media_player, &AVPlayer::started,
81 
82  ui->lineEditReference->installEventFilter(this);
83 
84  QSettings settings;
85  QString theme = settings.value("Preferences::theme", "light").toString();
86  ui->clearButton->setIcon(LoadSvg(":/resources/svg/trash.svg", theme));
87 
88  _label = new ImageLabel(this);
89  ui->verticalLayoutMain->addWidget(_label, 1.0);
90  _label->setHidden(true);
91 }
92 
94 {
95  delete ui;
96 }
97 
98 bool VideoDialog::loadFile(QString filename)
99 {
100  if(!filename.isEmpty() && QFileInfo::exists(filename))
101  {
102  _media_player->play(filename);
103  _media_player->pause(true);
104  ui->lineFilename->setText(filename);
105 
106  _frame_reader = std::make_unique<QtAV::FrameReader>();
107  _frame_reader->setMedia(filename);
108  _compressed_frames.clear();
109  ui->decodeButton->setEnabled(true);
110 
111  _decoded = false;
112 
113  _video_output->widget()->setHidden(false);
114  _label->setHidden(true);
115  return true;
116  }
117  return false;
118 }
119 
120 
122 {
123  return ui->lineEditReference->text();
124 }
125 
126 void VideoDialog::pause(bool paused)
127 {
128  _media_player->pause(paused);
129 }
130 
132 {
133  return _media_player->isPaused();
134 }
135 
137 {
138  QSettings settings;
139 
140  QString directory_path =
141  settings.value("VideoDialog.loadDirectory", QDir::currentPath()).toString();
142 
143  QString filename = QFileDialog::getOpenFileName(this, tr("Load Video"),
144  directory_path, tr("(*.*)"));
145  if (!loadFile(filename))
146  {
147  return;
148  }
149  directory_path = QFileInfo(filename).absolutePath();
150  settings.setValue("VideoDialog.loadDirectory", directory_path);
151 }
152 
154 {
155  const auto& fps = _media_player->statistics().video.frame_rate;
156  qint64 duration_ms = _media_player->duration();
157  int num_frames = static_cast<int>(qreal(duration_ms) * fps / 1000.0);
158  ui->timeSlider->setRange(0, num_frames);
159  _media_player->setNotifyInterval( static_cast<int>(1000 / fps) );
160  _media_player->pause(true);
161 
162  ui->timeSlider->setEnabled(true);
163 
164  if(_media_player->isSeekable() == false || duration_ms == 0)
165  {
166  QMessageBox msgBox(this);
167  msgBox.setWindowTitle("Video is not seekable");
168  msgBox.setText(tr("Video is not seekable. You will need to decode the video into individual frames.\n"));
169  msgBox.addButton(QMessageBox::Cancel);
170  QPushButton* button = msgBox.addButton(tr("Decode!"), QMessageBox::YesRole);
171  msgBox.setDefaultButton(button);
172 
173  int res = msgBox.exec();
174 
175  if (res < 0 || res == QMessageBox::Cancel)
176  {
177  ui->timeSlider->setEnabled(false);
178  }
179  else{
181  }
182  }
183 }
184 
186 {
187  double fps = _media_player->statistics().video.frame_rate;
188  double period = 1000 / fps;
189  qint64 frame_pos = static_cast<qint64>(qreal(num) * period );
190 
191  if( _decoded )
192  {
193  num = std::max(0, num);
194  num = std::min(int(_compressed_frames.size()-1), num);
195 
196  auto& frame = _compressed_frames[num];
197  void* data = qoi_decode( frame.data, frame.length, &frame.info, 3);
198  QImage image(static_cast<uchar*>(data), frame.info.width, frame.info.height, QImage::Format_RGB888);
199 
200  //qDebug() << "ratio: " << double(3*frame.info.width*frame.info.height) / 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 
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 
290 
292 {
293  if( _decoded )
294  {
295  return;
296  }
297 
298  double fps = _media_player->statistics().video.frame_rate;
299  QProgressDialog progress_dialog;
300  progress_dialog.setWindowTitle("PlotJuggler Video");
301  progress_dialog.setLabelText("Decoding file");
302  progress_dialog.setWindowModality(Qt::ApplicationModal);
303  progress_dialog.setRange(0, _media_player->duration() * fps / 1000);
304  progress_dialog.setAutoClose(true);
305  progress_dialog.setAutoReset(true);
306  progress_dialog.show();
307 
308  int count = 0;
309  while (_frame_reader->readMore())
310  {
311  while (_frame_reader->hasEnoughVideoFrames())
312  {
313  const QtAV::VideoFrame frame = _frame_reader->getVideoFrame();
314  if (!frame)
315  {
316  continue;
317  }
318 
319  QImage image = frame.toImage(QImage::Format_RGB888);
320 
321  CompressedFrame compressed_frame;
322  compressed_frame.info.width = frame.width();
323  compressed_frame.info.height = frame.height();
324  compressed_frame.info.channels = 3;
325  compressed_frame.info.colorspace = QOI_LINEAR;
326  compressed_frame.data = 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 }
unsigned char colorspace
Definition: qoi.h:260
void on_loadButton_clicked()
bool loadFile(QString filename)
unsigned int width
Definition: qoi.h:257
bool eventFilter(QObject *obj, QEvent *ev)
void on_clearButton_clicked()
void on_timeSlider_valueChanged(int value)
const QPixmap * pixmap() const
QString _dragging_curve
Definition: video_dialog.h:106
std::vector< CompressedFrame > _compressed_frames
Definition: video_dialog.h:103
ImageLabel(QWidget *parent=nullptr)
ImageLabel * _label
Definition: video_dialog.h:108
const QPixmap & LoadSvg(QString filename, QString style_name="light")
Definition: svg_util.h:26
void paintEvent(QPaintEvent *)
VideoDialog(QWidget *parent=nullptr)
QString referenceCurve() const
void * qoi_encode(const void *data, const qoi_desc *desc, int *out_len)
unsigned char channels
Definition: qoi.h:259
void * qoi_decode(const void *data, int size, qoi_desc *desc, int channels)
std::unique_ptr< QtAV::FrameReader > _frame_reader
Definition: video_dialog.h:82
void pause(bool paused)
constexpr auto count() -> size_t
Definition: core.h:1050
QPixmap pix
Definition: video_dialog.h:30
QtAV::VideoOutput * _video_output
Definition: video_dialog.h:80
const T & move(const T &v)
Definition: backward.hpp:394
unsigned int height
Definition: qoi.h:258
void on_decodeButton_clicked()
void setPixmap(const QPixmap &)
QtAV::AVPlayer * _media_player
Definition: video_dialog.h:81
#define QOI_LINEAR
Definition: qoi.h:254
Definition: core.h:1131
void seekByValue(double value)
void updateSlider()
Ui::VideoDialog * ui
Definition: video_dialog.h:48
Definition: format.h:895
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:583
bool isPaused() const


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:12:53