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