Audacity 3.2.0
ExportFFmpeg.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ExportFFmpeg.cpp
6
7 Audacity(R) is copyright (c) 1999-2009 Audacity Team.
8 License: GPL v2 or later. See License.txt.
9
10 LRN
11
12******************************************************************//*******************************************************************/
20
21
22
23
24#include "../FFmpeg.h"
25#include "FFmpegFunctions.h"
26
27#include <wx/choice.h>
28#include <wx/log.h>
29#include <wx/intl.h>
30#include <wx/timer.h>
31#include <wx/string.h>
32#include <wx/textctrl.h>
33#include <wx/listbox.h>
34#include <wx/window.h>
35#include <wx/spinctrl.h>
36#include <wx/combobox.h>
37
38#include "Mix.h"
39#include "ProjectRate.h"
40#include "ProjectSettings.h"
41#include "../Tags.h"
42#include "Track.h"
43#include "../widgets/AudacityMessageBox.h"
44#include "../widgets/ProgressDialog.h"
45#include "wxFileNameWrapper.h"
46
47#include "Export.h"
48
49#include "ExportFFmpegDialogs.h"
50#include "SelectFile.h"
51
52#if defined(WIN32) && _MSC_VER < 1900
53#define snprintf _snprintf
54#endif
55
56#if defined(USE_FFMPEG)
57
58// Define this to automatically resample audio to the nearest supported sample rate
59#define FFMPEG_AUTO_RESAMPLE 1
60
61static bool CheckFFmpegPresence(bool quiet = false)
62{
63 bool result = true;
64 auto ffmpeg = FFmpegFunctions::Load();
65
66 if (!ffmpeg)
67 {
68 if (!quiet)
69 {
71"Properly configured FFmpeg is required to proceed.\nYou can configure it at Preferences > Libraries."));
72 }
73 result = false;
74 }
75
76 return result;
77}
78
80{
81 int subFormat = -1;
82 for (int i = 0; i <= FMT_OTHER; i++)
83 {
84 if (ExportFFmpegOptions::fmts[i].compiledIn) subFormat++;
85 if (subFormat == format || i == FMT_OTHER)
86 {
87 subFormat = i;
88 break;
89 }
90 }
91 return subFormat;
92}
93
94//----------------------------------------------------------------------------
95// ExportFFmpeg
96//----------------------------------------------------------------------------
97
98class ExportFFmpeg final : public ExportPlugin
99{
100public:
101
102 ExportFFmpeg();
103 ~ExportFFmpeg() override;
104
106 bool CheckFileName(wxFileName &filename, int format = 0) override;
107
109 bool Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat);
110
112 bool AddTags(const Tags *metadata);
113
115 void SetMetadata(const Tags *tags, const char *name, const wxChar *tag);
116
118 bool EncodeAudioFrame(int16_t *pFrame, size_t frameSize);
119
121 bool Finalize();
122
123 void FreeResources();
124
127 void OptionsCreate(ShuttleGui &S, int format) override;
128
130 bool CheckSampleRate(int rate, int lowrate, int highrate, const int *sampRates);
131
133 int AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates);
134
146 std::unique_ptr<ProgressDialog> &pDialog,
147 unsigned channels,
148 const wxFileNameWrapper &fName,
149 bool selectedOnly,
150 double t0,
151 double t1,
152 MixerSpec *mixerSpec = NULL,
153 const Tags *metadata = NULL,
154 int subformat = 0) override;
155
156private:
158 bool InitCodecs(AudacityProject* project);
159
160 std::shared_ptr<FFmpegFunctions> mFFmpeg;
161
162 std::unique_ptr<AVOutputFormatWrapper> mEncFormatDesc; // describes our output file to libavformat
164 std::unique_ptr<AVStreamWrapper> mEncAudioStream; // the output audio stream (may remain NULL)
166
168
170 int mBitRate{};
172 unsigned mChannels{};
174
175 // Smart pointer fields, their order is the reverse in which they are reset in FreeResources():
176 std::unique_ptr<AVFifoBufferWrapper> mEncAudioFifo; // FIFO to write incoming audio samples into
177 AVDataBuffer<int16_t> mEncAudioFifoOutBuf; // buffer to read _out_ of the FIFO into
178 std::unique_ptr<AVFormatContextWrapper> mEncFormatCtx; // libavformat's context for our output file
179 std::unique_ptr<AVCodecContextWrapper> mEncAudioCodecCtx; // the encoder for the output audio stream
180};
181
183: ExportPlugin()
184{
185 mEncFormatDesc = NULL; // describes our output file to libavformat
186 mEncAudioStream = NULL; // the output audio stream (may remain NULL)
187 #define MAX_AUDIO_PACKET_SIZE (128 * 1024)
189
190 mSampleRate = 0;
191 mSupportsUTF8 = true;
192
194
195 int avfver = mFFmpeg ? mFFmpeg->AVFormatVersion.GetIntVersion() : 0;
196
197 int newfmt;
198 // Adds export types from the export type list
199 for (newfmt = 0; newfmt < FMT_LAST; newfmt++)
200 {
201 wxString shortname(ExportFFmpegOptions::fmts[newfmt].shortname);
202 // Don't hide export types when there's no av-libs, and don't hide FMT_OTHER
203 if (newfmt < FMT_OTHER && mFFmpeg)
204 {
205 // Format/Codec support is compiled in?
206 auto avoformat = mFFmpeg->GuessOutputFormat(shortname.mb_str(), nullptr, nullptr);
207 auto avcodec = mFFmpeg->CreateEncoder(mFFmpeg->GetAVCodecID(ExportFFmpegOptions::fmts[newfmt].codecid));
208
209 if (avoformat == NULL || avcodec == NULL)
210 {
212 continue;
213 }
214 }
215 int fmtindex = AddFormat() - 1;
216 SetFormat(ExportFFmpegOptions::fmts[newfmt].name,fmtindex);
217 AddExtension(ExportFFmpegOptions::fmts[newfmt].extension,fmtindex);
218 // For some types add other extensions
219 switch(newfmt)
220 {
221 case FMT_M4A:
222 AddExtension(wxT("3gp"),fmtindex);
223 AddExtension(wxT("m4r"),fmtindex);
224 AddExtension(wxT("mp4"),fmtindex);
225 break;
226 case FMT_WMA2:
227 AddExtension(wxT("asf"),fmtindex);
228 AddExtension(wxT("wmv"),fmtindex);
229 break;
230 default:
231 break;
232 }
233
234 SetMaxChannels(ExportFFmpegOptions::fmts[newfmt].maxchannels,fmtindex);
235 SetDescription(ExportFFmpegOptions::fmts[newfmt].description, fmtindex);
236
237 int canmeta = ExportFFmpegOptions::fmts[newfmt].canmetadata;
238 if (canmeta && (canmeta == AV_CANMETA || canmeta <= avfver))
239 {
240 SetCanMetaData(true,fmtindex);
241 }
242 else
243 {
244 SetCanMetaData(false,fmtindex);
245 }
246 }
247}
248
250{
251}
252
253bool ExportFFmpeg::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
254{
255 bool result = true;
256
257 // Show "Locate FFmpeg" dialog
258 if (!CheckFFmpegPresence(true))
259 {
262
263 return LoadFFmpeg(true);
264 }
265
266 return result;
267}
268
269bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat)
270{
271 // This will undo the acquisition of resources along any early exit path:
272 auto deleter = [](ExportFFmpeg *This) {
273 if (This)
274 This->FreeResources();
275 };
276 std::unique_ptr<ExportFFmpeg, decltype(deleter)> cleanup{ this, deleter };
277 //FFmpegLibsInst()->LoadLibs(NULL,true); //Loaded at startup or from Prefs now
278
279 if (!mFFmpeg)
280 return false;
281
282
283 // See if libavformat has modules that can write our output format. If so, mEncFormatDesc
284 // will describe the functions used to write the format (used internally by libavformat)
285 // and the default video/audio codecs that the format uses.
286 const auto path = mName.GetFullPath();
287 if ((mEncFormatDesc = mFFmpeg->GuessOutputFormat(shortname, OSINPUT(path), nullptr)) == nullptr)
288 {
290 XO(
291"FFmpeg : ERROR - Can't determine format description for file \"%s\".")
292 .Format( path ),
293 XO("FFmpeg Error"),
294 wxOK|wxCENTER|wxICON_EXCLAMATION );
295 return false;
296 }
297
298 // mEncFormatCtx is used by libavformat to carry around context data re our output file.
299 mEncFormatCtx = mFFmpeg->CreateAVFormatContext();
300 if (!mEncFormatCtx)
301 {
303 XO("FFmpeg : ERROR - Can't allocate output format context."),
304 XO("FFmpeg Error"),
305 wxOK|wxCENTER|wxICON_EXCLAMATION);
306 return false;
307 }
308
309 // Initialise the output format context.
310 mEncFormatCtx->SetOutputFormat(mFFmpeg->CreateAVOutputFormatWrapper(mEncFormatDesc->GetWrappedValue()));
311 mEncFormatCtx->SetFilename(OSINPUT(path));
312
313 // At the moment Audacity can export only one audio stream
314 if ((mEncAudioStream = mEncFormatCtx->CreateStream()) == nullptr)
315 {
317 XO("FFmpeg : ERROR - Can't add audio stream to output file \"%s\".")
318 .Format( path ),
319 XO("FFmpeg Error"),
320 wxOK|wxCENTER|wxICON_EXCLAMATION);
321 return false;
322 }
323
324 // Documentation for avformat_new_stream says
325 // "User is required to call avcodec_close() and avformat_free_context() to clean
326 // up the allocation by avformat_new_stream()."
327
328 // We use smart pointers that ensure these cleanups either in their destructors or
329 // sooner if they are reset. These are std::unique_ptr with nondefault deleter
330 // template parameters.
331
332 // mEncFormatCtx takes care of avformat_free_context(), so
333 // mEncAudioStream can be a plain pointer.
334
335 // mEncAudioCodecCtx now becomes responsible for closing the codec:
336 mEncAudioCodecCtx = mEncAudioStream->GetAVCodecContext();
337 mEncAudioStream->SetId(0);
338
339 // Open the output file.
340 if (!(mEncFormatDesc->GetFlags() & AUDACITY_AVFMT_NOFILE))
341 {
343 mEncFormatCtx->OpenOutputContext(path);
344
346 {
348 XO("FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d.")
349 .Format(path, static_cast<int>(result)),
350 XO("FFmpeg Error"),
351 wxOK|wxCENTER|wxICON_EXCLAMATION);
352
353 return false;
354 }
355 }
356
357 // Open the audio stream's codec and initialise any stream related data.
358 if (!InitCodecs(project))
359 return false;
360
361 if (metadata == NULL)
362 metadata = &Tags::Get( *project );
363
364 // Add metadata BEFORE writing the header.
365 // At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4.
366 if (GetCanMetaData(subformat))
367 {
369 AddTags(metadata);
370 }
371
372 // Write headers to the output file.
373 int err =
374 mFFmpeg->avformat_write_header(mEncFormatCtx->GetWrappedValue(), nullptr);
375
376 if (err < 0)
377 {
379 XO("FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d.")
380 .Format( path, err ),
381 XO("FFmpeg Error"),
382 wxOK|wxCENTER|wxICON_EXCLAMATION);
383 return false;
384 }
385
386 // Only now, we can keep all the resources until after Finalize().
387 // Cancel the local cleanup.
388 cleanup.release();
389
390 return true;
391}
392
393bool ExportFFmpeg::CheckSampleRate(int rate, int lowrate, int highrate, const int *sampRates)
394{
395 if (lowrate && highrate)
396 {
397 if (rate < lowrate || rate > highrate)
398 {
399 return false;
400 }
401 }
402
403 if (sampRates)
404 {
405 for (int i = 0; sampRates[i] > 0; i++)
406 {
407 if (rate == sampRates[i])
408 {
409 return true;
410 }
411 }
412 }
413
414 return false;
415}
416
418{
419 const auto &settings = ProjectSettings::Get( *project );
420 std::unique_ptr<AVCodecWrapper> codec;
421
423
424 // Get the sample rate from the passed settings if we haven't set it before.
425 // Doing this only when not set allows us to carry the sample rate from one
426 // iteration of ExportMultiple to the next. This prevents multiple resampling
427 // dialogs in the event the codec can't support the specified rate.
428 if (!mSampleRate)
429 {
430 mSampleRate = (int)ProjectRate::Get(*project).GetRate();
431 }
432
433 // Configure the audio stream's codec context.
434
435 const auto codecID = ExportFFmpegOptions::fmts[mSubFormat].codecid;
436
437 mEncAudioCodecCtx->SetGlobalQuality(-99999); //quality mode is off by default;
438
439 // Each export type has its own settings
440 switch (mSubFormat)
441 {
442 case FMT_M4A:
443 {
444 int q = gPrefs->Read(wxT("/FileFormats/AACQuality"),-99999);
445 mEncAudioCodecCtx->SetGlobalQuality(q);
446
447 q = wxClip( q, 98 * mChannels, 160 * mChannels );
448 // Set bit rate to between 98 kbps and 320 kbps (if two channels)
449 mEncAudioCodecCtx->SetBitRate(q * 1000);
451 mEncAudioCodecCtx->SetCutoff(0);
452
453 break;
454 }
455 case FMT_AC3:
456 mEncAudioCodecCtx->SetBitRate(gPrefs->Read(wxT("/FileFormats/AC3BitRate"), 192000));
457 if (!CheckSampleRate(
461 {
463 mEncAudioCodecCtx->GetBitRate(), mSampleRate,
467 }
468 break;
469 case FMT_AMRNB:
470 mSampleRate = 8000;
471 mEncAudioCodecCtx->SetBitRate(gPrefs->Read(wxT("/FileFormats/AMRNBBitRate"), 12200));
472 break;
473 case FMT_OPUS:
474 options.Set("b", gPrefs->Read(wxT("/FileFormats/OPUSBitRate"), wxT("128000")), 0);
475 options.Set("vbr", gPrefs->Read(wxT("/FileFormats/OPUSVbrMode"), wxT("on")), 0);
476 options.Set("compression_level", gPrefs->Read(wxT("/FileFormats/OPUSCompression"), wxT("10")), 0);
477 options.Set("frame_duration", gPrefs->Read(wxT("/FileFormats/OPUSFrameDuration"), wxT("20")), 0);
478 options.Set("application", gPrefs->Read(wxT("/FileFormats/OPUSApplication"), wxT("audio")), 0);
479 options.Set("cutoff", gPrefs->Read(wxT("/FileFormats/OPUSCutoff"), wxT("0")), 0);
480 options.Set("mapping_family", mChannels <= 2 ? "0" : "255", 0);
481 break;
482 case FMT_WMA2:
483 mEncAudioCodecCtx->SetBitRate(gPrefs->Read(wxT("/FileFormats/WMABitRate"), 198000));
484 if (!CheckSampleRate(
488 {
490 mEncAudioCodecCtx->GetBitRate(), mSampleRate,
494 }
495 break;
496 case FMT_OTHER:
497 {
498 AVDictionaryWrapper streamMetadata = mEncAudioStream->GetMetadata();
499 streamMetadata.Set(
500 "language",
501 gPrefs->Read(wxT("/FileFormats/FFmpegLanguage"), wxT("")), 0);
502
503 mEncAudioStream->SetMetadata(streamMetadata);
504
505 mEncAudioCodecCtx->SetSampleRate(
506 gPrefs->Read(wxT("/FileFormats/FFmpegSampleRate"), (long)0));
507
508 if (mEncAudioCodecCtx->GetSampleRate() != 0)
509 mSampleRate = mEncAudioCodecCtx->GetSampleRate();
510
511 mEncAudioCodecCtx->SetBitRate(
512 gPrefs->Read(wxT("/FileFormats/FFmpegBitRate"), (long)0));
513
514 mEncAudioCodecCtx->SetCodecTagFourCC(
515 gPrefs->Read(wxT("/FileFormats/FFmpegTag"), wxT(""))
516 .mb_str(wxConvUTF8));
517
518 mEncAudioCodecCtx->SetGlobalQuality(
519 gPrefs->Read(wxT("/FileFormats/FFmpegQuality"), (long)-99999));
520 mEncAudioCodecCtx->SetCutoff(
521 gPrefs->Read(wxT("/FileFormats/FFmpegCutOff"), (long)0));
522 mEncAudioCodecCtx->SetFlags2(0);
523
524 if (gPrefs->Read(wxT("/FileFormats/FFmpegBitReservoir"), true))
525 options.Set("reservoir", "1", 0);
526
527 if (gPrefs->Read(wxT("/FileFormats/FFmpegVariableBlockLen"), true))
528 mEncAudioCodecCtx->SetFlags2(
529 mEncAudioCodecCtx->GetFlags2() | 0x0004); // WMA only?
530
531 mEncAudioCodecCtx->SetCompressionLevel(
532 gPrefs->Read(wxT("/FileFormats/FFmpegCompLevel"), -1));
533 mEncAudioCodecCtx->SetFrameSize(
534 gPrefs->Read(wxT("/FileFormats/FFmpegFrameSize"), (long)0));
535
536 // FIXME The list of supported options for the selected encoder should be
537 // extracted instead of a few hardcoded
538 options.Set(
539 "lpc_coeff_precision",
540 gPrefs->Read(wxT("/FileFormats/FFmpegLPCCoefPrec"), (long)0));
541 options.Set(
542 "min_prediction_order",
543 gPrefs->Read(wxT("/FileFormats/FFmpegMinPredOrder"), (long)-1));
544 options.Set(
545 "max_prediction_order",
546 gPrefs->Read(wxT("/FileFormats/FFmpegMaxPredOrder"), (long)-1));
547 options.Set(
548 "min_partition_order",
549 gPrefs->Read(wxT("/FileFormats/FFmpegMinPartOrder"), (long)-1));
550 options.Set(
551 "max_partition_order",
552 gPrefs->Read(wxT("/FileFormats/FFmpegMaxPartOrder"), (long)-1));
553 options.Set(
554 "prediction_order_method",
555 gPrefs->Read(wxT("/FileFormats/FFmpegPredOrderMethod"), (long)0));
556 options.Set(
557 "muxrate", gPrefs->Read(wxT("/FileFormats/FFmpegMuxRate"), (long)0));
558
559 mEncFormatCtx->SetPacketSize(
560 gPrefs->Read(wxT("/FileFormats/FFmpegPacketSize"), (long)0));
561
562 codec = mFFmpeg->CreateEncoder(
563 gPrefs->Read(wxT("/FileFormats/FFmpegCodec")));
564
565 if (!codec)
566 codec = mFFmpeg->CreateEncoder(mEncFormatDesc->GetAudioCodec());
567 }
568 break;
569 default:
570 return false;
571 }
572
573 // This happens if user refused to resample the project
574 if (mSampleRate == 0) return false;
575
576 if (mEncAudioCodecCtx->GetGlobalQuality() >= 0)
577 {
578 mEncAudioCodecCtx->SetFlags(
580 }
581 else
582 {
583 mEncAudioCodecCtx->SetGlobalQuality(0);
584 }
585
586 mEncAudioCodecCtx->SetGlobalQuality(mEncAudioCodecCtx->GetGlobalQuality() * AUDACITY_FF_QP2LAMBDA);
587 mEncAudioCodecCtx->SetSampleRate(mSampleRate);
588 mEncAudioCodecCtx->SetChannels(mChannels);
589 mEncAudioCodecCtx->SetChannelLayout(mFFmpeg->av_get_default_channel_layout(mChannels));
590 mEncAudioCodecCtx->SetTimeBase({ 1, mSampleRate });
592 mEncAudioCodecCtx->SetStrictStdCompliance(
594
595 if (codecID == AUDACITY_AV_CODEC_ID_AC3)
596 {
597 // As of Jan 4, 2011, the default AC3 encoder only accept SAMPLE_FMT_FLT samples.
598 // But, currently, Audacity only supports SAMPLE_FMT_S16. So, for now, look for the
599 // "older" AC3 codec. this is not a proper solution, but will suffice until other
600 // encoders no longer support SAMPLE_FMT_S16.
601 codec = mFFmpeg->CreateEncoder("ac3_fixed");
602 }
603
604 if (!codec)
605 {
606 codec = mFFmpeg->CreateEncoder(mFFmpeg->GetAVCodecID(codecID));
607 }
608
609 // Is the required audio codec compiled into libavcodec?
610 if (codec == NULL)
611 {
613 XO(
614/* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
615"FFmpeg cannot find audio codec 0x%x.\nSupport for this codec is probably not compiled in.")
616 .Format(static_cast<const unsigned int>(codecID.value)),
617 XO("FFmpeg Error"),
618 wxOK|wxCENTER|wxICON_EXCLAMATION);
619 return false;
620 }
621
622 if (codec->GetSampleFmts()) {
623 for (int i = 0; codec->GetSampleFmts()[i] != AUDACITY_AV_SAMPLE_FMT_NONE; i++)
624 {
625 AVSampleFormatFwd fmt = codec->GetSampleFmts()[i];
626
627 if (
636 {
637 mEncAudioCodecCtx->SetSampleFmt(fmt);
638 }
639
640 if (
643 break;
644 }
645 }
646
647 if (codec->GetSupportedSamplerates())
648 {
649 // Workaround for crash in bug #2378. Proper fix is to get a newer version of FFmpeg.
650 if (codec->GetId() == mFFmpeg->GetAVCodecID(AUDACITY_AV_CODEC_ID_AAC))
651 {
652 std::vector<int> rates;
653 int i = 0;
654
655 while (codec->GetSupportedSamplerates()[i] &&
656 codec->GetSupportedSamplerates()[i] != 7350)
657 {
658 rates.push_back(codec->GetSupportedSamplerates()[i++]);
659 }
660
661 rates.push_back(0);
662
663 if (!CheckSampleRate(mSampleRate, 0, 0, rates.data()))
664 {
665 mSampleRate = AskResample(0, mSampleRate, 0, 0, rates.data());
666 mEncAudioCodecCtx->SetSampleRate(mSampleRate);
667 }
668 }
669 else
670 {
671 if (!CheckSampleRate(
672 mSampleRate, 0, 0, codec->GetSupportedSamplerates()))
673 {
675 0, mSampleRate, 0, 0, codec->GetSupportedSamplerates());
676 mEncAudioCodecCtx->SetSampleRate(mSampleRate);
677 }
678 }
679
680 // This happens if user refused to resample the project
681 if (mSampleRate == 0)
682 {
683 return false;
684 }
685 }
686
687 if (mEncFormatCtx->GetOutputFormat()->GetFlags() & AUDACITY_AVFMT_GLOBALHEADER)
688 {
691 }
692
693 // Open the codec.
694 int rc = mEncAudioCodecCtx->Open(codec.get(), &options);
695 if (rc < 0)
696 {
697 TranslatableString errmsg;
698
699 switch (rc)
700 {
701 case AUDACITY_AVERROR(EPERM):
702 errmsg = XO("The codec reported a generic error (EPERM)");
703 break;
704 case AUDACITY_AVERROR(EINVAL):
705 errmsg = XO("The codec reported an invalid parameter (EINVAL)");
706 break;
707 default:
708 char buf[64];
709 mFFmpeg->av_strerror(rc, buf, sizeof(buf));
710 errmsg = Verbatim(buf);
711 }
712
714 /* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
715 XO("Can't open audio codec \"%s\" (0x%x)\n\n%s")
716 .Format(codec->GetName(), codecID.value, errmsg),
717 XO("FFmpeg Error"),
718 wxOK|wxCENTER|wxICON_EXCLAMATION);
719 return false;
720 }
721
722 mDefaultFrameSize = mEncAudioCodecCtx->GetFrameSize();
723
724 if (mDefaultFrameSize == 0)
725 mDefaultFrameSize = 1024; // arbitrary non zero value;
726
727 wxLogDebug(
728 wxT("FFmpeg : Audio Output Codec Frame Size: %d samples."),
729 mEncAudioCodecCtx->GetFrameSize());
730
731 // The encoder may require a minimum number of raw audio samples for each encoding but we can't
732 // guarantee we'll get this minimum each time an audio frame is decoded from the input file so
733 // we use a FIFO to store up incoming raw samples until we have enough for one call to the codec.
734 mEncAudioFifo = mFFmpeg->CreateFifoBuffer(mDefaultFrameSize);
735
737 // Allocate a buffer to read OUT of the FIFO into. The FIFO maintains its own buffer internally.
738 mEncAudioFifoOutBuf = mFFmpeg->CreateMemoryBuffer<int16_t>(mEncAudioFifoOutBufSize);
739
740 if (mEncAudioFifoOutBuf.empty())
741 {
743 XO("FFmpeg : ERROR - Can't allocate buffer to read into from audio FIFO."),
744 XO("FFmpeg Error"),
745 wxOK|wxCENTER|wxICON_EXCLAMATION
746 );
747 return false;
748 }
749
750 return true;
751}
752
753// Returns 0 if no more output, 1 if more output, negative if error
754static int encode_audio(const FFmpegFunctions& ffmpeg, AVCodecContextWrapper*avctx, AVPacketWrapper *pkt, int16_t *audio_samples, int nb_samples)
755{
756 // Assume *pkt is already initialized.
757
758 int i, ch, buffer_size, ret, got_output = 0;
759 AVDataBuffer<uint8_t> samples;
760
761 std::unique_ptr<AVFrameWrapper> frame;
762
763 if (audio_samples) {
764 frame = ffmpeg.CreateAVFrameWrapper();
765
766 if (!frame)
767 return AUDACITY_AVERROR(ENOMEM);
768
769 frame->SetSamplesCount(nb_samples);
770 frame->SetFormat(avctx->GetSampleFmt());
771 frame->SetChannelLayout(avctx->GetChannelLayout());
772
773 buffer_size = ffmpeg.av_samples_get_buffer_size(
774 NULL, avctx->GetChannels(), nb_samples, avctx->GetSampleFmt(), 0);
775
776 if (buffer_size < 0) {
778 XO("FFmpeg : ERROR - Could not get sample buffer size"),
779 XO("FFmpeg Error"),
780 wxOK|wxCENTER|wxICON_EXCLAMATION
781 );
782 return buffer_size;
783 }
784
785 samples = ffmpeg.CreateMemoryBuffer<uint8_t>(buffer_size);
786
787 if (samples.empty()) {
789 XO("FFmpeg : ERROR - Could not allocate bytes for samples buffer"),
790 XO("FFmpeg Error"),
791 wxOK|wxCENTER|wxICON_EXCLAMATION
792 );
793
794 return AUDACITY_AVERROR(ENOMEM);
795 }
796 /* setup the data pointers in the AVFrame */
797 ret = ffmpeg.avcodec_fill_audio_frame(
798 frame->GetWrappedValue(), avctx->GetChannels(), avctx->GetSampleFmt(),
799 samples.data(), buffer_size, 0);
800
801 if (ret < 0) {
803 XO("FFmpeg : ERROR - Could not setup audio frame"),
804 XO("FFmpeg Error"),
805 wxOK|wxCENTER|wxICON_EXCLAMATION
806 );
807 return ret;
808 }
809
810 const int channelsCount = avctx->GetChannels();
811
812 for (ch = 0; ch < avctx->GetChannels(); ch++) {
813 for (i = 0; i < nb_samples; i++) {
814 switch(static_cast<AudacityAVSampleFormat>(avctx->GetSampleFmt())) {
816 ((uint8_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount]/258 + 128;
817 break;
819 ((uint8_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount]/258 + 128;
820 break;
822 ((int16_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount];
823 break;
825 ((int16_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount];
826 break;
828 ((int32_t*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount]<<16;
829 break;
831 ((int32_t*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount]<<16;
832 break;
834 ((float*)(frame->GetData(0)))[ch + i*channelsCount] = audio_samples[ch + i*channelsCount] / 32767.0;
835 break;
837 ((float*)(frame->GetData(ch)))[i] = audio_samples[ch + i*channelsCount] / 32767.;
838 break;
839 default:
840 wxASSERT(false);
841 break;
842 }
843 }
844 }
845 }
846
847 pkt->ResetData();
848
849 ret = ffmpeg.avcodec_encode_audio2(
850 avctx->GetWrappedValue(), pkt->GetWrappedValue(),
851 frame ? frame->GetWrappedValue() : nullptr, &got_output);
852
853 if (ret < 0) {
855 XO("FFmpeg : ERROR - encoding frame failed"),
856 XO("FFmpeg Error"),
857 wxOK|wxCENTER|wxICON_EXCLAMATION
858 );
859
860 char buf[64];
861 ffmpeg.av_strerror(ret, buf, sizeof(buf));
862 wxLogDebug(buf);
863
864 return ret;
865 }
866
867 pkt->ResetTimestamps(); // We don't set frame timestamps thus don't trust the AVPacket timestamps
868
869 return got_output;
870}
871
872
874{
875 // Flush the audio FIFO and encoder.
876 for (;;)
877 {
878 std::unique_ptr<AVPacketWrapper> pkt = mFFmpeg->CreateAVPacketWrapper();
879
880 const int nFifoBytes = mFFmpeg->av_fifo_size(
881 mEncAudioFifo->GetWrappedValue()); // any bytes left in audio FIFO?
882
883 int encodeResult = 0;
884
885 // Flush the audio FIFO first if necessary. It won't contain a _full_ audio frame because
886 // if it did we'd have pulled it from the FIFO during the last encodeAudioFrame() call
887 if (nFifoBytes > 0)
888 {
889 const int nAudioFrameSizeOut = mDefaultFrameSize * mEncAudioCodecCtx->GetChannels() * sizeof(int16_t);
890
891 if (nAudioFrameSizeOut > mEncAudioFifoOutBufSize || nFifoBytes > mEncAudioFifoOutBufSize) {
893 XO("FFmpeg : ERROR - Too much remaining data."),
894 XO("FFmpeg Error"),
895 wxOK | wxCENTER | wxICON_EXCLAMATION
896 );
897 return false;
898 }
899
900 // We have an incomplete buffer of samples left, encode it.
901 // If codec supports CODEC_CAP_SMALL_LAST_FRAME, we can feed it with smaller frame
902 // Or if frame_size is 1, then it's some kind of PCM codec, they don't have frames and will be fine with the samples
903 // Otherwise we'll send a full frame of audio + silence padding to ensure all audio is encoded
904 int frame_size = mDefaultFrameSize;
905 if (
906 mEncAudioCodecCtx->GetCodec()->GetCapabilities() &
908 frame_size == 1)
909 {
910 frame_size = nFifoBytes /
911 (mEncAudioCodecCtx->GetChannels() * sizeof(int16_t));
912 }
913
914 wxLogDebug(wxT("FFmpeg : Audio FIFO still contains %d bytes, writing %d sample frame ..."),
915 nFifoBytes, frame_size);
916
917 // Fill audio buffer with zeroes. If codec tries to read the whole buffer,
918 // it will just read silence. If not - who cares?
920 //const AVCodec *codec = mEncAudioCodecCtx->codec;
921
922 // Pull the bytes out from the FIFO and feed them to the encoder.
923 if (mFFmpeg->av_fifo_generic_read(mEncAudioFifo->GetWrappedValue(), mEncAudioFifoOutBuf.data(), nFifoBytes, NULL) == 0)
924 {
925 encodeResult = encode_audio(*mFFmpeg, mEncAudioCodecCtx.get(), pkt.get(), mEncAudioFifoOutBuf.data(), frame_size);
926 }
927 else
928 {
929 wxLogDebug(wxT("FFmpeg : Reading from Audio FIFO failed, aborting"));
930 // TODO: more precise message
931 ShowExportErrorDialog("FFmpeg:825");
932 return false;
933 }
934 }
935 else
936 {
937 // Fifo is empty, flush encoder. May be called multiple times.
938 encodeResult =
939 encode_audio(*mFFmpeg, mEncAudioCodecCtx.get(), pkt.get(), NULL, 0);
940 }
941
942 if (encodeResult < 0) {
943 // TODO: more precise message
944 ShowExportErrorDialog("FFmpeg:837");
945 return false;
946 }
947 else if (encodeResult == 0)
948 break;
949
950 // We have a packet, send to the muxer
951 pkt->SetStreamIndex(mEncAudioStream->GetIndex());
952
953 // Set presentation time of frame (currently in the codec's timebase) in the stream timebase.
954 if (pkt->GetPresentationTimestamp() != AUDACITY_AV_NOPTS_VALUE)
955 pkt->RescalePresentationTimestamp(mEncAudioCodecCtx->GetTimeBase(), mEncAudioStream->GetTimeBase());
956
957 if (pkt->GetDecompressionTimestamp() != AUDACITY_AV_NOPTS_VALUE)
958 pkt->RescaleDecompressionTimestamp(mEncAudioCodecCtx->GetTimeBase(), mEncAudioStream->GetTimeBase());
959
960 if (pkt->GetDuration() > 0)
961 pkt->RescaleDuration(mEncAudioCodecCtx->GetTimeBase(), mEncAudioStream->GetTimeBase());
962
963 if (mFFmpeg->av_interleaved_write_frame(mEncFormatCtx->GetWrappedValue(), pkt->GetWrappedValue()) != 0)
964 {
966 XO("FFmpeg : ERROR - Couldn't write last audio frame to output file."),
967 XO("FFmpeg Error"),
968 wxOK | wxCENTER | wxICON_EXCLAMATION
969 );
970 return false;
971 }
972 }
973
974 // Write any file trailers.
975 if (mFFmpeg->av_write_trailer(mEncFormatCtx->GetWrappedValue()) != 0)
976 {
977 // TODO: more precise message
978 ShowExportErrorDialog("FFmpeg:868");
979 return false;
980 }
981
982 return true;
983}
984
986{
987
988}
989
990// All paths in this that fail must report their error to the user.
991bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, size_t frameSize)
992{
993 int nBytesToWrite = 0;
994 uint8_t *pRawSamples = nullptr;
995 int nAudioFrameSizeOut = mDefaultFrameSize * mEncAudioCodecCtx->GetChannels() * sizeof(int16_t);
996 int ret;
997
998 nBytesToWrite = frameSize;
999 pRawSamples = (uint8_t*)pFrame;
1000 if (mFFmpeg->av_fifo_realloc2(mEncAudioFifo->GetWrappedValue(), mFFmpeg->av_fifo_size(mEncAudioFifo->GetWrappedValue()) + frameSize) < 0) {
1001 ShowExportErrorDialog("FFmpeg:905");
1002 return false;
1003 }
1004
1005 // Put the raw audio samples into the FIFO.
1006 ret = mFFmpeg->av_fifo_generic_write(
1007 mEncAudioFifo->GetWrappedValue(), pRawSamples, nBytesToWrite, nullptr);
1008
1009 if (ret != nBytesToWrite) {
1010 ShowExportErrorDialog("FFmpeg:913");
1011 return false;
1012 }
1013
1014 if (nAudioFrameSizeOut > mEncAudioFifoOutBufSize) {
1016 XO("FFmpeg : ERROR - nAudioFrameSizeOut too large."),
1017 XO("FFmpeg Error"),
1018 wxOK|wxCENTER|wxICON_EXCLAMATION
1019 );
1020 return false;
1021 }
1022
1023 // Read raw audio samples out of the FIFO in nAudioFrameSizeOut byte-sized groups to encode.
1024 while (mFFmpeg->av_fifo_size(mEncAudioFifo->GetWrappedValue()) >= nAudioFrameSizeOut)
1025 {
1026 ret = mFFmpeg->av_fifo_generic_read(
1027 mEncAudioFifo->GetWrappedValue(), mEncAudioFifoOutBuf.data(),
1028 nAudioFrameSizeOut, nullptr);
1029
1030 std::unique_ptr<AVPacketWrapper> pkt = mFFmpeg->CreateAVPacketWrapper();
1031
1032 ret = encode_audio(
1033 *mFFmpeg, mEncAudioCodecCtx.get(),
1034 pkt.get(), // out
1035 mEncAudioFifoOutBuf.data(), // in
1037
1038 if (ret < 0)
1039 {
1041 XO("FFmpeg : ERROR - Can't encode audio frame."),
1042 XO("FFmpeg Error"),
1043 wxOK|wxCENTER|wxICON_EXCLAMATION
1044 );
1045 return false;
1046 }
1047 if (ret == 0)
1048 continue;
1049
1050 // Rescale from the codec time_base to the AVStream time_base.
1051 if (pkt->GetPresentationTimestamp() != AUDACITY_AV_NOPTS_VALUE)
1052 pkt->RescalePresentationTimestamp(mEncAudioCodecCtx->GetTimeBase(), mEncAudioStream->GetTimeBase());
1053
1054 if (pkt->GetDecompressionTimestamp() != AUDACITY_AV_NOPTS_VALUE)
1055 pkt->RescaleDecompressionTimestamp(mEncAudioCodecCtx->GetTimeBase(), mEncAudioStream->GetTimeBase());
1056 //wxLogDebug(wxT("FFmpeg : (%d) Writing audio frame with PTS: %lld."), mEncAudioCodecCtx->frame_number, (long long) pkt.pts);
1057
1058 pkt->SetStreamIndex(mEncAudioStream->GetIndex());
1059
1060 // Write the encoded audio frame to the output file.
1061 if ((ret = mFFmpeg->av_interleaved_write_frame(mEncFormatCtx->GetWrappedValue(), pkt->GetWrappedValue())) < 0)
1062 {
1064 return false;
1065 }
1066 }
1067 return true;
1068}
1069
1070
1072 std::unique_ptr<ProgressDialog> &pDialog,
1073 unsigned channels, const wxFileNameWrapper &fName,
1074 bool selectionOnly, double t0, double t1,
1075 MixerSpec *mixerSpec, const Tags *metadata, int subformat)
1076{
1077 if (!CheckFFmpegPresence())
1079 mChannels = channels;
1080 // subformat index may not correspond directly to fmts[] index, convert it
1081 mSubFormat = AdjustFormatIndex(subformat);
1082 if (channels > ExportFFmpegOptions::fmts[mSubFormat].maxchannels)
1083 {
1085 XO(
1086"Attempted to export %d channels, but maximum number of channels for selected output format is %d")
1087 .Format(
1088 channels,
1090 XO("Error"));
1092 }
1093 mName = fName;
1094 const auto &tracks = TrackList::Get( *project );
1095 bool ret = true;
1096
1097 if (mSubFormat >= FMT_LAST) {
1098 // TODO: more precise message
1099 ShowExportErrorDialog("FFmpeg:996");
1101 }
1102
1103 wxString shortname(ExportFFmpegOptions::fmts[mSubFormat].shortname);
1104 if (mSubFormat == FMT_OTHER)
1105 shortname = gPrefs->Read(wxT("/FileFormats/FFmpegFormat"),wxT("matroska"));
1106 ret = Init(shortname.mb_str(),project, metadata, subformat);
1107 auto cleanup = finally ( [&] { FreeResources(); } );
1108
1109 if (!ret) {
1110 // TODO: more precise message
1111 ShowExportErrorDialog("FFmpeg:1008");
1113 }
1114
1115 size_t pcmBufferSize = mDefaultFrameSize;
1116
1117 auto mixer = CreateMixer(tracks, selectionOnly,
1118 t0, t1,
1119 channels, pcmBufferSize, true,
1120 mSampleRate, int16Sample, mixerSpec);
1121
1122 auto updateResult = ProgressResult::Success;
1123 {
1124 InitProgress( pDialog, fName,
1125 selectionOnly
1126 ? XO("Exporting selected audio as %s")
1128 : XO("Exporting the audio as %s")
1129 .Format( ExportFFmpegOptions::fmts[mSubFormat].description ) );
1130 auto &progress = *pDialog;
1131
1132 while (updateResult == ProgressResult::Success) {
1133 auto pcmNumSamples = mixer->Process(pcmBufferSize);
1134
1135 if (pcmNumSamples == 0)
1136 break;
1137
1138 short *pcmBuffer = (short *)mixer->GetBuffer();
1139
1140 if (!EncodeAudioFrame(
1141 pcmBuffer, (pcmNumSamples)*sizeof(int16_t)*mChannels)) {
1142 // All errors should already have been reported.
1143 //ShowDiskFullExportErrorDialog(mName);
1144 updateResult = ProgressResult::Cancelled;
1145 break;
1146 }
1147
1148 updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
1149 }
1150 }
1151
1152 if ( updateResult != ProgressResult::Cancelled )
1153 if ( !Finalize() ) // Finalize makes its own messages
1155
1156 // Flush the file
1157 mEncFormatCtx.reset();
1158
1159 return updateResult;
1160}
1161
1162void AddStringTagUTF8(char field[], int size, wxString value)
1163{
1164 memset(field,0,size);
1165 memcpy(field,value.ToUTF8(),(int)strlen(value.ToUTF8()) > size -1 ? size -1 : strlen(value.ToUTF8()));
1166}
1167
1168void AddStringTagANSI(char field[], int size, wxString value)
1169{
1170 memset(field,0,size);
1171 memcpy(field,value.mb_str(),(int)strlen(value.mb_str()) > size -1 ? size -1 : strlen(value.mb_str()));
1172}
1173
1175{
1176 if (tags == NULL)
1177 {
1178 return false;
1179 }
1180
1181 SetMetadata(tags, "album", TAG_ALBUM);
1182 SetMetadata(tags, "comment", TAG_COMMENTS);
1183 SetMetadata(tags, "genre", TAG_GENRE);
1184 SetMetadata(tags, "title", TAG_TITLE);
1185 SetMetadata(tags, "track", TAG_TRACK);
1186
1187 // Bug 2564: Add m4a tags
1188 if (mEncFormatDesc->GetAudioCodec() == mFFmpeg->GetAVCodecID(AUDACITY_AV_CODEC_ID_AAC))
1189 {
1190 SetMetadata(tags, "artist", TAG_ARTIST);
1191 SetMetadata(tags, "date", TAG_YEAR);
1192 }
1193 else
1194 {
1195 SetMetadata(tags, "author", TAG_ARTIST);
1196 SetMetadata(tags, "year", TAG_YEAR);
1197 }
1198
1199 return true;
1200}
1201
1202void ExportFFmpeg::SetMetadata(const Tags *tags, const char *name, const wxChar *tag)
1203{
1204 if (tags->HasTag(tag))
1205 {
1206 wxString value = tags->GetTag(tag);
1207
1208 AVDictionaryWrapper metadata = mEncFormatCtx->GetMetadata();
1209
1210 metadata.Set(name, mSupportsUTF8 ? value : value.mb_str(), 0);
1211 mEncFormatCtx->SetMetadata(metadata);
1212 }
1213}
1214
1215
1216//----------------------------------------------------------------------------
1217// AskResample dialog
1218//----------------------------------------------------------------------------
1219
1220int ExportFFmpeg::AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates)
1221{
1222#if defined(FFMPEG_AUTO_RESAMPLE)
1223 std::vector<int> rates;
1224
1225 for (int i = 0; sampRates[i]; ++i)
1226 {
1227 rates.push_back(sampRates[i]);
1228 }
1229
1230 std::sort(rates.begin(), rates.end());
1231
1232 int bestRate = 0;
1233 for (auto i : rates)
1234 {
1235 bestRate = i;
1236 if (i > rate)
1237 {
1238 break;
1239 }
1240 }
1241
1242 return bestRate;
1243#else
1244 wxDialogWrapper d(nullptr, wxID_ANY, XO("Invalid sample rate"));
1245 d.SetName();
1246 wxChoice *choice;
1248
1249 int selected = -1;
1250
1251 S.StartVerticalLay();
1252 {
1253 S.SetBorder(10);
1254 S.StartStatic(XO("Resample"));
1255 {
1256 S.StartHorizontalLay(wxALIGN_CENTER, false);
1257 {
1258 S.AddTitle(
1259 (bitrate == 0
1260 ? XO(
1261"The project sample rate (%d) is not supported by the current output\nfile format. ")
1262 .Format( rate )
1263 : XO(
1264"The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the current output file format. ")
1265 .Format( rate, bitrate/1000))
1266 + XO("You may resample to one of the rates below.")
1267 );
1268 }
1269 S.EndHorizontalLay();
1270
1271 S.StartHorizontalLay(wxALIGN_CENTER, false);
1272 {
1273 choice = S.AddChoice(XO("Sample Rates"),
1274 [&]{
1275 TranslatableStrings choices;
1276 for (int i = 0; sampRates[i] > 0; i++)
1277 {
1278 int label = sampRates[i];
1279 if ((!lowrate || label >= lowrate) && (!highrate || label <= highrate))
1280 {
1281 wxString name = wxString::Format(wxT("%d"),label);
1282 choices.push_back( Verbatim( name ) );
1283 if (label <= rate)
1284 selected = i;
1285 }
1286 }
1287 return choices;
1288 }(),
1289 std::max( 0, selected )
1290 );
1291 }
1292 S.EndHorizontalLay();
1293 }
1294 S.EndStatic();
1295
1296 S.AddStandardButtons();
1297 }
1298 S.EndVerticalLay();
1299
1300 d.Layout();
1301 d.Fit();
1302 d.SetMinSize(d.GetSize());
1303 d.Center();
1304
1305 if (d.ShowModal() == wxID_CANCEL) {
1306 return 0;
1307 }
1308
1309 return wxAtoi(choice->GetStringSelection());
1310#endif
1311}
1312
1314{
1315 // subformat index may not correspond directly to fmts[] index, convert it
1317 if (mSubFormat == FMT_M4A)
1318 {
1319 S.AddWindow(
1320 safenew ExportFFmpegAACOptions{ S.GetParent(), format } );
1321 return;
1322 }
1323 else if (mSubFormat == FMT_AC3)
1324 {
1325 S.AddWindow(
1326 safenew ExportFFmpegAC3Options{ S.GetParent(), format } );
1327 return;
1328 }
1329 else if (mSubFormat == FMT_AMRNB)
1330 {
1331 S.AddWindow(
1332 safenew ExportFFmpegAMRNBOptions{ S.GetParent(), format } );
1333 return;
1334 }
1335 else if (mSubFormat == FMT_OPUS)
1336 {
1337 S.AddWindow(
1338 safenew ExportFFmpegOPUSOptions{ S.GetParent(), format });
1339 return;
1340 }
1341 else if (mSubFormat == FMT_WMA2)
1342 {
1343 S.AddWindow(
1344 safenew ExportFFmpegWMAOptions{ S.GetParent(), format } );
1345 return;
1346 }
1347 else if (mSubFormat == FMT_OTHER)
1348 {
1349 S.AddWindow(
1350 safenew ExportFFmpegCustomOptions{ S.GetParent(), format } );
1351 return;
1352 }
1353
1355}
1356
1358 []{ return std::make_unique< ExportFFmpeg >(); }
1359};
1360
1361#endif
1362
@ AUDACITY_AV_CODEC_ID_AC3
Definition: AVCodecID.h:297
@ AUDACITY_AV_CODEC_ID_AAC
Definition: AVCodecID.h:296
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const TranslatableString name
Definition: Distortion.cpp:82
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption, bool allowReporting)
Definition: Export.cpp:1520
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
Definition: Export.cpp:1533
#define MAX_AUDIO_PACKET_SIZE
static Exporter::RegisteredExportPlugin sRegisteredPlugin
void AddStringTagUTF8(char field[], int size, wxString value)
static int encode_audio(const FFmpegFunctions &ffmpeg, AVCodecContextWrapper *avctx, AVPacketWrapper *pkt, int16_t *audio_samples, int nb_samples)
static bool CheckFFmpegPresence(bool quiet=false)
void AddStringTagANSI(char field[], int size, wxString value)
static int AdjustFormatIndex(int format)
#define AV_CANMETA
@ FMT_OPUS
@ FMT_M4A
@ FMT_OTHER
@ FMT_AC3
@ FMT_WMA2
@ FMT_AMRNB
@ FMT_LAST
static const std::vector< int > sampRates
Definition: ExportMP3.cpp:208
int format
Definition: ExportPCM.cpp:56
bool FindFFmpegLibs(wxWindow *parent)
Definition: FFmpeg.cpp:310
bool LoadFFmpeg(bool showerror)
Definition: FFmpeg.cpp:46
std::vector< T, AVAllocator< T > > AVDataBuffer
#define AUDACITY_FF_PROFILE_AAC_LOW
Definition: FFmpegTypes.h:98
#define AUDACITY_AV_CODEC_CAP_SMALL_LAST_FRAME
Definition: FFmpegTypes.h:79
#define AUDACITY_AV_CODEC_FLAG_GLOBAL_HEADER
Definition: FFmpegTypes.h:110
#define AUDACITY_AVERROR(e)
Definition: FFmpegTypes.h:25
#define AUDACITY_FF_COMPLIANCE_EXPERIMENTAL
Definition: FFmpegTypes.h:93
#define AUDACITY_FF_QP2LAMBDA
Definition: FFmpegTypes.h:84
#define AUDACITY_AV_CODEC_FLAG_QSCALE
Definition: FFmpegTypes.h:77
#define AUDACITY_AVFMT_GLOBALHEADER
Definition: FFmpegTypes.h:35
#define AUDACITY_AV_NOPTS_VALUE
Definition: FFmpegTypes.h:69
#define AUDACITY_AVFMT_NOFILE
Definition: FFmpegTypes.h:29
int AVSampleFormatFwd
Definition: FFmpegTypes.h:127
AudacityAVSampleFormat
Definition: FFmpegTypes.h:143
@ AUDACITY_AV_SAMPLE_FMT_S32P
signed 32 bits, planar
Definition: FFmpegTypes.h:153
@ AUDACITY_AV_SAMPLE_FMT_S16P
signed 16 bits, planar
Definition: FFmpegTypes.h:152
@ AUDACITY_AV_SAMPLE_FMT_FLTP
float, planar
Definition: FFmpegTypes.h:154
@ AUDACITY_AV_SAMPLE_FMT_NONE
Definition: FFmpegTypes.h:144
@ AUDACITY_AV_SAMPLE_FMT_S16
signed 16 bits
Definition: FFmpegTypes.h:146
@ AUDACITY_AV_SAMPLE_FMT_S32
signed 32 bits
Definition: FFmpegTypes.h:147
@ AUDACITY_AV_SAMPLE_FMT_FLT
float
Definition: FFmpegTypes.h:148
@ AUDACITY_AV_SAMPLE_FMT_U8
unsigned 8 bits
Definition: FFmpegTypes.h:145
@ AUDACITY_AV_SAMPLE_FMT_U8P
unsigned 8 bits, planar
Definition: FFmpegTypes.h:151
#define field(n, t)
Definition: ImportAUP.cpp:167
#define XO(s)
Definition: Internat.h:31
#define safenew
Definition: MemoryX.h:10
FileConfig * gPrefs
Definition: Prefs.cpp:71
an object holding per-project preferred sample rate
@ int16Sample
Definition: SampleFormat.h:32
#define OSINPUT(X)
Definition: SelectFile.h:47
@ eIsCreating
Definition: ShuttleGui.h:39
#define TAG_TRACK
Definition: Tags.h:61
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_GENRE
Definition: Tags.h:63
#define TAG_ALBUM
Definition: Tags.h:60
#define TAG_YEAR
Definition: Tags.h:62
#define TAG_TITLE
Definition: Tags.h:58
#define TAG_ARTIST
Definition: Tags.h:59
TranslatableString label
Definition: TagsEditor.cpp:163
#define S(N)
Definition: ToChars.cpp:64
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
Definition: TrackInfo.cpp:87
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
AVCodecContext * GetWrappedValue() noexcept
virtual uint64_t GetChannelLayout() const noexcept=0
virtual int GetChannels() const noexcept=0
virtual AVSampleFormatFwd GetSampleFmt() const noexcept=0
void Set(const std::string_view &key, const std::string &value, int flags=0) noexcept
virtual void ResetData() noexcept=0
AVPacket * GetWrappedValue() noexcept
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...
Definition: Project.h:89
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.
void OptionsCreate(ShuttleGui &S, int format) override
ProgressResult Export(AudacityProject *project, std::unique_ptr< 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 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.
void FreeResources()
~ExportFFmpeg() override
std::unique_ptr< AVFifoBufferWrapper > mEncAudioFifo
int mEncAudioFifoOutBufSize
std::unique_ptr< AVStreamWrapper > mEncAudioStream
wxFileNameWrapper mName
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.
unsigned mChannels
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
Definition: Export.cpp:209
void AddExtension(const FileExtension &extension, int index)
Definition: Export.cpp:127
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:101
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:117
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)
Definition: Export.cpp:223
void SetDescription(const TranslatableString &description, int index)
Definition: Export.cpp:122
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:147
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
Definition: Export.cpp:251
virtual bool GetCanMetaData(int index)
Definition: Export.cpp:185
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:142
Abstract base class used in importing a file.
Class used with Mixer.
Definition: Mix.h:37
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectSettings & Get(AudacityProject &project)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
ID3 Tags (for MP3)
Definition: Tags.h:73
bool HasTag(const wxString &name) const
Definition: Tags.cpp:407
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:416
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:467
Holds a msgid for the translation catalog; may also bind format arguments.
void SetName(const TranslatableString &title)
ProgressResult
Definition: BasicUI.h:145
int(* avcodec_fill_audio_frame)(AVFrame *frame, int nb_channels, AVSampleFormatFwd sample_fmt, const uint8_t *buf, int buf_size, int align)
int(* avcodec_encode_audio2)(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_output)
int(* av_samples_get_buffer_size)(int *linesize, int nb_channels, int nb_samples, AVSampleFormatFwd sample_fmt, int align)
int(* av_strerror)(int errnum, char *errbuf, size_t errbuf_size)
bool compiledIn
support for this codec/format is compiled in (checked at runtime)
const int canmetadata
!=0 if format supports metadata, AV_CANMETA any avformat version, otherwise version support added
bool canutf8
true if format supports metadata in UTF-8, false otherwise
AudacityAVCodecID codecid
codec ID (see libavcodec/avcodec.h)
AVDataBuffer< T > CreateMemoryBuffer(int preallocatedSize) const
std::unique_ptr< AVFrameWrapper > CreateAVFrameWrapper() const
static std::shared_ptr< FFmpegFunctions > Load(bool fromUserPathOnly=false)