Delete libmedia

It's nowhere close to working and just getting further away from working
as time goes on.

Originally committed to SVN as r6096.
This commit is contained in:
Thomas Goyne 2011-12-22 21:24:20 +00:00
parent e2eb7255a9
commit 48526bf341
53 changed files with 0 additions and 7437 deletions

View file

@ -457,10 +457,6 @@
RelativePath="..\..\libaegisub\include\libaegisub\mru.h"
>
</File>
<File
RelativePath="..\..\libaegisub\include\libaegisub\mutex.h"
>
</File>
<File
RelativePath="..\..\libaegisub\include\libaegisub\option.h"
>

View file

@ -60,11 +60,9 @@
<ClInclude Include="$(SrcDir)include\libaegisub\line_iterator.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\log.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\mru.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\mutex.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\option.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\option_value.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\path.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\progress.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\scoped_ptr.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\signal.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\types.h" />
@ -97,7 +95,6 @@
<ClCompile Include="$(SrcDir)common\option.cpp" />
<ClCompile Include="$(SrcDir)common\option_visit.cpp" />
<ClCompile Include="$(SrcDir)common\path.cpp" />
<ClCompile Include="$(SrcDir)common\progress.cpp" />
<ClCompile Include="$(SrcDir)common\util.cpp" />
<ClCompile Include="$(SrcDir)common\validator.cpp" />
<ClCompile Include="$(SrcDir)common\vfr.cpp" />

View file

@ -59,9 +59,6 @@
<ClInclude Include="$(SrcDir)include\libaegisub\mru.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\option.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -116,9 +113,6 @@
<ClInclude Include="$(SrcDir)include\libaegisub\keyframe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\progress.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\signal.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -187,9 +181,6 @@
<ClCompile Include="$(SrcDir)windows\path_win.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)common\progress.cpp">
<Filter>Source Files\Common</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)common\util.cpp">
<Filter>Source Files\Common</Filter>
</ClCompile>

View file

@ -206,18 +206,6 @@ AC_SUBST(DMG_STRING)
ACX_PTHREAD([], [AC_MSG_FAILURE([You must have working pthreads.])])
CC="$PTHREAD_CC"
AC_AGI_COMPILE([pthread_rwlock_*], [pthread_rwlock], [$PTHREAD_CFLAGS], [$PTHREAD_LIBS],[
#include <pthread.h>
#define _XOPEN_SOURCE 500
int main(void) {
pthread_rwlock_t l; pthread_rwlock_init(&l, NULL);
pthread_rwlock_rdlock(&l);
return 0;
}])
AS_IF([test x$agi_cv_with_pthread_rwlock = xyes],
[AC_DEFINE(HAVE_RWLOCK,1,[define if the compiler implements pthread_rwlock_*])])
######################
# Check compiler flags
######################

View file

@ -32,7 +32,6 @@ SRC = \
common/option.cpp \
common/option_visit.cpp \
common/path.cpp \
common/progress.cpp \
common/keyframe.cpp \
common/util.cpp \
common/log.cpp \

View file

@ -1,107 +0,0 @@
// Copyright (c) 2011, Niels Martin Hansen <nielsm@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file progress.cpp
/// @brief Progress bars.
/// @ingroup libaegisub
#ifndef LAG_PRE
#include <assert.h>
#include <string>
#include <iomanip>
#include <iostream>
#include <cmath>
#endif
#include "libaegisub/progress.h"
namespace agi {
class NullProgressSink : public ProgressSink {
public:
virtual void set_progress(int steps, int max) { }
virtual void set_operation(const std::string &operation) { }
virtual bool get_cancelled() const { return false; }
};
ProgressSink * NullProgressSinkFactory::create_progress_sink(const std::string &title) const {
return new NullProgressSink;
}
class StdioProgressSink : public ProgressSink {
private:
std::string operation;
float progress;
void print();
public:
StdioProgressSink(const std::string &title);
virtual ~StdioProgressSink();
virtual void set_progress(int steps, int max);
virtual void set_operation(const std::string &operation);
virtual bool get_cancelled() const { return false; } // or maybe see if there is an ESC waiting or get a ^C sent flag
};
ProgressSink * StdioProgressSinkFactory::create_progress_sink(const std::string &title) const {
return new StdioProgressSink(title);
}
StdioProgressSink::StdioProgressSink(const std::string &title)
: operation(title)
, progress(0) {
std::cout << title << ": ";
print();
}
StdioProgressSink::~StdioProgressSink()
{
std::cout << "end" << std::endl;
}
void StdioProgressSink::set_progress(int steps, int max) {
assert(steps >= 0);
assert(steps <= max);
float old_progress = progress;
progress = (100.f * steps)/max;
if (std::fabs(progress-old_progress) > 0.8)
{
print();
}
}
void StdioProgressSink::set_operation(const std::string &operation) {
this->operation = operation;
print();
}
void StdioProgressSink::print() {
std::cout << operation << ": " << std::setprecision(2) << progress << std::endl;
}
} // namespace agi

View file

@ -1,325 +0,0 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Craig Silverstein.
//
// A simple mutex wrapper, supporting locks and read-write locks.
// You should assume the locks are *not* re-entrant.
//
// To use: you should define the following macros in your configure.ac:
// ACX_PTHREAD
// AC_RWLOCK
// The latter is defined in ../autoconf.
//
// This class is meant to be internal-only and should be wrapped by an
// internal namespace. Before you use this module, please give the
// name of your internal namespace for this module. Or, if you want
// to expose it, you'll want to move it to the Google namespace. We
// cannot put this class in global namespace because there can be some
// problems when we have multiple versions of Mutex in each shared object.
//
// NOTE: by default, we have #ifdef'ed out the TryLock() method.
// This is for two reasons:
// 1) TryLock() under Windows is a bit annoying (it requires a
// #define to be defined very early).
// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
// mode.
// If you need TryLock(), and either these two caveats are not a
// problem for you, or you're willing to work around them, then
// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
// in the code below.
//
// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
// Because of that, we might as well use windows locks for
// cygwin. They seem to be more reliable than the cygwin pthreads layer.
//
// TRICKY IMPLEMENTATION NOTE:
// This class is designed to be safe to use during
// dynamic-initialization -- that is, by global constructors that are
// run before main() starts. The issue in this case is that
// dynamic-initialization happens in an unpredictable order, and it
// could be that someone else's dynamic initializer could call a
// function that tries to acquire this mutex -- but that all happens
// before this mutex's constructor has run. (This can happen even if
// the mutex and the function that uses the mutex are in the same .cc
// file.) Basically, because Mutex does non-trivial work in its
// constructor, it's not, in the naive implementation, safe to use
// before dynamic initialization has run on it.
//
// The solution used here is to pair the actual mutex primitive with a
// bool that is set to true when the mutex is dynamically initialized.
// (Before that it's false.) Then we modify all mutex routines to
// look at the bool, and not try to lock/unlock until the bool makes
// it to true (which happens after the Mutex constructor has run.)
//
// This works because before main() starts -- particularly, during
// dynamic initialization -- there are no threads, so a) it's ok that
// the mutex operations are a no-op, since we don't need locking then
// anyway; and b) we can be quite confident our bool won't change
// state between a call to Lock() and a call to Unlock() (that would
// require a global constructor in one translation unit to call Lock()
// and another global constructor in another translation unit to call
// Unlock() later, which is pretty perverse).
//
// That said, it's tricky, and can conceivably fail; it's safest to
// avoid trying to acquire a mutex in a global constructor, if you
// can. One way it can fail is that a really smart compiler might
// initialize the bool to true at static-initialization time (too
// early) rather than at dynamic-initialization time. To discourage
// that, we set is_safe_ to true in code (not the constructor
// colon-initializer) and set it to true via a function that always
// evaluates to true, but that the compiler can't know always
// evaluates to true. This should be good enough.
#ifndef GOOGLE_MUTEX_H_
#define GOOGLE_MUTEX_H_
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# ifdef GMUTEX_TRYLOCK
// We need Windows NT or later for TryEnterCriticalSection(). If you
// don't need that functionality, you can remove these _WIN32_WINNT
// lines, and change TryLock() to assert(0) or something.
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
# endif
# endif
// To avoid macro definition of ERROR.
# define NOGDI
// To avoid macro definition of min/max.
# ifndef NOMINMAX
# define NOMINMAX
# endif // NOMINMAX
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take it
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
// for locking there.)
# ifdef __linux__
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
# endif
# include <pthread.h>
typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
// We need to include these header files after defining _XOPEN_SOURCE
// as they may define the _XOPEN_SOURCE macro.
#include <assert.h>
#include <stdlib.h> // for abort()
#define MUTEX_NAMESPACE agi
namespace MUTEX_NAMESPACE {
class Mutex {
public:
// Create a Mutex that is not held by anybody. This constructor is
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
inline Mutex();
// Destructor
inline ~Mutex();
inline void Lock(); // Block if needed until free then acquire exclusively
inline void Unlock(); // Release a lock acquired via Lock()
#ifdef GMUTEX_TRYLOCK
inline bool TryLock(); // If free, Lock() and return true, else return false
#endif
// Note that on systems that don't support read-write locks, these may
// be implemented as synonyms to Lock() and Unlock(). So you can use
// these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock.
inline void ReaderLock(); // Block until free or shared then acquire a share
inline void ReaderUnlock(); // Release a read share of this Mutex
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
// TODO(hamaji): Do nothing, implement correctly.
inline void AssertHeld() {}
private:
MutexType mutex_;
// We want to make sure that the compiler sets is_safe_ to true only
// when we tell it to, and never makes assumptions is_safe_ is
// always true. volatile is the most reliable way to do that.
volatile bool is_safe_;
inline void SetIsSafe() { is_safe_ = true; }
// Catch the error of writing Mutex when intending MutexLock.
Mutex(Mutex* /*ignored*/) {}
// Disallow "evil" constructors
Mutex(const Mutex&);
void operator=(const Mutex&);
};
// Now the implementation of Mutex for various systems
#if defined(NO_THREADS)
// When we don't have threads, we can be either reading or writing,
// but not both. We can have lots of readers at once (in no-threads
// mode, that's most likely to happen in recursive function calls),
// but only one writer. We represent this by having mutex_ be -1 when
// writing and a number > 0 when reading (and 0 when no lock is held).
//
// In debug mode, we assert these invariants, while in non-debug mode
// we do nothing, for efficiency. That's why everything is in an
// assert.
Mutex::Mutex() : mutex_(0) { }
Mutex::~Mutex() { assert(mutex_ == 0); }
void Mutex::Lock() { assert(--mutex_ == -1); }
void Mutex::Unlock() { assert(mutex_++ == -1); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
#endif
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
TryEnterCriticalSection(&mutex_) != 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_rwlock_trywrlock(&mutex_) == 0 :
true; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_mutex_trylock(&mutex_) == 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); }
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#endif
// --------------------------------------------------------------------------
// Some helper classes
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class MutexLock {
public:
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
MutexLock(const MutexLock&);
void operator=(const MutexLock&);
};
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
class ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
~ReaderMutexLock() { mu_->ReaderUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
ReaderMutexLock(const ReaderMutexLock&);
void operator=(const ReaderMutexLock&);
};
class WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
~WriterMutexLock() { mu_->WriterUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
WriterMutexLock(const WriterMutexLock&);
void operator=(const WriterMutexLock&);
};
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
} // namespace MUTEX_NAMESPACE
using namespace MUTEX_NAMESPACE;
#undef MUTEX_NAMESPACE
#endif /* #define GOOGLE_MUTEX_H__ */

View file

@ -1,59 +0,0 @@
// Copyright (c) 2011, Niels Martin Hansen <nielsm@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file progress.h
/// @brief Progress bars.
/// @ingroup libaegisub
#ifndef LAG_PRE
#include <string>
#endif
namespace agi {
class ProgressSink;
class ProgressSinkFactory {
public:
virtual ~ProgressSinkFactory() { }
virtual ProgressSink * create_progress_sink(const std::string &title) const = 0;
};
class ProgressSink {
public:
virtual ~ProgressSink() { }
virtual void set_progress(int steps, int max) = 0;
virtual void set_operation(const std::string &operation) = 0;
virtual bool get_cancelled() const = 0;
};
class NullProgressSinkFactory : public ProgressSinkFactory {
public:
virtual ProgressSink * create_progress_sink(const std::string &title) const;
};
class StdioProgressSinkFactory : public ProgressSinkFactory {
private:
public:
StdioProgressSinkFactory();
virtual ProgressSink * create_progress_sink(const std::string &title) const;
};
} // namespace agi

View file

@ -1,46 +0,0 @@
# $Id$
include ../Makefile.inc
LIB_SHARED = libmedia_aegisub-3.0.so
LIB_SHARED_INSTALL = yes
LIB_VERSION = 3
CXXFLAGS = -Iinclude -I../libaegisub/include -I../src -I.. -DMAGI -fPIC -Wno-variadic-macros
PRECOMPILED_HEADER_NAME = magi_pre.h
magi_pre.h.gch: CXXFLAGS := $(CXXFLAGS)
#######################
# AUDIO / VIDEO SUPPORT
#######################
ifeq (yes, $(HAVE_PROVIDER_FFMPEGSOURCE))
SRC_OPT += audio/ffms_audio.cpp common/ffms_common.cpp video/ffms_video.cpp
common/ffms_common.o: CXXFLAGS += $(CFLAGS_FFMPEGSOURCE) $(CFLAGS_LIBAVFORMAT) $(CFLAGS_LIBAVCODEC) $(CFLAGS_LIBSWSCALE) $(CFLAGS_LIBAVUTIL) $(CFLAGS_LIBPOSTPROC)
audio/ffms_audio.o: CXXFLAGS += $(CFLAGS_FFMPEGSOURCE) $(CFLAGS_LIBAVFORMAT) $(CFLAGS_LIBAVCODEC) $(CFLAGS_LIBSWSCALE) $(CFLAGS_LIBAVUTIL) $(CFLAGS_LIBPOSTPROC)
video/ffms_video.o: CXXFLAGS += $(CFLAGS_FFMPEGSOURCE) $(CFLAGS_LIBAVFORMAT) $(CFLAGS_LIBAVCODEC) $(CFLAGS_LIBSWSCALE) $(CFLAGS_LIBAVUTIL) $(CFLAGS_LIBPOSTPROC)
LDFLAGS_POST += $(LDFLAGS_FFMPEGSOURCE)
endif
SRC = \
audio/downmix.cpp \
audio/convert.cpp \
audio/dummy_audio.cpp \
audio/pcm.cpp \
cache/audio_ram.cpp \
cache/audio_hd.cpp \
cache/video_cache.cpp \
common/audio_manager.cpp \
common/video_frame.cpp \
common/video_manager.cpp \
video/yuv4mpeg.cpp \
$(SRC_OPT)
HEADERS = \
*/*.h \
include/libmedia/*.h \
include ../Makefile.target
-include */*.d

View file

@ -1,174 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_avs.cpp
/// @brief Avisynth-based audio provider
/// @ingroup audio_input
///
#include "config.h"
#ifdef WITH_AVISYNTH
#ifndef AGI_PRE
#include <Mmreg.h>
#include <time.h>
#include <wx/filename.h>
#endif
#include "audio_provider_avs.h"
#include "charset_conv.h"
#include "compat.h"
#include "main.h"
#include "standard_paths.h"
#include "utils.h"
namespace media {
/// @brief Constructor
/// @param _filename
///
AvisynthAudioProvider::AvisynthAudioProvider(wxString filename) try : filename(filename) {
AVSValue script;
wxMutexLocker lock(AviSynthMutex);
wxFileName fn(filename);
if (!fn.FileExists())
throw agi::FileNotFoundError(STD_STR(filename));
// Include
if (filename.EndsWith(_T(".avs"))) {
char *fname = env->SaveString(fn.GetShortPath().mb_str(csConvLocal));
script = env->Invoke("Import", fname);
}
// Use DirectShowSource
else {
const char * argnames[3] = { 0, "video", "audio" };
AVSValue args[3] = { env->SaveString(fn.GetShortPath().mb_str(csConvLocal)), false, true };
// Load DirectShowSource.dll from app dir if it exists
wxFileName dsspath(StandardPaths::DecodePath(_T("?data/DirectShowSource.dll")));
if (dsspath.FileExists()) {
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetShortPath().mb_str(csConvLocal)));
}
// Load audio with DSS if it exists
if (env->FunctionExists("DirectShowSource")) {
script = env->Invoke("DirectShowSource", AVSValue(args,3),argnames);
}
// Otherwise fail
else {
throw AudioOpenError("No suitable audio source filter found. Try placing DirectShowSource.dll in the Aegisub application directory.");
}
}
LoadFromClip(script);
}
catch (AvisynthError &err) {
throw AudioOpenError("Avisynth error: " + std::string(err.msg));
}
/// @brief Read from environment
/// @param _clip
///
void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) {
AVSValue script;
// Check if it has audio
VideoInfo vi = _clip.AsClip()->GetVideoInfo();
if (!vi.HasAudio()) throw AudioOpenError("No audio found.");
// Convert to one channel
char buffer[1024];
strcpy(buffer,lagi_wxString(OPT_GET("Audio/Downmixer")->GetString()).mb_str(csConvLocal));
script = env->Invoke(buffer, _clip);
// Convert to 16 bits per sample
script = env->Invoke("ConvertAudioTo16bit", script);
vi = script.AsClip()->GetVideoInfo();
// Convert sample rate
int setsample = OPT_GET("Provider/Audio/AVS/Sample Rate")->GetInt();
if (vi.SamplesPerSecond() < 32000) setsample = 44100;
if (setsample != 0) {
AVSValue args[2] = { script, setsample };
script = env->Invoke("ResampleAudio", AVSValue(args,2));
}
// Set clip
PClip tempclip = script.AsClip();
vi = tempclip->GetVideoInfo();
// Read properties
channels = vi.AudioChannels();
num_samples = vi.num_audio_samples;
sample_rate = vi.SamplesPerSecond();
bytes_per_sample = vi.BytesPerAudioSample();
clip = tempclip;
}
/// @brief Get audio
/// @param buf
/// @param start
/// @param count
///
void AvisynthAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
// Requested beyond the length of audio
if (start+count > num_samples) {
int64_t oldcount = count;
count = num_samples-start;
if (count < 0) count = 0;
// Fill beyond with zero
if (bytes_per_sample == 1) {
char *temp = (char *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (count) {
clip->GetAudio(buf,start,count,env);
}
}
#endif
} // namespace

View file

@ -1,73 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_avs.h
/// @see audio_provider_avs.cpp
/// @ingroup audio_input
///
#ifdef WITH_AVISYNTH
#include "include/aegisub/audio_provider.h"
#include "avisynth_wrap.h"
namespace media {
/// DOCME
/// @class AvisynthAudioProvider
/// @brief DOCME
///
/// DOCME
class AvisynthAudioProvider : public AudioProvider, public AviSynthWrapper {
/// DOCME
wxString filename;
/// DOCME
PClip clip;
void LoadFromClip(AVSValue clip);
void SetFile();
public:
AvisynthAudioProvider(wxString _filename);
wxString GetFilename() const { return filename; }
bool AreSamplesNativeEndian() const { return true; }
bool NeedsCache() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
void GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int samples,float scale);
};
#endif
} // namespace

View file

@ -1,225 +0,0 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_convert.cpp
/// @brief Intermediate sample format-converting audio provider
/// @ingroup audio_input
///
#include "config.h"
#include "aegisub_endian.h"
#include "convert.h"
#include "downmix.h"
namespace media {
/// @brief Constructor
/// @param src
///
ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) : source(src) {
channels = source->GetChannels();
num_samples = source->GetNumSamples();
sample_rate = source->GetSampleRate();
bytes_per_sample = 2;
sampleMult = 1;
if (sample_rate < 16000) sampleMult = 4;
else if (sample_rate < 32000) sampleMult = 2;
sample_rate *= sampleMult;
num_samples *= sampleMult;
}
/// @brief Convert to 16-bit
/// @param src
/// @param dst
/// @param count
///
void ConvertAudioProvider::Make16Bit(const char *src, short *dst, int64_t count) const {
for (int64_t i=0;i<count;i++) {
dst[i] = (short(src[i])-128)*255;
}
}
//////////////////////
// Change sample rate
// This requres 16-bit input
// The SampleConverter is a class overloading operator() with a function from short to short
template<class SampleConverter>
/// @brief DOCME
/// @param src
/// @param dst
/// @param count
/// @param converter
///
void ConvertAudioProvider::ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter) const {
// Upsample by 2
if (sampleMult == 2) {
int64_t size = count/2;
short cur;
short next = 0;
for (int64_t i=0;i<size;i++) {
cur = next;
next = converter(*src++);
*(dst++) = cur;
*(dst++) = (cur+next)/2;
}
if (count%2) *(dst++) = next;
}
// Upsample by 4
else if (sampleMult == 4) {
int64_t size = count/4;
short cur;
short next = 0;
for (int64_t i=0;i<size;i++) {
cur = next;
next = converter(*src++);
*(dst++) = cur;
*(dst++) = (cur*3+next)/4;
*(dst++) = (cur+next)/2;
*(dst++) = (cur+next*3)/4;
}
for (int i=0;i<count%4;i++) *(dst++) = next;
}
// Nothing much to do, just ensure correct endedness
else if (sampleMult == 1) {
while (count-- > 0) {
*dst++ = converter(*src++);
}
}
}
/// DOCME
struct NullSampleConverter {
inline short operator()(const short val) const {
return val;
}
};
/// DOCME
struct EndianSwapSampleConverter {
inline short operator()(const short val) const {
return (short)Endian::Reverse((uint16_t)val);
};
};
/// @brief Get audio
/// @param destination
/// @param start
/// @param count
///
void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t count) const {
// Bits per sample
int srcBps = source->GetBytesPerSample();
// Nothing to do
if (sampleMult == 1 && srcBps == 2) {
source->GetAudio(destination,start,count);
}
// Convert
else {
// Allocate buffers with sufficient size for the entire operation
size_t fullSize = count;
int64_t srcCount = count / sampleMult;
short *buffer1 = NULL;
short *buffer2 = NULL;
short *last = NULL;
// Read audio
buffer1 = new short[fullSize * channels];
source->GetAudio(buffer1,start/sampleMult,srcCount);
// Convert from 8-bit to 16-bit
if (srcBps == 1) {
if (sampleMult == 1) {
Make16Bit((const char*)buffer1,(short*)destination,srcCount * channels);
}
else {
buffer2 = new short[fullSize * channels];
Make16Bit((const char*)buffer1,buffer2,srcCount * channels);
last = buffer2;
}
}
// Already 16-bit
else if (srcBps == 2) last = buffer1;
// Convert sample rate
if (sampleMult != 1 && source->AreSamplesNativeEndian()) {
ChangeSampleRate(last,(short*)destination,count * channels, NullSampleConverter());
}
else if (!source->AreSamplesNativeEndian()) {
ChangeSampleRate(last,(short*)destination,count * channels, EndianSwapSampleConverter());
}
delete [] buffer1;
delete [] buffer2;
}
}
/// @brief See if we need to downmix the number of channels
/// @param source_provider
///
AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider) {
AudioProvider *provider = source_provider;
// Aegisub requires 16 bit samples,
// some audio players break with low samplerates,
// everything breaks with wrong-ended samples.
if (provider->GetBytesPerSample() != 2 ||
provider->GetSampleRate() < 32000 ||
!provider->AreSamplesNativeEndian())
{
// @todo add support for more bitdepths (i.e. 24- and 32-bit audio)
if (provider->GetBytesPerSample() > 2)
throw AudioOpenError("Audio format converter: audio with bitdepths greater than 16 bits/sample is currently unsupported");
provider = new ConvertAudioProvider(provider);
}
// We also require mono audio for historical reasons
if (provider->GetChannels() != 1)
{
provider = new DownmixingAudioProvider(provider);
}
return provider;
}
} // namespace

View file

@ -1,75 +0,0 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_convert.h
/// @see audio_provider_convert.cpp
/// @ingroup audio_input
///
#include "libmedia/audio.h"
#ifndef AGI_PRE
#include <tr1/memory>
#endif
namespace media {
/// DOCME
/// @class ConvertAudioProvider
/// @brief DOCME
///
/// DOCME
class ConvertAudioProvider : public AudioProvider {
/// DOCME
int sampleMult;
/// DOCME
std::tr1::shared_ptr<AudioProvider> source;
void Make16Bit(const char *src, short *dst, int64_t count) const;
template<class SampleConverter>
void ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter) const;
public:
ConvertAudioProvider(AudioProvider *source);
/// By its nature, the ConvertAudioProvider always delivers machine endian.
/// That's one of the points of it!
bool AreSamplesNativeEndian() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
std::string GetFilename() const { return source->GetFilename(); }
};
AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider);
} // namespace

View file

@ -1,130 +0,0 @@
// Copyright (c) 2007-2008, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_downmix.cpp
/// @brief Intermediate audio provider downmixing the signal to mono
/// @ingroup audio_input
///
//////////////////
// Headers
#include "config.h"
#include "downmix.h"
namespace media {
/// @brief Constructor
/// @param source
///
DownmixingAudioProvider::DownmixingAudioProvider(AudioProvider *source) : provider(source) {
filename = source->GetFilename();
channels = 1; // target
src_channels = source->GetChannels();
num_samples = source->GetNumSamples();
bytes_per_sample = source->GetBytesPerSample();
sample_rate = source->GetSampleRate();
if (!(bytes_per_sample == 1 || bytes_per_sample == 2))
throw AudioOpenError("Downmixing Audio Provider: Can only downmix 8 and 16 bit audio");
if (!source->AreSamplesNativeEndian())
throw AudioOpenError("Downmixing Audio Provider: Source must have machine endian samples");
}
/// @brief Actual work happens here
/// @param buf
/// @param start
/// @param count
///
void DownmixingAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
if (count == 0) return;
// We can do this ourselves
if (start >= num_samples) {
if (bytes_per_sample == 1)
// 8 bit formats are usually unsigned with bias 127
memset(buf, 127, count);
else
// While everything else is signed
memset(buf, 0, count*bytes_per_sample);
return;
}
// So alloc some temporary memory for this
// Depending on use, this might be made faster by using
// a pre-allocced block of memory...?
char *tmp = new char[count*bytes_per_sample*src_channels];
try {
provider->GetAudio(tmp, start, count);
}
catch (...) {
delete tmp;
throw;
}
// Now downmix
// Just average the samples over the channels (really bad if they're out of phase!)
// XXX: Assuming here that sample data are in machine endian, an upstream provider should ensure that
if (bytes_per_sample == 1) {
uint8_t *src = (uint8_t *)tmp;
uint8_t *dst = (uint8_t *)buf;
while (count > 0) {
int sum = 0;
for (int c = 0; c < src_channels; c++)
sum += *(src++);
*(dst++) = (uint8_t)(sum / src_channels);
count--;
}
}
else if (bytes_per_sample == 2) {
int16_t *src = (int16_t *)tmp;
int16_t *dst = (int16_t *)buf;
while (count > 0) {
int sum = 0;
for (int c = 0; c < src_channels; c++)
sum += *(src++);
*(dst++) = (int16_t)(sum / src_channels);
count--;
}
}
// Done downmixing, free the work buffer
delete[] tmp;
}
} // namespace

View file

@ -1,66 +0,0 @@
// Copyright (c) 2007-2008, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_downmix.h
/// @see audio_provider_downmix.cpp
/// @ingroup audio_input
///
#include "libmedia/audio.h"
#ifndef AGI_PRE
#include <tr1/memory>
#endif
namespace media {
/// DOCME
/// @class DownmixingAudioProvider
/// @brief DOCME
///
/// DOCME
class DownmixingAudioProvider : public AudioProvider {
std::tr1::shared_ptr<AudioProvider> provider;
/// DOCME
int src_channels;
public:
DownmixingAudioProvider(AudioProvider *source);
/// @brief Downmixing requires samples to be native endian beforehand
///
bool AreSamplesNativeEndian() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
};
} // namespace

View file

@ -1,80 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_dummy.cpp
/// @brief Dummy (silence or noise) audio provider
/// @ingroup audio_input
///
#include "config.h"
#include "dummy_audio.h"
namespace media {
/// @brief Constructor
/// @param dur_ms
/// @param _noise
///
DummyAudioProvider::DummyAudioProvider(unsigned long dur_ms, bool _noise) {
noise = _noise;
channels = 1;
sample_rate = 44100;
bytes_per_sample = 2;
num_samples = (int64_t)dur_ms * sample_rate / 1000;
}
/// @brief Destructor
///
DummyAudioProvider::~DummyAudioProvider() {
}
/// @brief Get audio
/// @param buf
/// @param start
/// @param count
///
void DummyAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
short *workbuf = (short*)buf;
if (noise) {
while (--count > 0)
*workbuf++ = (rand() - RAND_MAX/2) * 10000 / RAND_MAX;
}
else {
while (--count > 0)
*workbuf++ = 0;
}
}
} // namespace

View file

@ -1,59 +0,0 @@
// Copyright (c) 2006, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_dummy.h
/// @see audio_provider_dummy.cpp
/// @ingroup audio_input
///
#include "libmedia/audio.h"
namespace media {
/// DOCME
/// @class DummyAudioProvider
/// @brief DOCME
///
/// DOCME
class DummyAudioProvider : public AudioProvider {
/// DOCME
bool noise;
public:
DummyAudioProvider(unsigned long dur_ms, bool _noise);
~DummyAudioProvider();
bool AreSamplesNativeEndian() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
};
} // namespace

View file

@ -1,225 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster <thefluff@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file ffms_audio.cpp
/// @brief FFmpegSource Audio support.
/// @ingroup fmms audio
#include "config.h"
#ifndef AGI_PRE
#endif
#include "ffms_audio.h"
#include "libmedia/audio.h"
namespace media {
namespace ffms {
/// @brief Constructor
/// @param filename
///
FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(std::string filename)
: 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 AudioOpenError("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;
ErrInfo.SubType = FFMS_ERROR_SUCCESS;
// SetLogLevel();
try {
LoadAudio(filename);
} catch (...) {
Close();
throw;
}
}
/// @brief Load audio file
/// @param filename
///
void FFmpegSourceAudioProvider::LoadAudio(std::string filename) {
// wxString FileNameShort = wxFileName(filename).GetShortPath();
FFMS_Indexer *Indexer = FFMS_CreateIndexer(filename.c_str(), &ErrInfo);
if (Indexer == NULL) {
throw agi::FileNotFoundError(ErrInfo.Buffer);
}
std::map<int,std::string> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
if (TrackList.size() <= 0)
throw AudioOpenError("no audio tracks found");
// initialize the track number to an invalid value so we can detect later on
// whether the user actually had to choose a track or not
int TrackNumber = -1;
if (TrackList.size() > 1) {
TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_AUDIO);
// if it's still -1 here, user pressed cancel
if (TrackNumber == -1)
throw agi::UserCancelException("audio loading cancelled by user");
}
// generate a name for the cache file
std::string CacheName = GetCacheFilename(filename);
// try to read index
FFMS_Index *Index = NULL;
Index = FFMS_ReadIndex(CacheName.c_str(), &ErrInfo);
bool IndexIsValid = false;
if (Index != NULL) {
if (FFMS_IndexBelongsToFile(Index, filename.c_str(), &ErrInfo)) {
FFMS_DestroyIndex(Index);
Index = NULL;
}
else
IndexIsValid = true;
}
// index valid but track number still not set?
if (IndexIsValid) {
// 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;
throw AudioOpenError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer);
}
// 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);
Index = NULL;
}
}
// no valid index exists and the file only has one audio track, index it
else if (TrackNumber < 0)
TrackNumber = FFMS_TRACKMASK_ALL;
// else: do nothing (keep track mask as it is)
// moment of truth
if (!IndexIsValid) {
int TrackMask;
// if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL)
if (TrackNumber == FFMS_TRACKMASK_ALL)
TrackMask = FFMS_TRACKMASK_ALL;
else
TrackMask = (1 << TrackNumber);
try {
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
}
catch (std::string const& err) {
throw AudioOpenError(err);
}
// if tracknumber still isn't set we need to set it now
if (TrackNumber == FFMS_TRACKMASK_ALL)
TrackNumber = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, &ErrInfo);
}
// update access time of index file so it won't get cleaned away
///XXX: Add something to libaegisub to support this.
// if (!wxFileName(CacheName).Touch()) {
// warn user?
// }
#if FFMS_VERSION >= ((2 << 24) | (14 << 16) | (1 << 8) | 0)
AudioSource = FFMS_CreateAudioSource(filename.c_str(), TrackNumber, Index, -1, &ErrInfo);
#else
AudioSource = FFMS_CreateAudioSource(filename.c_str(), TrackNumber, Index, &ErrInfo);
#endif
FFMS_DestroyIndex(Index);
Index = NULL;
if (!AudioSource) {
throw AudioOpenError(std::string("Failed to open audio track: %s") + ErrInfo.Buffer);
}
const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource);
channels = AudioInfo.Channels;
sample_rate = AudioInfo.SampleRate;
num_samples = AudioInfo.NumSamples;
if (channels <= 0 || sample_rate <= 0 || num_samples <= 0)
throw AudioOpenError("sanity check failed, consult your local psychiatrist");
// FIXME: use the actual sample format too?
// why not just bits_per_sample/8? maybe there's some oddball format with half bytes out there somewhere...
switch (AudioInfo.BitsPerSample) {
case 8: bytes_per_sample = 1; break;
case 16: bytes_per_sample = 2; break;
case 24: bytes_per_sample = 3; break;
case 32: bytes_per_sample = 4; break;
default:
throw AudioOpenError("unknown or unsupported sample format");
}
}
/// @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);
}
}
} // namespace ffms
} // namespace media

View file

@ -1,63 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster <thefluff@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file ffms_audio.h
/// @brief FFmpegSource Audio support.
/// @ingroup fmms audio
#include "../../libffms/include/ffms.h"
#include <libmedia/audio.h>
#ifndef AGI_PRE
#ifdef WIN32
#include <objbase.h>
#endif
#include <map>
#endif
#include "../common/ffms_common.h"
namespace media {
namespace ffms {
/// @class Audio
/// Audio file support.
class FFmpegSourceAudioProvider : public AudioProvider, FFmpegSourceProvider {
FFMS_AudioSource *AudioSource; ///< audio source object
bool COMInited; ///< COM initialization state
mutable char FFMSErrMsg[1024]; ///< FFMS error message
mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
void Close();
void LoadAudio(std::string filename);
public:
FFmpegSourceAudioProvider(std::string filename);
virtual ~FFmpegSourceAudioProvider();
/// @brief Checks sample endianness
/// @return Returns true.
/// FFMS always delivers native endian samples.
bool AreSamplesNativeEndian() const { return true; }
bool NeedsCache() const { return true; }
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
};
} // namespace ffms
} // namespace media

View file

@ -1,633 +0,0 @@
// Copyright (c) 2007-2008, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_pcm.cpp
/// @brief PCM WAV and WAV64 audio provider
/// @ingroup audio_input
///
#include "config.h"
#ifndef AGI_PRE
#include <assert.h>
#include <stdint.h>
#ifndef __WINDOWS__
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif
#endif
#include <libaegisub/log.h>
#include "aegisub_endian.h"
#include "pcm.h"
//#include "compat.h"
//#include "utils.h"
namespace media {
/// @brief DOCME
/// @param filename
///
PCMAudioProvider::PCMAudioProvider(const std::string &filename)
{
#ifdef _WIN32
file_handle = CreateFile(
filename.c_str(),
FILE_READ_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,
0);
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);
throw AudioOpenError("Failed getting file size");
}
file_size = li_file_size.QuadPart;
file_mapping = CreateFileMapping(
file_handle,
0,
PAGE_READONLY,
0, 0,
0);
if (file_mapping == 0) {
CloseHandle(file_handle);
throw AudioOpenError("Failed creating file mapping");
}
current_mapping = 0;
#else
file_handle = open(filename.c_str(), O_RDONLY);
if (file_handle == -1) {
throw agi::FileNotFoundError(filename);
}
struct stat filestats;
memset(&filestats, 0, sizeof(filestats));
if (fstat(file_handle, &filestats)) {
close(file_handle);
throw AudioOpenError("Could not stat file to get size");
}
file_size = filestats.st_size;
current_mapping = 0;
#endif
}
/// @brief DOCME
///
PCMAudioProvider::~PCMAudioProvider()
{
#ifdef _WIN32
if (current_mapping) {
UnmapViewOfFile(current_mapping);
}
CloseHandle(file_mapping);
CloseHandle(file_handle);
#else
if (current_mapping) {
munmap(current_mapping, mapping_length);
}
close(file_handle);
#endif
}
/// @brief DOCME
/// @param range_start
/// @param range_length
/// @return
///
char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length) const
{
if (range_start + range_length > file_size) {
throw AudioDecodeError("Attempted to map beyond end of file");
}
// Check whether the requested range is already visible
if (!current_mapping || range_start < mapping_start || range_start+range_length > mapping_start+(int64_t)mapping_length) {
// It's not visible, change the current mapping
if (current_mapping) {
#ifdef _WIN32
UnmapViewOfFile(current_mapping);
#else
munmap(current_mapping, mapping_length);
#endif
}
// Align range start on a 1 MB boundary and go 16 MB back
mapping_start = (range_start & ~0xFFFFF) - 0x1000000;
if (mapping_start < 0) mapping_start = 0;
if (sizeof(void*) > 4)
// Large address space, use a 2 GB mapping
mapping_length = 0x80000000;
else
// Small (32 bit) address space, use a 256 MB mapping
mapping_length = 0x10000000;
// Make sure to always make a mapping at least as large as the requested range
if ((int64_t)mapping_length < range_length) {
if (range_length > (int64_t)(~(size_t)0))
throw AudioDecodeError("Requested range larger than max size_t, cannot create view of file");
mapping_length = range_length;
}
// But also make sure we don't try to make a mapping larger than the file
if (mapping_start + (int64_t)mapping_length > file_size)
mapping_length = (size_t)(file_size - mapping_start);
// We already checked that the requested range doesn't extend over the end of the file
// Hopefully this should ensure that small files are always mapped in their entirety
#ifdef _WIN32
LARGE_INTEGER mapping_start_li;
mapping_start_li.QuadPart = mapping_start;
current_mapping = MapViewOfFile(
file_mapping, // Mapping handle
FILE_MAP_READ, // Access type
mapping_start_li.HighPart, // Offset high-part
mapping_start_li.LowPart, // Offset low-part
mapping_length); // Length of view
#else
current_mapping = mmap(0, mapping_length, PROT_READ, MAP_PRIVATE, file_handle, mapping_start);
#endif
if (!current_mapping) {
throw AudioDecodeError("Failed mapping a view of the file");
}
}
assert(current_mapping);
assert(range_start >= mapping_start);
// Difference between actual current mapping start and requested range start
ptrdiff_t rel_ofs = (ptrdiff_t)(range_start - mapping_start);
// Calculate a pointer into current mapping for the requested range
return ((char*)current_mapping) + rel_ofs;
}
/// @brief DOCME
/// @param buf
/// @param start
/// @param count
///
void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const
{
// Read blocks from the file
size_t index = 0;
while (count > 0 && index < index_points.size()) {
// Check if this index contains the samples we're looking for
const IndexPoint &ip = index_points[index];
if (ip.start_sample <= start && ip.start_sample+ip.num_samples > start) {
// How many samples we can maximum take from this block
int64_t samples_can_do = ip.num_samples - start + ip.start_sample;
if (samples_can_do > count) samples_can_do = count;
// Read as many samples we can
char *src = EnsureRangeAccessible(
ip.start_byte + (start - ip.start_sample) * bytes_per_sample * channels,
samples_can_do * bytes_per_sample * channels);
memcpy(buf, src, samples_can_do * bytes_per_sample * channels);
// Update data
buf = (char*)buf + samples_can_do * bytes_per_sample * channels;
start += samples_can_do;
count -= samples_can_do;
}
index++;
}
// If we exhausted all sample sections zerofill the rest
if (count > 0) {
if (bytes_per_sample == 1)
// 8 bit formats are usually unsigned with bias 127
memset(buf, 127, count*channels);
else
// While everything else is signed
memset(buf, 0, count*bytes_per_sample*channels);
}
}
/// DOCME
/// @class RiffWavPCMAudioProvider
/// @brief RIFF WAV PCM provider
///
/// Overview of RIFF WAV: <http://www.sonicspot.com/guide/wavefiles.html>
class RiffWavPCMAudioProvider : public PCMAudioProvider {
/// DOCME
struct ChunkHeader {
/// Always "RIFF"
char type[4];
/// File size minus sizeof(ChunkHeader) (i.e. 8)
uint32_t size;
};
/// DOCME
struct RIFFChunk {
/// DOCME
ChunkHeader ch;
/// Always "WAVE"
char format[4];
};
/// DOCME
struct fmtChunk {
/// compression format used
/// We support only PCM (0x1)
uint16_t compression;
/// Number of channels
uint16_t channels;
/// Samples per second
uint32_t samplerate;
/// Bytes per second
/// can't always be trusted
uint32_t avg_bytes_sec;
/// Bytes per sample
uint16_t block_align;
/// Bits per sample that are actually used; rest should be ignored
uint16_t significant_bits_sample;
// Here was supposed to be some more fields but we don't need them
// and just skipping by the size of the struct wouldn't be safe
// either way, as the fields can depend on the compression.
};
/// @brief DOCME
/// @param str1[]
/// @param str2[]
/// @return
///
static bool CheckFourcc(const char str1[], const char str2[])
{
assert(str1);
assert(str2);
return
(str1[0] == str2[0]) &&
(str1[1] == str2[1]) &&
(str1[2] == str2[2]) &&
(str1[3] == str2[3]);
}
public:
/// @brief DOCME
/// @param _filename
///
RiffWavPCMAudioProvider(const std::string &_filename)
: PCMAudioProvider(_filename)
{
filename = _filename;
// Read header
void *filestart = EnsureRangeAccessible(0, sizeof(RIFFChunk));
RIFFChunk &header = *(RIFFChunk*)filestart;
// Check magic values
if (!CheckFourcc(header.ch.type, "RIFF"))
throw AudioOpenError("File is not a RIFF file");
if (!CheckFourcc(header.format, "WAVE"))
throw AudioOpenError("File is not a RIFF WAV file");
// Count how much more data we can have in the entire file
// The first 4 bytes are already eaten by the header.format field
uint32_t data_left = Endian::LittleToMachine(header.ch.size) - 4;
// How far into the file we have processed.
// Must be incremented by the riff chunk size fields.
uint32_t filepos = sizeof(header);
bool got_fmt_header = false;
// Inherited from AudioProvider
num_samples = 0;
// Continue reading chunks until out of data
while (data_left) {
ChunkHeader &ch = *(ChunkHeader*)EnsureRangeAccessible(filepos, sizeof(ChunkHeader));
// Update counters
data_left -= sizeof(ch);
filepos += sizeof(ch);
if (CheckFourcc(ch.type, "fmt ")) {
if (got_fmt_header) throw AudioOpenError("Invalid file, multiple 'fmt ' chunks");
got_fmt_header = true;
fmtChunk &fmt = *(fmtChunk*)EnsureRangeAccessible(filepos, sizeof(fmtChunk));
if (Endian::LittleToMachine(fmt.compression) != 1)
throw AudioOpenError("Can't use file, not PCM encoding");
// Set stuff inherited from the AudioProvider class
sample_rate = Endian::LittleToMachine(fmt.samplerate);
channels = Endian::LittleToMachine(fmt.channels);
bytes_per_sample = (Endian::LittleToMachine(fmt.significant_bits_sample) + 7) / 8; // round up to nearest whole byte
}
else if (CheckFourcc(ch.type, "data")) {
// This won't pick up 'data' chunks inside 'wavl' chunks
// since the 'wavl' chunks wrap those.
if (!got_fmt_header) throw AudioOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.");
int64_t samples = Endian::LittleToMachine(ch.size) / bytes_per_sample;
int64_t frames = samples / channels;
IndexPoint ip;
ip.start_sample = num_samples;
ip.num_samples = frames;
ip.start_byte = filepos;
index_points.push_back(ip);
num_samples += frames;
}
// Support wavl (wave list) chunks too?
// Update counters
// Make sure they're word aligned
data_left -= (Endian::LittleToMachine(ch.size) + 1) & ~1;
filepos += (Endian::LittleToMachine(ch.size) + 1) & ~1;
}
}
/// @brief DOCME
/// @return
///
bool AreSamplesNativeEndian() const
{
// 8 bit samples don't consider endianness
if (bytes_per_sample < 2) return true;
// Otherwise test whether we're little endian
uint32_t testvalue = 0x008800ff;
return testvalue == Endian::LittleToMachine(testvalue);
}
};
/// DOCME
static const uint8_t w64GuidRIFF[16] = {
// {66666972-912E-11CF-A5D6-28DB04C10000}
0x72, 0x69, 0x66, 0x66, 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
};
/// DOCME
static const uint8_t w64GuidWAVE[16] = {
// {65766177-ACF3-11D3-8CD1-00C04F8EDB8A}
0x77, 0x61, 0x76, 0x65, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
};
/// DOCME
static const uint8_t w64Guidfmt[16] = {
// {20746D66-ACF3-11D3-8CD1-00C04F8EDB8A}
0x66, 0x6D, 0x74, 0x20, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
};
/// DOCME
static const uint8_t w64Guiddata[16] = {
// {61746164-ACF3-11D3-8CD1-00C04F8EDB8A}
0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
};
/// DOCME
/// @class Wave64AudioProvider
/// @brief Sony Wave64 audio provider
///
/// http://www.vcs.de/fileadmin/user_upload/MBS/PDF/Whitepaper/Informations_about_Sony_Wave64.pdf
class Wave64AudioProvider : public PCMAudioProvider {
// Here's some copy-paste from the FFmpegSource2 code
/// http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx
struct WaveFormatEx {
uint16_t wFormatTag;
uint16_t nChannels;
uint32_t nSamplesPerSec;
uint32_t nAvgBytesPerSec;
uint16_t nBlockAlign;
uint16_t wBitsPerSample;
uint16_t cbSize;
};
/// DOCME
struct RiffChunk {
/// DOCME
uint8_t riff_guid[16];
/// DOCME
uint64_t file_size;
/// DOCME
uint8_t format_guid[16];
};
/// DOCME
struct FormatChunk {
/// DOCME
uint8_t chunk_guid[16];
/// DOCME
uint64_t chunk_size;
/// DOCME
WaveFormatEx format;
/// DOCME
uint8_t padding[6];
};
/// DOCME
struct DataChunk {
/// DOCME
uint8_t chunk_guid[16];
/// DOCME
uint64_t chunk_size;
};
/// @brief DOCME
/// @param guid1
/// @param guid2
/// @return
///
inline bool CheckGuid(const uint8_t *guid1, const uint8_t *guid2)
{
return memcmp(guid1, guid2, 16) == 0;
}
public:
/// @brief DOCME
/// @param _filename
///
Wave64AudioProvider(const std::string &_filename)
: PCMAudioProvider(_filename)
{
filename = _filename;
int64_t smallest_possible_file = sizeof(RiffChunk) + sizeof(FormatChunk) + sizeof(DataChunk);
if (file_size < smallest_possible_file)
throw AudioOpenError("File is too small to be a Wave64 file");
// Read header
// This should throw an exception if the mapping fails
void *filestart = EnsureRangeAccessible(0, sizeof(RiffChunk));
assert(filestart);
RiffChunk &header = *(RiffChunk*)filestart;
// Check magic values
if (!CheckGuid(header.riff_guid, w64GuidRIFF))
throw AudioOpenError("File is not a Wave64 RIFF file");
if (!CheckGuid(header.format_guid, w64GuidWAVE))
throw AudioOpenError("File is not a Wave64 WAVE file");
// Count how much more data we can have in the entire file
uint64_t data_left = Endian::LittleToMachine(header.file_size) - sizeof(RiffChunk);
// How far into the file we have processed.
// Must be incremented by the riff chunk size fields.
uint64_t filepos = sizeof(header);
bool got_fmt_header = false;
// Inherited from AudioProvider
num_samples = 0;
// Continue reading chunks until out of data
while (data_left) {
uint8_t *chunk_guid = (uint8_t*)EnsureRangeAccessible(filepos, 16);
uint64_t chunk_size = Endian::LittleToMachine(*(uint64_t*)EnsureRangeAccessible(filepos+16, sizeof(uint64_t)));
if (CheckGuid(chunk_guid, w64Guidfmt)) {
if (got_fmt_header)
throw AudioOpenError("Bad file, found more than one 'fmt' chunk");
FormatChunk &fmt = *(FormatChunk*)EnsureRangeAccessible(filepos, sizeof(FormatChunk));
got_fmt_header = true;
if (Endian::LittleToMachine(fmt.format.wFormatTag) == 3)
throw AudioOpenError("File is IEEE 32 bit float format which isn't supported. Bug the developers if this matters.");
if (Endian::LittleToMachine(fmt.format.wFormatTag) != 1)
throw AudioOpenError("Can't use file, not PCM encoding");
// Set stuff inherited from the AudioProvider class
sample_rate = Endian::LittleToMachine(fmt.format.nSamplesPerSec);
channels = Endian::LittleToMachine(fmt.format.nChannels);
bytes_per_sample = (Endian::LittleToMachine(fmt.format.wBitsPerSample) + 7) / 8; // round up to nearest whole byte
}
else if (CheckGuid(chunk_guid, w64Guiddata)) {
if (!got_fmt_header)
throw AudioOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.");
int64_t samples = chunk_size / bytes_per_sample;
int64_t frames = samples / channels;
IndexPoint ip;
ip.start_sample = num_samples;
ip.num_samples = frames;
ip.start_byte = filepos;
index_points.push_back(ip);
num_samples += frames;
}
// Update counters
// Make sure they're 64 bit aligned
data_left -= (chunk_size + 7) & ~7;
filepos += (chunk_size + 7) & ~7;
}
}
/// @brief DOCME
/// @return
///
bool AreSamplesNativeEndian() const
{
// 8 bit samples don't consider endianness
if (bytes_per_sample < 2) return true;
// Otherwise test whether we're little endian
uint32_t testvalue = 0x008800ff;
return testvalue == Endian::LittleToMachine(testvalue);
}
};
/// @brief DOCME
/// @param filename
///
AudioProvider *CreatePCMAudioProvider(const std::string &filename)
{
std::string msg;
try {
return new RiffWavPCMAudioProvider(filename);
}
catch (AudioOpenError const& err) {
msg = "RIFF PCM WAV audio provider: " + err.GetMessage();
}
try {
return new Wave64AudioProvider(filename);
}
catch (AudioOpenError const& err) {
msg += "\nWave64 audio provider: " + err.GetMessage();
throw AudioOpenError(msg);
}
}
} // namespace

View file

@ -1,117 +0,0 @@
// Copyright (c) 2007-2008, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_pcm.h
/// @see audio_provider_pcm.cpp
/// @ingroup audio_input
///
#ifndef AGI_PRE
#include <vector>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include "libmedia/audio.h"
namespace media {
/// DOCME
/// @class PCMAudioProvider
/// @brief DOCME
///
/// DOCME
class PCMAudioProvider : public AudioProvider {
private:
#ifdef _WIN32
/// DOCME
HANDLE file_handle;
/// DOCME
HANDLE file_mapping;
/// DOCME
mutable void *current_mapping;
/// DOCME
mutable int64_t mapping_start;
/// DOCME
mutable size_t mapping_length;
#else
int file_handle;
mutable void *current_mapping;
mutable off_t mapping_start;
mutable size_t mapping_length;
#endif
protected:
PCMAudioProvider(const std::string &filename); // Create base object and open the file mapping
virtual ~PCMAudioProvider(); // Closes the file mapping
char * EnsureRangeAccessible(int64_t range_start, int64_t range_length) const; // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range
/// DOCME
int64_t file_size; // Size of the opened file
/// DOCME
struct IndexPoint {
/// DOCME
int64_t start_byte;
/// DOCME
int64_t start_sample;
/// DOCME
int64_t num_samples;
};
/// DOCME
typedef std::vector<IndexPoint> IndexVector;
/// DOCME
IndexVector index_points;
public:
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
};
// Construct the right PCM audio provider (if any) for the file
AudioProvider *CreatePCMAudioProvider(const std::string &filename);
} // namespace

View file

@ -1,180 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_hd.cpp
/// @brief Caching audio provider using a file for backing
/// @ingroup audio_input
///
#include "config.h"
#ifndef AGI_PRE
#endif
#include <libaegisub/io.h>
#include "audio_hd.h"
namespace media {
/// @brief Constructor
/// @param source
///
HDAudioProvider::HDAudioProvider(AudioProvider *src, agi::ProgressSinkFactory *progress_factory) {
std::auto_ptr<AudioProvider> source(src);
// Copy parameters
bytes_per_sample = source->GetBytesPerSample();
num_samples = source->GetNumSamples();
channels = source->GetChannels();
sample_rate = source->GetSampleRate();
filename = source->GetFilename();
samples_native_endian = source->AreSamplesNativeEndian();
// Check free space
uint64_t freespace;
// XXX: fixme (add diskspace method to agi::util)
// if (wxGetDiskSpace(DiskCachePath(), NULL, &freespace)) {
// if (num_samples * channels * bytes_per_sample > freespace) {
// throw AudioOpenError("Not enough free disk space in " + STD_STR(DiskCachePath()) + " to cache the audio");
// }
// }
// Open output file
diskCacheFilename = DiskCacheName();
// file_cache.Create(diskCacheFilename,true,wxS_DEFAULT);
io::Save file(diskCacheFilename);
std::ofstream& file_cache = file.Get();
// file_cache.Open(diskCacheFilename,wxFile::read_write);
if (!file_cache.is_open()) throw AudioOpenError("Unable to write to audio disk cache.");
// Start progress
ProgressSink *progress = progress_factory->create_progress_sink("Reading to Hard Disk cache");
volatile bool canceled = progress->get_cancelled();
// Write to disk
int block = 4096;
data = new char[block * channels * bytes_per_sample];
for (int64_t i=0;i<num_samples && !canceled; i+=block) {
if (block+i > num_samples) block = num_samples - i;
source->GetAudio(data,i,block);
file_cache.write(data,block * channels * bytes_per_sample);
progress->set_progress(i,num_samples);
}
file_cache.seekp(0);
// Finish
if (canceled) {
// file_cache.Close();
delete[] data;
throw agi::UserCancelException("Audio loading cancelled by user");
}
delete progress;
}
/// @brief Destructor
///
HDAudioProvider::~HDAudioProvider() {
//XXX wxRemoveFile(diskCacheFilename);
delete[] data;
}
/// @brief Get audio
/// @param buf
/// @param start
/// @param count
///
void HDAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
// Requested beyond the length of audio
if (start+count > num_samples) {
int64_t oldcount = count;
count = num_samples-start;
if (count < 0) count = 0;
// Fill beyond with zero
if (bytes_per_sample == 1) {
char *temp = (char *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (count) {
diskmutex.Lock();
file_cache.seekp(start*bytes_per_sample);
file_cache.read((char*)buf,count*bytes_per_sample*channels);
}
}
/// @brief Get disk cache path
/// @return
///
std::string HDAudioProvider::DiskCachePath() {
// Default
/*
std::string path = lagi_wxString(OPT_GET("Audio/Cache/HD/Location")->GetString());
if (path == _T("default")) return StandardPaths::DecodePath(_T("?temp/"));
// Specified
return DecodeRelativePath(path,StandardPaths::DecodePath(_T("?user/")));
*/
return "XXX: fixme";
}
/// @brief Get disk cache filename
///
std::string HDAudioProvider::DiskCacheName() {
/*
XXX: fixme
// Get pattern
std::string pattern = lagi_wxString(OPT_GET("Audio/Cache/HD/Name")->GetString());
if (pattern.Find(_T("%02i")) == wxNOT_FOUND) pattern = _T("audio%02i.tmp");
// Try from 00 to 99
for (int i=0;i<100;i++) {
// File exists?
wxString curStringTry = DiskCachePath() + wxString::Format(pattern.c_str(),i);
if (!wxFile::Exists(curStringTry)) return curStringTry;
}
*/
return "";
}
} // namespace media

View file

@ -1,78 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_hd.h
/// @see audio_provider_hd.cpp
/// @ingroup audio_input
///
#ifndef AGI_PRE
#endif
#include <libaegisub/mutex.h>
#include "libmedia/audio.h"
namespace media {
/// DOCME
/// @class HDAudioProvider
/// @brief DOCME
///
/// DOCME
class HDAudioProvider : public AudioProvider {
/// DOCME
mutable agi::Mutex diskmutex;
/// DOCME
mutable std::fstream file_cache;
/// DOCME
std::string diskCacheFilename;
/// DOCME
bool samples_native_endian;
/// DOCME
char *data;
static std::string DiskCachePath();
static std::string DiskCacheName();
public:
HDAudioProvider(AudioProvider *source, agi::ProgressSinkFactory *progress_factory);
~HDAudioProvider();
bool AreSamplesNativeEndian() const { return samples_native_endian; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
};
} // namespace media

View file

@ -1,179 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_ram.cpp
/// @brief Caching audio provider using heap memory for backing
/// @ingroup audio_input
///
#include "config.h"
#include "audio_ram.h"
//#include "dialog_progress.h"
//#include "frame_main.h"
//#include "main.h"
//#include "utils.h"
namespace media {
/// DOCME
#define CacheBits ((22))
/// DOCME
#define CacheBlockSize ((1 << CacheBits))
/// @brief Constructor
/// @param source
///
RAMAudioProvider::RAMAudioProvider(AudioProvider *src) {
std::auto_ptr<AudioProvider> source(src);
// Init
blockcache = NULL;
blockcount = 0;
samples_native_endian = source->AreSamplesNativeEndian();
// Allocate cache
int64_t ssize = source->GetNumSamples() * source->GetBytesPerSample();
blockcount = (ssize + CacheBlockSize - 1) >> CacheBits;
blockcache = new char*[blockcount];
for (int i = 0; i < blockcount; i++) {
blockcache[i] = NULL;
}
// Allocate cache blocks
try {
for (int i = 0; i < blockcount; i++) {
blockcache[i] = new char[std::min<size_t>(CacheBlockSize,ssize-i*CacheBlockSize)];
}
}
catch (...) {
Clear();
throw AudioOpenError("Couldn't open audio, not enough ram available.");
}
// Copy parameters
bytes_per_sample = source->GetBytesPerSample();
num_samples = source->GetNumSamples();
channels = source->GetChannels();
sample_rate = source->GetSampleRate();
filename = source->GetFilename();
// Start progress
//XXX fixme:
volatile bool canceled = false;
// DialogProgress *progress = new DialogProgress(AegisubApp::Get()->frame,_("Load audio"),&canceled,_("Reading into RAM"),0,source->GetNumSamples());
// progress->Show();
// progress->SetProgress(0,1);
// Read cache
int readsize = CacheBlockSize / source->GetBytesPerSample();
for (int i=0;i<blockcount && !canceled; i++) {
source->GetAudio((char*)blockcache[i],i*readsize, i == blockcount-1 ? (source->GetNumSamples() - i*readsize) : readsize);
// progress->SetProgress(i,blockcount-1);
}
// Clean up progress
if (canceled) {
Clear();
throw agi::UserCancelException("Audio loading cancelled by user");
}
// progress->Destroy();
}
/// @brief Destructor
///
RAMAudioProvider::~RAMAudioProvider() {
Clear();
}
/// @brief Clear
///
void RAMAudioProvider::Clear() {
// Free ram cache
if (blockcache) {
for (int i = 0; i < blockcount; i++) {
delete [] blockcache[i];
}
delete [] blockcache;
}
blockcache = NULL;
blockcount = 0;
}
/// @brief Get audio
/// @param buf
/// @param start
/// @param count
///
void RAMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
// Requested beyond the length of audio
if (start+count > num_samples) {
int64_t oldcount = count;
count = num_samples-start;
if (count < 0) count = 0;
// Fill beyond with zero
if (bytes_per_sample == 1) {
char *temp = (char *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (count) {
// Prepare copy
char *charbuf = (char *)buf;
int i = (start*bytes_per_sample) >> CacheBits;
int start_offset = (start*bytes_per_sample) & (CacheBlockSize-1);
int64_t bytesremaining = count*bytes_per_sample;
// Copy
while (bytesremaining) {
int readsize = std::min<int>(bytesremaining, CacheBlockSize - start_offset);
memcpy(charbuf,(char *)(blockcache[i++]+start_offset),readsize);
charbuf+=readsize;
start_offset=0;
bytesremaining-=readsize;
}
}
}
} // namespace media

View file

@ -1,65 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider_ram.h
/// @see audio_provider_ram.cpp
/// @ingroup audio_input
///
#include "libmedia/audio.h"
namespace media {
/// DOCME
/// @class RAMAudioProvider
/// @brief DOCME
///
/// DOCME
class RAMAudioProvider : public AudioProvider {
/// DOCME
char** blockcache;
/// DOCME
int blockcount;
/// DOCME
bool samples_native_endian;
void Clear();
public:
RAMAudioProvider(AudioProvider *source);
~RAMAudioProvider();
bool AreSamplesNativeEndian() const { return samples_native_endian; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
};
} // namespace media

View file

@ -1,129 +0,0 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_cache.cpp
/// @brief Aggregate video provider caching previously requested frames
/// @ingroup video_input
///
#include "config.h"
//#include "main.h"
#include "video_cache.h"
namespace media {
/// DOCME
/// @class CachedFrame
/// @brief DOCME
///
/// DOCME
struct CachedFrame {
/// DOCME
AegiVideoFrame frame;
/// DOCME
int n;
};
/// @brief Constructor
/// @param parent
///
VideoProviderCache::VideoProviderCache(VideoProvider *parent)
: master(parent)
//XXX: , cacheMax(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes
{
}
/// @brief Destructor
///
VideoProviderCache::~VideoProviderCache() {
while (cache.size()) {
cache.front().frame.Clear();
cache.pop_front();
}
}
/// @brief Get frame
/// @param n
/// @return
///
const AegiVideoFrame VideoProviderCache::GetFrame(int n) {
// See if frame is cached
CachedFrame cached;
for (std::list<CachedFrame>::iterator cur=cache.begin();cur!=cache.end();cur++) {
cached = *cur;
if (cached.n == n) {
cache.erase(cur);
cache.push_back(cached);
return cached.frame;
}
}
// Not cached, retrieve it
const AegiVideoFrame frame = master->GetFrame(n);
const AegiVideoFrame *srcFrame = &frame;
// Cache frame
Cache(n,*srcFrame);
return *srcFrame;
}
/// @brief Add to cache
/// @param n
/// @param frame
void VideoProviderCache::Cache(int n,const AegiVideoFrame frame) {
// Cache full, use frame at front
if (GetCurCacheSize() >= cacheMax) {
cache.push_back(cache.front());
cache.pop_front();
}
// Cache not full, insert new one
else {
cache.push_back(CachedFrame());
}
// Cache
cache.back().n = n;
cache.back().frame.CopyFrom(frame);
}
/// @brief Get the current size of the cache
/// @return Returns the size in bytes
unsigned VideoProviderCache::GetCurCacheSize() {
int sz = 0;
for (std::list<CachedFrame>::iterator i = cache.begin(); i != cache.end(); i++)
sz += i->frame.memSize;
return sz;
}
} // namespace media

View file

@ -1,86 +0,0 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_cache.h
/// @see video_provider_cache.cpp
/// @ingroup video_input
///
#ifndef AGI_PRE
#include <list>
#include <memory>
#endif
#include "libmedia/video.h"
namespace media {
struct CachedFrame;
/// DOCME
/// @class VideoProviderCache
/// @brief DOCME
///
/// DOCME
class VideoProviderCache : public VideoProvider {
/// DOCME
std::auto_ptr<VideoProvider> master;
/// DOCME
unsigned int cacheMax;
/// DOCME
std::list<CachedFrame> cache;
void Cache(int n,const AegiVideoFrame frame);
AegiVideoFrame GetCachedFrame(int n);
// Cache functions
unsigned GetCurCacheSize();
public:
// Base methods
const AegiVideoFrame GetFrame(int n);
VideoProviderCache(VideoProvider *master);
virtual ~VideoProviderCache();
// Override the following methods:
virtual int GetPosition() const { return master->GetPosition(); }
virtual int GetFrameCount() const { return master->GetFrameCount(); }
virtual int GetWidth() const { return master->GetWidth(); }
virtual int GetHeight() const { return master->GetHeight(); }
virtual agi::vfr::Framerate GetFPS() const { return master->GetFPS(); }
virtual std::vector<int> GetKeyFrames() const { return master->GetKeyFrames(); }
virtual std::string GetWarning() const { return master->GetWarning(); }
virtual std::string GetDecoderName() const { return master->GetDecoderName(); }
};
} // namespace media

View file

@ -1,193 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider.cpp
/// @brief Baseclass for audio providers
/// @ingroup audio_input
///
#include "config.h"
#ifndef AGI_PRE
#endif
#ifdef WITH_AVISYNTH
#include "../audio/avs_audio.h"
#endif
#include "../audio/convert.h"
#ifdef WITH_FFMPEGSOURCE
#include "../audio/ffms_audio.h"
#endif
#include "../cache/audio_hd.h"
#include "../cache/audio_ram.h"
#include "../audio/pcm.h"
//#include "compat.h"
//#include "main.h"
namespace media {
/// @brief Constructor
///
AudioProvider::AudioProvider() : raw(NULL) {
}
/// @brief Destructor
///
AudioProvider::~AudioProvider() {
delete[] raw;
}
/// @brief Get audio with volume
/// @param buf
/// @param start
/// @param count
/// @param volume
/// @return
///
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
try {
GetAudio(buf,start,count);
}
catch (...) {
// FIXME: Poor error handling though better than none, to patch issue #800.
// Just return blank audio if real provider fails.
memset(buf, 0, count*bytes_per_sample);
return;
}
if (volume == 1.0) return;
if (bytes_per_sample == 2) {
// Read raw samples
short *buffer = (short*) buf;
int value;
// Modify
for (int64_t i=0;i<count;i++) {
value = (int)(buffer[i]*volume+0.5);
if (value < -0x8000) value = -0x8000;
if (value > 0x7FFF) value = 0x7FFF;
buffer[i] = value;
}
}
}
/// @brief Get provider
/// @param filename
/// @param cache
/// @return
///
AudioProvider *AudioProviderFactory::GetProvider(std::string filename, agi::ProgressSinkFactory *progress_factory, int cache) {
AudioProvider *provider = NULL;
bool found = false;
std::string msg;
//XXX if (!OPT_GET("Provider/Audio/PCM/Disable")->GetBool()) {
if (1) {
// Try a PCM provider first
try {
provider = CreatePCMAudioProvider(filename);
}
catch (agi::FileNotFoundError const& err) {
msg = "PCM audio provider: " + err.GetMessage() + " not found.\n";
}
catch (AudioOpenError const& err) {
found = true;
msg += err.GetMessage();
}
}
if (!provider) {
//XXX std::vector<std::string> list = GetClasses(OPT_GET("Audio/Provider")->GetString());
std::vector<std::string> list = GetClasses("ffmpegsource");
if (list.empty()) throw AudioOpenError("No audio providers are available.");
for (unsigned int i=0;i<list.size();i++) {
try {
provider = Create(list[i], filename);
if (provider) break;
}
catch (agi::FileNotFoundError const& err) {
msg += list[i] + ": " + err.GetMessage() + " not found.\n";
}
catch (AudioOpenError const& err) {
found = true;
msg += list[i] + ": " + err.GetMessage();
}
}
}
if (!provider) {
if (found) {
throw AudioOpenError(msg);
}
else {
throw agi::FileNotFoundError(filename);
}
}
bool needsCache = provider->NeedsCache();
// Give it a converter if needed
if (provider->GetBytesPerSample() != 2 || provider->GetSampleRate() < 32000 || provider->GetChannels() != 1)
provider = CreateConvertAudioProvider(provider);
// Change provider to RAM/HD cache if needed
//XXX if (cache == -1) cache = OPT_GET("Audio/Cache/Type")->GetInt();
if (cache == -1) cache = 1;
if (!cache || !needsCache) {
return provider;
}
// Convert to RAM
if (cache == 1) return new RAMAudioProvider(provider);
// Convert to HD
if (cache == 2) return new HDAudioProvider(provider, progress_factory);
throw AudioOpenError("Unknown caching method");
}
/// @brief Register all providers
///
void AudioProviderFactory::RegisterProviders() {
#ifdef WITH_AVISYNTH
Register<AvisynthAudioProvider>("Avisynth");
#endif
#ifdef WITH_FFMPEGSOURCE
Register<ffms::FFmpegSourceAudioProvider>("FFmpegSource");
#endif
}
template<> AudioProviderFactory::map *FactoryBase<AudioProvider *(*)(std::string)>::classes = NULL;
} // namespace media

View file

@ -1,499 +0,0 @@
// Copyright (c) 2005, Niels Martin Hansen, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file colorspace.cpp
/// @brief Functions for converting colours between different representations
/// @ingroup utility
///
#include "config.h"
#include "libmedia/colourspace.h"
//#include "utils.h"
namespace media {
/// @brief matrix from http://forum.doom9.org/showthread.php?p=684080#post684080
/// @param Y
/// @param U
/// @param V
/// @param R
/// @param G
/// @param B
///
void yuv_to_rgb(int Y, int U, int V, unsigned char *R, unsigned char *G, unsigned char *B)
{
U = U - 128;
V = V - 128;
*R = clip_colorval((Y*65536 + int(1.140*65536) * V) / 65536);
*G = clip_colorval((Y*65536 - int(0.395*65536) * U - int(0.581*65536) * V) / 65536);
*B = clip_colorval((Y*65536 + int(2.032*65536) * U ) / 65536);
}
/// @brief making every value into 0..255 range though algorithm from http://130.113.54.154/~monger/hsl-rgb.html
/// @param H
/// @param S
/// @param L
/// @param R
/// @param G
/// @param B
/// @return
///
void hsl_to_rgb(int H, int S, int L, unsigned char *R, unsigned char *G, unsigned char *B)
{
if (S == 0) {
*R = L;
*G = L;
*B = L;
return;
}
if (L == 128 && S == 255) {
switch (H) {
case 0:
case 255: // actually this is wrong, since this is more like 359 degrees... but it's what you'd expect (sadly :)
*R = 255;
*G = 0;
*B = 0;
return;
case 43:
*R = 255;
*G = 255;
*B = 0;
return;
case 85:
*R = 0;
*G = 255;
*B = 0;
return;
case 128:
*R = 0;
*G = 255;
*B = 255;
return;
case 171:
*R = 0;
*G = 0;
*B = 255;
return;
case 213:
*R = 255;
*G = 0;
*B = 255;
return;
}
}
float h, s, l, r, g, b;
h = H / 255.f;
s = S / 255.f;
l = L / 255.f;
float temp2;
if (l < .5) {
temp2 = l * (1. + s);
} else {
temp2 = l + s - l*s;
}
float temp1 = 2.f * l - temp2;
// assume h is in range [0;1]
float temp3[3];
temp3[0] = h + 1.f/3.f;
if (temp3[0] > 1.f) temp3[0] -= 1.f;
temp3[1] = h;
temp3[2] = h - 1.f/3.f;
if (temp3[2] < 0.f) temp3[2] += 1.f;
if (6.f * temp3[0] < 1.f)
r = temp1 + (temp2 - temp1) * 6.f * temp3[0];
else if (2.f * temp3[0] < 1.f)
r = temp2;
else if (3.f * temp3[0] < 2.f)
r = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[0]) * 6.f;
else
r = temp1;
if (6.f * temp3[1] < 1.f)
g = temp1 + (temp2 - temp1) * 6.f * temp3[1];
else if (2.f * temp3[1] < 1.f)
g = temp2;
else if (3.f * temp3[1] < 2.f)
g = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[1]) * 6.f;
else
g = temp1;
if (6.f * temp3[2] < 1.f)
b = temp1 + (temp2 - temp1) * 6.f * temp3[2];
else if (2.f * temp3[2] < 1.f)
b = temp2;
else if (3.f * temp3[2] < 2.f)
b = temp1 + (temp2 - temp1) * ((2.f/3.f) - temp3[2]) * 6.f;
else
b = temp1;
*R = clip_colorval((int)(r*255));
*G = clip_colorval((int)(g*255));
*B = clip_colorval((int)(b*255));
}
/// @brief the range for H is 0..255 instead of 0..359, so 60 degrees has been translated to 256/6 here formulas taken from wikipedia: http://en.wikipedia.org/wiki/HSV_color_space
/// @param H
/// @param S
/// @param V
/// @param R
/// @param G
/// @param B
/// @return
///
void hsv_to_rgb(int H, int S, int V, unsigned char *R, unsigned char *G, unsigned char *B)
{
*R = *G = *B = 0;
// some special cases... oh yeah baby!
if (S == 255) {
switch (H) {
case 0:
case 255: // actually this is wrong, since this is more like 359 degrees... but it's what you'd expect (sadly :)
*R = V;
*G = 0;
*B = 0;
return;
case 43:
*R = V;
*G = V;
*B = 0;
return;
case 85:
*R = 0;
*G = V;
*B = 0;
return;
case 128:
*R = 0;
*G = V;
*B = V;
return;
case 171:
*R = 0;
*G = 0;
*B = V;
return;
case 213:
*R = V;
*G = 0;
*B = V;
return;
}
}
// Cap values
unsigned int h = H * 360;
unsigned int s = clip_colorval(S)*256;
unsigned int v = clip_colorval(V)*256;
// Saturation is zero, make grey
if (S == 0) {
*R = V;
*G = V;
*B = V;
return;
}
unsigned int r, g, b;
// Else, calculate color
unsigned int Hi = h / 60 / 256;
unsigned int f = h / 60 - Hi * 256;
unsigned int p = v * (65535 - s) / 65536;
unsigned int q = v * (65535 - (f * s)/256) / 65536;
unsigned int t = v * (65535 - ((255 - f) * s)/256) / 65536;
switch (Hi) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
default:
r = v;
g = p;
b = q;
break;
}
*R = clip_colorval(r/256);
*G = clip_colorval(g/256);
*B = clip_colorval(b/256);
}
/// @brief matrix from http://forum.doom9.org/showthread.php?p=684080#post684080
/// @param R
/// @param G
/// @param B
/// @param Y
/// @param U
/// @param V
///
void rgb_to_yuv(int R, int G, int B, unsigned char *Y, unsigned char *U, unsigned char *V)
{
*Y = clip_colorval(( int(0.299*65536) * R + int(0.587*65536) * G + int(0.114*65536) * B) / 65536);
*U = clip_colorval((-int(0.147*65536) * R - int(0.289*65536) * G + int(0.436*65536) * B) / 65536 + 128);
*V = clip_colorval(( int(0.615*65536) * R - int(0.515*65536) * G - int(0.100*65536) * B) / 65536 + 128);
}
/// @brief still keeping everything integer also from http://130.113.54.154/~monger/hsl-rgb.html
/// @param R
/// @param G
/// @param B
/// @param H
/// @param S
/// @param L
///
void rgb_to_hsl(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *L)
{
float r = R/255.f, g = G/255.f, b = B/255.f;
float h, s, l;
float maxrgb = std::max(r, std::max(g, b)), minrgb = std::min(r, std::min(g, b));
l = (minrgb + maxrgb) / 2;
if (minrgb == maxrgb) {
h = 0;
s = 0;
} else {
if (l < 0.5) {
s = (maxrgb - minrgb) / (maxrgb + minrgb);
} else {
s = (maxrgb - minrgb) / (2.f - maxrgb - minrgb);
}
if (r == maxrgb) {
h = (g-b) / (maxrgb-minrgb) + 0;
} else if (g == maxrgb) {
h = (b-r) / (maxrgb-minrgb) + 2;
} else { // if b == maxrgb
h = (r-g) / (maxrgb-minrgb) + 4;
}
}
if (h < 0) h += 6;
if (h >= 6) h -= 6;
*H = clip_colorval(int(h*256/6));
*S = clip_colorval(int(s*255));
*L = clip_colorval(int(l*255));
}
/// @brief formulas from http://en.wikipedia.org/wiki/HSV_color_space
/// @param R
/// @param G
/// @param B
/// @param H
/// @param S
/// @param V
///
void rgb_to_hsv(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *V)
{
float r = R/255.f, g = G/255.f, b = B/255.f;
float h, s, v;
float maxrgb = std::max(r, std::max(g, b)), minrgb = std::min(r, std::min(g, b));
v = maxrgb;
if (maxrgb < .001f) {
s = 1;
} else {
s = (maxrgb - minrgb) / maxrgb;
}
if (minrgb == maxrgb) {
h = 0;
} else if (maxrgb == r) {
h = (g-b) / (maxrgb-minrgb) + 0;
} else if (maxrgb == g) {
h = (b-r) / (maxrgb-minrgb) + 2;
} else { // if maxrgb == b
h = (r-g) / (maxrgb-minrgb) + 4;
}
if (h < 0) h += 6;
if (h >= 6) h -= 6;
*H = clip_colorval(int(h*256/6));
*S = clip_colorval(int(s*255));
*V = clip_colorval(int(v*255));
}
/// @brief DOCME
/// @param iH
/// @param iS
/// @param iV
/// @param oH
/// @param oS
/// @param oL
///
void hsv_to_hsl(int iH, int iS, int iV, unsigned char *oH, unsigned char *oS, unsigned char *oL)
{
int p = iV * (255 - iS);
*oH = iH;
*oL = clip_colorval((p + iV*255)/255/2);
if (*oL == 0) {
*oS = iS; // oS is actually undefined, so any value should work ;)
} else if (*oL <= 128) {
*oS = clip_colorval((iV*255 - p) / (2 * *oL));
} else {
*oS = clip_colorval((iV*255 - p) / (511 - 2 * *oL));
}
}
/// @brief DOCME
/// @param iH
/// @param iS
/// @param iL
/// @param oH
/// @param oS
/// @param oV
/// @return
///
void hsl_to_hsv(int iH, int iS, int iL, unsigned char *oH, unsigned char *oS, unsigned char *oV)
{
*oH = iH;
if (iS == 0) {
*oS = 0;
*oV = iL;
return;
}
if (iL < 128) {
*oV = iL * (255 + iS) / 255;
*oS = 2 * 255 * iS / (255 + iS);
} else {
*oV = (iL*255 + iS*255 - iL*iS)/255;
*oS = 2 * 255 * iS * (255 - iL) / (iL*255 + iS*255 - iL*iS);
}
}
/// @brief DOCME
/// @param color
/// @return
///
std::string color_to_html(agi::Colour color)
{
// return wxString::Format(_T("#%02X%02X%02X"), color.Red(), color.Green(), color.Blue());
return "broken";
}
/// @brief DOCME
/// @param html
///
std::string html_to_color(agi::Colour html)
{
/*
html.Trim(true);
html.Trim(false);
if (html.StartsWith(_T("#"))) {
html.Remove(0, 1);
}
if (html.size() == 6) {
// 8 bit per channel
long r, g, b;
wxString sr, sg, sb;
sr = html.Mid(0, 2);
sg = html.Mid(2, 2);
sb = html.Mid(4, 2);
if (sr.ToLong(&r, 16) && sg.ToLong(&g, 16) && sb.ToLong(&b, 16)) {
return wxColour(r, g, b);
} else {
return wxColour(*wxBLACK);
}
} else if (html.size() == 3) {
// 4 bit per channel
long r, g, b;
wxString sr, sg, sb;
sr = html.Mid(0, 1);
sg = html.Mid(1, 1);
sb = html.Mid(2, 1);
if (sr.ToLong(&r, 16) && sg.ToLong(&g, 16) && sb.ToLong(&b, 16)) {
return wxColour(r*16+r, g*16+g, b*16+b);
} else {
return wxColour(*wxBLACK);
}
} else {
// only care about valid colors
return wxColour(*wxBLACK);
}
*/
return "XXX: fixme";
}
} // namespace media

View file

@ -1,270 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file ffmpegsource_common.cpp
/// @brief Shared code for ffms video and audio providers
/// @ingroup video_input audio_input ffms
///
#include "config.h"
#ifdef WITH_FFMPEGSOURCE
#ifndef AGI_PRE
#include <inttypes.h>
#include <map>
//#include <wx/dir.h>
//#include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
#endif
#include <libaegisub/log.h>
#include "ffms_common.h"
//#include "compat.h"
//#include "ffmpegsource_common.h"
//#include "frame_main.h"
//#include "main.h"
//#include "md5.h"
//#include "standard_paths.h"
namespace media {
namespace ffms {
/// @brief Callback function that updates the indexing progress dialog
/// @param Current The current file positition in bytes
/// @param Total The total file size in bytes
/// @param Private A pointer to the progress dialog box to update
/// @return Returns non-0 if indexing is cancelled, 0 otherwise.
///
int FFMS_CC FFmpegSourceProvider::UpdateIndexingProgress(int64_t Current, int64_t Total, void *Private) {
IndexingProgressDialog *Progress = (IndexingProgressDialog *)Private;
if (Progress->IndexingCanceled)
return 1;
// no one cares about a little bit of a rounding error here anyway
// Progress->ProgressDialog->SetProgress(((int64_t)1000*Current)/Total, 1000);
return 0;
}
/// @brief Does indexing of a source file
/// @param Indexer A pointer to the indexer object representing the file to be indexed
/// @param CacheName The filename of the output index file
/// @param Trackmask A binary mask of the track numbers to index
/// @param IgnoreDecodeErrors True if audio decoding errors will be tolerated, false otherwise
/// @return Returns the index object on success, NULL otherwise
///
FFMS_Index *FFmpegSourceProvider::DoIndexing(FFMS_Indexer *Indexer, const std::string &CacheName, int Trackmask, FFMS_IndexErrorHandling IndexEH) {
char FFMSErrMsg[1024];
FFMS_ErrorInfo ErrInfo;
ErrInfo.Buffer = FFMSErrMsg;
ErrInfo.BufferSize = sizeof(FFMSErrMsg);
ErrInfo.ErrorType = FFMS_ERROR_SUCCESS;
ErrInfo.SubType = FFMS_ERROR_SUCCESS;
std::string MsgString;
/*
// set up progress dialog callback
IndexingProgressDialog Progress;
Progress.IndexingCanceled = false;
Progress.ProgressDialog = new DialogProgress(AegisubApp::Get()->frame,
_("Indexing"), &Progress.IndexingCanceled,
_("Reading timecodes and frame/sample data"), 0, 1);
Progress.ProgressDialog->Show();
Progress.ProgressDialog->SetProgress(0,1);
// index all audio tracks
FFMS_Index *Index = FFMS_DoIndexing(Indexer, Trackmask, FFMS_TRACKMASK_NONE, NULL, NULL, IndexEH,
FFmpegSourceProvider::UpdateIndexingProgress, &Progress, &ErrInfo);
Progress.ProgressDialog->Destroy();
if (Progress.IndexingCanceled) {
throw agi::UserCancelException("indexing cancelled by user");
}
if (Index == NULL) {
MsgString.append("Failed to index: ").append(ErrInfo.Buffer);
throw MsgString;
}
// write index to disk for later use
// ignore write errors for now
FFMS_WriteIndex(CacheName.c_str(), Index, &ErrInfo);
// if (FFMS_WriteIndex(CacheName.char_str(), Index, FFMSErrMsg, MsgSize)) {
// wxString temp(FFMSErrMsg, wxConvUTF8);
// MsgString << _T("Failed to write index: ") << temp;
// throw MsgString;
// }
*/
FFMS_Index *Index;
return Index;
}
/// @brief Finds all tracks of the given type and return their track numbers and respective codec names
/// @param Indexer The indexer object representing the source file
/// @param Type The track type to look for
/// @return Returns a std::map with the track numbers as keys and the codec names as values.
std::map<int,std::string> FFmpegSourceProvider::GetTracksOfType(FFMS_Indexer *Indexer, FFMS_TrackType Type) {
std::map<int,std::string> TrackList;
int NumTracks = FFMS_GetNumTracksI(Indexer);
for (int i=0; i<NumTracks; i++) {
if (FFMS_GetTrackTypeI(Indexer, i) == Type) {
std::string CodecName(FFMS_GetCodecNameI(Indexer, i));
TrackList.insert(std::pair<int,std::string>(i, CodecName));
}
}
return TrackList;
}
/// @brief Ask user for which track he wants to load
/// @param TrackList A std::map with the track numbers as keys and codec names as values
/// @param Type The track type to ask about
/// @return Returns the track number chosen (an integer >= 0) on success, or a negative integer if the user cancelled.
int FFmpegSourceProvider::AskForTrackSelection(const std::map<int,std::string> &TrackList, FFMS_TrackType Type) {
/*
std::vector<int> TrackNumbers;
wxArrayString Choices;
std::string TypeName = "";
if (Type == FFMS_TYPE_VIDEO)
TypeName = _("video");
else if (Type == FFMS_TYPE_AUDIO)
TypeName = _("audio");
for (std::map<int,std::string>::const_iterator i = TrackList.begin(); i != TrackList.end(); i++) {
istream str;
//XXX Choices.Add(ng::Format(_("Track %02d: %s"), i->first, i->second.c_str()));
TrackNumbers.push_back(i->first);
}
int Choice = wxGetSingleChoiceIndex(wxString::Format(_("Multiple %s tracks detected, please choose the one you wish to load:"), TypeName.c_str()),
wxString::Format(_("Choose %s track"), TypeName.c_str()), Choices);
if (Choice < 0)
return Choice;
else
return TrackNumbers[Choice];
*/
}
/// @brief Set ffms2 log level according to setting in config.dat
void FFmpegSourceProvider::SetLogLevel() {
/*
wxString LogLevel = lagi_wxString(OPT_GET("Provider/FFmpegSource/Log Level")->GetString());
if (!LogLevel.CmpNoCase("panic"))
FFMS_SetLogLevel(FFMS_LOG_PANIC);
else if (!LogLevel.CmpNoCase("fatal"))
FFMS_SetLogLevel(FFMS_LOG_FATAL);
else if (!LogLevel.CmpNoCase("error"))
FFMS_SetLogLevel(FFMS_LOG_ERROR);
else if (!LogLevel.CmpNoCase("warning"))
FFMS_SetLogLevel(FFMS_LOG_WARNING);
else if (!LogLevel.CmpNoCase("info"))
FFMS_SetLogLevel(FFMS_LOG_INFO);
else if (!LogLevel.CmpNoCase("verbose"))
FFMS_SetLogLevel(FFMS_LOG_VERBOSE);
else if (!LogLevel.CmpNoCase("debug"))
FFMS_SetLogLevel(FFMS_LOG_DEBUG);
else */
FFMS_SetLogLevel(FFMS_LOG_QUIET);
}
FFMS_IndexErrorHandling FFmpegSourceProvider::GetErrorHandlingMode() {
// std::string Mode = lagi_wxString(OPT_GET("Provider/Audio/FFmpegSource/Decode Error Handling")->GetString());
std::string mode = "ignore";
if (mode == "ignore")
return FFMS_IEH_IGNORE;
else if (mode == "clear")
return FFMS_IEH_CLEAR_TRACK;
else if (mode == "stop")
return FFMS_IEH_STOP_TRACK;
else if (mode == "abort")
return FFMS_IEH_ABORT;
else
return FFMS_IEH_STOP_TRACK; // questionable default?
}
#include <inttypes.h>
/// @brief Generates an unique name for the ffms2 index file and prepares the cache folder if it doesn't exist
/// @param filename The name of the source file
/// @return Returns the generated filename.
std::string FFmpegSourceProvider::GetCacheFilename(const std::string& _filename)
{
/*
// Get the size of the file to be hashed
wxFileOffset len = 0;
{
wxFile file(_filename,wxFile::read);
if (file.IsOpened()) len = file.Length();
}
wxFileName filename(_filename);
// Generate string to be hashed
// std::string toHash = wxString::Format("%s %" PRId64 " %" PRId64, filename.GetFullName(), len, (int64_t)filename.GetModificationTime().GetTicks());
std::string toHash = "XXX";
// Get the MD5 digest of the string
const wchar_t *tmp = toHash.wc_str();
md5_state_t state;
md5_byte_t digest[16];
md5_init(&state);
md5_append(&state,(md5_byte_t*)tmp,toHash.Length()*sizeof(wchar_t));
md5_finish(&state,digest);
// Generate the filename
unsigned int *md5 = (unsigned int*) digest;
wxString result = wxString::Format("?user/ffms2cache/%08X%08X%08X%08X.ffindex",md5[0],md5[1],md5[2],md5[3]);
result = StandardPaths::DecodePath(result);
// Ensure that folder exists
wxFileName fn(result);
wxString dir = fn.GetPath();
if (!wxFileName::DirExists(dir)) {
wxFileName::Mkdir(dir);
}
wxFileName dirfn(dir);
return dirfn.GetShortPath() + "/" + fn.GetFullName();
*/
return "XXX";
}
#endif // WITH_FFMPEGSOURCE
} // namespace ffms
} // namespace media

View file

@ -1,96 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file ffmpegsource_common.h
/// @see ffmpegsource_common.cpp
/// @ingroup video_input audio_input ffms
///
#ifdef WITH_FFMPEGSOURCE
#ifndef AGI_PRE
#include <map>
//#include <wx/filename.h>
//#include <wx/thread.h>
#endif
#include "../../libffms/include/ffms.h"
namespace media {
namespace ffms {
//#include "dialog_progress.h"
/// Index all tracks
#define FFMS_TRACKMASK_ALL -1
/// Index no tracks
#define FFMS_TRACKMASK_NONE 0
/// @class FFmpegSourceProvider
/// @brief Base class for FFMS2 source providers; contains common functions etc
class FFmpegSourceProvider {
public:
/// Logging level constants from avutil/log.h
enum FFMS_LogLevel {
/// nothing printed
FFMS_LOG_QUIET = -8,
FFMS_LOG_PANIC = 0,
FFMS_LOG_FATAL = 8,
FFMS_LOG_ERROR = 16,
FFMS_LOG_WARNING = 24,
FFMS_LOG_INFO = 32,
FFMS_LOG_VERBOSE = 40,
FFMS_LOG_DEBUG = 48,
};
/// Indexing progress report dialog
struct IndexingProgressDialog {
volatile bool IndexingCanceled;
// DialogProgress *ProgressDialog;
};
static int FFMS_CC UpdateIndexingProgress(int64_t Current, int64_t Total, void *Private);
FFMS_Index *DoIndexing(FFMS_Indexer *Indexer, const std::string& Cachename, int Trackmask, FFMS_IndexErrorHandling IndexEH);
std::map<int,std::string> GetTracksOfType(FFMS_Indexer *Indexer, FFMS_TrackType Type);
int AskForTrackSelection(const std::map<int,std::string>& TrackList, FFMS_TrackType Type);
std::string GetCacheFilename(const std::string& filename);
void SetLogLevel();
FFMS_IndexErrorHandling GetErrorHandlingMode();
virtual ~FFmpegSourceProvider() {}
};
#endif /* WITH_FFMPEGSOURCE */
} // namespace ffms
} // namespace media

View file

@ -1,90 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file subtitles_provider.cpp
/// @brief Base class for subtitle renderers
/// @ingroup subtitle_rendering
///
#include "config.h"
#include "compat.h"
#include "main.h"
#ifdef WITH_CSRI
#include "subtitles_provider_csri.h"
#endif
#ifdef WITH_LIBASS
#include "subtitles_provider_libass.h"
#endif
#if !defined(WITH_CSRI) && !defined(WITH_LIBASS)
#include "include/aegisub/subtitles_provider.h"
#endif
/// @brief Get provider
/// @return
///
SubtitlesProvider* SubtitlesProviderFactory::GetProvider() {
std::vector<std::string> list = GetClasses(OPT_GET("Subtitle/Provider")->GetString());
if (list.empty()) throw _T("No subtitle providers are available.");
// Get provider
wxString error;
for (unsigned int i=0;i<list.size();i++) {
try {
size_t pos = list[i].find('/');
std::string name = list[i].substr(0, pos);
std::string subType = pos < list[i].size() - 1 ? list[i].substr(pos + 1) : "";
SubtitlesProvider *provider = Create(list[i], subType);
if (provider) return provider;
}
catch (agi::UserCancelException const&) { throw; }
catch (wxString err) { error += list[i] + _T(" factory: ") + err + _T("\n"); }
catch (const wxChar *err) { error += list[i] + _T(" factory: ") + wxString(err) + _T("\n"); }
catch (...) { error += list[i] + _T(" factory: Unknown error\n"); }
}
// Failed
throw error;
}
/// @brief Register providers
///
void SubtitlesProviderFactory::RegisterProviders() {
#ifdef WITH_CSRI
Register<CSRISubtitlesProvider>("CSRI", false, CSRISubtitlesProvider::GetSubTypes());
#endif
#ifdef WITH_LIBASS
Register<LibassSubtitlesProvider>("libass");
LibassSubtitlesProvider::CacheFonts();
#endif
}
template<> SubtitlesProviderFactory::map *FactoryBase<SubtitlesProvider *(*)(std::string)>::classes = NULL;

View file

@ -1,116 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro <amz@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file video_frame.cpp
/// @brief Wrapper around a frame of video data
/// @ingroup video
///
#include "config.h"
#include "libmedia/video_frame.h"
#ifndef LAGI_PRE
#include <assert.h>
#include <string.h>
#endif
namespace media {
void AegiVideoFrame::Reset() {
// Zero variables
data = 0;
pitch = 0;
memSize = 0;
w = 0;
h = 0;
// Set properties
flipped = false;
invertChannels = true;
ownMem = true;
}
AegiVideoFrame::AegiVideoFrame() {
Reset();
}
/// @brief Create a solid black frame of the request size and format
/// @param width
/// @param height
AegiVideoFrame::AegiVideoFrame(unsigned int width, unsigned int height) {
assert(width > 0 && width < 10000);
assert(height > 0 && height < 10000);
Reset();
// Set format
w = width;
h = height;
pitch = w * GetBpp();
Allocate();
memset(data, 0, pitch * height);
}
void AegiVideoFrame::Allocate() {
assert(pitch > 0 && pitch < 10000);
assert(w > 0 && w < 10000);
assert(h > 0 && h < 10000);
unsigned int size = pitch * h;
// Reallocate, if necessary
if (memSize != size || !ownMem) {
if (ownMem) {
delete[] data;
}
data = new unsigned char[size];
memSize = size;
}
ownMem = true;
}
void AegiVideoFrame::Clear() {
if (ownMem) delete[] data;
Reset();
}
void AegiVideoFrame::CopyFrom(const AegiVideoFrame &source) {
w = source.w;
h = source.h;
pitch = source.pitch;
Allocate();
memcpy(data, source.data, memSize);
flipped = source.flipped;
invertChannels = source.invertChannels;
}
void AegiVideoFrame::SetTo(const unsigned char *source, unsigned int width, unsigned int height, unsigned int pitch) {
assert(pitch > 0 && pitch < 10000);
assert(width > 0 && width < 10000);
assert(height > 0 && height < 10000);
ownMem = false;
w = width;
h = height;
// Note that despite this cast, the contents of data should still never be modified
data = const_cast<unsigned char*>(source);
this->pitch = pitch;
}
} // namespace media

View file

@ -1,129 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_manager.cpp
/// @brief Keep track of installed video providers
/// @ingroup video_input
///
#include "config.h"
#ifndef MAGI_PRE
#include <string>
#endif
#include <libaegisub/log.h>
#include "libmedia/video.h"
#ifdef WITH_AVISYNTH
#include "../video/avs_video.h"
#endif
#include "../cache/video_cache.h"
//XXX: needs fixing. #include "../video/dummy_video.h"
#ifdef WITH_FFMPEGSOURCE
#include "../video/ffms_video.h"
#endif
//XXX: needs fixing. #include "../video/yuv4mpeg.h"
namespace media {
/// @brief Get provider
/// @param video
/// @return
///
VideoProvider *VideoProviderFactory::GetProvider(std::string video) {
//XXX std::vector<std::string> list = GetClasses(OPT_GET("Video/Provider")->GetString());
std::vector<std::string> list = GetClasses("ffmpegsource");
if (video.find("?dummy") == 0) list.insert(list.begin(), "Dummy");
list.insert(list.begin(), "YUV4MPEG");
bool fileFound = false;
bool fileSupported = false;
std::string errors;
errors.reserve(1024);
for (int i = 0; i < (signed)list.size(); ++i) {
std::string err;
try {
VideoProvider *provider = Create(list[i], video);
LOG_I("manager/video/provider") << list[i] << ": opened " << video;
if (provider->WantsCaching()) {
return new VideoProviderCache(provider);
}
return provider;
}
catch (agi::FileNotFoundError const&) {
err = list[i] + ": file not found.";
// Keep trying other providers as this one may just not be able to
// open a valid path
}
catch (VideoNotSupported const&) {
fileFound = true;
err = list[i] + ": video is not in a supported format.";
}
catch (VideoOpenError const& ex) {
fileSupported = true;
err = list[i] + ": " + ex.GetMessage();
}
catch (agi::vfr::Error const& ex) {
fileSupported = true;
err = list[i] + ": " + ex.GetMessage();
}
errors += err;
errors += "\n";
LOG_D("manager/video/provider") << err;
}
// No provider could open the file
LOG_E("manager/video/provider") << "Could not open " << video;
std::string msg = "Could not open " + video + ":\n" + errors;
if (!fileFound) throw agi::FileNotFoundError(video);
if (!fileSupported) throw VideoNotSupported(msg);
throw VideoOpenError(msg);
}
/// @brief Register all providers
///
void VideoProviderFactory::RegisterProviders() {
#ifdef WITH_AVISYNTH
Register<AvisynthVideoProvider>("Avisynth");
#endif
#ifdef WITH_FFMPEGSOURCE
Register<ffms::FFmpegSourceVideoProvider>("FFmpegSource");
#endif
//XXX Register<DummyVideoProvider>("Dummy", true);
//XXX Register<YUV4MPEGVideoProvider>("YUV4MPEG", true);
}
template<> VideoProviderFactory::map *FactoryBase<VideoProvider *(*)(std::string)>::classes = NULL;
} // namespace media

View file

@ -1,44 +0,0 @@
// Copyright (c) 2006-2008, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_manager.h
/// @see video_provider_manager.cpp
/// @ingroup video_input
///
#include "factory_manager.h"
#include "include/aegisub/video_provider.h"
class VideoProviderFactory : public Factory1<VideoProvider, wxString> {
public:
static VideoProvider *GetProvider(wxString video);
static void RegisterProviders();
};

View file

@ -1,111 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file audio_provider.h
/// @brief Declaration of base-class for audio providers
/// @ingroup main_headers audio_input
///
#pragma once
#include <libaegisub/exception.h>
#include <libaegisub/progress.h>
#include <libmedia/factory_manager.h>
namespace media {
/// @class AudioProvider
/// @brief DOCME
///
/// DOCME
class AudioProvider {
private:
/// DOCME
char *raw;
/// DOCME
int raw_len;
protected:
/// DOCME
int channels;
/// DOCME
int64_t num_samples; // for one channel, ie. number of PCM frames
/// DOCME
int sample_rate;
/// DOCME
int bytes_per_sample;
/// DOCME
std::string filename;
public:
AudioProvider();
virtual ~AudioProvider();
virtual std::string GetFilename() const { return filename; };
virtual void GetAudio(void *buf, int64_t start, int64_t count) const = 0;
void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const;
int64_t GetNumSamples() const { return num_samples; }
int GetSampleRate() const { return sample_rate; }
int GetBytesPerSample() const { return bytes_per_sample; }
int GetChannels() const { return channels; }
virtual bool AreSamplesNativeEndian() const = 0;
/// @brief Does this provider benefit from external caching?
virtual bool NeedsCache() const { return false; }
};
/// DOCME
/// @class AudioProviderFactory
/// @brief DOCME
///
/// DOCME
class AudioProviderFactory : public Factory1<AudioProvider, std::string> {
public:
static void RegisterProviders();
static AudioProvider *GetProvider(std::string filename, agi::ProgressSinkFactory *progress_factory, int cache=-1);
};
DEFINE_BASE_EXCEPTION_NOINNER(AudioProviderError, agi::Exception);
DEFINE_SIMPLE_EXCEPTION_NOINNER(AudioOpenError, AudioProviderError, "audio/open/failed");
/// Error of some sort occurred while decoding a frame
DEFINE_SIMPLE_EXCEPTION_NOINNER(AudioDecodeError, AudioProviderError, "audio/error");
} // namespace media

View file

@ -1,84 +0,0 @@
// Copyright (c) 2005, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file colorspace.h
/// @see colorspace.cpp
/// @ingroup utility
///
#ifndef AGI_PRE
#include <libaegisub/colour.h>
#endif
namespace media {
/// @brief DOCME
/// @param val
///
inline unsigned int clip_colorval(int val)
{
if (val < 0) return 0;
if (val > 255) return 255;
return val;
}
// Convert an YUV color to RGB; all values are expected to be in range 0..255
void yuv_to_rgb(int Y, int U, int V, unsigned char *R, unsigned char *G, unsigned char *B);
// Convert a HSL color to RGB; all values are expected to be in range 0..255
void hsl_to_rgb(int H, int S, int L, unsigned char *R, unsigned char *G, unsigned char *B);
// Convert a HSV color to RGB; all values are expected to be in range 0..255
void hsv_to_rgb(int H, int S, int V, unsigned char *R, unsigned char *G, unsigned char *B);
// Convert an RGB color to YUV; all values are expected to be in range 0..255
void rgb_to_yuv(int R, int G, int B, unsigned char *Y, unsigned char *U, unsigned char *V);
// Convert an RGB color to HSL; all values are expected to be in range 0..255
void rgb_to_hsl(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *L);
// Convert an RGB color to HSV; all values are expected to be in range 0..255
void rgb_to_hsv(int R, int G, int B, unsigned char *H, unsigned char *S, unsigned char *V);
void hsv_to_hsl(int iH, int iS, int iV, unsigned char *oH, unsigned char *oS, unsigned char *oL);
void hsl_to_hsv(int iH, int iS, int iL, unsigned char *oH, unsigned char *oS, unsigned char *oV);
// Convert a wxColour to a HTML hex string
std::string color_to_html(agi::Colour color);
// Convert a HTML hex string to a wxColour
std::string html_to_color(agi::Colour html);
} // namespace media

View file

@ -1,147 +0,0 @@
// Copyright (c) 2010, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file factory_manager.h
/// @brief Template/base-class for factory classes
/// @ingroup utility
///
#pragma once
#ifndef MAGI_PRE
#include <algorithm>
#include <cctype>
#include <map>
#include <vector>
#endif
namespace media {
template <class func>
class FactoryBase {
protected:
typedef std::map<std::string, std::pair<bool, func> > map;
typedef typename map::iterator iterator;
static map *classes;
static void DoRegister(func function, std::string name, bool hide, std::vector<std::string> &subtypes) {
if (!classes) classes = new map;
if (subtypes.empty()) {
classes->insert(std::make_pair(name, std::make_pair(hide, function)));
}
else {
for (size_t i = 0; i < subtypes.size(); i++) {
classes->insert(std::make_pair(name + '/' + subtypes[i], std::make_pair(hide, function)));
}
}
}
static func Find(std::string name) {
if (!classes) return NULL;
iterator factory = classes->find(name);
if (factory != classes->end()) return factory->second.second;
return NULL;
}
public:
static void Clear() {
delete classes;
}
static std::vector<std::string> GetClasses(std::string favourite="") {
std::vector<std::string> list;
if (!classes) return list;
std::string cmp;
std::transform(favourite.begin(), favourite.end(), favourite.begin(), ::tolower);
for (iterator cur=classes->begin();cur!=classes->end();cur++) {
cmp.clear();
std::transform(cur->first.begin(), cur->first.end(), std::back_inserter(cmp), ::tolower);
if (cmp == favourite) list.insert(list.begin(), cur->first);
else if (!cur->second.first) list.push_back(cur->first);
}
return list;
}
virtual ~FactoryBase() {
delete classes;
}
};
template<class Base>
class Factory0 : public FactoryBase<Base *(*)()> {
typedef Base *(*func)();
template<class T>
static Base* create() {
return new T;
}
public:
static Base* Create(std::string name) {
func factory = FactoryBase<func>::Find(name);
if (factory) {
return factory();
}
else {
return NULL;
}
}
template<class T>
static void Register(std::string name, bool hide = false, std::vector<std::string> subTypes = std::vector<std::string>()) {
DoRegister(&Factory0<Base>::template create<T>, name, hide, subTypes);
}
};
template<class Base, class Arg1>
class Factory1 : public FactoryBase<Base *(*)(Arg1)> {
typedef Base *(*func)(Arg1);
template<class T>
static Base* create(Arg1 a1) {
return new T(a1);
}
public:
static Base* Create(std::string name, Arg1 a1) {
func factory = FactoryBase<func>::Find(name);
if (factory) {
return factory(a1);
}
else {
return NULL;
}
}
template<class T>
static void Register(std::string name, bool hide = false, std::vector<std::string> subTypes = std::vector<std::string>()) {
DoRegister(&Factory1<Base, Arg1>::template create<T>, name, hide, subTypes);
}
};
} // namespace media

View file

@ -1,101 +0,0 @@
// Copyright (c) 2006-2008, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider.h
/// @brief Declaration of base-class for video providers
/// @ingroup main_headers video_input
///
#pragma once
#ifndef MAGI_PRE
#include <string>
#endif
#include <libmedia/factory_manager.h>
#include <libmedia/video_frame.h>
#include <libaegisub/exception.h>
#include <libaegisub/vfr.h>
namespace media {
/// @class VideoProvider
/// @brief DOCME
///
/// DOCME
class VideoProvider {
public:
virtual ~VideoProvider() {}
// Override this method to actually get frames
virtual const AegiVideoFrame GetFrame(int n)=0;
// Override the following methods to get video information:
virtual int GetPosition() const=0; ///< Get the number of the last frame loaded
virtual int GetFrameCount() const=0; ///< Get total number of frames
virtual int GetWidth() const=0; ///< Returns the video width in pixels
virtual int GetHeight() const=0; ///< Returns the video height in pixels
virtual agi::vfr::Framerate GetFPS() const=0; ///< Get frame rate
virtual std::vector<int> GetKeyFrames() const=0;///< Returns list of keyframes
/// @brief Use this to set any post-loading warnings, such as "being loaded with unreliable seeking"
virtual std::string GetWarning() const { return ""; }
/// @brief Name of decoder, e.g. "Avisynth/FFMpegSource"
virtual std::string GetDecoderName() const = 0;
/// @brief Does this provider want Aegisub to cache video frames?
/// @return Returns true if caching is desired, false otherwise.
virtual bool WantsCaching() const { return false; }
};
class VideoProviderFactory : public Factory1<VideoProvider, std::string> {
public:
static VideoProvider *GetProvider(std::string video);
static void RegisterProviders();
};
DEFINE_BASE_EXCEPTION_NOINNER(VideoProviderError, agi::Exception);
/// File could be opened, but is not a supported format
DEFINE_SIMPLE_EXCEPTION_NOINNER(VideoNotSupported, VideoProviderError, "video/open/notsupported");
/// File appears to be a supported format, but could not be opened
DEFINE_SIMPLE_EXCEPTION_NOINNER(VideoOpenError, VideoProviderError, "video/open/failed");
/// Error of some sort occurred while decoding a frame
DEFINE_SIMPLE_EXCEPTION_NOINNER(VideoDecodeError, VideoProviderError, "video/error");
} // namespace media

View file

@ -1,87 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro <amz@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file media_video_frame.h
/// @see media_video_frame.cpp
/// @ingroup video
///
#ifndef LAGI_PRE
#endif
namespace media {
/// DOCME
/// @class AegiVideoFrame
/// @brief DOCME
///
/// DOCME
class AegiVideoFrame {
/// Whether the object owns its buffer. If this is false, **data should never be modified
bool ownMem;
/// @brief Reset values to the defaults
///
/// Note that this function DOES NOT deallocate memory.
/// Use Clear() for that
void Reset();
public:
/// @brief Allocate memory if needed
void Allocate();
/// The size in bytes of the frame buffer
unsigned int memSize;
/// Pointer to the data planes
unsigned char *data;
/// Width in pixels
unsigned int w;
/// Height in pixels
unsigned int h;
// Pitch, that is, the number of bytes used by each row.
unsigned int pitch;
/// First row is actually the bottom one
bool flipped;
/// Swap Red and Blue channels (controls RGB versus BGR ordering etc)
bool invertChannels;
AegiVideoFrame();
AegiVideoFrame(unsigned int width, unsigned int height);
// @brief Clear this frame, freeing its memory if nessesary
void Clear();
/// @brief Copy from an AegiVideoFrame
/// @param source The frame to copy from
void CopyFrom(const AegiVideoFrame &source);
/// @brief Set the frame to an externally allocated block of memory
/// @param source Target frame data
/// @param width The frame width in pixels
/// @param height The frame height in pixels
/// @param pitch The frame's pitch
/// @param format The frame's format
void SetTo(const unsigned char *source, unsigned int width, unsigned int height, unsigned int pitch);
int GetBpp() const { return 4; };
};
} // namespace media

View file

@ -1,57 +0,0 @@
#define LAGI_PRE
#include "config.h"
// Common C
#include <errno.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
# include <time.h>
#endif
// Windows C
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#endif
// Common C++
#include <deque>
#include <fstream>
#include <iostream>
#include <iterator>
#include <numeric>
#include <map>
#include <sstream>
#include <string>
#ifdef _WIN32
#include <functional>
#include <memory>
#else
#include <tr1/functional>
#include <tr1/memory>
#endif
#ifdef __DEPRECATED // Dodge GCC warnings
# undef __DEPRECATED
# include <strstream>
# define __DEPRECATED
#else
# include <strstream>
#endif
// Cajun
#include "libaegisub/cajun/elements.h"
#include "libaegisub/cajun/reader.h"
#include "libaegisub/cajun/visitor.h"
#include "libaegisub/cajun/writer.h"

View file

@ -1,147 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file subtitles_provider_csri.cpp
/// @brief Wrapper for CSRI-based subtitle renderers
/// @ingroup subtitle_rendering
///
#include "config.h"
#ifdef WITH_CSRI
#include "ass_file.h"
#include "subtitles_provider_csri.h"
#include "text_file_writer.h"
#include "video_context.h"
#include "video_frame.h"
/// @brief Constructor
/// @param type
///
CSRISubtitlesProvider::CSRISubtitlesProvider(std::string type) : subType(type) {
}
/// @brief Destructor
///
CSRISubtitlesProvider::~CSRISubtitlesProvider() {
if (!tempfile.empty()) wxRemoveFile(tempfile);
}
/// @brief Load subtitles
/// @param subs
///
void CSRISubtitlesProvider::LoadSubtitles(AssFile *subs) {
// CSRI variables
csri_rend *cur,*renderer=NULL;
// Select renderer
bool canOpenMem = true;
for (cur = csri_renderer_default();cur;cur=csri_renderer_next(cur)) {
std::string name(csri_renderer_info(cur)->name);
if (name == subType) {
renderer = cur;
if (name.find("vsfilter") != name.npos) canOpenMem = false;
break;
}
}
// Matching renderer not found, fallback to default
if (!renderer) {
renderer = csri_renderer_default();
if (!renderer) {
throw _T("No CSRI renderer available, cannot show subtitles. Try installing one or switch to another subtitle provider.");
}
}
// Open from memory
if (canOpenMem) {
std::vector<char> data;
subs->SaveMemory(data,wxSTRING_ENCODING);
instance.reset(csri_open_mem(renderer,&data[0],data.size(),NULL), &csri_close);
}
// Open from disk
else {
if (tempfile.empty()) {
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
wxRemoveFile(tempfile);
tempfile += L".ass";
}
subs->Save(tempfile,false,false,wxSTRING_ENCODING);
instance.reset(csri_open_file(renderer,tempfile.utf8_str(),NULL), &csri_close);
}
}
/// @brief Draw subtitles
/// @param dst
/// @param time
/// @return
///
void CSRISubtitlesProvider::DrawSubtitles(AegiVideoFrame &dst,double time) {
// Check if CSRI loaded properly
if (!instance.get()) return;
// Load data into frame
csri_frame frame;
if (dst.flipped) {
frame.planes[0] = dst.data + (dst.h-1) * dst.pitch;
frame.strides[0] = -(signed)dst.pitch;
}
else {
frame.planes[0] = dst.data;
frame.strides[0] = dst.pitch;
}
frame.pixfmt = CSRI_F_BGR_;
// Set format
csri_fmt format;
format.width = dst.w;
format.height = dst.h;
format.pixfmt = frame.pixfmt;
int error = csri_request_fmt(instance.get(),&format);
if (error) return;
// Render
csri_render(instance.get(),&frame,time);
}
/// @brief Get CSRI subtypes
///
std::vector<std::string> CSRISubtitlesProvider::GetSubTypes() {
std::vector<std::string> final;
for (csri_rend *cur = csri_renderer_default();cur;cur = csri_renderer_next(cur)) {
final.push_back(csri_renderer_info(cur)->name);
}
return final;
}
#endif // WITH_CSRI

View file

@ -1,74 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file subtitles_provider_csri.h
/// @see subtitles_provider_csri.cpp
/// @ingroup subtitle_rendering
///
#ifdef WITH_CSRI
#ifndef AGI_PRE
#include <tr1/memory>
#include <vector>
#endif
#include "include/aegisub/subtitles_provider.h"
#ifdef WIN32
#define CSRIAPI
#include "../../contrib/csri/include/csri/csri.h"
#else
#include <csri/csri.h>
#endif
/// DOCME
/// @class CSRISubtitlesProvider
/// @brief DOCME
///
/// DOCME
class CSRISubtitlesProvider : public SubtitlesProvider {
/// DOCME
std::string subType;
/// DOCME
std::tr1::shared_ptr<csri_inst> instance;
wxString tempfile;
public:
CSRISubtitlesProvider(std::string subType);
~CSRISubtitlesProvider();
void LoadSubtitles(AssFile *subs);
void DrawSubtitles(AegiVideoFrame &dst,double time);
static std::vector<std::string> GetSubTypes();
};
#endif

View file

@ -1,252 +0,0 @@
// Copyright (c) 2006-2007, Rodrigo Braz Monteiro, Evgeniy Stepanov
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file subtitles_provider_libass.cpp
/// @brief libass-based subtitle renderer
/// @ingroup subtitle_rendering
///
#include "config.h"
#ifdef WITH_LIBASS
#ifndef AGI_PRE
#include <wx/filefn.h>
#include <wx/utils.h>
#endif
#ifdef __APPLE__
#include <sys/param.h>
#include <libaegisub/util_osx.h>
#endif
#include <libaegisub/log.h>
#include "ass_file.h"
#include "dialog_progress.h"
#include "frame_main.h"
#include "main.h"
#include "standard_paths.h"
#include "subtitles_provider_libass.h"
#include "utils.h"
#include "video_context.h"
#include "video_frame.h"
/// @brief Handle libass messages
///
static void msg_callback(int level, const char *fmt, va_list args, void *) {
if (level >= 7) return;
char buf[1024];
#ifdef _WIN32
vsprintf_s(buf, sizeof(buf), fmt, args);
#else
vsnprintf(buf, sizeof(buf), fmt, args);
#endif
if (level < 2) // warning/error
LOG_I("subtitle/provider/libass") << buf;
else // verbose
LOG_D("subtitle/provider/libass") << buf;
}
class FontConfigCacheThread : public wxThread {
ASS_Library *ass_library;
ASS_Renderer *ass_renderer;
FontConfigCacheThread** thisPtr;
ExitCode Entry() {
#ifdef __APPLE__
char config_path[MAXPATHLEN];
char *config_dir;
config_dir = agi::util::OSX_GetBundleResourcesDirectory();
snprintf(config_path, MAXPATHLEN, "%s/etc/fonts/fonts.conf", config_dir);
free(config_dir);
#else
const char *config_path = NULL;
#endif
if (ass_library) ass_renderer = ass_renderer_init(ass_library);
ass_set_fonts(ass_renderer, NULL, "Sans", 1, config_path, true);
if (ass_library) ass_renderer_done(ass_renderer);
*thisPtr = NULL;
return EXIT_SUCCESS;
}
public:
FontConfigCacheThread(ASS_Library *ass_library, FontConfigCacheThread **thisPtr)
: ass_library(ass_library)
, ass_renderer(NULL)
, thisPtr(thisPtr)
{
*thisPtr = this;
Create();
Run();
}
FontConfigCacheThread(ASS_Renderer *ass_renderer, FontConfigCacheThread **thisPtr)
: ass_library(NULL)
, ass_renderer(ass_renderer)
, thisPtr(thisPtr)
{
*thisPtr = this;
Create();
Run();
}
};
static void wait_for_cache_thread(FontConfigCacheThread const * const * const cache_worker) {
if (!*cache_worker) return;
bool canceled;
DialogProgress *progress = new DialogProgress(AegisubApp::Get()->frame, L"", &canceled, L"Caching fonts", 0, 1);
progress->Show();
while (*cache_worker) {
if (canceled) throw agi::UserCancelException("Font caching cancelled");
progress->Pulse();
wxYield();
wxMilliSleep(100);
}
progress->Destroy();
}
/// @brief Constructor
///
LibassSubtitlesProvider::LibassSubtitlesProvider(std::string) {
wait_for_cache_thread(&cache_worker);
// Initialize renderer
ass_track = NULL;
ass_renderer = ass_renderer_init(ass_library);
if (!ass_renderer) throw _T("ass_renderer_init failed");
ass_set_font_scale(ass_renderer, 1.);
new FontConfigCacheThread(ass_renderer, &cache_worker);
wait_for_cache_thread(&cache_worker);
}
/// @brief Destructor
///
LibassSubtitlesProvider::~LibassSubtitlesProvider() {
if (ass_track) ass_free_track(ass_track);
if (ass_renderer) ass_renderer_done(ass_renderer);
}
/// @brief Load subtitles
/// @param subs
///
void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) {
// Prepare subtitles
std::vector<char> data;
subs->SaveMemory(data,_T("UTF-8"));
// Load file
if (ass_track) ass_free_track(ass_track);
ass_track = ass_read_memory(ass_library, &data[0], data.size(),(char *)"UTF-8");
if (!ass_track) throw _T("libass failed to load subtitles.");
}
/// DOCME
#define _r(c) ((c)>>24)
/// DOCME
#define _g(c) (((c)>>16)&0xFF)
/// DOCME
#define _b(c) (((c)>>8)&0xFF)
/// DOCME
#define _a(c) ((c)&0xFF)
/// @brief Draw subtitles
/// @param frame
/// @param time
/// @return
///
void LibassSubtitlesProvider::DrawSubtitles(AegiVideoFrame &frame,double time) {
// Set size
ass_set_frame_size(ass_renderer, frame.w, frame.h);
// Get frame
ASS_Image* img = ass_render_frame(ass_renderer, ass_track, int(time * 1000), NULL);
// libass actually returns several alpha-masked monochrome images.
// Here, we loop through their linked list, get the colour of the current, and blend into the frame.
// This is repeated for all of them.
while (img) {
// Get colours
unsigned int opacity = 255 - ((unsigned int)_a(img->color));
unsigned int r = (unsigned int)_r(img->color);
unsigned int g = (unsigned int)_g(img->color);
unsigned int b = (unsigned int) _b(img->color);
// Prepare copy
int src_stride = img->stride;
int dst_stride = frame.pitch;
int dst_delta = dst_stride - img->w*4;
//int stride = std::min(src_stride,dst_stride);
const unsigned char *src = img->bitmap;
unsigned char *dst = frame.data + (img->dst_y * dst_stride + img->dst_x * 4);
unsigned int k,ck,t;
// Copy image to destination frame
for (int y=0;y<img->h;y++) {
//memcpy(dst,src,stride);
for (int x = 0; x < img->w; ++x) {
k = ((unsigned)src[x]) * opacity / 255;
ck = 255 - k;
t = *dst;
*dst++ = (k*b + ck*t) / 255;
t = *dst;
*dst++ = (k*g + ck*t) / 255;
t = *dst;
*dst++ = (k*r + ck*t) / 255;
dst++;
}
dst += dst_delta;
src += src_stride;
}
// Next image
img = img->next;
}
}
void LibassSubtitlesProvider::CacheFonts() {
ass_library = ass_library_init();
ass_set_message_cb(ass_library, msg_callback, NULL);
new FontConfigCacheThread(ass_library, &cache_worker);
}
/// DOCME
ASS_Library* LibassSubtitlesProvider::ass_library;
FontConfigCacheThread* LibassSubtitlesProvider::cache_worker = NULL;
#endif // WITH_LIBASS

View file

@ -1,76 +0,0 @@
// Copyright (c) 2006-2007, Rodrigo Braz Monteiro, Evgeniy Stepanov
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file subtitles_provider_libass.h
/// @see subtitles_provider_libass.cpp
/// @ingroup subtitle_rendering
///
#ifdef WITH_LIBASS
#include "include/aegisub/subtitles_provider.h"
extern "C" {
#ifdef __VISUALC__
#include "stdint.h"
#endif
#include "../libass/ass.h"
}
class FontConfigCacheThread;
/// DOCME
/// @class LibassSubtitlesProvider
/// @brief DOCME
///
/// DOCME
class LibassSubtitlesProvider : public SubtitlesProvider {
/// DOCME
static ASS_Library* ass_library;
/// DOCME
ASS_Renderer* ass_renderer;
/// DOCME
ASS_Track* ass_track;
static FontConfigCacheThread *cache_worker;
public:
LibassSubtitlesProvider(std::string);
~LibassSubtitlesProvider();
void LoadSubtitles(AssFile *subs);
void DrawSubtitles(AegiVideoFrame &dst,double time);
static void CacheFonts();
};
#endif

View file

@ -1,295 +0,0 @@
// Copyright (c) 2006, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_avs.cpp
/// @brief Avisynth-based video provider
/// @ingroup video_input
///
#include "config.h"
#ifdef WITH_AVISYNTH
#ifndef AGI_PRE
#include <wx/filename.h>
#include <wx/msw/registry.h>
#endif
#include "charset_conv.h"
#include "compat.h"
#include "gl_wrap.h"
#include <libaegisub/log.h>
#include "mkv_wrap.h"
#include "standard_paths.h"
#include "vfw_wrap.h"
#include "video_context.h"
#include "video_provider_avs.h"
namespace media {
/// @brief Constructor
/// @param _filename
///
AvisynthVideoProvider::AvisynthVideoProvider(wxString filename) try
: usedDirectShow(false)
, decoderName(_("Unknown"))
, num_frames(0)
, last_fnum(-1)
, RGB32Video(NULL)
{
RGB32Video = OpenVideo(filename);
vi = RGB32Video->GetVideoInfo();
}
catch (AvisynthError const& err) {
throw VideoOpenError("Avisynth error: " + std::string(err.msg));
}
/// @brief Destructor
AvisynthVideoProvider::~AvisynthVideoProvider() {
iframe.Clear();
}
AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& extension) {
char *videoFilename = env->SaveString(fname.GetShortPath().mb_str(csConvLocal));
// Avisynth file, just import it
if (extension == L".avs") {
LOG_I("avisynth/video") << "Opening .avs file with Import";
decoderName = L"Import";
return env->Invoke("Import", videoFilename);
}
// Open avi file with AviSource
if (extension == L".avi") {
LOG_I("avisynth/video") << "Opening .avi file with AviSource";
try {
const char *argnames[2] = { 0, "audio" };
AVSValue args[2] = { videoFilename, false };
decoderName = L"AviSource";
return env->Invoke("AviSource", AVSValue(args,2), argnames);
}
// On Failure, fallback to DSS
catch (AvisynthError &) {
LOG_I("avisynth/video") << "Failed to open .avi file with AviSource, switching to DirectShowSource";
}
}
// Open d2v with mpeg2dec3
if (extension == L".d2v" && env->FunctionExists("Mpeg2Dec3_Mpeg2Source")) {
LOG_I("avisynth/video") << "Opening .d2v file with Mpeg2Dec3_Mpeg2Source";
AVSValue script = env->Invoke("Mpeg2Dec3_Mpeg2Source", videoFilename);
decoderName = L"Mpeg2Dec3_Mpeg2Source";
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
if (env->FunctionExists("SetPlanarLegacyAlignment")) {
AVSValue args[2] = { script, true };
script = env->Invoke("SetPlanarLegacyAlignment", AVSValue(args,2));
}
return script;
}
// If that fails, try opening it with DGDecode
if (extension == L".d2v" && env->FunctionExists("DGDecode_Mpeg2Source")) {
LOG_I("avisynth/video") << "Opening .d2v file with DGDecode_Mpeg2Source";
decoderName = L"DGDecode_Mpeg2Source";
return env->Invoke("Mpeg2Source", videoFilename);
//note that DGDecode will also have issues like if the version is too ancient but no sane person
//would use that anyway
}
if (extension == L".d2v" && env->FunctionExists("Mpeg2Source")) {
LOG_I("avisynth/video") << "Opening .d2v file with other Mpeg2Source";
AVSValue script = env->Invoke("Mpeg2Source", videoFilename);
decoderName = L"Mpeg2Source";
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
if (env->FunctionExists("SetPlanarLegacyAlignment"))
script = env->Invoke("SetPlanarLegacyAlignment", script);
return script;
}
// Try loading DirectShowSource2
if (!env->FunctionExists("dss2")) {
wxFileName dss2path(StandardPaths::DecodePath(_T("?data/avss.dll")));
if (dss2path.FileExists()) {
env->Invoke("LoadPlugin",env->SaveString(dss2path.GetFullPath().mb_str(csConvLocal)));
}
}
// If DSS2 loaded properly, try using it
if (env->FunctionExists("dss2")) {
LOG_I("avisynth/video") << "Opening file with DSS2";
decoderName = L"DSS2";
return env->Invoke("DSS2", videoFilename);
}
// Try DirectShowSource
// Load DirectShowSource.dll from app dir if it exists
wxFileName dsspath(StandardPaths::DecodePath(_T("?data/DirectShowSource.dll")));
if (dsspath.FileExists()) {
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetFullPath().mb_str(csConvLocal)));
}
// Then try using DSS
if (env->FunctionExists("DirectShowSource")) {
const char *argnames[3] = { 0, "video", "audio" };
AVSValue args[3] = { videoFilename, true, false };
usedDirectShow = true;
decoderName = L"DirectShowSource";
LOG_I("avisynth/video") << "Opening file with DirectShowSource";
return env->Invoke("DirectShowSource", AVSValue(args,3), argnames);
}
// Failed to find a suitable function
LOG_E("avisynth/video") << "DSS function not found";
throw VideoNotSupported("No function suitable for opening the video found");
}
/// @brief Actually open the video into Avisynth
/// @param _filename
/// @return
///
PClip AvisynthVideoProvider::OpenVideo(wxString filename) {
wxMutexLocker lock(AviSynthMutex);
wxFileName fname(filename);
if (!fname.FileExists())
throw agi::FileNotFoundError(STD_STR(filename));
AVSValue script;
wxString extension = filename.Right(4).Lower();
try {
script = Open(fname, extension);
}
catch (AvisynthError const& err) {
throw VideoOpenError("Avisynth error: " + std::string(err.msg));
}
// Check if video was loaded properly
if (!script.IsClip() || !script.AsClip()->GetVideoInfo().HasVideo()) {
throw VideoNotSupported("No usable video found");
}
// Read keyframes and timecodes from MKV file
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
KeyFrames.clear();
if (extension == L".mkv" || mkvOpen) {
// Parse mkv
if (!mkvOpen) MatroskaWrapper::wrapper.Open(filename);
// Get keyframes
KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
MatroskaWrapper::wrapper.SetToTimecodes(vfr_fps);
// Close mkv
MatroskaWrapper::wrapper.Close();
}
// check if we have windows, if so we can load keyframes from AVI files using VFW
#ifdef __WINDOWS__
else if (extension == L".avi") {
KeyFrames.clear();
KeyFrames = VFWWrapper::GetKeyFrames(filename);
}
#endif /* __WINDOWS__ */
// Check if the file is all keyframes
bool isAllKeyFrames = true;
for (unsigned int i=1; i<KeyFrames.size(); i++) {
// Is the last keyframe not this keyframe -1?
if (KeyFrames[i-1] != (int)(i-1)) {
// It's not all keyframes, go ahead
isAllKeyFrames = false;
break;
}
}
// If it is all keyframes, discard the keyframe info as it is useless
if (isAllKeyFrames) {
KeyFrames.clear();
}
real_fps = (double)vi.fps_numerator / vi.fps_denominator;
// Convert to RGB32
script = env->Invoke("ConvertToRGB32", script);
// Cache
return (env->Invoke("Cache", script)).AsClip();
}
/// @brief Actually get a frame
/// @param _n
/// @return
///
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int n) {
if (vfr_fps.IsLoaded()) {
n = real_fps.FrameAtTime(vfr_fps.TimeAtFrame(n));
}
// Get avs frame
wxMutexLocker lock(AviSynthMutex);
PVideoFrame frame = RGB32Video->GetFrame(n,env);
int Bpp = vi.BitsPerPixel() / 8;
// Aegisub's video frame
AegiVideoFrame &final = iframe;
final.flipped = true;
final.invertChannels = true;
// Set size properties
final.pitch = frame->GetPitch();
final.w = frame->GetRowSize() / Bpp;
final.h = frame->GetHeight();
// Allocate
final.Allocate();
// Copy
memcpy(final.data,frame->GetReadPtr(),final.pitch * final.h);
// Set last number
last_fnum = n;
return final;
}
/// @brief Get warning
///
wxString AvisynthVideoProvider::GetWarning() const {
if (usedDirectShow) return L"Warning! The file is being opened using Avisynth's DirectShowSource, which has unreliable seeking. Frame numbers might not match the real number. PROCEED AT YOUR OWN RISK!";
else return L"";
}
#endif
} // namespace media

View file

@ -1,104 +0,0 @@
// Copyright (c) 2006, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_avs.h
/// @see video_provider_avs.cpp
/// @ingroup video_input
///
#ifdef WITH_AVISYNTH
#include "avisynth_wrap.h"
#include "include/aegisub/video_provider.h"
namespace media {
/// DOCME
/// @class AvisynthVideoProvider
/// @brief DOCME
///
/// DOCME
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
/// DOCME
VideoInfo vi;
/// DOCME
AegiVideoFrame iframe;
/// DOCME
bool usedDirectShow;
/// DOCME
wxString rendererCallString;
/// DOCME
wxString decoderName;
/// DOCME
int num_frames;
/// DOCME
int last_fnum;
/// DOCME
agi::vfr::Framerate real_fps;
agi::vfr::Framerate vfr_fps;
/// DOCME
std::vector<int> KeyFrames;
/// DOCME
PClip RGB32Video;
PClip OpenVideo(wxString filename);
AVSValue Open(wxFileName const& fname, wxString const& extension);
public:
AvisynthVideoProvider(wxString filename);
~AvisynthVideoProvider();
const AegiVideoFrame GetFrame(int n);
int GetPosition() const { return last_fnum; };
int GetFrameCount() const { return num_frames? num_frames: vi.num_frames; };
agi::vfr::Framerate GetFPS() const { return vfr_fps.IsLoaded() ? vfr_fps : real_fps; };
int GetWidth() const { return vi.width; };
int GetHeight() const { return vi.height; };
std::vector<int> GetKeyFrames() const { return KeyFrames; };
wxString GetWarning() const;
wxString GetDecoderName() const { return wxString(L"Avisynth/") + decoderName; }
};
#endif
} // namespace media

View file

@ -1,223 +0,0 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_dummy.cpp
/// @brief Video provider returning a constant frame
/// @ingroup video_input
///
#include "config.h"
#ifndef AGI_PRE
#include <wx/tokenzr.h>
#endif
#include "colorspace.h"
#include "video_provider_dummy.h"
namespace media {
/// @brief Constructor
/// @param _fps
/// @param frames
/// @param _width
/// @param _height
/// @param colour
/// @param pattern
///
void DummyVideoProvider::Create(double _fps, int frames, int _width, int _height, const wxColour &colour, bool pattern) {
lastFrame = -1;
framecount = frames;
fps = _fps;
width = _width;
height = _height;
frame = AegiVideoFrame(width,height);
unsigned char *dst = frame.data;
unsigned char r = colour.Red(), g = colour.Green(), b = colour.Blue();
unsigned char h, s, l, lr, lg, lb; // light variants
rgb_to_hsl(r, g, b, &h, &s, &l);
l += 24;
if (l < 24) l -= 48;
hsl_to_rgb(h, s, l, &lr, &lg, &lb);
if (pattern) {
int ppitch = frame.pitch / frame.GetBpp();
for (unsigned int y = 0; y < frame.h; ++y) {
if ((y / 8) & 1) {
for (int x = 0; x < ppitch; ++x) {
if ((x / 8) & 1) {
*dst++ = b;
*dst++ = g;
*dst++ = r;
*dst++ = 0;
}
else {
*dst++ = lb;
*dst++ = lg;
*dst++ = lr;
*dst++ = 0;
}
}
}
else {
for (int x = 0; x < ppitch; ++x) {
if ((x / 8) & 1) {
*dst++ = lb;
*dst++ = lg;
*dst++ = lr;
*dst++ = 0;
}
else {
*dst++ = b;
*dst++ = g;
*dst++ = r;
*dst++ = 0;
}
}
}
}
}
else {
for (int i=frame.pitch*frame.h/frame.GetBpp();--i>=0;) {
*dst++ = b;
*dst++ = g;
*dst++ = r;
*dst++ = 0;
}
}
}
/// @brief Parsing constructor
/// @param filename
///
DummyVideoProvider::DummyVideoProvider(wxString filename)
{
wxString params;
if (!filename.StartsWith(_T("?dummy:"), &params)) {
throw agi::FileNotFoundError("Attempted creating dummy video provider with non-dummy filename");
}
wxStringTokenizer t(params, _T(":"));
if (t.CountTokens() < 7) {
throw VideoOpenError("Too few fields in dummy video parameter list");
}
double fps;
long _frames, _width, _height, red, green, blue;
bool pattern = false;
wxString field = t.GetNextToken();
if (!field.ToDouble(&fps)) {
throw VideoOpenError("Unable to parse fps field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&_frames)) {
throw VideoOpenError("Unable to parse framecount field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&_width)) {
throw VideoOpenError("Unable to parse width field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&_height)) {
throw VideoOpenError("Unable to parse height field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&red)) {
throw VideoOpenError("Unable to parse red colour field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&green)) {
throw VideoOpenError("Unable to parse green colour field in dummy video parameter list");
}
field = t.GetNextToken();
if (!field.ToLong(&blue)) {
throw VideoOpenError("Unable to parse blue colour field in dummy video parameter list");
}
field = t.GetNextToken();
if (field == _T("c")) {
pattern = true;
}
Create(fps, _frames, _width, _height, wxColour(red, green, blue), pattern);
}
/// @brief Direct constructor
/// @param _fps
/// @param frames
/// @param _width
/// @param _height
/// @param colour
/// @param pattern
///
DummyVideoProvider::DummyVideoProvider(double _fps, int frames, int _width, int _height, const wxColour &colour, bool pattern) {
Create(_fps, frames, _width, _height, colour, pattern);
}
/// @brief Destructor
///
DummyVideoProvider::~DummyVideoProvider() {
frame.Clear();
}
/// @brief Construct a fake filename describing the video
/// @param fps
/// @param frames
/// @param _width
/// @param _height
/// @param colour
/// @param pattern
/// @return
///
wxString DummyVideoProvider::MakeFilename(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern) {
return wxString::Format(_T("?dummy:%f:%d:%d:%d:%d:%d:%d:%s"), fps, frames, _width, _height, colour.Red(), colour.Green(), colour.Blue(), pattern?_T("c"):_T(""));
}
/// @brief Get frame
/// @param n
/// @return
///
const AegiVideoFrame DummyVideoProvider::GetFrame(int n) {
lastFrame = n;
return frame;
}
} // namespace media

View file

@ -1,91 +0,0 @@
// Copyright (c) 2007, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_dummy.h
/// @see video_provider_dummy.cpp
/// @ingroup video_input
///
// The dummy video provider needs a header, since it needs to be created directly as a special case
#ifndef AGI_PRE
#include <wx/colour.h>
#endif
#include "include/aegisub/video_provider.h"
namespace media {
/// DOCME
/// @class DummyVideoProvider
/// @brief DOCME
///
/// DOCME
class DummyVideoProvider : public VideoProvider {
/// DOCME
int lastFrame;
/// DOCME
int framecount;
/// DOCME
agi::vfr::Framerate fps;
/// DOCME
int width;
/// DOCME
int height;
/// DOCME
AegiVideoFrame frame;
void Create(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
public:
DummyVideoProvider(wxString filename);
DummyVideoProvider(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
~DummyVideoProvider();
const AegiVideoFrame GetFrame(int n);
static wxString MakeFilename(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
int GetPosition() const { return lastFrame; }
int GetFrameCount() const { return framecount; }
int GetWidth() const { return width; }
int GetHeight() const { return height; }
agi::vfr::Framerate GetFPS() const { return fps; }
std::vector<int> GetKeyFrames() const { return std::vector<int>(); };
wxString GetDecoderName() const { return L"Dummy Video Provider"; }
};
} // namespace media

View file

@ -1,277 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster <thefluff@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file ffms_video.h
/// @brief FFmpegSource Video support.
/// @ingroup fmms video
#include "config.h"
#ifdef WITH_FFMPEGSOURCE
#ifndef AGI_PRE
#ifdef __WINDOWS__
#include <objbase.h>
#endif
#include <map>
//#include <wx/choicdlg.h>
//#include <wx/msgdlg.h>
//#include <wx/utils.h>
#endif
#include "ffms_video.h"
#include "libaegisub/util.h"
//#include "aegisub_endian.h"
//#include "compat.h"
//#include "main.h"
//#include "utils.h"
//#include "video_context.h"
//#include "video_provider_ffmpegsource.h"
namespace media {
namespace ffms {
/// @brief Constructor
/// @param filename The filename to open
FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(std::string filename)
: VideoSource(NULL)
, 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;
ErrInfo.SubType = FFMS_ERROR_SUCCESS;
// SetLogLevel();
// and here we go
try {
LoadVideo(filename);
}
catch (std::string const& err) {
Close();
throw VideoOpenError(err);
}
catch (...) {
Close();
throw;
}
}
/// @brief Destructor
FFmpegSourceVideoProvider::~FFmpegSourceVideoProvider() {
Close();
}
/// @brief Opens video
/// @param filename The filename to open
void FFmpegSourceVideoProvider::LoadVideo(std::string filename) {
FFMS_Indexer *Indexer = FFMS_CreateIndexer(filename.c_str(), &ErrInfo);
if (Indexer == NULL) {
throw agi::FileNotFoundError(ErrInfo.Buffer);
}
std::map<int,std::string> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_VIDEO);
if (TrackList.size() <= 0)
throw VideoNotSupported("no video tracks found");
// initialize the track number to an invalid value so we can detect later on
// whether the user actually had to choose a track or not
int TrackNumber = -1;
if (TrackList.size() > 1) {
TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_VIDEO);
// if it's still -1 here, user pressed cancel
if (TrackNumber == -1)
throw agi::UserCancelException("video loading cancelled by user");
}
// generate a name for the cache file
std::string CacheName = GetCacheFilename(filename);
// try to read index
FFMS_Index *Index = NULL;
Index = FFMS_ReadIndex(CacheName.c_str(), &ErrInfo);
bool IndexIsValid = false;
if (Index != NULL) {
if (FFMS_IndexBelongsToFile(Index, filename.c_str(), &ErrInfo)) {
FFMS_DestroyIndex(Index);
Index = NULL;
}
else
IndexIsValid = true;
}
// 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) {
FFMS_Track *TempTrackData = FFMS_GetTrackFromIndex(Index, TrackNumber);
if (FFMS_GetNumFrames(TempTrackData) <= 0) {
IndexIsValid = false;
FFMS_DestroyIndex(Index);
Index = NULL;
}
}
// moment of truth
if (!IndexIsValid) {
// int TrackMask = OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() ? FFMS_TRACKMASK_ALL : FFMS_TRACKMASK_NONE;
int TrackMask = 1 ? 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 (std::string err) {
throw VideoOpenError(err);
}
}
// update access time of index file so it won't get cleaned away
//XXX: wxFileName(CacheName).Touch();
// track number still not set?
if (TrackNumber < 0) {
// just grab the first track
TrackNumber = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_VIDEO, &ErrInfo);
if (TrackNumber < 0) {
FFMS_DestroyIndex(Index);
Index = NULL;
throw VideoNotSupported(std::string("Couldn't find any video tracks: ") + ErrInfo.Buffer);
}
}
// set thread count
// int Threads = OPT_GET("Provider/Video/FFmpegSource/Decoding Threads")->GetInt();
int Threads = 1;
if (Threads < 1)
throw VideoOpenError("invalid decoding thread count");
// set seekmode
// TODO: give this its own option?
int SeekMode;
// if (OPT_GET("Provider/Video/FFmpegSource/Unsafe Seeking")->GetBool())
// SeekMode = FFMS_SEEK_UNSAFE;
// else
SeekMode = FFMS_SEEK_NORMAL;
VideoSource = FFMS_CreateVideoSource(filename.c_str(), TrackNumber, Index, Threads, SeekMode, &ErrInfo);
FFMS_DestroyIndex(Index);
Index = NULL;
if (VideoSource == NULL) {
throw VideoOpenError(std::string("Failed to open video track: ") + ErrInfo.Buffer);
}
// load video properties
VideoInfo = FFMS_GetVideoProperties(VideoSource);
const FFMS_Frame *TempFrame = FFMS_GetFrame(VideoSource, 0, &ErrInfo);
if (TempFrame == NULL) {
throw VideoOpenError(std::string("Failed to decode first frame: ") + ErrInfo.Buffer);
}
Width = TempFrame->EncodedWidth;
Height = TempFrame->EncodedHeight;
if (FFMS_SetOutputFormatV(VideoSource, 1LL << FFMS_GetPixFmt("bgra"), Width, Height, FFMS_RESIZER_BICUBIC, &ErrInfo)) {
throw VideoOpenError(std::string("Failed to set output format: ") + ErrInfo.Buffer);
}
// get frame info data
FFMS_Track *FrameData = FFMS_GetTrackFromVideo(VideoSource);
if (FrameData == NULL)
throw VideoOpenError("failed to get frame data");
const FFMS_TrackTimeBase *TimeBase = FFMS_GetTimeBase(FrameData);
if (TimeBase == NULL)
throw VideoOpenError("failed to get track time base");
const FFMS_FrameInfo *CurFrameData;
// build list of keyframes and timecodes
std::vector<int> TimecodesVector;
for (int CurFrameNum = 0; CurFrameNum < VideoInfo->NumFrames; CurFrameNum++) {
CurFrameData = FFMS_GetFrameInfo(FrameData, CurFrameNum);
if (CurFrameData == NULL) {
//XXX throw VideoOpenError(STD_STR(wxString::Format(L"Couldn't get info about frame %d", CurFrameNum)));
throw VideoOpenError("Couldn't get info about frame %d");
}
// keyframe?
if (CurFrameData->KeyFrame)
KeyFramesList.push_back(CurFrameNum);
// calculate timestamp and add to timecodes vector
int Timestamp = (int)((CurFrameData->PTS * TimeBase->Num) / TimeBase->Den);
TimecodesVector.push_back(Timestamp);
}
Timecodes = agi::vfr::Framerate(TimecodesVector);
FrameNumber = 0;
}
/// @brief Close video
///
void FFmpegSourceVideoProvider::Close() {
if (VideoSource) FFMS_DestroyVideoSource(VideoSource);
#ifdef WIN32
if (COMInited)
CoUninitialize();
#endif
}
/// @brief Get frame
/// @param _n
/// @return
///
const media::AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int n) {
FrameNumber = agi::util::mid(0, n, GetFrameCount() - 1);
// decode frame
const FFMS_Frame *SrcFrame = FFMS_GetFrame(VideoSource, FrameNumber, &ErrInfo);
if (SrcFrame == NULL) {
throw VideoDecodeError(std::string("Failed to retrieve frame:") + ErrInfo.Buffer);
}
CurFrame.SetTo(SrcFrame->Data[0], Width, Height, SrcFrame->Linesize[0]);
return CurFrame;
}
#endif /* WITH_FFMPEGSOURCE */
} // namespace ffms
} // namespace media

View file

@ -1,80 +0,0 @@
// Copyright (c) 2008-2009, Karl Blomster <thefluff@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file ffms_video.h
/// @brief FFmpegSource Video support.
/// @ingroup fmms video
#ifndef AGI_PRE
#include <vector>
#endif
#include <libaegisub/exception.h>
#include "../../libffms/include/ffms.h"
#include "libaegisub/vfr.h"
#include "../common/ffms_common.h"
#include "libmedia/video.h"
namespace media {
namespace ffms {
/// @class FFmpegSourceVideoProvider
/// @brief Implements video loading through the FFMS library.
class FFmpegSourceVideoProvider : public VideoProvider, FFmpegSourceProvider {
private:
FFMS_VideoSource *VideoSource; /// video source object
const FFMS_VideoProperties *VideoInfo; /// video properties
int Width; /// width in pixels
int Height; /// height in pixels
int FrameNumber; /// current framenumber
std::vector<int> KeyFramesList; /// list of keyframes
agi::vfr::Framerate Timecodes; /// vfr object
bool COMInited; /// COM initialization state
media::AegiVideoFrame CurFrame; /// current video frame
char FFMSErrMsg[1024]; /// FFMS error message
FFMS_ErrorInfo ErrInfo; /// FFMS error codes/messages
void LoadVideo(std::string filename);
void Close();
public:
FFmpegSourceVideoProvider(std::string filename);
~FFmpegSourceVideoProvider();
const media::AegiVideoFrame GetFrame(int n);
int GetPosition() const { return FrameNumber; }
int GetFrameCount() const { return VideoInfo->NumFrames; }
int GetWidth() const { return Width; }
int GetHeight() const { return Height; }
agi::vfr::Framerate GetFPS() const { return Timecodes; }
/// @brief Gets a list of keyframes
/// @return Returns a vector<int> of keyframes.
std::vector<int> GetKeyFrames() const { return KeyFramesList; };
std::string GetDecoderName() const { return "FFmpegSource"; }
/// @brief Gets the desired cache behavior.
/// @return Returns true.
bool WantsCaching() const { return true; }
};
} // namespace ffms
} // namespace media

View file

@ -1,433 +0,0 @@
// Copyright (c) 2009, Karl Blomster
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_yuv4mpeg.cpp
/// @brief Video provider reading YUV4MPEG files directly without depending on external libraries
/// @ingroup video_input
///
#include "config.h"
#include <libaegisub/log.h>
#include <libaegisub/util.h>
#include "yuv4mpeg.h"
namespace media {
// All of this cstdio bogus is because of one reason and one reason only:
// MICROSOFT'S IMPLEMENTATION OF STD::FSTREAM DOES NOT SUPPORT FILES LARGER THAN 2 GB.
// (yes, really)
// With cstdio it's at least possible to work around the problem...
#ifdef _MSC_VER
#define fseeko _fseeki64
#define ftello _ftelli64
#endif
/// @brief Constructor
/// @param filename The filename to open
YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(std::string filename)
: sf(NULL)
, inited(false)
, w (0)
, h (0)
, num_frames(-1)
, cur_fn(-1)
, pixfmt(Y4M_PIXFMT_NONE)
, imode(Y4M_ILACE_NOTSET)
{
fps_rat.num = -1;
fps_rat.den = 1;
try {
#ifdef WIN32
sf = _wfopen(filename.c_str(), L"rb");
#else
sf = fopen(filename.c_str(), "rb");
#endif
if (sf == NULL) throw agi::FileNotFoundError(filename);
CheckFileFormat();
ParseFileHeader(ReadHeader(0, false));
if (w <= 0 || h <= 0)
throw VideoOpenError("Invalid resolution");
if (fps_rat.num <= 0 || fps_rat.den <= 0) {
fps_rat.num = 25;
fps_rat.den = 1;
LOG_D("provider/video/yuv4mpeg") << "framerate info unavailable, assuming 25fps";
}
if (pixfmt == Y4M_PIXFMT_NONE)
pixfmt = Y4M_PIXFMT_420JPEG;
if (imode == Y4M_ILACE_NOTSET)
imode = Y4M_ILACE_UNKNOWN;
luma_sz = w * h;
switch (pixfmt) {
case Y4M_PIXFMT_420JPEG:
case Y4M_PIXFMT_420MPEG2:
case Y4M_PIXFMT_420PALDV:
chroma_sz = (w * h) >> 2; break;
case Y4M_PIXFMT_422:
chroma_sz = (w * h) >> 1; break;
/// @todo add support for more pixel formats
default:
throw VideoOpenError("Unsupported pixel format");
}
frame_sz = luma_sz + chroma_sz*2;
num_frames = IndexFile();
if (num_frames <= 0 || seek_table.empty())
throw VideoOpenError("Unable to determine file length");
cur_fn = 0;
fseeko(sf, 0, SEEK_SET);
}
catch (...) {
if (sf) fclose(sf);
throw;
}
}
/// @brief Destructor
YUV4MPEGVideoProvider::~YUV4MPEGVideoProvider() {
if (sf) fclose(sf);
}
/// @brief Checks if the file is an YUV4MPEG file or not
/// Note that it reports the error by throwing an exception,
/// not by returning a false value.
void YUV4MPEGVideoProvider::CheckFileFormat() {
char buf[10];
if (fread(buf, 10, 1, sf) != 1)
throw VideoNotSupported("CheckFileFormat: Failed reading header");
if (strncmp("YUV4MPEG2 ", buf, 10))
throw VideoNotSupported("CheckFileFormat: File is not a YUV4MPEG file (bad magic)");
fseeko(sf, 0, SEEK_SET);
}
/// @brief Read a frame or file header at a given file position
/// @param startpos The byte offset at where to start reading
/// @param reset_pos If true, the function will reset the file position to what it was before the function call before returning
/// @return A list of parameters
std::vector<std::string> YUV4MPEGVideoProvider::ReadHeader(int64_t startpos, bool reset_pos) {
int64_t oldpos = ftello(sf);
std::vector<std::string> tags;
std::string curtag;
int bytesread = 0;
int buf;
if (fseeko(sf, startpos, SEEK_SET))
throw VideoOpenError("YUV4MPEG video provider: ReadHeader: failed seeking to position %d"); //XXX:, startpos)));
// read header until terminating newline (0x0A) is found
while ((buf = fgetc(sf)) != 0x0A) {
if (ferror(sf))
throw VideoOpenError("ReadHeader: Failed to read from file");
if (feof(sf)) {
// you know, this is one of the places where it would be really nice
// to be able to throw an exception object that tells the caller that EOF was reached
LOG_D("provider/video/yuv4mpeg") << "ReadHeader: Reached EOF, returning";
break;
}
// some basic low-effort sanity checking
if (buf == 0x00)
throw VideoOpenError("ReadHeader: Malformed header (unexpected NUL)");
if (++bytesread >= YUV4MPEG_HEADER_MAXLEN)
throw VideoOpenError("ReadHeader: Malformed header (no terminating newline found)");
// found a new tag
if (buf == 0x20) {
tags.push_back(curtag);
curtag.clear();
}
else
curtag.append((const char*)buf);
}
// if only one tag with no trailing space was found (possible in the
// FRAME header case), make sure we get it
if (!curtag.empty()) {
tags.push_back(curtag);
curtag.clear();
}
if (reset_pos)
fseeko(sf, oldpos, SEEK_SET);
return tags;
}
/// @brief Parses a list of parameters and sets reader state accordingly
/// @param tags The list of parameters to parse
void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<std::string>& tags) {
if (tags.size() <= 1)
throw VideoOpenError("ParseFileHeader: contentless header");
if (tags.front() == "YUV4MPEG2")
throw VideoOpenError("ParseFileHeader: malformed header (bad magic)");
// temporary stuff
int t_w = -1;
int t_h = -1;
int t_fps_num = -1;
int t_fps_den = -1;
Y4M_InterlacingMode t_imode = Y4M_ILACE_NOTSET;
Y4M_PixelFormat t_pixfmt = Y4M_PIXFMT_NONE;
for (unsigned i = 1; i < tags.size(); i++) {
std::string tag;
tag = tags[i];
if (tag.find("W") == 0) {
tag.erase(0,1);
t_w = agi::util::strtoi(tag);
if (t_w == 0)
throw VideoOpenError("ParseFileHeader: invalid width");
}
else if (tag.find("H") == 0) {
tag.erase(0,1);
t_h = agi::util::strtoi(tag);
if (t_h == 0)
throw VideoOpenError("ParseFileHeader: invalid height");
}
else if (tag.find("F") == 0) {
tag.erase(0,1);
int i = tag.find(":");
std::string num(tag.substr(0,i));
std::string den(tag.substr(i+1,den.size()));
t_fps_num = agi::util::strtoi(num);
t_fps_den = agi::util::strtoi(den);
if ((t_fps_num == 0) || (t_fps_den == 0))
throw VideoOpenError("ParseFileHeader: invalid framerate");
}
else if (tag.find("C") == 0) {
tag.erase(0,1);
// technically this should probably be case sensitive,
// but being liberal in what you accept doesn't hurt
agi::util::str_lower(tag);
if (tag == "420") t_pixfmt = Y4M_PIXFMT_420JPEG; // is this really correct?
else if (tag == "420jpeg") t_pixfmt = Y4M_PIXFMT_420JPEG;
else if (tag == "420mpeg2") t_pixfmt = Y4M_PIXFMT_420MPEG2;
else if (tag == "420paldv") t_pixfmt = Y4M_PIXFMT_420PALDV;
else if (tag == "411") t_pixfmt = Y4M_PIXFMT_411;
else if (tag == "422") t_pixfmt = Y4M_PIXFMT_422;
else if (tag == "444") t_pixfmt = Y4M_PIXFMT_444;
else if (tag == "444alpha") t_pixfmt = Y4M_PIXFMT_444ALPHA;
else if (tag == "mono") t_pixfmt = Y4M_PIXFMT_MONO;
else
throw VideoOpenError("ParseFileHeader: invalid or unknown colorspace");
}
else if (tag.find("I") == 0) {
tag.erase(0,1);
agi::util::str_lower(tag);
if (tag == "p") t_imode = Y4M_ILACE_PROGRESSIVE;
else if (tag == "t") t_imode = Y4M_ILACE_TFF;
else if (tag == "b") t_imode = Y4M_ILACE_BFF;
else if (tag == "m") t_imode = Y4M_ILACE_MIXED;
else if (tag == "?") t_imode = Y4M_ILACE_UNKNOWN;
else
throw VideoOpenError("ParseFileHeader: invalid or unknown interlacing mode");
}
else
LOG_D("provider/video/yuv4mpeg") << "Unparsed tag: " << tags[i].c_str();
}
// The point of all this is to allow multiple YUV4MPEG2 headers in a single file
// (can happen if you concat several files) as long as they have identical
// header flags. The spec doesn't explicitly say you have to allow this,
// but the "reference implementation" (mjpegtools) does, so I'm doing it too.
if (inited) {
if (t_w > 0 && t_w != w)
throw VideoOpenError("ParseFileHeader: illegal width change");
if (t_h > 0 && t_h != h)
throw VideoOpenError("ParseFileHeader: illegal height change");
if ((t_fps_num > 0 && t_fps_den > 0) && (t_fps_num != fps_rat.num || t_fps_den != fps_rat.den))
throw VideoOpenError("ParseFileHeader: illegal framerate change");
if (t_pixfmt != Y4M_PIXFMT_NONE && t_pixfmt != pixfmt)
throw VideoOpenError("ParseFileHeader: illegal colorspace change");
if (t_imode != Y4M_ILACE_NOTSET && t_imode != imode)
throw VideoOpenError("ParseFileHeader: illegal interlacing mode change");
}
else {
w = t_w;
h = t_h;
fps_rat.num = t_fps_num;
fps_rat.den = t_fps_den;
pixfmt = t_pixfmt != Y4M_PIXFMT_NONE ? t_pixfmt : Y4M_PIXFMT_420JPEG;
imode = t_imode != Y4M_ILACE_NOTSET ? t_imode : Y4M_ILACE_UNKNOWN;
fps = double(fps_rat.num) / fps_rat.den;
inited = true;
}
}
/// @brief Parses a frame header
/// @param tags The list of parameters to parse
/// @return The flags set, as a binary mask
/// This function is currently unimplemented (it will always return Y4M_FFLAG_NONE).
YUV4MPEGVideoProvider::Y4M_FrameFlags YUV4MPEGVideoProvider::ParseFrameHeader(const std::vector<std::string>& tags) {
if (tags.front() == "FRAME")
throw VideoOpenError("ParseFrameHeader: malformed frame header (bad magic)");
/// @todo implement parsing of frame flags
return Y4M_FFLAG_NONE;
}
/// @brief Indexes the file
/// @return The number of frames found in the file
/// This function goes through the file, finds and parses all file and frame headers,
/// and creates a seek table that lists the byte positions of all frames so seeking
/// can easily be done.
int YUV4MPEGVideoProvider::IndexFile() {
int framecount = 0;
int64_t curpos = ftello(sf);
// the ParseFileHeader() call in LoadVideo() will already have read
// the file header for us and set the seek position correctly
while (true) {
curpos = ftello(sf); // update position
// continue reading headers until no more are found
std::vector<std::string> tags = ReadHeader(curpos, false);
curpos = ftello(sf);
if (tags.empty())
break; // no more headers
Y4M_FrameFlags flags = Y4M_FFLAG_NOTSET;
if (tags.front() != "YUV4MPEG2") {
ParseFileHeader(tags);
continue;
}
else if (tags.front() != "FRAME")
flags = ParseFrameHeader(tags);
if (flags == Y4M_FFLAG_NONE) {
framecount++;
seek_table.push_back(curpos);
// seek to next frame header start position
if (fseeko(sf, frame_sz, SEEK_CUR))
throw VideoOpenError("IndexFile: failed seeking to position %d"); //XXX: , curpos + frame_sz)));
}
else {
/// @todo implement rff flags etc
}
}
return framecount;
}
// http://bob.allegronetwork.com/prog/tricks.html#clamp
static inline int clamp(int x) {
x &= (~x) >> 31;
x -= 255;
x &= x >> 31;
x += 255;
return x;
}
/// @brief Gets a given frame
/// @param n The frame number to return
/// @return The video frame
const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n) {
cur_fn = agi::util::mid(0, n, num_frames - 1);
int uv_width = w / 2;
switch (pixfmt) {
case Y4M_PIXFMT_420JPEG:
case Y4M_PIXFMT_420MPEG2:
case Y4M_PIXFMT_420PALDV:
break;
/// @todo add support for more pixel formats
default:
throw "YUV4MPEG video provider: GetFrame: Unsupported source colorspace";
}
std::vector<uint8_t> planes[3];
planes[0].resize(luma_sz);
planes[1].resize(chroma_sz);
planes[2].resize(chroma_sz);
fseeko(sf, seek_table[n], SEEK_SET);
size_t ret;
ret = fread(&planes[0][0], luma_sz, 1, sf);
if (ret != 1 || feof(sf) || ferror(sf))
throw "YUV4MPEG video provider: GetFrame: failed to read luma plane";
for (int i = 1; i <= 2; i++) {
ret = fread(&planes[i][0], chroma_sz, 1, sf);
if (ret != 1 || feof(sf) || ferror(sf))
throw "YUV4MPEG video provider: GetFrame: failed to read chroma planes";
}
AegiVideoFrame dst_frame;
dst_frame.invertChannels = true;
dst_frame.w = w;
dst_frame.h = h;
dst_frame.pitch = w * 4;
dst_frame.Allocate();
const unsigned char *src_y = &planes[0][0];
const unsigned char *src_u = &planes[1][0];
const unsigned char *src_v = &planes[2][0];
unsigned char *dst = dst_frame.data;
for (int py = 0; py < h; ++py) {
for (int px = 0; px < w / 2; ++px) {
const int u = *src_u++ - 128;
const int v = *src_v++ - 128;
for (unsigned int i = 0; i < 2; ++i) {
const int y = (*src_y++ - 16) * 298;
*dst++ = clamp((y + 516 * u + 128) >> 8); // Blue
*dst++ = clamp((y - 100 * u - 208 * v + 128) >> 8); // Green
*dst++ = clamp((y + 409 * v + 128) >> 8); // Red
*dst++ = 0; // Alpha
}
}
// Roll back u/v on even lines
if (!(py & 1)) {
src_u -= uv_width;
src_v -= uv_width;
}
}
return dst_frame;
}
} // namespace media

View file

@ -1,158 +0,0 @@
// Copyright (c) 2009, Karl Blomster
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
//
// $Id$
/// @file video_provider_yuv4mpeg.h
/// @see video_provider_yuv4mpeg.cpp
/// @ingroup video_input
///
#ifndef MAGI_PRE
#include <stdio.h>
#include <vector>
#endif
#include "libmedia/video.h"
namespace media {
/// the maximum allowed header length, in bytes
#define YUV4MPEG_HEADER_MAXLEN 128
/// @class YUV4MPEGVideoProvider
/// @brief Implements reading of YUV4MPEG uncompressed video files
class YUV4MPEGVideoProvider : public VideoProvider {
/// Pixel formats
enum Y4M_PixelFormat {
Y4M_PIXFMT_NONE = -1, /// not set/unknown
/// 4:2:0 sampling variants.
/// afaict the only difference between these three
/// is the chroma sample location, and nobody cares about that.
Y4M_PIXFMT_420JPEG, /// 4:2:0, H/V centered, for JPEG/MPEG-1
Y4M_PIXFMT_420MPEG2, /// 4:2:0, H cosited, for MPEG-2
Y4M_PIXFMT_420PALDV, /// 4:2:0, alternating Cb/Cr, for PAL-DV
Y4M_PIXFMT_411, /// 4:1:1, H cosited
Y4M_PIXFMT_422, /// 4:2:2, H cosited
Y4M_PIXFMT_444, /// 4:4:4, i.e. no chroma subsampling
Y4M_PIXFMT_444ALPHA, /// 4:4:4 plus alpha channel
Y4M_PIXFMT_MONO, /// luma only (grayscale)
};
/// Interlacing mode for an entire stream
enum Y4M_InterlacingMode {
Y4M_ILACE_NOTSET = -1, /// undefined
Y4M_ILACE_PROGRESSIVE, /// progressive (no interlacing)
Y4M_ILACE_TFF, /// interlaced, top field first
Y4M_ILACE_BFF, /// interlaced, bottom field first
Y4M_ILACE_MIXED, /// mixed interlaced/progressive, possibly with RFF flags
Y4M_ILACE_UNKNOWN, /// unknown interlacing mode (not the same as undefined)
};
/// Frame information flags
enum Y4M_FrameFlags {
Y4M_FFLAG_NOTSET = -1, /// undefined
Y4M_FFLAG_NONE = 0x0000, /// no flags set
/// field order/repeat field flags
Y4M_FFLAG_R_TFF = 0x0001, /// top field first
Y4M_FFLAG_R_TFF_R = 0x0002, /// top field first, and repeat that field
Y4M_FFLAG_R_BFF = 0x0004, /// bottom field first
Y4M_FFLAG_R_BFF_R = 0x0008, /// bottom field first, and repeat that field
Y4M_FFLAG_R_P = 0x0010, /// progressive
Y4M_FFLAG_R_P_R = 0x0020, /// progressive, and repeat frame once
Y4M_FFLAG_R_P_RR = 0x0040, /// progressive, and repeat frame twice
/// temporal sampling flags
Y4M_FFLAG_T_P = 0x0080, /// progressive (fields sampled at the same time)
Y4M_FFLAG_T_I = 0x0100, /// interlaced (fields sampled at different times)
/// chroma subsampling flags
Y4M_FFLAG_C_P = 0x0200, /// progressive (whole frame subsampled)
Y4M_FFLAG_C_I = 0x0400, /// interlaced (fields subsampled independently)
Y4M_FFLAG_C_UNKNOWN = 0x0800, /// unknown (only allowed for non-4:2:0 sampling)
};
FILE *sf; /// source file
bool inited; /// initialization state
int w, h; /// frame width/height
int num_frames; /// length of file in frames
int frame_sz; /// size of each frame in bytes
int luma_sz; /// size of the luma plane of each frame, in bytes
int chroma_sz; /// size of one of the two chroma planes of each frame, in bytes
int cur_fn; /// current frame number
Y4M_PixelFormat pixfmt; /// colorspace/pixel format
Y4M_InterlacingMode imode; /// interlacing mode (for the entire stream)
struct {
int num; /// numerator
int den; /// denominator
} fps_rat; /// framerate
agi::vfr::Framerate fps;
/// a list of byte positions detailing where in the file
/// each frame header can be found
std::vector<int64_t> seek_table;
void CheckFileFormat();
void ParseFileHeader(const std::vector<std::string>& tags);
Y4M_FrameFlags ParseFrameHeader(const std::vector<std::string>& tags);
std::vector<std::string> ReadHeader(int64_t startpos, bool reset_pos=false);
int IndexFile();
public:
YUV4MPEGVideoProvider(std::string filename);
~YUV4MPEGVideoProvider();
const AegiVideoFrame GetFrame(int n);
int GetPosition() const { return cur_fn; }
int GetFrameCount() const { return num_frames; }
int GetWidth() const { return w; }
int GetHeight() const { return h; }
agi::vfr::Framerate GetFPS() const { return fps; }
std::vector<int> GetKeyFrames() const { return std::vector<int>(); };
std::string GetDecoderName() const { return "YU4MPEG"; };
bool WantsCaching() const { return true; };
};
} // namespace media