2014-03-24 15:05:01 +01:00
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
2006-02-24 09:30:08 +01:00
//
2014-03-24 15:05:01 +01:00
// 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.
2006-02-24 09:30:08 +01:00
//
2014-03-24 15:05:01 +01:00
// 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.
2006-02-24 09:30:08 +01:00
//
2009-07-29 07:43:02 +02:00
// Aegisub Project http://www.aegisub.org/
2013-01-04 16:01:50 +01:00
# include "video_provider_manager.h"
2010-06-09 01:21:39 +02:00
2023-07-16 17:52:21 +02:00
# include "compat.h"
2014-03-24 15:44:20 +01:00
# include "factory_manager.h"
2014-03-24 15:05:01 +01:00
# include "include/aegisub/video_provider.h"
2013-01-07 02:50:09 +01:00
# include "options.h"
2007-01-21 07:30:19 +01:00
2013-01-04 16:01:50 +01:00
# include <libaegisub/log.h>
2023-07-16 17:52:21 +02:00
# include <libaegisub/format.h>
2007-01-21 07:30:19 +01:00
2014-03-24 15:44:20 +01:00
# include <boost/range/iterator_range.hpp>
2023-07-16 17:52:21 +02:00
# include <wx/choicdlg.h>
2014-03-25 17:51:38 +01:00
std : : unique_ptr < VideoProvider > CreateDummyVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
std : : unique_ptr < VideoProvider > CreateYUV4MPEGVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
std : : unique_ptr < VideoProvider > CreateFFmpegSourceVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
std : : unique_ptr < VideoProvider > CreateAvisynthVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
2022-08-08 02:14:31 +02:00
std : : unique_ptr < VideoProvider > CreateBSVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
2023-03-16 02:22:59 +01:00
std : : unique_ptr < VideoProvider > CreateVapourSynthVideoProvider ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
2014-03-24 15:05:01 +01:00
std : : unique_ptr < VideoProvider > CreateCacheVideoProvider ( std : : unique_ptr < VideoProvider > ) ;
namespace {
struct factory {
const char * name ;
2014-03-25 17:51:38 +01:00
std : : unique_ptr < VideoProvider > ( * create ) ( agi : : fs : : path const & , std : : string const & , agi : : BackgroundRunner * ) ;
2014-03-24 15:05:01 +01:00
bool hidden ;
2023-07-16 17:52:21 +02:00
std : : function < bool ( agi : : fs : : path const & ) > wants_to_open = [ ] ( auto p ) { return false ; } ;
2014-03-24 15:05:01 +01:00
} ;
const factory providers [ ] = {
{ " Dummy " , CreateDummyVideoProvider , true } ,
{ " YUV4MPEG " , CreateYUV4MPEGVideoProvider , true } ,
# ifdef WITH_FFMS2
{ " FFmpegSource " , CreateFFmpegSourceVideoProvider , false } ,
# endif
# ifdef WITH_AVISYNTH
2023-07-16 17:52:21 +02:00
{ " Avisynth " , CreateAvisynthVideoProvider , false , [ ] ( auto p ) { return agi : : fs : : HasExtension ( p , " avs " ) ; } } ,
2022-08-08 02:14:31 +02:00
# endif
# ifdef WITH_BESTSOURCE
2022-08-23 20:13:45 +02:00
{ " BestSource (SLOW) " , CreateBSVideoProvider , false } ,
2022-08-16 15:49:29 +02:00
# endif
# ifdef WITH_VAPOURSYNTH
2023-07-16 17:52:21 +02:00
{ " VapourSynth " , CreateVapourSynthVideoProvider , false , [ ] ( auto p ) { return agi : : fs : : HasExtension ( p , " py " ) | | agi : : fs : : HasExtension ( p , " vpy " ) ; } } ,
2014-03-24 15:05:01 +01:00
# endif
} ;
}
std : : vector < std : : string > VideoProviderFactory : : GetClasses ( ) {
2014-03-24 15:44:20 +01:00
return : : GetClasses ( boost : : make_iterator_range ( std : : begin ( providers ) , std : : end ( providers ) ) ) ;
2014-03-24 15:05:01 +01:00
}
2014-03-25 17:51:38 +01:00
std : : unique_ptr < VideoProvider > VideoProviderFactory : : GetProvider ( agi : : fs : : path const & filename , std : : string const & colormatrix , agi : : BackgroundRunner * br ) {
2014-03-24 15:05:01 +01:00
auto preferred = OPT_GET ( " Video/Provider " ) - > GetString ( ) ;
2014-03-24 15:44:20 +01:00
auto sorted = GetSorted ( boost : : make_iterator_range ( std : : begin ( providers ) , std : : end ( providers ) ) , preferred ) ;
2007-01-21 07:30:19 +01:00
2023-07-16 17:52:21 +02:00
RearrangeWithPriority ( sorted , filename ) ;
2013-01-04 16:01:50 +01:00
bool found = false ;
bool supported = false ;
2010-08-02 08:32:01 +02:00
std : : string errors ;
errors . reserve ( 1024 ) ;
2013-01-04 16:01:50 +01:00
2023-07-16 17:52:21 +02:00
auto tried_providers = sorted . begin ( ) ;
auto finalize_provider = [ & ] ( std : : unique_ptr < VideoProvider > provider ) {
return provider - > WantsCaching ( ) ? CreateCacheVideoProvider ( std : : move ( provider ) ) : std : : move ( provider ) ;
} ;
for ( ; tried_providers < sorted . end ( ) ; tried_providers + + ) {
auto factory = * tried_providers ;
2010-12-29 20:35:45 +01:00
std : : string err ;
2006-02-24 09:43:44 +01:00
try {
2014-03-25 17:51:38 +01:00
auto provider = factory - > create ( filename , colormatrix , br ) ;
2014-03-24 15:05:01 +01:00
if ( ! provider ) continue ;
LOG_I ( " manager/video/provider " ) < < factory - > name < < " : opened " < < filename ;
2023-07-16 17:52:21 +02:00
return finalize_provider ( std : : move ( provider ) ) ;
2010-08-02 08:32:01 +02:00
}
2023-07-16 17:52:21 +02:00
catch ( VideoNotSupported const & ex ) {
2013-01-04 16:01:50 +01:00
found = true ;
2023-07-16 17:52:21 +02:00
err = " video is not in a supported format: " + ex . GetMessage ( ) ;
2010-08-02 08:32:01 +02:00
}
catch ( VideoOpenError const & ex ) {
2013-01-04 16:01:50 +01:00
supported = true ;
err = ex . GetMessage ( ) ;
2006-02-24 09:43:44 +01:00
}
2010-12-29 20:35:45 +01:00
catch ( agi : : vfr : : Error const & ex ) {
2013-01-04 16:01:50 +01:00
supported = true ;
err = ex . GetMessage ( ) ;
2010-12-29 20:35:45 +01:00
}
2013-01-04 16:01:50 +01:00
2014-03-24 15:05:01 +01:00
errors + = std : : string ( factory - > name ) + " : " + err + " \n " ;
LOG_D ( " manager/video/provider " ) < < factory - > name < < " : " < < err ;
2023-07-16 17:52:21 +02:00
if ( factory - > name = = preferred )
break ;
}
// We failed to load the video using the preferred video provider (and the ones before it).
// The user might want to know about this, so show a dialog and let them choose what other provider to try.
std : : vector < const factory * > remaining_providers ( tried_providers + 1 , sorted . end ( ) ) ;
if ( ! remaining_providers . size ( ) ) {
// No provider could open the file
LOG_E ( " manager/video/provider " ) < < " Could not open " < < filename ;
std : : string msg = " Could not open " + filename . string ( ) + " : \n " + errors ;
if ( ! found ) throw agi : : fs : : FileNotFound ( filename . string ( ) ) ;
if ( ! supported ) throw VideoNotSupported ( msg ) ;
throw VideoOpenError ( msg ) ;
2006-02-24 09:43:44 +01:00
}
2006-02-24 09:30:08 +01:00
2023-07-16 17:52:21 +02:00
std : : vector < std : : string > names ;
for ( auto const & f : remaining_providers )
names . push_back ( f - > name ) ;
2010-08-02 08:32:01 +02:00
2023-07-16 17:52:21 +02:00
int choice = wxGetSingleChoiceIndex ( agi : : format ( " Could not open %s with the preferred provider: \n \n %s \n Please choose a different video provider to try: " , filename . string ( ) , errors ) , _ ( " Error loading video " ) , to_wx ( names ) ) ;
if ( choice = = - 1 ) {
throw agi : : UserCancelException ( " video loading cancelled by user " ) ;
}
try {
auto factory = remaining_providers [ choice ] ;
auto provider = factory - > create ( filename , colormatrix , br ) ;
if ( ! provider )
throw VideoNotSupported ( " Video provider returned null pointer " ) ;
LOG_I ( " manager/video/provider " ) < < factory - > name < < " : opened " < < filename ;
return finalize_provider ( std : : move ( provider ) ) ;
} catch ( agi : : vfr : : Error const & ex ) {
throw VideoOpenError ( ex . GetMessage ( ) ) ;
}
2006-02-24 09:30:08 +01:00
}