forked from mia/Aegisub
Do stuff to the AVS video provider
Remove the Matroska keyframe/timecode loading code, as opening MKVs via Avisynth is dumb and didn't work very well anyway. Fix framerate reporting by actually bothering to read the video information before trying to use it. Kill the VFW wrapper and just put the code in the avisynth video source. If reading the keyframes from an avi file fails just warn the user rather than refuse to load the video. Originally committed to SVN as r5558.
This commit is contained in:
parent
27867421b2
commit
017a6aa27d
5 changed files with 145 additions and 365 deletions
|
@ -601,14 +601,6 @@
|
||||||
RelativePath="..\..\src\mkv_wrap.h"
|
RelativePath="..\..\src\mkv_wrap.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\vfw_wrap.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\vfw_wrap.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Controls"
|
Name="Controls"
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
// Copyright (c) 2005, 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 vfw_wrap.cpp
|
|
||||||
/// @brief Reading timecode and keyframe data from AVI files using Video for Windows
|
|
||||||
/// @ingroup video_input
|
|
||||||
///
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <vfw.h>
|
|
||||||
|
|
||||||
#include "vfw_wrap.h"
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Get keyframe list
|
|
||||||
/// @param filename
|
|
||||||
///
|
|
||||||
std::vector<int> VFWWrapper::GetKeyFrames(wxString filename) {
|
|
||||||
std::vector<int> 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<frame_c;i++) {
|
|
||||||
if (AVIStreamIsKeyFrame(ppavi,(int)i)) {
|
|
||||||
frames.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
AVIStreamRelease(ppavi);
|
|
||||||
AVIFileRelease(pfile);
|
|
||||||
AVIFileExit();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright (c) 2005, 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 vfw_wrap.h
|
|
||||||
/// @see vfw_wrap.cpp
|
|
||||||
/// @ingroup video_input
|
|
||||||
///
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#ifndef AGI_PRE
|
|
||||||
#include <vector>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class VFWWrapper
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class VFWWrapper {
|
|
||||||
public:
|
|
||||||
static std::vector<int> GetKeyFrames(wxString filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -37,40 +37,128 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef WITH_AVISYNTH
|
#ifdef WITH_AVISYNTH
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#include <wx/msw/registry.h>
|
#include <wx/msw/registry.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <vfw.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "charset_conv.h"
|
#include "charset_conv.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "gl_wrap.h"
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
#include "mkv_wrap.h"
|
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
#include "vfw_wrap.h"
|
|
||||||
#include "video_context.h"
|
|
||||||
#include "video_provider_avs.h"
|
#include "video_provider_avs.h"
|
||||||
|
|
||||||
/// @brief Constructor
|
|
||||||
/// @param _filename
|
|
||||||
///
|
|
||||||
AvisynthVideoProvider::AvisynthVideoProvider(wxString filename) try
|
AvisynthVideoProvider::AvisynthVideoProvider(wxString filename) try
|
||||||
: usedDirectShow(false)
|
: last_fnum(-1)
|
||||||
, decoderName(_("Unknown"))
|
|
||||||
, num_frames(0)
|
|
||||||
, last_fnum(-1)
|
|
||||||
, RGB32Video(NULL)
|
|
||||||
{
|
{
|
||||||
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();
|
vi = RGB32Video->GetVideoInfo();
|
||||||
|
fps = (double)vi.fps_numerator / vi.fps_denominator;
|
||||||
}
|
}
|
||||||
catch (AvisynthError const& err) {
|
catch (AvisynthError const& err) {
|
||||||
throw VideoOpenError("Avisynth error: " + std::string(err.msg));
|
throw VideoOpenError("Avisynth error: " + std::string(err.msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Destructor
|
|
||||||
AvisynthVideoProvider::~AvisynthVideoProvider() {
|
AvisynthVideoProvider::~AvisynthVideoProvider() {
|
||||||
iframe.Clear();
|
iframe.Clear();
|
||||||
}
|
}
|
||||||
|
@ -79,33 +167,33 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
|
||||||
char *videoFilename = env->SaveString(fname.GetShortPath().mb_str(csConvLocal));
|
char *videoFilename = env->SaveString(fname.GetShortPath().mb_str(csConvLocal));
|
||||||
|
|
||||||
// Avisynth file, just import it
|
// Avisynth file, just import it
|
||||||
if (extension == L".avs") {
|
if (extension == ".avs") {
|
||||||
LOG_I("avisynth/video") << "Opening .avs file with Import";
|
LOG_I("avisynth/video") << "Opening .avs file with Import";
|
||||||
decoderName = L"Import";
|
decoderName = "Avisynth/Import";
|
||||||
return env->Invoke("Import", videoFilename);
|
return env->Invoke("Import", videoFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open avi file with AviSource
|
// Open avi file with AviSource
|
||||||
if (extension == L".avi") {
|
if (extension == ".avi") {
|
||||||
LOG_I("avisynth/video") << "Opening .avi file with AviSource";
|
LOG_I("avisynth/video") << "Opening .avi file with AviSource";
|
||||||
try {
|
try {
|
||||||
const char *argnames[2] = { 0, "audio" };
|
const char *argnames[2] = { 0, "audio" };
|
||||||
AVSValue args[2] = { videoFilename, false };
|
AVSValue args[2] = { videoFilename, false };
|
||||||
decoderName = L"AviSource";
|
decoderName = "Avisynth/AviSource";
|
||||||
return env->Invoke("AviSource", AVSValue(args,2), argnames);
|
return env->Invoke("AviSource", AVSValue(args,2), argnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Failure, fallback to DSS
|
// On Failure, fallback to DSS
|
||||||
catch (AvisynthError &) {
|
catch (AvisynthError &err) {
|
||||||
LOG_I("avisynth/video") << "Failed to open .avi file with AviSource, switching to DirectShowSource";
|
LOG_E("avisynth/video") << err.msg;
|
||||||
|
LOG_I("avisynth/video") << "Failed to open .avi file with AviSource, trying DirectShowSource";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open d2v with mpeg2dec3
|
// 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";
|
LOG_I("avisynth/video") << "Opening .d2v file with Mpeg2Dec3_Mpeg2Source";
|
||||||
AVSValue script = env->Invoke("Mpeg2Dec3_Mpeg2Source", videoFilename);
|
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 avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
|
||||||
if (env->FunctionExists("SetPlanarLegacyAlignment")) {
|
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 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";
|
LOG_I("avisynth/video") << "Opening .d2v file with DGDecode_Mpeg2Source";
|
||||||
decoderName = L"DGDecode_Mpeg2Source";
|
decoderName = "DGDecode_Mpeg2Source";
|
||||||
return env->Invoke("Mpeg2Source", videoFilename);
|
return env->Invoke("Avisynth/Mpeg2Source", videoFilename);
|
||||||
|
|
||||||
//note that DGDecode will also have issues like if the version is too ancient but no sane person
|
//note that DGDecode will also have issues like if the version is too
|
||||||
//would use that anyway
|
// 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";
|
LOG_I("avisynth/video") << "Opening .d2v file with other Mpeg2Source";
|
||||||
AVSValue script = env->Invoke("Mpeg2Source", videoFilename);
|
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 avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
|
||||||
if (env->FunctionExists("SetPlanarLegacyAlignment"))
|
if (env->FunctionExists("SetPlanarLegacyAlignment"))
|
||||||
|
@ -139,22 +227,22 @@ AVSValue AvisynthVideoProvider::Open(wxFileName const& fname, wxString const& ex
|
||||||
|
|
||||||
// Try loading DirectShowSource2
|
// Try loading DirectShowSource2
|
||||||
if (!env->FunctionExists("dss2")) {
|
if (!env->FunctionExists("dss2")) {
|
||||||
wxFileName dss2path(StandardPaths::DecodePath(_T("?data/avss.dll")));
|
wxFileName dss2path(StandardPaths::DecodePath("?data/avss.dll"));
|
||||||
if (dss2path.FileExists()) {
|
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 DSS2 loaded properly, try using it
|
||||||
if (env->FunctionExists("dss2")) {
|
if (env->FunctionExists("dss2")) {
|
||||||
LOG_I("avisynth/video") << "Opening file with DSS2";
|
LOG_I("avisynth/video") << "Opening file with DSS2";
|
||||||
decoderName = L"DSS2";
|
decoderName = "Avisynth/DSS2";
|
||||||
return env->Invoke("DSS2", videoFilename);
|
return env->Invoke("DSS2", videoFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try DirectShowSource
|
// Try DirectShowSource
|
||||||
// Load DirectShowSource.dll from app dir if it exists
|
// 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()) {
|
if (dsspath.FileExists()) {
|
||||||
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetFullPath().mb_str(csConvLocal)));
|
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")) {
|
if (env->FunctionExists("DirectShowSource")) {
|
||||||
const char *argnames[3] = { 0, "video", "audio" };
|
const char *argnames[3] = { 0, "video", "audio" };
|
||||||
AVSValue args[3] = { videoFilename, true, false };
|
AVSValue args[3] = { videoFilename, true, false };
|
||||||
usedDirectShow = true;
|
decoderName = "Avisynth/DirectShowSource";
|
||||||
decoderName = L"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";
|
LOG_I("avisynth/video") << "Opening file with DirectShowSource";
|
||||||
return env->Invoke("DirectShowSource", AVSValue(args,3), argnames);
|
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");
|
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) {
|
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int n) {
|
||||||
if (vfr_fps.IsLoaded()) {
|
if (n == last_fnum) return iframe;
|
||||||
n = real_fps.FrameAtTime(vfr_fps.TimeAtFrame(n));
|
|
||||||
}
|
|
||||||
// Get avs frame
|
|
||||||
wxMutexLocker lock(AviSynthMutex);
|
wxMutexLocker lock(AviSynthMutex);
|
||||||
|
|
||||||
PVideoFrame frame = RGB32Video->GetFrame(n,env);
|
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
|
iframe.Allocate();
|
||||||
AegiVideoFrame &final = iframe;
|
|
||||||
final.flipped = true;
|
|
||||||
final.invertChannels = true;
|
|
||||||
|
|
||||||
// Set size properties
|
memcpy(iframe.data, frame->GetReadPtr(), iframe.pitch * iframe.h);
|
||||||
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;
|
last_fnum = n;
|
||||||
return final;
|
return iframe;
|
||||||
}
|
}
|
||||||
|
#endif // HAVE_AVISYNTH
|
||||||
/// @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
|
|
||||||
|
|
|
@ -44,41 +44,17 @@
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
|
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
|
||||||
/// DOCME
|
AegiVideoFrame iframe;
|
||||||
|
wxString decoderName;
|
||||||
|
agi::vfr::Framerate fps;
|
||||||
|
std::vector<int> KeyFrames;
|
||||||
|
wxString warning;
|
||||||
|
|
||||||
|
PClip RGB32Video;
|
||||||
VideoInfo vi;
|
VideoInfo vi;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
AegiVideoFrame iframe;
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool usedDirectShow;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxString rendererCallString;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxString decoderName;
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int num_frames;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int last_fnum;
|
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);
|
AVSValue Open(wxFileName const& fname, wxString const& extension);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -88,12 +64,12 @@ public:
|
||||||
const AegiVideoFrame GetFrame(int n);
|
const AegiVideoFrame GetFrame(int n);
|
||||||
|
|
||||||
int GetPosition() const { return last_fnum; };
|
int GetPosition() const { return last_fnum; };
|
||||||
int GetFrameCount() const { return num_frames? num_frames: vi.num_frames; };
|
int GetFrameCount() const { return vi.num_frames; };
|
||||||
agi::vfr::Framerate GetFPS() const { return vfr_fps.IsLoaded() ? vfr_fps : real_fps; };
|
agi::vfr::Framerate GetFPS() const { return fps; };
|
||||||
int GetWidth() const { return vi.width; };
|
int GetWidth() const { return vi.width; };
|
||||||
int GetHeight() const { return vi.height; };
|
int GetHeight() const { return vi.height; };
|
||||||
std::vector<int> GetKeyFrames() const { return KeyFrames; };
|
std::vector<int> GetKeyFrames() const { return KeyFrames; };
|
||||||
wxString GetWarning() const;
|
wxString GetWarning() const { return warning; }
|
||||||
wxString GetDecoderName() const { return wxString(L"Avisynth/") + decoderName; }
|
wxString GetDecoderName() const { return decoderName; }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue