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