Audacity  3.0.3
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. See License.txt.
9 
10  LRN
11 
12 ******************************************************************//*******************************************************************/
20 
21 
22 
23 
24 #include "../FFmpeg.h"
25 
26 #include <wx/choice.h>
27 #include <wx/log.h>
28 #include <wx/intl.h>
29 #include <wx/timer.h>
30 #include <wx/string.h>
31 #include <wx/textctrl.h>
32 #include <wx/listbox.h>
33 #include <wx/window.h>
34 #include <wx/spinctrl.h>
35 #include <wx/combobox.h>
36 
37 #include "../Mix.h"
38 #include "../ProjectSettings.h"
39 #include "../Tags.h"
40 #include "../Track.h"
41 #include "../widgets/AudacityMessageBox.h"
42 #include "../widgets/ProgressDialog.h"
43 #include "../wxFileNameWrapper.h"
44 
45 #include "Export.h"
46 
47 #include "ExportFFmpegDialogs.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 
58 static bool CheckFFmpegPresence(bool quiet = false)
59 {
60  bool result = true;
62  if (!FFmpegLibsInst()->ValidLibsLoaded())
63  {
64  if (!quiet)
65  {
67 "Properly configured FFmpeg is required to proceed.\nYou can configure it at Preferences > Libraries."));
68  }
69  result = false;
70  }
72  return result;
73 }
74 
75 static int AdjustFormatIndex(int format)
76 {
77  int subFormat = -1;
78  for (int i = 0; i <= FMT_OTHER; i++)
79  {
80  if (ExportFFmpegOptions::fmts[i].compiledIn) subFormat++;
81  if (subFormat == format || i == FMT_OTHER)
82  {
83  subFormat = i;
84  break;
85  }
86  }
87  return subFormat;
88 }
89 
90 //----------------------------------------------------------------------------
91 // ExportFFmpeg
92 //----------------------------------------------------------------------------
93 
94 class ExportFFmpeg final : public ExportPlugin
95 {
96 public:
97 
98  ExportFFmpeg();
99  ~ExportFFmpeg() override;
100 
102  bool CheckFileName(wxFileName &filename, int format = 0) override;
103 
105  bool Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat);
106 
108  bool InitCodecs(AudacityProject *project);
109 
111  bool AddTags(const Tags *metadata);
112 
114  void SetMetadata(const Tags *tags, const char *name, const wxChar *tag);
115 
117  bool EncodeAudioFrame(int16_t *pFrame, size_t frameSize);
118 
120  bool Finalize();
121 
122  void FreeResources();
123 
126  void OptionsCreate(ShuttleGui &S, int format) override;
127 
129  bool CheckSampleRate(int rate, int lowrate, int highrate, const int *sampRates);
130 
132  int AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates);
133 
145  std::unique_ptr<ProgressDialog> &pDialog,
146  unsigned channels,
147  const wxFileNameWrapper &fName,
148  bool selectedOnly,
149  double t0,
150  double t1,
151  MixerSpec *mixerSpec = NULL,
152  const Tags *metadata = NULL,
153  int subformat = 0) override;
154 
155 private:
156 
157  AVOutputFormat * mEncFormatDesc{}; // describes our output file to libavformat
159  AVStream * mEncAudioStream{}; // the output audio stream (may remain NULL)
161 
163 
164  int mSubFormat{};
165  int mBitRate{};
166  int mSampleRate{};
167  unsigned mChannels{};
169 
170  // Smart pointer fields, their order is the reverse in which they are reset in FreeResources():
171  AVFifoBufferHolder mEncAudioFifo; // FIFO to write incoming audio samples into
172  AVMallocHolder<int16_t> mEncAudioFifoOutBuf; // buffer to read _out_ of the FIFO into
173  AVFormatContextHolder mEncFormatCtx; // libavformat's context for our output file
175  AVCodecContextHolder mEncAudioCodecCtx; // the encoder for the output audio stream
176 };
177 
179 : ExportPlugin()
180 {
181  mEncFormatDesc = NULL; // describes our output file to libavformat
182  mEncAudioStream = NULL; // the output audio stream (may remain NULL)
183  #define MAX_AUDIO_PACKET_SIZE (128 * 1024)
185 
186  mSampleRate = 0;
187  mSupportsUTF8 = true;
188 
189  PickFFmpegLibs(); // DropFFmpegLibs() call is in ExportFFmpeg destructor
190  int avfver = FFmpegLibsInst()->ValidLibsLoaded() ? avformat_version() : 0;
191  int newfmt;
192  // Adds export types from the export type list
193  for (newfmt = 0; newfmt < FMT_LAST; newfmt++)
194  {
195  wxString shortname(ExportFFmpegOptions::fmts[newfmt].shortname);
196  //Don't hide export types when there's no av-libs, and don't hide FMT_OTHER
197  if (newfmt < FMT_OTHER && FFmpegLibsInst()->ValidLibsLoaded())
198  {
199  // Format/Codec support is compiled in?
200  AVOutputFormat *avoformat = av_guess_format(shortname.mb_str(), NULL, NULL);
201  AVCodec *avcodec = avcodec_find_encoder(ExportFFmpegOptions::fmts[newfmt].codecid);
202  if (avoformat == NULL || avcodec == NULL)
203  {
204  ExportFFmpegOptions::fmts[newfmt].compiledIn = false;
205  continue;
206  }
207  }
208  int fmtindex = AddFormat() - 1;
209  SetFormat(ExportFFmpegOptions::fmts[newfmt].name,fmtindex);
210  AddExtension(ExportFFmpegOptions::fmts[newfmt].extension,fmtindex);
211  // For some types add other extensions
212  switch(newfmt)
213  {
214  case FMT_M4A:
215  AddExtension(wxT("3gp"),fmtindex);
216  AddExtension(wxT("m4r"),fmtindex);
217  AddExtension(wxT("mp4"),fmtindex);
218  break;
219  case FMT_WMA2:
220  AddExtension(wxT("asf"),fmtindex);
221  AddExtension(wxT("wmv"),fmtindex);
222  break;
223  default:
224  break;
225  }
226 
227  SetMaxChannels(ExportFFmpegOptions::fmts[newfmt].maxchannels,fmtindex);
228  SetDescription(ExportFFmpegOptions::fmts[newfmt].description, fmtindex);
229 
230  int canmeta = ExportFFmpegOptions::fmts[newfmt].canmetadata;
231  if (canmeta && (canmeta == AV_CANMETA || canmeta <= avfver))
232  {
233  SetCanMetaData(true,fmtindex);
234  }
235  else
236  {
237  SetCanMetaData(false,fmtindex);
238  }
239  }
240 }
241 
243 {
244  DropFFmpegLibs();
245 }
246 
247 bool ExportFFmpeg::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
248 {
249  bool result = true;
250 
251  // Show "Locate FFmpeg" dialog
252  if (!CheckFFmpegPresence(true))
253  {
254  FFmpegLibsInst()->FindLibs(NULL);
256  return LoadFFmpeg(true);
257  }
258 
259  return result;
260 }
261 
262 bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat)
263 {
264  // This will undo the acquisition of resources along any early exit path:
265  auto deleter = [](ExportFFmpeg *This) {
266  if (This)
267  This->FreeResources();
268  };
269  std::unique_ptr<ExportFFmpeg, decltype(deleter)> cleanup{ this, deleter };
270 
271  int err;
272  //FFmpegLibsInst()->LoadLibs(NULL,true); //Loaded at startup or from Prefs now
273 
274  if (!FFmpegLibsInst()->ValidLibsLoaded())
275  return false;
276 
277  av_log_set_callback(av_log_wx_callback);
278 
279  // See if libavformat has modules that can write our output format. If so, mEncFormatDesc
280  // will describe the functions used to write the format (used internally by libavformat)
281  // and the default video/audio codecs that the format uses.
282  const auto path = mName.GetFullPath();
283  if ((mEncFormatDesc = av_guess_format(shortname, OSINPUT(path), NULL)) == NULL)
284  {
286  XO(
287 "FFmpeg : ERROR - Can't determine format description for file \"%s\".")
288  .Format( path ),
289  XO("FFmpeg Error"),
290  wxOK|wxCENTER|wxICON_EXCLAMATION );
291  return false;
292  }
293 
294  // mEncFormatCtx is used by libavformat to carry around context data re our output file.
295  mEncFormatCtx.reset(avformat_alloc_context());
296  if (!mEncFormatCtx)
297  {
299  XO("FFmpeg : ERROR - Can't allocate output format context."),
300  XO("FFmpeg Error"),
301  wxOK|wxCENTER|wxICON_EXCLAMATION);
302  return false;
303  }
304 
305  // Initialise the output format context.
306  mEncFormatCtx->oformat = mEncFormatDesc;
307 
308  memcpy(mEncFormatCtx->filename, OSINPUT(path), strlen(OSINPUT(path))+1);
309 
310  // At the moment Audacity can export only one audio stream
311  if ((mEncAudioStream = avformat_new_stream(mEncFormatCtx.get(), NULL)) == NULL)
312  {
314  XO("FFmpeg : ERROR - Can't add audio stream to output file \"%s\".")
315  .Format( path ),
316  XO("FFmpeg Error"),
317  wxOK|wxCENTER|wxICON_EXCLAMATION);
318  return false;
319  }
320 
321  // Documentation for avformat_new_stream says
322  // "User is required to call avcodec_close() and avformat_free_context() to clean
323  // up the allocation by avformat_new_stream()."
324 
325  // We use smart pointers that ensure these cleanups either in their destructors or
326  // sooner if they are reset. These are std::unique_ptr with nondefault deleter
327  // template parameters.
328 
329  // mEncFormatCtx takes care of avformat_free_context(), so
330  // mEncAudioStream can be a plain pointer.
331 
332  // mEncAudioCodecCtx now becomes responsible for closing the codec:
333  mEncAudioCodecCtx.reset(mEncAudioStream->codec);
334  mEncAudioStream->id = 0;
335 
336  // Open the output file.
337  if (!(mEncFormatDesc->flags & AVFMT_NOFILE))
338  {
339  if ((err = ufile_fopen(&mEncFormatCtx->pb, path, AVIO_FLAG_WRITE)) < 0)
340  {
342  XO("FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d.")
343  .Format( path, err ),
344  XO("FFmpeg Error"),
345  wxOK|wxCENTER|wxICON_EXCLAMATION);
346  return false;
347  }
348  // Give mUfileCloser responsibility
349  mUfileCloser.reset(mEncFormatCtx->pb);
350  }
351 
352  // Open the audio stream's codec and initialise any stream related data.
353  if (!InitCodecs(project))
354  return false;
355 
356  if (metadata == NULL)
357  metadata = &Tags::Get( *project );
358 
359  // Add metadata BEFORE writing the header.
360  // At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4.
361  if (GetCanMetaData(subformat))
362  {
364  AddTags(metadata);
365  }
366 
367  // Write headers to the output file.
368  if ((err = avformat_write_header(mEncFormatCtx.get(), NULL)) < 0)
369  {
371  XO("FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d.")
372  .Format( path, err ),
373  XO("FFmpeg Error"),
374  wxOK|wxCENTER|wxICON_EXCLAMATION);
375  return false;
376  }
377 
378  // Only now, we can keep all the resources until after Finalize().
379  // Cancel the local cleanup.
380  cleanup.release();
381 
382  return true;
383 }
384 
385 bool ExportFFmpeg::CheckSampleRate(int rate, int lowrate, int highrate, const int *sampRates)
386 {
387  if (lowrate && highrate)
388  {
389  if (rate < lowrate || rate > highrate)
390  {
391  return false;
392  }
393  }
394 
395  if (sampRates)
396  {
397  for (int i = 0; sampRates[i] > 0; i++)
398  {
399  if (rate == sampRates[i])
400  {
401  return true;
402  }
403  }
404  }
405 
406  return false;
407 }
408 
409 static int set_dict_int(AVDictionary **dict, const char *key, int val)
410 {
411  char val_str[256];
412  snprintf(val_str, sizeof(val_str), "%d", val);
413  return av_dict_set(dict, key, val_str, 0);
414 }
415 
417 {
418  const auto &settings = ProjectSettings::Get( *project );
419  AVCodec *codec = NULL;
420  AVDictionary *options = NULL;
421  AVDictionaryCleanup cleanup{ &options };
422 
423  // Get the sample rate from the passed settings if we haven't set it before.
424  // Doing this only when not set allows us to carry the sample rate from one
425  // iteration of ExportMultiple to the next. This prevents multiple resampling
426  // dialogs in the event the codec can't support the specified rate.
427  if (!mSampleRate)
428  {
429  mSampleRate = (int)settings.GetRate();
430  }
431 
432  // Configure the audio stream's codec context.
433 
435  mEncAudioCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
436  mEncAudioCodecCtx->codec_tag = av_codec_get_tag(mEncFormatCtx->oformat->codec_tag,mEncAudioCodecCtx->codec_id);
437  mEncAudioCodecCtx->global_quality = -99999; //quality mode is off by default;
438 
439  // Each export type has its own settings
440  switch (mSubFormat)
441  {
442  case FMT_M4A:
443  {
444  int q = gPrefs->Read(wxT("/FileFormats/AACQuality"),-99999);
445  mEncAudioCodecCtx->global_quality = q;
446  q = wxClip( q, 98 * mChannels, 160 * mChannels);
447  // Set bit rate to between 98 kbps and 320 kbps (if two channels)
448  mEncAudioCodecCtx->bit_rate = q * 1000;
449  mEncAudioCodecCtx->profile = FF_PROFILE_AAC_LOW;
450  mEncAudioCodecCtx->cutoff = 0;
451  break;
452  }
453  case FMT_AC3:
454  mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/AC3BitRate"), 192000);
457  break;
458  case FMT_AMRNB:
459  mSampleRate = 8000;
460  mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/AMRNBBitRate"), 12200);
461  break;
462  case FMT_OPUS:
463  av_dict_set(&options, "b", gPrefs->Read(wxT("/FileFormats/OPUSBitRate"), wxT("128000")).ToUTF8(), 0);
464  av_dict_set(&options, "vbr", gPrefs->Read(wxT("/FileFormats/OPUSVbrMode"), wxT("on")).ToUTF8(), 0);
465  av_dict_set(&options, "compression_level", gPrefs->Read(wxT("/FileFormats/OPUSCompression"), wxT("10")).ToUTF8(), 0);
466  av_dict_set(&options, "frame_duration", gPrefs->Read(wxT("/FileFormats/OPUSFrameDuration"), wxT("20")).ToUTF8(), 0);
467  av_dict_set(&options, "application", gPrefs->Read(wxT("/FileFormats/OPUSApplication"), wxT("audio")).ToUTF8(), 0);
468  av_dict_set(&options, "cutoff", gPrefs->Read(wxT("/FileFormats/OPUSCutoff"), wxT("0")).ToUTF8(), 0);
469  av_dict_set(&options, "mapping_family", mChannels <= 2 ? "0" : "255", 0);
470  break;
471  case FMT_WMA2:
472  mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/WMABitRate"), 198000);
475  break;
476  case FMT_OTHER:
477  av_dict_set(&mEncAudioStream->metadata, "language", gPrefs->Read(wxT("/FileFormats/FFmpegLanguage"),wxT("")).ToUTF8(), 0);
478  mEncAudioCodecCtx->sample_rate = gPrefs->Read(wxT("/FileFormats/FFmpegSampleRate"),(long)0);
479  if (mEncAudioCodecCtx->sample_rate != 0) mSampleRate = mEncAudioCodecCtx->sample_rate;
480  mEncAudioCodecCtx->bit_rate = gPrefs->Read(wxT("/FileFormats/FFmpegBitRate"), (long)0);
481  strncpy((char *)&mEncAudioCodecCtx->codec_tag,gPrefs->Read(wxT("/FileFormats/FFmpegTag"),wxT("")).mb_str(wxConvUTF8),4);
482  mEncAudioCodecCtx->global_quality = gPrefs->Read(wxT("/FileFormats/FFmpegQuality"),(long)-99999);
483  mEncAudioCodecCtx->cutoff = gPrefs->Read(wxT("/FileFormats/FFmpegCutOff"),(long)0);
484  mEncAudioCodecCtx->flags2 = 0;
485  if (gPrefs->Read(wxT("/FileFormats/FFmpegBitReservoir"),true))
486  av_dict_set(&options, "reservoir", "1", 0);
487  if (gPrefs->Read(wxT("/FileFormats/FFmpegVariableBlockLen"),true)) mEncAudioCodecCtx->flags2 |= 0x0004; //WMA only?
488  mEncAudioCodecCtx->compression_level = gPrefs->Read(wxT("/FileFormats/FFmpegCompLevel"),-1);
489  mEncAudioCodecCtx->frame_size = gPrefs->Read(wxT("/FileFormats/FFmpegFrameSize"),(long)0);
490 
491 //FIXME The list of supported options for the selected encoder should be extracted instead of a few hardcoded
492  set_dict_int(&options, "lpc_coeff_precision", gPrefs->Read(wxT("/FileFormats/FFmpegLPCCoefPrec"),(long)0));
493  set_dict_int(&options, "min_prediction_order", gPrefs->Read(wxT("/FileFormats/FFmpegMinPredOrder"),(long)-1));
494  set_dict_int(&options, "max_prediction_order", gPrefs->Read(wxT("/FileFormats/FFmpegMaxPredOrder"),(long)-1));
495  set_dict_int(&options, "min_partition_order", gPrefs->Read(wxT("/FileFormats/FFmpegMinPartOrder"),(long)-1));
496  set_dict_int(&options, "max_partition_order", gPrefs->Read(wxT("/FileFormats/FFmpegMaxPartOrder"),(long)-1));
497  set_dict_int(&options, "prediction_order_method", gPrefs->Read(wxT("/FileFormats/FFmpegPredOrderMethod"),(long)0));
498  set_dict_int(&options, "muxrate", gPrefs->Read(wxT("/FileFormats/FFmpegMuxRate"),(long)0));
499  mEncFormatCtx->packet_size = gPrefs->Read(wxT("/FileFormats/FFmpegPacketSize"),(long)0);
500  codec = avcodec_find_encoder_by_name(gPrefs->Read(wxT("/FileFormats/FFmpegCodec")).ToUTF8());
501  if (!codec)
502  mEncAudioCodecCtx->codec_id = mEncFormatDesc->audio_codec;
503  break;
504  default:
505  return false;
506  }
507 
508  // This happens if user refused to resample the project
509  if (mSampleRate == 0) return false;
510 
511  if (mEncAudioCodecCtx->global_quality >= 0)
512  {
514  }
515  else mEncAudioCodecCtx->global_quality = 0;
516  mEncAudioCodecCtx->global_quality = mEncAudioCodecCtx->global_quality * FF_QP2LAMBDA;
517  mEncAudioCodecCtx->sample_rate = mSampleRate;
518  mEncAudioCodecCtx->channels = mChannels;
519  mEncAudioCodecCtx->channel_layout = av_get_default_channel_layout(mChannels);
520  mEncAudioCodecCtx->time_base.num = 1;
521  mEncAudioCodecCtx->time_base.den = mEncAudioCodecCtx->sample_rate;
522  mEncAudioCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
523  mEncAudioCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
524 
525  if (mEncAudioCodecCtx->codec_id == AV_CODEC_ID_AC3)
526  {
527  // As of Jan 4, 2011, the default AC3 encoder only accept SAMPLE_FMT_FLT samples.
528  // But, currently, Audacity only supports SAMPLE_FMT_S16. So, for now, look for the
529  // "older" AC3 codec. this is not a proper solution, but will suffice until other
530  // encoders no longer support SAMPLE_FMT_S16.
531  codec = avcodec_find_encoder_by_name("ac3_fixed");
532  }
533 
534  if (!codec)
535  {
536  codec = avcodec_find_encoder(mEncAudioCodecCtx->codec_id);
537  }
538 
539  // Is the required audio codec compiled into libavcodec?
540  if (codec == NULL)
541  {
543  XO(
544 /* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
545 "FFmpeg cannot find audio codec 0x%x.\nSupport for this codec is probably not compiled in.")
546  .Format( (unsigned int) mEncAudioCodecCtx->codec_id ),
547  XO("FFmpeg Error"),
548  wxOK|wxCENTER|wxICON_EXCLAMATION);
549  return false;
550  }
551 
552  if (codec->sample_fmts) {
553  for (int i=0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) {
554  enum AVSampleFormat fmt = codec->sample_fmts[i];
555  if ( fmt == AV_SAMPLE_FMT_U8
556  || fmt == AV_SAMPLE_FMT_U8P
557  || fmt == AV_SAMPLE_FMT_S16
558  || fmt == AV_SAMPLE_FMT_S16P
559  || fmt == AV_SAMPLE_FMT_S32
560  || fmt == AV_SAMPLE_FMT_S32P
561  || fmt == AV_SAMPLE_FMT_FLT
562  || fmt == AV_SAMPLE_FMT_FLTP) {
563  mEncAudioCodecCtx->sample_fmt = fmt;
564  }
565  if ( fmt == AV_SAMPLE_FMT_S16
566  || fmt == AV_SAMPLE_FMT_S16P)
567  break;
568  }
569  }
570 
571  if (codec->supported_samplerates)
572  {
573  // Workaround for crash in bug #2378. Proper fix is to get a newer version of FFmpeg.
574  if (codec->id == AV_CODEC_ID_AAC)
575  {
576  std::vector<int> rates;
577  int i = 0;
578 
579  while (codec->supported_samplerates[i] && codec->supported_samplerates[i] != 7350)
580  {
581  rates.push_back(codec->supported_samplerates[i++]);
582  }
583  rates.push_back(0);
584 
585  if (!CheckSampleRate(mSampleRate, 0, 0, rates.data()))
586  {
587  mEncAudioCodecCtx->sample_rate = mSampleRate = AskResample(0, mSampleRate, 0, 0, rates.data());
588  }
589  }
590  else
591  {
592  if (!CheckSampleRate(mSampleRate, 0, 0, codec->supported_samplerates))
593  {
594  mEncAudioCodecCtx->sample_rate = mSampleRate = AskResample(0, mSampleRate, 0, 0, codec->supported_samplerates);
595  }
596  }
597 
598  // This happens if user refused to resample the project
599  if (mSampleRate == 0)
600  {
601  return false;
602  }
603  }
604 
605  if (mEncFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
606  {
609  }
610 
611  // Open the codec.
612  int rc = avcodec_open2(mEncAudioCodecCtx.get(), codec, &options);
613  if (rc < 0)
614  {
615  TranslatableString errmsg;
616 
617  switch (rc)
618  {
619  case -EPERM:
620  errmsg = XO("The codec reported a generic error (EPERM)");
621  break;
622  case -EINVAL:
623  errmsg = XO("The codec reported an invalid parameter (EINVAL)");
624  break;
625  default:
626  char buf[AV_ERROR_MAX_STRING_SIZE];
627  av_strerror(rc, buf, sizeof(buf));
628  errmsg = Verbatim(buf);
629  }
630 
632  /* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
633  XO("Can't open audio codec \"%s\" (0x%x)\n\n%s")
634  .Format(codec->name, mEncAudioCodecCtx->codec_id, errmsg),
635  XO("FFmpeg Error"),
636  wxOK|wxCENTER|wxICON_EXCLAMATION);
637  return false;
638  }
639 
641  if (default_frame_size == 0)
642  default_frame_size = 1024; // arbitrary non zero value;
643 
644  wxLogDebug(wxT("FFmpeg : Audio Output Codec Frame Size: %d samples."), mEncAudioCodecCtx->frame_size);
645 
646  // The encoder may require a minimum number of raw audio samples for each encoding but we can't
647  // guarantee we'll get this minimum each time an audio frame is decoded from the input file so
648  // we use a FIFO to store up incoming raw samples until we have enough for one call to the codec.
649  mEncAudioFifo.reset(av_fifo_alloc(1024));
650 
652  // Allocate a buffer to read OUT of the FIFO into. The FIFO maintains its own buffer internally.
653  mEncAudioFifoOutBuf.reset(static_cast<int16_t*>(av_malloc(mEncAudioFifoOutBufSiz)));
654  if (!mEncAudioFifoOutBuf)
655  {
657  XO("FFmpeg : ERROR - Can't allocate buffer to read into from audio FIFO."),
658  XO("FFmpeg Error"),
659  wxOK|wxCENTER|wxICON_EXCLAMATION
660  );
661  return false;
662  }
663 
664  return true;
665 }
666 
667 // Returns 0 if no more output, 1 if more output, negative if error
668 static int encode_audio(AVCodecContext *avctx, AVPacket *pkt, int16_t *audio_samples, int nb_samples)
669 {
670  // Assume *pkt is already initialized.
671 
672  int i, ch, buffer_size, ret, got_output = 0;
673  AVMallocHolder<uint8_t> samples;
674  AVFrameHolder frame;
675 
676  if (audio_samples) {
677  frame.reset(av_frame_alloc());
678  if (!frame)
679  return AVERROR(ENOMEM);
680 
681  frame->nb_samples = nb_samples;
682  frame->format = avctx->sample_fmt;
683 #if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) || (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 13, 0))
684  frame->channel_layout = avctx->channel_layout;
685 #endif
686 
687  buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, frame->nb_samples,
688  avctx->sample_fmt, 0);
689  if (buffer_size < 0) {
691  XO("FFmpeg : ERROR - Could not get sample buffer size"),
692  XO("FFmpeg Error"),
693  wxOK|wxCENTER|wxICON_EXCLAMATION
694  );
695  return buffer_size;
696  }
697  samples.reset(static_cast<uint8_t*>(av_malloc(buffer_size)));
698  if (!samples) {
700  XO("FFmpeg : ERROR - Could not allocate bytes for samples buffer"),
701  XO("FFmpeg Error"),
702  wxOK|wxCENTER|wxICON_EXCLAMATION
703  );
704  return AVERROR(ENOMEM);
705  }
706  /* setup the data pointers in the AVFrame */
707  ret = avcodec_fill_audio_frame(frame.get(), avctx->channels, avctx->sample_fmt,
708  samples.get(), buffer_size, 0);
709  if (ret < 0) {
711  XO("FFmpeg : ERROR - Could not setup audio frame"),
712  XO("FFmpeg Error"),
713  wxOK|wxCENTER|wxICON_EXCLAMATION
714  );
715  return ret;
716  }
717 
718  for (ch = 0; ch < avctx->channels; ch++) {
719  for (i = 0; i < frame->nb_samples; i++) {
720  switch(avctx->sample_fmt) {
721  case AV_SAMPLE_FMT_U8:
722  ((uint8_t*)(frame->data[0]))[ch + i*avctx->channels] = audio_samples[ch + i*avctx->channels]/258 + 128;
723  break;
724  case AV_SAMPLE_FMT_U8P:
725  ((uint8_t*)(frame->data[ch]))[i] = audio_samples[ch + i*avctx->channels]/258 + 128;
726  break;
727  case AV_SAMPLE_FMT_S16:
728  ((int16_t*)(frame->data[0]))[ch + i*avctx->channels] = audio_samples[ch + i*avctx->channels];
729  break;
730  case AV_SAMPLE_FMT_S16P:
731  ((int16_t*)(frame->data[ch]))[i] = audio_samples[ch + i*avctx->channels];
732  break;
733  case AV_SAMPLE_FMT_S32:
734  ((int32_t*)(frame->data[0]))[ch + i*avctx->channels] = audio_samples[ch + i*avctx->channels]<<16;
735  break;
736  case AV_SAMPLE_FMT_S32P:
737  ((int32_t*)(frame->data[ch]))[i] = audio_samples[ch + i*avctx->channels]<<16;
738  break;
739  case AV_SAMPLE_FMT_FLT:
740  ((float*)(frame->data[0]))[ch + i*avctx->channels] = audio_samples[ch + i*avctx->channels] / 32767.0;
741  break;
742  case AV_SAMPLE_FMT_FLTP:
743  ((float*)(frame->data[ch]))[i] = audio_samples[ch + i*avctx->channels] / 32767.;
744  break;
745  case AV_SAMPLE_FMT_NONE:
746  case AV_SAMPLE_FMT_DBL:
747  case AV_SAMPLE_FMT_DBLP:
748  case AV_SAMPLE_FMT_NB:
749  wxASSERT(false);
750  break;
751  }
752  }
753  }
754  }
755 
756  pkt->data = NULL; // packet data will be allocated by the encoder
757  pkt->size = 0;
758 
759  ret = avcodec_encode_audio2(avctx, pkt, frame.get(), &got_output);
760  if (ret < 0) {
762  XO("FFmpeg : ERROR - encoding frame failed"),
763  XO("FFmpeg Error"),
764  wxOK|wxCENTER|wxICON_EXCLAMATION
765  );
766  return ret;
767  }
768 
769  pkt->dts = pkt->pts = AV_NOPTS_VALUE; // we dont set frame.pts thus dont trust the AVPacket ts
770 
771  return got_output;
772 }
773 
774 
776 {
777  // Flush the audio FIFO and encoder.
778  for (;;)
779  {
780  AVPacketEx pkt;
781  const int nFifoBytes = av_fifo_size(mEncAudioFifo.get()); // any bytes left in audio FIFO?
782  int encodeResult = 0;
783 
784  // Flush the audio FIFO first if necessary. It won't contain a _full_ audio frame because
785  // if it did we'd have pulled it from the FIFO during the last encodeAudioFrame() call
786  if (nFifoBytes > 0)
787  {
788  const int nAudioFrameSizeOut = default_frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
789 
790  if (nAudioFrameSizeOut > mEncAudioFifoOutBufSiz || nFifoBytes > mEncAudioFifoOutBufSiz) {
792  XO("FFmpeg : ERROR - Too much remaining data."),
793  XO("FFmpeg Error"),
794  wxOK | wxCENTER | wxICON_EXCLAMATION
795  );
796  return false;
797  }
798 
799  // We have an incomplete buffer of samples left, encode it.
800  // If codec supports CODEC_CAP_SMALL_LAST_FRAME, we can feed it with smaller frame
801  // 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
802  // Otherwise we'll send a full frame of audio + silence padding to ensure all audio is encoded
803  int frame_size = default_frame_size;
804  if (mEncAudioCodecCtx->codec->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME ||
805  frame_size == 1)
806  frame_size = nFifoBytes / (mEncAudioCodecCtx->channels * sizeof(int16_t));
807 
808  wxLogDebug(wxT("FFmpeg : Audio FIFO still contains %d bytes, writing %d sample frame ..."),
809  nFifoBytes, frame_size);
810 
811  // Fill audio buffer with zeroes. If codec tries to read the whole buffer,
812  // it will just read silence. If not - who cares?
814  //const AVCodec *codec = mEncAudioCodecCtx->codec;
815 
816  // Pull the bytes out from the FIFO and feed them to the encoder.
817  if (av_fifo_generic_read(mEncAudioFifo.get(), mEncAudioFifoOutBuf.get(), nFifoBytes, NULL) == 0)
818  {
819  encodeResult = encode_audio(mEncAudioCodecCtx.get(), &pkt, mEncAudioFifoOutBuf.get(), frame_size);
820  }
821  else
822  {
823  wxLogDebug(wxT("FFmpeg : Reading from Audio FIFO failed, aborting"));
824  // TODO: more precise message
825  ShowExportErrorDialog("FFmpeg:825");
826  return false;
827  }
828  }
829  else
830  {
831  // Fifo is empty, flush encoder. May be called multiple times.
832  encodeResult = encode_audio(mEncAudioCodecCtx.get(), &pkt, NULL, 0);
833  }
834 
835  if (encodeResult < 0) {
836  // TODO: more precise message
837  ShowExportErrorDialog("FFmpeg:837");
838  return false;
839  }
840  else if (encodeResult == 0)
841  break;
842 
843  // We have a packet, send to the muxer
844  pkt.stream_index = mEncAudioStream->index;
845 
846  // Set presentation time of frame (currently in the codec's timebase) in the stream timebase.
847  if (pkt.pts != int64_t(AV_NOPTS_VALUE))
848  pkt.pts = av_rescale_q(pkt.pts, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
849  if (pkt.dts != int64_t(AV_NOPTS_VALUE))
850  pkt.dts = av_rescale_q(pkt.dts, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
851  if (pkt.duration)
852  pkt.duration = av_rescale_q(pkt.duration, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
853 
854  if (av_interleaved_write_frame(mEncFormatCtx.get(), &pkt) != 0)
855  {
857  XO("FFmpeg : ERROR - Couldn't write last audio frame to output file."),
858  XO("FFmpeg Error"),
859  wxOK | wxCENTER | wxICON_EXCLAMATION
860  );
861  return false;
862  }
863  }
864 
865  // Write any file trailers.
866  if (av_write_trailer(mEncFormatCtx.get()) != 0) {
867  // TODO: more precise message
868  ShowExportErrorDialog("FFmpeg:868");
869  return false;
870  }
871 
872  return true;
873 }
874 
876 {
877  // Close the codecs.
878  mEncAudioCodecCtx.reset();
879 
880  // Close the output file if we created it.
881  mUfileCloser.reset();
882 
883  // Free any buffers or structures we allocated.
884  mEncFormatCtx.reset();
885 
886  mEncAudioFifoOutBuf.reset();
888 
889  mEncAudioFifo.reset();
890 
891  av_log_set_callback(av_log_default_callback);
892 }
893 
894 // All paths in this that fail must report their error to the user.
895 bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, size_t frameSize)
896 {
897  int nBytesToWrite = 0;
898  uint8_t *pRawSamples = NULL;
899  int nAudioFrameSizeOut = default_frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
900  int ret;
901 
902  nBytesToWrite = frameSize;
903  pRawSamples = (uint8_t*)pFrame;
904  if (av_fifo_realloc2(mEncAudioFifo.get(), av_fifo_size(mEncAudioFifo.get()) + frameSize) < 0) {
905  ShowExportErrorDialog("FFmpeg:905");
906  return false;
907  }
908 
909  // Put the raw audio samples into the FIFO.
910  ret = av_fifo_generic_write(mEncAudioFifo.get(), pRawSamples, nBytesToWrite,NULL);
911 
912  if (ret != nBytesToWrite) {
913  ShowExportErrorDialog("FFmpeg:913");
914  return false;
915  }
916 
917  if (nAudioFrameSizeOut > mEncAudioFifoOutBufSiz) {
919  XO("FFmpeg : ERROR - nAudioFrameSizeOut too large."),
920  XO("FFmpeg Error"),
921  wxOK|wxCENTER|wxICON_EXCLAMATION
922  );
923  return false;
924  }
925 
926  // Read raw audio samples out of the FIFO in nAudioFrameSizeOut byte-sized groups to encode.
927  while ( av_fifo_size(mEncAudioFifo.get()) >= nAudioFrameSizeOut)
928  {
929  ret = av_fifo_generic_read(mEncAudioFifo.get(), mEncAudioFifoOutBuf.get(), nAudioFrameSizeOut, NULL);
930 
931  AVPacketEx pkt;
932 
933  ret= encode_audio(mEncAudioCodecCtx.get(),
934  &pkt, // out
935  mEncAudioFifoOutBuf.get(), // in
937  if (ret < 0)
938  {
940  XO("FFmpeg : ERROR - Can't encode audio frame."),
941  XO("FFmpeg Error"),
942  wxOK|wxCENTER|wxICON_EXCLAMATION
943  );
944  return false;
945  }
946  if (ret == 0)
947  continue;
948 
949  // Rescale from the codec time_base to the AVStream time_base.
950  if (pkt.pts != int64_t(AV_NOPTS_VALUE))
951  pkt.pts = av_rescale_q(pkt.pts, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
952  if (pkt.dts != int64_t(AV_NOPTS_VALUE))
953  pkt.dts = av_rescale_q(pkt.dts, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
954  //wxLogDebug(wxT("FFmpeg : (%d) Writing audio frame with PTS: %lld."), mEncAudioCodecCtx->frame_number, (long long) pkt.pts);
955 
956  pkt.stream_index = mEncAudioStream->index;
957 
958  // Write the encoded audio frame to the output file.
959  if ((ret = av_interleaved_write_frame(mEncFormatCtx.get(), &pkt)) < 0)
960  {
962  return false;
963  }
964  }
965  return true;
966 }
967 
968 
970  std::unique_ptr<ProgressDialog> &pDialog,
971  unsigned channels, const wxFileNameWrapper &fName,
972  bool selectionOnly, double t0, double t1,
973  MixerSpec *mixerSpec, const Tags *metadata, int subformat)
974 {
975  if (!CheckFFmpegPresence())
977  mChannels = channels;
978  // subformat index may not correspond directly to fmts[] index, convert it
979  mSubFormat = AdjustFormatIndex(subformat);
980  if (channels > ExportFFmpegOptions::fmts[mSubFormat].maxchannels)
981  {
983  XO(
984 "Attempted to export %d channels, but maximum number of channels for selected output format is %d")
985  .Format(
986  channels,
987  ExportFFmpegOptions::fmts[mSubFormat].maxchannels ),
988  XO("Error"));
990  }
991  mName = fName;
992  const auto &tracks = TrackList::Get( *project );
993  bool ret = true;
994 
995  if (mSubFormat >= FMT_LAST) {
996  // TODO: more precise message
997  ShowExportErrorDialog("FFmpeg:996");
999  }
1000 
1001  wxString shortname(ExportFFmpegOptions::fmts[mSubFormat].shortname);
1002  if (mSubFormat == FMT_OTHER)
1003  shortname = gPrefs->Read(wxT("/FileFormats/FFmpegFormat"),wxT("matroska"));
1004  ret = Init(shortname.mb_str(),project, metadata, subformat);
1005  auto cleanup = finally ( [&] { FreeResources(); } );
1006 
1007  if (!ret) {
1008  // TODO: more precise message
1009  ShowExportErrorDialog("FFmpeg:1008");
1011  }
1012 
1013  size_t pcmBufferSize = 1024;
1014 
1015  auto mixer = CreateMixer(tracks, selectionOnly,
1016  t0, t1,
1017  channels, pcmBufferSize, true,
1018  mSampleRate, int16Sample, mixerSpec);
1019 
1020  auto updateResult = ProgressResult::Success;
1021  {
1022  InitProgress( pDialog, fName,
1023  selectionOnly
1024  ? XO("Exporting selected audio as %s")
1026  : XO("Exporting the audio as %s")
1027  .Format( ExportFFmpegOptions::fmts[mSubFormat].description ) );
1028  auto &progress = *pDialog;
1029 
1030  while (updateResult == ProgressResult::Success) {
1031  auto pcmNumSamples = mixer->Process(pcmBufferSize);
1032 
1033  if (pcmNumSamples == 0)
1034  break;
1035 
1036  short *pcmBuffer = (short *)mixer->GetBuffer();
1037 
1038  if (!EncodeAudioFrame(
1039  pcmBuffer, (pcmNumSamples)*sizeof(int16_t)*mChannels)) {
1040  // All errors should already have been reported.
1041  //ShowDiskFullExportErrorDialog(mName);
1042  updateResult = ProgressResult::Cancelled;
1043  break;
1044  }
1045 
1046  updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
1047  }
1048  }
1049 
1050  if ( updateResult != ProgressResult::Cancelled )
1051  if ( !Finalize() ) // Finalize makes its own messages
1053 
1054  if ( mUfileCloser.close() != 0 ) {
1055  // TODO: more precise message
1056  ShowExportErrorDialog("FFmpeg:1056");
1058  }
1059 
1060  return updateResult;
1061 }
1062 
1063 void AddStringTagUTF8(char field[], int size, wxString value)
1064 {
1065  memset(field,0,size);
1066  memcpy(field,value.ToUTF8(),(int)strlen(value.ToUTF8()) > size -1 ? size -1 : strlen(value.ToUTF8()));
1067 }
1068 
1069 void AddStringTagANSI(char field[], int size, wxString value)
1070 {
1071  memset(field,0,size);
1072  memcpy(field,value.mb_str(),(int)strlen(value.mb_str()) > size -1 ? size -1 : strlen(value.mb_str()));
1073 }
1074 
1075 bool ExportFFmpeg::AddTags(const Tags *tags)
1076 {
1077  if (tags == NULL)
1078  {
1079  return false;
1080  }
1081 
1082  SetMetadata(tags, "album", TAG_ALBUM);
1083  SetMetadata(tags, "comment", TAG_COMMENTS);
1084  SetMetadata(tags, "genre", TAG_GENRE);
1085  SetMetadata(tags, "title", TAG_TITLE);
1086  SetMetadata(tags, "track", TAG_TRACK);
1087 
1088  // Bug 2564: Add m4a tags
1089  if (mEncFormatDesc->audio_codec == AV_CODEC_ID_AAC)
1090  {
1091  SetMetadata(tags, "artist", TAG_ARTIST);
1092  SetMetadata(tags, "date", TAG_YEAR);
1093  }
1094  else
1095  {
1096  SetMetadata(tags, "author", TAG_ARTIST);
1097  SetMetadata(tags, "year", TAG_YEAR);
1098  }
1099 
1100  return true;
1101 }
1102 
1103 void ExportFFmpeg::SetMetadata(const Tags *tags, const char *name, const wxChar *tag)
1104 {
1105  if (tags->HasTag(tag))
1106  {
1107  wxString value = tags->GetTag(tag);
1108 
1109  av_dict_set(&mEncFormatCtx->metadata, name, mSupportsUTF8 ? value.ToUTF8() : value.mb_str(), 0);
1110  }
1111 }
1112 
1113 
1114 //----------------------------------------------------------------------------
1115 // AskResample dialog
1116 //----------------------------------------------------------------------------
1117 
1118 int ExportFFmpeg::AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates)
1119 {
1120 #if defined(FFMPEG_AUTO_RESAMPLE)
1121  std::vector<int> rates;
1122 
1123  for (int i = 0; sampRates[i]; ++i)
1124  {
1125  rates.push_back(sampRates[i]);
1126  }
1127 
1128  std::sort(rates.begin(), rates.end());
1129 
1130  int bestRate = 0;
1131  for (auto i : rates)
1132  {
1133  bestRate = i;
1134  if (i > rate)
1135  {
1136  break;
1137  }
1138  }
1139 
1140  return bestRate;
1141 #else
1142  wxDialogWrapper d(nullptr, wxID_ANY, XO("Invalid sample rate"));
1143  d.SetName();
1144  wxChoice *choice;
1145  ShuttleGui S(&d, eIsCreating);
1146 
1147  int selected = -1;
1148 
1149  S.StartVerticalLay();
1150  {
1151  S.SetBorder(10);
1152  S.StartStatic(XO("Resample"));
1153  {
1154  S.StartHorizontalLay(wxALIGN_CENTER, false);
1155  {
1156  S.AddTitle(
1157  (bitrate == 0
1158  ? XO(
1159 "The project sample rate (%d) is not supported by the current output\nfile format. ")
1160  .Format( rate )
1161  : XO(
1162 "The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the current output file format. ")
1163  .Format( rate, bitrate/1000))
1164  + XO("You may resample to one of the rates below.")
1165  );
1166  }
1167  S.EndHorizontalLay();
1168 
1169  S.StartHorizontalLay(wxALIGN_CENTER, false);
1170  {
1171  choice = S.AddChoice(XO("Sample Rates"),
1172  [&]{
1173  TranslatableStrings choices;
1174  for (int i = 0; sampRates[i] > 0; i++)
1175  {
1176  int label = sampRates[i];
1177  if ((!lowrate || label >= lowrate) && (!highrate || label <= highrate))
1178  {
1179  wxString name = wxString::Format(wxT("%d"),label);
1180  choices.push_back( Verbatim( name ) );
1181  if (label <= rate)
1182  selected = i;
1183  }
1184  }
1185  return choices;
1186  }(),
1187  std::max( 0, selected )
1188  );
1189  }
1190  S.EndHorizontalLay();
1191  }
1192  S.EndStatic();
1193 
1194  S.AddStandardButtons();
1195  }
1196  S.EndVerticalLay();
1197 
1198  d.Layout();
1199  d.Fit();
1200  d.SetMinSize(d.GetSize());
1201  d.Center();
1202 
1203  if (d.ShowModal() == wxID_CANCEL) {
1204  return 0;
1205  }
1206 
1207  return wxAtoi(choice->GetStringSelection());
1208 #endif
1209 }
1210 
1212 {
1213  // subformat index may not correspond directly to fmts[] index, convert it
1215  if (mSubFormat == FMT_M4A)
1216  {
1217  S.AddWindow(
1219  return;
1220  }
1221  else if (mSubFormat == FMT_AC3)
1222  {
1223  S.AddWindow(
1225  return;
1226  }
1227  else if (mSubFormat == FMT_AMRNB)
1228  {
1229  S.AddWindow(
1231  return;
1232  }
1233  else if (mSubFormat == FMT_OPUS)
1234  {
1235  S.AddWindow(
1237  return;
1238  }
1239  else if (mSubFormat == FMT_WMA2)
1240  {
1241  S.AddWindow(
1243  return;
1244  }
1245  else if (mSubFormat == FMT_OTHER)
1246  {
1247  S.AddWindow(
1249  return;
1250  }
1251 
1253 }
1254 
1256  []{ return std::make_unique< ExportFFmpeg >(); }
1257 };
1258 
1259 #endif
1260 
ExportFFmpeg
Controlling class for FFmpeg exporting. Creates the options dialog of the appropriate type,...
Definition: ExportFFmpeg.cpp:95
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
field
#define field(n, t)
Definition: ImportAUP.cpp:166
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
ExportFFmpegWMAOptions::iWMASampleRates
static const int iWMASampleRates[]
Definition: ExportFFmpegDialogs.h:167
ShuttleGuiBase::AddChoice
wxChoice * AddChoice(const TranslatableString &Prompt, const TranslatableStrings &choices, int Selected=-1)
Definition: ShuttleGui.cpp:398
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
ExportFFmpeg::mName
wxFileNameWrapper mName
Definition: ExportFFmpeg.cpp:162
BasicUI::ProgressResult::Success
@ Success
sRegisteredPlugin
static Exporter::RegisteredExportPlugin sRegisteredPlugin
Definition: ExportFFmpeg.cpp:1255
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
ufile_fopen
int ufile_fopen(AVIOContext **s, const FilePath &name, int flags)
Definition: FFmpeg.cpp:221
ShuttleGuiBase::AddTitle
void AddTitle(const TranslatableString &Prompt, int wrapWidth=0)
Centred text string.
Definition: ShuttleGui.cpp:281
CheckFFmpegPresence
static bool CheckFFmpegPresence(bool quiet=false)
Definition: ExportFFmpeg.cpp:58
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
ExposedFormat::compiledIn
bool compiledIn
support for this codec/format is compiled in (checked at runtime)
Definition: ExportFFmpegDialogs.h:59
ExportFFmpeg::mEncAudioFifo
AVFifoBufferHolder mEncAudioFifo
Definition: ExportFFmpeg.cpp:171
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: TranslatableString.h:295
FMT_AC3
@ FMT_AC3
Definition: ExportFFmpegDialogs.h:37
ExportPlugin::AddExtension
void AddExtension(const FileExtension &extension, int index)
Definition: Export.cpp:126
FFmpegLibs::FreeLibs
void FreeLibs()
! Frees (unloads) loaded libraries
Definition: FFmpeg.cpp:1016
ShowExportErrorDialog
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption)
Definition: Export.cpp:1518
AVPacketEx
Definition: FFmpeg.h:886
Tags::HasTag
bool HasTag(const wxString &name) const
Definition: Tags.cpp:452
Tags
ID3 Tags (for MP3)
Definition: Tags.h:74
FFmpegLibs::FindLibs
bool FindLibs(wxWindow *parent)
Definition: FFmpeg.cpp:644
ExportFFmpeg::mEncAudioStream
AVStream * mEncAudioStream
Definition: ExportFFmpeg.cpp:159
Format
Abstract base class used in importing a file.
TAG_TRACK
#define TAG_TRACK
Definition: Tags.h:63
ExportFFmpegCustomOptions
Definition: ExportFFmpegDialogs.h:176
BasicUI::ProgressResult
ProgressResult
Definition: BasicUI.h:145
ExportFFmpeg::mChannels
unsigned mChannels
Definition: ExportFFmpeg.cpp:167
ExportFFmpegAMRNBOptions
Options dialog for FFmpeg exporting of AMRNB format.
Definition: ExportFFmpegDialogs.h:106
AddStringTagANSI
void AddStringTagANSI(char field[], int size, wxString value)
Definition: ExportFFmpeg.cpp:1069
AV_CODEC_FLAG_QSCALE
#define AV_CODEC_FLAG_QSCALE
Definition: FFmpeg.h:137
ExportFFmpegAC3Options::iAC3SampleRates
static const int iAC3SampleRates[]
Definition: ExportFFmpegDialogs.h:85
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
ExportFFmpeg::AskResample
int AskResample(int bitrate, int rate, int lowrate, int highrate, const int *sampRates)
Asks user to resample the project or cancel the export procedure.
Definition: ExportFFmpeg.cpp:1118
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:40
FFmpegLibs::ValidLibsLoaded
bool ValidLibsLoaded()
Definition: FFmpeg.cpp:766
ExposedFormat::canmetadata
const int canmetadata
!=0 if format supports metadata, AV_CANMETA any avformat version, otherwise version support added
Definition: ExportFFmpegDialogs.h:55
ExportPlugin::GetCanMetaData
virtual bool GetCanMetaData(int index)
Definition: Export.cpp:184
PickFFmpegLibs
FFmpegLibs * PickFFmpegLibs()
Definition: FFmpeg.cpp:51
ExportFFmpeg::mEncAudioCodecCtx
AVCodecContextHolder mEncAudioCodecCtx
Definition: ExportFFmpeg.cpp:175
ExportFFmpeg::InitCodecs
bool InitCodecs(AudacityProject *project)
Codec initialization.
Definition: ExportFFmpeg.cpp:416
Tags::GetTag
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:461
sampRates
static const std::vector< int > sampRates
Definition: ExportMP3.cpp:205
ExportFFmpeg::FreeResources
void FreeResources()
Definition: ExportFFmpeg.cpp:875
Tags::Get
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:237
ExportFFmpeg::mSupportsUTF8
bool mSupportsUTF8
Definition: ExportFFmpeg.cpp:168
ExportFFmpeg::Export
ProgressResult Export(AudacityProject *project, std::unique_ptr< ProgressDialog > &pDialog, unsigned channels, const wxFileNameWrapper &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0) override
Definition: ExportFFmpeg.cpp:969
UFileHolder
FFmpeg structure to hold a file pointer and provide a return value when closing the file.
Definition: FFmpeg.h:985
LoadFFmpeg
bool LoadFFmpeg(bool showerror)
Definition: FFmpeg.cpp:71
AV_CANMETA
#define AV_CANMETA
Definition: ExportFFmpegDialogs.h:45
ExportFFmpeg::mEncFormatCtx
AVFormatContextHolder mEncFormatCtx
Definition: ExportFFmpeg.cpp:173
av_log_wx_callback
void av_log_wx_callback(void *ptr, int level, const char *fmt, va_list vl)
Callback function to catch FFmpeg log messages.
Definition: FFmpeg.cpp:128
ShowDiskFullExportErrorDialog
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
Definition: Export.cpp:1530
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
ExportFFmpegAACOptions
Options dialog for FFmpeg exporting of AAC format.
Definition: ExportFFmpegDialogs.h:94
ExportPlugin::InitProgress
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
Definition: Export.cpp:250
ExportFFmpeg::mUfileCloser
UFileHolder mUfileCloser
Definition: ExportFFmpeg.cpp:174
label
TranslatableString label
Definition: Tags.cpp:756
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
ExportPlugin::SetFormat
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:116
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
int16Sample
@ int16Sample
Definition: SampleFormat.h:32
ExportFFmpeg::Finalize
bool Finalize()
Flushes audio encoder.
Definition: ExportFFmpeg.cpp:775
FMT_OTHER
@ FMT_OTHER
Definition: ExportFFmpegDialogs.h:41
encode_audio
static int encode_audio(AVCodecContext *avctx, AVPacket *pkt, int16_t *audio_samples, int nb_samples)
Definition: ExportFFmpeg.cpp:668
ExportFFmpeg::SetMetadata
void SetMetadata(const Tags *tags, const char *name, const wxChar *tag)
Sets individual metadata values.
Definition: ExportFFmpeg.cpp:1103
ExportFFmpegAC3Options
AC3 export options dialog.
Definition: ExportFFmpegDialogs.h:73
UFileHolder::close
int close()
Definition: FFmpeg.h:994
AVFifoBufferHolder
std::unique_ptr< AVFifoBuffer, AV_Deleter< AVFifoBuffer, void, av_fifo_free > > AVFifoBufferHolder
Definition: FFmpeg.h:969
FMT_AMRNB
@ FMT_AMRNB
Definition: ExportFFmpegDialogs.h:38
name
const TranslatableString name
Definition: Distortion.cpp:98
ExportFFmpeg::mEncAudioFifoOutBuf
AVMallocHolder< int16_t > mEncAudioFifoOutBuf
Definition: ExportFFmpeg.cpp:172
TAG_GENRE
#define TAG_GENRE
Definition: Tags.h:65
format
int format
Definition: ExportPCM.cpp:56
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
Export.h
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
TAG_YEAR
#define TAG_YEAR
Definition: Tags.h:64
ExportPlugin::SetDescription
void SetDescription(const TranslatableString &description, int index)
Definition: Export.cpp:121
AVDictionaryCleanup
std::unique_ptr< AVDictionary *, AV_Deleter< AVDictionary *, void, av_dict_free > > AVDictionaryCleanup
Definition: FFmpeg.h:978
ExportFFmpeg::CheckFileName
bool CheckFileName(wxFileName &filename, int format=0) override
Callback, called from GetFilename.
Definition: ExportFFmpeg.cpp:247
wxDialogWrapper::SetName
void SetName(const TranslatableString &title)
Definition: wxPanelWrapper.cpp:76
ExportFFmpeg::default_frame_size
int default_frame_size
Definition: ExportFFmpeg.cpp:158
AVCodecContextHolder
std::unique_ptr< AVCodecContext, AV_Deleter< AVCodecContext, int, avcodec_close > > AVCodecContextHolder
Definition: FFmpeg.h:975
ExportFFmpeg::ExportFFmpeg
ExportFFmpeg()
Definition: ExportFFmpeg.cpp:178
ExportFFmpeg::mSubFormat
int mSubFormat
Definition: ExportFFmpeg.cpp:164
ExportFFmpeg::AddTags
bool AddTags(const Tags *metadata)
Writes metadata.
Definition: ExportFFmpeg.cpp:1075
ExportFFmpeg::EncodeAudioFrame
bool EncodeAudioFrame(int16_t *pFrame, size_t frameSize)
Encodes audio.
Definition: ExportFFmpeg.cpp:895
ExportFFmpegOptions::fmts
static ExposedFormat fmts[]
List of export types.
Definition: ExportFFmpegDialogs.h:232
ShuttleGuiBase::StartStatic
wxStaticBox * StartStatic(const TranslatableString &Str, int iProp=0)
Definition: ShuttleGui.cpp:893
ExportFFmpeg::Init
bool Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat)
Format initialization.
Definition: ExportFFmpeg.cpp:262
ExportPlugin::SetMaxChannels
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:141
AV_CODEC_FLAG_GLOBAL_HEADER
#define AV_CODEC_FLAG_GLOBAL_HEADER
Definition: FFmpeg.h:140
ExportFFmpegDialogs.h
wxDialogWrapper
Definition: wxPanelWrapper.h:81
Exporter::RegisteredExportPlugin
Definition: Export.h:177
ExportFFmpegWMAOptions
Options dialog for FFmpeg exporting of WMA format.
Definition: ExportFFmpegDialogs.h:157
key
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: CommandManager.cpp:197
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
set_dict_int
static int set_dict_int(AVDictionary **dict, const char *key, int val)
Definition: ExportFFmpeg.cpp:409
ExportFFmpeg::mEncFormatDesc
AVOutputFormat * mEncFormatDesc
Definition: ExportFFmpeg.cpp:157
FFmpegLibsInst
FFmpegLibs * FFmpegLibsInst()
Definition: FFmpeg.cpp:46
AVFormatContextHolder
std::unique_ptr< AVFormatContext, AV_Deleter< AVFormatContext, void, avformat_free_context > > AVFormatContextHolder
Definition: FFmpeg.h:972
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
ExportPlugin::CreateMixer
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
ExposedFormat::canutf8
bool canutf8
true if format supports metadata in UTF-8, false otherwise
Definition: ExportFFmpegDialogs.h:56
ExportPlugin::SetCanMetaData
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:146
ExportPlugin::OptionsCreate
virtual void OptionsCreate(ShuttleGui &S, int format)=0
Definition: Export.cpp:208
TAG_COMMENTS
#define TAG_COMMENTS
Definition: Tags.h:66
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
OSINPUT
#define OSINPUT(X)
Definition: FileNames.h:259
TAG_ARTIST
#define TAG_ARTIST
Definition: Tags.h:61
ExposedFormat::codecid
AVCodecID codecid
codec ID (see libavcodec/avcodec.h)
Definition: ExportFFmpegDialogs.h:58
DropFFmpegLibs
void DropFFmpegLibs()
Definition: FFmpeg.cpp:61
ExportFFmpeg::OptionsCreate
void OptionsCreate(ShuttleGui &S, int format) override
Definition: ExportFFmpeg.cpp:1211
ExportPlugin::AddFormat
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:100
ShuttleGui::AddStandardButtons
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
Definition: ShuttleGui.cpp:2432
AV_CODEC_CAP_SMALL_LAST_FRAME
#define AV_CODEC_CAP_SMALL_LAST_FRAME
Definition: FFmpeg.h:143
AVFrameHolder
std::unique_ptr< AVFrame, AV_Deleterp< AVFrame, void, av_frame_free > > AVFrameHolder
Definition: FFmpeg.h:966
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
MixerSpec
Class used with Mixer.
Definition: Mix.h:59
FMT_LAST
@ FMT_LAST
Definition: ExportFFmpegDialogs.h:42
ExportPlugin
Definition: Export.h:65
FMT_OPUS
@ FMT_OPUS
Definition: ExportFFmpegDialogs.h:39
AddStringTagUTF8
void AddStringTagUTF8(char field[], int size, wxString value)
Definition: ExportFFmpeg.cpp:1063
ShuttleGuiBase::EndStatic
void EndStatic()
Definition: ShuttleGui.cpp:922
safenew
#define safenew
Definition: MemoryX.h:10
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
audacity::ToUTF8
std::string ToUTF8(const std::wstring &wstr)
Definition: CodeConversions.cpp:19
MAX_AUDIO_PACKET_SIZE
#define MAX_AUDIO_PACKET_SIZE
ExportFFmpegOPUSOptions
Options dialog for FFmpeg exporting of OPUS format.
Definition: ExportFFmpegDialogs.h:123
ExportFFmpeg::mEncAudioFifoOutBufSiz
int mEncAudioFifoOutBufSiz
Definition: ExportFFmpeg.cpp:160
AdjustFormatIndex
static int AdjustFormatIndex(int format)
Definition: ExportFFmpeg.cpp:75
FMT_M4A
@ FMT_M4A
Definition: ExportFFmpegDialogs.h:36
ExportFFmpeg::~ExportFFmpeg
~ExportFFmpeg() override
Definition: ExportFFmpeg.cpp:242
TAG_TITLE
#define TAG_TITLE
Definition: Tags.h:60
AVMallocHolder
std::unique_ptr< T, AV_Deleter< void, void, av_free > > AVMallocHolder
Definition: FFmpeg.h:1004
ExportFFmpeg::mSampleRate
int mSampleRate
Definition: ExportFFmpeg.cpp:166
ExportFFmpeg::CheckSampleRate
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.
Definition: ExportFFmpeg.cpp:385
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
ExportFFmpeg::mBitRate
int mBitRate
Definition: ExportFFmpeg.cpp:165
FMT_WMA2
@ FMT_WMA2
Definition: ExportFFmpegDialogs.h:40
TAG_ALBUM
#define TAG_ALBUM
Definition: Tags.h:62