RaidenVideoRipper

Форк
0
/
editorwindow.cpp 
1027 строк · 28.8 Кб
1
#include "editorwindow.h"
2
#include <QApplication>
3
#include <QMainWindow>
4
#include <QMediaPlayer>
5
#include <QVideoWidget>
6
#include <QFileDialog>
7
#include <QAction>
8
#include <QSlider>
9
#include <QToolBar>
10
#include <QLabel>
11
#include <QMenuBar>
12
#include <QMessageBox>
13
#include <QSize>
14
#include <QStandardPaths>
15
#include <QStyle>
16
#include <QStatusBar>
17
#include <QScreen>
18
#include <QShortcut>
19
#include <QPushButton>
20
#include <QDial>
21
#include <QString>
22
#include <QLibraryInfo>
23
#include <videoprocessor.h>
24
#include "constants.h"
25
#include "utils.h"
26

27
EditorWindow::EditorWindow()
28
{
29
    qRegisterMetaType<OutputFormat>("OutputFormat");
30
    auto style = this->style();
31
    playIcon = QIcon::fromTheme(
32
        "media-playback-start.png",
33
        style->standardIcon(QStyle::SP_MediaPlay)
34
        );
35
    pauseIcon = QIcon::fromTheme(
36
        "media-playback-pause.png",
37
        style->standardIcon(QStyle::SP_MediaPause)
38
        );
39
    stopIcon = QIcon::fromTheme(
40
        "media-playback-stop.png",
41
        style->standardIcon(QStyle::SP_MediaStop)
42
        );
43
    playbackState = std::make_tuple(QMediaPlayer::StoppedState, 0);
44
    userForcedStop = false;
45
    state = IDLE;
46
    audioOutput = nullptr;
47

48
    auto mp4 = OutputFormat(
49
        outputFormatMp4,
50
        tr("Video (mp4)"),
51
        "mp4",
52
        settings.value(outputFormatIsSelectedKey(QString(outputFormatMp4)), true).value<bool>()
53
        );
54

55
    auto gif = OutputFormat(
56
        outputFormatGif,
57
        "Gif",
58
        "gif",
59
        settings.value(outputFormatIsSelectedKey(QString(outputFormatGif)), true).value<bool>()
60
        );
61

62
    auto webm = OutputFormat(
63
        outputFormatWebm,
64
        "WebM",
65
        "webm",
66
        settings.value(outputFormatIsSelectedKey(QString(outputFormatWebm)), false).value<bool>()
67
        );
68

69
    auto mp3 = OutputFormat(
70
        outputFormatMp3,
71
        tr("Audio (mp3)"),
72
        "mp3",
73
        settings.value(outputFormatIsSelectedKey(QString(outputFormatMp3)), false).value<bool>()
74
        );
75

76
    successfulRunsCount = settings.value(successfulRunsCountKey).value<int>();
77

78
    outputFormats.push_back(mp4);
79
    outputFormats.push_back(gif);
80
    outputFormats.push_back(webm);
81
    outputFormats.push_back(mp3);
82

83
    createLayout();
84
    initializePlayer();
85
    setupActions();
86
    updateWindowTitle();
87
    openArgumentsFileIfNeeded();
88
    updateDurationLabel();
89
    progressBarWindow = nullptr;
90
    restoreWindowSize();
91
}
92

93
void EditorWindow::showDonateWindowIfNeeded()
94
{
95
    successfulRunsCount += 1;
96
    auto outputText = tr("Success!");
97
    if (successfulRunsCount >= donateSuccessfulRunsCount) {
98
        outputText = tr("<b>Success!</b><br>If you like this application, please consider a donation:<br><a href=\"https://www.donationalerts.com/r/demensdeum\">https://www.donationalerts.com/r/demensdeum</a>");
99
        successfulRunsCount = 0;
100
    }
101
    showAlert(
102
        tr("Wow!"),
103
        outputText
104
        );
105
    settings.setValue(successfulRunsCountKey, successfulRunsCount);
106
}
107

108
QString EditorWindow::outputFormatIsSelectedKey(QString identifier)
109
{
110
    return identifier + isSelectedKeyExtension;
111
}
112

113
void EditorWindow::restoreWindowSize()
114
{
115
    restoreGeometry(settings.value(mainWindowGeometryKey).toByteArray());
116
    restoreState(settings.value(mainWindowStateKey).toByteArray());
117
}
118

119
void EditorWindow::openArgumentsFileIfNeeded()
120
{
121
    auto application = QCoreApplication::instance();
122
    auto arguments = application->arguments();
123
    if (arguments.length() == 2) {
124
        auto filepath = arguments.at(1);
125
        auto url = QUrl::fromLocalFile(filepath);
126
        handleOpenFile(url);
127
    }
128
}
129

130
void EditorWindow::setupActions()
131
{
132
    openAction = new QAction(tr("Open..."), this);
133
    openAction->setShortcut(QKeySequence::Open);
134
    connect(openAction, &QAction::triggered, this, &EditorWindow::open);
135

136
    auto exitAction = new QAction(tr("Exit"), this);
137
    connect(exitAction, &QAction::triggered, this, &QMainWindow::close);
138

139
    auto fileMenu = menuBar()->addMenu(tr("&File"));
140
    fileMenu->addAction(openAction);
141
    fileMenu->addAction(exitAction);
142

143
    auto optionsMenu = menuBar()->addMenu(tr("&Options"));
144

145
    auto isPreviewChecked = settings.value(previewCheckboxStateKey, true).value<bool>();
146
    previewCheckboxAction = new QAction(tr("Preview"), this);
147
    previewCheckboxAction->setCheckable(true);
148
    previewCheckboxAction->setChecked(isPreviewChecked);
149
    connect(
150
        previewCheckboxAction,
151
        &QAction::triggered,
152
        this,
153
        &EditorWindow::previewCheckboxStateChange
154
        );
155
    optionsMenu->addAction(previewCheckboxAction);
156

157
    for (auto&& outputFormat : outputFormats) {
158
        QAction *outputFormatCheckboxAction = new QAction(outputFormat.title, this);
159
        outputFormatCheckboxAction->setCheckable(true);
160
        outputFormatCheckboxAction->setChecked(outputFormat.isSelected);
161
        outputFormatCheckboxAction->setData(QVariant::fromValue(&outputFormat));
162
        connect(
163
            outputFormatCheckboxAction,
164
            &QAction::triggered,
165
            this,
166
            &EditorWindow::outputFormatCheckboxStateChanged
167
            );
168
        optionsMenu->addAction(outputFormatCheckboxAction);
169
    }
170

171
    auto aboutMenu = menuBar()->addMenu(tr("&About"));
172

173
    auto aboutApplicationAction = new QAction(tr("About Raiden Video Ripper"), this);
174
    connect(aboutApplicationAction, &QAction::triggered, qApp, [this] { showAboutApplication(); });
175
    aboutMenu->addAction(aboutApplicationAction);
176

177
    auto aboutQtAction = new QAction(tr("About &Qt"), this);
178
    connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt);
179
    aboutMenu->addAction(aboutQtAction);
180
}
181

182
void EditorWindow::updateDurationLabel()
183
{
184
    auto format = QString("hh:mm:ss.zzz");
185
    auto start = timelineIndicator->getStartValue();
186
    auto playback = timelineIndicator->getPlaybackValue();
187
    auto end = timelineIndicator->getEndValue();
188

189
    auto startTime = QTime(0, 0);
190
    startTime = startTime.addMSecs(start);
191
    auto startFormattedTime = startTime.toString(format);
192

193
    auto endTime = QTime(0, 0);
194
    endTime = endTime.addMSecs(end);
195
    auto endFormattedTime = endTime.toString(format);
196

197
    auto playbackTime = QTime(0, 0);
198
    playbackTime = playbackTime.addMSecs(playback);
199
    auto durationFormattedTime = playbackTime.toString(format);
200

201
    auto text = QString("%1 - %2 - %3")
202
                    .arg(
203
                        startFormattedTime,
204
                        durationFormattedTime,
205
                        endFormattedTime
206
                        );
207

208
    durationLabel->setText(text);
209
}
210

211
void EditorWindow::cancelInProgress()
212
{
213
    qDebug() << "cancel in progress";
214
    state = CANCELLED;
215
    progressBarWindow.value()->close();
216
    videoProcessor.value()->cancel();
217
    videoProcessorProgressPoller.value()->stop();
218
    RaidenVideoRipper::Utils::clearQueue(currentOutputFormats);
219
}
220

221
void EditorWindow::cleanupBeforeExit()
222
{
223
    settings.setValue(mainWindowGeometryKey, saveGeometry());
224
    settings.setValue(mainWindowStateKey, saveState());
225

226
    switch (state) {
227
    case IDLE:
228
        return;
229
    case FILE_PROCESSING:
230
        cancelInProgress();
231
        break;
232
    case CANCELLED:
233
        qDebug() << "Cleanup in cancelled state, wut?";
234
        return;
235
    case EnumCount:
236
        qDebug() << "Cleanup in Enum Count state, u nuts????";
237
        return;
238
    }
239
}
240

241
void EditorWindow::closeEvent(QCloseEvent *event)
242
{
243
    cleanupBeforeExit();
244
    QMainWindow::closeEvent(event);
245
}
246

247
void EditorWindow::createLayout()
248
{
249
    auto bottomPrimaryHorizontalPanel = new QWidget();
250
    bottomPrimaryHorizontalPanel->setFixedHeight(primaryPanelHeight);
251

252
    playbackButton = new QPushButton();
253
    playbackButton->setFixedWidth(40);
254
    playbackButton->setIcon(playIcon);
255
    connect(playbackButton, &QPushButton::clicked, this, &EditorWindow::playToggleButtonClicked);
256

257
    stopButton = new QPushButton();
258
    stopButton->setFixedWidth(40);
259
    stopButton->setIcon(stopIcon);
260
    connect(stopButton, &QPushButton::clicked, this, &EditorWindow::stopButtonClicked);
261

262
    auto bottomPrimaryHorizontalPanelLayout = new QHBoxLayout(bottomPrimaryHorizontalPanel);
263
    bottomPrimaryHorizontalPanelLayout->setContentsMargins(0, 0, 0, 0);
264
    bottomPrimaryHorizontalPanelLayout->addWidget(playbackButton);
265
    bottomPrimaryHorizontalPanelLayout->addWidget(stopButton);
266

267
    volumeSlider = new QSlider(Qt::Horizontal, this);
268
    volumeSlider->setMinimum(0);
269
    volumeSlider->setMaximum(100);
270
    volumeSlider->setToolTip("Volume");
271
    volumeSlider->setFixedWidth(80);
272
    auto savedVolume = settings.value(volumeSettingsKey, volumeSlider->maximum()).value<qint64>();
273
    volumeSlider->setValue(savedVolume);
274
    connect(volumeSlider, &QSlider::valueChanged, this, &EditorWindow::volumeChanged);
275
    bottomPrimaryHorizontalPanelLayout->addWidget(volumeSlider);
276
    this->volumeChanged(savedVolume);
277

278
    auto bottomSecondaryPanel = new QWidget();
279
    bottomSecondaryPanel->setFixedHeight(secondaryPanelHeight);
280

281
    auto startButton = new QPushButton(tr("START"));
282
    startButton->setFixedWidth(160);
283
    startButton->setFixedHeight(30);
284
    startButton->setStyleSheet(startButtonStyleSheet);
285
    connect(startButton, &QPushButton::clicked, this, &EditorWindow::startButtonClicked);
286

287
    durationLabel = new QLabel("00:00:00.00 - 00:00:00.00 - 00:00:00.00");
288
    durationLabel->setAlignment(Qt::AlignCenter);
289

290
    auto emptySpace = new QWidget();
291
    emptySpace->setFixedWidth(1);
292

293
    auto leftEmptySpace = new QWidget();
294
    leftEmptySpace->setFixedWidth(1);
295

296
    auto rightEmptySpace = new QWidget();
297
    rightEmptySpace->setFixedWidth(1);
298

299
    auto bottomSecondaryHorizontalPanelLayout = new QHBoxLayout(bottomSecondaryPanel);
300
    bottomSecondaryHorizontalPanelLayout->setContentsMargins(0, 0, 0, 0);
301
    bottomSecondaryHorizontalPanelLayout->addWidget(leftEmptySpace);
302
    bottomSecondaryHorizontalPanelLayout->addWidget(playbackButton);
303
    bottomSecondaryHorizontalPanelLayout->addWidget(stopButton);
304
    bottomSecondaryHorizontalPanelLayout->addWidget(emptySpace);
305
    bottomSecondaryHorizontalPanelLayout->addWidget(volumeSlider);
306
    bottomSecondaryHorizontalPanelLayout->addWidget(durationLabel);
307
    bottomSecondaryHorizontalPanelLayout->addWidget(startButton);
308
    bottomSecondaryHorizontalPanelLayout->addWidget(rightEmptySpace);
309

310
    videoWidget = new VideoWidget(this);
311
    videoWidget->setAspectRatioMode(Qt::KeepAspectRatio);
312
    videoWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
313
    connect(
314
        videoWidget,
315
        &VideoWidget::dragDidDropUrl,
316
        this,
317
        &EditorWindow::handleDropUrl
318
        );
319

320
    auto layout = new QVBoxLayout();
321
    layout->setContentsMargins(0, 0, 0, 0);
322
    layout->addWidget(videoWidget);
323

324
    timelineIndicator = new TimelineWidget(this, 100);
325

326
    connect(
327
        timelineIndicator,
328
        &TimelineWidget::startSliderDraggingStarted,
329
        this,
330
        &EditorWindow::startSliderDraggingStarted
331
        );
332

333
    connect(
334
        timelineIndicator,
335
        &TimelineWidget::startSliderDraggingFinished,
336
        this,
337
        &EditorWindow::startSliderDraggingFinished
338
        );
339

340
    connect(
341
        timelineIndicator,
342
        &TimelineWidget::playbackSliderDraggingStarted,
343
        this,
344
        &EditorWindow::playbackSliderDraggingStarted
345
        );
346

347
    connect(
348
        timelineIndicator,
349
        &TimelineWidget::playbackSliderDraggingFinished,
350
        this,
351
        &EditorWindow::playbackSliderDraggingFinished
352
        );
353

354
    connect(
355
        timelineIndicator,
356
        &TimelineWidget::endSliderDraggingStarted,
357
        this,
358
        &EditorWindow::endSliderDraggingStarted
359
        );
360

361
    connect(
362
        timelineIndicator,
363
        &TimelineWidget::endSliderDraggingFinished,
364
        this,
365
        &EditorWindow::endSliderDraggingFinished
366
        );
367

368
    connect(
369
        timelineIndicator,
370
        &TimelineWidget::startValueChanged,
371
        this,
372
        &EditorWindow::startPositionSliderMoved
373
        );
374

375
    connect(
376
        timelineIndicator,
377
        &TimelineWidget::playbackValueChanged,
378
        this,
379
        &EditorWindow::playbackSliderMoved
380
        );
381

382
    connect(
383
        timelineIndicator,
384
        &TimelineWidget::endValueChanged,
385
        this,
386
        &EditorWindow::endPositionSliderMoved
387
        );
388

389
    auto isPreviewChecked = settings.value(previewCheckboxStateKey, true).value<bool>();
390
    timelineIndicator->setFreeplayMode(!isPreviewChecked);
391

392
    auto horizontalIndicators = new QWidget();
393
    auto horizontalIndicatorsLayout = new QHBoxLayout(horizontalIndicators);
394
    horizontalIndicatorsLayout->setContentsMargins(0, 0, 0, 0);
395
    horizontalIndicatorsLayout->addWidget(timelineIndicator);
396
    layout->addWidget(horizontalIndicators);
397
    layout->addWidget(bottomSecondaryPanel);
398

399
    auto widget = new QWidget();
400
    widget->setLayout(layout);
401
    setCentralWidget(widget);
402

403
    QRect availableGeometry = QApplication::primaryScreen()->availableGeometry();
404
    auto width = availableGeometry.width() * 0.7038043478260869;
405
    auto height = width * 0.5625;
406

407
    resize(width, height);
408
}
409

410
void EditorWindow::playbackSliderDraggingStarted()
411
{
412
    auto state = player->playbackState();
413

414
    switch (state) {
415
    case QMediaPlayer::PlayingState:
416
    case QMediaPlayer::PausedState:
417
        playbackState = std::make_tuple(player->playbackState(), player->position());
418
        player->pause();
419
        return;
420
    case QMediaPlayer::StoppedState:
421
        return;
422
    }
423
}
424

425
void EditorWindow::playbackSliderDraggingFinished()
426
{
427
    auto state = std::get<0>(playbackState);
428

429
    switch (state) {
430
    case QMediaPlayer::PlayingState:
431
        player->play();
432
        break;
433
    case QMediaPlayer::PausedState:
434
        player->pause();
435
        break;
436
    default:
437
        break;
438
    }
439

440
    playbackState = std::make_tuple(QMediaPlayer::StoppedState, 0);
441
}
442

443
void EditorWindow::handleDropUrl(QUrl url)
444
{
445
    handleOpenFile(url);
446
}
447

448
void EditorWindow::startPositionSliderMoved(qint64 position) {
449
    if (!previewCheckboxAction->isChecked()) return;
450
    player->setPosition(position);
451
    this->updateDurationLabel();
452
}
453

454
void EditorWindow::endPositionSliderMoved(qint64 position) {
455
    if (!previewCheckboxAction->isChecked()) return;
456
    player->setPosition(position);
457
    this->updateDurationLabel();
458
}
459

460
void EditorWindow::initializePlayer()
461
{
462
    audioOutput = new QAudioOutput();
463
    player = new QMediaPlayer();
464
    player->setAudioOutput(audioOutput);
465

466
    connect(
467
        player,
468
        &QMediaPlayer::positionChanged,
469
        this,
470
        &EditorWindow::playbackChanged
471
        );
472
    connect(
473
        player,
474
        &QMediaPlayer::playbackStateChanged,
475
        this,
476
        &EditorWindow::playbackStateChanged
477
        );
478
    connect(
479
        player,
480
        &QMediaPlayer::errorOccurred,
481
        this,
482
        &EditorWindow::handlePlayerError
483
        );
484
    connect(
485
        player,
486
        &QMediaPlayer::durationChanged,
487
        this,
488
        &EditorWindow::durationLoaded
489
        );
490
    player->setVideoOutput(videoWidget);
491
}
492

493
void EditorWindow::durationLoaded(qint64 duration)
494
{
495
    fileDuration = duration;
496
    player->play();
497
    volumeChanged(volumeSlider->value());
498
    timelineIndicator->setMaximumValue(duration);
499
    timelineIndicator->setStartValue(0);
500
    timelineIndicator->setPlaybackValue(0);
501
    timelineIndicator->setEndValue(duration);
502
    updateWindowTitle();
503
}
504

505
void EditorWindow::playbackStateChanged(QMediaPlayer::PlaybackState state)
506
{
507
    updateButtons(state);
508

509
    if (previewCheckboxAction->isChecked()) {
510
        if (state == QMediaPlayer::StoppedState && userForcedStop == false) {
511
            player->play();
512
        }
513
    }
514
}
515

516
void EditorWindow::handleLeftKeyPress()
517
{
518
    timelineIndicator->moveLeft();
519
}
520

521
void EditorWindow::handleRightKeyPress()
522
{
523
    timelineIndicator->moveRight();
524
}
525

526
void EditorWindow::outputFormatCheckboxStateChanged(bool isChecked)
527
{
528
    auto sender = static_cast<QAction *>(QObject::sender());
529
    OutputFormat *outputFormat = qvariant_cast<OutputFormat *>(sender->data());
530
    outputFormat->isSelected = isChecked;
531
    auto key = outputFormatIsSelectedKey(outputFormat->identifier);
532
    settings.setValue(key, isChecked);
533
}
534

535
void EditorWindow::previewCheckboxStateChange(bool isChecked)
536
{
537
    timelineIndicator->setFreeplayMode(!isChecked);
538
    settings.setValue(previewCheckboxStateKey, isChecked);
539
    update();
540
}
541

542
void EditorWindow::playToggleButtonClicked() {
543
    userForcedStop = false;
544
    togglePlayback();
545
}
546

547
void EditorWindow::stopButtonClicked() {
548
    userForcedStop = true;
549
    player->stop();
550
}
551

552
void EditorWindow::togglePlayback() {
553
    userForcedStop = false;
554
    if (player->playbackState() == QMediaPlayer::PlayingState) {
555
        player->pause();
556
    }
557
    else {
558
        player->play();
559
    }
560
}
561

562
void EditorWindow::showAboutApplication()
563
{
564
    const auto copyright =
565
        tr("Copyright &copy; 2023 <a href=\"https://www.demensdeum.com/\">Ilia Prokhorov</a>")
566
            .arg(applicationName);
567
    const auto license =
568
        QStringLiteral("<a href=\"https://opensource.org/license/mit/\">MIT License</a>");
569
    const auto sourceCode =
570
        QStringLiteral("<a href=\"https://github.com/demensdeum/RaidenVideoRipper/\">https://github.com/demensdeum/RaidenVideoRipper</a>");
571

572
    QMessageBox::about(
573
        this,
574
        tr("About %1").arg(qApp->applicationName()),
575
        tr(
576
            "<h1>Version %1 %2</h1>"
577
            "<p><a href=\"%3\">%1</a> is an open-source project designed for video editing and format conversion. It's built using Qt 6 (Qt Creator) and allows you to trim and convert videos to MP4 or GIF formats.</p>"
578
            "<small><p>%4</p>"
579
            "<p>Licensed under the %5</p>"
580
            "<p>This program proudly uses the following projects:<ul>"
581
            "<li><a href=\"https://www.qt.io/\">Qt</a> application and UI framework</li>"
582
            "<li><a href=\"https://www.ffmpeg.org/\">FFmpeg</a> multimedia format and codec libraries</li>"
583
            "<li><a href=\"https://github.com/demensdeum/Dullahan-FFmpeg/\">Dullahan-FFmpeg</a> FFmpeg CLI as shared library </li>"
584
            "</ul></p>"
585
            "<p>The source code used to build this program can be downloaded from "
586
            "%6</p>"
587
            "This program is distributed in the hope that it will be useful, "
588
            "but WITHOUT ANY WARRANTY; without even the implied warranty of "
589
            "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</small>"
590
            )
591
            .arg(
592
                qApp->applicationName(),
593
                qApp->applicationVersion(),
594
                "https://github.com/demensdeum/RaidenVideoRipper",
595
                copyright,
596
                license,
597
                sourceCode
598
                )
599
        );
600
}
601

602
void EditorWindow::savePlaybackState()
603
{
604
    auto state = player->playbackState();
605
    switch (state) {
606
    case QMediaPlayer::PlayingState:
607
    case QMediaPlayer::PausedState:
608
        playbackState = std::make_tuple(player->playbackState(), player->position());
609
        player->pause();
610
        return;
611
    default:
612
        return;
613
    }
614
}
615

616
void EditorWindow::restorePlaybackState()
617
{
618
    auto state = std::get<0>(playbackState);
619
    auto position = std::get<1>(playbackState);
620

621
    if (
622
        position >= timelineIndicator->getStartValue()
623
        &&
624
        position <= timelineIndicator->getEndValue()
625
        )
626
    {
627
        player->setPosition(position);
628
    }
629
    else {
630
        player->setPosition(timelineIndicator->getStartValue());
631
    }
632
    switch (state) {
633
    case QMediaPlayer::PlayingState:
634
        player->play();
635
        break;
636
    case QMediaPlayer::PausedState:
637
        player->pause();
638
        break;
639
    default:
640
        break;
641
    }
642

643
    playbackState = std::make_tuple(QMediaPlayer::StoppedState, 0);
644
}
645

646
void EditorWindow::startSliderDraggingStarted()
647
{
648
    savePlaybackState();
649
}
650

651
void EditorWindow::startSliderDraggingFinished()
652
{
653
    restorePlaybackState();
654
}
655

656
void EditorWindow::endSliderDraggingStarted()
657
{
658
    savePlaybackState();
659
}
660

661
void EditorWindow::endSliderDraggingFinished()
662
{
663
    restorePlaybackState();
664
}
665

666
void EditorWindow::open()
667
{
668
    QFileDialog fileDialog(this);
669

670
    QString moviesLocation = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
671
    auto path = settings.value(previousWorkingPathKey, moviesLocation).value<QString>();
672

673
    fileDialog.setDirectory(path);
674

675
    if (fileDialog.exec() == QDialog::Accepted)
676
    {
677
        QUrl url = fileDialog.selectedUrls().at(0);
678
        handleOpenFile(url);
679
    }
680
}
681

682
void EditorWindow::handleOpenFile(QUrl url)
683
{
684
    switch (state) {
685
    case IDLE:
686
        break;
687
    case FILE_PROCESSING:
688
        raiseProgressWindowToUser();
689
        qDebug() << "Open file while in processing state, user nuts?";
690
        return;
691
    case CANCELLED:
692
    case EnumCount:
693
        qDebug() << "Wtf? Trying to use wrong state for file open!!!";
694
        return;
695
    }
696

697
    auto incomingFilepath = QDir::toNativeSeparators(url.toLocalFile());
698

699
    if (incomingFilepath == filePath) {
700
        qDebug() << "User trying to open same file, are they nuts?";
701
        return;
702
    }
703
    filePath = incomingFilepath;
704

705
    auto filePathDirectory = QFileInfo(filePath).absolutePath();
706
    settings.setValue(previousWorkingPathKey, filePathDirectory);
707
    fileDuration.reset();
708
    player->setSource(url);
709
}
710

711
void EditorWindow::updateWindowTitle()
712
{
713
    auto applicationTitle = QString(applicationName) + " " + QString(applicationVersion);
714
    auto title = applicationTitle;
715
    if (!filePath.isEmpty()) {
716
        title = QFileInfo(filePath).fileName() + " - " + applicationTitle;
717
    }
718
    this->setWindowTitle(title);
719
}
720

721
std::vector<OutputFormat> EditorWindow::getSelectedOutputFormats()
722
{
723
    std::vector<OutputFormat> selectedFormats;
724

725
    std::copy_if(outputFormats.begin(), outputFormats.end(), std::back_inserter(selectedFormats),
726
                 [](const OutputFormat& format) {
727
                     return format.isSelected;
728
                 });
729

730
    return selectedFormats;
731
}
732

733
void EditorWindow::raiseProgressWindowToUser()
734
{
735
    progressBarWindow.value()->raise();
736
    progressBarWindow.value()->activateWindow();
737
}
738

739
void EditorWindow::startButtonClicked()
740
{
741
    auto selectedOutputFormats = getSelectedOutputFormats();
742
    switch (state) {
743
    case IDLE:
744
        if (filePath.isEmpty()) {
745
            showAlert(tr("WUT!"), tr("Open file first!"));
746
            return;
747
        }
748
        else if (selectedOutputFormats.empty())
749
        {
750
            showAlert(tr("WUT!"), tr("Select output formats checkboxes first!"));
751
            return;
752
        }
753
        break;
754

755
    case FILE_PROCESSING:
756
        raiseProgressWindowToUser();
757
        qDebug() << "Start pressed in file processing state, user nuts?";
758
        return;
759

760
    case CANCELLED:
761
        qDebug() << "Start pressed in cancelled state, wtf?";
762
        return;
763

764
    case EnumCount:
765
        break;
766
    }
767

768
    for (auto&& outputFormat : selectedOutputFormats) {
769
        currentOutputFormats.push(outputFormat);
770
    }
771

772
    state = FILE_PROCESSING;
773

774
    cut();
775
}
776

777
void EditorWindow::volumeChanged(qint64 position)
778
{
779
    auto volume = static_cast<float>(position) / static_cast<float>(volumeSlider->maximum());
780
    if (audioOutput) {
781
        audioOutput->setVolume(volume);
782
    }
783
    settings.setValue(volumeSettingsKey, position);
784
}
785

786
void EditorWindow::showProgressbarWindow(QString text)
787
{
788
    if (!fileDuration.has_value()) {
789
        qDebug() << "showProgressbar - no duration!";
790
        return;
791
    }
792
    progressBarWindow = new ProgressBarWindow(text);
793
    connect(
794
        progressBarWindow.value(),
795
        &ProgressBarWindow::cancelButtonPressed,
796
        this,
797
        &EditorWindow::cancelInProgress
798
        );
799
    progressBarWindow.value()->show();
800

801
    if (videoProcessorProgressPoller.has_value()) {
802
        videoProcessorProgressPoller.value()->stop();
803
    }
804
    videoProcessorProgressPoller = new VideoProcessorProgressPoller(fileDuration.value());
805
    connect(
806
        videoProcessorProgressPoller.value(),
807
        &VideoProcessorProgressPoller::didPollProgress,
808
        this,
809
        &EditorWindow::didPollProgress
810
        );
811
}
812

813
void EditorWindow::cut()
814
{
815
    if (!fileDuration.has_value()) {
816
        qDebug() << "No file duration";
817
        return;
818
    }
819

820
    if (!currentOutputFormats.empty()) {
821
        auto front = currentOutputFormats.front();
822
        currentOutputFormat = new OutputFormat(
823
            front.identifier,
824
            front.title,
825
            front.extension,
826
            front.isSelected
827
        );
828
        currentOutputFormats.pop();
829
    }
830
    else {
831
        qDebug() << "Cut called with empty currentOutputFormats, wtf?";
832
        return;
833
    }
834

835
    int startPosition = timelineIndicator->getStartValue();
836
    int endPosition = timelineIndicator->getEndValue();
837

838
    if (endPosition < startPosition)
839
    {
840
        state = IDLE;
841
        return;
842
    }
843

844
    QString outputVideoPath;
845
    switch (state)
846
    {
847
    case IDLE:
848
        qDebug() << "Internal error, IDLE state!";
849
        return;
850

851
    case FILE_PROCESSING:
852
        outputVideoPath = filePath + outputFileSuffix + "." + currentOutputFormat.value()->extension;
853
        break;
854

855
    case CANCELLED:
856
        qDebug() << "Cut started in cancelled mode, wtf?";
857
        return;
858

859
    case EnumCount:
860
        qDebug() << "State is EnumCount, the hell?";
861
        return;
862
    }
863

864
    auto stateString = RaidenVideoRipper::Utils::capitalized(
865
        currentOutputFormat.value()->title
866
        );
867
    QString text = tr("Cutting ") + stateString + "...";
868
    showProgressbarWindow(text);
869

870
    videoProcessor = new VideoProcessor(
871
        startPosition,
872
        endPosition,
873
        filePath,
874
        outputVideoPath
875
        );
876
    videoProcessor.value()->setAutoDelete(true);
877

878
    connect(
879
        videoProcessor.value(),
880
        &VideoProcessor::videoProcessingDidFinish,
881
        this,
882
        &EditorWindow::convertingDidFinish
883
        );
884
    threadPool.start(videoProcessor.value());
885
}
886

887
void EditorWindow::didPollProgress(int progress)
888
{
889
    progressBarWindow.value()->setProgress(progress);
890
}
891

892
void EditorWindow::showAlert(const QString &title, const QString &message)
893
{
894
    QMessageBox messageBox;
895
    messageBox.setWindowTitle(title);
896
    messageBox.setText(message);
897
    messageBox.setIcon(QMessageBox::Information);
898
    messageBox.exec();
899
}
900

901
void EditorWindow::processNextOutputFormatOrFinish()
902
{
903
    if (!currentOutputFormats.empty()) {
904
        cut();
905
    }
906
    else {
907
        switch (state) {
908
        case IDLE:
909
            return;
910
        case FILE_PROCESSING:
911
            state = IDLE;
912
            showDonateWindowIfNeeded();
913
            return;
914
        case CANCELLED:
915
            state = IDLE;
916
            return;
917
        case EnumCount:
918
            return;
919
        }
920
    }
921
}
922

923
void EditorWindow::convertingDidFinish(bool result)
924
{
925
    videoProcessorProgressPoller.value()->stop();
926
    progressBarWindow.value()->close();
927

928
    qDebug("Process Finished");
929

930
    auto isSuccess = result == 0;
931

932
    switch (state) {
933
    case IDLE:
934
        break;
935
    case FILE_PROCESSING:
936
        if (isSuccess) {
937
            processNextOutputFormatOrFinish();
938
        }
939
        else {
940
            state = IDLE;
941
            showAlert(
942
                tr("Uhh!"),
943
                tr("Error while cutting! Result code: %1")
944
                    .arg(
945
                        QString::number(result)
946
                        )
947
                );
948
        }
949
        break;
950

951
    case CANCELLED:
952
        processNextOutputFormatOrFinish();
953
        break;
954

955
    case EnumCount:
956
        break;
957
    }
958
}
959

960
void EditorWindow::playbackSliderMoved(qint64 position)
961
{
962
    player->setPosition(position);
963
    this->updateDurationLabel();
964
}
965

966
void EditorWindow::playbackChanged(qint64 position)
967
{
968
    auto sliderUpdate = [this] (int position) {
969
        timelineIndicator->blockSignals(true);
970
        timelineIndicator->setPlaybackValue(position);
971
        timelineIndicator->blockSignals(false);
972
    };
973

974
    if (player->isPlaying() && this->previewCheckboxAction->isChecked()) {
975
        auto startPosition = timelineIndicator->getStartValue();
976
        auto endPosition = timelineIndicator->getEndValue();
977
        if (position > endPosition) {
978
            player->setPosition(startPosition);
979
        }
980
        else if (position < startPosition) {
981
            player->setPosition(startPosition);
982
        }
983
    }
984
    sliderUpdate(player->position());
985
    updateDurationLabel();
986
}
987

988
void EditorWindow::ensureStopped()
989
{
990
    if (player->playbackState() != QMediaPlayer::StoppedState)
991
    {
992
        player->stop();
993
    }
994
}
995

996
void EditorWindow::updateButtons(QMediaPlayer::PlaybackState state)
997
{
998
    if (player->isPlaying()) {
999
        playbackButton->setIcon(pauseIcon);
1000
    }
1001
    else {
1002
        playbackButton->setIcon(playIcon);
1003
    }
1004
    stopButton->setEnabled(state != QMediaPlayer::StoppedState);
1005
}
1006

1007
void EditorWindow::showErrorMessage([[maybe_unused]]const QString &message)
1008
{
1009
    auto previousErrorFilePath = std::get<0>(previousFileAndErrorState);
1010
    auto previousErrorText = std::get<1>(previousFileAndErrorState);
1011
    if (
1012
        previousErrorFilePath == filePath
1013
        &&
1014
        previousErrorText == message
1015
        )
1016
    {
1017
        return;
1018
    }
1019
    previousFileAndErrorState = std::make_tuple(filePath, message);
1020
    showAlert(tr("Uhh!"), message);
1021
}
1022

1023
void EditorWindow::handlePlayerError(QMediaPlayer::Error error, const QString &errorString)
1024
{
1025
    Q_UNUSED(error);
1026
    showErrorMessage(errorString);
1027
}
1028

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.