Use scoped_holder in a handful of places

Originally committed to SVN as r6492.
This commit is contained in:
Thomas Goyne 2012-02-20 18:22:12 +00:00
parent b9ddf00ead
commit 17b0d83831
12 changed files with 125 additions and 250 deletions

View file

@ -119,25 +119,19 @@ struct COMObjectRetainer {
}; };
/// @brief RAII wrapper around Win32 HANDLE type /// @brief RAII wrapper around Win32 HANDLE type
struct Win32KernelHandle { struct Win32KernelHandle : public agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> {
/// HANDLE value being managed
HANDLE handle;
/// @brief Create with a managed handle /// @brief Create with a managed handle
/// @param handle Win32 handle to manage /// @param handle Win32 handle to manage
Win32KernelHandle(HANDLE handle = 0) Win32KernelHandle(HANDLE handle = 0)
: handle(handle) : scoped_holder(handle, CloseHandle)
{ {
} }
/// @brief Destructor, closes the managed handle Win32KernelHandle& operator=(HANDLE new_handle)
~Win32KernelHandle()
{ {
if (handle) CloseHandle(handle); scoped_holder::operator=(new_handle);
return *this;
} }
/// @brief Returns the managed handle
operator HANDLE () const { return handle; }
}; };
/// @class DirectSoundPlayer2Thread /// @class DirectSoundPlayer2Thread
@ -667,7 +661,7 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
start_frame = 0; start_frame = 0;
end_frame = 0; end_frame = 0;
thread_handle.handle = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0); thread_handle = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0);
if (!thread_handle) if (!thread_handle)
throw agi::AudioPlayerOpenError("Failed creating playback thread in DirectSoundPlayer2. This is bad.", 0); throw agi::AudioPlayerOpenError("Failed creating playback thread in DirectSoundPlayer2. This is bad.", 0);

View file

@ -53,52 +53,31 @@
#include "main.h" #include "main.h"
/// @brief Constructor /// @brief Constructor
/// @param filename /// @param filename The filename to open
/// FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(wxString filename) try
FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(wxString filename) : AudioSource(NULL, FFMS_DestroyAudioSource)
: AudioSource(NULL)
, COMInited(false)
{ {
#ifdef WIN32
HRESULT res;
res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(res))
COMInited = true;
else if (res != RPC_E_CHANGED_MODE)
throw agi::AudioProviderOpenError("COM initialization failure", 0);
#endif
// initialize ffmpegsource
// FIXME: CPU detection?
#if FFMS_VERSION >= ((2 << 24) | (14 << 16) | (0 << 8) | 0)
FFMS_Init(0, 1);
#else
FFMS_Init(0);
#endif
ErrInfo.Buffer = FFMSErrMsg; ErrInfo.Buffer = FFMSErrMsg;
ErrInfo.BufferSize = sizeof(FFMSErrMsg); ErrInfo.BufferSize = sizeof(FFMSErrMsg);
ErrInfo.ErrorType = FFMS_ERROR_SUCCESS; ErrInfo.ErrorType = FFMS_ERROR_SUCCESS;
ErrInfo.SubType = FFMS_ERROR_SUCCESS; ErrInfo.SubType = FFMS_ERROR_SUCCESS;
SetLogLevel(); SetLogLevel();
try { LoadAudio(filename);
LoadAudio(filename); }
} catch (...) { catch (wxString const& err) {
Close(); throw agi::AudioProviderOpenError(STD_STR(err), 0);
throw; }
} catch (const char *err) {
throw agi::AudioProviderOpenError(err, 0);
} }
/// @brief Load audio file
/// @param filename
///
void FFmpegSourceAudioProvider::LoadAudio(wxString filename) { void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
wxString FileNameShort = wxFileName(filename).GetShortPath(); wxString FileNameShort = wxFileName(filename).GetShortPath();
FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo); FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo);
if (Indexer == NULL) { if (!Indexer)
throw agi::FileNotFoundError(ErrInfo.Buffer); throw agi::FileNotFoundError(ErrInfo.Buffer);
}
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO); std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
if (TrackList.size() <= 0) if (TrackList.size() <= 0)
@ -118,37 +97,25 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
wxString CacheName = GetCacheFilename(filename); wxString CacheName = GetCacheFilename(filename);
// try to read index // try to read index
FFMS_Index *Index = NULL; agi::scoped_holder<FFMS_Index*, void (FFMS_CC*)(FFMS_Index*)>
Index = FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo); Index(FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo), FFMS_DestroyIndex);
bool IndexIsValid = false;
if (Index != NULL) { if (Index && !FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo))
if (FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo)) { Index = NULL;
FFMS_DestroyIndex(Index);
Index = NULL;
}
else
IndexIsValid = true;
}
// index valid but track number still not set? // index valid but track number still not set?
if (IndexIsValid) { if (Index) {
// track number not set? just grab the first track // track number not set? just grab the first track
if (TrackNumber < 0) if (TrackNumber < 0)
TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo); TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo);
if (TrackNumber < 0) { if (TrackNumber < 0)
FFMS_DestroyIndex(Index);
Index = NULL;
throw agi::AudioDataNotFoundError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer, 0); throw agi::AudioDataNotFoundError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer, 0);
}
// index is valid and track number is now set, // index is valid and track number is now set,
// but do we have indexing info for the desired audio track? // but do we have indexing info for the desired audio track?
FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber); FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
if (FFMS_GetNumFrames(TempTrackData) <= 0) { if (FFMS_GetNumFrames(TempTrackData) <= 0)
IndexIsValid = false;
FFMS_DestroyIndex(Index);
Index = NULL; Index = NULL;
}
} }
// no valid index exists and the file only has one audio track, index it // no valid index exists and the file only has one audio track, index it
else if (TrackNumber < 0) else if (TrackNumber < 0)
@ -156,19 +123,14 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
// else: do nothing (keep track mask as it is) // else: do nothing (keep track mask as it is)
// moment of truth // moment of truth
if (!IndexIsValid) { if (!Index) {
int TrackMask; int TrackMask;
if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL) if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL)
TrackMask = FFMS_TRACKMASK_ALL; TrackMask = FFMS_TRACKMASK_ALL;
else else
TrackMask = (1 << TrackNumber); TrackMask = (1 << TrackNumber);
try { Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
}
catch (wxString const& err) {
throw agi::AudioProviderOpenError(STD_STR(err), 0);
}
// if tracknumber still isn't set we need to set it now // if tracknumber still isn't set we need to set it now
if (TrackNumber == FFMS_TRACKMASK_ALL) if (TrackNumber == FFMS_TRACKMASK_ALL)
@ -185,11 +147,8 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
#else #else
AudioSource = FFMS_CreateAudioSource(FileNameShort.utf8_str(), TrackNumber, Index, &ErrInfo); AudioSource = FFMS_CreateAudioSource(FileNameShort.utf8_str(), TrackNumber, Index, &ErrInfo);
#endif #endif
FFMS_DestroyIndex(Index); if (!AudioSource)
Index = NULL; throw agi::AudioProviderOpenError(std::string("Failed to open audio track: ") + ErrInfo.Buffer, 0);
if (!AudioSource) {
throw agi::AudioProviderOpenError(std::string("Failed to open audio track: %s") + ErrInfo.Buffer, 0);
}
const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource); const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource);
@ -211,27 +170,6 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
} }
} }
/// @brief Destructor
///
FFmpegSourceAudioProvider::~FFmpegSourceAudioProvider() {
Close();
}
/// @brief Clean up
///
void FFmpegSourceAudioProvider::Close() {
if (AudioSource) FFMS_DestroyAudioSource(AudioSource);
#ifdef WIN32
if (COMInited)
CoUninitialize();
#endif
}
/// @brief Get audio
/// @param Buf
/// @param Start
/// @param Count
///
void FFmpegSourceAudioProvider::GetAudio(void *Buf, int64_t Start, int64_t Count) const { void FFmpegSourceAudioProvider::GetAudio(void *Buf, int64_t Start, int64_t Count) const {
if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) { if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) {
throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer); throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer);

View file

@ -42,19 +42,16 @@
/// @class FFmpegSourceAudioProvider /// @class FFmpegSourceAudioProvider
/// @brief Implements audio loading with the FFMS library. /// @brief Implements audio loading with the FFMS library.
class FFmpegSourceAudioProvider : public AudioProvider, FFmpegSourceProvider { class FFmpegSourceAudioProvider : public AudioProvider, FFmpegSourceProvider {
private: /// audio source object
FFMS_AudioSource *AudioSource; ///< audio source object agi::scoped_holder<FFMS_AudioSource*, void (FFMS_CC *)(FFMS_AudioSource*)> AudioSource;
bool COMInited; ///< COM initialization state
mutable char FFMSErrMsg[1024]; ///< FFMS error message mutable char FFMSErrMsg[1024]; ///< FFMS error message
mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
void Close();
void LoadAudio(wxString filename); void LoadAudio(wxString filename);
public: public:
FFmpegSourceAudioProvider(wxString filename); FFmpegSourceAudioProvider(wxString filename);
virtual ~FFmpegSourceAudioProvider();
/// @brief Checks sample endianness /// @brief Checks sample endianness
/// @return Returns true. /// @return Returns true.

View file

@ -64,8 +64,10 @@
/// @param filename /// @param filename
/// ///
PCMAudioProvider::PCMAudioProvider(const wxString &filename) PCMAudioProvider::PCMAudioProvider(const wxString &filename)
{
#ifdef _WIN32 #ifdef _WIN32
: file_handle(0, CloseHandle)
, file_mapping(0, CloseHandle)
{
file_handle = CreateFile( file_handle = CreateFile(
filename.c_str(), filename.c_str(),
FILE_READ_DATA, FILE_READ_DATA,
@ -75,15 +77,13 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,
0); 0);
if (file_handle == INVALID_HANDLE_VALUE) { if (file_handle == INVALID_HANDLE_VALUE)
throw agi::FileNotFoundError(STD_STR(filename)); throw agi::FileNotFoundError(STD_STR(filename));
}
LARGE_INTEGER li_file_size = {0}; LARGE_INTEGER li_file_size = {0};
if (!GetFileSizeEx(file_handle, &li_file_size)) { if (!GetFileSizeEx(file_handle, &li_file_size))
CloseHandle(file_handle);
throw agi::AudioProviderOpenError("Failed getting file size", 0); throw agi::AudioProviderOpenError("Failed getting file size", 0);
}
file_size = li_file_size.QuadPart; file_size = li_file_size.QuadPart;
file_mapping = CreateFileMapping( file_mapping = CreateFileMapping(
@ -93,20 +93,16 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
0, 0, 0, 0,
0); 0);
if (file_mapping == 0) { if (file_mapping == 0)
CloseHandle(file_handle);
throw agi::AudioProviderOpenError("Failed creating file mapping", 0); throw agi::AudioProviderOpenError("Failed creating file mapping", 0);
}
current_mapping = 0; current_mapping = 0;
#else #else
: file_handle(open(filename.mb_str(*wxConvFileName), O_RDONLY), close)
file_handle = open(filename.mb_str(*wxConvFileName), O_RDONLY); {
if (file_handle == -1)
if (file_handle == -1) {
throw agi::FileNotFoundError(STD_STR(filename)); throw agi::FileNotFoundError(STD_STR(filename));
}
struct stat filestats; struct stat filestats;
memset(&filestats, 0, sizeof(filestats)); memset(&filestats, 0, sizeof(filestats));
@ -125,18 +121,11 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
PCMAudioProvider::~PCMAudioProvider() PCMAudioProvider::~PCMAudioProvider()
{ {
#ifdef _WIN32 #ifdef _WIN32
if (current_mapping) { if (current_mapping)
UnmapViewOfFile(current_mapping); UnmapViewOfFile(current_mapping);
}
CloseHandle(file_mapping);
CloseHandle(file_handle);
#else #else
if (current_mapping) { if (current_mapping)
munmap(current_mapping, mapping_length); munmap(current_mapping, mapping_length);
}
close(file_handle);
#endif #endif
} }

View file

@ -47,6 +47,8 @@
#include "include/aegisub/audio_provider.h" #include "include/aegisub/audio_provider.h"
#include <libaegisub/scoped_ptr.h>
/// DOCME /// DOCME
/// @class PCMAudioProvider /// @class PCMAudioProvider
@ -54,14 +56,12 @@
/// ///
/// DOCME /// DOCME
class PCMAudioProvider : public AudioProvider { class PCMAudioProvider : public AudioProvider {
private:
#ifdef _WIN32 #ifdef _WIN32
/// DOCME
agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_handle;
/// DOCME /// DOCME
HANDLE file_handle; agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_mapping;
/// DOCME
HANDLE file_mapping;
/// DOCME /// DOCME
mutable void *current_mapping; mutable void *current_mapping;
@ -72,7 +72,7 @@ private:
/// DOCME /// DOCME
mutable size_t mapping_length; mutable size_t mapping_length;
#else #else
int file_handle; agi::scoped_holder<int, int(*)(int)> file_handle;
mutable void *current_mapping; mutable void *current_mapping;
mutable off_t mapping_start; mutable off_t mapping_start;
mutable size_t mapping_length; mutable size_t mapping_length;

View file

@ -271,28 +271,22 @@ typedef BOOL (WINAPI * PGetUserPreferredUILanguages)(DWORD dwFlags, PULONG pulNu
// Try using Win 6+ functions if available // Try using Win 6+ functions if available
static wxString GetUILanguage() static wxString GetUILanguage()
{ {
wxString res; agi::scoped_holder<HMODULE, BOOL (__stdcall *)(HMODULE)> kernel32(LoadLibraryW(L"kernel32.dll"), FreeLibrary);
if (!kernel32) return "";
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
if (!kernel32) return res;
PGetUserPreferredUILanguages gupuil = (PGetUserPreferredUILanguages)GetProcAddress(kernel32, "GetUserPreferredUILanguages"); PGetUserPreferredUILanguages gupuil = (PGetUserPreferredUILanguages)GetProcAddress(kernel32, "GetUserPreferredUILanguages");
if (!gupuil) goto error; if (!gupuil) return "";
ULONG numlang = 0, output_len = 0; ULONG numlang = 0, output_len = 0;
if (gupuil(MUI_LANGUAGE_NAME, &numlang, 0, &output_len) == TRUE && output_len) if (gupuil(MUI_LANGUAGE_NAME, &numlang, 0, &output_len) != TRUE || !output_len)
{ return "";
std::vector<wchar_t> output(output_len);
if (gupuil(MUI_LANGUAGE_NAME, &numlang, &output[0], &output_len) && numlang >= 1)
{
// We got at least one language, just treat it as the only, and a null-terminated string
res = &output[0];
}
}
error: std::vector<wchar_t> output(output_len);
FreeModule(kernel32); if (!gupuil(MUI_LANGUAGE_NAME, &numlang, &output[0], &output_len) || numlang < 1)
return res; return "";
// We got at least one language, just treat it as the only, and a null-terminated string
return &output[0];
} }
static wxString GetSystemLanguage() static wxString GetSystemLanguage()
{ {

View file

@ -56,6 +56,33 @@
#include "md5.h" #include "md5.h"
#include "standard_paths.h" #include "standard_paths.h"
#ifdef WIN32
static void deinit_com(bool) {
CoUninitialize();
}
#else
static void deinit_com(bool) { }
#endif
FFmpegSourceProvider::FFmpegSourceProvider()
: COMInited(false, deinit_com)
{
#ifdef WIN32
HRESULT res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(res))
COMInited = true;
else if (res != RPC_E_CHANGED_MODE)
throw "COM initialization failure";
#endif
// initialize ffmpegsource
// FIXME: CPU detection?
#if FFMS_VERSION >= ((2 << 24) | (14 << 16) | (0 << 8) | 0)
FFMS_Init(0, 1);
#else
FFMS_Init(0);
#endif
}
wxMutex FFmpegSourceProvider::CleaningInProgress; wxMutex FFmpegSourceProvider::CleaningInProgress;

View file

@ -45,6 +45,8 @@
#include <ffms.h> #include <ffms.h>
#include <libaegisub/scoped_ptr.h>
/// Index all tracks /// Index all tracks
#define FFMS_TRACKMASK_ALL -1 #define FFMS_TRACKMASK_ALL -1
/// Index no tracks /// Index no tracks
@ -54,7 +56,11 @@
/// @brief Base class for FFMS2 source providers; contains common functions etc /// @brief Base class for FFMS2 source providers; contains common functions etc
class FFmpegSourceProvider { class FFmpegSourceProvider {
friend class FFmpegSourceCacheCleaner; friend class FFmpegSourceCacheCleaner;
agi::scoped_holder<bool> COMInited; ///< COM initialization state
public: public:
FFmpegSourceProvider();
/// Logging level constants from avutil/log.h /// Logging level constants from avutil/log.h
enum FFMS_LogLevel { enum FFMS_LogLevel {
/// nothing printed /// nothing printed
@ -85,7 +91,6 @@ public:
/// @class FFmpegSourceCacheCleaner /// @class FFmpegSourceCacheCleaner
/// @brief Implements index cache cleaning functionality for the FFMS2 providers /// @brief Implements index cache cleaning functionality for the FFMS2 providers
class FFmpegSourceCacheCleaner : public wxThread { class FFmpegSourceCacheCleaner : public wxThread {
private:
FFmpegSourceProvider *parent; FFmpegSourceProvider *parent;
public: public:
@ -96,4 +101,3 @@ public:
}; };
#endif /* WITH_FFMS2 */ #endif /* WITH_FFMS2 */

View file

@ -124,7 +124,7 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
bold; bold;
int slant = italic ? 110 : 0; int slant = italic ? 110 : 0;
scoped<FcPattern*> pat(FcPatternCreate(), FcPatternDestroy); agi::scoped_holder<FcPattern*> pat(FcPatternCreate(), FcPatternDestroy);
if (!pat) return ret; if (!pat) return ret;
int family_cnt = add_families(pat, family); int family_cnt = add_families(pat, family);
@ -138,11 +138,11 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
if (!FcConfigSubstitute(config, pat, FcMatchPattern)) return ret; if (!FcConfigSubstitute(config, pat, FcMatchPattern)) return ret;
FcResult result; FcResult result;
scoped<FcFontSet*> fsorted(FcFontSort(config, pat, true, NULL, &result), FcFontSetDestroy); agi::scoped_holder<FcFontSet*> fsorted(FcFontSort(config, pat, true, NULL, &result), FcFontSetDestroy);
scoped<FcFontSet*> ffullname(MatchFullname(family.c_str(), weight, slant), FcFontSetDestroy); agi::scoped_holder<FcFontSet*> ffullname(MatchFullname(family.c_str(), weight, slant), FcFontSetDestroy);
if (!fsorted || !ffullname) return ret; if (!fsorted || !ffullname) return ret;
scoped<FcFontSet*> fset(FcFontSetCreate(), FcFontSetDestroy); agi::scoped_holder<FcFontSet*> fset(FcFontSetCreate(), FcFontSetDestroy);
for (int cur_font = 0; cur_font < ffullname->nfont; ++cur_font) { for (int cur_font = 0; cur_font < ffullname->nfont; ++cur_font) {
FcPattern *curp = ffullname->fonts[cur_font]; FcPattern *curp = ffullname->fonts[cur_font];
FcPatternReference(curp); FcPatternReference(curp);
@ -169,7 +169,7 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
for (; family_cnt > 1; --family_cnt) for (; family_cnt > 1; --family_cnt)
FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
scoped<FcPattern*> rpat(FcFontRenderPrepare(config, pat, fset->fonts[cur_font]), FcPatternDestroy); agi::scoped_holder<FcPattern*> rpat(FcFontRenderPrepare(config, pat, fset->fonts[cur_font]), FcPatternDestroy);
if (!rpat) return ret; if (!rpat) return ret;
FcChar8 *r_family; FcChar8 *r_family;

View file

@ -25,23 +25,15 @@
#include "font_file_lister.h" #include "font_file_lister.h"
#include <libaegisub/scoped_ptr.h>
typedef struct _FcConfig FcConfig; typedef struct _FcConfig FcConfig;
typedef struct _FcFontSet FcFontSet; typedef struct _FcFontSet FcFontSet;
/// @class FontConfigFontFileLister /// @class FontConfigFontFileLister
/// @brief fontconfig powered font lister /// @brief fontconfig powered font lister
class FontConfigFontFileLister : public FontFileLister { class FontConfigFontFileLister : public FontFileLister {
template<typename T> class scoped { agi::scoped_holder<FcConfig*> config;
T data;
void (*destructor)(T);
public:
scoped(T data, void (*destructor)(T)) : data(data), destructor(destructor) { }
~scoped() { if (data) destructor(data); }
operator T() { return data; }
T operator->() { return data; }
};
scoped<FcConfig*> config;
/// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans") /// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans")
/// @param family font fullname /// @param family font fullname

View file

@ -57,33 +57,15 @@
#include "video_context.h" #include "video_context.h"
#include "video_provider_ffmpegsource.h" #include "video_provider_ffmpegsource.h"
/// @brief Constructor /// @brief Constructor
/// @param filename The filename to open /// @param filename The filename to open
FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename) FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename) try
: VideoSource(NULL) : VideoSource(NULL, FFMS_DestroyVideoSource)
, VideoInfo(NULL) , VideoInfo(NULL)
, Width(-1) , Width(-1)
, Height(-1) , Height(-1)
, FrameNumber(-1) , FrameNumber(-1)
, COMInited(false)
{ {
#ifdef WIN32
HRESULT res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(res))
COMInited = true;
else if (res != RPC_E_CHANGED_MODE)
throw VideoOpenError("COM initialization failure");
#endif
// initialize ffmpegsource
// FIXME: CPU detection?
#if FFMS_VERSION >= ((2 << 24) | (14 << 16) | (0 << 8) | 0)
FFMS_Init(0, 1);
#else
FFMS_Init(0);
#endif
ErrInfo.Buffer = FFMSErrMsg; ErrInfo.Buffer = FFMSErrMsg;
ErrInfo.BufferSize = sizeof(FFMSErrMsg); ErrInfo.BufferSize = sizeof(FFMSErrMsg);
ErrInfo.ErrorType = FFMS_ERROR_SUCCESS; ErrInfo.ErrorType = FFMS_ERROR_SUCCESS;
@ -92,25 +74,14 @@ FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename)
SetLogLevel(); SetLogLevel();
// and here we go // and here we go
try { LoadVideo(filename);
LoadVideo(filename);
}
catch (wxString const& err) {
Close();
throw VideoOpenError(STD_STR(err));
}
catch (...) {
Close();
throw;
}
} }
catch (wxString const& err) {
throw VideoOpenError(STD_STR(err));
/// @brief Destructor }
FFmpegSourceVideoProvider::~FFmpegSourceVideoProvider() { catch (const char * err) {
Close(); throw VideoOpenError(err);
} }
/// @brief Opens video /// @brief Opens video
/// @param filename The filename to open /// @param filename The filename to open
@ -118,9 +89,8 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
wxString FileNameShort = wxFileName(filename).GetShortPath(); wxString FileNameShort = wxFileName(filename).GetShortPath();
FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo); FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo);
if (Indexer == NULL) { if (!Indexer)
throw agi::FileNotFoundError(ErrInfo.Buffer); throw agi::FileNotFoundError(ErrInfo.Buffer);
}
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_VIDEO); std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_VIDEO);
if (TrackList.size() <= 0) if (TrackList.size() <= 0)
@ -140,40 +110,26 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
wxString CacheName = GetCacheFilename(filename); wxString CacheName = GetCacheFilename(filename);
// try to read index // try to read index
FFMS_Index *Index = NULL; agi::scoped_holder<FFMS_Index*, void (FFMS_CC*)(FFMS_Index*)>
Index = FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo); Index(FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo), FFMS_DestroyIndex);
bool IndexIsValid = false;
if (Index != NULL) { if (Index && !FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo))
if (FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo)) { Index = NULL;
FFMS_DestroyIndex(Index);
Index = NULL;
}
else
IndexIsValid = true;
}
// time to examine the index and check if the track we want is indexed // time to examine the index and check if the track we want is indexed
// technically this isn't really needed since all video tracks should always be indexed, // technically this isn't really needed since all video tracks should always be indexed,
// but a bit of sanity checking never hurt anyone // but a bit of sanity checking never hurt anyone
if (IndexIsValid && TrackNumber >= 0) { if (Index && TrackNumber >= 0) {
FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber); FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
if (FFMS_GetNumFrames(TempTrackData) <= 0) { if (FFMS_GetNumFrames(TempTrackData) <= 0)
IndexIsValid = false;
FFMS_DestroyIndex(Index);
Index = NULL; Index = NULL;
}
} }
// moment of truth // moment of truth
if (!IndexIsValid) { if (!Index) {
int TrackMask = OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() ? FFMS_TRACKMASK_ALL : FFMS_TRACKMASK_NONE; int TrackMask = OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() ? FFMS_TRACKMASK_ALL : FFMS_TRACKMASK_NONE;
try { // ignore audio decoding errors here, we don't care right now
// ignore audio decoding errors here, we don't care right now Index = DoIndexing(Indexer, CacheName, TrackMask, FFMS_IEH_IGNORE);
Index = DoIndexing(Indexer, CacheName, TrackMask, FFMS_IEH_IGNORE);
}
catch (wxString err) {
throw VideoOpenError(STD_STR(err));
}
} }
// update access time of index file so it won't get cleaned away // update access time of index file so it won't get cleaned away
@ -188,11 +144,8 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
if (TrackNumber < 0) { if (TrackNumber < 0) {
// just grab the first track // just grab the first track
TrackNumber = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_VIDEO, &ErrInfo); TrackNumber = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_VIDEO, &ErrInfo);
if (TrackNumber < 0) { if (TrackNumber < 0)
FFMS_DestroyIndex(Index);
Index = NULL;
throw VideoNotSupported(std::string("Couldn't find any video tracks: ") + ErrInfo.Buffer); throw VideoNotSupported(std::string("Couldn't find any video tracks: ") + ErrInfo.Buffer);
}
} }
// set thread count // set thread count
@ -207,11 +160,8 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
SeekMode = FFMS_SEEK_NORMAL; SeekMode = FFMS_SEEK_NORMAL;
VideoSource = FFMS_CreateVideoSource(FileNameShort.utf8_str(), TrackNumber, Index, Threads, SeekMode, &ErrInfo); VideoSource = FFMS_CreateVideoSource(FileNameShort.utf8_str(), TrackNumber, Index, Threads, SeekMode, &ErrInfo);
FFMS_DestroyIndex(Index); if (!VideoSource)
Index = NULL;
if (VideoSource == NULL) {
throw VideoOpenError(std::string("Failed to open video track: ") + ErrInfo.Buffer); throw VideoOpenError(std::string("Failed to open video track: ") + ErrInfo.Buffer);
}
// load video properties // load video properties
VideoInfo = FFMS_GetVideoProperties(VideoSource); VideoInfo = FFMS_GetVideoProperties(VideoSource);
@ -274,14 +224,6 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
FrameNumber = 0; FrameNumber = 0;
} }
void FFmpegSourceVideoProvider::Close() {
if (VideoSource) FFMS_DestroyVideoSource(VideoSource);
#ifdef WIN32
if (COMInited)
CoUninitialize();
#endif
}
const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int n) { const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int n) {
FrameNumber = mid(0, n, GetFrameCount() - 1); FrameNumber = mid(0, n, GetFrameCount() - 1);

View file

@ -46,7 +46,8 @@
/// @class FFmpegSourceVideoProvider /// @class FFmpegSourceVideoProvider
/// @brief Implements video loading through the FFMS library. /// @brief Implements video loading through the FFMS library.
class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider { class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
FFMS_VideoSource *VideoSource; ///< video source object /// video source object
agi::scoped_holder<FFMS_VideoSource*, void (FFMS_CC*)(FFMS_VideoSource*)> VideoSource;
const FFMS_VideoProperties *VideoInfo; ///< video properties const FFMS_VideoProperties *VideoInfo; ///< video properties
int Width; ///< width in pixels int Width; ///< width in pixels
@ -54,7 +55,6 @@ class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
int FrameNumber; ///< current framenumber int FrameNumber; ///< current framenumber
std::vector<int> KeyFramesList; ///< list of keyframes std::vector<int> KeyFramesList; ///< list of keyframes
agi::vfr::Framerate Timecodes; ///< vfr object agi::vfr::Framerate Timecodes; ///< vfr object
bool COMInited; ///< COM initialization state
wxString ColorSpace; ///< Colorspace name wxString ColorSpace; ///< Colorspace name
AegiVideoFrame CurFrame; ///< current video frame AegiVideoFrame CurFrame; ///< current video frame
@ -63,11 +63,9 @@ class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
void LoadVideo(wxString filename); void LoadVideo(wxString filename);
void Close();
public: public:
FFmpegSourceVideoProvider(wxString filename); FFmpegSourceVideoProvider(wxString filename);
~FFmpegSourceVideoProvider();
const AegiVideoFrame GetFrame(int n); const AegiVideoFrame GetFrame(int n);