#include "exportdialog.h" #include "ui_exportdialog.h" #include #include #include #include #include #include #include "debug.h" #include "panels/panels.h" #include "panels/viewer.h" #include "panels/timeline.h" #include "ui/viewerwidget.h" #include "project/sequence.h" #include "io/exportthread.h" #include "playback/playback.h" #include "mainwindow.h" extern "C" { #include } enum ExportFormats { FORMAT_3GPP, FORMAT_AIFF, FORMAT_APNG, FORMAT_AVI, FORMAT_DNXHD, FORMAT_AC3, FORMAT_FLV, FORMAT_GIF, FORMAT_IMG, FORMAT_MP2, FORMAT_MP3, FORMAT_MPEG1, FORMAT_MPEG2, FORMAT_MPEG4, FORMAT_MPEGTS, FORMAT_MKV, FORMAT_OGG, FORMAT_MOV, FORMAT_WAV, FORMAT_WEBM, FORMAT_WMV, FORMAT_SIZE }; ExportDialog::ExportDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ExportDialog) { ui->setupUi(this); ui->rangeCombobox->setCurrentIndex(0); if (sequence->using_workarea) { ui->rangeCombobox->setEnabled(sequence->using_workarea); ui->rangeCombobox->setCurrentIndex(1); } format_strings.resize(FORMAT_SIZE); format_strings[FORMAT_3GPP] = "3GPP"; format_strings[FORMAT_AIFF] = "AIFF"; format_strings[FORMAT_APNG] = "Animated PNG"; format_strings[FORMAT_AVI] = "AVI"; format_strings[FORMAT_DNXHD] = "DNxHD"; format_strings[FORMAT_AC3] = "Dolby Digital (AC3)"; format_strings[FORMAT_FLV] = "FLV"; format_strings[FORMAT_GIF] = "GIF"; format_strings[FORMAT_IMG] = "Image Sequence"; format_strings[FORMAT_MP2] = "MP2 Audio"; format_strings[FORMAT_MP3] = "MP3 Audio"; format_strings[FORMAT_MPEG1] = "MPEG-1 Video"; format_strings[FORMAT_MPEG2] = "MPEG-2 Video"; format_strings[FORMAT_MPEG4] = "MPEG-4 Video"; format_strings[FORMAT_MPEGTS] = "MPEG-TS"; format_strings[FORMAT_MKV] = "Matroska MKV"; format_strings[FORMAT_OGG] = "Ogg"; format_strings[FORMAT_MOV] = "QuickTime MOV"; format_strings[FORMAT_WAV] = "WAVE Audio"; format_strings[FORMAT_WEBM] = "WebM"; format_strings[FORMAT_WMV] = "Windows Media"; for (int i=0;iformatCombobox->addItem(format_strings[i]); } ui->formatCombobox->setCurrentIndex(FORMAT_MPEG4); ui->widthSpinbox->setValue(sequence->width); ui->heightSpinbox->setValue(sequence->height); ui->samplingRateSpinbox->setValue(sequence->audio_frequency); ui->framerateSpinbox->setValue(sequence->frame_rate); } ExportDialog::~ExportDialog() { delete ui; } void ExportDialog::on_formatCombobox_currentIndexChanged(int index) { format_vcodecs.clear(); format_acodecs.clear(); ui->vcodecCombobox->clear(); ui->acodecCombobox->clear(); int default_vcodec = 0; int default_acodec = 0; switch (index) { case FORMAT_3GPP: format_vcodecs.append(AV_CODEC_ID_MPEG4); format_vcodecs.append(AV_CODEC_ID_H264); format_acodecs.append(AV_CODEC_ID_AAC); default_vcodec = 1; break; case FORMAT_AIFF: format_acodecs.append(AV_CODEC_ID_PCM_S16LE); break; case FORMAT_APNG: format_vcodecs.append(AV_CODEC_ID_APNG); break; case FORMAT_AVI: format_vcodecs.append(AV_CODEC_ID_H264); format_vcodecs.append(AV_CODEC_ID_MPEG4); format_vcodecs.append(AV_CODEC_ID_MJPEG); format_vcodecs.append(AV_CODEC_ID_MSVIDEO1); format_vcodecs.append(AV_CODEC_ID_RAWVIDEO); format_vcodecs.append(AV_CODEC_ID_HUFFYUV); format_vcodecs.append(AV_CODEC_ID_DVVIDEO); format_acodecs.append(AV_CODEC_ID_AAC); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_FLAC); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); default_vcodec = 3; default_acodec = 5; break; case FORMAT_DNXHD: format_vcodecs.append(AV_CODEC_ID_DNXHD); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); break; case FORMAT_AC3: format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_EAC3); break; case FORMAT_FLV: format_vcodecs.append(AV_CODEC_ID_FLV1); format_acodecs.append(AV_CODEC_ID_MP3); break; case FORMAT_GIF: format_vcodecs.append(AV_CODEC_ID_GIF); break; case FORMAT_IMG: format_vcodecs.append(AV_CODEC_ID_BMP); format_vcodecs.append(AV_CODEC_ID_MJPEG); format_vcodecs.append(AV_CODEC_ID_JPEG2000); format_vcodecs.append(AV_CODEC_ID_PSD); format_vcodecs.append(AV_CODEC_ID_PNG); format_vcodecs.append(AV_CODEC_ID_TIFF); default_vcodec = 4; break; case FORMAT_MP2: format_acodecs.append(AV_CODEC_ID_MP2); break; case FORMAT_MP3: format_acodecs.append(AV_CODEC_ID_MP3); break; case FORMAT_MPEG1: format_vcodecs.append(AV_CODEC_ID_MPEG1VIDEO); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); default_acodec = 1; break; case FORMAT_MPEG2: format_vcodecs.append(AV_CODEC_ID_MPEG2VIDEO); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); default_acodec = 1; break; case FORMAT_MPEG4: format_vcodecs.append(AV_CODEC_ID_MPEG4); format_vcodecs.append(AV_CODEC_ID_H264); format_acodecs.append(AV_CODEC_ID_AAC); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); default_vcodec = 1; break; case FORMAT_MPEGTS: format_vcodecs.append(AV_CODEC_ID_MPEG2VIDEO); format_acodecs.append(AV_CODEC_ID_AAC); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); default_acodec = 2; break; case FORMAT_MKV: format_vcodecs.append(AV_CODEC_ID_MPEG4); format_vcodecs.append(AV_CODEC_ID_H264); format_acodecs.append(AV_CODEC_ID_AAC); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_EAC3); format_acodecs.append(AV_CODEC_ID_FLAC); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); format_acodecs.append(AV_CODEC_ID_OPUS); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); format_acodecs.append(AV_CODEC_ID_VORBIS); format_acodecs.append(AV_CODEC_ID_WAVPACK); format_acodecs.append(AV_CODEC_ID_WMAV1); format_acodecs.append(AV_CODEC_ID_WMAV2); default_vcodec = 1; break; case FORMAT_OGG: format_vcodecs.append(AV_CODEC_ID_THEORA); format_acodecs.append(AV_CODEC_ID_OPUS); format_acodecs.append(AV_CODEC_ID_VORBIS); default_acodec = 1; break; case FORMAT_MOV: format_vcodecs.append(AV_CODEC_ID_QTRLE); format_vcodecs.append(AV_CODEC_ID_MPEG4); format_vcodecs.append(AV_CODEC_ID_H264); format_vcodecs.append(AV_CODEC_ID_MJPEG); format_vcodecs.append(AV_CODEC_ID_PRORES); format_acodecs.append(AV_CODEC_ID_AAC); format_acodecs.append(AV_CODEC_ID_AC3); format_acodecs.append(AV_CODEC_ID_MP2); format_acodecs.append(AV_CODEC_ID_MP3); format_acodecs.append(AV_CODEC_ID_PCM_S16LE); default_vcodec = 2; break; case FORMAT_WAV: format_acodecs.append(AV_CODEC_ID_PCM_S16LE); break; case FORMAT_WEBM: format_vcodecs.append(AV_CODEC_ID_VP8); format_vcodecs.append(AV_CODEC_ID_VP9); format_acodecs.append(AV_CODEC_ID_OPUS); format_acodecs.append(AV_CODEC_ID_VORBIS); default_vcodec = 1; break; case FORMAT_WMV: format_vcodecs.append(AV_CODEC_ID_WMV1); format_vcodecs.append(AV_CODEC_ID_WMV2); format_acodecs.append(AV_CODEC_ID_WMAV1); format_acodecs.append(AV_CODEC_ID_WMAV2); default_vcodec = 1; default_acodec = 1; break; default: dout << "[ERROR] Invalid format selection - this is a bug, please inform the developers"; } AVCodec* codec_info; for (int i=0;ivcodecCombobox->addItem("NULL"); } else { ui->vcodecCombobox->addItem(codec_info->long_name); } } for (int i=0;iacodecCombobox->addItem("NULL"); } else { ui->acodecCombobox->addItem(codec_info->long_name); } } ui->vcodecCombobox->setCurrentIndex(default_vcodec); ui->acodecCombobox->setCurrentIndex(default_acodec); bool video_enabled = format_vcodecs.size() != 0; bool audio_enabled = format_acodecs.size() != 0; ui->videoGroupbox->setChecked(video_enabled); ui->audioGroupbox->setChecked(audio_enabled); ui->videoGroupbox->setEnabled(video_enabled); ui->audioGroupbox->setEnabled(audio_enabled); } void ExportDialog::on_pushButton_2_clicked() { close(); } void ExportDialog::render_thread_finished() { if (ui->progressBar->value() < 100 && !cancelled) { QMessageBox::critical(this, "Export Failed", "Export failed - " + export_error, QMessageBox::Ok); } prep_ui_for_render(false); panel_sequence_viewer->viewer_widget->makeCurrent(); panel_sequence_viewer->viewer_widget->initializeGL(); update_ui(false); if (ui->progressBar->value() == 100) close(); } void ExportDialog::prep_ui_for_render(bool r) { ui->pushButton->setEnabled(!r); ui->pushButton_2->setEnabled(!r); ui->renderCancel->setEnabled(r); } void ExportDialog::on_pushButton_clicked() { if (ui->widthSpinbox->value()%2 == 1 || ui->heightSpinbox->value()%2 == 1) { QMessageBox::critical(this, "Invalid dimensions", "Export width and height must both be even numbers/divisible by 2.", QMessageBox::Ok); return; } QString ext; switch (ui->formatCombobox->currentIndex()) { case FORMAT_3GPP: ext = "3gp"; break; case FORMAT_AIFF: ext = "aiff"; break; case FORMAT_APNG: ext = "apng"; break; case FORMAT_AVI: ext = "avi"; break; case FORMAT_DNXHD: ext = "mxf"; break; case FORMAT_AC3: ext = "ac3"; break; case FORMAT_FLV: ext = "flv"; break; case FORMAT_GIF: ext = "gif"; break; case FORMAT_IMG: switch (format_vcodecs.at(ui->vcodecCombobox->currentIndex())) { case AV_CODEC_ID_BMP: ext = "bmp"; break; case AV_CODEC_ID_MJPEG: ext = "jpg"; break; case AV_CODEC_ID_JPEG2000: ext = "jp2"; break; case AV_CODEC_ID_PSD: ext = "psd"; break; case AV_CODEC_ID_PNG: ext = "png"; break; case AV_CODEC_ID_TIFF: ext = "tif"; break; default: dout << "[ERROR] Invalid codec selection for an image sequence"; QMessageBox::critical(this, "Invalid codec", "Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers.", QMessageBox::Ok); return; } break; case FORMAT_MP3: ext = "mp3"; break; case FORMAT_MPEG1: if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) { ext = "m1v"; } else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) { ext = "m1a"; } else { ext = "mpg"; } break; case FORMAT_MPEG2: if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) { ext = "m2v"; } else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) { ext = "m2a"; } else { ext = "mpg"; } break; case FORMAT_MPEG4: if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) { ext = "m4v"; } else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) { ext = "m4a"; } else { ext = "mp4"; } break; case FORMAT_MPEGTS: ext = "ts"; break; case FORMAT_MKV: if (!ui->videoGroupbox->isChecked()) { ext = "mka"; } else { ext = "mkv"; } break; case FORMAT_OGG: ext = "ogg"; break; case FORMAT_MOV: ext = "mov"; break; case FORMAT_WAV: ext = "wav"; break; case FORMAT_WEBM: ext = "webm"; break; case FORMAT_WMV: if (ui->videoGroupbox->isChecked()) { ext = "wmv"; } else { ext = "wma"; } break; default: dout << "[ERROR] Invalid format - this is a bug, please inform the developers"; QMessageBox::critical(this, "Invalid format", "Couldn't determine output format. This is a bug, please contact the developers.", QMessageBox::Ok); return; } QString filename = QFileDialog::getSaveFileName(this, "Export Media", "", format_strings[ui->formatCombobox->currentIndex()] + " (*." + ext + ")"); if (!filename.isEmpty()) { if (!filename.endsWith("." + ext, Qt::CaseInsensitive)) { filename += "." + ext; } if (ui->formatCombobox->currentIndex() == FORMAT_IMG) { int ext_location = filename.lastIndexOf('.'); if (ext_location > filename.lastIndexOf('/')) { filename.insert(ext_location, 'd'); filename.insert(ext_location, '5'); filename.insert(ext_location, '0'); filename.insert(ext_location, '%'); } } et = new ExportThread(); connect(et, SIGNAL(finished()), et, SLOT(deleteLater())); connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished())); connect(et, SIGNAL(progress_changed(int, qint64)), this, SLOT(update_progress_bar(int, qint64))); closeActiveClips(sequence, true); mainWindow->autorecover_interval(); rendering = true; panel_sequence_viewer->viewer_widget->context()->doneCurrent(); panel_sequence_viewer->viewer_widget->context()->moveToThread(et); prep_ui_for_render(true); et->filename = filename; et->video_enabled = ui->videoGroupbox->isChecked(); if (et->video_enabled) { et->video_codec = format_vcodecs.at(ui->vcodecCombobox->currentIndex()); et->video_width = ui->widthSpinbox->value(); et->video_height = ui->heightSpinbox->value(); et->video_frame_rate = ui->framerateSpinbox->value(); et->video_compression_type = ui->compressionTypeCombobox->currentData().toInt(); et->video_bitrate = ui->videobitrateSpinbox->value(); } et->audio_enabled = ui->audioGroupbox->isChecked(); if (et->audio_enabled) { et->audio_codec = format_acodecs.at(ui->acodecCombobox->currentIndex()); et->audio_sampling_rate = ui->samplingRateSpinbox->value(); et->audio_bitrate = ui->audiobitrateSpinbox->value(); } et->start_frame = 0; et->end_frame = sequence->getEndFrame(); // entire sequence if (ui->rangeCombobox->currentIndex() == 1) { et->start_frame = qMax(sequence->workarea_in, et->start_frame); et->end_frame = qMin(sequence->workarea_out, et->end_frame); } et->ed = this; cancelled = false; et->start(); } } void ExportDialog::update_progress_bar(int value, qint64 remaining_ms) { // convert ms to H:MM:SS int seconds = qFloor(remaining_ms*0.001)%60; int minutes = qFloor(remaining_ms/60000)%60; int hours = qFloor(remaining_ms/3600000); ui->progressBar->setFormat("%p% (ETA: " + QString::number(hours) + ":" + QString::number(minutes).rightJustified(2, '0') + ":" + QString::number(seconds).rightJustified(2, '0') + ")"); ui->progressBar->setValue(value); } void ExportDialog::on_renderCancel_clicked() { panel_sequence_viewer->viewer_widget->force_quit = true; et->continueEncode = false; cancelled = true; } void ExportDialog::on_vcodecCombobox_currentIndexChanged(int index) { ui->compressionTypeCombobox->clear(); if ((format_vcodecs.size() > 0 && format_vcodecs.at(index) == AV_CODEC_ID_H264)) { ui->compressionTypeCombobox->setEnabled(true); ui->compressionTypeCombobox->addItem("Quality-based (Constant Rate Factor)", COMPRESSION_TYPE_CFR); // ui->compressionTypeCombobox->addItem("File size-based (Two-Pass)", COMPRESSION_TYPE_TARGETSIZE); // ui->compressionTypeCombobox->addItem("Average bitrate (Two-Pass)", COMPRESSION_TYPE_TARGETBR); } else { ui->compressionTypeCombobox->addItem("Constant Bitrate", COMPRESSION_TYPE_CBR); ui->compressionTypeCombobox->setCurrentIndex(0); ui->compressionTypeCombobox->setEnabled(false); } } void ExportDialog::on_compressionTypeCombobox_currentIndexChanged(int) { ui->videobitrateSpinbox->setToolTip(""); ui->videobitrateSpinbox->setMinimum(0); ui->videobitrateSpinbox->setMaximum(99.99); switch (ui->compressionTypeCombobox->currentData().toInt()) { case COMPRESSION_TYPE_CBR: case COMPRESSION_TYPE_TARGETBR: ui->videoBitrateLabel->setText("Bitrate (Mbps):"); ui->videobitrateSpinbox->setValue(qMax(0.5, (double) qRound((0.01528 * sequence->height) - 4.5))); break; case COMPRESSION_TYPE_CFR: ui->videoBitrateLabel->setText("Quality (CRF):"); ui->videobitrateSpinbox->setValue(36); ui->videobitrateSpinbox->setMaximum(51); ui->videobitrateSpinbox->setToolTip("Quality Factor:\n\n0 = lossless\n17-18 = visually lossless (compressed, but unnoticeable)\n23 = high quality\n51 = lowest quality possible"); break; case COMPRESSION_TYPE_TARGETSIZE: ui->videoBitrateLabel->setText("Target File Size (MB):"); ui->videobitrateSpinbox->setValue(100); break; } }