Audacity  3.0.3
FFmpeg.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 FFmpeg.cpp
6 
7 Audacity(R) is copyright (c) 1999-2009 Audacity Team.
8 License: GPL v2. See License.txt.
9 
10 ******************************************************************//*******************************************************************/
16 
17 // Store function pointers here when including FFmpeg.h
18 #define DEFINE_FFMPEG_POINTERS
19 
20 
21 #include "FFmpeg.h"
22 
23 #include "FileNames.h"
24 #include "widgets/HelpSystem.h"
26 
27 #include <wx/checkbox.h>
28 #include <wx/dynlib.h>
29 #include <wx/file.h>
30 #include <wx/log.h>
31 #include <wx/textctrl.h>
32 
33 #if !defined(USE_FFMPEG)
37 {
38  return XO("FFmpeg support not compiled in");
39 }
40 
41 #else
42 
45 std::unique_ptr<FFmpegLibs> FFmpegLibsPtr{};
47 {
48  return FFmpegLibsPtr.get();
49 }
50 
52 {
53  if (FFmpegLibsPtr)
54  FFmpegLibsPtr->refcount++;
55  else
56  FFmpegLibsPtr = std::make_unique<FFmpegLibs>();
57 
58  return FFmpegLibsPtr.get();
59 }
60 
62 {
63  if (FFmpegLibsPtr)
64  {
65  FFmpegLibsPtr->refcount--;
66  if (FFmpegLibsPtr->refcount == 0)
67  FFmpegLibsPtr.reset();
68  }
69 }
70 
71 bool LoadFFmpeg(bool showerror)
72 {
74  if (FFmpegLibsInst()->ValidLibsLoaded())
75  {
77  return true;
78  }
79  if (!FFmpegLibsInst()->LoadLibs(NULL, showerror))
80  {
82  gPrefs->Write(wxT("/FFmpeg/Enabled"), false);
83  gPrefs->Flush();
84  return false;
85  }
86  else
87  {
88  gPrefs->Write(wxT("/FFmpeg/Enabled"), true);
89  gPrefs->Flush();
90  return true;
91  }
92 }
93 
96 {
97  bool enabled = false;
98  gPrefs->Read(wxT("/FFmpeg/Enabled"),&enabled);
99  // 'false' means that no errors should be shown whatsoever
100  if (!LoadFFmpeg(false))
101  {
102  if (enabled)
103  {
105 "FFmpeg was configured in Preferences and successfully loaded before, \
106 \nbut this time Audacity failed to load it at startup. \
107 \n\nYou may want to go back to Preferences > Libraries and re-configure it."),
108  XO("FFmpeg startup failed"));
109  }
110  }
111 }
112 
114 {
115  PickFFmpegLibs();
116 
117  auto versionString = XO("FFmpeg library not found");
118 
119  if (FFmpegLibsInst()->ValidLibsLoaded()) {
120  versionString = Verbatim( FFmpegLibsInst()->GetLibraryVersion() );
121  }
122 
123  DropFFmpegLibs();
124 
125  return versionString;
126 }
127 
128 void av_log_wx_callback(void* ptr, int level, const char* fmt, va_list vl)
129 {
130  //Most of this stuff is taken from FFmpeg tutorials and FFmpeg itself
131  int av_log_level = AV_LOG_INFO;
132  AVClass* avc = ptr ? *(AVClass**)ptr : NULL;
133  if (level > av_log_level)
134  return;
135  wxString printstring(wxT(""));
136 
137  if (avc) {
138  printstring.Append(wxString::Format(wxT("[%s @ %p] "), wxString::FromUTF8(avc->item_name(ptr)), avc));
139  }
140 
141  wxString frm(fmt,wxConvLibc);
142 
143  printstring.Append(wxString::FormatV(frm,vl));
144  wxString cpt;
145  switch (level)
146  {
147  case 0: cpt = wxT("Error"); break;
148  case 1: cpt = wxT("Info"); break;
149  case 2: cpt = wxT("Debug"); break;
150  default: cpt = wxT("Log"); break;
151  }
152  wxLogDebug(wxT("%s: %s"),cpt,printstring);
153 }
154 
155 //======================= Unicode aware uri protocol for FFmpeg
156 // Code inspired from ffmpeg-users mailing list sample
157 
158 static int ufile_read(void *opaque, uint8_t *buf, int size)
159 {
160  int ret = (int)((wxFile *) opaque)->Read(buf, size);
161  return ret;
162 }
163 
164 static int ufile_write(void *opaque, uint8_t *buf, int size)
165 {
166  auto bytes = (int) ((wxFile *) opaque)->Write(buf, size);
167  if (bytes != size)
168  return -ENOSPC;
169  return bytes;
170 }
171 
172 static int64_t ufile_seek(void *opaque, int64_t pos, int whence)
173 {
174  wxSeekMode mode = wxFromStart;
175 
176 #if !defined(AVSEEK_FORCE)
177 #define AVSEEK_FORCE 0
178 #endif
179 
180  switch (whence & ~AVSEEK_FORCE)
181  {
182  case (SEEK_SET):
183  mode = wxFromStart;
184  break;
185  case (SEEK_CUR):
186  mode = wxFromCurrent;
187  break;
188  case (SEEK_END):
189  mode = wxFromEnd;
190  break;
191  case (AVSEEK_SIZE):
192  return ((wxFile *) opaque)->Length();
193  }
194 
195  return ((wxFile *) opaque)->Seek(pos, mode);
196 }
197 
198 int ufile_close(AVIOContext *pb)
199 {
200  std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque };
201 
202  bool success = true;
203  if (f) {
204  if (pb->write_flag) {
205  success = f->Flush();
206  }
207  if (success) {
208  success = f->Close();
209  }
210  pb->opaque = nullptr;
211  }
212 
213  // We're not certain that a close error is for want of space, but we'll
214  // guess that
215  return success ? 0 : -ENOSPC;
216 
217  // Implicitly destroy the wxFile object here
218 }
219 
220 // Open a file with a (possibly) Unicode filename
221 int ufile_fopen(AVIOContext **s, const FilePath & name, int flags)
222 {
223  wxFile::OpenMode mode;
224 
225  auto f = std::make_unique<wxFile>();
226  if (!f) {
227  return -ENOMEM;
228  }
229 
230  if (flags == (AVIO_FLAG_READ | AVIO_FLAG_WRITE)) {
231  return -EINVAL;
232  } else if (flags == AVIO_FLAG_WRITE) {
233  mode = wxFile::write;
234  } else {
235  mode = wxFile::read;
236  }
237 
238  if (!f->Open(name, mode)) {
239  return -ENOENT;
240  }
241 
242  *s = avio_alloc_context((unsigned char*)av_malloc(32768), 32768,
243  flags & AVIO_FLAG_WRITE,
244  /*opaque*/f.get(),
245  ufile_read,
246  ufile_write,
247  ufile_seek);
248  if (!*s) {
249  return -ENOMEM;
250  }
251 
252  f.release(); // s owns the file object now
253 
254  return 0;
255 }
256 
257 
258 // Detect type of input file and open it if recognized. Routine
259 // based on the av_open_input_file() libavformat function.
260 int ufile_fopen_input(std::unique_ptr<FFmpegContext> &context_ptr, FilePath & name)
261 {
262  context_ptr.reset();
263  auto context = std::make_unique<FFmpegContext>();
264 
265  wxFileName ff{ name };
266  wxCharBuffer fname;
267  const char *filename;
268  int err;
269 
270  fname = ff.GetFullName().mb_str();
271  filename = (const char *) fname;
272 
273  // Open the file to prepare for probing
274  if ((err = ufile_fopen(&context->pb, name, AVIO_FLAG_READ)) < 0) {
275  goto fail;
276  }
277 
278  context->ic_ptr = avformat_alloc_context();
279  context->ic_ptr->pb = context->pb;
280 
281  // And finally, attempt to associate an input stream with the file
282  err = avformat_open_input(&context->ic_ptr, filename, NULL, NULL);
283  if (err) {
284  goto fail;
285  }
286 
287  // success
288  context_ptr = std::move(context);
289  return 0;
290 
291 fail:
292 
293  return err;
294 }
295 
297 {
298  if (FFmpegLibsInst()->ValidLibsLoaded())
299  {
300  if (ic_ptr)
301  avformat_close_input(&ic_ptr);
302  av_log_set_callback(av_log_default_callback);
303  }
304 
305  if (pb) {
306  ufile_close(pb);
307  if (FFmpegLibsInst()->ValidLibsLoaded())
308  {
309  av_free(pb->buffer);
310  av_free(pb);
311  }
312  }
313 }
314 
315 streamContext *import_ffmpeg_read_next_frame(AVFormatContext* formatContext,
316  streamContext** streams,
317  unsigned int numStreams)
318 {
319  streamContext *sc = NULL;
320  AVPacketEx pkt;
321 
322  if (av_read_frame(formatContext, &pkt) < 0)
323  {
324  return NULL;
325  }
326 
327  // Find a stream to which this frame belongs
328  for (unsigned int i = 0; i < numStreams; i++)
329  {
330  if (streams[i]->m_stream->index == pkt.stream_index)
331  sc = streams[i];
332  }
333 
334  // Off-stream packet. Don't panic, just skip it.
335  // When not all streams are selected for import this will happen very often.
336  if (sc == NULL)
337  {
338  return (streamContext*)1;
339  }
340 
341  // Copy the frame to the stream context
342  sc->m_pkt.emplace(std::move(pkt));
343 
344  sc->m_pktDataPtr = sc->m_pkt->data;
345  sc->m_pktRemainingSiz = sc->m_pkt->size;
346 
347  return sc;
348 }
349 
351 {
352  int nBytesDecoded;
353  wxUint8 *pDecode = sc->m_pktDataPtr;
354  int nDecodeSiz = sc->m_pktRemainingSiz;
355 
356  sc->m_frameValid = 0;
357 
358  if (flushing)
359  {
360  // If we're flushing the decoders we don't actually have any NEW data to decode.
361  pDecode = NULL;
362  nDecodeSiz = 0;
363  }
364  else
365  {
366  if (!sc->m_pkt || (sc->m_pktRemainingSiz <= 0))
367  {
368  //No more data
369  return -1;
370  }
371  }
372 
373  AVPacketEx avpkt;
374  avpkt.data = pDecode;
375  avpkt.size = nDecodeSiz;
376 
377  AVFrameHolder frame{ av_frame_alloc() };
378  int got_output = 0;
379 
380  nBytesDecoded =
381  avcodec_decode_audio4(sc->m_codecCtx,
382  frame.get(), // out
383  &got_output, // out
384  &avpkt); // in
385 
386  if (nBytesDecoded < 0)
387  {
388  // Decoding failed. Don't stop.
389  return -1;
390  }
391 
392  sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
393  sc->m_samplesize = static_cast<size_t>(av_get_bytes_per_sample(sc->m_samplefmt));
394 
395  int channels = sc->m_codecCtx->channels;
396  auto newsize = sc->m_samplesize * frame->nb_samples * channels;
397  sc->m_decodedAudioSamplesValidSiz = newsize;
398  // Reallocate the audio sample buffer if it's smaller than the frame size.
399  if (newsize > sc->m_decodedAudioSamplesSiz )
400  {
401  // Reallocate a bigger buffer. But av_realloc is NOT compatible with the returns of av_malloc!
402  // So do this:
403  sc->m_decodedAudioSamples.reset(static_cast<uint8_t *>(av_malloc(newsize)));
404  sc->m_decodedAudioSamplesSiz = newsize;
405  if (!sc->m_decodedAudioSamples)
406  {
407  //Can't allocate bytes
408  return -1;
409  }
410  }
411  if (frame->data[1]) {
412  for (int i = 0; i<frame->nb_samples; i++) {
413  for (int ch = 0; ch<channels; ch++) {
414  memcpy(sc->m_decodedAudioSamples.get() + sc->m_samplesize * (ch + channels*i),
415  frame->extended_data[ch] + sc->m_samplesize*i,
416  sc->m_samplesize);
417  }
418  }
419  } else {
420  memcpy(sc->m_decodedAudioSamples.get(), frame->data[0], newsize);
421  }
422 
423  // We may not have read all of the data from this packet. If so, the user can call again.
424  // Whether or not they do depends on if m_pktRemainingSiz == 0 (they can check).
425  sc->m_pktDataPtr += nBytesDecoded;
426  sc->m_pktRemainingSiz -= nBytesDecoded;
427 
428  // At this point it's normally safe to assume that we've read some samples. However, the MPEG
429  // audio decoder is broken. If this is the case then we just return with m_frameValid == 0
430  // but m_pktRemainingSiz perhaps != 0, so the user can call again.
431  if (sc->m_decodedAudioSamplesValidSiz > 0)
432  {
433  sc->m_frameValid = 1;
434  }
435  return 0;
436 }
437 
438 
439 
440 /*******************************************************/
441 
443 
444 //----------------------------------------------------------------------------
445 // FindFFmpegDialog
446 //----------------------------------------------------------------------------
447 
448 #define ID_FFMPEG_BROWSE 5000
449 #define ID_FFMPEG_DLOAD 5001
450 
452 class FindFFmpegDialog final : public wxDialogWrapper
453 {
454 public:
455 
456  FindFFmpegDialog(wxWindow *parent, const wxString &path, const wxString &name,
457  FileNames::FileTypes types)
458  : wxDialogWrapper(parent, wxID_ANY, XO("Locate FFmpeg"))
459  {
460  SetName();
461  ShuttleGui S(this, eIsCreating);
462 
463  mPath = path;
464  mName = name;
465  mTypes = std::move( types );
466 
467  mLibPath.Assign(mPath, mName);
468 
470  }
471 
473  {
474  S.SetBorder(10);
475  S.StartVerticalLay(true);
476  {
477  S.AddTitle(
478  XO(
479 "Audacity needs the file '%s' to import and export audio via FFmpeg.")
480  .Format( mName ) );
481 
482  S.SetBorder(3);
483  S.StartHorizontalLay(wxALIGN_LEFT, true);
484  {
485  S.AddTitle( XO("Location of '%s':").Format( mName ) );
486  }
487  S.EndHorizontalLay();
488 
489  S.StartMultiColumn(2, wxEXPAND);
490  S.SetStretchyCol(0);
491  {
492  if (mLibPath.GetFullPath().empty()) {
493  mPathText = S.AddTextBox( {},
494  wxString::Format(_("To find '%s', click here -->"), mName), 0);
495  }
496  else {
497  mPathText = S.AddTextBox( {}, mLibPath.GetFullPath(), 0);
498  }
499  S.Id(ID_FFMPEG_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
500  S.AddVariableText(
501  XO("To get a free copy of FFmpeg, click here -->"), true);
502  S.Id(ID_FFMPEG_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
503  }
504  S.EndMultiColumn();
505 
506  S.AddStandardButtons();
507  }
508  S.EndVerticalLay();
509 
510  Layout();
511  Fit();
512  SetMinSize(GetSize());
513  Center();
514 
515  return;
516  }
517 
518  void OnBrowse(wxCommandEvent & WXUNUSED(event))
519  {
520  /* i18n-hint: It's asking for the location of a file, for
521  example, "Where is lame_enc.dll?" - you could translate
522  "Where would I find the file '%s'?" instead if you want. */
523  auto question = XO("Where is '%s'?").Format( mName );
524 
525  wxString path = FileNames::SelectFile(FileNames::Operation::_None,
526  question,
527  mLibPath.GetPath(),
528  mLibPath.GetFullName(),
529  wxT(""),
530  mTypes,
531  wxFD_OPEN | wxRESIZE_BORDER,
532  this);
533  if (!path.empty()) {
534  mLibPath = path;
535  mPathText->SetValue(path);
536  }
537  }
538 
539  void OnDownload(wxCommandEvent & WXUNUSED(event))
540  {
541  HelpSystem::ShowHelp(this, L"FAQ:Installing_the_FFmpeg_Import_Export_Library");
542  }
543 
544  wxString GetLibPath()
545  {
546  return mLibPath.GetFullPath();
547  }
548 
549 private:
550 
551  wxFileName mLibPath;
552 
553  wxString mPath;
554  wxString mName;
556 
557  wxTextCtrl *mPathText;
558 
559  DECLARE_EVENT_TABLE()
560 };
561 
562 BEGIN_EVENT_TABLE(FindFFmpegDialog, wxDialogWrapper)
566 
567 
568 //----------------------------------------------------------------------------
569 // FFmpegNotFoundDialog
570 //----------------------------------------------------------------------------
571 
573  : wxDialogWrapper(parent, wxID_ANY, XO("FFmpeg not found"))
574 {
575  SetName();
576  ShuttleGui S(this, eIsCreating);
577  PopulateOrExchange(S);
578 }
579 
581 {
582  wxString text;
583 
584  S.SetBorder(10);
585  S.StartVerticalLay(true);
586  {
587  S.AddFixedText(XO(
588 "Audacity attempted to use FFmpeg to import an audio file,\n\
589 but the libraries were not found.\n\n\
590 To use FFmpeg import, go to Edit > Preferences > Libraries\n\
591 to download or locate the FFmpeg libraries."
592  ));
593 
594  mDontShow = S
595  .AddCheckBox(XXO("Do not show this warning again"),
596  gPrefs->ReadBool(wxT("/FFmpeg/NotFoundDontShow"), false) );
597 
599  }
600  S.EndVerticalLay();
601 
602  Layout();
603  Fit();
604  SetMinSize(GetSize());
605  Center();
606 
607  return;
608 }
609 
610 void FFmpegNotFoundDialog::OnOk(wxCommandEvent & WXUNUSED(event))
611 {
612  if (mDontShow->GetValue())
613  {
614  gPrefs->Write(wxT("/FFmpeg/NotFoundDontShow"),1);
615  gPrefs->Flush();
616  }
617  this->EndModal(0);
618 }
619 
620 BEGIN_EVENT_TABLE(FFmpegNotFoundDialog, wxDialogWrapper)
623 
624 
625 //----------------------------------------------------------------------------
626 // FFmpegLibs
627 //----------------------------------------------------------------------------
628 
630 {
631  mLibsLoaded = false;
632  refcount = 1;
633  if (gPrefs) {
634  mLibAVFormatPath = gPrefs->Read(wxT("/FFmpeg/FFmpegLibPath"), wxT(""));
635  }
636 
637 }
638 
640 {
641  FreeLibs();
642 };
643 
644 bool FFmpegLibs::FindLibs(wxWindow *parent)
645 {
646  wxString path;
647  wxString name;
648 
649  // If we're looking for the lib, use the standard name, as the
650  // configured name is not found.
652  wxLogMessage(wxT("Looking for FFmpeg libraries..."));
653  if (!mLibAVFormatPath.empty()) {
654  wxLogMessage(wxT("mLibAVFormatPath ('%s') is not empty."), mLibAVFormatPath);
655  const wxFileName fn{ mLibAVFormatPath };
656  path = fn.GetPath();
657  }
658  else {
659  path = GetLibAVFormatPath();
660  wxLogMessage(wxT("mLibAVFormatPath is empty, starting with path '%s', name '%s'."),
661  path, name);
662  }
663 
664  FindFFmpegDialog fd(parent,
665  path,
666  name,
667  GetLibraryTypes());
668 
669  if (fd.ShowModal() == wxID_CANCEL) {
670  wxLogMessage(wxT("User canceled the dialog. Failed to find FFmpeg libraries."));
671  return false;
672  }
673 
674  path = fd.GetLibPath();
675 
676  wxLogMessage(wxT("User-specified path = '%s'"), path);
677  if (!::wxFileExists(path)) {
678  wxLogError(wxT("User-specified file does not exist. Failed to find FFmpeg libraries."));
679  return false;
680  }
681  wxLogMessage(wxT("User-specified FFmpeg file exists. Success."));
682  mLibAVFormatPath = path;
683  gPrefs->Write(wxT("/FFmpeg/FFmpegLibPath"), mLibAVFormatPath);
684  gPrefs->Flush();
685 
686  return true;
687 }
688 
689 bool FFmpegLibs::LoadLibs(wxWindow * WXUNUSED(parent), bool showerr)
690 {
691 #if defined(DISABLE_DYNAMIC_LOADING_FFMPEG)
692  mLibsLoaded = InitLibs(wxEmptyString, showerr);
693  return mLibsLoaded;
694 #endif
695 
696  wxLogMessage(wxT("Trying to load FFmpeg libraries..."));
697  if (ValidLibsLoaded()) {
698  wxLogMessage(wxT("FFmpeg libraries are already loaded."));
699  FreeLibs();
700  }
701 
702  // First try loading it from a previously located path
703  if (!mLibAVFormatPath.empty()) {
704  wxLogMessage(wxT("mLibAVFormatPath ('%s') is not empty. Loading from it."),mLibAVFormatPath);
706  }
707 
708  // If not successful, try loading it from default path
709  if (!mLibsLoaded && !GetLibAVFormatPath().empty()) {
710  const wxFileName fn{ GetLibAVFormatPath(), GetLibAVFormatName() };
711  wxString path = fn.GetFullPath();
712  wxLogMessage(wxT("Trying to load FFmpeg libraries from default path, '%s'."), path);
713  mLibsLoaded = InitLibs(path,showerr);
714  if (mLibsLoaded) {
715  mLibAVFormatPath = path;
716  }
717  }
718 
719 #if defined(__WXMAC__)
720  // If not successful, try loading it from legacy path
721  if (!mLibsLoaded && !GetLibAVFormatPath().empty()) {
722  const wxFileName fn{wxT("/usr/local/lib/audacity"), GetLibAVFormatName()};
723  wxString path = fn.GetFullPath();
724  wxLogMessage(wxT("Trying to load FFmpeg libraries from legacy path, '%s'."), path);
725  mLibsLoaded = InitLibs(path,showerr);
726  if (mLibsLoaded) {
727  mLibAVFormatPath = path;
728  }
729  }
730 #endif
731 
732  // If not successful, try loading using system search paths
733  if (!ValidLibsLoaded()) {
734  wxString path = GetLibAVFormatName();
735  wxLogMessage(wxT("Trying to load FFmpeg libraries from system paths. File name is '%s'."), path);
736  mLibsLoaded = InitLibs(path,showerr);
737  if (mLibsLoaded) {
738  mLibAVFormatPath = path;
739  }
740  }
741 
742  // If libraries aren't loaded - nag user about that
743  /*
744  if (!ValidLibsLoaded())
745  {
746  wxLogError(wxT("Failed to load libraries altogether."));
747  int dontShowDlg;
748  gPrefs->Read(wxT("/FFmpeg/NotFoundDontShow"),&dontShowDlg,0);
749  if ((dontShowDlg == 0) && (showerr))
750  FFmpegNotFoundDialog{nullptr}.ShowModal();
751  }
752  */
753  // Oh well, just give up
754  if (!ValidLibsLoaded()) {
755  auto msg = XO("Failed to find compatible FFmpeg libraries.");
756  if (showerr)
757  AudacityMessageBox( msg );
758  wxLogError(msg.Debug());
759  return false;
760  }
761 
762  wxLogMessage(wxT("FFmpeg libraries loaded successfully."));
763  return true;
764 }
765 
767 {
768  return mLibsLoaded;
769 }
770 
771 bool FFmpegLibs::InitLibs(const wxString &libpath_format, bool WXUNUSED(showerr))
772 {
773 #if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG)
774  FreeLibs();
775 
776 #if defined(__WXMSW__)
777  wxString oldpath;
778  wxString syspath;
779  bool pathExisted = false;
780 
781  // Return PATH to normal
782  auto restorePath = finally([&]()
783  {
784  if (oldpath != syspath)
785  {
786  if (pathExisted)
787  {
788  wxLogMessage(wxT("Returning PATH to previous setting: %s"), oldpath);
789  wxSetEnv(wxT("PATH"), oldpath);
790  }
791  else
792  {
793  wxLogMessage(wxT("Removing PATH environment variable"));
794  wxUnsetEnv(wxT("PATH"));
795  }
796  }
797  });
798 
799  wxLogMessage(wxT("Looking up PATH environment variable..."));
800  // First take PATH environment variable and store its content.
801  pathExisted = wxGetEnv(wxT("PATH"),&syspath);
802  oldpath = syspath;
803 
804  wxLogMessage(wxT("PATH = '%s'"), syspath);
805 
806  const wxString &fmtdir{ wxPathOnly(libpath_format) };
807  wxString fmtdirsc = fmtdir + wxT(";");
808  wxString scfmtdir = wxT(";") + fmtdir;
809 
810  if (syspath.Left(1) == wxT(';'))
811  {
812  wxLogMessage(wxT("Temporarily prepending '%s' to PATH..."), fmtdir);
813  syspath.Prepend(scfmtdir);
814  }
815  else
816  {
817  wxLogMessage(wxT("Temporarily prepending '%s' to PATH..."), scfmtdir);
818  syspath.Prepend(fmtdirsc);
819  }
820 
821  if (!wxSetEnv(wxT("PATH"),syspath))
822  {
823  wxLogSysError(wxT("Setting PATH via wxSetEnv('%s') failed."), syspath);
824  }
825 #endif
826 
827  //Load libavformat
828  // Initially we don't know where are the avcodec and avutl libs
829  wxDynamicLibrary *codec = NULL;
830  wxDynamicLibrary *util = NULL;
831  wxFileName avcodec_filename;
832  wxFileName avutil_filename;
833  wxFileName name{ libpath_format };
834  wxString nameFull{name.GetFullPath()};
835  bool gotError = false;
836 
837  // Check for a monolithic avformat
838  avformat = std::make_unique<wxDynamicLibrary>();
839  wxLogMessage(wxT("Checking for monolithic avformat from '%s'."), nameFull);
840  gotError = !avformat->Load(nameFull, wxDL_LAZY);
841 
842  // Verify it really is monolithic
843  if (!gotError) {
844  avutil_filename = FileNames::PathFromAddr(avformat->GetSymbol(wxT("avutil_version")));
845  avcodec_filename = FileNames::PathFromAddr(avformat->GetSymbol(wxT("avcodec_version")));
846  if (avutil_filename.GetFullPath() == nameFull) {
847  if (avcodec_filename.GetFullPath() == nameFull) {
848  util = avformat.get();
849  codec = avformat.get();
850  }
851  }
852  if (!avcodec_filename.FileExists()) {
853  avcodec_filename = GetLibAVCodecName();
854  }
855  if (!avutil_filename.FileExists()) {
856  avutil_filename = GetLibAVUtilName();
857  }
858 
859  if (util == NULL || codec == NULL) {
860  wxLogMessage(wxT("avformat not monolithic"));
861  avformat->Unload();
862  util = NULL;
863  codec = NULL;
864  }
865  else {
866  wxLogMessage(wxT("avformat is monolithic"));
867  }
868  }
869 
870  // The two wxFileNames don't change after this
871  const wxString avcodec_filename_full{ avcodec_filename.GetFullPath() };
872  const wxString avutil_filename_full{ avutil_filename.GetFullPath() };
873 
874  if (!util) {
875  util = (avutil = std::make_unique<wxDynamicLibrary>()).get();
876  wxLogMessage(wxT("Loading avutil from '%s'."), avutil_filename_full);
877  util->Load(avutil_filename_full, wxDL_LAZY);
878  }
879 
880  if (!codec) {
881  codec = (avcodec = std::make_unique<wxDynamicLibrary>()).get();
882  wxLogMessage(wxT("Loading avcodec from '%s'."), avcodec_filename_full);
883  codec->Load(avcodec_filename_full, wxDL_LAZY);
884  }
885 
886  if (!avformat->IsLoaded()) {
887  name.SetFullName(libpath_format);
888  nameFull = name.GetFullPath();
889  wxLogMessage(wxT("Loading avformat from '%s'."), nameFull);
890  gotError = !avformat->Load(nameFull, wxDL_LAZY);
891  }
892 
893  if (gotError) {
894  wxLogError(wxT("Failed to load FFmpeg libraries."));
895  FreeLibs();
896  return false;
897  }
898 
899  // Show the actual libraries loaded
900  if (avutil) {
901  wxLogMessage(wxT("Actual avutil path %s"),
902  FileNames::PathFromAddr(avutil->GetSymbol(wxT("avutil_version"))));
903  }
904  if (avcodec) {
905  wxLogMessage(wxT("Actual avcodec path %s"),
906  FileNames::PathFromAddr(avcodec->GetSymbol(wxT("avcodec_version"))));
907  }
908  if (avformat) {
909  wxLogMessage(wxT("Actual avformat path %s"),
910  FileNames::PathFromAddr(avformat->GetSymbol(wxT("avformat_version"))));
911  }
912 
913  wxLogMessage(wxT("Importing symbols..."));
914  FFMPEG_INITDYN(avformat, av_register_all);
915  FFMPEG_INITDYN(avformat, avformat_find_stream_info);
916  FFMPEG_INITDYN(avformat, av_read_frame);
917  FFMPEG_INITDYN(avformat, av_seek_frame);
918  FFMPEG_INITDYN(avformat, avformat_close_input);
919  FFMPEG_INITDYN(avformat, avformat_write_header);
920  FFMPEG_INITDYN(avformat, av_interleaved_write_frame);
921  FFMPEG_INITDYN(avformat, av_oformat_next);
922  FFMPEG_INITDYN(avformat, avformat_new_stream);
923  FFMPEG_INITDYN(avformat, avformat_alloc_context);
924  FFMPEG_INITDYN(avformat, av_write_trailer);
925  FFMPEG_INITDYN(avformat, av_codec_get_tag);
926  FFMPEG_INITDYN(avformat, avformat_version);
927  FFMPEG_INITDYN(avformat, avformat_open_input);
928  FFMPEG_INITDYN(avformat, avio_size);
929  FFMPEG_INITDYN(avformat, avio_alloc_context);
930  FFMPEG_INITALT(avformat, av_guess_format, avformat, guess_format);
931  FFMPEG_INITDYN(avformat, avformat_free_context);
932 
933  FFMPEG_INITDYN(avcodec, av_init_packet);
934  FFMPEG_INITDYN(avcodec, av_free_packet);
935  FFMPEG_INITDYN(avcodec, avcodec_find_encoder);
936  FFMPEG_INITDYN(avcodec, avcodec_find_encoder_by_name);
937  FFMPEG_INITDYN(avcodec, avcodec_find_decoder);
938  FFMPEG_INITDYN(avcodec, avcodec_get_name);
939  FFMPEG_INITDYN(avcodec, avcodec_open2);
940  FFMPEG_INITDYN(avcodec, avcodec_decode_audio4);
941  FFMPEG_INITDYN(avcodec, avcodec_encode_audio2);
942  FFMPEG_INITDYN(avcodec, avcodec_close);
943  FFMPEG_INITDYN(avcodec, avcodec_register_all);
944  FFMPEG_INITDYN(avcodec, avcodec_version);
945  FFMPEG_INITDYN(avcodec, av_codec_next);
946  FFMPEG_INITDYN(avcodec, av_codec_is_encoder);
947  FFMPEG_INITDYN(avcodec, avcodec_fill_audio_frame);
948 
949  FFMPEG_INITDYN(avutil, av_free);
950  FFMPEG_INITDYN(avutil, av_dict_free);
951  FFMPEG_INITDYN(avutil, av_dict_get);
952  FFMPEG_INITDYN(avutil, av_dict_set);
953  FFMPEG_INITDYN(avutil, av_get_bytes_per_sample);
954  FFMPEG_INITDYN(avutil, av_log_set_callback);
955  FFMPEG_INITDYN(avutil, av_log_default_callback);
956  FFMPEG_INITDYN(avutil, av_fifo_alloc);
957  FFMPEG_INITDYN(avutil, av_fifo_generic_read);
958  FFMPEG_INITDYN(avutil, av_fifo_realloc2);
959  FFMPEG_INITDYN(avutil, av_fifo_free);
960  FFMPEG_INITDYN(avutil, av_fifo_size);
961  FFMPEG_INITDYN(avutil, av_malloc);
962  FFMPEG_INITDYN(avutil, av_fifo_generic_write);
963  // FFMPEG_INITDYN(avutil, av_freep);
964  FFMPEG_INITDYN(avutil, av_rescale_q);
965  FFMPEG_INITDYN(avutil, avutil_version);
966  FFMPEG_INITALT(avutil, av_frame_alloc, avcodec, avcodec_alloc_frame);
967  FFMPEG_INITALT(avutil, av_frame_free, avcodec, avcodec_free_frame);
968  FFMPEG_INITDYN(avutil, av_samples_get_buffer_size);
969  FFMPEG_INITDYN(avutil, av_get_default_channel_layout);
970  FFMPEG_INITDYN(avutil, av_strerror);
971 
972  wxLogMessage(wxT("All symbols loaded successfully. Initializing the library."));
973 #endif
974 
975  //FFmpeg initialization
976  avcodec_register_all();
977  av_register_all();
978 
979  wxLogMessage(wxT("Retrieving FFmpeg library version numbers:"));
980  int avfver = avformat_version();
981  int avcver = avcodec_version();
982  int avuver = avutil_version();
983  mAVCodecVersion = wxString::Format(wxT("%d.%d.%d"),avcver >> 16 & 0xFF, avcver >> 8 & 0xFF, avcver & 0xFF);
984  mAVFormatVersion = wxString::Format(wxT("%d.%d.%d"),avfver >> 16 & 0xFF, avfver >> 8 & 0xFF, avfver & 0xFF);
985  mAVUtilVersion = wxString::Format(wxT("%d.%d.%d"),avuver >> 16 & 0xFF, avuver >> 8 & 0xFF, avuver & 0xFF);
986 
987  wxLogMessage(wxT(" AVCodec version 0x%06x - %s (built against 0x%06x - %s)"),
988  avcver, mAVCodecVersion, LIBAVCODEC_VERSION_INT,
989  wxString::FromUTF8(AV_STRINGIFY(LIBAVCODEC_VERSION)));
990  wxLogMessage(wxT(" AVFormat version 0x%06x - %s (built against 0x%06x - %s)"),
991  avfver, mAVFormatVersion, LIBAVFORMAT_VERSION_INT,
992  wxString::FromUTF8(AV_STRINGIFY(LIBAVFORMAT_VERSION)));
993  wxLogMessage(wxT(" AVUtil version 0x%06x - %s (built against 0x%06x - %s)"),
994  avuver,mAVUtilVersion, LIBAVUTIL_VERSION_INT,
995  wxString::FromUTF8(AV_STRINGIFY(LIBAVUTIL_VERSION)));
996 
997  int avcverdiff = (avcver >> 16 & 0xFF) - (int)(LIBAVCODEC_VERSION_MAJOR);
998  int avfverdiff = (avfver >> 16 & 0xFF) - (int)(LIBAVFORMAT_VERSION_MAJOR);
999  int avuverdiff = (avuver >> 16 & 0xFF) - (int)(LIBAVUTIL_VERSION_MAJOR);
1000  if (avcverdiff != 0)
1001  wxLogError(wxT("AVCodec version mismatch = %d"), avcverdiff);
1002  if (avfverdiff != 0)
1003  wxLogError(wxT("AVFormat version mismatch = %d"), avfverdiff);
1004  if (avuverdiff != 0)
1005  wxLogError(wxT("AVUtil version mismatch = %d"), avuverdiff);
1006  //make sure that header and library major versions are the same
1007  if (avcverdiff != 0 || avfverdiff != 0 || avuverdiff != 0)
1008  {
1009  wxLogError(wxT("Version mismatch. FFmpeg libraries are unusable."));
1010  return false;
1011  }
1012 
1013  return true;
1014 }
1015 
1017 {
1018  avformat.reset();
1019  avcodec.reset();
1020  avutil.reset();
1021  mLibsLoaded = false;
1022  return;
1023 }
1024 
1025 #endif //USE_FFMPEG
streamContext::m_frameValid
int m_frameValid
Definition: FFmpeg.h:1019
streamContext::m_pktRemainingSiz
int m_pktRemainingSiz
Definition: FFmpeg.h:1014
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
streamContext::m_pkt
Optional< AVPacketEx > m_pkt
Definition: FFmpeg.h:1012
Optional::emplace
X & emplace(Args &&... args)
Definition: MemoryX.h:193
FilePath
wxString FilePath
Definition: Identifier.h:227
ufile_fopen_input
int ufile_fopen_input(std::unique_ptr< FFmpegContext > &context_ptr, FilePath &name)
Definition: FFmpeg.cpp:260
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
FindFFmpegDialog::GetLibPath
wxString GetLibPath()
Definition: FFmpeg.cpp:544
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
ShuttleGuiBase::AddCheckBox
wxCheckBox * AddCheckBox(const TranslatableString &Prompt, bool Selected)
Definition: ShuttleGui.cpp:309
streamContext
Definition: FFmpeg.h:1007
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
fn
static const auto fn
Definition: WaveformView.cpp:1114
HelpSystem.h
ufile_fopen
int ufile_fopen(AVIOContext **s, const FilePath &name, int flags)
Definition: FFmpeg.cpp:221
ShuttleGuiBase::AddTitle
void AddTitle(const TranslatableString &Prompt, int wrapWidth=0)
Centred text string.
Definition: ShuttleGui.cpp:281
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
FFmpeg.h
FindFFmpegDialog::OnDownload
void OnDownload(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:539
FFmpegLibs::FreeLibs
void FreeLibs()
! Frees (unloads) loaded libraries
Definition: FFmpeg.cpp:1016
AVPacketEx
Definition: FFmpeg.h:886
FFMPEG_INITALT
#define FFMPEG_INITALT(w, f, x, a)
Definition: FFmpeg.h:480
FFmpegLibs::FindLibs
bool FindLibs(wxWindow *parent)
Definition: FFmpeg.cpp:644
Format
Abstract base class used in importing a file.
streamContext::m_samplesize
size_t m_samplesize
Definition: FFmpeg.h:1025
ufile_write
static int ufile_write(void *opaque, uint8_t *buf, int size)
Definition: FFmpeg.cpp:164
FFmpegContext::ic_ptr
AVFormatContext * ic_ptr
Definition: FFmpeg.h:385
XO
#define XO(s)
Definition: Internat.h:31
FindFFmpegDialog::mTypes
FileNames::FileTypes mTypes
Definition: FFmpeg.cpp:555
streamContext::m_pktDataPtr
uint8_t * m_pktDataPtr
Definition: FFmpeg.h:1013
FFmpegLibs::ValidLibsLoaded
bool ValidLibsLoaded()
Definition: FFmpeg.cpp:766
FFmpegLibs::InitLibs
bool InitLibs(const wxString &libpath_codec, bool showerr)
Definition: FFmpeg.cpp:771
FFmpegLibs::mLibsLoaded
bool mLibsLoaded
! true if libraries are loaded, false otherwise
Definition: FFmpeg.h:366
streamContext::m_decodedAudioSamplesSiz
unsigned int m_decodedAudioSamplesSiz
Definition: FFmpeg.h:1021
ShuttleGuiBase::EndMultiColumn
void EndMultiColumn()
Definition: ShuttleGui.cpp:1238
PickFFmpegLibs
FFmpegLibs * PickFFmpegLibs()
Definition: FFmpeg.cpp:51
ufile_read
static int ufile_read(void *opaque, uint8_t *buf, int size)
Definition: FFmpeg.cpp:158
FFmpegLibs::GetLibAVUtilName
wxString GetLibAVUtilName()
Definition: FFmpeg.h:341
FindFFmpegDialog::mLibPath
wxFileName mLibPath
Definition: FFmpeg.cpp:551
HelpSystem::ShowHelp
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
FindFFmpegDialog::FindFFmpegDialog
FindFFmpegDialog(wxWindow *parent, const wxString &path, const wxString &name, FileNames::FileTypes types)
Definition: FFmpeg.cpp:456
FFmpegLibs
Class used to dynamically load FFmpeg libraries.
Definition: FFmpeg.h:207
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
streamContext::m_samplefmt
AVSampleFormat m_samplefmt
Definition: FFmpeg.h:1026
LoadFFmpeg
bool LoadFFmpeg(bool showerror)
Definition: FFmpeg.cpp:71
FFmpegContext::~FFmpegContext
~FFmpegContext()
Definition: FFmpeg.cpp:296
FFmpegLibs::GetLibAVCodecName
wxString GetLibAVCodecName()
Definition: FFmpeg.h:336
av_log_wx_callback
void av_log_wx_callback(void *ptr, int level, const char *fmt, va_list vl)
Callback function to catch FFmpeg log messages.
Definition: FFmpeg.cpp:128
FFmpegLibs::GetLibraryTypes
FileNames::FileTypes GetLibraryTypes()
Definition: FFmpeg.h:317
XXO
#define XXO(s)
Definition: Internat.h:44
AVSEEK_FORCE
#define AVSEEK_FORCE
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
ufile_seek
static int64_t ufile_seek(void *opaque, int64_t pos, int whence)
Definition: FFmpeg.cpp:172
ShuttleGuiBase::AddTextBox
wxTextCtrl * AddTextBox(const TranslatableString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:638
ShuttleGuiBase::StartMultiColumn
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:1229
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
FileNames::PathFromAddr
AUDACITY_DLL_API FilePath PathFromAddr(void *addr)
FindFFmpegDialog::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S)
Definition: FFmpeg.cpp:472
FFmpegLibs::mAVCodecVersion
wxString mAVCodecVersion
! Stored library version
Definition: FFmpeg.h:358
streamContext::m_decodedAudioSamplesValidSiz
size_t m_decodedAudioSamplesValidSiz
Definition: FFmpeg.h:1022
GetFFmpegVersion
TranslatableString GetFFmpegVersion()
Definition: FFmpeg.cpp:113
FFmpegLibs::GetLibAVFormatName
wxString GetLibAVFormatName()
Definition: FFmpeg.h:331
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
FindFFmpegDialog::mPath
wxString mPath
Definition: FFmpeg.cpp:553
FFmpegNotFoundDialog
Definition: FFmpeg.h:185
name
const TranslatableString name
Definition: Distortion.cpp:98
FFMPEG_INITDYN
#define FFMPEG_INITDYN(w, f)
Definition: FFmpeg.h:469
FFmpegLibs::mAVUtilVersion
wxString mAVUtilVersion
Definition: FFmpeg.h:360
FindFFmpegDialog::mPathText
wxTextCtrl * mPathText
Definition: FFmpeg.cpp:557
FFmpegLibs::mLibAVFormatPath
wxString mLibAVFormatPath
! Stored path to libavformat library
Definition: FFmpeg.h:355
import_ffmpeg_read_next_frame
streamContext * import_ffmpeg_read_next_frame(AVFormatContext *formatContext, streamContext **streams, unsigned int numStreams)
Definition: FFmpeg.cpp:315
streamContext::m_decodedAudioSamples
AVMallocHolder< uint8_t > m_decodedAudioSamples
Definition: FFmpeg.h:1020
FindFFmpegDialog::mName
wxString mName
Definition: FFmpeg.cpp:554
ShuttleGuiBase::AddButton
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:360
wxDialogWrapper
Definition: wxPanelWrapper.h:81
FFmpegLibs::LoadLibs
bool LoadLibs(wxWindow *parent, bool showerr)
Definition: FFmpeg.cpp:689
streamContext::m_codecCtx
AVCodecContext * m_codecCtx
Definition: FFmpeg.h:1010
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
eOkButton
@ eOkButton
Definition: ShuttleGui.h:600
Read
gPrefs Read(wxT("/GUI/VerticalZooming"), &bVZoom, false)
FFmpegNotFoundDialog::mDontShow
wxCheckBox * mDontShow
Definition: FFmpeg.h:196
FindFFmpegDialog::OnBrowse
void OnBrowse(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:518
FileNames::SelectFile
AUDACITY_DLL_API FilePath SelectFile(Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
FFmpegLibsInst
FFmpegLibs * FFmpegLibsInst()
Definition: FFmpeg.cpp:46
ID_FFMPEG_DLOAD
#define ID_FFMPEG_DLOAD
Definition: FFmpeg.cpp:449
_
#define _(s)
Definition: Internat.h:75
FFmpegLibs::mAVFormatVersion
wxString mAVFormatVersion
Definition: FFmpeg.h:359
FileNames.h
AudacityMessageBox.h
FFmpegNotFoundDialog::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S)
Definition: FFmpeg.cpp:580
FFmpegLibs::GetLibAVFormatPath
wxString GetLibAVFormatPath()
Definition: FFmpeg.h:326
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
ID_FFMPEG_BROWSE
#define ID_FFMPEG_BROWSE
Definition: FFmpeg.cpp:448
DropFFmpegLibs
void DropFFmpegLibs()
Definition: FFmpeg.cpp:61
ShuttleGui::AddStandardButtons
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
Definition: ShuttleGui.cpp:2432
FFmpegLibs::~FFmpegLibs
~FFmpegLibs()
Definition: FFmpeg.cpp:639
ufile_close
int ufile_close(AVIOContext *pb)
Definition: FFmpeg.cpp:198
FileNames::FileTypes
std::vector< FileType > FileTypes
Definition: FileNames.h:79
FFmpegStartup
void FFmpegStartup()
Definition: FFmpeg.cpp:95
AVFrameHolder
std::unique_ptr< AVFrame, AV_Deleterp< AVFrame, void, av_frame_free > > AVFrameHolder
Definition: FFmpeg.h:966
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
wxDialogWrapper::SetName
void SetName()
Definition: wxPanelWrapper.cpp:81
import_ffmpeg_decode_frame
int import_ffmpeg_decode_frame(streamContext *sc, bool flushing)
Definition: FFmpeg.cpp:350
ShuttleGuiBase::AddVariableText
wxStaticText * AddVariableText(const TranslatableString &Str, bool bCenter=false, int PositionFlags=0, int wrapWidth=0)
Definition: ShuttleGui.cpp:463
FFmpegLibs::avformat
std::unique_ptr< wxDynamicLibrary > avformat
! wx interfaces for dynamic libraries
Definition: FFmpeg.h:363
ShuttleGuiBase::SetStretchyCol
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:202
FFmpegLibs::avutil
std::unique_ptr< wxDynamicLibrary > avutil
Definition: FFmpeg.h:363
FFmpegContext::pb
AVIOContext * pb
Definition: FFmpeg.h:384
END_EVENT_TABLE
END_EVENT_TABLE()
FindFFmpegDialog
Allows user to locate libav* libraries.
Definition: FFmpeg.cpp:453
FFmpegLibsPtr
std::unique_ptr< FFmpegLibs > FFmpegLibsPtr
Definition: FFmpeg.cpp:45
FFmpegNotFoundDialog::OnOk
void OnOk(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:610
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
FFmpegLibs::avcodec
std::unique_ptr< wxDynamicLibrary > avcodec
Definition: FFmpeg.h:363