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