1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-02 00:49:33 +02:00

Bug 2166 - Opus export fails - cannot open codec

This commit is contained in:
Leland Lucius 2020-03-30 12:02:03 -05:00
parent e3f33b3367
commit ddadd8d429
5 changed files with 341 additions and 9 deletions

View File

@ -967,6 +967,7 @@ bool FFmpegLibs::InitLibs(const wxString &libpath_format, bool WXUNUSED(showerr)
FFMPEG_INITALT(avutil, av_frame_free, avcodec, avcodec_free_frame); FFMPEG_INITALT(avutil, av_frame_free, avcodec, avcodec_free_frame);
FFMPEG_INITDYN(avutil, av_samples_get_buffer_size); FFMPEG_INITDYN(avutil, av_samples_get_buffer_size);
FFMPEG_INITDYN(avutil, av_get_default_channel_layout); FFMPEG_INITDYN(avutil, av_get_default_channel_layout);
FFMPEG_INITDYN(avutil, av_strerror);
wxLogMessage(wxT("All symbols loaded successfully. Initializing the library.")); wxLogMessage(wxT("All symbols loaded successfully. Initializing the library."));
#endif #endif

View File

@ -52,6 +52,7 @@ extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libavutil/fifo.h> #include <libavutil/fifo.h>
#include <libavutil/mathematics.h> #include <libavutil/mathematics.h>
@ -527,6 +528,12 @@ extern "C" {
(int nb_channels), (int nb_channels),
(nb_channels) (nb_channels)
); );
FFMPEG_FUNCTION_WITH_RETURN(
int,
av_strerror,
(int errnum, char *errbuf, size_t errbuf_size),
(errnum, errbuf, errbuf_size)
);
// //
// libavcodec // libavcodec

View File

@ -445,6 +445,20 @@ bool ExportFFmpeg::InitCodecs(AudacityProject *project)
mSampleRate = 8000; mSampleRate = 8000;
mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/AMRNBBitRate"), 12200); mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/AMRNBBitRate"), 12200);
break; break;
case FMT_OPUS:
av_dict_set(&options, "b", gPrefs->Read(wxT("/FileFormats/OPUSBitRate"), wxT("128000")).ToUTF8(), 0);
av_dict_set(&options, "vbr", gPrefs->Read(wxT("/FileFormats/OPUSVbrMode"), wxT("on")).ToUTF8(), 0);
av_dict_set(&options, "compression_level", gPrefs->Read(wxT("/FileFormats/OPUSCompression"), wxT("10")).ToUTF8(), 0);
av_dict_set(&options, "frame_duration", gPrefs->Read(wxT("/FileFormats/OPUSFrameDuration"), wxT("20")).ToUTF8(), 0);
av_dict_set(&options, "application", gPrefs->Read(wxT("/FileFormats/OPUSApplication"), wxT("audio")).ToUTF8(), 0);
av_dict_set(&options, "cutoff", gPrefs->Read(wxT("/FileFormats/OPUSCutoff"), wxT("0")).ToUTF8(), 0);
av_dict_set(&options, "mapping_family", mChannels <= 2 ? "0" : "255", 0);
if (!CheckSampleRate(mSampleRate, ExportFFmpegOPUSOptions::iOPUSSampleRates[4], ExportFFmpegOPUSOptions::iOPUSSampleRates[0], &ExportFFmpegOPUSOptions::iOPUSSampleRates[0]))
{
int bitrate = gPrefs->Read(wxT("/FileFormats/OPUSBitRate"), 128000);
mSampleRate = AskResample(bitrate, mSampleRate, ExportFFmpegOPUSOptions::iOPUSSampleRates[4], ExportFFmpegOPUSOptions::iOPUSSampleRates[0], &ExportFFmpegOPUSOptions::iOPUSSampleRates[0]);
}
break;
case FMT_WMA2: case FMT_WMA2:
mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/WMABitRate"), 198000); mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/WMABitRate"), 198000);
if (!CheckSampleRate(mSampleRate,ExportFFmpegWMAOptions::iWMASampleRates[0], ExportFFmpegWMAOptions::iWMASampleRates[4], &ExportFFmpegWMAOptions::iWMASampleRates[0])) if (!CheckSampleRate(mSampleRate,ExportFFmpegWMAOptions::iWMASampleRates[0], ExportFFmpegWMAOptions::iWMASampleRates[4], &ExportFFmpegWMAOptions::iWMASampleRates[0]))
@ -552,12 +566,15 @@ bool ExportFFmpeg::InitCodecs(AudacityProject *project)
} }
// Open the codec. // Open the codec.
if (avcodec_open2(mEncAudioCodecCtx.get(), codec, &options) < 0) int rc = avcodec_open2(mEncAudioCodecCtx.get(), codec, &options);
if (rc < 0)
{ {
char buf[AV_ERROR_MAX_STRING_SIZE];
av_strerror(rc, buf, sizeof(buf));
AudacityMessageBox( AudacityMessageBox(
/* i18n-hint: "codec" is short for a "coder-decoder" algorithm */ /* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
XO("FFmpeg : ERROR - Can't open audio codec 0x%x.") XO("FFmpeg : ERROR - Can't open audio codec 0x%x\n\n%s")
.Format( mEncAudioCodecCtx->codec_id ), .Format(mEncAudioCodecCtx->codec_id, wxString(buf)),
XO("FFmpeg Error"), XO("FFmpeg Error"),
wxOK|wxCENTER|wxICON_EXCLAMATION); wxOK|wxCENTER|wxICON_EXCLAMATION);
return false; return false;
@ -1054,7 +1071,7 @@ int ExportFFmpeg::AskResample(int bitrate, int rate, int lowrate, int highrate,
.Format( rate ) .Format( rate )
: XO( : XO(
"The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the current output file format. ") "The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the current output file format. ")
.Format( rate, bitrate/1024)) .Format( rate, bitrate/1000))
+ XO("You may resample to one of the rates below.") + XO("You may resample to one of the rates below.")
); );
} }
@ -1123,6 +1140,12 @@ void ExportFFmpeg::OptionsCreate(ShuttleGui &S, int format)
safenew ExportFFmpegAMRNBOptions{ S.GetParent(), format } ); safenew ExportFFmpegAMRNBOptions{ S.GetParent(), format } );
return; return;
} }
else if (mSubFormat == FMT_OPUS)
{
S.AddWindow(
safenew ExportFFmpegOPUSOptions{ S.GetParent(), format });
return;
}
else if (mSubFormat == FMT_WMA2) else if (mSubFormat == FMT_WMA2)
{ {
S.AddWindow( S.AddWindow(

View File

@ -26,6 +26,11 @@
*//***************************************************************//** *//***************************************************************//**
\class ExportFFmpegOPUSOptions
\brief Options dialog for FFmpeg exporting of OPUS format.
*//***************************************************************//**
\class ExportFFmpegWMAOptions \class ExportFFmpegWMAOptions
\brief Options dialog for FFmpeg exporting of WMA format. \brief Options dialog for FFmpeg exporting of WMA format.
@ -400,6 +405,266 @@ bool ExportFFmpegAMRNBOptions::TransferDataFromWindow()
return true; return true;
} }
//----------------------------------------------------------------------------
// ExportFFmpegOPUSOptions Class
//----------------------------------------------------------------------------
const int ExportFFmpegOPUSOptions::iOPUSSampleRates[] =
{ 48000, 24000, 16000, 12000, 8000, 0 };
namespace {
/// Bit Rates supported by OPUS encoder. Setting bit rate to other values will not result in different file size.
ChoiceSetting OPUSBitrate
{
wxT("/FileFormats/OPUSBitrate"),
{
ByColumns,
{
// i18n-hint kbps abbreviates "thousands of bits per second"
XO("24 kbps"),
XO("32 kbps"),
XO("40 kbps"),
XO("48 kbps"),
XO("64 kbps"),
XO("80 kbps"),
XO("96 kbps"),
XO("128 kbps"),
XO("160 kbps"),
XO("192 kbps"),
XO("256 kbps"),
XO("320 kbps"),
XO("510 kbps"),
},
{
wxT("24000"),
wxT("32000"),
wxT("40000"),
wxT("48000"),
wxT("64000"),
wxT("80000"),
wxT("96000"),
wxT("128000"),
wxT("160000"),
wxT("192000"),
wxT("256000"),
wxT("320000"),
wxT("510000"),
}
},
7 // "128 kbps"
};
ChoiceSetting OPUSCompression
{
wxT("/FileFormats/OPUSCompression"),
{
ByColumns,
{
XO("0"),
XO("1"),
XO("2"),
XO("3"),
XO("4"),
XO("5"),
XO("6"),
XO("7"),
XO("8"),
XO("9"),
XO("10"),
},
{
wxT("0"),
wxT("1"),
wxT("2"),
wxT("3"),
wxT("4"),
wxT("5"),
wxT("67"),
wxT("7"),
wxT("8"),
wxT("9"),
wxT("10"),
}
},
10 // "10"
};
ChoiceSetting OPUSVbrMode
{
wxT("/FileFormats/OPUSVbrMode"),
{
ByColumns,
{
XO("Off"),
XO("On"),
XO("Constrained"),
},
{
wxT("off"),
wxT("on"),
wxT("constrained"),
}
},
1 // "On"
};
ChoiceSetting OPUSApplication
{
wxT("/FileFormats/OPUSApplication"),
{
ByColumns,
{
XO("VOIP"),
XO("Audio"),
XO("Low Delay"),
},
{
wxT("voip"),
wxT("audio"),
wxT("lowdelay"),
}
},
1 // "Audio"
};
ChoiceSetting OPUSFrameDuration
{
wxT("/FileFormats/OPUSFrameDuration"),
{
ByColumns,
{
XO("2.5 ms"),
XO("5 ms"),
XO("10 ms"),
XO("20 ms"),
XO("40 ms"),
XO("60 ms"),
},
{
wxT("2.5"),
wxT("5"),
wxT("10"),
wxT("20"),
wxT("40"),
wxT("60"),
}
},
3 // "20"
};
ChoiceSetting OPUSCutoff
{
wxT("/FileFormats/OPUSCutoff"),
{
ByColumns,
{
XO("Disabled"),
XO("Narrowband"),
XO("Mediumband"),
XO("Wideband"),
XO("Super Wideband"),
XO("Fullband"),
},
{
wxT("0"),
wxT("4000"),
wxT("6000"),
wxT("8000"),
wxT("12000"),
wxT("20000"),
}
},
0 // "Disabled"
};
}
ExportFFmpegOPUSOptions::ExportFFmpegOPUSOptions(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
TransferDataToWindow();
}
ExportFFmpegOPUSOptions::~ExportFFmpegOPUSOptions()
{
TransferDataFromWindow();
}
///
///
void ExportFFmpegOPUSOptions::PopulateOrExchange(ShuttleGui & S)
{
S.SetSizerProportion(1);
S.SetBorder(4);
S.StartVerticalLay();
{
S.StartHorizontalLay(wxCENTER);
{
S.StartMultiColumn(2, wxCENTER);
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(
XO("Bit Rate:"),
OPUSBitrate);
S.TieChoice(
XO("Compression"),
OPUSCompression);
S.TieChoice(
XO("Frame Duration:"),
OPUSFrameDuration);
}
S.EndMultiColumn();
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(
XO("Vbr Mode:"),
OPUSVbrMode);
S.TieChoice(
XO("Application:"),
OPUSApplication);
S.TieChoice(
XO("Cutoff:"),
OPUSCutoff);
}
S.EndMultiColumn();
}
S.EndMultiColumn();
}
S.EndHorizontalLay();
}
S.EndVerticalLay();
}
///
///
bool ExportFFmpegOPUSOptions::TransferDataToWindow()
{
return true;
}
///
///
bool ExportFFmpegOPUSOptions::TransferDataFromWindow()
{
ShuttleGui S(this, eIsSavingToPrefs);
PopulateOrExchange(S);
gPrefs->Flush();
return true;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// ExportFFmpegWMAOptions Class // ExportFFmpegWMAOptions Class
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1340,11 +1605,12 @@ ChoiceSetting AACProfiles { wxT("/FileFormats/FFmpegAACProfile"),
/// List of export types /// List of export types
ExposedFormat ExportFFmpegOptions::fmts[] = ExposedFormat ExportFFmpegOptions::fmts[] =
{ {
{FMT_M4A, wxT("M4A"), wxT("m4a"), wxT("ipod"), 48, AV_CANMETA, true, XO("M4A (AAC) Files (FFmpeg)"), AV_CODEC_ID_AAC, true}, {FMT_M4A, wxT("M4A"), wxT("m4a"), wxT("ipod"), 48, AV_CANMETA, true, XO("M4A (AAC) Files (FFmpeg)"), AV_CODEC_ID_AAC, true},
{FMT_AC3, wxT("AC3"), wxT("ac3"), wxT("ac3"), 7, AV_VERSION_INT(0,0,0), false, XO("AC3 Files (FFmpeg)"), AV_CODEC_ID_AC3, true}, {FMT_AC3, wxT("AC3"), wxT("ac3"), wxT("ac3"), 7, AV_VERSION_INT(0,0,0), false, XO("AC3 Files (FFmpeg)"), AV_CODEC_ID_AC3, true},
{FMT_AMRNB, wxT("AMRNB"), wxT("amr"), wxT("amr"), 1, AV_VERSION_INT(0,0,0), false, XO("AMR (narrow band) Files (FFmpeg)"), AV_CODEC_ID_AMR_NB, true}, {FMT_AMRNB, wxT("AMRNB"), wxT("amr"), wxT("amr"), 1, AV_VERSION_INT(0,0,0), false, XO("AMR (narrow band) Files (FFmpeg)"), AV_CODEC_ID_AMR_NB, true},
{FMT_WMA2, wxT("WMA"), wxT("wma"), wxT("asf"), 2, AV_VERSION_INT(52,53,0), false, XO("WMA (version 2) Files (FFmpeg)"), AV_CODEC_ID_WMAV2, true}, {FMT_OPUS, wxT("OPUS"), wxT("opus"), wxT("opus"), 255, AV_CANMETA, true, XO("OPUS (OggOpus) Files (FFmpeg)"), AV_CODEC_ID_OPUS, true},
{FMT_OTHER, wxT("FFMPEG"), wxT(""), wxT(""), 255, AV_CANMETA, true, XO("Custom FFmpeg Export"), AV_CODEC_ID_NONE, true} {FMT_WMA2, wxT("WMA"), wxT("wma"), wxT("asf"), 2, AV_VERSION_INT(52,53,0), false, XO("WMA (version 2) Files (FFmpeg)"), AV_CODEC_ID_WMAV2, true},
{FMT_OTHER, wxT("FFMPEG"), wxT(""), wxT(""), 255, AV_CANMETA, true, XO("Custom FFmpeg Export"), AV_CODEC_ID_NONE, true}
}; };
/// Sample rates supported by AAC encoder (must end with zero-element) /// Sample rates supported by AAC encoder (must end with zero-element)

View File

@ -36,6 +36,7 @@ enum FFmpegExposedFormat
FMT_M4A, FMT_M4A,
FMT_AC3, FMT_AC3,
FMT_AMRNB, FMT_AMRNB,
FMT_OPUS,
FMT_WMA2, FMT_WMA2,
FMT_OTHER, FMT_OTHER,
FMT_LAST FMT_LAST
@ -122,6 +123,40 @@ private:
int mBitRateFromChoice; int mBitRateFromChoice;
}; };
class ExportFFmpegOPUSOptions final : public wxPanelWrapper
{
public:
ExportFFmpegOPUSOptions(wxWindow *parent, int format);
~ExportFFmpegOPUSOptions();
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
static const int iOPUSSampleRates[];
private:
wxSlider *mBitRateSlider;
int mBitRateFromSlider;
wxChoice *mVbrChoice;
int mVbrFromChoice;
wxSlider *mComplexitySlider;
int mComplexityFromSlider;
wxChoice *mFramesizeChoice;
int mFramesizeFromChoice;
wxChoice *mApplicationChoice;
int mApplicationFromChoice;
wxChoice *mCuttoffChoice;
int mCutoffFromChoice;
};
class ExportFFmpegWMAOptions final : public wxPanelWrapper class ExportFFmpegWMAOptions final : public wxPanelWrapper
{ {
public: public: