Skip to content

Commit

Permalink
Added support for audio: audio trimming added, support for mp3 and aa…
Browse files Browse the repository at this point in the history
…c files added, possibility to remove audio or to only export audio
  • Loading branch information
andreasGBL committed Nov 20, 2022
1 parent d598835 commit 50db0ee
Show file tree
Hide file tree
Showing 8 changed files with 831 additions and 395 deletions.
17 changes: 13 additions & 4 deletions include/ffmpegwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@ 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);
QString getFramerateFilter(double Framerate, double vidFramerate);
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);
Expand Down
3 changes: 2 additions & 1 deletion include/filedropwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
64 changes: 46 additions & 18 deletions include/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<QString> profiles;
int profile; //also default profile
int mainProfile;
std::vector<QString> 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];
//}

Expand All @@ -135,4 +161,6 @@ struct Video {
double framerate;
CodecConfig codec;
double bitrate;
double audioBitrate;
QTime audioLength;
};
3 changes: 3 additions & 0 deletions include/videolowwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
52 changes: 33 additions & 19 deletions src/ffmpegwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,18 +31,25 @@ bool FFMPEGWrapper::exportFile(const Video& video, const TrimSettings& settings,

//filters
std::vector<QString> 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 + " ";
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down
Loading

0 comments on commit 50db0ee

Please sign in to comment.