audio: extended support for planar/packed formats

This commit is contained in:
itsmattkc
2022-05-03 13:41:27 -07:00
parent 6e7e6f81f9
commit b290c4d007
22 changed files with 393 additions and 103 deletions
+13 -7
View File
@@ -77,7 +77,7 @@ int InputCallback(const void *input, void *output, unsigned long frameCount, con
s->set_sample_count(frameCount);
s->set_audio_params(f->params().audio_params());
f->WriteAudioData(f->params().audio_params(), false, reinterpret_cast<const uint8_t**>(&input), frameCount);
f->WriteAudioData(f->params().audio_params(), reinterpret_cast<const uint8_t**>(&input), frameCount);
return paContinue;
}
@@ -115,16 +115,22 @@ void AudioManager::ClearBufferedOutput()
PaSampleFormat AudioManager::GetPortAudioSampleFormat(AudioParams::Format fmt)
{
switch (fmt) {
case AudioParams::kFormatUnsigned8:
case AudioParams::kFormatUnsigned8Packed:
case AudioParams::kFormatUnsigned8Planar:
return paUInt8;
case AudioParams::kFormatSigned16:
case AudioParams::kFormatSigned16Packed:
case AudioParams::kFormatSigned16Planar:
return paInt16;
case AudioParams::kFormatSigned32:
case AudioParams::kFormatSigned32Packed:
case AudioParams::kFormatSigned32Planar:
return paInt32;
case AudioParams::kFormatFloat32:
case AudioParams::kFormatFloat32Packed:
case AudioParams::kFormatFloat32Planar:
return paFloat32;
case AudioParams::kFormatSigned64:
case AudioParams::kFormatFloat64:
case AudioParams::kFormatSigned64Packed:
case AudioParams::kFormatSigned64Planar:
case AudioParams::kFormatFloat64Packed:
case AudioParams::kFormatFloat64Planar:
case AudioParams::kFormatInvalid:
case AudioParams::kFormatCount:
break;
+2 -2
View File
@@ -42,10 +42,10 @@ bool PackedProcessor::Open(const AudioParams &params)
swr_ctx_ = swr_alloc_set_opts(nullptr,
params.channel_layout(),
FFmpegUtils::GetFFmpegSampleFormat(params.format(), false),
FFmpegUtils::GetFFmpegSampleFormat(AudioParams::GetPackedEquivalent(params.format())),
params.sample_rate(),
params.channel_layout(),
FFmpegUtils::GetFFmpegSampleFormat(params.format(), true),
FFmpegUtils::GetFFmpegSampleFormat(params.format()),
params.sample_rate(),
0,
nullptr);
+2 -2
View File
@@ -42,10 +42,10 @@ bool PlanarProcessor::Open(const AudioParams &params)
swr_ctx_ = swr_alloc_set_opts(nullptr,
params.channel_layout(),
FFmpegUtils::GetFFmpegSampleFormat(params.format(), true),
FFmpegUtils::GetFFmpegSampleFormat(AudioParams::GetPlanarEquivalent(params.format())),
params.sample_rate(),
params.channel_layout(),
FFmpegUtils::GetFFmpegSampleFormat(params.format(), false),
FFmpegUtils::GetFFmpegSampleFormat(params.format()),
params.sample_rate(),
0,
nullptr);
+7 -1
View File
@@ -320,7 +320,8 @@ Encoder::Type Encoder::GetTypeFromFormat(ExportFormat::Format f)
case ExportFormat::kFormatDNxHD:
case ExportFormat::kFormatMatroska:
case ExportFormat::kFormatQuickTime:
case ExportFormat::kFormatMPEG4:
case ExportFormat::kFormatMPEG4Video:
case ExportFormat::kFormatMPEG4Audio:
case ExportFormat::kFormatWAV:
case ExportFormat::kFormatAIFF:
case ExportFormat::kFormatMP3:
@@ -350,4 +351,9 @@ QStringList Encoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
return QStringList();
}
std::vector<AudioParams::Format> Encoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
{
return std::vector<AudioParams::Format>();
}
}
+1
View File
@@ -155,6 +155,7 @@ public:
static Encoder *CreateFromFormat(ExportFormat::Format f, const EncodingParams &params);
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const;
virtual std::vector<AudioParams::Format> GetSampleFormatsForCodec(ExportCodec::Codec c) const;
const EncodingParams& params() const;
+29
View File
@@ -103,4 +103,33 @@ bool ExportCodec::IsCodecAStillImage(ExportCodec::Codec c)
return false;
}
bool ExportCodec::IsCodecLossless(Codec c)
{
switch (c) {
case kCodecPCM:
case kCodecFLAC:
return true;
case kCodecDNxHD:
case kCodecH264:
case kCodecH264rgb:
case kCodecH265:
case kCodecProRes:
case kCodecCineform:
case kCodecMP2:
case kCodecMP3:
case kCodecAAC:
case kCodecVorbis:
case kCodecOpus:
case kCodecVP9:
case kCodecSRT:
case kCodecOpenEXR:
case kCodecPNG:
case kCodecTIFF:
case kCodecCount:
break;
}
return false;
}
}
+3 -5
View File
@@ -33,8 +33,8 @@ class ExportCodec : public QObject
{
Q_OBJECT
public:
// Only append to this list (never insert) because indexes are used in serialized files
enum Codec {
// Video codecs
kCodecDNxHD,
kCodecH264,
kCodecH264rgb,
@@ -45,8 +45,6 @@ public:
kCodecCineform,
kCodecTIFF,
kCodecVP9,
// Audio codecs
kCodecMP2,
kCodecMP3,
kCodecAAC,
@@ -54,8 +52,6 @@ public:
kCodecOpus,
kCodecVorbis,
kCodecFLAC,
// Subtitle codecs
kCodecSRT,
kCodecCount
@@ -65,6 +61,8 @@ public:
static bool IsCodecAStillImage(Codec c);
static bool IsCodecLossless(Codec c);
};
}
+26 -5
View File
@@ -31,8 +31,10 @@ QString ExportFormat::GetName(olive::ExportFormat::Format f)
return tr("DNxHD");
case kFormatMatroska:
return tr("Matroska Video");
case kFormatMPEG4:
case kFormatMPEG4Video:
return tr("MPEG-4 Video");
case kFormatMPEG4Audio:
return tr("MPEG-4 Audio");
case kFormatOpenEXR:
return tr("OpenEXR");
case kFormatPNG:
@@ -70,8 +72,10 @@ QString ExportFormat::GetExtension(ExportFormat::Format f)
return QStringLiteral("mxf");
case kFormatMatroska:
return QStringLiteral("mkv");
case kFormatMPEG4:
case kFormatMPEG4Video:
return QStringLiteral("mp4");
case kFormatMPEG4Audio:
return QStringLiteral("m4a");
case kFormatOpenEXR:
return QStringLiteral("exr");
case kFormatPNG:
@@ -108,7 +112,7 @@ QList<ExportCodec::Codec> ExportFormat::GetVideoCodecs(ExportFormat::Format f)
return {ExportCodec::kCodecDNxHD};
case kFormatMatroska:
return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265, ExportCodec::kCodecVP9};
case kFormatMPEG4:
case kFormatMPEG4Video:
return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265};
case kFormatOpenEXR:
return {ExportCodec::kCodecOpenEXR};
@@ -122,6 +126,7 @@ QList<ExportCodec::Codec> ExportFormat::GetVideoCodecs(ExportFormat::Format f)
return {ExportCodec::kCodecVP9};
case kFormatOgg:
case kFormatWAV:
case kFormatMPEG4Audio:
case kFormatAIFF:
case kFormatMP3:
case kFormatFLAC:
@@ -141,7 +146,8 @@ QList<ExportCodec::Codec> ExportFormat::GetAudioCodecs(ExportFormat::Format f)
return {ExportCodec::kCodecPCM};
case kFormatMatroska:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis, ExportCodec::kCodecOpus, ExportCodec::kCodecFLAC};
case kFormatMPEG4:
case kFormatMPEG4Video:
case kFormatMPEG4Audio:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3};
case kFormatQuickTime:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM};
@@ -177,7 +183,8 @@ QList<ExportCodec::Codec> ExportFormat::GetSubtitleCodecs(Format f)
{
switch (f) {
case kFormatDNxHD:
case kFormatMPEG4:
case kFormatMPEG4Video:
case kFormatMPEG4Audio:
case kFormatOpenEXR:
case kFormatQuickTime:
case kFormatPNG:
@@ -211,4 +218,18 @@ QStringList ExportFormat::GetPixelFormatsForCodec(ExportFormat::Format f, Export
return list;
}
std::vector<AudioParams::Format> ExportFormat::GetSampleFormatsForCodec(Format format, ExportCodec::Codec c)
{
std::vector<AudioParams::Format> f;
Encoder *e = Encoder::CreateFromFormat(format, EncodingParams());
if (e) {
f = e->GetSampleFormatsForCodec(c);
delete e;
}
return f;
}
}
+4 -1
View File
@@ -33,10 +33,11 @@ class ExportFormat : public QObject
{
Q_OBJECT
public:
// Only append to this list (never insert) because indexes are used in serialized files
enum Format {
kFormatDNxHD,
kFormatMatroska,
kFormatMPEG4,
kFormatMPEG4Video,
kFormatOpenEXR,
kFormatQuickTime,
kFormatPNG,
@@ -48,6 +49,7 @@ public:
kFormatOgg,
kFormatWebM,
kFormatSRT,
kFormatMPEG4Audio,
kFormatCount
};
@@ -59,6 +61,7 @@ public:
static QList<ExportCodec::Codec> GetSubtitleCodecs(ExportFormat::Format f);
static QStringList GetPixelFormatsForCodec(Format f, ExportCodec::Codec c);
static std::vector<AudioParams::Format> GetSampleFormatsForCodec(Format f, ExportCodec::Codec c);
};
+1 -1
View File
@@ -455,7 +455,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
// Create resampling context
SwrContext* resampler = swr_alloc_set_opts(nullptr,
params.channel_layout(),
FFmpegUtils::GetFFmpegSampleFormat(params.format(), true),
FFmpegUtils::GetFFmpegSampleFormat(params.format()),
params.sample_rate(),
channel_layout,
static_cast<AVSampleFormat>(instance_.avstream()->codecpar->format),
+50 -12
View File
@@ -62,6 +62,38 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
return pix_fmts;
}
std::vector<AudioParams::Format> FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
{
std::vector<AudioParams::Format> f;
if (c == ExportCodec::kCodecPCM) {
// FFmpeg lists these as separate codecs so we need custom functionality here
// We list signed 16 first because ExportDialog will always use the first element by default
// (beacuse first element is the "default" in FFmpeg)
f = {
AudioParams::kFormatSigned16Packed,
AudioParams::kFormatUnsigned8Packed,
AudioParams::kFormatSigned32Packed,
AudioParams::kFormatSigned64Packed,
AudioParams::kFormatFloat32Packed,
AudioParams::kFormatFloat64Packed
};
} else {
const AVCodec* codec_info = GetEncoder(c, AudioParams::kFormatInvalid);
if (codec_info && codec_info->sample_fmts) {
for (int i=0; codec_info->sample_fmts[i]!=-1; i++) {
AudioParams::Format this_format = FFmpegUtils::GetNativeSampleFormat(static_cast<AVSampleFormat>(codec_info->sample_fmts[i]));
if (this_format != AudioParams::kFormatInvalid) {
f.push_back(this_format);
}
}
}
}
return f;
}
bool FFmpegEncoder::Open()
{
if (open_) {
@@ -246,14 +278,14 @@ bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio)
int input_linesize;
av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio->audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio->audio_params().format(), true), 0);
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio->audio_params().format()), 0);
for (int i=0; i<audio->audio_params().channel_count(); i++) {
memcpy(input_data[i], audio->data(i), input_sample_count * audio->audio_params().bytes_per_sample_per_channel());
}
}
result = WriteAudioData(audio->audio_params(), true, const_cast<const uint8_t**>(input_data), input_sample_count);
result = WriteAudioData(audio->audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
if (input_data) {
av_freep(&input_data[0]);
@@ -263,9 +295,9 @@ bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio)
return result;
}
bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params, bool planar, const uint8_t **input_data, int input_sample_count)
bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params, const uint8_t **input_data, int input_sample_count)
{
if (!InitializeResampleContext(audio_params, planar)) {
if (!InitializeResampleContext(audio_params)) {
qCritical() << "Failed to initialize resample context";
return false;
}
@@ -783,7 +815,7 @@ void FFmpegEncoder::FlushCodecCtx(AVCodecContext *codec_ctx, AVStream* stream)
av_packet_free(&pkt);
}
bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio, bool planar)
bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio)
{
if (audio_resample_ctx_) {
return true;
@@ -795,7 +827,7 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio, bool pla
audio_codec_ctx_->sample_fmt,
audio_codec_ctx_->sample_rate,
static_cast<int64_t>(audio.channel_layout()),
FFmpegUtils::GetFFmpegSampleFormat(audio.format(), planar),
FFmpegUtils::GetFFmpegSampleFormat(audio.format()),
audio.sample_rate(),
0,
nullptr);
@@ -875,18 +907,24 @@ const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, AudioParams::Form
switch (aformat) {
case AudioParams::kFormatInvalid:
case AudioParams::kFormatCount:
case AudioParams::kFormatUnsigned8Planar:
case AudioParams::kFormatSigned16Planar:
case AudioParams::kFormatSigned32Planar:
case AudioParams::kFormatSigned64Planar:
case AudioParams::kFormatFloat32Planar:
case AudioParams::kFormatFloat64Planar:
break;
case AudioParams::kFormatUnsigned8:
case AudioParams::kFormatUnsigned8Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_U8);
case AudioParams::kFormatSigned16:
case AudioParams::kFormatSigned16Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE);
case AudioParams::kFormatSigned32:
case AudioParams::kFormatSigned32Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_S32LE);
case AudioParams::kFormatSigned64:
case AudioParams::kFormatSigned64Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_S64LE);
case AudioParams::kFormatFloat32:
case AudioParams::kFormatFloat32Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_F32LE);
case AudioParams::kFormatFloat64:
case AudioParams::kFormatFloat64Packed:
return avcodec_find_encoder(AV_CODEC_ID_PCM_F64LE);
}
break;
+4 -2
View File
@@ -41,13 +41,15 @@ public:
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const override;
virtual std::vector<AudioParams::Format> GetSampleFormatsForCodec(ExportCodec::Codec c) const override;
virtual bool Open() override;
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override;
virtual bool WriteAudio(olive::SampleBufferPtr audio) override;
bool WriteAudioData(const AudioParams &audio_params, bool planar, const uint8_t **data, int input_sample_count);
bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data, int input_sample_count);
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override;
@@ -78,7 +80,7 @@ private:
void FlushEncoders();
void FlushCodecCtx(AVCodecContext* codec_ctx, AVStream *stream);
bool InitializeResampleContext(const AudioParams &audio, bool planar);
bool InitializeResampleContext(const AudioParams &audio);
static const AVCodec *GetEncoder(ExportCodec::Codec c, AudioParams::Format aformat);
+37 -19
View File
@@ -42,23 +42,29 @@ AudioParams::Format FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp
{
switch (smp_fmt) {
case AV_SAMPLE_FMT_U8:
return AudioParams::kFormatUnsigned8;
return AudioParams::kFormatUnsigned8Packed;
case AV_SAMPLE_FMT_S16:
return AudioParams::kFormatSigned16;
return AudioParams::kFormatSigned16Packed;
case AV_SAMPLE_FMT_S32:
return AudioParams::kFormatSigned32;
return AudioParams::kFormatSigned32Packed;
case AV_SAMPLE_FMT_S64:
return AudioParams::kFormatSigned64;
return AudioParams::kFormatSigned64Packed;
case AV_SAMPLE_FMT_FLT:
return AudioParams::kFormatFloat32;
return AudioParams::kFormatFloat32Packed;
case AV_SAMPLE_FMT_DBL:
return AudioParams::kFormatFloat64;
return AudioParams::kFormatFloat64Packed;
case AV_SAMPLE_FMT_U8P :
return AudioParams::kFormatUnsigned8Planar;
case AV_SAMPLE_FMT_S16P:
return AudioParams::kFormatSigned16Planar;
case AV_SAMPLE_FMT_S32P:
return AudioParams::kFormatSigned32Planar;
case AV_SAMPLE_FMT_S64P:
return AudioParams::kFormatSigned64Planar;
case AV_SAMPLE_FMT_FLTP:
return AudioParams::kFormatFloat32Planar;
case AV_SAMPLE_FMT_DBLP:
return AudioParams::kFormatFloat64Planar;
case AV_SAMPLE_FMT_NONE:
case AV_SAMPLE_FMT_NB:
break;
@@ -67,21 +73,33 @@ AudioParams::Format FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp
return AudioParams::kFormatInvalid;
}
AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt, bool planar)
AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt)
{
switch (smp_fmt) {
case AudioParams::kFormatUnsigned8:
return planar ? AV_SAMPLE_FMT_U8P : AV_SAMPLE_FMT_U8;
case AudioParams::kFormatSigned16:
return planar ? AV_SAMPLE_FMT_S16P : AV_SAMPLE_FMT_S16;
case AudioParams::kFormatSigned32:
return planar ? AV_SAMPLE_FMT_S32P : AV_SAMPLE_FMT_S32;
case AudioParams::kFormatSigned64:
return planar ? AV_SAMPLE_FMT_S64P : AV_SAMPLE_FMT_S64;
case AudioParams::kFormatFloat32:
return planar ? AV_SAMPLE_FMT_FLTP : AV_SAMPLE_FMT_FLT;
case AudioParams::kFormatFloat64:
return planar ? AV_SAMPLE_FMT_DBLP : AV_SAMPLE_FMT_DBL;
case AudioParams::kFormatUnsigned8Packed:
return AV_SAMPLE_FMT_U8;
case AudioParams::kFormatSigned16Packed:
return AV_SAMPLE_FMT_S16;
case AudioParams::kFormatSigned32Packed:
return AV_SAMPLE_FMT_S32;
case AudioParams::kFormatSigned64Packed:
return AV_SAMPLE_FMT_S64;
case AudioParams::kFormatFloat32Packed:
return AV_SAMPLE_FMT_FLT;
case AudioParams::kFormatFloat64Packed:
return AV_SAMPLE_FMT_DBL;
case AudioParams::kFormatUnsigned8Planar:
return AV_SAMPLE_FMT_U8P;
case AudioParams::kFormatSigned16Planar:
return AV_SAMPLE_FMT_S16P;
case AudioParams::kFormatSigned32Planar:
return AV_SAMPLE_FMT_S32P;
case AudioParams::kFormatSigned64Planar:
return AV_SAMPLE_FMT_S64P;
case AudioParams::kFormatFloat32Planar:
return AV_SAMPLE_FMT_FLTP;
case AudioParams::kFormatFloat64Planar:
return AV_SAMPLE_FMT_DBLP;
case AudioParams::kFormatInvalid:
case AudioParams::kFormatCount:
break;
+1 -1
View File
@@ -56,7 +56,7 @@ public:
/**
* @brief Returns an FFmpeg sample format type for a given native type
*/
static AVSampleFormat GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt, bool planar = false);
static AVSampleFormat GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt);
};
}
+1 -1
View File
@@ -125,7 +125,7 @@ void Config::SetDefaults()
SetEntryInternal(QStringLiteral("AudioRecordingCodec"), NodeValue::kInt, ExportCodec::kCodecPCM);
SetEntryInternal(QStringLiteral("AudioRecordingSampleRate"), NodeValue::kInt, 48000);
SetEntryInternal(QStringLiteral("AudioRecordingChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO);
SetEntryInternal(QStringLiteral("AudioRecordingSampleFormat"), NodeValue::kInt, AudioParams::kFormatSigned16);
SetEntryInternal(QStringLiteral("AudioRecordingSampleFormat"), NodeValue::kInt, AudioParams::kFormatSigned16Packed);
SetEntryInternal(QStringLiteral("AudioRecordingBitRate"), NodeValue::kInt, 320);
SetEntryInternal(QStringLiteral("DiskCacheBehind"), NodeValue::kRational, QVariant::fromValue(rational(0)));
+4 -4
View File
@@ -194,8 +194,8 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
SetDefaultFilename();
// Set defaults
previously_selected_format_ = ExportFormat::kFormatMPEG4;
format_combobox_->SetFormat(ExportFormat::kFormatMPEG4);
previously_selected_format_ = ExportFormat::kFormatMPEG4Video;
format_combobox_->SetFormat(ExportFormat::kFormatMPEG4Video);
connect(format_combobox_, &ExportFormatComboBox::FormatChanged, this, &ExportDialog::FormatChanged);
FormatChanged(format_combobox_->GetFormat());
@@ -211,7 +211,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
video_tab_->pixel_format_field()->SetPixelFormat(static_cast<VideoParams::Format>(Config::Current()[QStringLiteral("OnlinePixelFormat")].toInt()));
video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing());
audio_tab_->sample_rate_combobox()->SetSampleRate(ap.sample_rate());
audio_tab_->sample_format_combobox()->SetSampleFormat(ap.format());
audio_tab_->sample_format_combobox()->SetAttemptToRestoreFormat(false);
audio_tab_->channel_layout_combobox()->SetChannelLayout(ap.channel_layout());
video_aspect_ratio_ = static_cast<double>(vp.width()) / static_cast<double>(vp.height());
@@ -514,7 +514,7 @@ ExportParams ExportDialog::GenerateParams() const
video_tab_->interlaced_combobox()->GetInterlaceMode(),
1);
AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(),
AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->GetSampleRate(),
audio_tab_->channel_layout_combobox()->GetChannelLayout(),
audio_tab_->sample_format_combobox()->GetSampleFormat());
+30 -1
View File
@@ -27,6 +27,8 @@
namespace olive {
const int ExportAudioTab::kDefaultBitRate = 320;
ExportAudioTab::ExportAudioTab(QWidget* parent) :
QWidget(parent)
{
@@ -40,6 +42,8 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) :
layout->addWidget(new QLabel(tr("Codec:")), row, 0);
codec_combobox_ = new QComboBox();
connect(codec_combobox_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ExportAudioTab::UpdateSampleFormats);
connect(codec_combobox_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ExportAudioTab::UpdateBitRateEnabled);
layout->addWidget(codec_combobox_, row, 1);
row++;
@@ -70,7 +74,7 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) :
bit_rate_slider_ = new IntegerSlider();
bit_rate_slider_->SetMinimum(32);
bit_rate_slider_->SetMaximum(320);
bit_rate_slider_->SetValue(320);
bit_rate_slider_->SetValue(kDefaultBitRate);
bit_rate_slider_->SetFormat(tr("%1 kbps"));
layout->addWidget(bit_rate_slider_, row, 1);
@@ -81,11 +85,36 @@ int ExportAudioTab::SetFormat(ExportFormat::Format format)
{
QList<ExportCodec::Codec> acodecs = ExportFormat::GetAudioCodecs(format);
setEnabled(!acodecs.isEmpty());
codec_combobox_->blockSignals(true);
codec_combobox_->clear();
foreach (ExportCodec::Codec acodec, acodecs) {
codec_combobox_->addItem(ExportCodec::GetCodecName(acodec), acodec);
}
codec_combobox_->blockSignals(false);
fmt_ = format;
UpdateSampleFormats();
UpdateBitRateEnabled();
return acodecs.size();
}
void ExportAudioTab::UpdateSampleFormats()
{
auto fmts = ExportFormat::GetSampleFormatsForCodec(fmt_, GetCodec());
sample_format_combobox_->SetAvailableFormats(fmts);
}
void ExportAudioTab::UpdateBitRateEnabled()
{
bool uses_bitrate = !ExportCodec::IsCodecLossless(GetCodec());
bit_rate_slider_->setEnabled(uses_bitrate);
if (!uses_bitrate) {
bit_rate_slider_->SetTristate();
} else {
bit_rate_slider_->SetValue(kDefaultBitRate );
}
}
}
+8
View File
@@ -76,12 +76,20 @@ public slots:
int SetFormat(ExportFormat::Format format);
private:
ExportFormat::Format fmt_;
QComboBox* codec_combobox_;
SampleRateComboBox* sample_rate_combobox_;
ChannelLayoutComboBox* channel_layout_combobox_;
SampleFormatComboBox *sample_format_combobox_;
IntegerSlider* bit_rate_slider_;
static const int kDefaultBitRate;
private slots:
void UpdateSampleFormats();
void UpdateBitRateEnabled();
};
}
@@ -103,6 +103,7 @@ PreferencesAudioTab::PreferencesAudioTab()
fmt_layout->addWidget(record_format_combo_);
record_options_ = new ExportAudioTab();
record_options_->SetFormat(record_format_combo_->GetFormat());
record_options_->SetCodec(static_cast<ExportCodec::Codec>(OLIVE_CONFIG("AudioRecordingCodec").toInt()));
record_options_->sample_rate_combobox()->SetSampleRate(OLIVE_CONFIG("AudioRecordingSampleRate").toInt());
record_options_->channel_layout_combobox()->SetChannelLayout(OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong());
@@ -111,8 +112,6 @@ PreferencesAudioTab::PreferencesAudioTab()
recording_layout->addWidget(record_options_);
connect(record_format_combo_, &ExportFormatComboBox::FormatChanged, record_options_, &ExportAudioTab::SetFormat);
record_options_->SetFormat(record_format_combo_->GetFormat());
}
QHBoxLayout* refresh_layout = new QHBoxLayout();
+107 -25
View File
@@ -52,7 +52,7 @@ const QVector<uint64_t> AudioParams::kSupportedChannelLayouts = {
AV_CH_LAYOUT_7POINT1
};
const AudioParams::Format AudioParams::kInternalFormat = AudioParams::kFormatFloat32;
const AudioParams::Format AudioParams::kInternalFormat = AudioParams::kFormatFloat32Planar;
bool AudioParams::operator==(const AudioParams &other) const
{
@@ -144,15 +144,21 @@ int AudioParams::channel_count() const
int AudioParams::bytes_per_sample_per_channel() const
{
switch (format_) {
case kFormatUnsigned8:
case kFormatUnsigned8Packed:
case kFormatUnsigned8Planar:
return 1;
case kFormatSigned16:
case kFormatSigned16Packed:
case kFormatSigned16Planar:
return 2;
case kFormatSigned32:
case kFormatFloat32:
case kFormatSigned32Packed:
case kFormatSigned32Planar:
case kFormatFloat32Packed:
case kFormatFloat32Planar:
return 4;
case kFormatSigned64:
case kFormatFloat64:
case kFormatSigned64Packed:
case kFormatSigned64Planar:
case kFormatFloat64Packed:
case kFormatFloat64Planar:
return 8;
case kFormatInvalid:
case kFormatCount:
@@ -247,24 +253,30 @@ QString AudioParams::ChannelLayoutToString(const uint64_t &layout)
QString AudioParams::FormatToString(const Format &f)
{
switch (f) {
case kFormatUnsigned8:
return QCoreApplication::translate("AudioParams", "Unsigned 8-bit");
break;
case kFormatSigned16:
return QCoreApplication::translate("AudioParams", "Signed 16-bit");
break;
case kFormatSigned32:
return QCoreApplication::translate("AudioParams", "Signed 32-bit");
break;
case kFormatSigned64:
return QCoreApplication::translate("AudioParams", "Signed 64-bit");
break;
case kFormatFloat32:
return QCoreApplication::translate("AudioParams", "Float 32-bit");
break;
case kFormatFloat64:
return QCoreApplication::translate("AudioParams", "Float 64-bit");
break;
case kFormatUnsigned8Packed:
return QCoreApplication::translate("AudioParams", "Unsigned 8-bit (Packed)");
case kFormatSigned16Packed:
return QCoreApplication::translate("AudioParams", "Signed 16-bit (Packed)");
case kFormatSigned32Packed:
return QCoreApplication::translate("AudioParams", "Signed 32-bit (Packed)");
case kFormatSigned64Packed:
return QCoreApplication::translate("AudioParams", "Signed 64-bit (Packed)");
case kFormatFloat32Packed:
return QCoreApplication::translate("AudioParams", "Float 32-bit (Packed)");
case kFormatFloat64Packed:
return QCoreApplication::translate("AudioParams", "Float 64-bit (Packed)");
case kFormatUnsigned8Planar:
return QCoreApplication::translate("AudioParams", "Unsigned 8-bit (Planar)");
case kFormatSigned16Planar:
return QCoreApplication::translate("AudioParams", "Signed 16-bit (Planar)");
case kFormatSigned32Planar:
return QCoreApplication::translate("AudioParams", "Signed 32-bit (Planar)");
case kFormatSigned64Planar:
return QCoreApplication::translate("AudioParams", "Signed 64-bit (Planar)");
case kFormatFloat32Planar:
return QCoreApplication::translate("AudioParams", "Float 32-bit (Planar)");
case kFormatFloat64Planar:
return QCoreApplication::translate("AudioParams", "Float 64-bit (Planar)");
case kFormatInvalid:
case kFormatCount:
@@ -274,4 +286,74 @@ QString AudioParams::FormatToString(const Format &f)
return QCoreApplication::translate("AudioParams", "Unknown (0x%1)").arg(f, 1, 16);
}
AudioParams::Format AudioParams::GetPackedEquivalent(Format fmt)
{
switch (fmt) {
// For packed input, just return input
case kFormatUnsigned8Packed:
case kFormatSigned16Packed:
case kFormatSigned32Packed:
case kFormatSigned64Packed:
case kFormatFloat32Packed:
case kFormatFloat64Packed:
return fmt;
// Convert to packed
case kFormatUnsigned8Planar:
return kFormatUnsigned8Packed;
case kFormatSigned16Planar:
return kFormatSigned16Packed;
case kFormatSigned32Planar:
return kFormatSigned32Packed;
case kFormatSigned64Planar:
return kFormatSigned64Packed;
case kFormatFloat32Planar:
return kFormatFloat32Packed;
case kFormatFloat64Planar:
return kFormatFloat64Packed;
case kFormatInvalid:
case kFormatCount:
break;
}
return kFormatInvalid;
}
AudioParams::Format AudioParams::GetPlanarEquivalent(Format fmt)
{
switch (fmt) {
// Convert to planar
case kFormatUnsigned8Packed:
return kFormatUnsigned8Planar;
case kFormatSigned16Packed:
return kFormatSigned16Planar;
case kFormatSigned32Packed:
return kFormatSigned32Planar;
case kFormatSigned64Packed:
return kFormatSigned64Planar;
case kFormatFloat32Packed:
return kFormatFloat32Planar;
case kFormatFloat64Packed:
return kFormatFloat64Planar;
// For planar input, just return input
case kFormatUnsigned8Planar:
case kFormatSigned16Planar:
case kFormatSigned32Planar:
case kFormatSigned64Planar:
case kFormatFloat32Planar:
case kFormatFloat64Planar:
return fmt;
case kFormatInvalid:
case kFormatCount:
break;
}
return kFormatInvalid;
}
}
+34 -7
View File
@@ -35,30 +35,54 @@ namespace olive {
class AudioParams {
public:
// Only append to this list (never insert) because indexes are used in serialized files
enum Format {
/// Invalid
kFormatInvalid = -1,
/// 8-bit unsigned integer
kFormatUnsigned8,
kFormatUnsigned8Planar,
/// 16-bit signed integer
kFormatSigned16,
kFormatSigned16Planar,
/// 32-bit signed integer
kFormatSigned32,
kFormatSigned32Planar,
/// 64-bit signed integer
kFormatSigned64,
kFormatSigned64Planar,
/// 32-bit float
kFormatFloat32,
kFormatFloat32Planar,
/// 64-bit float
kFormatFloat64,
kFormatFloat64Planar,
/// 8-bit unsigned integer
kFormatUnsigned8Packed,
/// 16-bit signed integer
kFormatSigned16Packed,
/// 32-bit signed integer
kFormatSigned32Packed,
/// 64-bit signed integer
kFormatSigned64Packed,
/// 32-bit float
kFormatFloat32Packed,
/// 64-bit float
kFormatFloat64Packed,
/// Total format count
kFormatCount
kFormatCount,
kPlanarStart = kFormatUnsigned8Planar,
kPackedStart = kFormatUnsigned8Packed,
kPlanarEnd = kPackedStart,
kPackedEnd = kFormatCount
};
static const Format kInternalFormat;
@@ -202,6 +226,9 @@ public:
static QString FormatToString(const Format &f);
static AudioParams::Format GetPackedEquivalent(AudioParams::Format fmt);
static AudioParams::Format GetPlanarEquivalent(AudioParams::Format fmt);
private:
void set_default_footage_parameters()
{
@@ -32,13 +32,28 @@ class SampleFormatComboBox : public QComboBox
Q_OBJECT
public:
SampleFormatComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
QComboBox(parent),
attempt_to_restore_format_(true)
{
// Set up preview formats
for (int i=0;i<AudioParams::kFormatCount;i++) {
AudioParams::Format smp_fmt = static_cast<AudioParams::Format>(i);
}
this->addItem(AudioParams::FormatToString(smp_fmt), smp_fmt);
void SetAttemptToRestoreFormat(bool e) { attempt_to_restore_format_ = e; }
void SetAvailableFormats(const std::vector<AudioParams::Format> &formats)
{
AudioParams::Format tmp;
if (attempt_to_restore_format_) {
tmp = GetSampleFormat();
}
clear();
foreach (const AudioParams::Format &of, formats) {
AddFormatItem(of);
}
if (attempt_to_restore_format_) {
SetSampleFormat(tmp);
}
}
@@ -57,6 +72,14 @@ public:
}
}
private:
void AddFormatItem(AudioParams::Format f)
{
this->addItem(AudioParams::FormatToString(f), f);
}
bool attempt_to_restore_format_;
};
}