Marble

TourCaptureDialog.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2014 Sanjiban Bairagya <sanjiban22393@gmail.com>
4//
5
6#include "TourCaptureDialog.h"
7#include "ui_TourCaptureDialog.h"
8
9#include <QFileDialog>
10#include <QMessageBox>
11#include <QTimer>
12
13#include "MarbleWidget.h"
14#include "MovieCapture.h"
15#include "TourPlayback.h"
16
17namespace Marble {
18
19TourCaptureDialog::TourCaptureDialog(MarbleWidget *widget, QWidget *parent) :
20 QDialog(parent),
21 ui(new Ui::TourCaptureDialog),
22 m_recorder(new MovieCapture(widget, parent)),
23 m_playback(nullptr),
24 m_writingPossible( true ),
25 m_current_position( 0.0 )
26{
27 ui->setupUi(this);
28 m_recorder->setSnapshotMethod(MovieCapture::DataDriven);
29 ui->progressBar->setValue(0);
30
31 connect(ui->fpsSlider, SIGNAL(valueChanged(int)),
32 ui->fpsSpin, SLOT(setValue(int)));
33
34 connect(ui->fpsSpin, SIGNAL(valueChanged(int)),
35 ui->fpsSlider, SLOT(setValue(int)));
36
37 connect(ui->fpsSlider, SIGNAL(valueChanged(int)),
38 m_recorder, SLOT(setFps(int)));
39
40 connect(ui->closeButton, SIGNAL(clicked()),
41 this, SLOT(close()));
42
43 connect(ui->startButton, SIGNAL(clicked()),
44 this, SLOT(startRecording()));
45
46 connect(ui->openButton, SIGNAL(clicked()),
47 this, SLOT(loadDestinationFile()));
48
49 connect(m_recorder, SIGNAL(rateCalculated(double)),
50 this, SLOT(setRate(double))) ;
51
52 connect(m_recorder, SIGNAL(errorOccured()),
53 this, SLOT(handleError()) );
54}
55
56TourCaptureDialog::~TourCaptureDialog()
57{
58 delete ui;
59}
60
61void TourCaptureDialog::loadDestinationFile()
62{
63 const QVector<MovieFormat> formats = m_recorder->availableFormats();
64 if( formats.isEmpty() ) {
65 QMessageBox::warning( this, tr( "Codecs are unavailable" ), tr( "Supported codecs are not found. (ffmpeg/avconv needs to be installed and in PATH.)" ) );
66 return;
67 }
68 QString filter = formats.first().name() + QLatin1String(" (*.") + formats.first().extension() + QLatin1Char(')');
69 for( int i = 1; i < formats.size(); i++ )
70 {
71 filter += QLatin1String(";;") + formats.at(i).name() + QLatin1String(" (*.") + formats.at(i).extension() + QLatin1Char(')');
72 }
73 const QString defaultFileName =
74 ui->destinationEdit->text().isEmpty() ? m_defaultFileName : ui->destinationEdit->text();
75
76 const QString destination =
77 QFileDialog::getSaveFileName(this, tr("Save video file"), defaultFileName,
78 filter );
79
80 if (destination.isEmpty()) {
81 return;
82 }
83
84 bool supported = false;
85 for(const MovieFormat &format: formats) {
86 if (destination.endsWith(QLatin1Char('.') + format.extension())) {
87 supported = true;
88 break;
89 }
90 }
91
92 if (!supported) {
93 QString formatsExtensions = QLatin1Char('.') + formats.at(0).extension();
94 for( int i = 1; i < formats.size(); ++i )
95 {
96 formatsExtensions += QLatin1String(", .") + formats.at(i).extension();
97 }
98 QMessageBox::warning(this, tr("Filename is not valid"),
99 tr("This file format is not supported. "
100 "Please, use %1 instead").arg( formatsExtensions ) );
101 return;
102 }
103
104 ui->destinationEdit->setText(destination);
105 m_recorder->setFilename(destination);
106}
107
108void TourCaptureDialog::startRecording()
109{
110 if( ui->startButton->text() == tr("Start") ){
111 ui->startButton->setText(tr("Cancel"));
112 ui->closeButton->setDisabled(true);
113 const QString path = ui->destinationEdit->text();
114
115 if( path.isEmpty() ){
116 QMessageBox::warning(this, tr("Missing filename"),
117 tr("Destination video file is not set. "
118 "I don't know where to save recorded "
119 "video. Please, specify one."));
120 return;
121 }
122
123 m_recorder->setSnapshotMethod( MovieCapture::DataDriven );
124 m_recorder->setFps(ui->fpsSlider->value());
125 m_recorder->startRecording();
126 m_current_position = 0.0;
127 recordNextFrame();
128 }
129 else{
130 ui->startButton->setText(tr("Start"));
131 m_recorder->cancelRecording();
132 ui->progressBar->setValue(0);
133 ui->closeButton->setEnabled(true);
134 }
135}
136
137void TourCaptureDialog::updateProgress(double position)
138{
139 ui->progressBar->setValue(position);
140}
141
142void TourCaptureDialog::recordNextFrame()
143{
144 double const shift = 1.0 / ( ui->fpsSlider->value() );
145 double const duration = m_playback->duration();
146
147 if (!m_writingPossible) {
148 ui->rate->setText(QString("<font color=\"red\">%1</font>").arg(tr("Video writing failed.")));
149 return;
150 }
151
152 if (ui->startButton->text() == QLatin1String("Start")) {
153 return;
154 }
155
156 if (m_current_position <= duration) {
157 m_playback->seek( m_current_position );
158 m_recorder->recordFrame();
159 updateProgress( m_current_position * 100 );
160 m_current_position += shift;
161 QTimer::singleShot(1, this, SLOT(recordNextFrame()));
162 } else {
163 m_recorder->stopRecording();
164 ui->progressBar->setValue(duration*100);
165 ui->startButton->setText(tr("Start"));
166 ui->rate->setText(QString("<font color=\"green\">%1</font>").arg(tr("Video export completed.")));
167 ui->closeButton->setEnabled(true);
168 }
169}
170
171void TourCaptureDialog::setRate(double rate)
172{
173 ui->rate->setText(QString("%1 KBytes/sec").arg(rate));
174}
175
176void TourCaptureDialog::stopRecording()
177{
178 m_recorder->stopRecording();
179}
180
181void TourCaptureDialog::setTourPlayback( TourPlayback* playback )
182{
183 m_playback = playback;
184 ui->progressBar->setMaximum(playback->duration() * 100);
185}
186
187void TourCaptureDialog::setDefaultFilename(const QString &filename)
188{
189 m_defaultFileName = filename;
190}
191
192void TourCaptureDialog::handleError()
193{
194 m_writingPossible = false;
195}
196
197} // namespace Marble
198
199#include "moc_TourCaptureDialog.cpp"
This file contains the headers for MarbleWidget.
QString path(const QString &relativePath)
const QList< QKeySequence > & close()
Binds a QML item to a specific geodetic location in screen coordinates.
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
const_reference at(qsizetype i) const const
T & first()
bool isEmpty() const const
qsizetype size() const const
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setupUi(QWidget *widget)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.