forked from mia/Aegisub
Use scoped_holder in a handful of places
Originally committed to SVN as r6492.
This commit is contained in:
parent
b9ddf00ead
commit
17b0d83831
12 changed files with 125 additions and 250 deletions
|
@ -119,25 +119,19 @@ struct COMObjectRetainer {
|
|||
};
|
||||
|
||||
/// @brief RAII wrapper around Win32 HANDLE type
|
||||
struct Win32KernelHandle {
|
||||
/// HANDLE value being managed
|
||||
HANDLE handle;
|
||||
|
||||
struct Win32KernelHandle : public agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> {
|
||||
/// @brief Create with a managed handle
|
||||
/// @param handle Win32 handle to manage
|
||||
Win32KernelHandle(HANDLE handle = 0)
|
||||
: handle(handle)
|
||||
: scoped_holder(handle, CloseHandle)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Destructor, closes the managed handle
|
||||
~Win32KernelHandle()
|
||||
Win32KernelHandle& operator=(HANDLE new_handle)
|
||||
{
|
||||
if (handle) CloseHandle(handle);
|
||||
scoped_holder::operator=(new_handle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Returns the managed handle
|
||||
operator HANDLE () const { return handle; }
|
||||
};
|
||||
|
||||
/// @class DirectSoundPlayer2Thread
|
||||
|
@ -667,7 +661,7 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
|
|||
start_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)
|
||||
throw agi::AudioPlayerOpenError("Failed creating playback thread in DirectSoundPlayer2. This is bad.", 0);
|
||||
|
|
|
@ -53,52 +53,31 @@
|
|||
#include "main.h"
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param filename
|
||||
///
|
||||
FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(wxString filename)
|
||||
: AudioSource(NULL)
|
||||
, COMInited(false)
|
||||
/// @param filename The filename to open
|
||||
FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(wxString filename) try
|
||||
: AudioSource(NULL, FFMS_DestroyAudioSource)
|
||||
{
|
||||
#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.BufferSize = sizeof(FFMSErrMsg);
|
||||
ErrInfo.ErrorType = FFMS_ERROR_SUCCESS;
|
||||
ErrInfo.SubType = FFMS_ERROR_SUCCESS;
|
||||
SetLogLevel();
|
||||
|
||||
try {
|
||||
LoadAudio(filename);
|
||||
} catch (...) {
|
||||
Close();
|
||||
throw;
|
||||
}
|
||||
LoadAudio(filename);
|
||||
}
|
||||
catch (wxString const& err) {
|
||||
throw agi::AudioProviderOpenError(STD_STR(err), 0);
|
||||
}
|
||||
catch (const char *err) {
|
||||
throw agi::AudioProviderOpenError(err, 0);
|
||||
}
|
||||
|
||||
/// @brief Load audio file
|
||||
/// @param filename
|
||||
///
|
||||
void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||
wxString FileNameShort = wxFileName(filename).GetShortPath();
|
||||
|
||||
FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo);
|
||||
if (Indexer == NULL) {
|
||||
if (!Indexer)
|
||||
throw agi::FileNotFoundError(ErrInfo.Buffer);
|
||||
}
|
||||
|
||||
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
|
||||
if (TrackList.size() <= 0)
|
||||
|
@ -118,37 +97,25 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
|||
wxString CacheName = GetCacheFilename(filename);
|
||||
|
||||
// try to read index
|
||||
FFMS_Index *Index = NULL;
|
||||
Index = FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo);
|
||||
bool IndexIsValid = false;
|
||||
if (Index != NULL) {
|
||||
if (FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo)) {
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
}
|
||||
else
|
||||
IndexIsValid = true;
|
||||
}
|
||||
agi::scoped_holder<FFMS_Index*, void (FFMS_CC*)(FFMS_Index*)>
|
||||
Index(FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo), FFMS_DestroyIndex);
|
||||
|
||||
if (Index && !FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo))
|
||||
Index = NULL;
|
||||
|
||||
// index valid but track number still not set?
|
||||
if (IndexIsValid) {
|
||||
if (Index) {
|
||||
// track number not set? just grab the first track
|
||||
if (TrackNumber < 0)
|
||||
TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo);
|
||||
if (TrackNumber < 0) {
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
if (TrackNumber < 0)
|
||||
throw agi::AudioDataNotFoundError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer, 0);
|
||||
}
|
||||
|
||||
// index is valid and track number is now set,
|
||||
// but do we have indexing info for the desired audio track?
|
||||
FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
|
||||
if (FFMS_GetNumFrames(TempTrackData) <= 0) {
|
||||
IndexIsValid = false;
|
||||
FFMS_DestroyIndex(Index);
|
||||
if (FFMS_GetNumFrames(TempTrackData) <= 0)
|
||||
Index = NULL;
|
||||
}
|
||||
}
|
||||
// no valid index exists and the file only has one audio track, index it
|
||||
else if (TrackNumber < 0)
|
||||
|
@ -156,19 +123,14 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
|||
// else: do nothing (keep track mask as it is)
|
||||
|
||||
// moment of truth
|
||||
if (!IndexIsValid) {
|
||||
if (!Index) {
|
||||
int TrackMask;
|
||||
if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL)
|
||||
TrackMask = FFMS_TRACKMASK_ALL;
|
||||
else
|
||||
TrackMask = (1 << TrackNumber);
|
||||
|
||||
try {
|
||||
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
|
||||
}
|
||||
catch (wxString const& err) {
|
||||
throw agi::AudioProviderOpenError(STD_STR(err), 0);
|
||||
}
|
||||
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
|
||||
|
||||
// if tracknumber still isn't set we need to set it now
|
||||
if (TrackNumber == FFMS_TRACKMASK_ALL)
|
||||
|
@ -185,12 +147,9 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
|||
#else
|
||||
AudioSource = FFMS_CreateAudioSource(FileNameShort.utf8_str(), TrackNumber, Index, &ErrInfo);
|
||||
#endif
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
if (!AudioSource) {
|
||||
throw agi::AudioProviderOpenError(std::string("Failed to open audio track: %s") + ErrInfo.Buffer, 0);
|
||||
}
|
||||
|
||||
if (!AudioSource)
|
||||
throw agi::AudioProviderOpenError(std::string("Failed to open audio track: ") + ErrInfo.Buffer, 0);
|
||||
|
||||
const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource);
|
||||
|
||||
channels = AudioInfo.Channels;
|
||||
|
@ -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 {
|
||||
if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) {
|
||||
throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer);
|
||||
|
|
|
@ -42,19 +42,16 @@
|
|||
/// @class FFmpegSourceAudioProvider
|
||||
/// @brief Implements audio loading with the FFMS library.
|
||||
class FFmpegSourceAudioProvider : public AudioProvider, FFmpegSourceProvider {
|
||||
private:
|
||||
FFMS_AudioSource *AudioSource; ///< audio source object
|
||||
bool COMInited; ///< COM initialization state
|
||||
/// audio source object
|
||||
agi::scoped_holder<FFMS_AudioSource*, void (FFMS_CC *)(FFMS_AudioSource*)> AudioSource;
|
||||
|
||||
mutable char FFMSErrMsg[1024]; ///< FFMS error message
|
||||
mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
|
||||
|
||||
void Close();
|
||||
void LoadAudio(wxString filename);
|
||||
|
||||
public:
|
||||
FFmpegSourceAudioProvider(wxString filename);
|
||||
virtual ~FFmpegSourceAudioProvider();
|
||||
|
||||
/// @brief Checks sample endianness
|
||||
/// @return Returns true.
|
||||
|
|
|
@ -64,8 +64,10 @@
|
|||
/// @param filename
|
||||
///
|
||||
PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
: file_handle(0, CloseHandle)
|
||||
, file_mapping(0, CloseHandle)
|
||||
{
|
||||
file_handle = CreateFile(
|
||||
filename.c_str(),
|
||||
FILE_READ_DATA,
|
||||
|
@ -75,15 +77,13 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
|||
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,
|
||||
0);
|
||||
|
||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
throw agi::FileNotFoundError(STD_STR(filename));
|
||||
}
|
||||
|
||||
LARGE_INTEGER li_file_size = {0};
|
||||
if (!GetFileSizeEx(file_handle, &li_file_size)) {
|
||||
CloseHandle(file_handle);
|
||||
if (!GetFileSizeEx(file_handle, &li_file_size))
|
||||
throw agi::AudioProviderOpenError("Failed getting file size", 0);
|
||||
}
|
||||
|
||||
file_size = li_file_size.QuadPart;
|
||||
|
||||
file_mapping = CreateFileMapping(
|
||||
|
@ -93,20 +93,16 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
|||
0, 0,
|
||||
0);
|
||||
|
||||
if (file_mapping == 0) {
|
||||
CloseHandle(file_handle);
|
||||
if (file_mapping == 0)
|
||||
throw agi::AudioProviderOpenError("Failed creating file mapping", 0);
|
||||
}
|
||||
|
||||
current_mapping = 0;
|
||||
|
||||
#else
|
||||
|
||||
file_handle = open(filename.mb_str(*wxConvFileName), O_RDONLY);
|
||||
|
||||
if (file_handle == -1) {
|
||||
: file_handle(open(filename.mb_str(*wxConvFileName), O_RDONLY), close)
|
||||
{
|
||||
if (file_handle == -1)
|
||||
throw agi::FileNotFoundError(STD_STR(filename));
|
||||
}
|
||||
|
||||
struct stat filestats;
|
||||
memset(&filestats, 0, sizeof(filestats));
|
||||
|
@ -125,18 +121,11 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
|||
PCMAudioProvider::~PCMAudioProvider()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (current_mapping) {
|
||||
if (current_mapping)
|
||||
UnmapViewOfFile(current_mapping);
|
||||
}
|
||||
|
||||
CloseHandle(file_mapping);
|
||||
CloseHandle(file_handle);
|
||||
#else
|
||||
if (current_mapping) {
|
||||
if (current_mapping)
|
||||
munmap(current_mapping, mapping_length);
|
||||
}
|
||||
|
||||
close(file_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
#include "include/aegisub/audio_provider.h"
|
||||
|
||||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class PCMAudioProvider
|
||||
|
@ -54,14 +56,12 @@
|
|||
///
|
||||
/// DOCME
|
||||
class PCMAudioProvider : public AudioProvider {
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
/// DOCME
|
||||
agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_handle;
|
||||
|
||||
/// DOCME
|
||||
HANDLE file_handle;
|
||||
|
||||
/// DOCME
|
||||
HANDLE file_mapping;
|
||||
agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_mapping;
|
||||
|
||||
/// DOCME
|
||||
mutable void *current_mapping;
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
/// DOCME
|
||||
mutable size_t mapping_length;
|
||||
#else
|
||||
int file_handle;
|
||||
agi::scoped_holder<int, int(*)(int)> file_handle;
|
||||
mutable void *current_mapping;
|
||||
mutable off_t mapping_start;
|
||||
mutable size_t mapping_length;
|
||||
|
|
|
@ -271,28 +271,22 @@ typedef BOOL (WINAPI * PGetUserPreferredUILanguages)(DWORD dwFlags, PULONG pulNu
|
|||
// Try using Win 6+ functions if available
|
||||
static wxString GetUILanguage()
|
||||
{
|
||||
wxString res;
|
||||
|
||||
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
|
||||
if (!kernel32) return res;
|
||||
agi::scoped_holder<HMODULE, BOOL (__stdcall *)(HMODULE)> kernel32(LoadLibraryW(L"kernel32.dll"), FreeLibrary);
|
||||
if (!kernel32) return "";
|
||||
|
||||
PGetUserPreferredUILanguages gupuil = (PGetUserPreferredUILanguages)GetProcAddress(kernel32, "GetUserPreferredUILanguages");
|
||||
if (!gupuil) goto error;
|
||||
if (!gupuil) return "";
|
||||
|
||||
ULONG numlang = 0, output_len = 0;
|
||||
if (gupuil(MUI_LANGUAGE_NAME, &numlang, 0, &output_len) == TRUE && output_len)
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
if (gupuil(MUI_LANGUAGE_NAME, &numlang, 0, &output_len) != TRUE || !output_len)
|
||||
return "";
|
||||
|
||||
error:
|
||||
FreeModule(kernel32);
|
||||
return res;
|
||||
std::vector<wchar_t> output(output_len);
|
||||
if (!gupuil(MUI_LANGUAGE_NAME, &numlang, &output[0], &output_len) || numlang < 1)
|
||||
return "";
|
||||
|
||||
// We got at least one language, just treat it as the only, and a null-terminated string
|
||||
return &output[0];
|
||||
}
|
||||
static wxString GetSystemLanguage()
|
||||
{
|
||||
|
|
|
@ -56,6 +56,33 @@
|
|||
#include "md5.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;
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
#include <ffms.h>
|
||||
|
||||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
/// Index all tracks
|
||||
#define FFMS_TRACKMASK_ALL -1
|
||||
/// Index no tracks
|
||||
|
@ -54,7 +56,11 @@
|
|||
/// @brief Base class for FFMS2 source providers; contains common functions etc
|
||||
class FFmpegSourceProvider {
|
||||
friend class FFmpegSourceCacheCleaner;
|
||||
agi::scoped_holder<bool> COMInited; ///< COM initialization state
|
||||
|
||||
public:
|
||||
FFmpegSourceProvider();
|
||||
|
||||
/// Logging level constants from avutil/log.h
|
||||
enum FFMS_LogLevel {
|
||||
/// nothing printed
|
||||
|
@ -85,7 +91,6 @@ public:
|
|||
/// @class FFmpegSourceCacheCleaner
|
||||
/// @brief Implements index cache cleaning functionality for the FFMS2 providers
|
||||
class FFmpegSourceCacheCleaner : public wxThread {
|
||||
private:
|
||||
FFmpegSourceProvider *parent;
|
||||
|
||||
public:
|
||||
|
@ -96,4 +101,3 @@ public:
|
|||
};
|
||||
|
||||
#endif /* WITH_FFMS2 */
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
|
|||
bold;
|
||||
int slant = italic ? 110 : 0;
|
||||
|
||||
scoped<FcPattern*> pat(FcPatternCreate(), FcPatternDestroy);
|
||||
agi::scoped_holder<FcPattern*> pat(FcPatternCreate(), FcPatternDestroy);
|
||||
if (!pat) return ret;
|
||||
|
||||
int family_cnt = add_families(pat, family);
|
||||
|
@ -138,11 +138,11 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
|
|||
if (!FcConfigSubstitute(config, pat, FcMatchPattern)) return ret;
|
||||
|
||||
FcResult result;
|
||||
scoped<FcFontSet*> fsorted(FcFontSort(config, pat, true, NULL, &result), FcFontSetDestroy);
|
||||
scoped<FcFontSet*> ffullname(MatchFullname(family.c_str(), weight, slant), FcFontSetDestroy);
|
||||
agi::scoped_holder<FcFontSet*> fsorted(FcFontSort(config, pat, true, NULL, &result), FcFontSetDestroy);
|
||||
agi::scoped_holder<FcFontSet*> ffullname(MatchFullname(family.c_str(), weight, slant), FcFontSetDestroy);
|
||||
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) {
|
||||
FcPattern *curp = ffullname->fonts[cur_font];
|
||||
FcPatternReference(curp);
|
||||
|
@ -169,7 +169,7 @@ FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString
|
|||
for (; family_cnt > 1; --family_cnt)
|
||||
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;
|
||||
|
||||
FcChar8 *r_family;
|
||||
|
|
|
@ -25,23 +25,15 @@
|
|||
|
||||
#include "font_file_lister.h"
|
||||
|
||||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
typedef struct _FcConfig FcConfig;
|
||||
typedef struct _FcFontSet FcFontSet;
|
||||
|
||||
/// @class FontConfigFontFileLister
|
||||
/// @brief fontconfig powered font lister
|
||||
class FontConfigFontFileLister : public FontFileLister {
|
||||
template<typename T> class scoped {
|
||||
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;
|
||||
agi::scoped_holder<FcConfig*> config;
|
||||
|
||||
/// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans")
|
||||
/// @param family font fullname
|
||||
|
|
|
@ -57,33 +57,15 @@
|
|||
#include "video_context.h"
|
||||
#include "video_provider_ffmpegsource.h"
|
||||
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param filename The filename to open
|
||||
FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename)
|
||||
: VideoSource(NULL)
|
||||
FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename) try
|
||||
: VideoSource(NULL, FFMS_DestroyVideoSource)
|
||||
, VideoInfo(NULL)
|
||||
, Width(-1)
|
||||
, Height(-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.BufferSize = sizeof(FFMSErrMsg);
|
||||
ErrInfo.ErrorType = FFMS_ERROR_SUCCESS;
|
||||
|
@ -92,25 +74,14 @@ FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename)
|
|||
SetLogLevel();
|
||||
|
||||
// and here we go
|
||||
try {
|
||||
LoadVideo(filename);
|
||||
}
|
||||
catch (wxString const& err) {
|
||||
Close();
|
||||
throw VideoOpenError(STD_STR(err));
|
||||
}
|
||||
catch (...) {
|
||||
Close();
|
||||
throw;
|
||||
}
|
||||
LoadVideo(filename);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
FFmpegSourceVideoProvider::~FFmpegSourceVideoProvider() {
|
||||
Close();
|
||||
catch (wxString const& err) {
|
||||
throw VideoOpenError(STD_STR(err));
|
||||
}
|
||||
catch (const char * err) {
|
||||
throw VideoOpenError(err);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Opens video
|
||||
/// @param filename The filename to open
|
||||
|
@ -118,9 +89,8 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
wxString FileNameShort = wxFileName(filename).GetShortPath();
|
||||
|
||||
FFMS_Indexer *Indexer = FFMS_CreateIndexer(FileNameShort.utf8_str(), &ErrInfo);
|
||||
if (Indexer == NULL) {
|
||||
if (!Indexer)
|
||||
throw agi::FileNotFoundError(ErrInfo.Buffer);
|
||||
}
|
||||
|
||||
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_VIDEO);
|
||||
if (TrackList.size() <= 0)
|
||||
|
@ -140,40 +110,26 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
wxString CacheName = GetCacheFilename(filename);
|
||||
|
||||
// try to read index
|
||||
FFMS_Index *Index = NULL;
|
||||
Index = FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo);
|
||||
bool IndexIsValid = false;
|
||||
if (Index != NULL) {
|
||||
if (FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo)) {
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
}
|
||||
else
|
||||
IndexIsValid = true;
|
||||
}
|
||||
agi::scoped_holder<FFMS_Index*, void (FFMS_CC*)(FFMS_Index*)>
|
||||
Index(FFMS_ReadIndex(CacheName.utf8_str(), &ErrInfo), FFMS_DestroyIndex);
|
||||
|
||||
if (Index && !FFMS_IndexBelongsToFile(Index, FileNameShort.utf8_str(), &ErrInfo))
|
||||
Index = NULL;
|
||||
|
||||
// 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,
|
||||
// but a bit of sanity checking never hurt anyone
|
||||
if (IndexIsValid && TrackNumber >= 0) {
|
||||
if (Index && TrackNumber >= 0) {
|
||||
FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
|
||||
if (FFMS_GetNumFrames(TempTrackData) <= 0) {
|
||||
IndexIsValid = false;
|
||||
FFMS_DestroyIndex(Index);
|
||||
if (FFMS_GetNumFrames(TempTrackData) <= 0)
|
||||
Index = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// moment of truth
|
||||
if (!IndexIsValid) {
|
||||
if (!Index) {
|
||||
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
|
||||
Index = DoIndexing(Indexer, CacheName, TrackMask, FFMS_IEH_IGNORE);
|
||||
}
|
||||
catch (wxString err) {
|
||||
throw VideoOpenError(STD_STR(err));
|
||||
}
|
||||
// ignore audio decoding errors here, we don't care right now
|
||||
Index = DoIndexing(Indexer, CacheName, TrackMask, FFMS_IEH_IGNORE);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// just grab the first track
|
||||
TrackNumber = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_VIDEO, &ErrInfo);
|
||||
if (TrackNumber < 0) {
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
if (TrackNumber < 0)
|
||||
throw VideoNotSupported(std::string("Couldn't find any video tracks: ") + ErrInfo.Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// set thread count
|
||||
|
@ -207,11 +160,8 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
SeekMode = FFMS_SEEK_NORMAL;
|
||||
|
||||
VideoSource = FFMS_CreateVideoSource(FileNameShort.utf8_str(), TrackNumber, Index, Threads, SeekMode, &ErrInfo);
|
||||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
if (VideoSource == NULL) {
|
||||
if (!VideoSource)
|
||||
throw VideoOpenError(std::string("Failed to open video track: ") + ErrInfo.Buffer);
|
||||
}
|
||||
|
||||
// load video properties
|
||||
VideoInfo = FFMS_GetVideoProperties(VideoSource);
|
||||
|
@ -274,14 +224,6 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
FrameNumber = 0;
|
||||
}
|
||||
|
||||
void FFmpegSourceVideoProvider::Close() {
|
||||
if (VideoSource) FFMS_DestroyVideoSource(VideoSource);
|
||||
#ifdef WIN32
|
||||
if (COMInited)
|
||||
CoUninitialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int n) {
|
||||
FrameNumber = mid(0, n, GetFrameCount() - 1);
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
/// @class FFmpegSourceVideoProvider
|
||||
/// @brief Implements video loading through the FFMS library.
|
||||
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
|
||||
|
||||
int Width; ///< width in pixels
|
||||
|
@ -54,7 +55,6 @@ class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
|
|||
int FrameNumber; ///< current framenumber
|
||||
std::vector<int> KeyFramesList; ///< list of keyframes
|
||||
agi::vfr::Framerate Timecodes; ///< vfr object
|
||||
bool COMInited; ///< COM initialization state
|
||||
wxString ColorSpace; ///< Colorspace name
|
||||
|
||||
AegiVideoFrame CurFrame; ///< current video frame
|
||||
|
@ -63,11 +63,9 @@ class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
|
|||
FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
|
||||
|
||||
void LoadVideo(wxString filename);
|
||||
void Close();
|
||||
|
||||
public:
|
||||
FFmpegSourceVideoProvider(wxString filename);
|
||||
~FFmpegSourceVideoProvider();
|
||||
|
||||
const AegiVideoFrame GetFrame(int n);
|
||||
|
||||
|
|
Loading…
Reference in a new issue