Files
tenacity/modules/import-export/mod-ffmpeg/FFmpeg.cpp
Avery King 908c64809a Perform rebranding
This includes the following changes:

- Rename Audacity to Tenacity
- Rename theme

A few notes too:

- Some strings that were updated to use Tenacity's name might later be
  removed pending remerges.
- I'm not readding Tenacity's original themes. We'll rewrite the theme
  system before reintroducing them.

Signed-off-by: Avery King <avery98@pm.me>
2025-01-04 14:54:43 -08:00

365 lines
9.0 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
FFmpeg.cpp
Audacity(R) is copyright (c) 1999-2009 Audacity Team.
License: GPL v2 or later. See License.txt.
******************************************************************//**
\class FFmpegLibs
\brief Class used to dynamically load FFmpeg libraries
*//*******************************************************************/
// Store function pointers here when including FFmpeg.h
#define DEFINE_FFMPEG_POINTERS
#include "FFmpeg.h"
#include "FFmpegFunctions.h"
#include "ModuleConstants.h"
#include "FileNames.h"
#include "SelectFile.h"
#include "HelpSystem.h"
#include "AudacityMessageBox.h"
#include "ShuttleGui.h"
#include <wx/checkbox.h>
#include <wx/dynlib.h>
#include <wx/file.h>
#include <wx/log.h>
#include <wx/textctrl.h>
static BoolSetting FFmpegEnabled{ L"/FFmpeg/Enabled", false };
bool LoadFFmpeg(bool showerror)
{
auto ffmpeg = FFmpegFunctions::Load();
if (!ffmpeg)
{
FFmpegEnabled.Write(false);
gPrefs->Flush();
return false;
}
else
{
FFmpegEnabled.Write(true);
gPrefs->Flush();
return true;
}
}
/** Called during Audacity start-up to try and load the ffmpeg libraries */
void FFmpegStartup()
{
bool enabled = FFmpegEnabled.Read();
// 'false' means that no errors should be shown whatsoever
if (!LoadFFmpeg(false))
{
if (enabled)
{
AudacityMessageBox(XO(
"FFmpeg was configured in Preferences and successfully loaded before, \
\nbut this time Tenacity failed to load it at startup. \
\n\nYou may want to go back to Preferences > Libraries and re-configure it."),
XO("FFmpeg startup failed"));
}
}
}
TranslatableString GetFFmpegVersion()
{
auto ffmpeg = FFmpegFunctions::Load();
if (ffmpeg)
{
return Verbatim(
wxString::Format(
wxT("F(%d.%d.%d),C(%d.%d.%d),U(%d.%d.%d)"),
ffmpeg->AVFormatVersion.Major, ffmpeg->AVFormatVersion.Minor, ffmpeg->AVFormatVersion.Micro,
ffmpeg->AVCodecVersion.Major, ffmpeg->AVCodecVersion.Minor, ffmpeg->AVCodecVersion.Micro,
ffmpeg->AVUtilVersion.Major, ffmpeg->AVUtilVersion.Minor, ffmpeg->AVUtilVersion.Micro
));
}
return XO("FFmpeg library not found");
}
/*******************************************************/
class FFmpegNotFoundDialog;
//----------------------------------------------------------------------------
// FindFFmpegDialog
//----------------------------------------------------------------------------
#define ID_FFMPEG_BROWSE 5000
#define ID_FFMPEG_DLOAD 5001
/// Allows user to locate libav* libraries
class FindFFmpegDialog final : public wxDialogWrapper
{
public:
FindFFmpegDialog(wxWindow *parent, const wxString &path, const wxString &name)
: wxDialogWrapper(parent, wxID_ANY, XO("Locate FFmpeg"))
, mName(name)
, mFullPath(path, {})
{
SetName();
ShuttleGui S(this, eIsCreating);
PopulateOrExchange(S);
}
void PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(10);
S.StartVerticalLay(true);
{
S.AddTitle(
XO(
"Tenacity needs the file '%s' to import and export audio via FFmpeg.")
.Format( mName ) );
S.SetBorder(3);
S.StartHorizontalLay(wxALIGN_LEFT, true);
{
S.AddTitle( XO("Location of '%s':").Format( mName ) );
}
S.EndHorizontalLay();
S.StartMultiColumn(2, wxEXPAND);
S.SetStretchyCol(0);
{
if (mFullPath.GetFullPath().empty())
{
mPathText = S.AddTextBox(
{},
XO("To find '%s', click here -->")
.Format(mName)
.Translation(),
0);
}
else
{
mPathText = S.AddTextBox({}, mFullPath.GetFullPath(), 0);
}
S.Id(ID_FFMPEG_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
S.AddVariableText(
XO("To get a free copy of FFmpeg, click here -->"), true);
S.Id(ID_FFMPEG_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
}
S.EndMultiColumn();
S.AddStandardButtons();
}
S.EndVerticalLay();
Layout();
Fit();
SetMinSize(GetSize());
Center();
return;
}
void OnBrowse(wxCommandEvent & WXUNUSED(event))
{
static const FileNames::FileTypes types = {
# if defined(__WXMSW__)
{ XO("Only avformat.dll"), { wxT("avformat-*.dll") } },
# elif defined(__WXMAC__)
{ XO("Only libavformat.dylib"), { wxT("ffmpeg.*.dylib"), wxT("libavformat.*.dylib") } },
# else
{ XO("Only libavformat.so"), { wxT("libavformat.so.*") } },
# endif
FileNames::DynamicLibraries,
FileNames::AllFiles
};
UpdatePath();
/* i18n-hint: It's asking for the location of a file, for
example, "Where is lame_enc.dll?" - you could translate
"Where would I find the file '%s'?" instead if you want. */
auto question = XO("Where is '%s'?").Format( mName );
wxString path = SelectFile(
FileNames::Operation::_None,
question,
mFullPath.GetPath(),
mFullPath.GetFullName(),
wxT(""),
types,
wxFD_OPEN | wxRESIZE_BORDER,
this);
if (!path.empty())
{
mFullPath = path;
mPathText->SetValue(path);
}
}
void OnDownload(wxCommandEvent & WXUNUSED(event))
{
HelpSystem::ShowHelp(this, L"FAQ:Installing_the_FFmpeg_Import_Export_Library");
}
void UpdatePath()
{
const wxString path = mPathText->GetValue();
if (wxDirExists(path))
mFullPath = wxFileName(path, {}, wxPATH_NATIVE);
else
mFullPath = mPathText->GetValue();
}
wxString GetLibPath()
{
UpdatePath();
return mFullPath.GetFullPath();
}
private:
wxString mName;
wxFileName mFullPath;
wxTextCtrl *mPathText;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(FindFFmpegDialog, wxDialogWrapper)
EVT_BUTTON(ID_FFMPEG_BROWSE, FindFFmpegDialog::OnBrowse)
EVT_BUTTON(ID_FFMPEG_DLOAD, FindFFmpegDialog::OnDownload)
END_EVENT_TABLE()
//----------------------------------------------------------------------------
// FFmpegNotFoundDialog
//----------------------------------------------------------------------------
FFmpegNotFoundDialog::FFmpegNotFoundDialog(wxWindow *parent)
: wxDialogWrapper(parent, wxID_ANY, XO("FFmpeg not found"))
{
SetName();
ShuttleGui S(this, eIsCreating);
PopulateOrExchange(S);
}
void FFmpegNotFoundDialog::PopulateOrExchange(ShuttleGui & S)
{
wxString text;
S.SetBorder(10);
S.StartVerticalLay(true);
{
S.AddFixedText(XO(
"Tenacity attempted to use FFmpeg to import an audio file,\n\
but the libraries were not found.\n\n\
To use FFmpeg import, go to Edit > Preferences > Libraries\n\
to download or locate the FFmpeg libraries."
));
mDontShow = S
.AddCheckBox(XXO("Do not show this warning again"),
FFmpegNotFoundDontShow.Read() );
S.AddStandardButtons(eOkButton);
}
S.EndVerticalLay();
Layout();
Fit();
SetMinSize(GetSize());
Center();
return;
}
void FFmpegNotFoundDialog::OnOk(wxCommandEvent & WXUNUSED(event))
{
if (mDontShow->GetValue())
{
FFmpegNotFoundDontShow.Write(true);
gPrefs->Flush();
}
this->EndModal(0);
}
BEGIN_EVENT_TABLE(FFmpegNotFoundDialog, wxDialogWrapper)
EVT_BUTTON(wxID_OK, FFmpegNotFoundDialog::OnOk)
END_EVENT_TABLE()
bool FindFFmpegLibs(wxWindow* parent)
{
wxString path;
#if defined(__WXMSW__)
const wxString name = wxT("avformat.dll");
#elif defined(__WXMAC__)
const wxString name = wxT("libavformat.dylib");
#else
const wxString name = wxT("libavformat.so");
#endif
wxLogMessage(wxT("Looking for FFmpeg libraries..."));
auto searchPaths = FFmpegFunctions::GetSearchPaths(false);
if (!searchPaths.empty())
path = searchPaths.front();
FindFFmpegDialog fd(parent, path, name);
if (fd.ShowModal() == wxID_CANCEL) {
wxLogMessage(wxT("User canceled the dialog. Failed to find FFmpeg libraries."));
return false;
}
path = fd.GetLibPath();
const wxFileName fileName(path);
if (fileName.FileExists())
path = fileName.GetPath();
wxLogMessage(wxT("User-specified path = '%s'"), path);
SettingTransaction transaction;
AVFormatPath.Write(path);
// Try to load FFmpeg from the user provided path
if (!FFmpegFunctions::Load(true))
{
wxLogError(wxT("User-specified path does not contain FFmpeg libraries."));
return false;
}
transaction.Commit();
wxLogMessage(wxT("User-specified FFmpeg file exists. Success."));
return true;
}
BoolSetting FFmpegNotFoundDontShow{ L"/FFmpeg/NotFoundDontShow", false };
DEFINE_VERSION_CHECK
extern "C" DLL_API int ModuleDispatch(ModuleDispatchTypes type)
{
if(type == ModuleInitialize)
FFmpegStartup();
return 1;
}