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
+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);