diff --git a/include/ffmpegwrapper.h b/include/ffmpegwrapper.h index da1d72f..c95ef6a 100644 --- a/include/ffmpegwrapper.h +++ b/include/ffmpegwrapper.h @@ -9,16 +9,25 @@ struct Video; class QTime; class QString; +struct ExportSettings { + double VideoMBitRate; + double framerate; + bool trimOnly; + bool vertical; + bool audioOnly; + bool videoOnly; +}; + class FFMPEGWrapper { public: FFMPEGWrapper(); - bool exportFile(Video const & video, TrimSettings const & settings, double MBitRate, Resolution const & res, CodecConfig const & codec, int Framerate, bool trimOnly, bool vertical); + bool exportFile(Video const & video, TrimSettings const & settings, Resolution const & res, CodecConfig const & codec, ExportSettings const & exports); private: QString getFileName(QString const & filePath); - QString getExportFileName(QString const & fileName); + QString getExportFileName(QString const & fileName, bool audioOnly, const QString & audioFileType); QString getPath(QString const & filePath); - QString getExportFilePath(QString const & filePath); + QString getExportFilePath(QString const& filePath, bool audioOnly, const QString & audioFileType); QString getTrimString(QTime const & start, QTime const & end, Video const & video); QString getMBitRateString(double MBitRate); @@ -26,7 +35,7 @@ class FFMPEGWrapper QString getScaleFilterString(Resolution const & res, Resolution const & vidRes, int HardwareAcceleration, bool vertical); QString getVideoCodecString(CodecConfig const & codec, bool trimOnly); - QString getAudioCodecString(bool canCopy); + QString getAudioCodecString(const Video& video, const TrimSettings& settings, const CodecConfig& codec, const ExportSettings& exports); QString getHardwareAccelerationString(int HardwareAcceleration, bool usesScaleFilter); QString getInputFileString(QString const & filePath); QString getOutputFileString(QString const & filePath); diff --git a/include/filedropwidget.h b/include/filedropwidget.h index 2a99f75..1332bca 100644 --- a/include/filedropwidget.h +++ b/include/filedropwidget.h @@ -10,7 +10,8 @@ class QMimeData; namespace acceptedFileTypes { QString const MP4("mp4"); - QString const ALL[1] = { MP4 }; + QString const MP3("mp3"); + QString const ALL[2] = { MP4, MP3 }; } class FileDropWidget : public QLabel diff --git a/include/structs.h b/include/structs.h index 97b56a1..28ff5c4 100644 --- a/include/structs.h +++ b/include/structs.h @@ -9,12 +9,6 @@ struct Resolution { int height; }; -//struct Codec { -// std::string defaultName; -// std::string NVIDIA; -// std::string AMD; -//}; - struct TrimSettings { QTime start; QTime end; @@ -76,55 +70,87 @@ float const FRAMERATES[] = { 240 }; -enum CODEC_IDX { +int const AUDIO_BITRATES[] = { + 0, + 320, + 256, + 192, + 160, + 128, + 64 +}; + +enum VIDEO_CODEC { H264, HEVC, - UNSUPPORTED + UNSUPPORTED_VIDEO +}; + +enum AUDIO_CODEC { + AAC, + MP3, + UNSUPPORTED_AUDIO }; -QString const CODEC_IDX_STRINGS[] = { +QString const VIDEO_CODEC_STRINGS[] = { "H264", "HEVC", "Unsupported" }; +QString const AUDIO_CODEC_STRINGS[]{ + "AAC", + "MP3", + "Unsupported" +}; + +QString const AUDIO_ENCODER_STRINGS[]{ + "aac", + "libmp3lame", + "Unsupported" +}; + struct CodecConfig { - int id; + int videoCodec; QString name; HARDWARE_ACCELERATION hw_acceleration; - QString encoderName; + QString videoEncoderName; std::vector profiles; int profile; //also default profile int mainProfile; std::vector extraOptions; + int audioBitrateIdx; + int audioCodec; + QString audioCodecName; + QString audioEncoderName; }; CodecConfig const DefaultCodecs[2][3] = { { { - CODEC_IDX::H264, CODEC_IDX_STRINGS[CODEC_IDX::H264], HARDWARE_ACCELERATION::NONE, "libx264", {"Baseline", "Main", "High", "High10", "High444"}, 2, 1, {"", "", "", "", " -pix_fmt yuv444p"} + VIDEO_CODEC::H264, VIDEO_CODEC_STRINGS[VIDEO_CODEC::H264], HARDWARE_ACCELERATION::NONE, "libx264", {"Baseline", "Main", "High", "High10", "High444"}, 2, 1, {"", "", "", "", " -pix_fmt yuv444p"}, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] }, { - CODEC_IDX::H264, CODEC_IDX_STRINGS[CODEC_IDX::H264], HARDWARE_ACCELERATION::NVIDIA, "h264_nvenc", {"Baseline", "Main", "High", "High444p"}, 2, 1, {"", "", "", " -pix_fmt yuv444p"} + VIDEO_CODEC::H264, VIDEO_CODEC_STRINGS[VIDEO_CODEC::H264], HARDWARE_ACCELERATION::NVIDIA, "h264_nvenc", {"Baseline", "Main", "High", "High444p"}, 2, 1, {"", "", "", " -pix_fmt yuv444p"}, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] }, { - CODEC_IDX::H264, CODEC_IDX_STRINGS[CODEC_IDX::H264], HARDWARE_ACCELERATION::AMD, "h264_amf", {"Constrained_Baseline", "Main", "High", "Constrained_High"}, 2, 1, {" -quality:v 2"} + VIDEO_CODEC::H264, VIDEO_CODEC_STRINGS[VIDEO_CODEC::H264], HARDWARE_ACCELERATION::AMD, "h264_amf", {"Constrained_Baseline", "Main", "High", "Constrained_High"}, 2, 1, {" -quality:v 2"}, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] } }, { { - CODEC_IDX::HEVC, CODEC_IDX_STRINGS[CODEC_IDX::HEVC], HARDWARE_ACCELERATION::NONE, "libx265", {"Main", "Main10", "Main12"}, 0, 0, {""} + VIDEO_CODEC::HEVC, VIDEO_CODEC_STRINGS[VIDEO_CODEC::HEVC], HARDWARE_ACCELERATION::NONE, "libx265", {"Main", "Main10", "Main12"}, 0, 0, {""}, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] }, { - CODEC_IDX::HEVC, CODEC_IDX_STRINGS[CODEC_IDX::HEVC], HARDWARE_ACCELERATION::NVIDIA, "hevc_nvenc", {"Main", "Main10", "Rext"}, 0, 0, {""} + VIDEO_CODEC::HEVC, VIDEO_CODEC_STRINGS[VIDEO_CODEC::HEVC], HARDWARE_ACCELERATION::NVIDIA, "hevc_nvenc", {"Main", "Main10", "Rext"}, 0, 0, {""}, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] }, { - CODEC_IDX::HEVC, CODEC_IDX_STRINGS[CODEC_IDX::HEVC], HARDWARE_ACCELERATION::AMD, "hevc_amf", {"Main"}, 0, 0, {" -quality:v 0"} //TODO: test AMD codec + VIDEO_CODEC::HEVC, VIDEO_CODEC_STRINGS[VIDEO_CODEC::HEVC], HARDWARE_ACCELERATION::AMD, "hevc_amf", {"Main"}, 0, 0, {" -quality:v 0"} /* TODO: test AMD codec */, 0, AUDIO_CODEC::AAC, AUDIO_CODEC_STRINGS[AUDIO_CODEC::AAC], AUDIO_ENCODER_STRINGS[AUDIO_CODEC::AAC] } } }; -//CodecConfig getDefaultCodec(CODEC_IDX codec, HARDWARE_ACCELERATION acc = HARDWARE_ACCELERATION::NONE) { +//CodecConfig getDefaultCodec(VIDEO_CODEC codec, HARDWARE_ACCELERATION acc = HARDWARE_ACCELERATION::NONE) { // return DefaultCodecs[codec][acc]; //} @@ -135,4 +161,6 @@ struct Video { double framerate; CodecConfig codec; double bitrate; + double audioBitrate; + QTime audioLength; }; \ No newline at end of file diff --git a/include/videolowwindow.h b/include/videolowwindow.h index 701dc24..ad7f54d 100644 --- a/include/videolowwindow.h +++ b/include/videolowwindow.h @@ -38,6 +38,8 @@ private slots: void gotCutInformation(QTime start, QTime end, bool cancelled); void startTimeEdited(); void endTimeEdited(); + void uncheckRemoveAudio(bool isAudioOnlyChecked); + void uncheckAudioOnly(bool isRemoveAudioChecked); public slots: void newVideoFile(Video const & vid); @@ -52,6 +54,7 @@ public slots: void quickH264(double MBitRate); void quickHEVC(double MBitRate); void handleExportExitCode(bool success, bool hardwareAcc); + void setQuickExportsEnabled(bool enabled); TrimSettings getTrimSettings(); FFMPEGWrapper *ffmpeg = nullptr; diff --git a/src/ffmpegwrapper.cpp b/src/ffmpegwrapper.cpp index c1bf10a..ce71db2 100644 --- a/src/ffmpegwrapper.cpp +++ b/src/ffmpegwrapper.cpp @@ -18,10 +18,10 @@ FFMPEGWrapper::FFMPEGWrapper() } } -bool FFMPEGWrapper::exportFile(const Video& video, const TrimSettings& settings, double MBitRate, const Resolution& res, const CodecConfig& codec, int Framerate, bool trimOnly, bool vertical) +bool FFMPEGWrapper::exportFile(const Video& video, const TrimSettings& settings, const Resolution& res, const CodecConfig& codec, const ExportSettings & exports) { const QString& filePath = video.filePath; - QString expFilePath = getExportFilePath(filePath); + QString expFilePath = getExportFilePath(filePath, exports.audioOnly, codec.audioCodecName); std::cout << "Export File Path: " << expFilePath.toStdString().c_str() << std::endl; QString cmd = "ffmpeg -y "; //options part 1 @@ -31,18 +31,25 @@ bool FFMPEGWrapper::exportFile(const Video& video, const TrimSettings& settings, //filters std::vector filters; - QString framerateFilter = getFramerateFilter(Framerate, video.framerate); - QString scaleFilter = getScaleFilterString(res, video.resolution, codec.hw_acceleration, vertical); + QString framerateFilter = getFramerateFilter(exports.framerate, video.framerate); + QString scaleFilter = getScaleFilterString(res, video.resolution, codec.hw_acceleration, exports.vertical); //options part2 - QString audioCodec = getAudioCodecString(settings.start == QTime(0, 0) || !settings.trim || trimOnly); - QString videoCodec = getVideoCodecString(codec, trimOnly); - QString bitrate = getMBitRateString(MBitRate); + QString audioCodec = getAudioCodecString(video, settings, codec, exports); + QString videoCodec = getVideoCodecString(codec, exports.trimOnly); + QString bitrate = getMBitRateString(exports.VideoMBitRate); QString outputFile = getOutputFileString(expFilePath); //options part1 hwac QString hwacc = getHardwareAccelerationString(codec.hw_acceleration, scaleFilter.length() > 0); + if (exports.audioOnly) { + videoCodec = "-vn"; + bitrate = ""; + hwacc = ""; + framerateFilter = ""; + scaleFilter = ""; + } //add options part 1 if (trimming.length() > 0 && settings.trim) cmd += trimming + " "; @@ -79,11 +86,11 @@ QString FFMPEGWrapper::getFileName(QString const& filePath) return filePath.mid(lastIdx); } -QString FFMPEGWrapper::getExportFileName(QString const& fileName) +QString FFMPEGWrapper::getExportFileName(QString const& fileName, bool audioOnly, const QString & audioFileType) { auto endIdx = fileName.lastIndexOf("."); auto file = fileName.mid(0, endIdx); - auto ending = fileName.mid(endIdx + 1); + auto ending = audioOnly ? audioFileType : fileName.mid(endIdx + 1); return file + "Export." + ending; } @@ -93,10 +100,10 @@ QString FFMPEGWrapper::getPath(QString const& filePath) return filePath.mid(0, lastIdx); } -QString FFMPEGWrapper::getExportFilePath(QString const& filePath) +QString FFMPEGWrapper::getExportFilePath(QString const& filePath, bool audioOnly, const QString & audioFileType) { QString fileName = getFileName(filePath); - return getPath(filePath) + getExportFileName(fileName); + return getPath(filePath) + getExportFileName(fileName, audioOnly, audioFileType); } QString FFMPEGWrapper::getTrimString(QTime const& start, QTime const& end, Video const& video) @@ -126,13 +133,15 @@ QString FFMPEGWrapper::getFramerateFilter(double Framerate, double vidFramerate) QString FFMPEGWrapper::getScaleFilterString(Resolution const& res, Resolution const& vidRes, int HardwareAcceleration, bool vertical) { - if (res.height <= 0 && res.width <= 0 || (res.height == vidRes.height && res.width == vidRes.width)) { + int w = res.width, h = res.height; + if (vertical) + std::swap(w, h); + if (h <= 0 && w <= 0 || (h == vidRes.height && w == vidRes.width)) { return QString(""); } - QString d1 = QString::number(res.width); - QString d2 = QString::number(res.height); - if (vertical) - std::swap(d1, d2); + QString d1 = QString::number(w); + QString d2 = QString::number(h); + QString resolutionString = d1 + ":" + d2; switch (HardwareAcceleration) { @@ -150,16 +159,21 @@ QString FFMPEGWrapper::getVideoCodecString(CodecConfig const& codec, bool trimOn return prefix + "copy"; } else { - return prefix + codec.encoderName + " -vprofile " + codec.profiles[codec.profile].toLower() + codec.extraOptions[codec.profile % codec.extraOptions.size()]; // use modulo to never go out of bounds on shorter vectors + return prefix + codec.videoEncoderName + " -vprofile " + codec.profiles[codec.profile].toLower() + codec.extraOptions[codec.profile % codec.extraOptions.size()]; // use modulo to never go out of bounds on shorter vectors } } -QString FFMPEGWrapper::getAudioCodecString(bool canCopy) +QString FFMPEGWrapper::getAudioCodecString(const Video& video, const TrimSettings& settings, const CodecConfig& codec, const ExportSettings& exports) { + bool canCopy = ((settings.start == QTime(0, 0) || !settings.trim) && codec.audioCodec == video.codec.audioCodec && codec.audioBitrateIdx == 0) || exports.trimOnly; + int audioBitrate = AUDIO_BITRATES[codec.audioBitrateIdx]; + QString audioBitrateString = codec.audioBitrateIdx == 0 ? "" : " -b:a " + QString::number(audioBitrate) + "K"; if (canCopy) return QString("-c:a copy"); + else if (exports.videoOnly) + return QString("-an"); else - return QString(""); + return QString("-c:a " + codec.audioEncoderName + audioBitrateString); } QString FFMPEGWrapper::getHardwareAccelerationString(int HardwareAcceleration, bool usesScaleFilter) diff --git a/src/filedropwidget.cpp b/src/filedropwidget.cpp index 4434384..b571ec0 100644 --- a/src/filedropwidget.cpp +++ b/src/filedropwidget.cpp @@ -57,15 +57,19 @@ void FileDropWidget::dropEvent(QDropEvent * event) setBackgroundRole(QPalette::Window); const QMimeData * mimeData = event->mimeData(); if (acceptMimeType(mimeData)) { + //accept File QString path = mimeData->text().split("file:///")[1]; std::cout << "New File: " << path.toStdString() << std::endl; setText(tr(breakLines(path, 40).toStdString().c_str())); - std::string cmd = "ffprobe.exe -hide_banner -select_streams v:0 -show_streams -v error -i \"" + path.toStdString() + "\" 2>&1"; //redirect stderr to stdout + + //Call FFProbe to get file information + std::string cmd = "ffprobe.exe -hide_banner -show_streams -v error -i \"" + path.toStdString() + "\" 2>&1"; //redirect stderr to stdout QString probe(""); Resolution resolution = {0, 0}; double framerate = 0.; QTime vidLength; - double bitrate = 0.; + QTime audioLength(0,0); + double bitrate = 0., audioBitrate = 0.; CodecConfig codec; { { @@ -79,58 +83,122 @@ void FileDropWidget::dropEvent(QDropEvent * event) } } probe += "\n"; - //std::cout << "Probe:" << probe.toStdString() << std::endl; - const int num_param = 7; - QString parameters[num_param] = { "codec_name", "width", "height", "profile", "r_frame_rate", "duration", "bit_rate" }; - std::vector results; - for (QString const& param : parameters) { - results.push_back(extractParameter(probe, param)); + std::cout << "Probe:" << probe.toStdString() << std::endl; + //split streams + QString videoStream = ""; + QString audioStream = ""; + auto streamSplits = probe.split("[/STREAM]"); + for (auto str : streamSplits) { + if (str.contains("[STREAM]")) { + if (str.contains("codec_type=audio")) { + audioStream = str; + } + else if (str.contains("codec_type=video")) { + videoStream = str; + } + } + if (videoStream.compare("") != 0 && audioStream.compare("") != 0) + break; + } + + //extract video data + if (videoStream != "") { + const int num_param = 7; + QString parameters[num_param] = { "codec_name", "width", "height", "profile", "r_frame_rate", "duration", "bit_rate" }; + std::vector results; + for (QString const& param : parameters) { + results.push_back(extractParameter(videoStream, param)); + } + + codec.videoCodec = VIDEO_CODEC::UNSUPPORTED_VIDEO; + codec.name = VIDEO_CODEC_STRINGS[VIDEO_CODEC::UNSUPPORTED_VIDEO]; + for (int i = 0; i < VIDEO_CODEC::UNSUPPORTED_VIDEO; i++) { + if (results[0].compare(VIDEO_CODEC_STRINGS[i], Qt::CaseInsensitive) == 0) { + codec = DefaultCodecs[static_cast(i)][HARDWARE_ACCELERATION::NONE]; + } + } + + bool ok = true; + auto w = results[1].toInt(&ok); + if (ok) + resolution.width = w; + auto h = results[2].toInt(&ok); + if (ok) + resolution.height = h; + codec.profiles = { results[3] }; + codec.profile = 0; + bool ok2 = true; + double fr1 = results[4].split("/")[0].toDouble(&ok); + double fr2 = results[4].split("/")[1].toDouble(&ok2); + if (ok && ok2) { + framerate = fr1 / fr2; + } + auto dur = results[5].toDouble(&ok); + if (ok) + vidLength = QTime::fromMSecsSinceStartOfDay((int)(dur * 1000.0)); + auto bit = results[6].toDouble(&ok); + if (ok) + bitrate = bit / 1024.0 / 1024.0; + + std::vector parsed; + parsed.push_back(QString::number(codec.videoCodec)); + parsed.push_back(QString::number(resolution.width)); + parsed.push_back(QString::number(resolution.height)); + parsed.push_back(codec.profiles[codec.profile]); + parsed.push_back(QString::number(framerate)); + parsed.push_back(vidLength.toString()); + parsed.push_back(QString::number(bitrate)); + for (int i = 0; i < num_param; i++) { + std::cout << parameters[i].toStdString() << ": " << parsed[i].toStdString() << "(" << results[i].toStdString() << ")\n"; + } } - if (results[0].compare("h264", Qt::CaseInsensitive) == 0) - codec = DefaultCodecs[CODEC_IDX::H264][HARDWARE_ACCELERATION::NONE]; - else if (results[0].compare("hevc", Qt::CaseInsensitive) == 0) - codec = DefaultCodecs[CODEC_IDX::HEVC][HARDWARE_ACCELERATION::NONE]; else { - codec.id = CODEC_IDX::UNSUPPORTED; + codec.videoCodec = VIDEO_CODEC::UNSUPPORTED_VIDEO; codec.name = "Unsupported"; + codec.profiles = { "-" }; + codec.profile = 0; } - bool ok = true; - auto w = results[1].toInt(&ok); - if (ok) - resolution.width = w; - auto h = results[2].toInt(&ok); - if (ok) - resolution.height = h; - codec.profiles = { results[3] }; - codec.profile = 0; - bool ok2 = true; - double fr1 = results[4].split("/")[0].toDouble(&ok); - double fr2 = results[4].split("/")[1].toDouble(&ok2); - if (ok && ok2) { - framerate = fr1 / fr2; + + //extract audio data + if (videoStream != "") { + const int num_param = 3; + QString parameters[num_param] = { "codec_name", "duration", "bit_rate" }; + std::vector results; + for (QString const& param : parameters) { + results.push_back(extractParameter(audioStream, param)); + } + codec.audioCodec = AUDIO_CODEC::UNSUPPORTED_AUDIO; + for (int i = 0; i < AUDIO_CODEC::UNSUPPORTED_AUDIO; i++) { + if (results[0].compare(AUDIO_CODEC_STRINGS[i], Qt::CaseInsensitive) == 0) { + codec.audioCodec = static_cast(i); + } + } + codec.audioCodecName = AUDIO_CODEC_STRINGS[codec.audioCodec]; + + bool ok = true; + auto dur = results[1].toDouble(&ok); + if (ok) + audioLength = QTime::fromMSecsSinceStartOfDay((int)(dur * 1000.0)); + auto bit = results[2].toDouble(&ok); + if (ok) + audioBitrate = bit / 1000.0 / 1000.0; + codec.audioBitrateIdx = 0; + std::vector parsed; + parsed.push_back(QString::number(codec.audioCodec)); + parsed.push_back(audioLength.toString()); + parsed.push_back(QString::number(audioBitrate)); + for (int i = 0; i < num_param; i++) { + std::cout << parameters[i].toStdString() << ": " << parsed[i].toStdString() << "(" << results[i].toStdString() << ")\n"; + } } - auto dur = results[5].toDouble(&ok); - if (ok) - vidLength = QTime::fromMSecsSinceStartOfDay((int) (dur * 1000.0)); - auto bit = results[6].toDouble(&ok); - if (ok) - bitrate = bit / 1024.0 / 1024.0; - - std::vector parsed; - parsed.push_back(QString::number(codec.id)); - parsed.push_back(QString::number(resolution.width)); - parsed.push_back(QString::number(resolution.height)); - parsed.push_back(codec.profiles[codec.profile]); - parsed.push_back(QString::number(framerate)); - parsed.push_back(vidLength.toString()); - parsed.push_back(QString::number(bitrate)); - for (int i = 0; i < num_param; i++) { - std::cout << parameters[i].toStdString() << ": " << parsed[i].toStdString() << "(" << results[i].toStdString() << ")\n"; + else { + codec.audioCodec = AUDIO_CODEC::UNSUPPORTED_AUDIO; + codec.audioCodecName = AUDIO_CODEC_STRINGS[AUDIO_CODEC::UNSUPPORTED_AUDIO]; + codec.audioBitrateIdx = 0; } - } - + //thumbnail generation int msecsMid = vidLength.msecsSinceStartOfDay() / 2; QTime thumbnailTime = QTime::fromMSecsSinceStartOfDay(msecsMid > 3000 ? 3000 : msecsMid); //prefer a thumbnail at 3 seconds or at videoLength / 2, if video is shorter QString tempFolder("VideoLow.tmp"); @@ -139,22 +207,32 @@ void FileDropWidget::dropEvent(QDropEvent * event) QString format("hh:mm:ss.zzz"); cmd = "ffmpeg -y -i \"" + path.toStdString() + "\" -ss " + thumbnailTime.toString(format).toStdString() + " -vf \"scale=1000:1000:force_original_aspect_ratio=decrease\" -vframes 1 \"" + thumbnail.toStdString() + "\" 2>&1"; //redirect stderr to stdout - QString thumb; - { - FILE * f; - f = _popen(cmd.c_str(), "r"); - char buff[128]; - if (f) { - while (fgets(buff, 128, f)) { - thumb.append(buff); + if (codec.videoCodec != VIDEO_CODEC::UNSUPPORTED_VIDEO) { + QString thumb; + { + FILE* f; + f = _popen(cmd.c_str(), "r"); + char buff[128]; + if (f) { + while (fgets(buff, 128, f)) { + thumb.append(buff); + } } } + //std::cout << cmd << "\n--------\n" << thumb.toStdString() << std::endl; + QPixmap m(thumbnail); + auto scaled = m.scaled(previewLabel->width(), previewLabel->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + previewLabel->setText(""); + previewLabel->setPixmap(scaled); + } + else { + QPixmap p; + previewLabel->setPixmap(p); + previewLabel->setText("Video codec not supported or no video stream found."); } - // std::cout<width(), previewLabel->height(), Qt::KeepAspectRatio,Qt::SmoothTransformation); - previewLabel->setPixmap(scaled); - Video vid = { path, vidLength, resolution, framerate, codec, bitrate}; //TODO: check if video got detected properly + + + Video vid = { path, vidLength, resolution, framerate, codec, bitrate, audioBitrate, audioLength}; //TODO: check if video got detected properly emit newVideoFileDropped(vid); hasDrop = true; } diff --git a/src/videolowwindow.cpp b/src/videolowwindow.cpp index 5dd46bd..76ddde1 100644 --- a/src/videolowwindow.cpp +++ b/src/videolowwindow.cpp @@ -10,8 +10,6 @@ #include -//TODO: add vertical Video option - VideoLowWindow::VideoLowWindow(QWidget* parent) : QMainWindow(parent) , ffmpeg(new FFMPEGWrapper()) @@ -30,6 +28,12 @@ VideoLowWindow::VideoLowWindow(QWidget* parent) connectSlots(); setWindowFlags(Qt::Window | Qt::MSWindowsFixedSizeDialogHint); this->statusBar()->setSizeGripEnabled(false); + for (int i = 0; i < AUDIO_CODEC::UNSUPPORTED_AUDIO; i++) { + ui->AudioCodecComboBox->addItem(AUDIO_CODEC_STRINGS[i]); + } + for (int i = 0; i < VIDEO_CODEC::UNSUPPORTED_VIDEO; i++) { + ui->CodecComboBox->addItem(VIDEO_CODEC_STRINGS[i]); + } codecConfigChanged(0); } @@ -68,30 +72,43 @@ void VideoLowWindow::connectSlots() QObject::connect(ui->EndTimeEdit, &QTimeEdit::editingFinished, this, &VideoLowWindow::endTimeEdited); QObject::connect(ui->DropWidget, &FileDropWidget::newVideoFileDropped, this, &VideoLowWindow::newVideoFile); + + QObject::connect(ui->AudioOnlyCheckBox, &QCheckBox::toggled, this, &VideoLowWindow::uncheckRemoveAudio); + QObject::connect(ui->RemoveAudioCheckBox, &QCheckBox::toggled, this, &VideoLowWindow::uncheckAudioOnly); + } CodecConfig VideoLowWindow::getCodecConfig() { - CodecConfig codec = DefaultCodecs[CODEC_IDX(ui->CodecComboBox->currentIndex())][HARDWARE_ACCELERATION(ui->HardwareAccelerationComboBox->currentIndex())]; + CodecConfig codec = DefaultCodecs[VIDEO_CODEC(ui->CodecComboBox->currentIndex())][HARDWARE_ACCELERATION(ui->HardwareAccelerationComboBox->currentIndex())]; codec.profile = ui->ProfileComboBox->currentIndex(); + codec.audioCodec = ui->AudioCodecComboBox->currentIndex(); + codec.audioCodecName = AUDIO_CODEC_STRINGS[codec.audioCodec]; + codec.audioEncoderName = AUDIO_ENCODER_STRINGS[codec.audioCodec]; + codec.audioBitrateIdx = ui->audioBitrateComboBox->currentIndex(); return codec; } void VideoLowWindow::quickH264(double MBitRate) { if (currentVideo) { - CodecConfig h264 = DefaultCodecs[CODEC_IDX::H264][HARDWARE_ACCELERATION(ui->HardwareAccelerationQuickComboBox->currentIndex())]; + CodecConfig h264 = DefaultCodecs[VIDEO_CODEC::H264][HARDWARE_ACCELERATION(ui->HardwareAccelerationQuickComboBox->currentIndex())]; h264.profile = h264.mainProfile; + ExportSettings exp = { + MBitRate, + FRAMERATES[ui->FramerateQuickComboBox->currentIndex()], + false, + false, + false, + false + }; handleExportExitCode( ffmpeg->exportFile( *currentVideo, getTrimSettings(), - MBitRate, RESOLUTIONS[RESOLUTION_IDX::RESOLUTION_AS_INPUT], h264, - FRAMERATES[ui->FramerateQuickComboBox->currentIndex()], - false, - false + exp ), ui->HardwareAccelerationQuickComboBox->currentIndex() != 0 ); @@ -101,18 +118,23 @@ void VideoLowWindow::quickH264(double MBitRate) void VideoLowWindow::quickHEVC(double MBitRate) { if (currentVideo) { - CodecConfig hevc = DefaultCodecs[CODEC_IDX::HEVC][HARDWARE_ACCELERATION(ui->HardwareAccelerationQuickComboBox->currentIndex())]; + CodecConfig hevc = DefaultCodecs[VIDEO_CODEC::HEVC][HARDWARE_ACCELERATION(ui->HardwareAccelerationQuickComboBox->currentIndex())]; hevc.profile = hevc.mainProfile; + ExportSettings exp = { + MBitRate, + FRAMERATES[ui->FramerateQuickComboBox->currentIndex()], + false, + false, + false, + false + }; handleExportExitCode( ffmpeg->exportFile( *currentVideo, getTrimSettings(), - MBitRate, RESOLUTIONS[RESOLUTION_IDX::RESOLUTION_AS_INPUT], hevc, - FRAMERATES[ui->FramerateQuickComboBox->currentIndex()], - false, - false + exp ), ui->HardwareAccelerationQuickComboBox->currentIndex() != 0 ); @@ -135,6 +157,19 @@ void VideoLowWindow::handleExportExitCode(bool success, bool hardwareAcc) } } +void VideoLowWindow::setQuickExportsEnabled(bool enabled) +{ + ui->H264_2->setEnabled(enabled); + ui->H264_4->setEnabled(enabled); + ui->H264_8->setEnabled(enabled); + ui->H264_16->setEnabled(enabled); + + ui->HEVC_2->setEnabled(enabled); + ui->HEVC_4->setEnabled(enabled); + ui->HEVC_8->setEnabled(enabled); + ui->HEVC_16->setEnabled(enabled); +} + TrimSettings VideoLowWindow::getTrimSettings() { QTime start = ui->startTimeEdit->time(); @@ -192,16 +227,22 @@ void VideoLowWindow::exportVideo() std::cout << "export" << std::endl; if (currentVideo) { auto codec = getCodecConfig(); + ExportSettings exp = { + ui->BitrateDoubleSpinBox->value(), + FRAMERATES[ui->FramerateComboBox->currentIndex()], + false, + ui->verticalVideoCheckbox->isChecked(), + ui->AudioOnlyCheckBox->isChecked(), + ui->RemoveAudioCheckBox->isChecked() + }; + handleExportExitCode( ffmpeg->exportFile( *currentVideo, getTrimSettings(), - ui->BitrateDoubleSpinBox->value(), RESOLUTIONS[ui->ResolutionComboBox->currentIndex()], codec, - FRAMERATES[ui->FramerateComboBox->currentIndex()], - false, - ui->verticalVideoCheckbox->isChecked() + exp ), ui->HardwareAccelerationComboBox->currentIndex() != 0 ); @@ -219,17 +260,22 @@ void VideoLowWindow::reviewVideo() void VideoLowWindow::quickTrimOnly() { if (currentVideo) { - CodecConfig codec = DefaultCodecs[CODEC_IDX::H264][HARDWARE_ACCELERATION::NONE]; //default parameters as it doesnt matter for this trimming + CodecConfig codec = DefaultCodecs[VIDEO_CODEC::H264][HARDWARE_ACCELERATION::NONE]; //default parameters as it doesnt matter for this trimming + ExportSettings exp = { + ui->BitrateDoubleSpinBox->value(), + FRAMERATES[0], + true, + false, + false, + false + }; handleExportExitCode( ffmpeg->exportFile( *currentVideo, getTrimSettings(), - ui->BitrateDoubleSpinBox->value(), RESOLUTIONS[RESOLUTION_IDX::RESOLUTION_AS_INPUT], codec, - FRAMERATES[0], - true, - false + exp ), ui->HardwareAccelerationQuickComboBox->currentIndex() != 0 ); @@ -238,7 +284,7 @@ void VideoLowWindow::quickTrimOnly() void VideoLowWindow::codecConfigChanged(int) { - auto codec = DefaultCodecs[CODEC_IDX(ui->CodecComboBox->currentIndex())][HARDWARE_ACCELERATION(ui->HardwareAccelerationComboBox->currentIndex())]; + auto codec = DefaultCodecs[VIDEO_CODEC(ui->CodecComboBox->currentIndex())][HARDWARE_ACCELERATION(ui->HardwareAccelerationComboBox->currentIndex())]; int count = ui->ProfileComboBox->count(); for (int i = 0; i < count; i++) { ui->ProfileComboBox->removeItem(0); @@ -283,30 +329,88 @@ void VideoLowWindow::endTimeEdited() ui->EndTimeEdit->setTime(current); } +void VideoLowWindow::uncheckRemoveAudio(bool isAudioOnlyChecked) +{ + if(isAudioOnlyChecked) + ui->RemoveAudioCheckBox->setChecked(false); +} + +void VideoLowWindow::uncheckAudioOnly(bool isRemoveAudioChecked) +{ + if (isRemoveAudioChecked) + ui->AudioOnlyCheckBox->setChecked(false); +} + void VideoLowWindow::newVideoFile(Video const& vid) { + ui->SettingsTab->setCurrentIndex(0); + ui->AudioTab->setEnabled(true); + ui->VideoTab->setEnabled(true); + ui->VideoInfoLayout->setEnabled(true); + ui->AudioInfoLayout->setEnabled(true); + setQuickExportsEnabled(true); + + ui->RemoveAudioCheckBox->setChecked(false); + ui->RemoveAudioCheckBox->setEnabled(true); + ui->AudioOnlyCheckBox->setChecked(false); + ui->AudioOnlyCheckBox->setEnabled(true); + if (!currentVideo) { currentVideo = new Video(vid); } else *currentVideo = vid; + bool unsupportedVideo = vid.codec.videoCodec == VIDEO_CODEC::UNSUPPORTED_VIDEO; + bool unsupportedAudio = vid.codec.audioCodec == AUDIO_CODEC::UNSUPPORTED_AUDIO; + QTime zero(0, 0); ui->reviewVideoButton->setDisabled(false); ui->trimVideoCheckBox->setChecked(false); ui->startTimeEdit->setTime(zero); ui->EndTimeEdit->setTime(vid.length); - ui->videoLengthTimeEdit->setTime(vid.length); - if (vid.resolution.width && vid.resolution.height) + if (vid.length.msec() == -1 || unsupportedVideo) { + ui->videoLengthTimeEdit->setTime(zero); + } + else { + ui->videoLengthTimeEdit->setTime(vid.length); + } + if (vid.resolution.width && vid.resolution.height && !unsupportedVideo) ui->videoResolutionLabel->setText(QString::number(vid.resolution.width) + "x" + QString::number(vid.resolution.height)); else ui->videoResolutionLabel->setText("-"); - if (vid.framerate) + if (vid.framerate && !unsupportedVideo) ui->videoFramerateLabel->setText(QString::number(vid.framerate, 'f', 2) + " fps"); else ui->videoFramerateLabel->setText("-"); ui->videoCodecLabel->setText(vid.codec.name + " (" + vid.codec.profiles[vid.codec.profile] + ")"); - ui->videoBitrateLabel->setText(vid.bitrate == 0. ? QString("-") : QString::number(vid.bitrate, 'f', 2) + " MBit/s"); + ui->videoBitrateLabel->setText((vid.bitrate == 0. || unsupportedVideo) ? QString("-") : QString::number(vid.bitrate, 'f', 2) + " MBit/s"); + + ui->audioCodecLabel->setText(vid.codec.audioCodecName); + + if (unsupportedAudio) { + //disable audio + ui->AudioTab->setEnabled(false); + ui->audioBitrateLabel->setText("-"); + ui->audioLengthTimeEdit->setTime(zero); + } + else { + ui->audioBitrateLabel->setText(QString::number(vid.audioBitrate * 1000.0, 'f', 2) + " KBit/s"); + ui->audioLengthTimeEdit->setTime(vid.audioLength); + } + + if (unsupportedVideo) { + //disable video + ui->VideoTab->setEnabled(false); + ui->SettingsTab->setCurrentIndex(1); + //disable all quick export except trimming + setQuickExportsEnabled(false); + //disable remove audio and audio only while selecting audio only + ui->RemoveAudioCheckBox->setChecked(false); + ui->RemoveAudioCheckBox->setEnabled(false); + ui->AudioOnlyCheckBox->setChecked(true); + ui->AudioOnlyCheckBox->setEnabled(false); + } } diff --git a/src/videolowwindow.ui b/src/videolowwindow.ui index 43cd042..7771a18 100644 --- a/src/videolowwindow.ui +++ b/src/videolowwindow.ui @@ -6,8 +6,8 @@ 0 0 - 773 - 762 + 779 + 829 @@ -32,7 +32,7 @@ 0 0 771 - 721 + 802 @@ -146,239 +146,357 @@ - - - QLayout::SetMinimumSize - - - 5 - - - 5 + + + 0 - - - - - - Bitrate (Mbit/s): - - - + + + Video + + - - - 1 - - - 0.100000000000000 + + + QLayout::SetMinimumSize - - 0.100000000000000 + + 5 - - 5.000000000000000 - - - - - - - - - - - Export Codec: + + 5 - - - - - - H.264 - + + + + + Bitrate (Mbit/s): + + + + + + + 1 + + + 0.100000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + - - HEVC (H.265) - + + + + + Export Codec: + + + + + + + - - - - - - - - - - Hardware Acceleration: - - - - - - - 0 - - - None - + + + + + Hardware Acceleration: + + + + + + + 0 + + + + None + + + + + Nvidia + + + + + AMD + + + + + - - Nvidia - + + + + + Codec Profile: + + + + + + + 2 + + + + Baseline + + + + + Main + + + + + High + + + + + - - AMD - + + + + + Output Resolution: + + + + + + + + As Input + + + + + 4K + + + + + 1440p + + + + + 1080p + + + + + 720p + + + + + 480p + + + + + 240p + + + + + + + + Vertical Video + + + + - - - - - - - - - - Codec Profile: - - - - - - - 2 - - - Baseline - - - - - Main - - - - - High - + + + + + Output Framerate: + + + + + + + + As Input + + + + + 30 + + + + + 60 + + + + + 120 + + + + + 240 + + + + + - + - - - + + + + Audio + + - - - Output Resolution: + + + QLayout::SetMinimumSize - - - - - - - As Input - - - - - 4K - - - - - 1440p - - - - - 1080p - - - - - 720p - - - - - 480p - - - - - 240p - - - - - - - - Vertical Video + + 5 - - - - - - - - - - Output Framerate: + + 5 - - - - - - As Input - + + + + + Bitrate (Kbit/s): + + + + + + + + As Input + + + + + 320 Kbit/s + + + + + 256 Kbit/s + + + + + 192 Kbit/s + + + + + 160 Kbit/s + + + + + 128 Kbit/s + + + + + 64 Kbit/s + + + + + - - 30 - + + + + + Export Codec: + + + + + + + - - 60 - - - - - 120 - + + + + + Export Audio Only + + + + + + + Remove Audio + + + + - - 240 - + + + Qt::Vertical + + + + 20 + 40 + + + - + - - - - - Export - - - - + + + + + + + Export + + @@ -544,67 +662,71 @@ - - - H.264 2 Mbit/s - - - - - - - H.264 4 Mbit/s - - - - - - - H.264 8 Mbit/s - - - - - - - H.264 16 Mbit/s - - - - - - - Qt::Horizontal - - - - - - - HEVC 2 Mbit/s - - - - - - - HEVC 4 Mbit/s - - - - - - - HEVC 8 Mbit/s - - - - - - - HEVC 16 Mbit/s - - + + + + + H.264 2 Mbit/s + + + + + + + H.264 4 Mbit/s + + + + + + + H.264 8 Mbit/s + + + + + + + H.264 16 Mbit/s + + + + + + + Qt::Horizontal + + + + + + + HEVC 2 Mbit/s + + + + + + + HEVC 4 Mbit/s + + + + + + + HEVC 8 Mbit/s + + + + + + + HEVC 16 Mbit/s + + + + @@ -619,7 +741,7 @@ false - Only Trim Video + Only Trim Media @@ -756,7 +878,7 @@ - + 5 @@ -858,6 +980,81 @@ + + + + 5 + + + + + Audio: + + + + + + + Length: + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + HH:mm:ss.zzz + + + + + + + Bitrate: + + + + + + + - + + + + + + + Codec: + + + + + + + - + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -924,14 +1121,14 @@ false - Review Video + Review Media - Trim Video + Trim Media @@ -958,7 +1155,7 @@ 0 0 - 773 + 779 22