audio: extended support for planar/packed formats
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -42,10 +42,10 @@ bool PackedProcessor::Open(const AudioParams ¶ms)
|
||||
|
||||
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);
|
||||
|
||||
@@ -42,10 +42,10 @@ bool PlanarProcessor::Open(const AudioParams ¶ms)
|
||||
|
||||
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);
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ public:
|
||||
static Encoder *CreateFromFormat(ExportFormat::Format f, const EncodingParams ¶ms);
|
||||
|
||||
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const;
|
||||
virtual std::vector<AudioParams::Format> GetSampleFormatsForCodec(ExportCodec::Codec c) const;
|
||||
|
||||
const EncodingParams& params() const;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user