Audacity  2.2.2
ExportFFmpegDialogs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ExportFFmpegDialogs.cpp
6 
7  Audacity(R) is copyright (c) 1999-2010 Audacity Team.
8  License: GPL v2. See License.txt.
9 
10  LRN
11 
12 ******************************************************************//***************************************************************//***************************************************************//***************************************************************//***************************************************************//*******************************************************************/
38 
39 #include "../Audacity.h" // keep ffmpeg before wx because they interact
40 #include "../FFmpeg.h" // and Audacity.h before FFmpeg for config*.h
41 
42 #include "ExportFFmpegDialogs.h"
43 
44 #include <wx/choice.h>
45 #include <wx/intl.h>
46 #include <wx/timer.h>
47 #include <wx/progdlg.h>
48 #include <wx/string.h>
49 #include <wx/textctrl.h>
50 #include <wx/listbox.h>
51 #include <wx/window.h>
52 #include <wx/spinctrl.h>
53 #include <wx/combobox.h>
54 #include <wx/listimpl.cpp>
55 #include <FileDialog.h>
56 
57 #include "../FileFormats.h"
58 #include "../Internat.h"
59 #include "../Mix.h"
60 #include "../Prefs.h"
61 #include "../Project.h"
62 #include "../Tags.h"
63 #include "../TranslatableStringArray.h"
64 #include "../widgets/ErrorDialog.h"
65 
66 #include "Export.h"
67 
68 #if defined(USE_FFMPEG)
69 
70 extern FFmpegLibs *FFmpegLibsInst();
71 
76 #define FFMPEG_EXPORT_CTRL_ID_ENTRIES \
77  FFMPEG_EXPORT_CTRL_ID_FIRST_ENTRY(FEFirstID, 20000), \
78  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEFormatID), \
79  FFMPEG_EXPORT_CTRL_ID_ENTRY(FECodecID), \
80  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEBitrateID), \
81  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEQualityID), \
82  FFMPEG_EXPORT_CTRL_ID_ENTRY(FESampleRateID), \
83  FFMPEG_EXPORT_CTRL_ID_ENTRY(FELanguageID), \
84  FFMPEG_EXPORT_CTRL_ID_ENTRY(FETagID), \
85  FFMPEG_EXPORT_CTRL_ID_ENTRY(FECutoffID), \
86  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEFrameSizeID), \
87  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEBufSizeID), \
88  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEProfileID), \
89  FFMPEG_EXPORT_CTRL_ID_ENTRY(FECompLevelID), \
90  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEUseLPCID), \
91  FFMPEG_EXPORT_CTRL_ID_ENTRY(FELPCCoeffsID), \
92  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEMinPredID), \
93  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEMaxPredID), \
94  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEPredOrderID), \
95  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEMinPartOrderID), \
96  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEMaxPartOrderID), \
97  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEMuxRateID), \
98  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEPacketSizeID), \
99  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEBitReservoirID), \
100  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEVariableBlockLenID), \
101  FFMPEG_EXPORT_CTRL_ID_ENTRY(FELastID), \
102  \
103  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEFormatLabelID), \
104  FFMPEG_EXPORT_CTRL_ID_ENTRY(FECodecLabelID), \
105  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEFormatNameID), \
106  FFMPEG_EXPORT_CTRL_ID_ENTRY(FECodecNameID), \
107  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEPresetID), \
108  FFMPEG_EXPORT_CTRL_ID_ENTRY(FESavePresetID), \
109  FFMPEG_EXPORT_CTRL_ID_ENTRY(FELoadPresetID), \
110  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEDeletePresetID), \
111  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEAllFormatsID), \
112  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEAllCodecsID), \
113  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEImportPresetsID), \
114  FFMPEG_EXPORT_CTRL_ID_ENTRY(FEExportPresetsID) \
115 
116 // First the enumeration
117 #define FFMPEG_EXPORT_CTRL_ID_FIRST_ENTRY(name, num) name = num
118 #define FFMPEG_EXPORT_CTRL_ID_ENTRY(name) name
119 
120 enum FFmpegExportCtrlID {
121  FFMPEG_EXPORT_CTRL_ID_ENTRIES
122 };
123 
124 // Now the string representations
125 #undef FFMPEG_EXPORT_CTRL_ID_FIRST_ENTRY
126 #define FFMPEG_EXPORT_CTRL_ID_FIRST_ENTRY(name, num) wxT(#name)
127 #undef FFMPEG_EXPORT_CTRL_ID_ENTRY
128 #define FFMPEG_EXPORT_CTRL_ID_ENTRY(name) wxT(#name)
129 static const wxChar *FFmpegExportCtrlIDNames[] = {
130  FFMPEG_EXPORT_CTRL_ID_ENTRIES
131 };
132 
133 #undef FFMPEG_EXPORT_CTRL_ID_ENTRIES
134 #undef FFMPEG_EXPORT_CTRL_ID_ENTRY
135 #undef FFMPEG_EXPORT_CTRL_ID_FIRST_ENTRY
136 
137 //----------------------------------------------------------------------------
138 // ExportFFmpegAC3Options Class
139 //----------------------------------------------------------------------------
140 
141 // This initialises content for the static const member variables defined in
142 // ExportFFmpegDialogs.h (note no static keyword - important!)
143 const int ExportFFmpegAC3Options::iAC3BitRates[] = { 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 448000, 512000, 576000, 640000 };
144 const int ExportFFmpegAC3Options::iAC3SampleRates[] = { 32000, 44100, 48000, 0 };
145 
146 ExportFFmpegAC3Options::ExportFFmpegAC3Options(wxWindow *parent, int WXUNUSED(format))
147 : wxPanelWrapper(parent, wxID_ANY)
148 {
149  for (unsigned int i=0; i < (sizeof(iAC3BitRates)/sizeof(int)); i++)
150  {
151  mBitRateNames.Add(wxString::Format(_("%i kbps"),iAC3BitRates[i]/1000));
152  mBitRateLabels.push_back(iAC3BitRates[i]);
153  }
154 
156  PopulateOrExchange(S);
157 
158  TransferDataToWindow();
159 }
160 
161 ExportFFmpegAC3Options::~ExportFFmpegAC3Options()
162 {
163  TransferDataFromWindow();
164 }
165 
168 void ExportFFmpegAC3Options::PopulateOrExchange(ShuttleGui & S)
169 {
170  S.StartVerticalLay();
171  {
172  S.StartHorizontalLay(wxCENTER);
173  {
174  S.StartMultiColumn(2, wxCENTER);
175  {
176  S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/AC3BitRate"),
177  160000, mBitRateNames, mBitRateLabels);
178  }
179  S.EndMultiColumn();
180  }
181  S.EndHorizontalLay();
182  }
183  S.EndVerticalLay();
184 }
185 
188 bool ExportFFmpegAC3Options::TransferDataToWindow()
189 {
190  return true;
191 }
192 
195 bool ExportFFmpegAC3Options::TransferDataFromWindow()
196 {
197  ShuttleGui S(this, eIsSavingToPrefs);
198  PopulateOrExchange(S);
199 
200  gPrefs->Flush();
201 
202  return true;
203 }
204 
205 //----------------------------------------------------------------------------
206 // ExportFFmpegAACOptions Class
207 //----------------------------------------------------------------------------
208 
209 ExportFFmpegAACOptions::ExportFFmpegAACOptions(wxWindow *parent, int WXUNUSED(format))
210 : wxPanelWrapper(parent, wxID_ANY)
211 {
213  PopulateOrExchange(S);
214 
215  TransferDataToWindow();
216 }
217 
218 ExportFFmpegAACOptions::~ExportFFmpegAACOptions()
219 {
220  TransferDataFromWindow();
221 }
222 
225 void ExportFFmpegAACOptions::PopulateOrExchange(ShuttleGui & S)
226 {
227  S.StartVerticalLay();
228  {
229  S.StartHorizontalLay(wxEXPAND);
230  {
231  S.SetSizerProportion(1);
232  S.StartMultiColumn(2, wxCENTER);
233  {
234  S.SetStretchyCol(1);
235  S.Prop(1).TieSlider(_("Quality:"),wxT("/FileFormats/AACQuality"),100,500,10);
236  }
237  S.EndMultiColumn();
238  }
239  S.EndHorizontalLay();
240  }
241  S.EndVerticalLay();
242 }
243 
246 bool ExportFFmpegAACOptions::TransferDataToWindow()
247 {
248  return true;
249 }
250 
253 bool ExportFFmpegAACOptions::TransferDataFromWindow()
254 {
255  ShuttleGui S(this, eIsSavingToPrefs);
256  PopulateOrExchange(S);
257 
258  gPrefs->Flush();
259 
260  return true;
261 }
262 
263 //----------------------------------------------------------------------------
264 // ExportFFmpegAMRNBOptions Class
265 //----------------------------------------------------------------------------
266 
269 int ExportFFmpegAMRNBOptions::iAMRNBBitRate[] =
270 { 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200 };
271 
272 ExportFFmpegAMRNBOptions::ExportFFmpegAMRNBOptions(wxWindow *parent, int WXUNUSED(format))
273 : wxPanelWrapper(parent, wxID_ANY)
274 {
275  for (unsigned int i=0; i < (sizeof(iAMRNBBitRate)/sizeof(int)); i++)
276  {
277  mBitRateNames.Add(wxString::Format(_("%.2f kbps"),(float)iAMRNBBitRate[i]/1000));
278  mBitRateLabels.push_back(iAMRNBBitRate[i]);
279  }
280 
282  PopulateOrExchange(S);
283 
284  TransferDataToWindow();
285 }
286 
287 ExportFFmpegAMRNBOptions::~ExportFFmpegAMRNBOptions()
288 {
289  TransferDataFromWindow();
290 }
291 
294 void ExportFFmpegAMRNBOptions::PopulateOrExchange(ShuttleGui & S)
295 {
296  S.StartVerticalLay();
297  {
298  S.StartHorizontalLay(wxCENTER);
299  {
300  S.StartMultiColumn(2, wxCENTER);
301  {
302  S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/AMRNBBitRate"),
303  12200, mBitRateNames, mBitRateLabels);
304  }
305  S.EndMultiColumn();
306  }
307  S.EndHorizontalLay();
308  }
309  S.EndVerticalLay();
310 }
311 
314 bool ExportFFmpegAMRNBOptions::TransferDataToWindow()
315 {
316  return true;
317 }
318 
321 bool ExportFFmpegAMRNBOptions::TransferDataFromWindow()
322 {
323  ShuttleGui S(this, eIsSavingToPrefs);
324  PopulateOrExchange(S);
325 
326  gPrefs->Flush();
327 
328  return true;
329 }
330 
331 //----------------------------------------------------------------------------
332 // ExportFFmpegWMAOptions Class
333 //----------------------------------------------------------------------------
334 
335 const int ExportFFmpegWMAOptions::iWMASampleRates[] =
336 { 8000, 11025, 16000, 22050, 44100, 0};
337 
339 const int ExportFFmpegWMAOptions::iWMABitRate[] =
340 { 24000, 32000, 40000, 48000, 64000, 80000, 96000, 128000, 160000, 192000, 256000, 320000 };
341 
342 ExportFFmpegWMAOptions::ExportFFmpegWMAOptions(wxWindow *parent, int WXUNUSED(format))
343 : wxPanelWrapper(parent, wxID_ANY)
344 {
345  for (unsigned int i=0; i < (sizeof(iWMABitRate)/sizeof(int)); i++)
346  {
347  mBitRateNames.Add(wxString::Format(wxT("%i kbps"),iWMABitRate[i]/1000));
348  mBitRateLabels.push_back(iWMABitRate[i]);
349  }
350 
352  PopulateOrExchange(S);
353 
354  TransferDataToWindow();
355 }
356 
357 ExportFFmpegWMAOptions::~ExportFFmpegWMAOptions()
358 {
359  TransferDataFromWindow();
360 }
361 
364 void ExportFFmpegWMAOptions::PopulateOrExchange(ShuttleGui & S)
365 {
366  S.StartVerticalLay();
367  {
368  S.StartHorizontalLay(wxCENTER);
369  {
370  S.StartMultiColumn(2, wxCENTER);
371  {
372  S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/WMABitRate"),
373  128000, mBitRateNames, mBitRateLabels);
374  }
375  S.EndMultiColumn();
376  }
377  S.EndHorizontalLay();
378  }
379  S.EndVerticalLay();
380 }
381 
384 bool ExportFFmpegWMAOptions::TransferDataToWindow()
385 {
386  return true;
387 }
388 
391 bool ExportFFmpegWMAOptions::TransferDataFromWindow()
392 {
393  ShuttleGui S(this, eIsSavingToPrefs);
394  PopulateOrExchange(S);
395 
396  gPrefs->Flush();
397 
398  return true;
399 }
400 
401 //----------------------------------------------------------------------------
402 // ExportFFmpegCustomOptions Class
403 //----------------------------------------------------------------------------
404 
405 #define OpenID 9000
406 
407 BEGIN_EVENT_TABLE(ExportFFmpegCustomOptions, wxPanelWrapper)
408  EVT_BUTTON(OpenID, ExportFFmpegCustomOptions::OnOpen)
410 
411 ExportFFmpegCustomOptions::ExportFFmpegCustomOptions(wxWindow *parent, int WXUNUSED(format))
412 : wxPanelWrapper(parent, wxID_ANY)
413 {
415  PopulateOrExchange(S);
416 
417  TransferDataToWindow();
418 }
419 
420 ExportFFmpegCustomOptions::~ExportFFmpegCustomOptions()
421 {
422  TransferDataFromWindow();
423 }
424 
427 void ExportFFmpegCustomOptions::PopulateOrExchange(ShuttleGui & S)
428 {
429  S.StartHorizontalLay(wxCENTER);
430  {
431  S.StartHorizontalLay(wxCENTER, 0);
432  {
433  S.Id(OpenID).AddButton(_("Open custom FFmpeg format options"));
434  }
435  S.EndHorizontalLay();
436  }
437  S.EndHorizontalLay();
438 }
439 
442 bool ExportFFmpegCustomOptions::TransferDataToWindow()
443 {
444  return true;
445 }
446 
449 bool ExportFFmpegCustomOptions::TransferDataFromWindow()
450 {
451  return true;
452 }
453 
456 void ExportFFmpegCustomOptions::OnOpen(wxCommandEvent & WXUNUSED(evt))
457 {
458  // Show "Locate FFmpeg" dialog
459  PickFFmpegLibs();
460  if (!FFmpegLibsInst()->ValidLibsLoaded())
461  {
462  FFmpegLibsInst()->FindLibs(NULL);
463  FFmpegLibsInst()->FreeLibs();
464  if (!LoadFFmpeg(true))
465  {
466  return;
467  }
468  }
469  DropFFmpegLibs();
470 
471  ExportFFmpegOptions od(wxGetTopLevelParent(this));
472  od.ShowModal();
473 }
474 
475 FFmpegPreset::FFmpegPreset()
476 {
477  mControlState.SetCount(FELastID - FEFirstID);
478 }
479 
480 FFmpegPreset::~FFmpegPreset()
481 {
482 }
483 
484 FFmpegPresets::FFmpegPresets()
485 {
486  mPreset = NULL;
487  mAbortImport = false;
488 
489  XMLFileReader xmlfile;
490  wxFileName xmlFileName(FileNames::DataDir(), wxT("ffmpeg_presets.xml"));
491  xmlfile.Parse(this,xmlFileName.GetFullPath());
492 }
493 
494 FFmpegPresets::~FFmpegPresets()
495 {
496  // We're in a destructor! Don't let exceptions out!
497  GuardedCall( [&] {
498  wxFileName xmlFileName{ FileNames::DataDir(), wxT("ffmpeg_presets.xml") };
499  XMLFileWriter writer{
500  xmlFileName.GetFullPath(), _("Error Saving FFmpeg Presets") };
501  WriteXMLHeader(writer);
502  WriteXML(writer);
503  writer.Commit();
504  } );
505 }
506 
507 void FFmpegPresets::ImportPresets(wxString &filename)
508 {
509  mPreset = NULL;
510  mAbortImport = false;
511 
512  FFmpegPresetMap savePresets = mPresets;
513 
514  XMLFileReader xmlfile;
515  bool success = xmlfile.Parse(this,filename);
516  if (!success || mAbortImport) {
517  mPresets = savePresets;
518  }
519 }
520 
521 void FFmpegPresets::ExportPresets(wxString &filename)
522 {
523  GuardedCall( [&] {
524  XMLFileWriter writer{ filename, _("Error Saving FFmpeg Presets") };
525  WriteXMLHeader(writer);
526  WriteXML(writer);
527  writer.Commit();
528  } );
529 }
530 
531 void FFmpegPresets::GetPresetList(wxArrayString &list)
532 {
533  list.Clear();
534  FFmpegPresetMap::iterator iter;
535  for (iter = mPresets.begin(); iter != mPresets.end(); ++iter)
536  {
537  list.Add(iter->second.mPresetName);
538  }
539 
540  list.Sort();
541 }
542 
543 void FFmpegPresets::DeletePreset(wxString &name)
544 {
545  FFmpegPresetMap::iterator iter = mPresets.find(name);
546  if (iter != mPresets.end())
547  {
548  mPresets.erase(iter);
549  }
550 }
551 
552 FFmpegPreset *FFmpegPresets::FindPreset(wxString &name)
553 {
554  FFmpegPresetMap::iterator iter = mPresets.find(name);
555  if (iter != mPresets.end())
556  {
557  return &iter->second;
558  }
559 
560  return NULL;
561 }
562 
563 void FFmpegPresets::SavePreset(ExportFFmpegOptions *parent, wxString &name)
564 {
565  wxString format;
566  wxString codec;
567  FFmpegPreset *preset = FindPreset(name);
568  if (preset)
569  {
570  wxString query = wxString::Format(_("Overwrite preset '%s'?"),name);
571  int action = AudacityMessageBox(query,_("Confirm Overwrite"),wxYES_NO | wxCENTRE);
572  if (action == wxNO) return;
573  }
574 
575  wxWindow *wnd;
576  wxListBox *lb;
577 
578  wnd = dynamic_cast<wxWindow*>(parent)->FindWindowById(FEFormatID,parent);
579  lb = dynamic_cast<wxListBox*>(wnd);
580  if (lb->GetSelection() < 0)
581  {
582  AudacityMessageBox(_("Please select format before saving a profile"));
583  return;
584  }
585  format = lb->GetStringSelection();
586 
587  wnd = dynamic_cast<wxWindow*>(parent)->FindWindowById(FECodecID,parent);
588  lb = dynamic_cast<wxListBox*>(wnd);
589  if (lb->GetSelection() < 0)
590  {
591  AudacityMessageBox(_("Please select codec before saving a profile"));
592  return;
593  }
594  codec = lb->GetStringSelection();
595 
596  preset = &mPresets[name];
597  preset->mPresetName = name;
598 
599  wxSpinCtrl *sc;
600  wxTextCtrl *tc;
601  wxCheckBox *cb;
602  wxChoice *ch;
603 
604  for (int id = FEFirstID; id < FELastID; id++)
605  {
606  wxWindow *wnd = dynamic_cast<wxWindow*>(parent)->FindWindowById(id,parent);
607  if (wnd != NULL)
608  {
609  switch(id)
610  {
611  case FEFormatID:
612  preset->mControlState.Item(id - FEFirstID) = format;
613  break;
614  case FECodecID:
615  preset->mControlState.Item(id - FEFirstID) = codec;
616  break;
617  // Spin control
618  case FEBitrateID:
619  case FEQualityID:
620  case FESampleRateID:
621  case FECutoffID:
622  case FEFrameSizeID:
623  case FEBufSizeID:
624  case FECompLevelID:
625  case FELPCCoeffsID:
626  case FEMinPredID:
627  case FEMaxPredID:
628  case FEMinPartOrderID:
629  case FEMaxPartOrderID:
630  case FEMuxRateID:
631  case FEPacketSizeID:
632  sc = dynamic_cast<wxSpinCtrl*>(wnd);
633  preset->mControlState.Item(id - FEFirstID) = wxString::Format(wxT("%d"),sc->GetValue());
634  break;
635  // Text control
636  case FELanguageID:
637  case FETagID:
638  tc = dynamic_cast<wxTextCtrl*>(wnd);
639  preset->mControlState.Item(id - FEFirstID) = tc->GetValue();
640  break;
641  // Choice
642  case FEProfileID:
643  case FEPredOrderID:
644  ch = dynamic_cast<wxChoice*>(wnd);
645  preset->mControlState.Item(id - FEFirstID) = wxString::Format(wxT("%d"),ch->GetSelection());
646  break;
647  // Check box
648  case FEUseLPCID:
649  case FEBitReservoirID:
650  case FEVariableBlockLenID:
651  cb = dynamic_cast<wxCheckBox*>(wnd);
652  preset->mControlState.Item(id - FEFirstID) = wxString::Format(wxT("%d"),cb->GetValue());
653  break;
654  }
655  }
656  }
657 }
658 
659 void FFmpegPresets::LoadPreset(ExportFFmpegOptions *parent, wxString &name)
660 {
661  FFmpegPreset *preset = FindPreset(name);
662  if (!preset)
663  {
664  AudacityMessageBox(wxString::Format(_("Preset '%s' does not exist."),name));
665  return;
666  }
667 
668  wxListBox *lb;
669  wxSpinCtrl *sc;
670  wxTextCtrl *tc;
671  wxCheckBox *cb;
672  wxChoice *ch;
673 
674  for (int id = FEFirstID; id < FELastID; id++)
675  {
676  wxWindow *wnd = parent->FindWindowById(id,parent);
677  if (wnd != NULL)
678  {
679  wxString readstr;
680  long readlong;
681  bool readbool;
682  switch(id)
683  {
684  // Listbox
685  case FEFormatID:
686  case FECodecID:
687  lb = dynamic_cast<wxListBox*>(wnd);
688  readstr = preset->mControlState.Item(id - FEFirstID);
689  readlong = lb->FindString(readstr);
690  if (readlong > -1) lb->Select(readlong);
691  break;
692  // Spin control
693  case FEBitrateID:
694  case FEQualityID:
695  case FESampleRateID:
696  case FECutoffID:
697  case FEFrameSizeID:
698  case FEBufSizeID:
699  case FECompLevelID:
700  case FELPCCoeffsID:
701  case FEMinPredID:
702  case FEMaxPredID:
703  case FEMinPartOrderID:
704  case FEMaxPartOrderID:
705  case FEMuxRateID:
706  case FEPacketSizeID:
707  sc = dynamic_cast<wxSpinCtrl*>(wnd);
708  preset->mControlState.Item(id - FEFirstID).ToLong(&readlong);
709  sc->SetValue(readlong);
710  break;
711  // Text control
712  case FELanguageID:
713  case FETagID:
714  tc = dynamic_cast<wxTextCtrl*>(wnd);
715  tc->SetValue(preset->mControlState.Item(id - FEFirstID));
716  break;
717  // Choice
718  case FEProfileID:
719  case FEPredOrderID:
720  ch = dynamic_cast<wxChoice*>(wnd);
721  preset->mControlState.Item(id - FEFirstID).ToLong(&readlong);
722  if (readlong > -1) ch->Select(readlong);
723  break;
724  // Check box
725  case FEUseLPCID:
726  case FEBitReservoirID:
727  case FEVariableBlockLenID:
728  cb = dynamic_cast<wxCheckBox*>(wnd);
729  preset->mControlState.Item(id - FEFirstID).ToLong(&readlong);
730  if (readlong) readbool = true; else readbool = false;
731  cb->SetValue(readbool);
732  break;
733  }
734  }
735  }
736 }
737 
738 bool FFmpegPresets::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
739 {
740  if (mAbortImport)
741  {
742  return false;
743  }
744 
745  if (!wxStrcmp(tag,wxT("ffmpeg_presets")))
746  {
747  return true;
748  }
749 
750  if (!wxStrcmp(tag,wxT("preset")))
751  {
752  while (*attrs)
753  {
754  const wxChar *attr = *attrs++;
755  wxString value = *attrs++;
756 
757  if (!value)
758  break;
759 
760  if (!wxStrcmp(attr,wxT("name")))
761  {
762  mPreset = FindPreset(value);
763  if (mPreset)
764  {
765  wxString query = wxString::Format(_("Replace preset '%s'?"), value);
766  int action = AudacityMessageBox(query, _("Confirm Overwrite"), wxYES_NO | wxCANCEL | wxCENTRE);
767  if (action == wxCANCEL)
768  {
769  mAbortImport = true;
770  return false;
771  }
772  if (action == wxNO)
773  {
774  mPreset = NULL;
775  return false;
776  }
777  *mPreset = FFmpegPreset();
778  }
779  else
780  {
781  mPreset = &mPresets[value];
782  }
783  mPreset->mPresetName = value;
784  }
785  }
786  return true;
787  }
788 
789  if (!wxStrcmp(tag,wxT("setctrlstate")) && mPreset)
790  {
791  long id = -1;
792  while (*attrs)
793  {
794  const wxChar *attr = *attrs++;
795  const wxChar *value = *attrs++;
796 
797  if (!value)
798  break;
799 
800  if (!wxStrcmp(attr,wxT("id")))
801  {
802  for (long i = FEFirstID; i < FELastID; i++)
803  if (!wxStrcmp(FFmpegExportCtrlIDNames[i - FEFirstID],value))
804  id = i;
805  }
806  else if (!wxStrcmp(attr,wxT("state")))
807  {
808  if (id > FEFirstID && id < FELastID)
809  mPreset->mControlState.Item(id - FEFirstID) = wxString(value);
810  }
811  }
812  return true;
813  }
814 
815  return false;
816 }
817 
818 XMLTagHandler *FFmpegPresets::HandleXMLChild(const wxChar *tag)
819 {
820  if (mAbortImport)
821  {
822  return NULL;
823  }
824 
825  if (!wxStrcmp(tag, wxT("preset")))
826  {
827  return this;
828  }
829  else if (!wxStrcmp(tag, wxT("setctrlstate")))
830  {
831  return this;
832  }
833  return NULL;
834 }
835 
836 void FFmpegPresets::WriteXMLHeader(XMLWriter &xmlFile) const
837 // may throw
838 {
839  xmlFile.Write(wxT("<?xml "));
840  xmlFile.Write(wxT("version=\"1.0\" "));
841  xmlFile.Write(wxT("standalone=\"no\" "));
842  xmlFile.Write(wxT("?>\n"));
843 
844  wxString dtdName = wxT("-//audacityffmpegpreset-1.0.0//DTD//EN");
845  wxString dtdURI =
846  wxT("http://audacity.sourceforge.net/xml/audacityffmpegpreset-1.0.0.dtd");
847 
848  xmlFile.Write(wxT("<!DOCTYPE "));
849  xmlFile.Write(wxT("project "));
850  xmlFile.Write(wxT("PUBLIC "));
851  xmlFile.Write(wxT("\"-//audacityffmpegpreset-1.0.0//DTD//EN\" "));
852  xmlFile.Write(wxT("\"http://audacity.sourceforge.net/xml/audacityffmpegpreset-1.0.0.dtd\" "));
853  xmlFile.Write(wxT(">\n"));
854 }
855 
856 void FFmpegPresets::WriteXML(XMLWriter &xmlFile) const
857 // may throw
858 {
859  xmlFile.StartTag(wxT("ffmpeg_presets"));
860  xmlFile.WriteAttr(wxT("version"),wxT("1.0"));
861  FFmpegPresetMap::const_iterator iter;
862  for (iter = mPresets.begin(); iter != mPresets.end(); ++iter)
863  {
864  auto preset = &iter->second;
865  xmlFile.StartTag(wxT("preset"));
866  xmlFile.WriteAttr(wxT("name"),preset->mPresetName);
867  for (long i = FEFirstID + 1; i < FELastID; i++)
868  {
869  xmlFile.StartTag(wxT("setctrlstate"));
870  xmlFile.WriteAttr(wxT("id"),wxString(FFmpegExportCtrlIDNames[i - FEFirstID]));
871  xmlFile.WriteAttr(wxT("state"),preset->mControlState.Item(i - FEFirstID));
872  xmlFile.EndTag(wxT("setctrlstate"));
873  }
874  xmlFile.EndTag(wxT("preset"));
875  }
876  xmlFile.EndTag(wxT("ffmpeg_presets"));
877 }
878 
879 //----------------------------------------------------------------------------
880 // ExportFFmpegOptions Class
881 //----------------------------------------------------------------------------
882 
883 BEGIN_EVENT_TABLE(ExportFFmpegOptions, wxDialogWrapper)
884  EVT_BUTTON(wxID_OK,ExportFFmpegOptions::OnOK)
885  EVT_LISTBOX(FEFormatID,ExportFFmpegOptions::OnFormatList)
886  EVT_LISTBOX(FECodecID,ExportFFmpegOptions::OnCodecList)
887  EVT_BUTTON(FEAllFormatsID,ExportFFmpegOptions::OnAllFormats)
888  EVT_BUTTON(FEAllCodecsID,ExportFFmpegOptions::OnAllCodecs)
889  EVT_BUTTON(FESavePresetID,ExportFFmpegOptions::OnSavePreset)
890  EVT_BUTTON(FELoadPresetID,ExportFFmpegOptions::OnLoadPreset)
891  EVT_BUTTON(FEDeletePresetID,ExportFFmpegOptions::OnDeletePreset)
892  EVT_BUTTON(FEImportPresetsID,ExportFFmpegOptions::OnImportPresets)
893  EVT_BUTTON(FEExportPresetsID,ExportFFmpegOptions::OnExportPresets)
895 
898 CompatibilityEntry ExportFFmpegOptions::CompatibilityList[] =
899 {
900  { wxT("adts"), AV_CODEC_ID_AAC },
901 
902  { wxT("aiff"), AV_CODEC_ID_PCM_S16BE },
903  { wxT("aiff"), AV_CODEC_ID_PCM_S8 },
904  { wxT("aiff"), AV_CODEC_ID_PCM_S24BE },
905  { wxT("aiff"), AV_CODEC_ID_PCM_S32BE },
906  { wxT("aiff"), AV_CODEC_ID_PCM_ALAW },
907  { wxT("aiff"), AV_CODEC_ID_PCM_MULAW },
908  { wxT("aiff"), AV_CODEC_ID_MACE3 },
909  { wxT("aiff"), AV_CODEC_ID_MACE6 },
910  { wxT("aiff"), AV_CODEC_ID_GSM },
911  { wxT("aiff"), AV_CODEC_ID_ADPCM_G726 },
912  { wxT("aiff"), AV_CODEC_ID_PCM_S16LE },
913  { wxT("aiff"), AV_CODEC_ID_ADPCM_IMA_QT },
914  { wxT("aiff"), AV_CODEC_ID_QDM2 },
915 
916  { wxT("amr"), AV_CODEC_ID_AMR_NB },
917  { wxT("amr"), AV_CODEC_ID_AMR_WB },
918 
919  { wxT("asf"), AV_CODEC_ID_PCM_S16LE },
920  { wxT("asf"), AV_CODEC_ID_PCM_U8 },
921  { wxT("asf"), AV_CODEC_ID_PCM_S24LE },
922  { wxT("asf"), AV_CODEC_ID_PCM_S32LE },
923  { wxT("asf"), AV_CODEC_ID_ADPCM_MS },
924  { wxT("asf"), AV_CODEC_ID_PCM_ALAW },
925  { wxT("asf"), AV_CODEC_ID_PCM_MULAW },
926  { wxT("asf"), AV_CODEC_ID_WMAVOICE },
927  { wxT("asf"), AV_CODEC_ID_ADPCM_IMA_WAV },
928  { wxT("asf"), AV_CODEC_ID_ADPCM_YAMAHA },
929  { wxT("asf"), AV_CODEC_ID_TRUESPEECH },
930  { wxT("asf"), AV_CODEC_ID_GSM_MS },
931  { wxT("asf"), AV_CODEC_ID_ADPCM_G726 },
932  { wxT("asf"), AV_CODEC_ID_MP2 },
933  { wxT("asf"), AV_CODEC_ID_MP3 },
934 #if LIBAVCODEC_VERSION_MAJOR < 58
935  { wxT("asf"), AV_CODEC_ID_VOXWARE },
936 #endif
937  { wxT("asf"), AV_CODEC_ID_AAC },
938  { wxT("asf"), AV_CODEC_ID_WMAV1 },
939  { wxT("asf"), AV_CODEC_ID_WMAV2 },
940  { wxT("asf"), AV_CODEC_ID_WMAPRO },
941  { wxT("asf"), AV_CODEC_ID_ADPCM_CT },
942  { wxT("asf"), AV_CODEC_ID_ATRAC3 },
943  { wxT("asf"), AV_CODEC_ID_IMC },
944  { wxT("asf"), AV_CODEC_ID_AC3 },
945  { wxT("asf"), AV_CODEC_ID_DTS },
946  { wxT("asf"), AV_CODEC_ID_FLAC },
947  { wxT("asf"), AV_CODEC_ID_ADPCM_SWF },
948  { wxT("asf"), AV_CODEC_ID_VORBIS },
949 
950  { wxT("au"), AV_CODEC_ID_PCM_MULAW },
951  { wxT("au"), AV_CODEC_ID_PCM_S8 },
952  { wxT("au"), AV_CODEC_ID_PCM_S16BE },
953  { wxT("au"), AV_CODEC_ID_PCM_ALAW },
954 
955  { wxT("avi"), AV_CODEC_ID_PCM_S16LE },
956  { wxT("avi"), AV_CODEC_ID_PCM_U8 },
957  { wxT("avi"), AV_CODEC_ID_PCM_S24LE },
958  { wxT("avi"), AV_CODEC_ID_PCM_S32LE },
959  { wxT("avi"), AV_CODEC_ID_ADPCM_MS },
960  { wxT("avi"), AV_CODEC_ID_PCM_ALAW },
961  { wxT("avi"), AV_CODEC_ID_PCM_MULAW },
962  { wxT("avi"), AV_CODEC_ID_WMAVOICE },
963  { wxT("avi"), AV_CODEC_ID_ADPCM_IMA_WAV },
964  { wxT("avi"), AV_CODEC_ID_ADPCM_YAMAHA },
965  { wxT("avi"), AV_CODEC_ID_TRUESPEECH },
966  { wxT("avi"), AV_CODEC_ID_GSM_MS },
967  { wxT("avi"), AV_CODEC_ID_ADPCM_G726 },
968  { wxT("avi"), AV_CODEC_ID_MP2 },
969  { wxT("avi"), AV_CODEC_ID_MP3 },
970 #if LIBAVCODEC_VERSION_MAJOR < 58
971  { wxT("avi"), AV_CODEC_ID_VOXWARE },
972 #endif
973  { wxT("avi"), AV_CODEC_ID_AAC },
974  { wxT("avi"), AV_CODEC_ID_WMAV1 },
975  { wxT("avi"), AV_CODEC_ID_WMAV2 },
976  { wxT("avi"), AV_CODEC_ID_WMAPRO },
977  { wxT("avi"), AV_CODEC_ID_ADPCM_CT },
978  { wxT("avi"), AV_CODEC_ID_ATRAC3 },
979  { wxT("avi"), AV_CODEC_ID_IMC },
980  { wxT("avi"), AV_CODEC_ID_AC3 },
981  { wxT("avi"), AV_CODEC_ID_DTS },
982  { wxT("avi"), AV_CODEC_ID_FLAC },
983  { wxT("avi"), AV_CODEC_ID_ADPCM_SWF },
984  { wxT("avi"), AV_CODEC_ID_VORBIS },
985 
986  { wxT("crc"), AV_CODEC_ID_NONE },
987 
988  { wxT("dv"), AV_CODEC_ID_PCM_S16LE },
989 
990  { wxT("ffm"), AV_CODEC_ID_NONE },
991 
992  { wxT("flv"), AV_CODEC_ID_MP3 },
993  { wxT("flv"), AV_CODEC_ID_PCM_S8 },
994  { wxT("flv"), AV_CODEC_ID_PCM_S16BE },
995  { wxT("flv"), AV_CODEC_ID_PCM_S16LE },
996  { wxT("flv"), AV_CODEC_ID_ADPCM_SWF },
997  { wxT("flv"), AV_CODEC_ID_AAC },
998  { wxT("flv"), AV_CODEC_ID_NELLYMOSER },
999 
1000  { wxT("framecrc"), AV_CODEC_ID_NONE },
1001 
1002  { wxT("gxf"), AV_CODEC_ID_PCM_S16LE },
1003 
1004  { wxT("matroska"), AV_CODEC_ID_PCM_S16LE },
1005  { wxT("matroska"), AV_CODEC_ID_PCM_U8 },
1006  { wxT("matroska"), AV_CODEC_ID_PCM_S24LE },
1007  { wxT("matroska"), AV_CODEC_ID_PCM_S32LE },
1008  { wxT("matroska"), AV_CODEC_ID_ADPCM_MS },
1009  { wxT("matroska"), AV_CODEC_ID_PCM_ALAW },
1010  { wxT("matroska"), AV_CODEC_ID_PCM_MULAW },
1011  { wxT("matroska"), AV_CODEC_ID_WMAVOICE },
1012  { wxT("matroska"), AV_CODEC_ID_ADPCM_IMA_WAV },
1013  { wxT("matroska"), AV_CODEC_ID_ADPCM_YAMAHA },
1014  { wxT("matroska"), AV_CODEC_ID_TRUESPEECH },
1015  { wxT("matroska"), AV_CODEC_ID_GSM_MS },
1016  { wxT("matroska"), AV_CODEC_ID_ADPCM_G726 },
1017  { wxT("matroska"), AV_CODEC_ID_MP2 },
1018  { wxT("matroska"), AV_CODEC_ID_MP3 },
1019 #if LIBAVCODEC_VERSION_MAJOR < 58
1020  { wxT("matroska"), AV_CODEC_ID_VOXWARE },
1021 #endif
1022  { wxT("matroska"), AV_CODEC_ID_AAC },
1023  { wxT("matroska"), AV_CODEC_ID_WMAV1 },
1024  { wxT("matroska"), AV_CODEC_ID_WMAV2 },
1025  { wxT("matroska"), AV_CODEC_ID_WMAPRO },
1026  { wxT("matroska"), AV_CODEC_ID_ADPCM_CT },
1027  { wxT("matroska"), AV_CODEC_ID_ATRAC3 },
1028  { wxT("matroska"), AV_CODEC_ID_IMC },
1029  { wxT("matroska"), AV_CODEC_ID_AC3 },
1030  { wxT("matroska"), AV_CODEC_ID_DTS },
1031  { wxT("matroska"), AV_CODEC_ID_FLAC },
1032  { wxT("matroska"), AV_CODEC_ID_ADPCM_SWF },
1033  { wxT("matroska"), AV_CODEC_ID_VORBIS },
1034 
1035  { wxT("mmf"), AV_CODEC_ID_ADPCM_YAMAHA },
1036 
1037  { wxT("mov"), AV_CODEC_ID_PCM_S32BE }, //mov
1038  { wxT("mov"), AV_CODEC_ID_PCM_S32LE },
1039  { wxT("mov"), AV_CODEC_ID_PCM_S24BE },
1040  { wxT("mov"), AV_CODEC_ID_PCM_S24LE },
1041  { wxT("mov"), AV_CODEC_ID_PCM_S16BE },
1042  { wxT("mov"), AV_CODEC_ID_PCM_S16LE },
1043  { wxT("mov"), AV_CODEC_ID_PCM_S8 },
1044  { wxT("mov"), AV_CODEC_ID_PCM_U8 },
1045  { wxT("mov"), AV_CODEC_ID_PCM_MULAW },
1046  { wxT("mov"), AV_CODEC_ID_PCM_ALAW },
1047  { wxT("mov"), AV_CODEC_ID_ADPCM_IMA_QT },
1048  { wxT("mov"), AV_CODEC_ID_MACE3 },
1049  { wxT("mov"), AV_CODEC_ID_MACE6 },
1050  { wxT("mov"), AV_CODEC_ID_MP3 },
1051  { wxT("mov"), AV_CODEC_ID_AAC },
1052  { wxT("mov"), AV_CODEC_ID_AMR_NB },
1053  { wxT("mov"), AV_CODEC_ID_AMR_WB },
1054  { wxT("mov"), AV_CODEC_ID_GSM },
1055  { wxT("mov"), AV_CODEC_ID_ALAC },
1056  { wxT("mov"), AV_CODEC_ID_QCELP },
1057  { wxT("mov"), AV_CODEC_ID_QDM2 },
1058  { wxT("mov"), AV_CODEC_ID_DVAUDIO },
1059  { wxT("mov"), AV_CODEC_ID_WMAV2 },
1060  { wxT("mov"), AV_CODEC_ID_ALAC },
1061 
1062  { wxT("mp4"), AV_CODEC_ID_AAC },
1063  { wxT("mp4"), AV_CODEC_ID_QCELP },
1064  { wxT("mp4"), AV_CODEC_ID_MP3 },
1065  { wxT("mp4"), AV_CODEC_ID_VORBIS },
1066 
1067  { wxT("psp"), AV_CODEC_ID_AAC },
1068  { wxT("psp"), AV_CODEC_ID_QCELP },
1069  { wxT("psp"), AV_CODEC_ID_MP3 },
1070  { wxT("psp"), AV_CODEC_ID_VORBIS },
1071 
1072  { wxT("ipod"), AV_CODEC_ID_AAC },
1073  { wxT("ipod"), AV_CODEC_ID_QCELP },
1074  { wxT("ipod"), AV_CODEC_ID_MP3 },
1075  { wxT("ipod"), AV_CODEC_ID_VORBIS },
1076 
1077  { wxT("3gp"), AV_CODEC_ID_AAC },
1078  { wxT("3gp"), AV_CODEC_ID_AMR_NB },
1079  { wxT("3gp"), AV_CODEC_ID_AMR_WB },
1080 
1081  { wxT("3g2"), AV_CODEC_ID_AAC },
1082  { wxT("3g2"), AV_CODEC_ID_AMR_NB },
1083  { wxT("3g2"), AV_CODEC_ID_AMR_WB },
1084 
1085  { wxT("mp3"), AV_CODEC_ID_MP3 },
1086 
1087  { wxT("mpeg"), AV_CODEC_ID_AC3 },
1088  { wxT("mpeg"), AV_CODEC_ID_DTS },
1089  { wxT("mpeg"), AV_CODEC_ID_PCM_S16BE },
1090  { wxT("mpeg"), AV_CODEC_ID_MP2 },
1091 
1092  { wxT("vcd"), AV_CODEC_ID_AC3 },
1093  { wxT("vcd"), AV_CODEC_ID_DTS },
1094  { wxT("vcd"), AV_CODEC_ID_PCM_S16BE },
1095  { wxT("vcd"), AV_CODEC_ID_MP2 },
1096 
1097  { wxT("vob"), AV_CODEC_ID_AC3 },
1098  { wxT("vob"), AV_CODEC_ID_DTS },
1099  { wxT("vob"), AV_CODEC_ID_PCM_S16BE },
1100  { wxT("vob"), AV_CODEC_ID_MP2 },
1101 
1102  { wxT("svcd"), AV_CODEC_ID_AC3 },
1103  { wxT("svcd"), AV_CODEC_ID_DTS },
1104  { wxT("svcd"), AV_CODEC_ID_PCM_S16BE },
1105  { wxT("svcd"), AV_CODEC_ID_MP2 },
1106 
1107  { wxT("dvd"), AV_CODEC_ID_AC3 },
1108  { wxT("dvd"), AV_CODEC_ID_DTS },
1109  { wxT("dvd"), AV_CODEC_ID_PCM_S16BE },
1110  { wxT("dvd"), AV_CODEC_ID_MP2 },
1111 
1112  { wxT("nut"), AV_CODEC_ID_PCM_S16LE },
1113  { wxT("nut"), AV_CODEC_ID_PCM_U8 },
1114  { wxT("nut"), AV_CODEC_ID_PCM_S24LE },
1115  { wxT("nut"), AV_CODEC_ID_PCM_S32LE },
1116  { wxT("nut"), AV_CODEC_ID_ADPCM_MS },
1117  { wxT("nut"), AV_CODEC_ID_PCM_ALAW },
1118  { wxT("nut"), AV_CODEC_ID_PCM_MULAW },
1119  { wxT("nut"), AV_CODEC_ID_WMAVOICE },
1120  { wxT("nut"), AV_CODEC_ID_ADPCM_IMA_WAV },
1121  { wxT("nut"), AV_CODEC_ID_ADPCM_YAMAHA },
1122  { wxT("nut"), AV_CODEC_ID_TRUESPEECH },
1123  { wxT("nut"), AV_CODEC_ID_GSM_MS },
1124  { wxT("nut"), AV_CODEC_ID_ADPCM_G726 },
1125  { wxT("nut"), AV_CODEC_ID_MP2 },
1126  { wxT("nut"), AV_CODEC_ID_MP3 },
1127  #if LIBAVCODEC_VERSION_MAJOR < 58
1128  { wxT("nut"), AV_CODEC_ID_VOXWARE },
1129  #endif
1130  { wxT("nut"), AV_CODEC_ID_AAC },
1131  { wxT("nut"), AV_CODEC_ID_WMAV1 },
1132  { wxT("nut"), AV_CODEC_ID_WMAV2 },
1133  { wxT("nut"), AV_CODEC_ID_WMAPRO },
1134  { wxT("nut"), AV_CODEC_ID_ADPCM_CT },
1135  { wxT("nut"), AV_CODEC_ID_ATRAC3 },
1136  { wxT("nut"), AV_CODEC_ID_IMC },
1137  { wxT("nut"), AV_CODEC_ID_AC3 },
1138  { wxT("nut"), AV_CODEC_ID_DTS },
1139  { wxT("nut"), AV_CODEC_ID_FLAC },
1140  { wxT("nut"), AV_CODEC_ID_ADPCM_SWF },
1141  { wxT("nut"), AV_CODEC_ID_VORBIS },
1142 
1143  { wxT("ogg"), AV_CODEC_ID_VORBIS },
1144  { wxT("ogg"), AV_CODEC_ID_FLAC },
1145 
1146  { wxT("ac3"), AV_CODEC_ID_AC3 },
1147 
1148  { wxT("dts"), AV_CODEC_ID_DTS },
1149 
1150  { wxT("flac"), AV_CODEC_ID_FLAC },
1151 
1152  { wxT("RoQ"), AV_CODEC_ID_ROQ_DPCM },
1153 
1154  { wxT("rm"), AV_CODEC_ID_AC3 },
1155 
1156  { wxT("swf"), AV_CODEC_ID_MP3 },
1157 
1158  { wxT("avm2"), AV_CODEC_ID_MP3 },
1159 
1160  { wxT("voc"), AV_CODEC_ID_PCM_U8 },
1161 
1162  { wxT("wav"), AV_CODEC_ID_PCM_S16LE },
1163  { wxT("wav"), AV_CODEC_ID_PCM_U8 },
1164  { wxT("wav"), AV_CODEC_ID_PCM_S24LE },
1165  { wxT("wav"), AV_CODEC_ID_PCM_S32LE },
1166  { wxT("wav"), AV_CODEC_ID_ADPCM_MS },
1167  { wxT("wav"), AV_CODEC_ID_PCM_ALAW },
1168  { wxT("wav"), AV_CODEC_ID_PCM_MULAW },
1169  { wxT("wav"), AV_CODEC_ID_WMAVOICE },
1170  { wxT("wav"), AV_CODEC_ID_ADPCM_IMA_WAV },
1171  { wxT("wav"), AV_CODEC_ID_ADPCM_YAMAHA },
1172  { wxT("wav"), AV_CODEC_ID_TRUESPEECH },
1173  { wxT("wav"), AV_CODEC_ID_GSM_MS },
1174  { wxT("wav"), AV_CODEC_ID_ADPCM_G726 },
1175  { wxT("wav"), AV_CODEC_ID_MP2 },
1176  { wxT("wav"), AV_CODEC_ID_MP3 },
1177 #if LIBAVCODEC_VERSION_MAJOR < 58
1178  { wxT("wav"), AV_CODEC_ID_VOXWARE },
1179 #endif
1180  { wxT("wav"), AV_CODEC_ID_AAC },
1181  { wxT("wav"), AV_CODEC_ID_WMAV1 },
1182  { wxT("wav"), AV_CODEC_ID_WMAV2 },
1183  { wxT("wav"), AV_CODEC_ID_WMAPRO },
1184  { wxT("wav"), AV_CODEC_ID_ADPCM_CT },
1185  { wxT("wav"), AV_CODEC_ID_ATRAC3 },
1186  { wxT("wav"), AV_CODEC_ID_IMC },
1187  { wxT("wav"), AV_CODEC_ID_AC3 },
1188  { wxT("wav"), AV_CODEC_ID_DTS },
1189  { wxT("wav"), AV_CODEC_ID_FLAC },
1190  { wxT("wav"), AV_CODEC_ID_ADPCM_SWF },
1191  { wxT("wav"), AV_CODEC_ID_VORBIS },
1192 
1193  { NULL, AV_CODEC_ID_NONE }
1194 };
1195 
1197 int ExportFFmpegOptions::iAACProfileValues[] = {
1198  FF_PROFILE_AAC_LOW,
1199  FF_PROFILE_AAC_MAIN,
1200  /*FF_PROFILE_AAC_SSR,*/
1201  FF_PROFILE_AAC_LTP
1202 };
1203 
1205 static wxString iAACProfileNames(int index)
1206 {
1207  static const wxString names[] = {
1208  XO("LC"),
1209  XO("Main"),
1210  /*_("SSR"),*/ //SSR is not supported
1211  XO("LTP")
1212  };
1213 
1214  class NamesArray final : public TranslatableStringArray
1215  {
1216  void Populate() override
1217  {
1218  for (auto &name : names)
1219  mContents.push_back( wxGetTranslation( name ) );
1220  }
1221  };
1222 
1223  static NamesArray theArray;
1224 
1225  return theArray.Get()[ index ];
1226 }
1227 
1229 ExposedFormat ExportFFmpegOptions::fmts[] =
1230 {
1231  {FMT_M4A, wxT("M4A"), wxT("m4a"), wxT("ipod"), 48, AV_CANMETA, true, XO("M4A (AAC) Files (FFmpeg)"), AV_CODEC_ID_AAC, true},
1232  {FMT_AC3, wxT("AC3"), wxT("ac3"), wxT("ac3"), 7, AV_VERSION_INT(0,0,0), false, XO("AC3 Files (FFmpeg)"), AV_CODEC_ID_AC3, true},
1233  {FMT_AMRNB, wxT("AMRNB"), wxT("amr"), wxT("amr"), 1, AV_VERSION_INT(0,0,0), false, XO("AMR (narrow band) Files (FFmpeg)"), AV_CODEC_ID_AMR_NB, true},
1234  {FMT_WMA2, wxT("WMA"), wxT("wma"), wxT("asf"), 2, AV_VERSION_INT(52,53,0), false, XO("WMA (version 2) Files (FFmpeg)"), AV_CODEC_ID_WMAV2, true},
1235  {FMT_OTHER, wxT("FFMPEG"), wxT(""), wxT(""), 255, AV_CANMETA, true, XO("Custom FFmpeg Export"), AV_CODEC_ID_NONE, true}
1236 };
1237 
1238 wxString ExposedFormat::Description() const
1239 {
1240  return wxGetTranslation(description_);
1241 }
1242 
1244 const int ExportFFmpegOptions::iAACSampleRates[] = { 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 0 };
1245 
1253 ApplicableFor ExportFFmpegOptions::apptable[] =
1254 {
1255  {TRUE,FEQualityID,AV_CODEC_ID_AAC,"any"},
1256  {TRUE,FEQualityID,AV_CODEC_ID_MP3,"any"},
1257  {TRUE,FEQualityID,AV_CODEC_ID_VORBIS,"any"},
1258  {FALSE,FEQualityID,AV_CODEC_ID_NONE,"any"},
1259 
1260  {TRUE,FECutoffID,AV_CODEC_ID_AC3,"any"},
1261  {TRUE,FECutoffID,AV_CODEC_ID_AAC,"any"},
1262  {TRUE,FECutoffID,AV_CODEC_ID_VORBIS,"any"},
1263  {FALSE,FECutoffID,AV_CODEC_ID_NONE,"any"},
1264 
1265  {TRUE,FEFrameSizeID,AV_CODEC_ID_FLAC,"any"},
1266  {FALSE,FEFrameSizeID,AV_CODEC_ID_NONE,"any"},
1267 
1268  {TRUE,FEProfileID,AV_CODEC_ID_AAC,"any"},
1269  {FALSE,FEProfileID,AV_CODEC_ID_NONE,"any"},
1270 
1271  {TRUE,FECompLevelID,AV_CODEC_ID_FLAC,"any"},
1272  {FALSE,FECompLevelID,AV_CODEC_ID_NONE,"any"},
1273 
1274  {TRUE,FEUseLPCID,AV_CODEC_ID_FLAC,"any"},
1275  {FALSE,FEUseLPCID,AV_CODEC_ID_NONE,"any"},
1276 
1277  {TRUE,FELPCCoeffsID,AV_CODEC_ID_FLAC,"any"},
1278  {FALSE,FELPCCoeffsID,AV_CODEC_ID_NONE,"any"},
1279 
1280  {TRUE,FEMinPredID,AV_CODEC_ID_FLAC,"any"},
1281  {FALSE,FEMinPredID,AV_CODEC_ID_NONE,"any"},
1282 
1283  {TRUE,FEMaxPredID,AV_CODEC_ID_FLAC,"any"},
1284  {FALSE,FEMaxPredID,AV_CODEC_ID_NONE,"any"},
1285 
1286  {TRUE,FEPredOrderID,AV_CODEC_ID_FLAC,"any"},
1287  {FALSE,FEPredOrderID,AV_CODEC_ID_NONE,"any"},
1288 
1289  {TRUE,FEMinPartOrderID,AV_CODEC_ID_FLAC,"any"},
1290  {FALSE,FEMinPartOrderID,AV_CODEC_ID_NONE,"any"},
1291 
1292  {TRUE,FEMaxPartOrderID,AV_CODEC_ID_FLAC,"any"},
1293  {FALSE,FEMaxPartOrderID,AV_CODEC_ID_NONE,"any"},
1294 
1295  {TRUE,FEMuxRateID,AV_CODEC_ID_NONE,"mpeg"},
1296  {TRUE,FEMuxRateID,AV_CODEC_ID_NONE,"vcd"},
1297  {TRUE,FEMuxRateID,AV_CODEC_ID_NONE,"vob"},
1298  {TRUE,FEMuxRateID,AV_CODEC_ID_NONE,"svcd"},
1299  {TRUE,FEMuxRateID,AV_CODEC_ID_NONE,"dvd"},
1300  {FALSE,FEMuxRateID,AV_CODEC_ID_NONE,"any"},
1301 
1302  {TRUE,FEPacketSizeID,AV_CODEC_ID_NONE,"mpeg"},
1303  {TRUE,FEPacketSizeID,AV_CODEC_ID_NONE,"vcd"},
1304  {TRUE,FEPacketSizeID,AV_CODEC_ID_NONE,"vob"},
1305  {TRUE,FEPacketSizeID,AV_CODEC_ID_NONE,"svcd"},
1306  {TRUE,FEPacketSizeID,AV_CODEC_ID_NONE,"dvd"},
1307  {FALSE,FEPacketSizeID,AV_CODEC_ID_NONE,"any"},
1308 
1309  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"matroska"},
1310  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"mov"},
1311  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"3gp"},
1312  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"mp4"},
1313  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"psp"},
1314  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"3g2"},
1315  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"ipod"},
1316  {TRUE,FELanguageID,AV_CODEC_ID_NONE,"mpegts"},
1317  {FALSE,FELanguageID,AV_CODEC_ID_NONE,"any"},
1318 
1319  {TRUE,FEBitReservoirID,AV_CODEC_ID_MP3,"any"},
1320  {TRUE,FEBitReservoirID,AV_CODEC_ID_WMAV1,"any"},
1321  {TRUE,FEBitReservoirID,AV_CODEC_ID_WMAV2,"any"},
1322  {FALSE,FEBitReservoirID,AV_CODEC_ID_NONE,"any"},
1323 
1324  {TRUE,FEVariableBlockLenID,AV_CODEC_ID_WMAV1,"any"},
1325  {TRUE,FEVariableBlockLenID,AV_CODEC_ID_WMAV2,"any"},
1326  {FALSE,FEVariableBlockLenID,AV_CODEC_ID_NONE,"any"},
1327 
1328  {FALSE,FFmpegExportCtrlID(0),AV_CODEC_ID_NONE,NULL}
1329 };
1330 
1332 static wxString PredictionOrderMethodNames(int index)
1333 {
1334  static const wxString names[] = {
1335  XO("Estimate"),
1336  XO("2-level"),
1337  XO("4-level"),
1338  XO("8-level"),
1339  XO("Full search"),
1340  XO("Log search")
1341  };
1342 
1343  class NamesArray final : public TranslatableStringArray
1344  {
1345  void Populate() override
1346  {
1347  for (auto &name : names)
1348  mContents.push_back( wxGetTranslation( name ) );
1349  }
1350  };
1351 
1352  static NamesArray theArray;
1353 
1354  return theArray.Get()[ index ];
1355 }
1356 
1357 
1358 
1359 ExportFFmpegOptions::~ExportFFmpegOptions()
1360 {
1361  DropFFmpegLibs();
1362 }
1363 
1364 ExportFFmpegOptions::ExportFFmpegOptions(wxWindow *parent)
1365 : wxDialogWrapper(parent, wxID_ANY,
1366  wxString(_("Configure custom FFmpeg options")))
1367 {
1368  SetName(GetTitle());
1370  PickFFmpegLibs();
1371  //FFmpegLibsInst()->LoadLibs(NULL,true); //Loaded at startup or from Prefs now
1372 
1373  mPresets = std::make_unique<FFmpegPresets>();
1374  mPresets->GetPresetList(mPresetNames);
1375 
1376  if (FFmpegLibsInst()->ValidLibsLoaded())
1377  {
1378  FetchFormatList();
1379  FetchCodecList();
1380 
1381  for (unsigned int i = 0; i < 6; i++)
1382  {
1383  mPredictionOrderMethodLabels.push_back(i);
1384  mPredictionOrderMethodNames.Add(wxString::Format(wxT("%s"),PredictionOrderMethodNames(i)));
1385  }
1386 
1387  for (unsigned int i=0; i < (sizeof(iAACProfileValues)/sizeof(int)); i++)
1388  {
1389  mProfileNames.Add(wxString::Format(wxT("%s"),iAACProfileNames(i)));
1390  mProfileLabels.push_back(iAACProfileValues[i]);
1391  }
1392 
1393  PopulateOrExchange(S);
1394 
1395  //Select the format that was selected last time this dialog was closed
1396  mFormatList->Select(mFormatList->FindString(gPrefs->Read(wxT("/FileFormats/FFmpegFormat"))));
1397  DoOnFormatList();
1398 
1399  //Select the codec that was selected last time this dialog was closed
1400  AVCodec *codec = avcodec_find_encoder_by_name(gPrefs->Read(wxT("/FileFormats/FFmpegCodec")).ToUTF8());
1401  if (codec != NULL) mCodecList->Select(mCodecList->FindString(wxString::FromUTF8(codec->name)));
1402  DoOnCodecList();
1403  }
1404 
1405 }
1406 
1409 void ExportFFmpegOptions::FetchFormatList()
1410 {
1411  // Enumerate all output formats
1412  AVOutputFormat *ofmt = NULL;
1413  while ((ofmt = av_oformat_next(ofmt))!=NULL)
1414  {
1415  // Any audio-capable format has default audio codec.
1416  // If it doesn't, then it doesn't supports any audio codecs
1417  if (ofmt->audio_codec != AV_CODEC_ID_NONE)
1418  {
1419  mFormatNames.Add(wxString::FromUTF8(ofmt->name));
1420  mFormatLongNames.Add(wxString::Format(wxT("%s - %s"),mFormatNames.Last(),wxString::FromUTF8(ofmt->long_name)));
1421  }
1422  }
1423  // Show all formats
1424  mShownFormatNames = mFormatNames;
1425  mShownFormatLongNames = mFormatLongNames;
1426 }
1427 
1430 void ExportFFmpegOptions::FetchCodecList()
1431 {
1432  // Enumerate all codecs
1433  AVCodec *codec = NULL;
1434  while ((codec = av_codec_next(codec))!=NULL)
1435  {
1436  // We're only interested in audio and only in encoders
1437  if (codec->type == AVMEDIA_TYPE_AUDIO && av_codec_is_encoder(codec))
1438  {
1439  mCodecNames.Add(wxString::FromUTF8(codec->name));
1440  mCodecLongNames.Add(wxString::Format(wxT("%s - %s"),mCodecNames.Last(),wxString::FromUTF8(codec->long_name)));
1441  }
1442  }
1443  // Show all codecs
1444  mShownCodecNames = mCodecNames;
1445  mShownCodecLongNames = mCodecLongNames;
1446 }
1447 
1450 void ExportFFmpegOptions::PopulateOrExchange(ShuttleGui & S)
1451 {
1452  S.StartVerticalLay(1);
1453  S.StartMultiColumn(1, wxEXPAND);
1454  {
1455  S.SetStretchyRow(3);
1456  S.StartMultiColumn(7, wxEXPAND);
1457  {
1458  S.SetStretchyCol(1);
1459  mPresetCombo = S.Id(FEPresetID).AddCombo(_("Preset:"), gPrefs->Read(wxT("/FileFormats/FFmpegPreset"),wxEmptyString), &mPresetNames);
1460  mLoadPreset = S.Id(FELoadPresetID).AddButton(_("Load Preset"));
1461  mSavePreset = S.Id(FESavePresetID).AddButton(_("Save Preset"));
1462  mDeletePreset = S.Id(FEDeletePresetID).AddButton(_("Delete Preset"));
1463  mImportPresets = S.Id(FEImportPresetsID).AddButton(_("Import Presets"));
1464  mExportPresets = S.Id(FEExportPresetsID).AddButton(_("Export Presets"));
1465  }
1466  S.EndMultiColumn();
1467  S.StartMultiColumn(4, wxALIGN_LEFT);
1468  {
1469  S.SetStretchyCol(1);
1470  S.SetStretchyCol(3);
1471  S.Id(FEFormatLabelID).AddFixedText(_("Format:"));
1472  mFormatName = S.Id(FEFormatNameID).AddVariableText( {} );
1473  S.Id(FECodecLabelID).AddFixedText(_("Codec:"));
1474  mCodecName = S.Id(FECodecNameID).AddVariableText( {} );
1475  }
1476  S.EndMultiColumn();
1477  S.AddVariableText(_("Not all formats and codecs are compatible. Nor are all option combinations compatible with all codecs."), false);
1478  S.StartMultiColumn(2, wxEXPAND);
1479  {
1480  S.StartMultiColumn(2, wxEXPAND);
1481  {
1482  S.SetStretchyRow(1);
1483  S.Id(FEAllFormatsID).AddButton(_("Show All Formats"));
1484  S.Id(FEAllCodecsID).AddButton(_("Show All Codecs"));
1485  mFormatList = S.Id(FEFormatID).AddListBox(&mFormatNames);
1486  mFormatList->DeselectAll();
1487  mCodecList = S.Id(FECodecID).AddListBox(&mCodecNames);
1488  mCodecList->DeselectAll();
1489  }
1490  S.EndMultiColumn();
1491  S.StartVerticalLay();
1492  {
1493  //S.StartScroller( );
1494  S.SetBorder( 3 );
1495  S.StartStatic(_("General Options"), 0);
1496  {
1497  S.StartMultiColumn(8, wxEXPAND);
1498  {
1499  mLanguageText = S.Id(FELanguageID).TieTextBox(_("Language:"), wxT("/FileFormats/FFmpegLanguage"), wxEmptyString, 9);
1500  mLanguageText->SetToolTip(_("ISO 639 3-letter language code\nOptional\nempty - automatic"));
1501 
1502  S.AddSpace( 20,0 );
1503  S.AddVariableText(_("Bit Reservoir"));
1504  S.Id(FEBitReservoirID).TieCheckBox( {}, wxT("/FileFormats/FFmpegBitReservoir"), true);
1505 
1506  S.AddSpace( 20,0 );
1507  S.AddVariableText(_("VBL"));
1508  S.Id(FEVariableBlockLenID).TieCheckBox( {}, wxT("/FileFormats/FFmpegVariableBlockLen"), true);
1509  }
1510  S.EndMultiColumn();
1511  S.StartMultiColumn(4, wxALIGN_LEFT);
1512  {
1513  mTag = S.Id(FETagID).TieTextBox(_("Tag:"), wxT("/FileFormats/FFmpegTag"), wxEmptyString, 4);
1514  mTag->SetToolTip(_("Codec tag (FOURCC)\nOptional\nempty - automatic"));
1515 
1516  mBitrateSpin = S.Id(FEBitrateID).TieSpinCtrl(_("Bit Rate:"), wxT("/FileFormats/FFmpegBitRate"), 0, 1000000, 0);
1517  mBitrateSpin->SetToolTip(_("Bit Rate (bits/second) - influences the resulting file size and quality\nSome codecs may only accept specific values (128k, 192k, 256k etc)\n0 - automatic\nRecommended - 192000"));
1518 
1519  mQualitySpin = S.Id(FEQualityID).TieSpinCtrl(_("Quality:"), wxT("/FileFormats/FFmpegQuality"), 0, 500, -1);
1520  mQualitySpin->SetToolTip(_("Overall quality, used differently by different codecs\nRequired for vorbis\n0 - automatic\n-1 - off (use bitrate instead)"));
1521 
1522  mSampleRateSpin = S.Id(FESampleRateID).TieSpinCtrl(_("Sample Rate:"), wxT("/FileFormats/FFmpegSampleRate"), 0, 200000, 0);
1523  mSampleRateSpin->SetToolTip(_("Sample rate (Hz)\n0 - don't change sample rate"));
1524 
1525  mCutoffSpin = S.Id(FECutoffID).TieSpinCtrl(_("Cutoff:"), wxT("/FileFormats/FFmpegCutOff"), 0, 10000000, 0);
1526  mCutoffSpin->SetToolTip(_("Audio cutoff bandwidth (Hz)\nOptional\n0 - automatic"));
1527 
1528  mProfileChoice = S.Id(FEProfileID).TieChoice(_("Profile:"), wxT("/FileFormats/FFmpegAACProfile"),
1529  mProfileLabels[0], mProfileNames, mProfileLabels);
1530  mProfileChoice->SetSizeHints( 100,-1);
1531  mProfileChoice->SetToolTip(_("AAC Profile\nLow Complexity - default\nMost players won't play anything other than LC"));
1532 
1533  }
1534  S.EndMultiColumn();
1535  }
1536  S.EndStatic();
1537  S.StartStatic(_("FLAC options"),0);
1538  {
1539  S.StartMultiColumn(4, wxALIGN_LEFT);
1540  {
1541  mCompressionLevelSpin = S.Id(FECompLevelID).TieSpinCtrl(_("Compression:"), wxT("/FileFormats/FFmpegCompLevel"), 0, 10, -1);
1542  mCompressionLevelSpin->SetToolTip(_("Compression level\nRequired for FLAC\n-1 - automatic\nmin - 0 (fast encoding, large output file)\nmax - 10 (slow encoding, small output file)"));
1543 
1544  mFrameSizeSpin = S.Id(FEFrameSizeID).TieSpinCtrl(_("Frame:"), wxT("/FileFormats/FFmpegFrameSize"), 0, 65535, 0);
1545  mFrameSizeSpin->SetToolTip(_("Frame size\nOptional\n0 - default\nmin - 16\nmax - 65535"));
1546 
1547  mLPCCoeffsPrecisionSpin = S.Id(FELPCCoeffsID).TieSpinCtrl(_("LPC"), wxT("/FileFormats/FFmpegLPCCoefPrec"), 0, 15, 0);
1548  mLPCCoeffsPrecisionSpin->SetToolTip(_("LPC coefficients precision\nOptional\n0 - default\nmin - 1\nmax - 15"));
1549 
1550  mPredictionOrderMethodChoice = S.Id(FEPredOrderID).TieChoice(_("PdO Method:"), wxT("/FileFormats/FFmpegPredOrderMethod"),
1551  mPredictionOrderMethodLabels[4], mPredictionOrderMethodNames, mPredictionOrderMethodLabels);
1552  mPredictionOrderMethodChoice->SetSizeHints( 100,-1);
1553  mPredictionOrderMethodChoice->SetToolTip(_("Prediction Order Method\nEstimate - fastest, lower compression\nLog search - slowest, best compression\nFull search - default"));
1554 
1555  mMinPredictionOrderSpin = S.Id(FEMinPredID).TieSpinCtrl(_("Min. PdO"), wxT("/FileFormats/FFmpegMinPredOrder"), -1, 32, -1);
1556  mMinPredictionOrderSpin->SetToolTip(_("Minimal prediction order\nOptional\n-1 - default\nmin - 0\nmax - 32 (with LPC) or 4 (without LPC)"));
1557 
1558  mMaxPredictionOrderSpin = S.Id(FEMaxPredID).TieSpinCtrl(_("Max. PdO"), wxT("/FileFormats/FFmpegMaxPredOrder"), -1, 32, -1);
1559  mMaxPredictionOrderSpin->SetToolTip(_("Maximal prediction order\nOptional\n-1 - default\nmin - 0\nmax - 32 (with LPC) or 4 (without LPC)"));
1560 
1561  mMinPartitionOrderSpin = S.Id(FEMinPartOrderID).TieSpinCtrl(_("Min. PtO"), wxT("/FileFormats/FFmpegMinPartOrder"), -1, 8, -1);
1562  mMinPartitionOrderSpin->SetToolTip(_("Minimal partition order\nOptional\n-1 - default\nmin - 0\nmax - 8"));
1563 
1564  mMaxPartitionOrderSpin = S.Id(FEMaxPartOrderID).TieSpinCtrl(_("Max. PtO"), wxT("/FileFormats/FFmpegMaxPredOrder"), -1, 8, -1);
1565  mMaxPartitionOrderSpin->SetToolTip(_("Maximal partition order\nOptional\n-1 - default\nmin - 0\nmax - 8"));
1566 
1567  S.AddVariableText(_("Use LPC"));
1568  S.Id(FEUseLPCID).TieCheckBox( {}, wxT("/FileFormats/FFmpegUseLPC"), true);
1569  }
1570  S.EndMultiColumn();
1571  }
1572  S.EndStatic();
1573  S.StartStatic(_("MPEG container options"),0);
1574  {
1575  S.StartMultiColumn(4, wxALIGN_LEFT);
1576  {
1577  /* i18n-hint: 'mux' is short for multiplexor, a device that selects between several inputs
1578  'Mux Rate' is a parameter that has some bearing on compression ratio for MPEG
1579  it has a hard to predict effect on the degree of compression */
1580  mMuxRate = S.Id(FEMuxRateID).TieSpinCtrl(_("Mux Rate:"), wxT("/FileFormats/FFmpegMuxRate"), 0, 10000000, 0);
1581  mMuxRate->SetToolTip(_("Maximum bit rate of the multiplexed stream\nOptional\n0 - default"));
1582 
1583  /* i18n-hint: 'Packet Size' is a parameter that has some bearing on compression ratio for MPEG
1584  compression. It measures how big a chunk of audio is compressed in one piece. */
1585  mPacketSize = S.Id(FEPacketSizeID).TieSpinCtrl(_("Packet Size:"), wxT("/FileFormats/FFmpegPacketSize"), 0, 10000000, 0);
1586  mPacketSize->SetToolTip(_("Packet size\nOptional\n0 - default"));
1587  }
1588  S.EndMultiColumn();
1589  }
1590  S.EndStatic();
1591  //S.EndScroller();
1592  S.SetBorder( 5 );
1593  S.AddStandardButtons();
1594  }
1595  S.EndVerticalLay();
1596  }
1597  S.EndMultiColumn();
1598  }
1599  S.EndMultiColumn();
1600  S.EndVerticalLay();
1601 
1602  Layout();
1603  Fit();
1604  SetMinSize(GetSize());
1605  Center();
1606 
1607  return;
1608 }
1609 
1612 void ExportFFmpegOptions::FindSelectedFormat(wxString **name, wxString **longname)
1613 {
1614  // Get current selection
1615  wxArrayInt selections;
1616  int n = mFormatList->GetSelections(selections);
1617  if (n <= 0) return;
1618 
1619  // Get selected format short name
1620  wxString selfmt = mFormatList->GetString(selections[0]);
1621 
1622  // Find it's index
1623  int nFormat = mFormatNames.Index(selfmt);
1624  if (nFormat == wxNOT_FOUND) return;
1625 
1626  // Return short name and description
1627  if (name != NULL) *name = &mFormatNames[nFormat];
1628  if (longname != NULL) *longname = &mFormatLongNames[nFormat];
1629  return;
1630 }
1633 void ExportFFmpegOptions::FindSelectedCodec(wxString **name, wxString **longname)
1634 {
1635  // Get current selection
1636  wxArrayInt selections;
1637  int n = mCodecList->GetSelections(selections);
1638  if (n <= 0) return;
1639 
1640  // Get selected codec short name
1641  wxString selcdc = mCodecList->GetString(selections[0]);
1642 
1643  // Find it's index
1644  int nCodec = mCodecNames.Index(selcdc);
1645  if (nCodec == wxNOT_FOUND) return;
1646 
1647  // Return short name and description
1648  if (name != NULL) *name = &mCodecNames[nCodec];
1649  if (longname != NULL) *longname = &mCodecLongNames[nCodec];
1650 }
1651 
1654 int ExportFFmpegOptions::FetchCompatibleCodecList(const wxChar *fmt, AVCodecID id)
1655 {
1656  // By default assume that id is not in the list
1657  int index = -1;
1658  // By default no codecs are compatible (yet)
1659  mShownCodecNames.Clear();
1660  mShownCodecLongNames.Clear();
1661  // Clear the listbox
1662  mCodecList->Clear();
1663  // Zero - format is not found at all
1664  int found = 0;
1665  wxString str(fmt);
1666  for (int i = 0; CompatibilityList[i].fmt != NULL; i++)
1667  {
1668  if (str.Cmp(CompatibilityList[i].fmt) == 0)
1669  {
1670  // Format is found in the list
1671  found = 1;
1672  if (CompatibilityList[i].codec == AV_CODEC_ID_NONE)
1673  {
1674  // Format is found in the list and it is compatible with AV_CODEC_ID_NONE (means that it is compatible to anything)
1675  found = 2;
1676  break;
1677  }
1678  // Find the codec, that is claimed to be compatible
1679  AVCodec *codec = avcodec_find_encoder(CompatibilityList[i].codec);
1680  // If it exists, is audio and has encoder
1681  if (codec != NULL && (codec->type == AVMEDIA_TYPE_AUDIO) && av_codec_is_encoder(codec))
1682  {
1683  // If it was selected - remember it's NEW index
1684  if ((id >= 0) && codec->id == id) index = mShownCodecNames.GetCount();
1685  mShownCodecNames.Add(wxString::FromUTF8(codec->name));
1686  mShownCodecLongNames.Add(wxString::Format(wxT("%s - %s"),mShownCodecNames.Last(),wxString::FromUTF8(codec->long_name)));
1687  }
1688  }
1689  }
1690  // All codecs are compatible with this format
1691  if (found == 2)
1692  {
1693  AVCodec *codec = NULL;
1694  while ((codec = av_codec_next(codec))!=NULL)
1695  {
1696  if (codec->type == AVMEDIA_TYPE_AUDIO && av_codec_is_encoder(codec))
1697  {
1698  if (mShownCodecNames.Index(wxString::FromUTF8(codec->name)) < 0)
1699  {
1700  if ((id >= 0) && codec->id == id) index = mShownCodecNames.GetCount();
1701  mShownCodecNames.Add(wxString::FromUTF8(codec->name));
1702  mShownCodecLongNames.Add(wxString::Format(wxT("%s - %s"),mShownCodecNames.Last(),wxString::FromUTF8(codec->long_name)));
1703  }
1704  }
1705  }
1706  }
1707  // Format is not found - find format in libavformat and add it's default audio codec
1708  // This allows us to provide limited support for NEW formats without modifying the compatibility list
1709  else if (found == 0)
1710  {
1711  wxCharBuffer buf = str.ToUTF8();
1712  AVOutputFormat *format = av_guess_format(buf,NULL,NULL);
1713  if (format != NULL)
1714  {
1715  AVCodec *codec = avcodec_find_encoder(format->audio_codec);
1716  if (codec != NULL && (codec->type == AVMEDIA_TYPE_AUDIO) && av_codec_is_encoder(codec))
1717  {
1718  if ((id >= 0) && codec->id == id) index = mShownCodecNames.GetCount();
1719  mShownCodecNames.Add(wxString::FromUTF8(codec->name));
1720  mShownCodecLongNames.Add(wxString::Format(wxT("%s - %s"),mShownCodecNames.Last(),wxString::FromUTF8(codec->long_name)));
1721  }
1722  }
1723  }
1724  // Show NEW codec list
1725  mCodecList->Append(mShownCodecNames);
1726 
1727  return index;
1728 }
1729 
1732 int ExportFFmpegOptions::FetchCompatibleFormatList(AVCodecID id, wxString *selfmt)
1733 {
1734  int index = -1;
1735  mShownFormatNames.Clear();
1736  mShownFormatLongNames.Clear();
1737  mFormatList->Clear();
1738  AVOutputFormat *ofmt = NULL;
1739  ofmt = NULL;
1740  wxArrayString FromList;
1741  // Find all formats compatible to this codec in compatibility list
1742  for (int i = 0; CompatibilityList[i].fmt != NULL; i++)
1743  {
1744  if (CompatibilityList[i].codec == id || CompatibilityList[i].codec == AV_CODEC_ID_NONE)
1745  {
1746  if ((selfmt != NULL) && (selfmt->Cmp(CompatibilityList[i].fmt) == 0)) index = mShownFormatNames.GetCount();
1747  FromList.Add(CompatibilityList[i].fmt);
1748  mShownFormatNames.Add(CompatibilityList[i].fmt);
1749  AVOutputFormat *tofmt = av_guess_format(wxString(CompatibilityList[i].fmt).ToUTF8(),NULL,NULL);
1750  if (tofmt != NULL) mShownFormatLongNames.Add(wxString::Format(wxT("%s - %s"),CompatibilityList[i].fmt,wxString::FromUTF8(tofmt->long_name)));
1751  }
1752  }
1753  bool found = false;
1754  if (selfmt != NULL)
1755  {
1756  for (int i = 0; CompatibilityList[i].fmt != NULL; i++)
1757  {
1758  if (!selfmt->Cmp(CompatibilityList[i].fmt))
1759  {
1760  found = true;
1761  break;
1762  }
1763  }
1764  }
1765  // Format was in the compatibility list
1766  if (found)
1767  {
1768  // Find all formats which have this codec as default and which are not in the list yet and add them too
1769  while ((ofmt = av_oformat_next(ofmt))!=NULL)
1770  {
1771  if (ofmt->audio_codec == id)
1772  {
1773  wxString ofmtname = wxString::FromUTF8(ofmt->name);
1774  bool found = false;
1775  for (unsigned int i = 0; i < FromList.GetCount(); i++)
1776  {
1777  if (ofmtname.Cmp(FromList[i]) == 0)
1778  {
1779  found = true;
1780  break;
1781  }
1782  }
1783  if (!found)
1784  {
1785  if ((selfmt != NULL) && (selfmt->Cmp(wxString::FromUTF8(ofmt->name)) == 0)) index = mShownFormatNames.GetCount();
1786  mShownFormatNames.Add(wxString::FromUTF8(ofmt->name));
1787  mShownFormatLongNames.Add(wxString::Format(wxT("%s - %s"),mShownFormatNames.Last(),wxString::FromUTF8(ofmt->long_name)));
1788  }
1789  }
1790  }
1791  }
1792  mFormatList->Append(mShownFormatNames);
1793  return index;
1794 }
1795 
1798 void ExportFFmpegOptions::OnDeletePreset(wxCommandEvent& WXUNUSED(event))
1799 {
1800  wxComboBox *preset = dynamic_cast<wxComboBox*>(FindWindowById(FEPresetID,this));
1801  wxString presetname = preset->GetValue();
1802  if (presetname.IsEmpty())
1803  {
1804  AudacityMessageBox(_("You can't delete a preset without name"));
1805  return;
1806  }
1807 
1808  wxString query = wxString::Format(_("Delete preset '%s'?"),presetname);
1809  int action = AudacityMessageBox(query,_("Confirm Deletion"),wxYES_NO | wxCENTRE);
1810  if (action == wxNO) return;
1811 
1812  mPresets->DeletePreset(presetname);
1813  long index = preset->FindString(presetname);
1814  preset->SetValue(wxEmptyString);
1815  preset->Delete(index);
1816  mPresetNames.Remove(presetname);
1817 }
1818 
1821 void ExportFFmpegOptions::OnSavePreset(wxCommandEvent& WXUNUSED(event))
1822 {
1823  wxComboBox *preset = dynamic_cast<wxComboBox*>(FindWindowById(FEPresetID,this));
1824  wxString name = preset->GetValue();
1825  if (name.IsEmpty())
1826  {
1827  AudacityMessageBox(_("You can't save a preset without name"));
1828  return;
1829  }
1830  mPresets->SavePreset(this,name);
1831  int index = mPresetNames.Index(name,false);
1832  if (index == -1)
1833  {
1834  mPresetNames.Add(name);
1835  mPresetCombo->Clear();
1836  mPresetCombo->Append(mPresetNames);
1837  mPresetCombo->Select(mPresetNames.Index(name,false));
1838  }
1839 }
1840 
1843 void ExportFFmpegOptions::OnLoadPreset(wxCommandEvent& WXUNUSED(event))
1844 {
1845  wxComboBox *preset = dynamic_cast<wxComboBox*>(FindWindowById(FEPresetID,this));
1846  wxString presetname = preset->GetValue();
1847 
1848  mShownFormatNames = mFormatNames;
1849  mShownFormatLongNames = mFormatLongNames;
1850  mFormatList->Clear();
1851  mFormatList->Append(mFormatNames);
1852 
1853  mShownCodecNames = mCodecNames;
1854  mShownCodecLongNames = mCodecLongNames;
1855  mCodecList->Clear();
1856  mCodecList->Append(mCodecNames);
1857 
1858  mPresets->LoadPreset(this,presetname);
1859 
1860  DoOnFormatList();
1861  DoOnCodecList();
1862 }
1863 
1866 void ExportFFmpegOptions::OnImportPresets(wxCommandEvent& WXUNUSED(event))
1867 {
1868  wxString path;
1869  FileDialogWrapper dlg(this,
1870  _("Select xml file with presets to import"),
1871  gPrefs->Read(wxT("/FileFormats/FFmpegPresetDir")),
1872  wxEmptyString,
1873  wxString(_("XML files (*.xml)|*.xml|All files|*")),
1874  wxFD_OPEN);
1875  if (dlg.ShowModal() == wxID_CANCEL) return;
1876  path = dlg.GetPath();
1877  mPresets->ImportPresets(path);
1878  mPresets->GetPresetList(mPresetNames);
1879  mPresetCombo->Clear();
1880  mPresetCombo->Append(mPresetNames);
1881 }
1882 
1885 void ExportFFmpegOptions::OnExportPresets(wxCommandEvent& WXUNUSED(event))
1886 {
1887  wxString path;
1888  FileDialogWrapper dlg(this,
1889  _("Select xml file to export presets into"),
1890  gPrefs->Read(wxT("/FileFormats/FFmpegPresetDir")),
1891  wxEmptyString,
1892  wxString(_("XML files (*.xml)|*.xml|All files|*")),
1893  wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
1894  if (dlg.ShowModal() == wxID_CANCEL) return;
1895  path = dlg.GetPath();
1896  mPresets->ExportPresets(path);
1897 }
1898 
1901 void ExportFFmpegOptions::OnAllFormats(wxCommandEvent& WXUNUSED(event))
1902 {
1903  mShownFormatNames = mFormatNames;
1904  mShownFormatLongNames = mFormatLongNames;
1905  mFormatList->Clear();
1906  mFormatList->Append(mFormatNames);
1907 }
1908 
1911 void ExportFFmpegOptions::OnAllCodecs(wxCommandEvent& WXUNUSED(event))
1912 {
1913  mShownCodecNames = mCodecNames;
1914  mShownCodecLongNames = mCodecLongNames;
1915  mCodecList->Clear();
1916  mCodecList->Append(mCodecNames);
1917 }
1918 
1919 void ExportFFmpegOptions::EnableDisableControls(AVCodec *cdc, wxString *selfmt)
1920 {
1921  int handled = -1;
1922  for (int i = 0; apptable[i].control != 0; i++)
1923  {
1924  if (apptable[i].control != handled)
1925  {
1926  bool codec = false;
1927  bool format = false;
1928  if (apptable[i].codec == AV_CODEC_ID_NONE) codec = true;
1929  else if (cdc != NULL && apptable[i].codec == cdc->id) codec = true;
1930  if (!wxString::FromUTF8(apptable[i].format).Cmp(wxT("any"))) format = true;
1931  else if (selfmt != NULL && selfmt->Cmp(wxString::FromUTF8(apptable[i].format)) == 0) format = true;
1932  if (codec && format)
1933  {
1934  handled = apptable[i].control;
1935  wxWindow *item = FindWindowById(apptable[i].control,this);
1936  if (item != NULL) item->Enable(apptable[i].enable);
1937  }
1938  }
1939  }
1940 }
1941 
1942 void ExportFFmpegOptions::DoOnFormatList()
1943 {
1944  wxString *selfmt = NULL;
1945  wxString *selfmtlong = NULL;
1946  FindSelectedFormat(&selfmt, &selfmtlong);
1947  if (selfmt == NULL)
1948  {
1949  return;
1950  }
1951 
1952  wxString *selcdc = NULL;
1953  wxString *selcdclong = NULL;
1954  FindSelectedCodec(&selcdc, &selcdclong);
1955 
1956  AVOutputFormat *fmt = av_guess_format(selfmt->ToUTF8(),NULL,NULL);
1957  if (fmt == NULL)
1958  {
1959  //This shouldn't really happen
1960  mFormatName->SetLabel(wxString(_("Failed to guess format")));
1961  return;
1962  }
1963  mFormatName->SetLabel(wxString::Format(wxT("%s"), *selfmtlong));
1964  int selcdcid = -1;
1965 
1966  if (selcdc != NULL)
1967  {
1968  AVCodec *cdc = avcodec_find_encoder_by_name(selcdc->ToUTF8());
1969  if (cdc != NULL)
1970  {
1971  selcdcid = cdc->id;
1972  }
1973  }
1974  int newselcdc = FetchCompatibleCodecList(*selfmt, (AVCodecID)selcdcid);
1975  if (newselcdc >= 0) mCodecList->Select(newselcdc);
1976 
1977  AVCodec *cdc = NULL;
1978  if (selcdc != NULL)
1979  cdc = avcodec_find_encoder_by_name(selcdc->ToUTF8());
1980  EnableDisableControls(cdc, selfmt);
1981  Layout();
1982  Fit();
1983  return;
1984 }
1985 
1986 void ExportFFmpegOptions::DoOnCodecList()
1987 {
1988  wxString *selcdc = NULL;
1989  wxString *selcdclong = NULL;
1990  FindSelectedCodec(&selcdc, &selcdclong);
1991  if (selcdc == NULL)
1992  {
1993  return;
1994  }
1995 
1996  wxString *selfmt = NULL;
1997  wxString *selfmtlong = NULL;
1998  FindSelectedFormat(&selfmt, &selfmtlong);
1999 
2000  AVCodec *cdc = avcodec_find_encoder_by_name(selcdc->ToUTF8());
2001  if (cdc == NULL)
2002  {
2003  //This shouldn't really happen
2004  mCodecName->SetLabel(wxString(_("Failed to find the codec")));
2005  return;
2006  }
2007  mCodecName->SetLabel(wxString::Format(wxT("[%d] %s"), (int) cdc->id, *selcdclong));
2008 
2009  if (selfmt != NULL)
2010  {
2011  AVOutputFormat *fmt = av_guess_format(selfmt->ToUTF8(),NULL,NULL);
2012  if (fmt == NULL)
2013  {
2014  selfmt = NULL;
2015  selfmtlong = NULL;
2016  }
2017  }
2018 
2019  int newselfmt = FetchCompatibleFormatList(cdc->id,selfmt);
2020  if (newselfmt >= 0) mFormatList->Select(newselfmt);
2021 
2022  EnableDisableControls(cdc, selfmt);
2023  Layout();
2024  Fit();
2025  return;
2026 }
2027 
2030 void ExportFFmpegOptions::OnFormatList(wxCommandEvent& WXUNUSED(event))
2031 {
2032  DoOnFormatList();
2033 }
2034 
2037 void ExportFFmpegOptions::OnCodecList(wxCommandEvent& WXUNUSED(event))
2038 {
2039  DoOnCodecList();
2040 }
2041 
2044 void ExportFFmpegOptions::OnOK(wxCommandEvent& WXUNUSED(event))
2045 {
2046  int selcdc = mCodecList->GetSelection();
2047  int selfmt = mFormatList->GetSelection();
2048  if (selcdc > -1) gPrefs->Write(wxT("/FileFormats/FFmpegCodec"),mCodecList->GetString(selcdc));
2049  if (selfmt > -1) gPrefs->Write(wxT("/FileFormats/FFmpegFormat"),mFormatList->GetString(selfmt));
2050  gPrefs->Flush();
2051 
2052  ShuttleGui S(this, eIsSavingToPrefs);
2053  PopulateOrExchange(S);
2054 
2055  gPrefs->Flush();
2056 
2057  EndModal(wxID_OK);
2058 
2059  return;
2060 }
2061 
2062 #endif
wxChoice * TieChoice(const wxString &Prompt, WrappedType &WrappedRef, const wxArrayString *pChoices)
static wxArrayString names()
Definition: Tags.cpp:697
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
wxSlider * TieSlider(const wxString &Prompt, WrappedType &WrappedRef, const int max, const int min=0)
void EndMultiColumn()
#define XO(s)
Definition: Internat.h:30
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
wxSpinCtrl * TieSpinCtrl(const wxString &Prompt, WrappedType &WrappedRef, const int max, const int min=0)
void SetSizerProportion(int iProp)
Definition: ShuttleGui.h:254
void OnOpen(const CommandContext &context)
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
bool Parse(XMLTagHandler *baseHandler, const wxString &fname)
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:18
int format
Definition: ExportPCM.cpp:56
Wrapper to output XML data to files.
Definition: XMLWriter.h:74
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:998
ShuttleGui & Id(int id)
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:70
void AddFixedText(const wxString &Str, bool bCenter=false)
Definition: ShuttleGui.cpp:356
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
wxComboBox * AddCombo(const wxString &Prompt, const wxString &Selected, const wxArrayString *pChoices, long style=0)
Definition: ShuttleGui.cpp:399
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
const wxChar * name
Definition: Distortion.cpp:94
wxListBox * AddListBox(const wxArrayString *pChoices, long style=0)
Definition: ShuttleGui.cpp:584
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:373
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:701
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:374
Class used to dynamically load FFmpeg libraries.
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:22
virtual void Populate()=0
void SetBorder(int Border)
Definition: ShuttleGui.h:251
wxButton * AddButton(const wxString &Text, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:301
Options dialog for Custom FFmpeg export format.
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:192
wxTextCtrl * TieTextBox(const wxString &Prompt, WrappedType &WrappedRef, const int nChars)
void SetStretchyRow(int i)
Used to modify an already placed FlexGridSizer to make a row stretchy.
Definition: ShuttleGui.cpp:202
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982