29#include <wx/textctrl.h>
30#include <wx/listbox.h>
32#include <wx/spinctrl.h>
33#include <wx/combobox.h>
49#if defined(WIN32) && _MSC_VER < 1900
50#define snprintf _snprintf
53#if defined(USE_FFMPEG)
56#define FFMPEG_AUTO_RESAMPLE 1
68"Properly configured FFmpeg is required to proceed.\nYou can configure it at Preferences > Libraries."));
143 std::unique_ptr<BasicUI::ProgressDialog>& pDialog,
150 const Tags *metadata = NULL,
151 int subformat = 0)
override;
188 #define MAX_AUDIO_PACKET_SIZE (128 * 1024)
196 int avfver =
mFFmpeg ?
mFFmpeg->AVFormatVersion.GetIntVersion() : 0;
200 for (newfmt = 0; newfmt <
FMT_LAST; newfmt++)
207 auto avoformat =
mFFmpeg->GuessOutputFormat(shortname.mb_str(),
nullptr,
nullptr);
210 if (avoformat == NULL || avcodec == NULL)
239 if (canmeta && (canmeta ==
AV_CANMETA || canmeta <= avfver))
275 This->FreeResources();
277 std::unique_ptr<
ExportFFmpeg,
decltype(deleter)> cleanup{
this, deleter };
287 const auto path =
mName.GetFullPath();
292"FFmpeg : ERROR - Can't determine format description for file \"%s\".")
295 wxOK|wxCENTER|wxICON_EXCLAMATION );
304 XO(
"FFmpeg : ERROR - Can't allocate output format context."),
306 wxOK|wxCENTER|wxICON_EXCLAMATION);
318 XO(
"FFmpeg : ERROR - Can't add audio stream to output file \"%s\".")
321 wxOK|wxCENTER|wxICON_EXCLAMATION);
349 XO(
"FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d.")
350 .
Format(path,
static_cast<int>(result)),
352 wxOK|wxCENTER|wxICON_EXCLAMATION);
365 if (metadata == NULL)
383 XO(
"FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d.")
386 wxOK|wxCENTER|wxICON_EXCLAMATION);
399 if (lowrate && highrate)
401 if (rate < lowrate || rate > highrate)
424 std::unique_ptr<AVCodecWrapper> codec;
448 int q =
gPrefs->Read(
wxT(
"/FileFormats/AACQuality"),-99999);
477 options.
Set(
"b",
gPrefs->Read(
wxT(
"/FileFormats/OPUSBitRate"),
wxT(
"128000")), 0);
478 options.
Set(
"vbr",
gPrefs->Read(
wxT(
"/FileFormats/OPUSVbrMode"),
wxT(
"on")), 0);
479 options.
Set(
"compression_level",
gPrefs->Read(
wxT(
"/FileFormats/OPUSCompression"),
wxT(
"10")), 0);
480 options.
Set(
"frame_duration",
gPrefs->Read(
wxT(
"/FileFormats/OPUSFrameDuration"),
wxT(
"20")), 0);
481 options.
Set(
"application",
gPrefs->Read(
wxT(
"/FileFormats/OPUSApplication"),
wxT(
"audio")), 0);
482 options.
Set(
"cutoff",
gPrefs->Read(
wxT(
"/FileFormats/OPUSCutoff"),
wxT(
"0")), 0);
483 options.
Set(
"mapping_family",
mChannels <= 2 ?
"0" :
"255", 0);
504 gPrefs->Read(
wxT(
"/FileFormats/FFmpegLanguage"),
wxT(
"")), 0);
509 gPrefs->Read(
wxT(
"/FileFormats/FFmpegSampleRate"), (
long)0));
515 gPrefs->Read(
wxT(
"/FileFormats/FFmpegBitRate"), (
long)0));
519 .mb_str(wxConvUTF8));
522 gPrefs->Read(
wxT(
"/FileFormats/FFmpegQuality"), (
long)-99999));
524 gPrefs->Read(
wxT(
"/FileFormats/FFmpegCutOff"), (
long)0));
527 if (
gPrefs->Read(
wxT(
"/FileFormats/FFmpegBitReservoir"),
true))
528 options.
Set(
"reservoir",
"1", 0);
530 if (
gPrefs->Read(
wxT(
"/FileFormats/FFmpegVariableBlockLen"),
true))
535 gPrefs->Read(
wxT(
"/FileFormats/FFmpegCompLevel"), -1));
537 gPrefs->Read(
wxT(
"/FileFormats/FFmpegFrameSize"), (
long)0));
542 "lpc_coeff_precision",
543 gPrefs->Read(
wxT(
"/FileFormats/FFmpegLPCCoefPrec"), (
long)0));
545 "min_prediction_order",
546 gPrefs->Read(
wxT(
"/FileFormats/FFmpegMinPredOrder"), (
long)-1));
548 "max_prediction_order",
549 gPrefs->Read(
wxT(
"/FileFormats/FFmpegMaxPredOrder"), (
long)-1));
551 "min_partition_order",
552 gPrefs->Read(
wxT(
"/FileFormats/FFmpegMinPartOrder"), (
long)-1));
554 "max_partition_order",
555 gPrefs->Read(
wxT(
"/FileFormats/FFmpegMaxPartOrder"), (
long)-1));
557 "prediction_order_method",
558 gPrefs->Read(
wxT(
"/FileFormats/FFmpegPredOrderMethod"), (
long)0));
560 "muxrate",
gPrefs->Read(
wxT(
"/FileFormats/FFmpegMuxRate"), (
long)0));
563 gPrefs->Read(
wxT(
"/FileFormats/FFmpegPacketSize"), (
long)0));
565 codec =
mFFmpeg->CreateEncoder(
566 gPrefs->Read(
wxT(
"/FileFormats/FFmpegCodec")));
604 codec =
mFFmpeg->CreateEncoder(
"ac3_fixed");
618"FFmpeg cannot find audio codec 0x%x.\nSupport for this codec is probably not compiled in.")
619 .
Format(
static_cast<const unsigned int>(codecID.value)),
621 wxOK|wxCENTER|wxICON_EXCLAMATION);
625 if (codec->GetSampleFmts()) {
650 if (codec->GetSupportedSamplerates())
655 std::vector<int> rates;
658 while (codec->GetSupportedSamplerates()[i] &&
659 codec->GetSupportedSamplerates()[i] != 7350)
661 rates.push_back(codec->GetSupportedSamplerates()[i++]);
675 mSampleRate, 0, 0, codec->GetSupportedSamplerates()))
678 0,
mSampleRate, 0, 0, codec->GetSupportedSamplerates());
705 errmsg =
XO(
"The codec reported a generic error (EPERM)");
708 errmsg =
XO(
"The codec reported an invalid parameter (EINVAL)");
712 mFFmpeg->av_strerror(rc, buf,
sizeof(buf));
718 XO(
"Can't open audio codec \"%s\" (0x%x)\n\n%s")
719 .
Format(codec->GetName(), codecID.value, errmsg),
721 wxOK|wxCENTER|wxICON_EXCLAMATION);
731 wxT(
"FFmpeg : Audio Output Codec Frame Size: %d samples."),
746 XO(
"FFmpeg : ERROR - Can't allocate buffer to read into from audio FIFO."),
748 wxOK|wxCENTER|wxICON_EXCLAMATION
773 mFFmpeg->av_interleaved_write_frame(
777 XO(
"FFmpeg : ERROR - Couldn't write audio frame to output file."),
778 XO(
"FFmpeg Error"), wxOK | wxCENTER | wxICON_EXCLAMATION);
790 int i, ch, buffer_size, ret, got_output = 0;
793 std::unique_ptr<AVFrameWrapper> frame;
796 frame =
mFFmpeg->CreateAVFrameWrapper();
801 frame->SetSamplesCount(nb_samples);
805 buffer_size =
mFFmpeg->av_samples_get_buffer_size(
809 if (buffer_size < 0) {
811 XO(
"FFmpeg : ERROR - Could not get sample buffer size"),
813 wxOK|wxCENTER|wxICON_EXCLAMATION
818 samples =
mFFmpeg->CreateMemoryBuffer<uint8_t>(buffer_size);
820 if (samples.empty()) {
822 XO(
"FFmpeg : ERROR - Could not allocate bytes for samples buffer"),
824 wxOK|wxCENTER|wxICON_EXCLAMATION
830 ret =
mFFmpeg->avcodec_fill_audio_frame(
836 XO(
"FFmpeg : ERROR - Could not setup audio frame"),
838 wxOK|wxCENTER|wxICON_EXCLAMATION
847 for (i = 0; i < nb_samples; i++) {
852 ((uint8_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount]/258 + 128;
855 ((uint8_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount]/258 + 128;
858 ((int16_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount];
861 ((int16_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount];
864 ((int32_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount]<<16;
867 ((int32_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount]<<16;
870 ((
float*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount] / 32767.0;
873 ((
float*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount] / 32767.;
887 if (
mFFmpeg->avcodec_send_frame !=
nullptr)
889 ret =
mFFmpeg->avcodec_send_frame(
891 frame ? frame->GetWrappedValue() :
nullptr);
895 ret =
mFFmpeg->avcodec_receive_packet(
914 ret =
mFFmpeg->avcodec_encode_audio2(
916 frame ? frame->GetWrappedValue() :
nullptr, &got_output);
927 XO(
"FFmpeg : ERROR - encoding frame failed"),
929 wxOK|wxCENTER|wxICON_EXCLAMATION
933 mFFmpeg->av_strerror(ret, buf,
sizeof(buf));
950 std::unique_ptr<AVPacketWrapper> pkt =
mFFmpeg->CreateAVPacketWrapper();
952 const int nFifoBytes =
mFFmpeg->av_fifo_size(
955 int encodeResult = 0;
965 XO(
"FFmpeg : ERROR - Too much remaining data."),
967 wxOK | wxCENTER | wxICON_EXCLAMATION
982 frame_size = nFifoBytes /
986 wxLogDebug(
wxT(
"FFmpeg : Audio FIFO still contains %d bytes, writing %d sample frame ..."),
987 nFifoBytes, frame_size);
1001 wxLogDebug(
wxT(
"FFmpeg : Reading from Audio FIFO failed, aborting"));
1014 if (encodeResult < 0) {
1019 else if (encodeResult == 0)
1042 int nBytesToWrite = 0;
1043 uint8_t *pRawSamples =
nullptr;
1047 nBytesToWrite = frameSize;
1048 pRawSamples = (uint8_t*)pFrame;
1055 ret =
mFFmpeg->av_fifo_generic_write(
1056 mEncAudioFifo->GetWrappedValue(), pRawSamples, nBytesToWrite,
nullptr);
1058 if (ret != nBytesToWrite) {
1065 XO(
"FFmpeg : ERROR - nAudioFrameSizeOut too large."),
1067 wxOK|wxCENTER|wxICON_EXCLAMATION
1075 ret =
mFFmpeg->av_fifo_generic_read(
1077 nAudioFrameSizeOut,
nullptr);
1079 std::unique_ptr<AVPacketWrapper> pkt =
mFFmpeg->CreateAVPacketWrapper();
1089 XO(
"FFmpeg : ERROR - Can't encode audio frame."),
1091 wxOK|wxCENTER|wxICON_EXCLAMATION
1101 AudacityProject* project, std::unique_ptr<BasicUI::ProgressDialog>& pDialog,
1103 bool selectionOnly,
double t0,
double t1,
1115"Attempted to export %d channels, but maximum number of channels for selected output format is %d")
1134 shortname =
gPrefs->Read(
wxT(
"/FileFormats/FFmpegFormat"),
wxT(
"matroska"));
1135 ret =
Init(shortname.mb_str(),project, metadata, subformat);
1148 channels, pcmBufferSize,
true,
1155 ?
XO(
"Exporting selected audio as %s")
1157 :
XO(
"Exporting the audio as %s")
1159 auto &progress = *pDialog;
1162 auto pcmNumSamples = mixer->Process();
1163 if (pcmNumSamples == 0)
1166 short *pcmBuffer = (
short *)mixer->GetBuffer();
1169 pcmBuffer, (pcmNumSamples)*
sizeof(int16_t)*
mChannels)) {
1176 updateResult = progress.Poll(mixer->MixGetCurrentTime() - t0, t1 - t0);
1187 return updateResult;
1193 memcpy(
field,value.ToUTF8(),(
int)strlen(value.ToUTF8()) >
size -1 ?
size -1 : strlen(value.ToUTF8()));
1199 memcpy(
field,value.mb_str(),(
int)strlen(value.mb_str()) >
size -1 ?
size -1 : strlen(value.mb_str()));
1234 wxString value = tags->
GetTag(tag);
1250#if defined(FFMPEG_AUTO_RESAMPLE)
1251 std::vector<int> rates;
1258 std::sort(rates.begin(), rates.end());
1261 for (
auto i : rates)
1279 S.StartVerticalLay();
1282 S.StartStatic(
XO(
"Resample"));
1284 S.StartHorizontalLay(wxALIGN_CENTER,
false);
1289"The project sample rate (%d) is not supported by the current output\nfile format. ")
1292"The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the current output file format. ")
1293 .
Format( rate, bitrate/1000))
1294 +
XO(
"You may resample to one of the rates below.")
1297 S.EndHorizontalLay();
1299 S.StartHorizontalLay(wxALIGN_CENTER,
false);
1301 choice =
S.AddChoice(
XO(
"Sample Rates"),
1307 if ((!lowrate ||
label >= lowrate) && (!highrate ||
label <= highrate))
1317 std::max( 0, selected )
1320 S.EndHorizontalLay();
1324 S.AddStandardButtons();
1330 d.SetMinSize(d.GetSize());
1333 if (d.ShowModal() == wxID_CANCEL) {
1337 return wxAtoi(choice->GetStringSelection());
1386 []{
return std::make_unique< ExportFFmpeg >(); }
@ AUDACITY_AV_CODEC_ID_AC3
@ AUDACITY_AV_CODEC_ID_AAC
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const TranslatableString name
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption, bool allowReporting)
#define MAX_AUDIO_PACKET_SIZE
static Exporter::RegisteredExportPlugin sRegisteredPlugin
void AddStringTagUTF8(char field[], int size, wxString value)
static bool CheckFFmpegPresence(bool quiet=false)
void AddStringTagANSI(char field[], int size, wxString value)
static int AdjustFormatIndex(int format)
static const std::vector< int > sampRates
bool FindFFmpegLibs(wxWindow *parent)
bool LoadFFmpeg(bool showerror)
std::vector< T, AVAllocator< T > > AVDataBuffer
#define AUDACITY_FF_PROFILE_AAC_LOW
#define AUDACITY_AV_CODEC_CAP_SMALL_LAST_FRAME
#define AUDACITY_AV_CODEC_FLAG_GLOBAL_HEADER
#define AUDACITY_AVERROR(e)
#define AUDACITY_FF_COMPLIANCE_EXPERIMENTAL
#define AUDACITY_AVERROR_EOF
#define AUDACITY_FF_QP2LAMBDA
#define AUDACITY_AV_CODEC_FLAG_QSCALE
#define AUDACITY_AVFMT_GLOBALHEADER
#define AUDACITY_AV_NOPTS_VALUE
#define AUDACITY_AVFMT_NOFILE
@ AUDACITY_AV_SAMPLE_FMT_S32P
signed 32 bits, planar
@ AUDACITY_AV_SAMPLE_FMT_S16P
signed 16 bits, planar
@ AUDACITY_AV_SAMPLE_FMT_FLTP
float, planar
@ AUDACITY_AV_SAMPLE_FMT_NONE
@ AUDACITY_AV_SAMPLE_FMT_S16
signed 16 bits
@ AUDACITY_AV_SAMPLE_FMT_S32
signed 32 bits
@ AUDACITY_AV_SAMPLE_FMT_FLT
float
@ AUDACITY_AV_SAMPLE_FMT_U8
unsigned 8 bits
@ AUDACITY_AV_SAMPLE_FMT_U8P
unsigned 8 bits, planar
an object holding per-project preferred sample rate
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
void Set(const std::string_view &key, const std::string &value, int flags=0) noexcept
virtual void ResetData() noexcept=0
virtual void SetStreamIndex(int index) noexcept=0
virtual int GetDuration() const noexcept=0
virtual void RescalePresentationTimestamp(AudacityAVRational bq, AudacityAVRational cq) noexcept=0
virtual int64_t GetDecompressionTimestamp() const noexcept=0
AVPacket * GetWrappedValue() noexcept
virtual void RescaleDecompressionTimestamp(AudacityAVRational bq, AudacityAVRational cq) noexcept=0
virtual void RescaleDuration(AudacityAVRational bq, AudacityAVRational cq) noexcept=0
virtual int64_t GetPresentationTimestamp() const noexcept=0
virtual void ResetTimestamps() noexcept=0
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Options dialog for FFmpeg exporting of AAC format.
AC3 export options dialog.
static const int iAC3SampleRates[]
Options dialog for FFmpeg exporting of AMRNB format.
Controlling class for FFmpeg exporting. Creates the options dialog of the appropriate type,...
bool AddTags(const Tags *metadata)
Writes metadata.
std::unique_ptr< AVCodecContextWrapper > mEncAudioCodecCtx
std::unique_ptr< AVOutputFormatWrapper > mEncFormatDesc
bool EncodeAudioFrame(int16_t *pFrame, size_t frameSize)
Encodes audio.
int EncodeAudio(AVPacketWrapper &pkt, int16_t *audio_samples, int nb_samples)
void OptionsCreate(ShuttleGui &S, int format) override
bool CheckSampleRate(int rate, int lowrate, int highrate, const int *sampRates)
Check whether or not current project sample rate is compatible with the export codec.
bool CheckFileName(wxFileName &filename, int format=0) override
Callback, called from GetFilename.
bool Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat)
Format initialization.
std::unique_ptr< AVFifoBufferWrapper > mEncAudioFifo
ProgressResult Export(AudacityProject *project, std::unique_ptr< BasicUI::ProgressDialog > &pDialog, unsigned channels, const wxFileNameWrapper &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0) override
bool WritePacket(AVPacketWrapper &packet)
int mEncAudioFifoOutBufSize
std::unique_ptr< AVStreamWrapper > mEncAudioStream
bool Finalize()
Flushes audio encoder.
std::unique_ptr< AVFormatContextWrapper > mEncFormatCtx
std::shared_ptr< FFmpegFunctions > mFFmpeg
bool InitCodecs(AudacityProject *project)
Codec initialization.
int AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates)
Asks user to resample the project or cancel the export procedure.
void SetMetadata(const Tags *tags, const char *name, const wxChar *tag)
Sets individual metadata values.
AVDataBuffer< int16_t > mEncAudioFifoOutBuf
Options dialog for FFmpeg exporting of OPUS format.
static ExposedFormat fmts[]
List of export types.
Options dialog for FFmpeg exporting of WMA format.
static const int iWMASampleRates[]
virtual void OptionsCreate(ShuttleGui &S, int format)=0
void AddExtension(const FileExtension &extension, int index)
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
static void InitProgress(std::unique_ptr< BasicUI::ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
void SetFormat(const wxString &format, int index)
std::unique_ptr< Mixer > CreateMixer(const TrackList &tracks, bool selectionOnly, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, MixerSpec *mixerSpec)
void SetDescription(const TranslatableString &description, int index)
void SetCanMetaData(bool canmetadata, int index)
virtual bool GetCanMetaData(int index)
void SetMaxChannels(unsigned maxchannels, unsigned index)
A matrix of booleans, one row per input channel, column per output.
static ProjectRate & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
void SetName(const TranslatableString &title)
static std::shared_ptr< FFmpegFunctions > Load(bool fromUserPathOnly=false)