Audacity 3.2.0
FFmpeg.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5FFmpeg.cpp
6
7Audacity(R) is copyright (c) 1999-2009 Audacity Team.
8License: GPL v2 or later. 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 "SelectFile.h"
25#include "widgets/HelpSystem.h"
27
28#include <wx/checkbox.h>
29#include <wx/dynlib.h>
30#include <wx/file.h>
31#include <wx/log.h>
32#include <wx/textctrl.h>
33
34#if !defined(USE_FFMPEG)
38{
39 return XO("FFmpeg support not compiled in");
40}
41
42#else
43
44static BoolSetting FFmpegEnabled{ L"/FFmpeg/Enabled", false };
45
46bool LoadFFmpeg(bool showerror)
47{
48 auto ffmpeg = FFmpegFunctions::Load();
49
50 if (!ffmpeg)
51 {
52 FFmpegEnabled.Write(false);
53 gPrefs->Flush();
54 return false;
55 }
56 else
57 {
58 FFmpegEnabled.Write(true);
59 gPrefs->Flush();
60 return true;
61 }
62}
63
66{
67 bool enabled = FFmpegEnabled.Read();
68 // 'false' means that no errors should be shown whatsoever
69 if (!LoadFFmpeg(false))
70 {
71 if (enabled)
72 {
74"FFmpeg was configured in Preferences and successfully loaded before, \
75\nbut this time Audacity failed to load it at startup. \
76\n\nYou may want to go back to Preferences > Libraries and re-configure it."),
77 XO("FFmpeg startup failed"));
78 }
79 }
80}
81
83{
84 auto ffmpeg = FFmpegFunctions::Load();
85
86 if (ffmpeg)
87 {
88 return Verbatim(
89 wxString::Format(
90 wxT("F(%d.%d.%d),C(%d.%d.%d),U(%d.%d.%d)"),
91 ffmpeg->AVFormatVersion.Major, ffmpeg->AVFormatVersion.Minor, ffmpeg->AVFormatVersion.Micro,
92 ffmpeg->AVCodecVersion.Major, ffmpeg->AVCodecVersion.Minor, ffmpeg->AVCodecVersion.Micro,
93 ffmpeg->AVUtilVersion.Major, ffmpeg->AVUtilVersion.Minor, ffmpeg->AVUtilVersion.Micro
94 ));
95 }
96
97 return XO("FFmpeg library not found");
98}
99
100/*******************************************************/
101
103
104//----------------------------------------------------------------------------
105// FindFFmpegDialog
106//----------------------------------------------------------------------------
107
108#define ID_FFMPEG_BROWSE 5000
109#define ID_FFMPEG_DLOAD 5001
110
113{
114public:
115
116 FindFFmpegDialog(wxWindow *parent, const wxString &path, const wxString &name)
117 : wxDialogWrapper(parent, wxID_ANY, XO("Locate FFmpeg"))
118 , mName(name)
119 , mFullPath(path, {})
120 {
121 SetName();
122
123 ShuttleGui S(this, eIsCreating);
125 }
126
128 {
129 S.SetBorder(10);
130 S.StartVerticalLay(true);
131 {
132 S.AddTitle(
133 XO(
134"Audacity needs the file '%s' to import and export audio via FFmpeg.")
135 .Format( mName ) );
136
137 S.SetBorder(3);
138 S.StartHorizontalLay(wxALIGN_LEFT, true);
139 {
140 S.AddTitle( XO("Location of '%s':").Format( mName ) );
141 }
142 S.EndHorizontalLay();
143
144 S.StartMultiColumn(2, wxEXPAND);
145 S.SetStretchyCol(0);
146 {
147 if (mFullPath.GetFullPath().empty())
148 {
149 mPathText = S.AddTextBox(
150 {},
151 XO("To find '%s', click here -->")
152 .Format(mName)
153 .Translation(),
154 0);
155 }
156 else
157 {
158 mPathText = S.AddTextBox({}, mFullPath.GetFullPath(), 0);
159 }
160
161 S.Id(ID_FFMPEG_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
162 S.AddVariableText(
163 XO("To get a free copy of FFmpeg, click here -->"), true);
164 S.Id(ID_FFMPEG_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
165 }
166 S.EndMultiColumn();
167
168 S.AddStandardButtons();
169 }
170 S.EndVerticalLay();
171
172 Layout();
173 Fit();
174 SetMinSize(GetSize());
175 Center();
176
177 return;
178 }
179
180 void OnBrowse(wxCommandEvent & WXUNUSED(event))
181 {
182 static const FileNames::FileTypes types = {
183# if defined(__WXMSW__)
184 { XO("Only avformat.dll"), { wxT("avformat-*.dll") } },
185# elif defined(__WXMAC__)
186 { XO("Only ffmpeg.*.dylib"), { wxT("ffmpeg.*.dylib"), wxT("libavformat.*.dylib") } },
187# else
188 { XO("Only libavformat.so"), { wxT("libavformat.so.*") } },
189# endif
192 };
193
194 UpdatePath();
195
196 /* i18n-hint: It's asking for the location of a file, for
197 example, "Where is lame_enc.dll?" - you could translate
198 "Where would I find the file '%s'?" instead if you want. */
199 auto question = XO("Where is '%s'?").Format( mName );
200
201 wxString path = SelectFile(
202 FileNames::Operation::_None,
203 question,
204 mFullPath.GetPath(),
205 mFullPath.GetFullName(),
206 wxT(""),
207 types,
208 wxFD_OPEN | wxRESIZE_BORDER,
209 this);
210
211 if (!path.empty())
212 {
213 mFullPath = path;
214 mPathText->SetValue(path);
215 }
216 }
217
218 void OnDownload(wxCommandEvent & WXUNUSED(event))
219 {
220 HelpSystem::ShowHelp(this, L"FAQ:Installing_the_FFmpeg_Import_Export_Library");
221 }
222
224 {
225 const wxString path = mPathText->GetValue();
226
227 if (wxDirExists(path))
228 mFullPath = wxFileName(path, {}, wxPATH_NATIVE);
229 else
230 mFullPath = mPathText->GetValue();
231 }
232
233 wxString GetLibPath()
234 {
235 UpdatePath();
236 return mFullPath.GetFullPath();
237 }
238
239private:
240 wxString mName;
241 wxFileName mFullPath;
242
243 wxTextCtrl *mPathText;
244
245 DECLARE_EVENT_TABLE()
246};
247
248BEGIN_EVENT_TABLE(FindFFmpegDialog, wxDialogWrapper)
252
253
254//----------------------------------------------------------------------------
255// FFmpegNotFoundDialog
256//----------------------------------------------------------------------------
257
259 : wxDialogWrapper(parent, wxID_ANY, XO("FFmpeg not found"))
260{
261 SetName();
262 ShuttleGui S(this, eIsCreating);
263 PopulateOrExchange(S);
264}
265
267{
268 wxString text;
269
270 S.SetBorder(10);
271 S.StartVerticalLay(true);
272 {
273 S.AddFixedText(XO(
274"Audacity attempted to use FFmpeg to import an audio file,\n\
275but the libraries were not found.\n\n\
276To use FFmpeg import, go to Edit > Preferences > Libraries\n\
277to download or locate the FFmpeg libraries."
278 ));
279
280 mDontShow = S
281 .AddCheckBox(XXO("Do not show this warning again"),
283
284 S.AddStandardButtons(eOkButton);
285 }
286 S.EndVerticalLay();
287
288 Layout();
289 Fit();
290 SetMinSize(GetSize());
291 Center();
292
293 return;
294}
295
296void FFmpegNotFoundDialog::OnOk(wxCommandEvent & WXUNUSED(event))
297{
298 if (mDontShow->GetValue())
299 {
301 gPrefs->Flush();
302 }
303 this->EndModal(0);
304}
305
306BEGIN_EVENT_TABLE(FFmpegNotFoundDialog, wxDialogWrapper)
309
310bool FindFFmpegLibs(wxWindow* parent)
311{
312 wxString path;
313
314#if defined(__WXMSW__)
315 const wxString name = wxT("avformat.dll");
316#elif defined(__WXMAC__)
317 const wxString name = wxT("ffmpeg.64bit.dylib");
318#else
319 const wxString name = wxT("libavformat.so");
320#endif
321
322 wxLogMessage(wxT("Looking for FFmpeg libraries..."));
323
324 auto searchPaths = FFmpegFunctions::GetSearchPaths(false);
325
326 if (!searchPaths.empty())
327 path = searchPaths.front();
328
329 FindFFmpegDialog fd(parent, path, name);
330
331 if (fd.ShowModal() == wxID_CANCEL) {
332 wxLogMessage(wxT("User canceled the dialog. Failed to find FFmpeg libraries."));
333 return false;
334 }
335
336 path = fd.GetLibPath();
337
338 const wxFileName fileName(path);
339
340 if (fileName.FileExists())
341 path = fileName.GetPath();
342
343 wxLogMessage(wxT("User-specified path = '%s'"), path);
344
345 SettingTransaction transaction;
346 AVFormatPath.Write(path);
347
348 // Try to load FFmpeg from the user provided path
349 if (!FFmpegFunctions::Load(true))
350 {
351 wxLogError(wxT("User-specified path does not contain FFmpeg libraries."));
352 return false;
353 }
354
355 transaction.Commit();
356
357 wxLogMessage(wxT("User-specified FFmpeg file exists. Success."));
358
359 return true;
360}
361
362BoolSetting FFmpegNotFoundDontShow{ L"/FFmpeg/NotFoundDontShow", false };
363
364#endif //USE_FFMPEG
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
TranslatableString GetFFmpegVersion()
Definition: FFmpeg.cpp:82
static BoolSetting FFmpegEnabled
Definition: FFmpeg.cpp:44
#define ID_FFMPEG_BROWSE
Definition: FFmpeg.cpp:108
#define ID_FFMPEG_DLOAD
Definition: FFmpeg.cpp:109
bool FindFFmpegLibs(wxWindow *parent)
Definition: FFmpeg.cpp:310
BoolSetting FFmpegNotFoundDontShow
Definition: FFmpeg.cpp:362
bool LoadFFmpeg(bool showerror)
Definition: FFmpeg.cpp:46
void FFmpegStartup()
Definition: FFmpeg.cpp:65
StringSetting AVFormatPath
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
FileConfig * gPrefs
Definition: Prefs.cpp:71
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
@ eIsCreating
Definition: ShuttleGui.h:39
@ eOkButton
Definition: ShuttleGui.h:600
#define S(N)
Definition: ToChars.cpp:64
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:286
void PopulateOrExchange(ShuttleGui &S)
Definition: FFmpeg.cpp:266
void OnOk(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:296
wxCheckBox * mDontShow
Definition: FFmpeg.h:68
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
std::vector< FileType > FileTypes
Definition: FileNames.h:76
FILES_API const FileType AllFiles
Definition: FileNames.h:71
FILES_API const FileType DynamicLibraries
Definition: FileNames.h:73
Allows user to locate libav* libraries.
Definition: FFmpeg.cpp:113
void OnDownload(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:218
wxFileName mFullPath
Definition: FFmpeg.cpp:241
FindFFmpegDialog(wxWindow *parent, const wxString &path, const wxString &name)
Definition: FFmpeg.cpp:116
wxTextCtrl * mPathText
Definition: FFmpeg.cpp:243
void UpdatePath()
Definition: FFmpeg.cpp:223
void PopulateOrExchange(ShuttleGui &S)
Definition: FFmpeg.cpp:127
wxString GetLibPath()
Definition: FFmpeg.cpp:233
void OnBrowse(wxCommandEvent &WXUNUSED(event))
Definition: FFmpeg.cpp:180
wxString mName
Definition: FFmpeg.cpp:240
Abstract base class used in importing a file.
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:229
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:185
Extend SettingScope with Commit() which flushes updates in a batch.
Definition: Prefs.h:130
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
Holds a msgid for the translation catalog; may also bind format arguments.
static std::vector< wxString > GetSearchPaths(bool fromUserPathOnly)
static std::shared_ptr< FFmpegFunctions > Load(bool fromUserPathOnly=false)