2006-01-22 13:44:53 +01:00
// 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.
//
2009-07-29 07:43:02 +02:00
// Aegisub Project http://www.aegisub.org/
2006-01-22 13:44:53 +01:00
//
2009-07-29 07:43:02 +02:00
// $Id$
/// @file video_provider_avs.cpp
/// @brief Avisynth-based video provider
/// @ingroup video_input
///
2006-01-22 13:44:53 +01:00
2007-01-21 08:12:47 +01:00
///////////
// Headers
2009-01-04 07:31:48 +01:00
# include "config.h"
2007-01-21 07:30:19 +01:00
# include <wx/wxprec.h>
2008-01-22 03:54:16 +01:00
# ifdef WITH_AVISYNTH
2006-01-22 13:44:53 +01:00
# include <wx/filename.h>
# include <wx/msw/registry.h>
2006-12-26 02:08:46 +01:00
# include <wx/filename.h>
2008-03-05 03:05:01 +01:00
# include "video_provider_avs.h"
2007-01-21 07:30:19 +01:00
# include "video_context.h"
2006-01-22 13:44:53 +01:00
# include "options.h"
2007-06-21 02:46:50 +02:00
# include "standard_paths.h"
2007-01-01 04:29:20 +01:00
# include "vfr.h"
2007-01-27 07:15:25 +01:00
# include "gl_wrap.h"
2008-07-15 02:08:05 +02:00
# include "mkv_wrap.h"
# include "vfw_wrap.h"
2009-07-14 23:28:49 +02:00
# include "charset_conv.h"
2006-01-22 13:44:53 +01:00
2006-12-19 18:30:25 +01:00
///////////////
// Constructor
2009-07-23 17:16:53 +02:00
AvisynthVideoProvider : : AvisynthVideoProvider ( wxString _filename ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( wxString : : Format ( _T ( " AvisynthVideoProvider: Creating new AvisynthVideoProvider: \" %s \" , \" %s \" " ) , _filename , _subfilename ) ) ;
2006-02-24 03:54:30 +01:00
bool mpeg2dec3_priority = true ;
2006-01-22 13:44:53 +01:00
RGB32Video = NULL ;
2009-07-20 02:39:38 +02:00
fps = 0 ;
2007-01-01 04:29:20 +01:00
num_frames = 0 ;
2007-01-21 07:30:19 +01:00
last_fnum = - 1 ;
2007-07-29 11:06:38 +02:00
byFrame = false ;
2008-07-15 02:08:05 +02:00
KeyFrames . Clear ( ) ;
keyFramesLoaded = false ;
isVfr = false ;
2006-01-22 13:44:53 +01:00
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: Opening video " ) ) ;
2006-02-25 21:48:32 +01:00
RGB32Video = OpenVideo ( _filename , mpeg2dec3_priority ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: Video opened " ) ) ;
2006-01-22 13:44:53 +01:00
2009-05-15 14:44:36 +02:00
vi = RGB32Video - > GetVideoInfo ( ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: Got video info " ) ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider: Done creating AvisynthVideoProvider " ) ) ;
2006-01-22 13:44:53 +01:00
}
2006-12-19 18:30:25 +01:00
//////////////
// Destructor
2006-02-23 04:41:29 +01:00
AvisynthVideoProvider : : ~ AvisynthVideoProvider ( ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: Destroying AvisynthVideoProvider " ) ) ;
2006-01-22 13:44:53 +01:00
RGB32Video = NULL ;
2007-01-21 07:30:19 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: Destroying frame " ) ) ;
iframe . Clear ( ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider: AvisynthVideoProvider destroyed " ) ) ;
2006-01-22 13:44:53 +01:00
}
2006-12-19 18:30:25 +01:00
2006-01-22 13:44:53 +01:00
2007-01-21 07:30:19 +01:00
////////////////////////////////////// VIDEO PROVIDER //////////////////////////////////////
2006-01-22 13:44:53 +01:00
2006-12-19 18:30:25 +01:00
/////////////////////////////////////////
// Actually open the video into Avisynth
2009-07-23 17:16:53 +02:00
PClip AvisynthVideoProvider : : OpenVideo ( wxString _filename , bool mpeg2dec3_priority ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening video " ) ) ;
2006-01-22 13:44:53 +01:00
wxMutexLocker lock ( AviSynthMutex ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Got AVS mutex " ) ) ;
2006-01-22 13:44:53 +01:00
AVSValue script ;
2007-07-29 11:06:38 +02:00
byFrame = false ;
usedDirectShow = false ;
2007-08-20 00:21:41 +02:00
decoderName = _ ( " Unknown " ) ;
2006-01-22 13:44:53 +01:00
2009-07-23 21:57:57 +02:00
wxString extension = _filename . Right ( 4 ) ;
2006-01-22 13:44:53 +01:00
extension . LowerCase ( ) ;
try {
// Prepare filename
2006-12-26 02:08:46 +01:00
//char *videoFilename = env->SaveString(_filename.mb_str(wxConvLocal));
wxFileName fname ( _filename ) ;
2009-07-14 23:28:49 +02:00
char * videoFilename = env - > SaveString ( fname . GetShortPath ( ) . mb_str ( csConvLocal ) ) ;
2006-01-22 13:44:53 +01:00
2006-12-19 18:30:25 +01:00
// Avisynth file, just import it
2006-01-22 13:44:53 +01:00
if ( extension = = _T ( " .avs " ) ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening .avs file with Import " ) ) ;
2006-01-22 13:44:53 +01:00
script = env - > Invoke ( " Import " , videoFilename ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Finished " ) ) ;
2007-10-19 02:55:03 +02:00
decoderName = _T ( " Import " ) ;
2006-12-17 05:58:10 +01:00
}
2006-12-19 18:30:25 +01:00
// Open avi file with AviSource
2006-12-17 05:58:10 +01:00
else if ( extension = = _T ( " .avi " ) ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening .avi file with AviSource " ) ) ;
2006-01-22 13:44:53 +01:00
try {
const char * argnames [ 2 ] = { 0 , " audio " } ;
AVSValue args [ 2 ] = { videoFilename , false } ;
script = env - > Invoke ( " AviSource " , AVSValue ( args , 2 ) , argnames ) ;
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Successfully opened .avi file without audio " ) ) ;
2007-07-29 11:06:38 +02:00
byFrame = true ;
2007-08-20 00:21:41 +02:00
decoderName = _T ( " AviSource " ) ;
2006-12-19 18:30:25 +01:00
}
// On Failure, fallback to DSS
catch ( AvisynthError & ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " Failed to open .avi file with AviSource, switching to DirectShowSource " ) ) ;
2006-01-22 13:44:53 +01:00
goto directshowOpen ;
}
}
2006-12-19 18:30:25 +01:00
// Open d2v with mpeg2dec3
2007-01-11 20:49:37 +01:00
else if ( extension = = _T ( " .d2v " ) & & env - > FunctionExists ( " Mpeg2Dec3_Mpeg2Source " ) & & mpeg2dec3_priority ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening .d2v file with Mpeg2Dec3_Mpeg2Source " ) ) ;
script = env - > Invoke ( " Mpeg2Dec3_Mpeg2Source " , videoFilename ) ;
2007-08-20 00:21:41 +02:00
decoderName = _T ( " Mpeg2Dec3_Mpeg2Source " ) ;
2007-01-11 20:49:37 +01:00
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
2007-01-15 21:48:58 +01:00
if ( env - > FunctionExists ( " SetPlanarLegacyAlignment " ) ) {
AVSValue args [ 2 ] = { script , true } ;
script = env - > Invoke ( " SetPlanarLegacyAlignment " , AVSValue ( args , 2 ) ) ;
}
2007-01-11 20:49:37 +01:00
}
// If that fails, try opening it with DGDecode
else if ( extension = = _T ( " .d2v " ) & & env - > FunctionExists ( " DGDecode_Mpeg2Source " ) ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening .d2v file with DGDecode_Mpeg2Source " ) ) ;
script = env - > Invoke ( " Mpeg2Source " , videoFilename ) ;
2007-08-20 00:21:41 +02:00
decoderName = _T ( " DGDecode_Mpeg2Source " ) ;
2007-01-11 20:49:37 +01:00
//note that DGDecode will also have issues like if the version is too ancient but no sane person
//would use that anyway
2006-12-17 05:58:10 +01:00
}
2006-12-19 18:30:25 +01:00
else if ( extension = = _T ( " .d2v " ) & & env - > FunctionExists ( " Mpeg2Source " ) ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening .d2v file with other Mpeg2Source " ) ) ;
2006-01-22 13:44:53 +01:00
script = env - > Invoke ( " Mpeg2Source " , videoFilename ) ;
2007-08-20 00:21:41 +02:00
decoderName = _T ( " Mpeg2Source " ) ;
2007-01-11 20:49:37 +01:00
//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 ) ;
2006-12-17 05:58:10 +01:00
}
2006-12-19 18:30:25 +01:00
2009-07-21 22:36:27 +02:00
// Some other format, such as mkv, mp4, ogm... try both flavors of DirectShowSource
2006-01-22 13:44:53 +01:00
else {
2007-08-20 00:56:22 +02:00
directshowOpen :
2009-07-21 22:36:27 +02:00
// DirectShowSource
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Opening file with DirectShowSource " ) ) ;
// Try loading DirectShowSource2
bool dss2 = false ;
if ( env - > FunctionExists ( " dss2 " ) ) dss2 = true ;
if ( ! dss2 ) {
wxFileName dss2path ( StandardPaths : : DecodePath ( _T ( " ?data/avss.dll " ) ) ) ;
if ( dss2path . FileExists ( ) ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Loading DirectShowSource2 " ) ) ;
env - > Invoke ( " LoadPlugin " , env - > SaveString ( dss2path . GetFullPath ( ) . mb_str ( csConvLocal ) ) ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Loaded DirectShowSource2 " ) ) ;
2006-12-19 18:30:25 +01:00
}
2006-12-17 05:58:10 +01:00
}
2006-12-19 18:30:25 +01:00
2009-07-21 22:36:27 +02:00
// If DSS2 loaded properly, try using it
dss2 = false ;
if ( env - > FunctionExists ( " dss2 " ) ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Invoking DSS2 " ) ) ;
script = env - > Invoke ( " DSS2 " , videoFilename ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Successfully opened file with DSS2 " ) ) ;
dss2 = true ;
decoderName = _T ( " DSS2 " ) ;
2006-12-17 05:58:10 +01:00
}
2006-12-19 18:30:25 +01:00
2009-07-21 22:36:27 +02:00
// Try DirectShowSource
if ( ! dss2 ) {
// Load DirectShowSource.dll from app dir if it exists
wxFileName dsspath ( StandardPaths : : DecodePath ( _T ( " ?data/DirectShowSource.dll " ) ) ) ;
if ( dsspath . FileExists ( ) ) {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Loading DirectShowSource " ) ) ;
env - > Invoke ( " LoadPlugin " , env - > SaveString ( dsspath . GetFullPath ( ) . mb_str ( csConvLocal ) ) ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Loaded DirectShowSource " ) ) ;
2007-06-17 00:07:43 +02:00
}
2009-07-21 22:36:27 +02:00
// Then try using DSS
if ( env - > FunctionExists ( " DirectShowSource " ) ) {
const char * argnames [ 3 ] = { 0 , " video " , " audio " } ;
AVSValue args [ 3 ] = { videoFilename , true , false } ;
script = env - > Invoke ( " DirectShowSource " , AVSValue ( args , 3 ) , argnames ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Successfully opened file with DSS without audio " ) ) ;
usedDirectShow = true ;
decoderName = _T ( " DirectShowSource " ) ;
2006-12-19 18:30:25 +01:00
}
2009-07-21 22:36:27 +02:00
// Failed to find a suitable function
else {
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: DSS function not found " ) ) ;
throw AvisynthError ( " No function suitable for opening the video found " ) ;
2006-12-19 18:30:25 +01:00
}
}
}
}
// Catch errors
catch ( AvisynthError & err ) {
2009-07-14 23:28:49 +02:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Avisynth error: " ) + wxString ( err . msg , csConvLocal ) ) ;
throw _T ( " AviSynth error: " ) + wxString ( err . msg , csConvLocal ) ;
2006-01-22 13:44:53 +01:00
}
2006-12-19 18:30:25 +01:00
// Check if video was loaded properly
2008-03-06 22:38:40 +01:00
if ( ! script . IsClip ( ) | | ! script . AsClip ( ) - > GetVideoInfo ( ) . HasVideo ( ) ) {
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: No suitable video found " ) ) ;
2007-07-18 15:46:38 +02:00
throw _T ( " Avisynth: No usable video found in " ) + _filename ;
2006-12-17 05:58:10 +01:00
}
2006-01-22 13:44:53 +01:00
2008-07-15 02:08:05 +02:00
// Read keyframes and timecodes from MKV file
isVfr = false ;
FrameRate temp ;
double overFps = 0 ;
bool mkvOpen = MatroskaWrapper : : wrapper . IsOpen ( ) ;
KeyFrames . Clear ( ) ;
if ( extension = = _T ( " .mkv " ) | | mkvOpen ) {
// Parse mkv
if ( ! mkvOpen ) MatroskaWrapper : : wrapper . Open ( _filename ) ;
// Get keyframes
KeyFrames = MatroskaWrapper : : wrapper . GetKeyFrames ( ) ;
keyFramesLoaded = true ;
// Ask to override timecodes
int override = wxYES ;
if ( VFR_Output . IsLoaded ( ) ) override = wxMessageBox ( _ ( " You already have timecodes loaded. Replace them with the timecodes from the Matroska file? " ) , _ ( " Replace timecodes? " ) , wxYES_NO | wxICON_QUESTION ) ;
if ( override = = wxYES ) {
MatroskaWrapper : : wrapper . SetToTimecodes ( temp ) ;
isVfr = temp . GetFrameRateType ( ) = = VFR ;
if ( isVfr ) {
overFps = temp . GetCommonFPS ( ) ;
MatroskaWrapper : : wrapper . SetToTimecodes ( VFR_Input ) ;
MatroskaWrapper : : wrapper . SetToTimecodes ( VFR_Output ) ;
trueFrameRate = temp ;
}
}
// 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 = = _T ( " .avi " ) ) {
keyFramesLoaded = false ;
KeyFrames . Clear ( ) ;
KeyFrames = VFWWrapper : : GetKeyFrames ( _filename ) ;
keyFramesLoaded = true ;
}
# endif /* __WINDOWS__ */
// Check if the file is all keyframes
bool isAllKeyFrames = true ;
for ( unsigned int i = 1 ; i < KeyFrames . GetCount ( ) ; 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 ( ) ;
keyFramesLoaded = false ;
}
2006-01-22 13:44:53 +01:00
// Convert to RGB32
2009-07-20 03:32:01 +02:00
script = env - > Invoke ( " ConvertToRGB32 " , script ) ;
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Converted to RGB32 " ) ) ;
2006-01-22 13:44:53 +01:00
// Cache
2006-12-17 05:58:10 +01:00
AVSTRACE ( _T ( " AvisynthVideoProvider::OpenVideo: Finished opening video, AVS mutex will be released now " ) ) ;
2006-02-22 20:47:44 +01:00
return ( env - > Invoke ( " Cache " , script ) ) . AsClip ( ) ;
2006-01-22 13:44:53 +01:00
}
2006-12-19 18:30:25 +01:00
2007-01-21 07:30:19 +01:00
////////////////////////
// Actually get a frame
2009-07-20 05:50:25 +02:00
const AegiVideoFrame AvisynthVideoProvider : : GetFrame ( int _n ) {
2007-01-21 07:30:19 +01:00
// Transform n if overriden
int n = _n ;
if ( frameTime . Count ( ) ) {
if ( n < 0 ) n = 0 ;
if ( n > = ( signed ) frameTime . Count ( ) ) n = frameTime . Count ( ) - 1 ;
int time = frameTime [ n ] ;
double curFps = ( double ) vi . fps_numerator / ( double ) vi . fps_denominator ;
n = time * curFps / 1000.0 ;
}
// Get avs frame
AVSTRACE ( _T ( " AvisynthVideoProvider::GetFrame " ) ) ;
wxMutexLocker lock ( AviSynthMutex ) ;
2009-05-15 14:44:36 +02:00
PVideoFrame frame = RGB32Video - > GetFrame ( n , env ) ;
2007-01-21 07:30:19 +01:00
int Bpp = vi . BitsPerPixel ( ) / 8 ;
// Aegisub's video frame
AegiVideoFrame & final = iframe ;
final . flipped = false ;
final . cppAlloc = true ;
2007-01-29 06:47:29 +01:00
final . invertChannels = false ;
2007-01-21 07:30:19 +01:00
// Format
2009-07-20 05:50:25 +02:00
final . format = FORMAT_RGB32 ;
final . flipped = true ;
final . invertChannels = true ;
2007-01-21 07:30:19 +01:00
// Set size properties
final . pitch [ 0 ] = frame - > GetPitch ( ) ;
final . w = frame - > GetRowSize ( ) / Bpp ;
final . h = frame - > GetHeight ( ) ;
// Allocate
final . Allocate ( ) ;
// Copy
memcpy ( final . data [ 0 ] , frame - > GetReadPtr ( ) , final . pitch [ 0 ] * final . h ) ;
// Set last number
last_fnum = n ;
return final ;
}
2007-01-01 04:29:20 +01:00
////////////////////////
// Override frame times
void AvisynthVideoProvider : : OverrideFrameTimeList ( wxArrayInt list ) {
frameTime = list ;
num_frames = frameTime . Count ( ) ;
}
2007-01-23 05:42:08 +01:00
2007-07-29 11:06:38 +02:00
///////////////
// Get warning
2009-07-23 17:16:53 +02:00
wxString AvisynthVideoProvider : : GetWarning ( ) {
2008-03-07 22:24:14 +01:00
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 " " ;
2007-07-29 11:06:38 +02:00
}
2007-01-23 05:42:08 +01:00
# endif
2009-07-29 07:43:02 +02:00