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
|
/// @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);
|
||||||
|
|
|
@ -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 (...) {
|
}
|
||||||
Close();
|
catch (wxString const& err) {
|
||||||
throw;
|
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) {
|
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,57 +97,40 @@ 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)) {
|
|
||||||
FFMS_DestroyIndex(Index);
|
|
||||||
Index = NULL;
|
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)
|
||||||
TrackNumber = FFMS_TRACKMASK_ALL;
|
TrackNumber = FFMS_TRACKMASK_ALL;
|
||||||
// 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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,35 +74,23 @@ FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename)
|
||||||
SetLogLevel();
|
SetLogLevel();
|
||||||
|
|
||||||
// and here we go
|
// and here we go
|
||||||
try {
|
|
||||||
LoadVideo(filename);
|
LoadVideo(filename);
|
||||||
}
|
}
|
||||||
catch (wxString const& err) {
|
catch (wxString const& err) {
|
||||||
Close();
|
|
||||||
throw VideoOpenError(STD_STR(err));
|
throw VideoOpenError(STD_STR(err));
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
Close();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (const char * err) {
|
||||||
|
throw VideoOpenError(err);
|
||||||
/// @brief Destructor
|
|
||||||
FFmpegSourceVideoProvider::~FFmpegSourceVideoProvider() {
|
|
||||||
Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Opens video
|
/// @brief Opens video
|
||||||
/// @param filename The filename to open
|
/// @param filename The filename to open
|
||||||
void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
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,41 +110,27 @@ 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)) {
|
|
||||||
FFMS_DestroyIndex(Index);
|
|
||||||
Index = NULL;
|
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
|
||||||
wxFileName(CacheName).Touch();
|
wxFileName(CacheName).Touch();
|
||||||
|
@ -188,12 +144,9 @@ 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
|
||||||
int Threads = OPT_GET("Provider/Video/FFmpegSource/Decoding Threads")->GetInt();
|
int Threads = OPT_GET("Provider/Video/FFmpegSource/Decoding Threads")->GetInt();
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue