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