audacia/src/FFmpeg.cpp

936 lines
26 KiB
C++
Raw Normal View History

/**********************************************************************
Audacity: A Digital Audio Editor
FFmpeg.cpp
Audacity(R) is copyright (c) 1999-2009 Audacity Team.
License: GPL v2. See License.txt.
******************************************************************//**
\class FFmpegLibs
\brief Class used to dynamically load FFmpeg libraries
*//*******************************************************************/
#include "Audacity.h" // for config*.h
#include "FFmpeg.h"
#include "AudacityApp.h"
#include <wx/file.h>
#ifdef _DEBUG
#ifdef _MSC_VER
#undef THIS_FILE
static char*THIS_FILE= __FILE__;
#define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
#endif
#endif
#if !defined(USE_FFMPEG)
/// FFmpeg support may or may not be compiled in,
/// but Preferences dialog requires this function nevertheless
wxString GetFFmpegVersion(wxWindow *parent)
{
return wxString(_("FFmpeg support not compiled in"));
}
#else
/** This pointer to the shared object has global scope and is used to track the
* singleton object which wraps the FFmpeg codecs */
FFmpegLibs *FFmpegLibsInst = NULL;
FFmpegLibs *PickFFmpegLibs()
{
if (FFmpegLibsInst != NULL)
{
FFmpegLibsInst->refcount++;
return FFmpegLibsInst;
}
else
{
FFmpegLibsInst = new FFmpegLibs();
return FFmpegLibsInst;
}
}
void DropFFmpegLibs()
{
if (FFmpegLibsInst != NULL)
{
FFmpegLibsInst->refcount--;
if (FFmpegLibsInst->refcount == 0)
{
delete FFmpegLibsInst;
FFmpegLibsInst = NULL;
}
}
}
bool LoadFFmpeg(bool showerror)
{
PickFFmpegLibs();
if (FFmpegLibsInst->ValidLibsLoaded())
{
DropFFmpegLibs();
return true;
}
if (!FFmpegLibsInst->LoadLibs(NULL,showerror))
{
DropFFmpegLibs();
gPrefs->Write(wxT("/FFmpeg/Enabled"), false);
return false;
}
else
{
gPrefs->Write(wxT("/FFmpeg/Enabled"), true);
return true;
}
}
/** Called during Audacity start-up to try and load the ffmpeg libraries */
void FFmpegStartup()
{
bool enabled = false;
gPrefs->Read(wxT("/FFmpeg/Enabled"),&enabled);
// 'false' means that no errors should be shown whatsoever
if (enabled && !LoadFFmpeg(false))
{
wxMessageBox(_("FFmpeg was configured in Preferences and successfully loaded before, \
\nbut this time Audacity failed to load it at startup. \
\n\nYou may want to go back to Preferences > Libraries and re-configure it."),
_("FFmpeg startup failed"));
}
}
wxString GetFFmpegVersion(wxWindow *parent)
{
PickFFmpegLibs();
wxString versionString = _("FFmpeg library not found");
if (FFmpegLibsInst->ValidLibsLoaded()) {
versionString = FFmpegLibsInst->GetLibraryVersion();
}
DropFFmpegLibs();
return versionString;
}
void av_log_wx_callback(void* ptr, int level, const char* fmt, va_list vl)
{
//Most of this stuff is taken from FFmpeg tutorials and FFmpeg itself
int av_log_level = AV_LOG_WARNING;
AVClass* avc = ptr ? *(AVClass**)ptr : NULL;
if (level > av_log_level)
return;
wxString printstring(wxT(""));
if (avc) {
printstring.Append(wxString::Format(wxT("[%s @ %p] "), wxString::FromUTF8(avc->item_name(ptr)).c_str(), avc));
}
wxString frm(fmt,wxConvLibc);
#if defined(__WXMSW__)
frm.Replace(wxT("%t"),wxT("%i"),true); //TODO: on Windows vprintf won't handle %t, and probably some others. Investigate.
#endif
#if defined(wxUSE_UNICODE)
// String comes with %s format field and a value in value list is ascii char*. Thus in Unicode configurations
// we have to convert %s to %S.
frm.Replace(wxT("%s"),wxT("%S"),true);
#endif
printstring.Append(wxString::FormatV(frm,vl));
wxString cpt;
switch (level)
{
case 0: cpt = wxT("Error"); break;
case 1: cpt = wxT("Info"); break;
case 2: cpt = wxT("Debug"); break;
default: cpt = wxT("Log"); break;
}
#ifdef EXPERIMENTAL_OD_FFMPEG
//if the decoding happens thru OD then this gets called from a non main thread, which means wxLogMessage
//will crash.
//TODO:find some workaround for the log. perhaps use ODManager as a bridge. for now just print
if(!wxThread::IsMain())
printf("%s: %s\n",(char*)cpt.char_str(),(char*)printstring.char_str());
else
#endif
wxLogMessage(wxT("%s: %s"),cpt.c_str(),printstring.c_str());
}
//======================= Unicode aware uri protocol for FFmpeg
// Code inspired from ffmpeg-users mailing list sample
static int ufile_open(URLContext *h, const char *filename, int flags)
{
wxFile *f;
wxFile::OpenMode mode;
f = new wxFile;
if (!f) {
return AVERROR(ENOMEM);
}
if (flags & URL_RDWR) {
mode = wxFile::read_write;
} else if (flags & URL_WRONLY) {
mode = wxFile::write;
} else {
mode = wxFile::read;
}
if (!f->Open((const wxChar *) filename, mode)) {
delete f;
return AVERROR(ENOENT);
}
h->priv_data = (void *)f;
return 0;
}
static int ufile_read(URLContext *h, unsigned char *buf, int size)
{
//return (int) ((wxFile *) h->priv_data)->Read(buf, size);
static int totalret = 0;
int ret = (int) ((wxFile *) h->priv_data)->Read(buf, size);
totalret += ret;
return ret;
}
static int ufile_write(URLContext *h, unsigned char *buf, int size)
{
return (int) ((wxFile *) h->priv_data)->Write(buf, size);
}
#if LIBAVFORMAT_VERSION_MAJOR >= 52
static int64_t ufile_seek(URLContext *h, int64_t pos, int whence)
#else
static offset_t ufile_seek(URLContext *h, offset_t pos, int whence)
#endif
{
wxSeekMode mode;
switch (whence)
{
case (SEEK_SET):
mode = wxFromStart;
break;
case (SEEK_CUR):
mode = wxFromCurrent;
break;
case (SEEK_END):
mode = wxFromEnd;
break;
case (AVSEEK_SIZE):
return ((wxFile *) h->priv_data)->Length();
}
return ((wxFile *) h->priv_data)->Seek(pos, mode);
}
static int ufile_close(URLContext *h)
{
wxFile *f = (wxFile *) h->priv_data;
if (f) {
f->Close();
delete f;
}
return 0;
}
URLProtocol ufile_protocol = {
"ufile",
ufile_open,
ufile_read,
ufile_write,
ufile_seek,
ufile_close,
};
// Open a file with a (possibly) Unicode filename
int ufile_fopen(ByteIOContext **s, const wxString & name, int flags)
{
URLContext *h;
int err;
// Open the file using our custom protocol and passing the (possibly) Unicode
// filename. This is playing a slight trick since our ufile_open() routine above
// knows that the "char *" name may actually be wide characters.
err = FFmpegLibsInst->url_open_protocol(&h, &ufile_protocol, (const char *) name.c_str(), flags);
if (err < 0) {
return err;
}
// Associate the file with a context
err = FFmpegLibsInst->url_fdopen(s, h);
if (err < 0) {
FFmpegLibsInst->url_close(h);
return err;
}
return 0;
}
// Size of probe buffer, for guessing file type from file contents
#define PROBE_BUF_MIN 2048
#define PROBE_BUF_MAX (1<<20)
// Detect type of input file and open it if recognized. Routine
// based on the av_open_input_file() libavformat function.
int ufile_fopen_input(AVFormatContext **ic_ptr, wxString & name)
{
wxFileName f(name);
wxCharBuffer fname;
const char *filename;
AVProbeData pd;
ByteIOContext *pb = NULL;
AVInputFormat *fmt = NULL;
AVInputFormat *fmt1;
int probe_size;
int err;
// Create a dummy file name using the extension from the original
f.SetName(wxT("ufile"));
fname = f.GetFullName().mb_str();
filename = (const char *) fname;
// Initialize probe data...go ahead and preallocate the maximum buffer size.
pd.filename = filename;
pd.buf_size = 0;
pd.buf = (unsigned char *) FFmpegLibsInst->av_malloc(PROBE_BUF_MAX + AVPROBE_PADDING_SIZE);
if (pd.buf == NULL) {
err = AVERROR_NOMEM;
goto fail;
}
// Open the file to prepare for probing
if ((err = ufile_fopen(&pb, name, URL_RDONLY)) < 0) {
goto fail;
}
for (probe_size = PROBE_BUF_MIN; probe_size <= PROBE_BUF_MAX && !fmt; probe_size <<= 1) {
int score_max = probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX / 4 : 0;
// Read up to a "probe_size" worth of data
pd.buf_size = FFmpegLibsInst->get_buffer(pb, pd.buf, probe_size);
// Clear up to a "AVPROBE_PADDING_SIZE" worth of unused buffer
memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
// Reposition file for succeeding scan
if (FFmpegLibsInst->url_fseek(pb, 0, SEEK_SET) < 0) {
err = AVERROR(EIO);
goto fail;
}
// Scan all input formats
fmt = NULL;
for (fmt1 = FFmpegLibsInst->av_iformat_next(NULL); fmt1 != NULL; fmt1 = FFmpegLibsInst->av_iformat_next(fmt1)) {
int score = 0;
// Ignore the ones that are not file based
if (fmt1->flags & AVFMT_NOFILE) {
continue;
}
// If the format can probe the file then try that first
if (fmt1->read_probe) {
score = fmt1->read_probe(&pd);
}
// Otherwize, resort to extension matching if available
else if (fmt1->extensions) {
if (FFmpegLibsInst->match_ext(filename, fmt1->extensions)) {
score = 50;
}
}
// Remember this format if it scored higher than a previous match
if (score > score_max) {
score_max = score;
fmt = fmt1;
}
else if (score == score_max) {
fmt = NULL;
}
}
}
// Didn't find a suitable format, so bail
if (!fmt) {
err = AVERROR_NOFMT;
goto fail;
}
// And finally, attempt to associate an input stream with the file
err = FFmpegLibsInst->av_open_input_stream(ic_ptr, pb, filename, fmt, NULL);
if (err) {
goto fail;
}
// Done with the probe buffer
FFmpegLibsInst->av_freep(&pd.buf);
return 0;
fail:
if (pd.buf) {
FFmpegLibsInst->av_freep(&pd.buf);
}
if (pb) {
FFmpegLibsInst->url_fclose(pb);
}
*ic_ptr = NULL;
return err;
}
/*******************************************************/
class FFmpegNotFoundDialog;
//----------------------------------------------------------------------------
// FindFFmpegDialog
//----------------------------------------------------------------------------
#define ID_FFMPEG_BROWSE 5000
#define ID_FFMPEG_DLOAD 5001
/// Allows user to locate libav* libraries
class FindFFmpegDialog : public wxDialog
{
public:
FindFFmpegDialog(wxWindow *parent, wxString path, wxString name, wxString type)
: wxDialog(parent, wxID_ANY, wxString(_("Locate FFmpeg")))
{
ShuttleGui S(this, eIsCreating);
mPath = path;
mName = name;
mType = type;
mLibPath.Assign(mPath, mName);
PopulateOrExchange(S);
}
void PopulateOrExchange(ShuttleGui & S)
{
wxString text;
S.SetBorder(10);
S.StartVerticalLay(true);
{
text.Printf(_("Audacity needs the file %s to import and export audio via FFmpeg."), mName.c_str());
S.AddTitle(text);
S.SetBorder(3);
S.StartHorizontalLay(wxALIGN_LEFT, true);
{
text.Printf(_("Location of %s:"), mName.c_str());
S.AddTitle(text);
}
S.EndHorizontalLay();
S.StartMultiColumn(2, wxEXPAND);
S.SetStretchyCol(0);
{
if (mLibPath.GetFullPath().IsEmpty()) {
text.Printf(_("To find %s, click here -->"), mName.c_str());
mPathText = S.AddTextBox(wxT(""), text, 0);
}
else {
mPathText = S.AddTextBox(wxT(""), mLibPath.GetFullPath(), 0);
}
S.Id(ID_FFMPEG_BROWSE).AddButton(_("Browse..."), wxALIGN_RIGHT);
S.AddVariableText(_("To get a free copy of FFmpeg, click here -->"), true);
S.Id(ID_FFMPEG_DLOAD).AddButton(_("Download"), wxALIGN_RIGHT);
}
S.EndMultiColumn();
S.AddStandardButtons();
}
S.EndVerticalLay();
Layout();
Fit();
SetMinSize(GetSize());
Center();
return;
}
void OnBrowse(wxCommandEvent & event)
{
wxString question;
/* 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. */
question.Printf(_("Where is %s?"), mName.c_str());
wxString path = FileSelector(question,
mLibPath.GetPath(),
mLibPath.GetName(),
wxT(""),
mType,
wxFD_OPEN | wxRESIZE_BORDER,
this);
if (!path.IsEmpty()) {
mLibPath = path;
mPathText->SetValue(path);
}
}
void OnDownload(wxCommandEvent & event)
{
wxString page = wxT("http://www.audacityteam.org/manual/index.php?title=FAQ:Installation_and_Plug-Ins%23installffmpeg");
::OpenInDefaultBrowser(page);
}
wxString GetLibPath()
{
return mLibPath.GetFullPath();
}
private:
wxFileName mLibPath;
wxString mPath;
wxString mName;
wxString mType;
wxTextCtrl *mPathText;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(FindFFmpegDialog, wxDialog)
EVT_BUTTON(ID_FFMPEG_BROWSE, FindFFmpegDialog::OnBrowse)
EVT_BUTTON(ID_FFMPEG_DLOAD, FindFFmpegDialog::OnDownload)
END_EVENT_TABLE()
//----------------------------------------------------------------------------
// FFmpegNotFoundDialog
//----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(FFmpegNotFoundDialog, wxDialog)
EVT_BUTTON(wxID_OK, FFmpegNotFoundDialog::OnOk)
END_EVENT_TABLE()
//----------------------------------------------------------------------------
// FFmpegLibs
//----------------------------------------------------------------------------
FFmpegLibs::FFmpegLibs()
{
mLibsLoaded = false;
refcount = 1;
avformat = avcodec = avutil = NULL;
if (gPrefs) {
mLibAVFormatPath = gPrefs->Read(wxT("/FFmpeg/FFmpegLibPath"), wxT(""));
}
}
FFmpegLibs::~FFmpegLibs()
{
FreeLibs();
};
bool FFmpegLibs::FindLibs(wxWindow *parent)
{
wxString path;
wxString name;
wxLogMessage(wxT("Looking for FFmpeg libraries..."));
if (!mLibAVFormatPath.IsEmpty()) {
wxLogMessage(wxT("mLibAVFormatPath is not empty, = %s"),mLibAVFormatPath.c_str());
wxFileName fn = mLibAVFormatPath;
path = fn.GetPath();
name = fn.GetFullName();
}
else {
path = GetLibAVFormatPath();
name = GetLibAVFormatName();
wxLogMessage(wxT("mLibAVFormatPath is empty, starting with path '%s', name '%s'"),path.c_str(),name.c_str());
}
FindFFmpegDialog fd(parent,
path,
name,
GetLibraryTypeString());
if (fd.ShowModal() == wxID_CANCEL) {
wxLogMessage(wxT("User canceled the dialog. Failed to find libraries."));
return false;
}
path = fd.GetLibPath();
wxLogMessage(wxT("User-specified path = %s"),path.c_str());
if (!::wxFileExists(path)) {
wxLogMessage(wxT("User-specified file doesn't exist! Failed to find libraries."));
return false;
}
wxLogMessage(wxT("User-specified file exists. Success."));
mLibAVFormatPath = path;
gPrefs->Write(wxT("/FFmpeg/FFmpegLibPath"), mLibAVFormatPath);
return true;
}
bool FFmpegLibs::LoadLibs(wxWindow *parent, bool showerr)
{
wxLogMessage(wxT("Trying to load FFmpeg libraries"));
if (ValidLibsLoaded()) {
wxLogMessage(wxT("Libraries already loaded - freeing"));
FreeLibs();
}
// First try loading it from a previously located path
if (!mLibAVFormatPath.IsEmpty()) {
wxLogMessage(wxT("mLibAVFormatPath is not empty, = %s. Loading from it."),mLibAVFormatPath.c_str());
mLibsLoaded = InitLibs(mLibAVFormatPath,showerr);
}
// If not successful, try loading it from default path
if (!mLibsLoaded && !GetLibAVFormatPath().IsEmpty()) {
wxFileName fn(GetLibAVFormatPath(), GetLibAVFormatName());
wxString path = fn.GetFullPath();
wxLogMessage(wxT("Trying to load from default path %s."),path.c_str());
mLibsLoaded = InitLibs(path,showerr);
if (mLibsLoaded) {
mLibAVFormatPath = path;
}
}
// If not successful, try loading using system search paths
if (!ValidLibsLoaded()) {
wxString path = GetLibAVFormatName();
wxLogMessage(wxT("Trying to load from system paths. File name is %s"),path.c_str());
mLibsLoaded = InitLibs(path,showerr);
if (mLibsLoaded) {
mLibAVFormatPath = path;
}
}
// If libraries aren't loaded - nag user about that
/*
if (!ValidLibsLoaded())
{
wxLogMessage(wxT("Failed to load libraries altogether."));
int dontShowDlg;
FFmpegNotFoundDialog *dlg;
gPrefs->Read(wxT("/FFmpeg/NotFoundDontShow"),&dontShowDlg,0);
if ((dontShowDlg == 0) && (showerr))
{
dlg = new FFmpegNotFoundDialog(NULL);
dlg->ShowModal();
delete dlg;
}
}
*/
// Oh well, just give up
if (!ValidLibsLoaded()) {
if (showerr) wxMessageBox(_("Failed to find compatible FFmpeg libraries"));
return false;
}
wxLogMessage(wxT("Libraries loaded successfully!"));
return true;
}
bool FFmpegLibs::ValidLibsLoaded()
{
return mLibsLoaded;
}
bool FFmpegLibs::InitLibs(wxString libpath_format, bool showerr)
{
// Initially we don't know where are the avcodec and avutl libs
wxDynamicLibrary *codec = NULL;
wxDynamicLibrary *util = NULL;
wxFileName name(libpath_format);
wxLogWindow* mLogger = wxGetApp().mLogger;
bool gotError = false;
wxString syspath;
bool pathfix = false;
FreeLibs();
#if defined(__WXMSW__)
wxLogMessage(wxT("Looking up PATH..."));
// First take PATH environment variable (store it's content)
if (wxGetEnv(wxT("PATH"),&syspath))
{
wxLogMessage(wxT("PATH = %s"),syspath.c_str());
wxString fmtdirsc = wxPathOnly(libpath_format) + wxT(";");
wxString scfmtdir = wxT(";") + wxPathOnly(libpath_format);
wxString fmtdir = wxPathOnly(libpath_format);
wxLogMessage(wxT("Checking that %s is in PATH..."),fmtdir.c_str());
// If the directory, where libavformat is, is not in PATH - add it
if (!syspath.Contains(fmtdirsc) && !syspath.Contains(scfmtdir) && !syspath.Contains(fmtdir))
{
wxLogMessage(wxT("not in PATH!"));
if (syspath.Last() == wxT(';'))
{
wxLogMessage(wxT("Appending %s ..."),fmtdir.c_str());
syspath.Append(fmtdirsc);
}
else
{
wxLogMessage(wxT("Appending %s ..."),scfmtdir.c_str());
syspath.Append(scfmtdir);
}
if (wxSetEnv(wxT("PATH"),syspath.c_str()))
{
// Remember to change PATH back to normal after we're done
pathfix = true;
}
else
{
wxLogMessage(wxT("wxSetEnv(%s) failed."),syspath.c_str());
}
}
else
{
wxLogMessage(wxT("in PATH."));
}
}
else
{
wxLogMessage(wxT("PATH does not exist."));
}
#endif
//Load libavformat
avformat = new wxDynamicLibrary();
wxLogMessage(wxT("Loading avformat from %s"),libpath_format.c_str());
if (showerr)
mLogger->SetActiveTarget(NULL);
gotError = !avformat->Load(libpath_format, wxDL_LAZY);
if (showerr)
mLogger->SetActiveTarget(mLogger);
if (!gotError) {
if (avformat->HasSymbol(wxT("av_free"))) {
util = avformat;
}
if (avformat->HasSymbol(wxT("avcodec_init"))) {
codec = avformat;
}
}
if (!util) {
name.SetFullName(GetLibAVUtilName());
avutil = util = new wxDynamicLibrary();
wxLogMessage(wxT("Loading avutil from %s"),name.GetFullPath().c_str());
if (showerr)
mLogger->SetActiveTarget(NULL);
util->Load(name.GetFullPath(), wxDL_LAZY);
if (showerr)
mLogger->SetActiveTarget(mLogger);
}
if (!codec) {
name.SetFullName(GetLibAVCodecName());
avcodec = codec = new wxDynamicLibrary();
wxLogMessage(wxT("Loading avcodec from %s"),name.GetFullPath().c_str());
if (showerr)
mLogger->SetActiveTarget(NULL);
codec->Load(name.GetFullPath(), wxDL_LAZY);
if (showerr)
mLogger->SetActiveTarget(mLogger);
}
if (!avformat->IsLoaded()) {
if (showerr)
mLogger->SetActiveTarget(NULL);
gotError = !avformat->Load(libpath_format, wxDL_LAZY);
if (showerr)
mLogger->SetActiveTarget(mLogger);
}
//Return PATH to normal
if ( pathfix )
{
wxString oldpath = syspath.BeforeLast(wxT(';'));
wxLogMessage(wxT("Returning PATH to normal..."));
wxSetEnv(wxT("PATH"),oldpath.c_str());
}
if (gotError) {
wxLogMessage(wxT("Failed to load FFmpeg libs"));
FreeLibs();
return false;
}
wxLogMessage(wxT("Importing symbols..."));
INITDYN(avformat,av_register_all);
INITDYN(avformat,av_open_input_file);
INITDYN(avformat,av_find_stream_info);
INITDYN(avformat,av_read_frame);
INITDYN(avformat,av_seek_frame);
INITDYN(avformat,av_close_input_file);
INITDYN(avformat,av_index_search_timestamp);
INITDYN(avformat,av_write_header);
INITDYN(avformat,av_interleaved_write_frame);
INITDYN(avformat,av_write_frame);
INITDYN(avformat,av_iformat_next);
INITDYN(avformat,av_oformat_next);
INITDYN(avformat,av_set_parameters);
#if LIBAVFORMAT_VERSION_MAJOR < 53
INITDYN(avformat,register_protocol);
av_register_protocol = register_protocol;
#else
INITDYN(avformat,av_register_protocol);
#endif
INITDYN(avformat,url_open_protocol);
INITDYN(avformat,url_fdopen);
INITDYN(avformat,url_close);
INITDYN(avformat,url_fopen);
INITDYN(avformat,url_fseek);
INITDYN(avformat,url_fclose);
INITDYN(avformat,url_fsize);
INITDYN(avformat,av_new_stream);
INITDYN(avformat,av_alloc_format_context);
INITDYN(avformat,guess_format);
INITDYN(avformat,av_write_trailer);
INITDYN(avformat,av_codec_get_id);
INITDYN(avformat,av_codec_get_tag);
INITDYN(avformat,avformat_version);
INITDYN(avformat,av_open_input_file);
INITDYN(avformat,av_open_input_stream);
INITDYN(avformat,get_buffer);
INITDYN(avformat,match_ext);
#if FFMPEG_STABLE
INITDYN(avformat,av_init_packet);
#else
INITDYN(codec,av_init_packet);
INITDYN(codec,av_free_packet);
#endif
INITDYN(codec,avcodec_init);
INITDYN(codec,avcodec_find_encoder);
INITDYN(codec,avcodec_find_encoder_by_name);
INITDYN(codec,avcodec_find_decoder);
INITDYN(codec,avcodec_find_decoder_by_name);
INITDYN(codec,avcodec_string);
INITDYN(codec,avcodec_get_context_defaults);
INITDYN(codec,avcodec_alloc_context);
INITDYN(codec,avcodec_get_frame_defaults);
INITDYN(codec,avcodec_alloc_frame);
INITDYN(codec,avcodec_open);
INITDYN(codec,avcodec_decode_audio2);
INITDYN(codec,avcodec_encode_audio);
INITDYN(codec,avcodec_close);
INITDYN(codec,avcodec_register_all);
INITDYN(codec,avcodec_flush_buffers);
INITDYN(codec,av_get_bits_per_sample);
INITDYN(codec,av_get_bits_per_sample_format);
INITDYN(codec,avcodec_version);
INITDYN(codec,av_fast_realloc);
INITDYN(codec,av_codec_next);
INITDYN(util,av_free);
INITDYN(util,av_log_set_callback);
INITDYN(util,av_log_default_callback);
#if FFMPEG_STABLE
INITDYN(util,av_fifo_init);
INITDYN(util,av_fifo_read);
INITDYN(util,av_fifo_realloc);
#else
INITDYN(util,av_fifo_alloc);
INITDYN(util,av_fifo_generic_read);
INITDYN(util,av_fifo_realloc2);
#endif
INITDYN(util,av_fifo_free);
INITDYN(util,av_fifo_size);
INITDYN(util,av_malloc);
INITDYN(util,av_fifo_generic_write);
INITDYN(util,av_freep);
INITDYN(util,av_rescale_q);
INITDYN(util,av_strstart);
INITDYN(util,avutil_version);
//FFmpeg initialization
wxLogMessage(wxT("All symbols loaded successfully. Initializing the library."));
this->avcodec_init();
this->avcodec_register_all();
this->av_register_all();
wxLogMessage(wxT("Retrieving library version."));
int avcver = this->avcodec_version();
int avfver = this->avformat_version();
int avuver = this->avutil_version();
mAVCodecVersion = wxString::Format(wxT("%d.%d.%d"),avcver >> 16 & 0xFF, avcver >> 8 & 0xFF, avcver & 0xFF);
mAVFormatVersion = wxString::Format(wxT("%d.%d.%d"),avfver >> 16 & 0xFF, avfver >> 8 & 0xFF, avfver & 0xFF);
mAVUtilVersion = wxString::Format(wxT("%d.%d.%d"),avuver >> 16 & 0xFF, avuver >> 8 & 0xFF, avuver & 0xFF);
wxLogMessage(wxT("AVCodec version 0x%06x - %s (built against 0x%06x - %s)"),avcver,mAVCodecVersion.c_str(),LIBAVCODEC_VERSION_INT,wxString::FromUTF8(AV_STRINGIFY(LIBAVCODEC_VERSION)).c_str());
wxLogMessage(wxT("AVFormat version 0x%06x - %s (built against 0x%06x - %s)"),avfver,mAVFormatVersion.c_str(),LIBAVFORMAT_VERSION_INT,wxString::FromUTF8(AV_STRINGIFY(LIBAVFORMAT_VERSION)).c_str());
wxLogMessage(wxT("AVUtil version 0x%06x - %s (built against 0x%06x - %s)"),avuver,mAVUtilVersion.c_str(),LIBAVUTIL_VERSION_INT,wxString::FromUTF8(AV_STRINGIFY(LIBAVUTIL_VERSION)).c_str());
int avcverdiff = (avcver >> 16 & 0xFF) - int(LIBAVCODEC_VERSION_MAJOR);
int avfverdiff = (avfver >> 16 & 0xFF) - int(LIBAVFORMAT_VERSION_MAJOR);
int avuverdiff = (avuver >> 16 & 0xFF) - int(LIBAVUTIL_VERSION_MAJOR);
wxLogMessage(wxT("AVCodec version mismatch is %d"),avcverdiff);
wxLogMessage(wxT("AVFormat version mismatch is %d"),avfverdiff);
wxLogMessage(wxT("AVUtil version mismatch is %d"),avuverdiff);
//make sure that header and library major versions are the same
if (avcverdiff != 0 || avfverdiff != 0 || avuverdiff != 0)
{
wxLogMessage(wxT("Version mismatch! Libraries are unusable."));
return false;
}
av_register_protocol(&ufile_protocol);
return true;
}
void FFmpegLibs::FreeLibs()
{
if (avformat != NULL) {
delete avformat;
avformat = NULL;
}
if (avcodec != NULL) {
delete avcodec;
avcodec = NULL;
}
if (avutil != NULL) {
delete avutil;
avutil = NULL;
}
mLibsLoaded = false;
return;
}
#endif //USE_FFMPEG