// 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 // // Website: http://aegisub.cellosoft.com // Contact: mailto:zeratul@cellosoft.com // #include #include #include "video_provider.h" #include "options.h" #include "main.h" VideoProvider::VideoProvider(wxString _filename, wxString _subfilename, double _zoom, bool &usedDirectshow, bool mpeg2dec3_priority) { RGB32Video = NULL; SubtitledVideo = NULL; ResizedVideo = NULL; data = NULL; last_fnum = -1; subfilename = _subfilename; zoom = _zoom; LoadVSFilter(); RGB32Video = OpenVideo(_filename,usedDirectshow,mpeg2dec3_priority); dar = GetSourceWidth()/(double)GetSourceHeight(); SubtitledVideo = ApplySubtitles(subfilename, RGB32Video); ResizedVideo = ApplyDARZoom(zoom, dar, SubtitledVideo); } VideoProvider::~VideoProvider() { RGB32Video = NULL; SubtitledVideo = NULL; ResizedVideo = NULL; delete data; } void VideoProvider::RefreshSubtitles() { ResizedVideo = NULL; SubtitledVideo = NULL; SubtitledVideo = ApplySubtitles(subfilename, RGB32Video); ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo); GetFrame(last_fnum,true); } void VideoProvider::SetDAR(double _dar) { dar = _dar; ResizedVideo = NULL; delete data; data = NULL; ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo); GetFrame(last_fnum,true); } void VideoProvider::SetZoom(double _zoom) { zoom = _zoom; ResizedVideo = NULL; delete data; data = NULL; ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo); GetFrame(last_fnum,true); } PClip VideoProvider::OpenVideo(wxString _filename, bool &usedDirectshow, bool mpeg2dec3_priority) { wxMutexLocker lock(AviSynthMutex); AVSValue script; usedDirectshow = false; wxString extension = _filename.Right(4); extension.LowerCase(); try { // Prepare filename char *videoFilename = env->SaveString(_filename.mb_str(wxConvLocal)); // Load depending on extension if (extension == _T(".avs")) { script = env->Invoke("Import", videoFilename); } else if (extension == _T(".avi")) { try { const char *argnames[2] = { 0, "audio" }; AVSValue args[2] = { videoFilename, false }; script = env->Invoke("AviSource", AVSValue(args,2), argnames); //fix me, check for video? } catch (AvisynthError &) { goto directshowOpen; } } else if (extension == _T(".d2v") && env->FunctionExists("mpeg2dec3_Mpeg2Source") && mpeg2dec3_priority) //prefer mpeg2dec3 script = env->Invoke("mpeg2dec3_Mpeg2Source", videoFilename); else if (extension == _T(".d2v") && env->FunctionExists("Mpeg2Source")) //try other mpeg2source script = env->Invoke("Mpeg2Source", videoFilename); else { directshowOpen: 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); usedDirectshow = true; } else throw AvisynthError("No function suitable for opening the video found"); } } catch (AvisynthError &err) { throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal); } if (!script.AsClip()->GetVideoInfo().HasVideo()) throw _T("No usable video found in ") + _filename; // Convert to RGB32 script = env->Invoke("ConvertToRGB32", script); // Cache return (env->Invoke("InternalCache", script)).AsClip(); } PClip VideoProvider::ApplySubtitles(wxString _filename, PClip videosource) { wxMutexLocker lock(AviSynthMutex); // Insert subs AVSValue script; char temp[512]; strcpy(temp,_filename.mb_str(wxConvLocal)); AVSValue args[2] = { videosource, temp }; try { script = env->Invoke("TextSub", AVSValue(args,2)); } catch (AvisynthError &err) { throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal); } // Cache return (env->Invoke("InternalCache", script)).AsClip(); } PClip VideoProvider::ApplyDARZoom(double _zoom, double _dar, PClip videosource) { wxMutexLocker lock(AviSynthMutex); AVSValue script; VideoInfo vil = videosource->GetVideoInfo(); int w = vil.height * _zoom * _dar; int h = vil.height * _zoom; try { // Resize if (!env->FunctionExists(Options.AsText(_T("Video resizer")).mb_str(wxConvLocal))) throw AvisynthError("Selected resizer doesn't exist"); AVSValue args[3] = { videosource, w, h }; script = env->Invoke(Options.AsText(_T("Video resizer")).mb_str(wxConvLocal), AVSValue(args,3)); } catch (AvisynthError &err) { throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal); } vi = script.AsClip()->GetVideoInfo(); return (env->Invoke("InternalCache",script)).AsClip(); } wxBitmap VideoProvider::GetFrame(int n, bool force) { if (n != last_fnum || force) { wxMutexLocker lock(AviSynthMutex); PVideoFrame frame = ResizedVideo->GetFrame(n,env); //will fail if not rgb32 if (!data) data = new unsigned char[vi.width*vi.height*vi.BitsPerPixel()/8]; unsigned char* dst = data+(vi.width*(vi.height-1)*vi.BitsPerPixel()/8); int rs = vi.RowSize(); const unsigned char* src = frame->GetReadPtr(); int srcpitch = frame->GetPitch(); for (int i = 0; i < vi.height; i++) { memcpy(dst,src,rs); src+=srcpitch; dst-=rs; } last_frame = wxBitmap((const char*)data, vi.width, vi.height, vi.BitsPerPixel()); last_fnum = n; } return wxBitmap(last_frame); } void VideoProvider::LoadVSFilter() { // Loading an avisynth plugin multiple times does almost nothing wxFileName vsfilterPath(AegisubApp::folderName + _T("vsfilter.dll")); if (vsfilterPath.FileExists()) env->Invoke("LoadPlugin",env->SaveString(vsfilterPath.GetFullPath().mb_str(wxConvLocal))); else { wxRegKey reg(_T("HKEY_CLASSES_ROOT\\CLSID\\{9852A670-F845-491B-9BE6-EBD841B8A613}\\InprocServer32")); if (reg.Exists()) { wxString fn; reg.QueryValue(_T(""),fn); vsfilterPath = fn; if (vsfilterPath.FileExists()) { env->Invoke("LoadPlugin",env->SaveString(vsfilterPath.GetFullPath().mb_str(wxConvLocal))); return; } vsfilterPath = _T("vsfilter.dll"); } else if (vsfilterPath.FileExists()) env->Invoke("LoadPlugin",env->SaveString(vsfilterPath.GetFullPath().mb_str(wxConvLocal))); else if (!env->FunctionExists("TextSub")) throw _T("Couldn't locate VSFilter"); } }