diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
index fc9754759..26ebc056c 100644
--- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
+++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
@@ -601,14 +601,6 @@
RelativePath="..\..\src\mkv_wrap.h"
>
-
-
-
-
-
-#include "vfw_wrap.h"
-
-
-/// @brief Get keyframe list
-/// @param filename
-///
-std::vector VFWWrapper::GetKeyFrames(wxString filename) {
- std::vector frames;
-
-#ifdef __WINDOWS__
- // Init vfw
- AVIFileInit();
-
- // Open file
- PAVIFILE pfile;
- long hr = AVIFileOpen(&pfile, filename.wc_str(), OF_SHARE_DENY_WRITE, 0);
- if (hr != 0) {
- AVIFileExit();
- switch (hr) {
- case AVIERR_BADFORMAT:
- throw _T("Unable to open AVI file for reading keyframes:\nThe file is corrupted, incomplete or has an otherwise bad format.");
- case AVIERR_MEMORY:
- throw _T("Unable to open AVI file for reading keyframes:\nThe file could not be opened because of insufficient memory.");
- case AVIERR_FILEREAD:
- throw _T("Unable to open AVI file for reading keyframes:\nAn error occurred reading the file. There might be a problem with the storage media.");
- case AVIERR_FILEOPEN:
- throw _T("Unable to open AVI file for reading keyframes:\nThe file could not be opened. It might be in use by another application, or you do not have permission to access it.");
- case REGDB_E_CLASSNOTREG:
- throw _T("Unable to open AVI file for reading keyframes:\nThere is no handler installed for the file extension. This might indicate a fundameltal problem in your Video for Windows installation, and can be caused by extremely stripped Windows installations.");
- default:
- throw _T("Unable to open AVI file for reading keyframes:\nUnknown error.");
- }
- }
-
- // Open stream
- PAVISTREAM ppavi;
- hr = AVIFileGetStream(pfile,&ppavi,streamtypeVIDEO,0);
- if (hr != 0) {
- AVIFileRelease(pfile);
- AVIFileExit();
- switch (hr) {
- case AVIERR_NODATA:
- throw _T("Unable to open AVI video stream for reading keyframes:\nThe file does not contain a usable video stream.");
- case AVIERR_MEMORY:
- throw _T("Unable to open AVI video stream for reading keyframes:\nNot enough memory.");
- default:
- throw _T("Unable to open AVI video stream for reading keyframes:\nUnknown error.");
- }
-
- }
-
- // Get stream data
- AVISTREAMINFO avis;
- hr = AVIStreamInfo(ppavi,&avis,sizeof(avis));
- if (hr != 0) {
- AVIStreamRelease(ppavi);
- AVIFileRelease(pfile);
- AVIFileExit();
- throw _T("Unable to read keyframes from AVI file:\nCould not get stream information.");
- }
- size_t frame_c = avis.dwLength;
-
- // Loop through stream
- for (size_t i=0;i
-#endif
-
-
-/// DOCME
-/// @class VFWWrapper
-/// @brief DOCME
-///
-/// DOCME
-class VFWWrapper {
-public:
- static std::vector GetKeyFrames(wxString filename);
-};
-
-
diff --git a/aegisub/src/video_provider_avs.cpp b/aegisub/src/video_provider_avs.cpp
index 7d35288ee..eb9776a63 100644
--- a/aegisub/src/video_provider_avs.cpp
+++ b/aegisub/src/video_provider_avs.cpp
@@ -37,40 +37,128 @@
#include "config.h"
#ifdef WITH_AVISYNTH
+
#ifndef AGI_PRE
#include
#include
#endif
+#ifdef _WIN32
+#include
+#endif
+
#include "charset_conv.h"
#include "compat.h"
-#include "gl_wrap.h"
#include
-#include "mkv_wrap.h"
#include "standard_paths.h"
-#include "vfw_wrap.h"
-#include "video_context.h"
#include "video_provider_avs.h"
-/// @brief Constructor
-/// @param _filename
-///
AvisynthVideoProvider::AvisynthVideoProvider(wxString filename) try
-: usedDirectShow(false)
-, decoderName(_("Unknown"))
-, num_frames(0)
-, last_fnum(-1)
-, RGB32Video(NULL)
+: last_fnum(-1)
{
- RGB32Video = OpenVideo(filename);
+ iframe.flipped = true;
+ iframe.invertChannels = true;
+ wxMutexLocker lock(AviSynthMutex);
+
+ wxFileName fname(filename);
+ if (!fname.FileExists())
+ throw agi::FileNotFoundError(STD_STR(filename));
+
+ wxString extension = filename.Right(4).Lower();
+
+#ifdef _WIN32
+ if (extension == ".avi") {
+ // Try to read the keyframes before actually opening the file as trying
+ // to open the file while it's already open can cause problems with
+ // badly written VFW decoders
+ AVIFileInit();
+
+ PAVIFILE pfile;
+ long hr = AVIFileOpen(&pfile, filename.wc_str(), OF_SHARE_DENY_WRITE, 0);
+ if (hr) {
+ warning = "Unable to open AVI file for reading keyframes:\n";
+ switch (hr) {
+ case AVIERR_BADFORMAT:
+ warning += "The file is corrupted, incomplete or has an otherwise bad format.";
+ break;
+ case AVIERR_MEMORY:
+ warning += "The file could not be opened because of insufficient memory.";
+ break;
+ case AVIERR_FILEREAD:
+ warning += "An error occurred reading the file. There might be a problem with the storage media.";
+ break;
+ case AVIERR_FILEOPEN:
+ warning += "The file could not be opened. It might be in use by another application, or you do not have permission to access it.";
+ break;
+ case REGDB_E_CLASSNOTREG:
+ warning += "There is no handler installed for the file extension. This might indicate a fundameltal problem in your Video for Windows installation, and can be caused by extremely stripped Windows installations.";
+ break;
+ default:
+ warning += "Unknown error.";
+ break;
+ }
+ goto file_exit;
+ }
+
+ PAVISTREAM ppavi;
+ if (hr = AVIFileGetStream(pfile, &ppavi, streamtypeVIDEO, 0)) {
+ warning = "Unable to open AVI video stream for reading keyframes:\n";
+ switch (hr) {
+ case AVIERR_NODATA:
+ warning += "The file does not contain a usable video stream.";
+ break;
+ case AVIERR_MEMORY:
+ warning += "Not enough memory.";
+ break;
+ default:
+ warning += "Unknown error.";
+ break;
+ }
+ goto file_release;
+ }
+
+ AVISTREAMINFO avis;
+ if (AVIStreamInfo(ppavi,&avis,sizeof(avis))) {
+ warning = "Unable to read keyframes from AVI file:\nCould not get stream information.";
+ goto stream_release;
+ }
+
+ bool all_keyframes = true;
+ for (size_t i = 0; i < avis.dwLength; i++) {
+ if (AVIStreamIsKeyFrame(ppavi, i))
+ KeyFrames.push_back(i);
+ else
+ all_keyframes = false;
+ }
+
+ // If every frame is a keyframe then just discard the keyframe data as it's useless
+ if (all_keyframes) KeyFrames.clear();
+
+ // Clean up
+stream_release:
+ AVIStreamRelease(ppavi);
+file_release:
+ AVIFileRelease(pfile);
+file_exit:
+ AVIFileExit();
+ }
+#endif
+
+ AVSValue script = Open(fname, extension);
+
+ // Check if video was loaded properly
+ if (!script.IsClip() || !script.AsClip()->GetVideoInfo().HasVideo())
+ throw VideoNotSupported("No usable video found");
+
+ RGB32Video = (env->Invoke("Cache", env->Invoke("ConvertToRGB32", script))).AsClip();
vi = RGB32Video->GetVideoInfo();
+ fps = (double)vi.fps_numerator / vi.fps_denominator;
}
catch (AvisynthError const& err) {
throw VideoOpenError("Avisynth error: " + std::string(err.msg));
}
-/// @brief Destructor
AvisynthVideoProvider::~AvisynthVideoProvider() {
iframe.Clear();
}
@@ -79,33 +167,33 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
char *videoFilename = env->SaveString(fname.GetShortPath().mb_str(csConvLocal));
// Avisynth file, just import it
- if (extension == L".avs") {
+ if (extension == ".avs") {
LOG_I("avisynth/video") << "Opening .avs file with Import";
- decoderName = L"Import";
+ decoderName = "Avisynth/Import";
return env->Invoke("Import", videoFilename);
}
// Open avi file with AviSource
- if (extension == L".avi") {
+ if (extension == ".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";
+ decoderName = "Avisynth/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";
+ catch (AvisynthError &err) {
+ LOG_E("avisynth/video") << err.msg;
+ LOG_I("avisynth/video") << "Failed to open .avi file with AviSource, trying DirectShowSource";
}
}
// Open d2v with mpeg2dec3
- if (extension == L".d2v" && env->FunctionExists("Mpeg2Dec3_Mpeg2Source")) {
+ if (extension == ".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";
+ decoderName = "Avisynth/Mpeg2Dec3_Mpeg2Source";
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
if (env->FunctionExists("SetPlanarLegacyAlignment")) {
@@ -116,19 +204,19 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
}
// If that fails, try opening it with DGDecode
- if (extension == L".d2v" && env->FunctionExists("DGDecode_Mpeg2Source")) {
+ if (extension == ".d2v" && env->FunctionExists("DGDecode_Mpeg2Source")) {
LOG_I("avisynth/video") << "Opening .d2v file with DGDecode_Mpeg2Source";
- decoderName = L"DGDecode_Mpeg2Source";
- return env->Invoke("Mpeg2Source", videoFilename);
+ decoderName = "DGDecode_Mpeg2Source";
+ return env->Invoke("Avisynth/Mpeg2Source", videoFilename);
- //note that DGDecode will also have issues like if the version is too ancient but no sane person
- //would use that anyway
+ //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")) {
+ if (extension == ".d2v" && env->FunctionExists("Mpeg2Source")) {
LOG_I("avisynth/video") << "Opening .d2v file with other Mpeg2Source";
AVSValue script = env->Invoke("Mpeg2Source", videoFilename);
- decoderName = L"Mpeg2Source";
+ decoderName = "Avisynth/Mpeg2Source";
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
if (env->FunctionExists("SetPlanarLegacyAlignment"))
@@ -139,22 +227,22 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
// Try loading DirectShowSource2
if (!env->FunctionExists("dss2")) {
- wxFileName dss2path(StandardPaths::DecodePath(_T("?data/avss.dll")));
+ wxFileName dss2path(StandardPaths::DecodePath("?data/avss.dll"));
if (dss2path.FileExists()) {
- env->Invoke("LoadPlugin",env->SaveString(dss2path.GetFullPath().mb_str(csConvLocal)));
+ 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";
+ decoderName = "Avisynth/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")));
+ wxFileName dsspath(StandardPaths::DecodePath("?data/DirectShowSource.dll"));
if (dsspath.FileExists()) {
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetFullPath().mb_str(csConvLocal)));
}
@@ -163,8 +251,8 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
if (env->FunctionExists("DirectShowSource")) {
const char *argnames[3] = { 0, "video", "audio" };
AVSValue args[3] = { videoFilename, true, false };
- usedDirectShow = true;
- decoderName = L"DirectShowSource";
+ decoderName = "Avisynth/DirectShowSource";
+ warning = "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!";
LOG_I("avisynth/video") << "Opening file with DirectShowSource";
return env->Invoke("DirectShowSource", AVSValue(args,3), argnames);
}
@@ -174,118 +262,21 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
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; iInvoke("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
+ if (n == last_fnum) return iframe;
+
wxMutexLocker lock(AviSynthMutex);
+
PVideoFrame frame = RGB32Video->GetFrame(n,env);
- int Bpp = vi.BitsPerPixel() / 8;
+ iframe.pitch = frame->GetPitch();
+ iframe.w = frame->GetRowSize() / (vi.BitsPerPixel() / 8);
+ iframe.h = frame->GetHeight();
- // Aegisub's video frame
- AegiVideoFrame &final = iframe;
- final.flipped = true;
- final.invertChannels = true;
+ iframe.Allocate();
- // Set size properties
- final.pitch = frame->GetPitch();
- final.w = frame->GetRowSize() / Bpp;
- final.h = frame->GetHeight();
+ memcpy(iframe.data, frame->GetReadPtr(), iframe.pitch * iframe.h);
- // Allocate
- final.Allocate();
-
- // Copy
- memcpy(final.data,frame->GetReadPtr(),final.pitch * final.h);
-
- // Set last number
last_fnum = n;
- return final;
+ return iframe;
}
-
-/// @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
+#endif // HAVE_AVISYNTH
diff --git a/aegisub/src/video_provider_avs.h b/aegisub/src/video_provider_avs.h
index b6a024fca..3fb739250 100644
--- a/aegisub/src/video_provider_avs.h
+++ b/aegisub/src/video_provider_avs.h
@@ -44,41 +44,17 @@
///
/// DOCME
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
- /// DOCME
+ AegiVideoFrame iframe;
+ wxString decoderName;
+ agi::vfr::Framerate fps;
+ std::vector KeyFrames;
+ wxString warning;
+
+ PClip RGB32Video;
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 KeyFrames;
-
- /// DOCME
- PClip RGB32Video;
-
- PClip OpenVideo(wxString filename);
AVSValue Open(wxFileName const& fname, wxString const& extension);
public:
@@ -88,12 +64,12 @@ public:
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 GetFrameCount() const { return vi.num_frames; };
+ agi::vfr::Framerate GetFPS() const { return fps; };
int GetWidth() const { return vi.width; };
int GetHeight() const { return vi.height; };
std::vector GetKeyFrames() const { return KeyFrames; };
- wxString GetWarning() const;
- wxString GetDecoderName() const { return wxString(L"Avisynth/") + decoderName; }
+ wxString GetWarning() const { return warning; }
+ wxString GetDecoderName() const { return decoderName; }
};
#endif