The big VideoDisplay split
Originally committed to SVN as r20.
This commit is contained in:
parent
cb573429fb
commit
227febdd24
8 changed files with 480 additions and 672 deletions
|
@ -191,7 +191,7 @@ int DialogProperties::SetInfoIfDifferent(wxString key,wxString value) {
|
|||
//////////////////////////
|
||||
// Set res to match video
|
||||
void DialogProperties::OnSetFromVideo(wxCommandEvent &event) {
|
||||
ResX->SetValue(wxString::Format(_T("%i"),vid->orig_w));
|
||||
ResY->SetValue(wxString::Format(_T("%i"),vid->orig_h));
|
||||
ResX->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceWidth())); //fix me, null check?
|
||||
ResY->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceHeight())); //fix me, identical to other set?
|
||||
event.Skip();
|
||||
}
|
||||
|
|
|
@ -232,8 +232,8 @@ void DialogResample::OnResample (wxCommandEvent &event) {
|
|||
/////////////////////////////////////////
|
||||
// Get destination resolution from video
|
||||
void DialogResample::OnGetDestRes (wxCommandEvent &event) {
|
||||
ResX->SetValue(wxString::Format(_T("%i"),vid->orig_w));
|
||||
ResY->SetValue(wxString::Format(_T("%i"),vid->orig_h));
|
||||
ResX->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceWidth())); //fix me, null check?
|
||||
ResY->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceHeight()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -465,8 +465,7 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
|
|||
}
|
||||
|
||||
// Setup
|
||||
bool isFile = true;
|
||||
if (filename == _T("")) isFile = false;
|
||||
bool isFile = (filename != _T(""));
|
||||
|
||||
// Load
|
||||
try {
|
||||
|
@ -513,7 +512,7 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
|
|||
SynchronizeProject(true);
|
||||
|
||||
// Update video
|
||||
videoBox->videoDisplay->SetSubtitles(filename);
|
||||
//videoBox->videoDisplay->SetSubtitles(filename); //fix me, remove?
|
||||
|
||||
// Update title bar
|
||||
UpdateTitle();
|
||||
|
@ -523,9 +522,6 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
|
|||
//////////////////
|
||||
// Save subtitles
|
||||
bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) {
|
||||
// Synchronize
|
||||
SynchronizeProject();
|
||||
|
||||
// Try to get filename from file
|
||||
wxString filename;
|
||||
if (saveas == false && AssFile::top->IsASS) filename = AssFile::top->filename;
|
||||
|
@ -534,8 +530,12 @@ bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) {
|
|||
if (filename == _T("")) {
|
||||
videoBox->videoDisplay->Stop();
|
||||
filename = wxFileSelector(_("Save subtitles file"),_T(""),_T(""),_T(""),_T("Advanced Substation Alpha (*.ass)|*.ass"),wxSAVE | wxOVERWRITE_PROMPT,this);
|
||||
AssFile::top->filename = filename; //fix me, ghetto hack for correct relative path generation in SynchronizeProject()
|
||||
}
|
||||
|
||||
// Synchronize
|
||||
SynchronizeProject();
|
||||
|
||||
// Actually save
|
||||
if (!filename.empty()) {
|
||||
// Get charset
|
||||
|
@ -548,7 +548,7 @@ bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) {
|
|||
|
||||
// Save
|
||||
try {
|
||||
videoBox->videoDisplay->SetSubtitles(filename);
|
||||
//videoBox->videoDisplay->SetSubtitles(filename); fix me, remove?
|
||||
AssFile::top->Save(filename,true,true,charset);
|
||||
UpdateTitle();
|
||||
}
|
||||
|
@ -641,7 +641,6 @@ void FrameMain::SetDisplayMode(int mode) {
|
|||
// Update
|
||||
curMode = mode;
|
||||
UpdateToolbar();
|
||||
videoBox->videoDisplay->RefreshVideo();
|
||||
videoBox->VideoSizer->Layout();
|
||||
MainSizer->Layout();
|
||||
//Layout();
|
||||
|
@ -760,8 +759,6 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
|
||||
// Video
|
||||
if (curSubsVideo != videoBox->videoDisplay->videoName) {
|
||||
videoBox->videoDisplay->Locked(true);
|
||||
videoBox->videoDisplay->Reset();
|
||||
if (curSubsVideo != _T("")) {
|
||||
LoadVideo(curSubsVideo);
|
||||
if (videoBox->videoDisplay->loaded) {
|
||||
|
@ -770,7 +767,6 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
videoBox->videoDisplay->SetZoomPos(videoZoom-1);
|
||||
}
|
||||
}
|
||||
videoBox->videoDisplay->Locked(false);
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
@ -851,7 +847,7 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
|
|||
if (videoBox->videoDisplay->loaded) {
|
||||
int scriptx = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResX"));
|
||||
int scripty = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResY"));
|
||||
int vidx = videoBox->videoDisplay->orig_w, vidy = videoBox->videoDisplay->orig_h;
|
||||
int vidx = videoBox->videoDisplay->provider->GetSourceWidth(), vidy = videoBox->videoDisplay->provider->GetSourceHeight();
|
||||
if (scriptx != vidx || scripty != vidy) {
|
||||
switch (Options.AsInt(_T("Video Check Script Res"))) {
|
||||
case 1:
|
||||
|
@ -929,7 +925,6 @@ void FrameMain::LoadVFR(wxString filename) {
|
|||
|
||||
SubsBox->CommitChanges();
|
||||
EditBox->UpdateFrameTiming();
|
||||
//SynchronizeProject();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1640,7 +1640,9 @@ void SubtitlesGrid::CommitChanges(bool force) {
|
|||
// Export
|
||||
wxString workfile = GetTempWorkFile();
|
||||
ass->Export(workfile);
|
||||
video->RefreshVideo(true);
|
||||
|
||||
if (video->loaded)
|
||||
video->RefreshSubtitles();
|
||||
|
||||
// Resume play
|
||||
if (playing) video->Play();
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
////////////
|
||||
// Includes
|
||||
#include "video_display.h"
|
||||
#include "avisynth_wrap.h"
|
||||
#include "vfr.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_time.h"
|
||||
|
@ -86,22 +85,18 @@ END_EVENT_TABLE()
|
|||
VideoDisplay::VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
|
||||
: wxWindow (parent, id, pos, size, style, name)
|
||||
{
|
||||
provider = NULL;
|
||||
curLine = NULL;
|
||||
curFrame = NULL;
|
||||
backbuffer = NULL;
|
||||
ControlSlider = NULL;
|
||||
PositionDisplay = NULL;
|
||||
loaded = false;
|
||||
frame_n = 0;
|
||||
origSize = size;
|
||||
zoom = 0.75;
|
||||
arType = 0;
|
||||
isLocked = false;
|
||||
gettingFrame = false;
|
||||
IsPlaying = false;
|
||||
threaded = Options.AsBool(_T("Threaded Video"));
|
||||
nextFrame = -1;
|
||||
framesSkipped = 0;
|
||||
|
||||
// Create PNG handler
|
||||
wxPNGHandler *png = new wxPNGHandler;
|
||||
|
@ -116,476 +111,108 @@ VideoDisplay::VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|||
//////////////
|
||||
// Destructor
|
||||
VideoDisplay::~VideoDisplay () {
|
||||
ControlSlider = NULL;
|
||||
Unload();
|
||||
if (backbuffer) delete backbuffer;
|
||||
backbuffer = NULL;
|
||||
SetVideo(_T(""));
|
||||
delete backbuffer;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// Sets video filename
|
||||
void VideoDisplay::SetVideo(const wxString &filename) {
|
||||
try {
|
||||
if (!filename.empty()) {
|
||||
// Verify if file exists
|
||||
wxFileName filetest(filename);
|
||||
if (!filetest.FileExists()) throw _T("File not found.");
|
||||
|
||||
// OK to load
|
||||
if (videoName != filename) {
|
||||
Unload();
|
||||
videoName = filename;
|
||||
OpenAVSVideo();
|
||||
if (!loaded) Reset();
|
||||
else RefreshVideo();
|
||||
|
||||
// Set keyframes
|
||||
if (filename.Right(4).Lower() == _T(".avi")) KeyFrames = VFWWrapper::GetKeyFrames(filename);
|
||||
else KeyFrames.Clear();
|
||||
|
||||
// Add to recent
|
||||
Options.AddToRecentList(filename,_T("Recent vid"));
|
||||
}
|
||||
|
||||
else Reset();
|
||||
}
|
||||
else Reset();
|
||||
}
|
||||
|
||||
catch (wchar_t *error) {
|
||||
wxMessageBox(error,_T("Error setting video"),wxICON_ERROR | wxOK);
|
||||
Reset();
|
||||
}
|
||||
|
||||
catch (...) {
|
||||
wxMessageBox(_T("Unhandled exception"),_T("Error setting video"),wxICON_ERROR | wxOK);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////
|
||||
// Sets subtitles filename
|
||||
void VideoDisplay::SetSubtitles(const wxString &filename) {
|
||||
if (!loaded) return;
|
||||
wxString old = subsName;
|
||||
subsName = filename;
|
||||
|
||||
if (!videoName.empty()) {
|
||||
OpenAVSSubs();
|
||||
RefreshVideo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////
|
||||
// Open AVS
|
||||
void VideoDisplay::OpenAVSVideo() {
|
||||
if (videoName.empty()) return;
|
||||
bool directShow = false;
|
||||
|
||||
// Create AviSynth environment
|
||||
{
|
||||
wxMutexLocker lock(AviSynthMutex);
|
||||
AVSValue script;
|
||||
|
||||
// Load VSFilter
|
||||
try {
|
||||
env->Invoke("LoadPlugin", env->SaveString(GetVSFilter().mb_str(wxConvLocal)));
|
||||
}
|
||||
catch (AvisynthError &) {
|
||||
throw _T("Failed opening VSfilter");
|
||||
}
|
||||
|
||||
try {
|
||||
// Prepare filename
|
||||
char *videoFilename = env->SaveString(videoName.mb_str(wxConvLocal));
|
||||
|
||||
wxString extension = videoName.Right(4);
|
||||
extension.LowerCase();
|
||||
|
||||
// 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 &) {
|
||||
const char *argnames[3] = { 0, "video", "audio" };
|
||||
AVSValue args[3] = { videoFilename, true, false };
|
||||
script = env->Invoke("DirectShowSource", AVSValue(args,3),argnames);
|
||||
directShow = true;
|
||||
}
|
||||
}
|
||||
else if (extension == _T(".d2v") && env->FunctionExists("mpeg2dec3_Mpeg2Source")) //prefer mpeg2dec3
|
||||
script = env->Invoke("mpeg2dec3_Mpeg2Source", videoFilename);
|
||||
else if (extension == _T(".d2v")) //try other mpeg2source
|
||||
script = env->Invoke("Mpeg2Source", videoFilename);
|
||||
else {
|
||||
const char *argnames[3] = { 0, "video", "audio" };
|
||||
AVSValue args[3] = { videoFilename, true, false };
|
||||
script = env->Invoke("DirectShowSource", AVSValue(args,3),argnames);
|
||||
directShow = true;
|
||||
}
|
||||
} catch (AvisynthError &err) {
|
||||
wxMessageBox (wxString(_T("AviSynth error: ")) + wxString(err.msg,wxConvLocal), _T("Error"), wxOK | wxICON_ERROR);
|
||||
}
|
||||
|
||||
// Check if video is valid
|
||||
PClip clip = script.AsClip();
|
||||
VideoInfo vi = clip->GetVideoInfo();
|
||||
|
||||
if (!vi.HasVideo())
|
||||
wxMessageBox (wxString(_T("No video found: ")), _T("Error"), wxOK | wxICON_ERROR);
|
||||
|
||||
// Get resolution
|
||||
orig_w = vi.width;
|
||||
orig_h = vi.height;
|
||||
|
||||
// Convert to RGB32 if needed
|
||||
script = env->Invoke("ConvertToRGB32", clip);
|
||||
|
||||
// Cache
|
||||
sublessVideo = (env->Invoke("InternalCache", script)).AsClip();
|
||||
}
|
||||
|
||||
// Continue with subs
|
||||
OpenAVSSubs();
|
||||
|
||||
// Issue warning if it's DirectShow
|
||||
if (directShow) wxMessageBox (_("This file is being loaded using DirectShow, which has UNRELIABLE seeking. Frame numbers MIGHT NOT match display, so precise timing CANNOT be trusted."), _("Warning!"), wxOK | wxICON_WARNING);
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
// Opens subtitles
|
||||
void VideoDisplay::OpenAVSSubs () {
|
||||
// Vars
|
||||
{
|
||||
wxMutexLocker lock(AviSynthMutex);
|
||||
AVSValue script;
|
||||
video = sublessVideo;
|
||||
|
||||
// Make sure there is a workfile
|
||||
wxString workfile = grid->GetTempWorkFile();
|
||||
wxFileName file(workfile);
|
||||
if (!file.FileExists()) {
|
||||
grid->CommitChanges(true);
|
||||
}
|
||||
if (!file.FileExists()) {
|
||||
throw _T("Failed creating temporary subs file. Make sure you have write permission on folder.");
|
||||
}
|
||||
|
||||
// Insert subs
|
||||
try {
|
||||
PClip clip = video;
|
||||
char temp[512];
|
||||
strcpy(temp,workfile.mb_str(wxConvLocal));
|
||||
AVSValue args1[2] = { clip, temp };
|
||||
script = env->Invoke("TextSub", AVSValue(args1,2));
|
||||
video = script.AsClip();
|
||||
} catch (AvisynthError &err) {
|
||||
wxMessageBox (wxString(_T("AviSynth error: ")) + wxString(err.msg,wxConvLocal), _T("Error"), wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Zoom & AR
|
||||
if (zoom != 1.0 || arType != 0) {
|
||||
try {
|
||||
// Get video data
|
||||
PClip clip = video;
|
||||
VideoInfo vi = clip->GetVideoInfo();
|
||||
|
||||
// Get aspect ratio data
|
||||
int pos_h = vi.height;
|
||||
int pos_w = vi.width;
|
||||
switch (arType) {
|
||||
case 1: pos_w = pos_h * 4 / 3; break;
|
||||
case 2: pos_w = pos_h * 16 / 9; break;
|
||||
}
|
||||
|
||||
// Resize
|
||||
AVSValue args[3] = { clip, int(zoom*pos_w), int(zoom*pos_h) };
|
||||
script = env->Invoke(Options.AsText(_T("Video resizer")).mb_str(wxConvLocal), AVSValue(args,3));
|
||||
video = script.AsClip();
|
||||
} catch (AvisynthError &err) {
|
||||
wxMessageBox (wxString(_T("AviSynth error: ")) + wxString(err.msg,wxConvLocal), _T("Error"), wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache
|
||||
video = (env->Invoke("InternalCache", video)).AsClip();
|
||||
}
|
||||
|
||||
// Set final
|
||||
PrepareAfterAVS();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Sets control up after loading an AVS
|
||||
void VideoDisplay::PrepareAfterAVS() {
|
||||
{
|
||||
// Gather video parameters
|
||||
wxMutexLocker lock(AviSynthMutex);
|
||||
VideoInfo vi = video->GetVideoInfo();
|
||||
w = vi.width;
|
||||
h = vi.height;
|
||||
length = vi.num_frames;
|
||||
if (vi.fps_denominator != 0) fps = double(vi.fps_numerator) / double(vi.fps_denominator);
|
||||
else fps = 0;
|
||||
VFR_Input.SetCFR(fps);
|
||||
if (!VFR_Output.loaded) VFR_Output.SetCFR(fps,true);
|
||||
void VideoDisplay::UpdateSize() {
|
||||
if (provider) {
|
||||
w = provider->GetWidth();
|
||||
h = provider->GetHeight();
|
||||
|
||||
// Set the size for this control
|
||||
SetClientSize(w,h);
|
||||
int _w,_h;
|
||||
GetSize(&_w,&_h);
|
||||
SetSizeHints(_w,_h,_w,_h);
|
||||
|
||||
// Set range of slider
|
||||
if (ControlSlider) ControlSlider->SetRange(0,vi.num_frames-1);
|
||||
|
||||
// Clear frame
|
||||
if (curFrame) delete curFrame;
|
||||
curFrame = NULL;
|
||||
|
||||
// Flag as loaded
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////
|
||||
// Unloads
|
||||
void VideoDisplay::Unload() {
|
||||
{
|
||||
wxMutexLocker lock(AviSynthMutex);
|
||||
|
||||
// AviSynth cleanup
|
||||
video = NULL;
|
||||
sublessVideo = NULL;
|
||||
|
||||
// Internal cleanup
|
||||
loaded = false;
|
||||
if (curFrame) delete curFrame;
|
||||
curFrame = NULL;
|
||||
videoName = _T("");
|
||||
///////////////////////
|
||||
// Sets video filename
|
||||
void VideoDisplay::SetVideo(const wxString &filename) {
|
||||
if (filename == _T("")) {
|
||||
delete provider;
|
||||
provider = NULL;
|
||||
if (VFR_Output.vfr == NULL) VFR_Output.Unload();
|
||||
VFR_Input.Unload();
|
||||
|
||||
videoName = _T("");
|
||||
|
||||
frame_n = 0;
|
||||
if (ControlSlider) {
|
||||
ControlSlider->SetRange(0,0);
|
||||
|
||||
Reset();
|
||||
} else {
|
||||
SetVideo(_T(""));
|
||||
|
||||
try {
|
||||
grid->CommitChanges(true);
|
||||
|
||||
bool usedDirectshow;
|
||||
|
||||
provider = new VideoProvider(filename,grid->GetTempWorkFile(),0.75,usedDirectshow,true);
|
||||
|
||||
// Set keyframes
|
||||
if (filename.Right(4).Lower() == _T(".avi"))
|
||||
KeyFrames = VFWWrapper::GetKeyFrames(filename);
|
||||
else
|
||||
KeyFrames.Clear();
|
||||
|
||||
UpdateSize();
|
||||
|
||||
//Gather video parameters
|
||||
length = provider->GetFrameCount();
|
||||
fps = provider->GetFPS();
|
||||
VFR_Input.SetCFR(fps);
|
||||
if (!VFR_Output.loaded) VFR_Output.SetCFR(fps,true);
|
||||
|
||||
// Set range of slider
|
||||
ControlSlider->SetRange(0,length-1);
|
||||
ControlSlider->SetValue(0);
|
||||
}
|
||||
|
||||
videoName = filename;
|
||||
|
||||
// Add to recent
|
||||
Options.AddToRecentList(filename,_T("Recent vid"));
|
||||
|
||||
RefreshVideo();
|
||||
} catch (wxString &e) {
|
||||
wxMessageBox(e,_T("Error setting video"),wxICON_ERROR | wxOK);
|
||||
}
|
||||
}
|
||||
|
||||
loaded = provider != NULL;
|
||||
|
||||
}
|
||||
|
||||
//////////
|
||||
// Resets
|
||||
void VideoDisplay::Reset() {
|
||||
Unload();
|
||||
w = origSize.GetX();
|
||||
h = origSize.GetY();
|
||||
SetClientSize(w,h);
|
||||
int _w,_h;
|
||||
GetSize(&_w,&_h);
|
||||
SetSizeHints(_w,_h,_w,_h);
|
||||
}
|
||||
|
||||
void VideoDisplay::RefreshSubtitles() {
|
||||
provider->RefreshSubtitles();
|
||||
RefreshVideo();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// Gets a frame image
|
||||
void VideoDisplay::GetFrameImage(int n) {
|
||||
// Prepare copy
|
||||
unsigned char *data;
|
||||
VideoInfo vi = video->GetVideoInfo();
|
||||
PVideoFrame avsFrame;
|
||||
try {
|
||||
avsFrame = video->GetFrame(n,env);
|
||||
}
|
||||
catch (AvisynthError err) {
|
||||
wxMessageBox (wxString(_T("AviSynth error: ")) + wxString(err.msg,wxConvLocal), _T("Error getting frame"), wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
wxMessageBox(_T("AviSynth threw an exception while trying to retrieve frame."),_T("Error getting frame"),wxICON_ERROR | wxOK);
|
||||
return;
|
||||
}
|
||||
unsigned int pitch = avsFrame->GetPitch();
|
||||
unsigned int read_w = avsFrame->GetRowSize();
|
||||
unsigned int read_h = avsFrame->GetHeight();
|
||||
int depth = wxDisplayDepth();
|
||||
int bpp = depth/8;
|
||||
unsigned int x,y,dx;
|
||||
|
||||
// Output
|
||||
data = (unsigned char*) malloc(w*h*bpp);
|
||||
|
||||
// RGB24
|
||||
if (vi.IsRGB24()) {
|
||||
if (depth == 16) {
|
||||
// Get pointers
|
||||
const unsigned char *read_ptr = avsFrame->GetReadPtr();
|
||||
unsigned short *write_ptr = (unsigned short*) (data+(w*h*2));
|
||||
unsigned char r,g,b;
|
||||
|
||||
for (y=0;y<read_h;y++) {
|
||||
write_ptr = write_ptr - read_w/3;
|
||||
for (x=0,dx=0;x<read_w;x+=3,dx++) {
|
||||
r = *(read_ptr+x+2);
|
||||
g = *(read_ptr+x+1);
|
||||
b = *(read_ptr+x);
|
||||
*(write_ptr+dx) = ((r>>3)<<11) | ((g>>2)<<5) | b>>3;
|
||||
}
|
||||
read_ptr = read_ptr + pitch;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth == 24) {
|
||||
// Get pointers
|
||||
const unsigned char *read_ptr = avsFrame->GetReadPtr();
|
||||
unsigned char *write_ptr = data+(w*h*3);
|
||||
|
||||
for (y=0;y<read_h;y++) {
|
||||
write_ptr = write_ptr - read_w;
|
||||
for (x=0;x<read_w;x+=3) {
|
||||
*(write_ptr+x) = *(read_ptr+x);
|
||||
*(write_ptr+x+1) = *(read_ptr+x+1);
|
||||
*(write_ptr+x+2) = *(read_ptr+x+2);
|
||||
}
|
||||
read_ptr = read_ptr + pitch;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth == 32) {
|
||||
// Get pointers
|
||||
const unsigned char *read_ptr = avsFrame->GetReadPtr();
|
||||
unsigned char *write_ptr = data+(w*h*4);
|
||||
unsigned int delta = pitch-read_w;
|
||||
unsigned int linelen = read_w*4/3;
|
||||
int wid = read_w/3;
|
||||
int i,j;
|
||||
|
||||
for (j=read_h;--j>=0;) {
|
||||
write_ptr -= linelen;
|
||||
for (i=wid;--i>=0;) {
|
||||
*(write_ptr++) = *(read_ptr++);
|
||||
*(write_ptr++) = *(read_ptr++);
|
||||
*(write_ptr++) = *(read_ptr++);
|
||||
write_ptr++;
|
||||
}
|
||||
read_ptr = read_ptr += delta;
|
||||
write_ptr -= linelen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RGB32
|
||||
else if (vi.IsRGB32()) {
|
||||
if (depth == 8) {
|
||||
throw _T("8-bit display not supported");
|
||||
}
|
||||
|
||||
if (depth == 15) {
|
||||
throw _T("15-bit display not supported");
|
||||
}
|
||||
|
||||
if (depth == 16) {
|
||||
// Get pointers
|
||||
const unsigned char *read_ptr = avsFrame->GetReadPtr();
|
||||
unsigned short *write_ptr = (unsigned short*) (data+(w*h*2));
|
||||
unsigned char r,g,b;
|
||||
|
||||
for (y=0;y<read_h;y++) {
|
||||
write_ptr = write_ptr - read_w/4;
|
||||
for (x=0,dx=0;x<read_w;x+=4,dx++) {
|
||||
r = *(read_ptr+x+2);
|
||||
g = *(read_ptr+x+1);
|
||||
b = *(read_ptr+x);
|
||||
*(write_ptr+dx) = ((r>>3)<<11) | ((g>>2)<<5) | b>>3;
|
||||
}
|
||||
read_ptr = read_ptr + pitch;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth == 24) {
|
||||
throw _T("24-bit display not supported");
|
||||
}
|
||||
|
||||
if (depth == 32) {
|
||||
// Get pointers
|
||||
const unsigned int *read_ptr = (const unsigned int *) avsFrame->GetReadPtr();
|
||||
unsigned int *write_ptr = ((unsigned int *) (data))+(w*h);
|
||||
unsigned int delta = (pitch-read_w)/4;
|
||||
unsigned int linelen = read_w/4;
|
||||
int i;
|
||||
|
||||
for (i=read_h;--i>=0;) {
|
||||
write_ptr -= linelen;
|
||||
memcpy(write_ptr,read_ptr,read_w);
|
||||
read_ptr += linelen + delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
throw _T("Wrong colour format.");
|
||||
}
|
||||
|
||||
// Copy to image
|
||||
BitmapMutex.Lock();
|
||||
try {
|
||||
if (curFrame) {
|
||||
delete curFrame;
|
||||
curFrame = NULL;
|
||||
}
|
||||
curFrame = new wxBitmap((const char*)data,w,h,depth);
|
||||
}
|
||||
catch (...) {}
|
||||
BitmapMutex.Unlock();
|
||||
free(data);
|
||||
|
||||
// Done
|
||||
frame_n = n;
|
||||
}
|
||||
|
||||
|
||||
/////////////////
|
||||
// OnPaint event
|
||||
void VideoDisplay::OnPaint(wxPaintEvent& event) {
|
||||
wxPaintDC dc(this);
|
||||
|
||||
// Try to grab frame if none
|
||||
{
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
if (!curFrame) GetFrame(frame_n);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
if (curFrame) {
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
dc.BeginDrawing();
|
||||
dc.DrawBitmap(*curFrame,0,0);
|
||||
dc.DrawBitmap(GetFrame(frame_n),0,0);
|
||||
dc.EndDrawing();
|
||||
}
|
||||
|
||||
// Failed
|
||||
else {
|
||||
dc.BeginDrawing();
|
||||
dc.SetBrush(*wxBLUE_BRUSH);
|
||||
dc.DrawRectangle(0,0,w,h);
|
||||
dc.EndDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Mouse stuff
|
||||
|
@ -640,7 +267,6 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
if (needCreate) backbuffer = new wxBitmap(w,h);
|
||||
|
||||
// Prepare drawing
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(*backbuffer);
|
||||
dc.BeginDrawing();
|
||||
|
@ -648,7 +274,7 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
dc.SetLogicalFunction(wxINVERT);
|
||||
|
||||
// Draw frame
|
||||
dc.DrawBitmap(*curFrame,0,0);
|
||||
dc.DrawBitmap(GetFrame(frame_n),0,0);
|
||||
|
||||
// Current position info
|
||||
if (x >= 0 && x < w && y >= 0 && y < h) {
|
||||
|
@ -703,14 +329,7 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
|
||||
if (IsPlaying) return;
|
||||
|
||||
// Refresh display
|
||||
{
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
wxClientDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
dc.DrawBitmap(*curFrame,0,0);
|
||||
dc.EndDrawing();
|
||||
}
|
||||
RefreshVideo();
|
||||
}
|
||||
|
||||
|
||||
|
@ -724,10 +343,14 @@ void VideoDisplay::JumpToFrame(int n) {
|
|||
if (IsPlaying && n != PlayNextFrame) return;
|
||||
|
||||
// Set frame
|
||||
if (frame_n != n) GetFrame(n);
|
||||
GetFrame(n);
|
||||
|
||||
// Display
|
||||
RefreshVideo();
|
||||
UpdatePositionDisplay();
|
||||
|
||||
// Update slider
|
||||
if (ControlSlider) ControlSlider->SetValue(n);
|
||||
ControlSlider->SetValue(n);
|
||||
|
||||
// Update grid
|
||||
if (!IsPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->UpdateRowColours();
|
||||
|
@ -744,15 +367,13 @@ void VideoDisplay::JumpToTime(int ms) {
|
|||
///////////////////
|
||||
// Sets zoom level
|
||||
void VideoDisplay::SetZoom(double value) {
|
||||
if (value != zoom) {
|
||||
zoom = value;
|
||||
if (loaded) {
|
||||
OpenAVSSubs();
|
||||
if (provider) {
|
||||
provider->SetZoom(value);
|
||||
UpdateSize();
|
||||
RefreshVideo();
|
||||
GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
|
@ -768,15 +389,17 @@ void VideoDisplay::SetZoomPos(int value) {
|
|||
///////////////////
|
||||
// Sets zoom level
|
||||
void VideoDisplay::SetAspectRatio(int value) {
|
||||
if (value != arType) {
|
||||
arType = value;
|
||||
if (loaded) {
|
||||
//GetParent()->Freeze();
|
||||
OpenAVSSubs();
|
||||
if (provider) {
|
||||
if (value == 0)
|
||||
provider->SetDAR((float)provider->GetSourceWidth()/(float)provider->GetSourceHeight());
|
||||
else if (value == 1)
|
||||
provider->SetDAR(4.0/3.0);
|
||||
else if (value == 2)
|
||||
provider->SetDAR(16.0/9.0);
|
||||
|
||||
UpdateSize();
|
||||
RefreshVideo();
|
||||
GetParent()->Layout();
|
||||
//GetParent()->Thaw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,21 +477,11 @@ void VideoDisplay::UpdateSubsRelativeTime() {
|
|||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// Locks/unlocks updating
|
||||
void VideoDisplay::Locked(bool state) {
|
||||
bool oldState = isLocked;
|
||||
isLocked = state;
|
||||
if (loaded && oldState == true && isLocked == false) RefreshVideo();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Copy to clipboard
|
||||
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &event) {
|
||||
if (wxTheClipboard->Open()) {
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
wxTheClipboard->SetData(new wxBitmapDataObject(*curFrame));
|
||||
wxTheClipboard->SetData(new wxBitmapDataObject(GetFrame(frame_n)));
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +505,7 @@ void VideoDisplay::SaveSnapshot() {
|
|||
}
|
||||
|
||||
// Save
|
||||
curFrame->ConvertToImage().SaveFile(path,wxBITMAP_TYPE_PNG);
|
||||
GetFrame(frame_n).ConvertToImage().SaveFile(path,wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
|
||||
|
||||
|
@ -910,153 +523,25 @@ void VideoDisplay::OnCopyCoords(wxCommandEvent &event) {
|
|||
}
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// Get VSFilter filename
|
||||
wxString VideoDisplay::GetVSFilter() {
|
||||
if (VSFilterPath.IsEmpty()) {
|
||||
wxFileName vsfilterPath(AegisubApp::folderName + _T("vsfilter.dll"));
|
||||
if (vsfilterPath.FileExists()) {
|
||||
VSFilterPath = AegisubApp::folderName + _T("vsfilter.dll");
|
||||
}
|
||||
else {
|
||||
wxRegKey reg(_T("HKEY_CLASSES_ROOT\\CLSID\\{9852A670-F845-491B-9BE6-EBD841B8A613}\\InprocServer32"));
|
||||
if (reg.Exists()) {
|
||||
reg.QueryValue(_T(""),VSFilterPath);
|
||||
wxFileName file(VSFilterPath);
|
||||
if (!file.FileExists()) VSFilterPath = _T("vsfilter.dll");
|
||||
}
|
||||
else {
|
||||
VSFilterPath = _T("vsfilter.dll");
|
||||
}
|
||||
}
|
||||
}
|
||||
return VSFilterPath;
|
||||
}
|
||||
|
||||
|
||||
//////////////////
|
||||
// Refresh screen
|
||||
void VideoDisplay::RefreshVideo(bool force) {
|
||||
// Prepare
|
||||
if (isLocked) return;
|
||||
|
||||
// Not loaded
|
||||
if (!loaded) {
|
||||
wxClientDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
dc.SetBrush(*wxBLUE_BRUSH);
|
||||
dc.DrawRectangle(0,0,w,h);
|
||||
dc.EndDrawing();
|
||||
}
|
||||
|
||||
else {
|
||||
// Forced
|
||||
if (force) {
|
||||
int n = frame_n;
|
||||
frame_n = -1;
|
||||
OpenAVSSubs();
|
||||
GetFrame(n);
|
||||
}
|
||||
|
||||
// No frame, try to get one
|
||||
{
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
if (!curFrame) GetFrame(frame_n);
|
||||
}
|
||||
|
||||
void VideoDisplay::RefreshVideo() {
|
||||
// Draw frame
|
||||
if (curFrame) {
|
||||
wxMutexLocker locker(BitmapMutex);
|
||||
wxClientDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
dc.DrawBitmap(*curFrame,0,0);
|
||||
dc.DrawBitmap(GetFrame(),0,0);
|
||||
dc.EndDrawing();
|
||||
//Refresh(false);
|
||||
}
|
||||
|
||||
// Draw black
|
||||
else {
|
||||
wxClientDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
dc.Clear();
|
||||
dc.EndDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
// Display
|
||||
UpdatePositionDisplay();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////
|
||||
// Requests a new frame
|
||||
void VideoDisplay::GetFrame(int n) {
|
||||
// Make sure it's loaded
|
||||
if (!loaded) {
|
||||
//throw _T("Video not loaded");
|
||||
return;
|
||||
}
|
||||
wxBitmap VideoDisplay::GetFrame(int n) {
|
||||
frame_n = n;
|
||||
|
||||
// Threaded mode
|
||||
if (threaded) {
|
||||
nextFrame = n;
|
||||
if (!gettingFrame || framesSkipped > 999999) {
|
||||
framesSkipped = 0;
|
||||
gettingFrame = true;
|
||||
wxThread *thread = new GetFrameThread(this,n);
|
||||
thread->Create();
|
||||
thread->Run();
|
||||
}
|
||||
else {
|
||||
framesSkipped++;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple mode
|
||||
else {
|
||||
GetFrameImage(n);
|
||||
return provider->GetFrame(n);
|
||||
RefreshVideo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Get frame thread constructor
|
||||
GetFrameThread::GetFrameThread(VideoDisplay *parent,int n)
|
||||
: wxThread(wxTHREAD_DETACHED)
|
||||
{
|
||||
display = parent;
|
||||
image_n = n;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// Get Frame thread entry
|
||||
wxThread::ExitCode GetFrameThread::Entry() {
|
||||
// Get frame
|
||||
display->gettingFrame = true;
|
||||
AviSynthWrapper::AviSynthMutex.Lock();
|
||||
try { display->GetFrameImage(image_n); }
|
||||
catch (...) { }
|
||||
AviSynthWrapper::AviSynthMutex.Unlock();
|
||||
|
||||
// Refresh video
|
||||
//wxMutexGuiEnter();
|
||||
try {
|
||||
display->RefreshVideo();
|
||||
}
|
||||
catch (...) { }
|
||||
//wxMutexGuiLeave();
|
||||
display->gettingFrame = false;
|
||||
|
||||
if (display->nextFrame != image_n) {
|
||||
display->GetFrame(display->nextFrame);
|
||||
}
|
||||
|
||||
// Return
|
||||
Exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
|
@ -1077,7 +562,6 @@ void VideoDisplay::GetScriptSize(int &sw,int &sh) {
|
|||
// Width
|
||||
temp = grid->ass->GetScriptInfo(_T("PlayResX"));
|
||||
if (temp == _T("") || !temp.IsNumber()) {
|
||||
//sw = orig_w * sh / orig_h;
|
||||
sw = 288;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -42,55 +42,31 @@
|
|||
// Headers
|
||||
#include <wx/wxprec.h>
|
||||
#include <windows.h>
|
||||
#include "avisynth_wrap.h"
|
||||
#include <time.h>
|
||||
#include "video_provider.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class SubtitlesGrid;
|
||||
class VideoDisplay;
|
||||
class VideoSlider;
|
||||
class AudioProvider;
|
||||
class AudioDisplay;
|
||||
class AssDialogue;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Get Frame thread
|
||||
class GetFrameThread: public wxThread {
|
||||
private:
|
||||
VideoDisplay *display;
|
||||
int image_n;
|
||||
|
||||
public:
|
||||
GetFrameThread(VideoDisplay *parent,int n);
|
||||
wxThread::ExitCode Entry();
|
||||
};
|
||||
|
||||
class VideoProvider;
|
||||
|
||||
//////////////
|
||||
// Main class
|
||||
class VideoDisplay: public wxWindow, public AviSynthWrapper {
|
||||
friend class GetFrameThread;
|
||||
class VideoDisplay: public wxWindow {
|
||||
friend class AudioProvider;
|
||||
|
||||
private:
|
||||
int mouse_x,mouse_y;
|
||||
wxBitmap *backbuffer;
|
||||
wxString subsName;
|
||||
wxString VSFilterPath;
|
||||
|
||||
PClip sublessVideo;
|
||||
PClip video;
|
||||
double zoom;
|
||||
wxSize origSize;
|
||||
bool isLocked;
|
||||
bool threaded;
|
||||
bool gettingFrame;
|
||||
int nextFrame;
|
||||
int framesSkipped;
|
||||
wxMutex BitmapMutex;
|
||||
|
||||
clock_t PlayTime;
|
||||
clock_t StartTime;
|
||||
|
@ -99,12 +75,10 @@ private:
|
|||
int EndFrame;
|
||||
int PlayNextFrame;
|
||||
|
||||
void GetFrameImage(int n);
|
||||
void GetFrame(int n);
|
||||
void FrameReady();
|
||||
wxBitmap GetFrame(int n);
|
||||
wxBitmap GetFrame() { return GetFrame(frame_n); };
|
||||
|
||||
void SetZoom(double value);
|
||||
wxString GetVSFilter();
|
||||
void UpdateSize();
|
||||
void SaveSnapshot();
|
||||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
@ -116,20 +90,19 @@ private:
|
|||
void OnPlayTimer(wxTimerEvent &event);
|
||||
|
||||
public:
|
||||
wxBitmap *curFrame;
|
||||
VideoProvider *provider;
|
||||
|
||||
wxArrayInt KeyFrames;
|
||||
SubtitlesGrid *grid;
|
||||
wxString videoName;
|
||||
int arType;
|
||||
int w,h;
|
||||
int orig_w,orig_h;
|
||||
int frame_n;
|
||||
int length;
|
||||
bool loaded;
|
||||
bool IsPlaying;
|
||||
double fps;
|
||||
VideoSlider *ControlSlider;
|
||||
//wxSlider *zoomSlider;
|
||||
wxComboBox *zoomBox;
|
||||
wxTextCtrl *PositionDisplay;
|
||||
wxTextCtrl *SubsPosition;
|
||||
|
@ -139,21 +112,18 @@ public:
|
|||
VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr);
|
||||
~VideoDisplay();
|
||||
|
||||
void OpenAVSVideo();
|
||||
void OpenAVSSubs();
|
||||
void PrepareAfterAVS();
|
||||
void SetVideo(const wxString &filename);
|
||||
void SetSubtitles(const wxString &filename);
|
||||
void Reset();
|
||||
void Unload();
|
||||
void JumpToFrame(int n);
|
||||
void JumpToTime(int ms);
|
||||
void RefreshVideo(bool force=false);
|
||||
void RefreshSubtitles();
|
||||
void RefreshVideo();
|
||||
void UpdatePositionDisplay();
|
||||
void SetAspectRatio(int type);
|
||||
void SetZoom(double value);
|
||||
int GetAspectRatio() { return arType; }
|
||||
void SetZoomPos(int pos);
|
||||
void Locked(bool state);
|
||||
void UpdateSubsRelativeTime();
|
||||
void GetScriptSize(int &w,int &h);
|
||||
|
||||
|
|
257
core/video_provider.cpp
Normal file
257
core/video_provider.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
// 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 <wx/filename.h>
|
||||
#include <wx/msw/registry.h>
|
||||
#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");
|
||||
}
|
||||
}
|
100
core/video_provider.h
Normal file
100
core/video_provider.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
// 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
|
||||
//
|
||||
|
||||
#ifndef VIDEO_PROVIDER_H
|
||||
#define VIDEO_PROVIDER_H
|
||||
|
||||
#include "avisynth_wrap.h"
|
||||
|
||||
/*class GetFrameVPThread: public wxThread {
|
||||
private:
|
||||
int getting_n;
|
||||
int current_n;
|
||||
|
||||
PClip video;
|
||||
|
||||
wxThread::ExitCode Entry();
|
||||
public:
|
||||
void GetFrame(int n);
|
||||
GetFrameVPThread(PClip clip);
|
||||
};*/
|
||||
|
||||
class VideoProvider: public AviSynthWrapper {
|
||||
private:
|
||||
VideoInfo vi;
|
||||
|
||||
wxString subfilename;
|
||||
|
||||
int last_fnum;
|
||||
|
||||
unsigned char* data;
|
||||
wxBitmap last_frame;
|
||||
|
||||
double dar;
|
||||
double zoom;
|
||||
|
||||
PClip RGB32Video;
|
||||
PClip SubtitledVideo;
|
||||
PClip ResizedVideo;
|
||||
|
||||
PClip OpenVideo(wxString _filename, bool &usedDirectshow, bool mpeg2dec3_priority = true);
|
||||
PClip ApplySubtitles(wxString _filename, PClip videosource);
|
||||
PClip ApplyDARZoom(double _zoom, double _dar, PClip videosource);
|
||||
wxBitmap GetFrame(int n, bool force);
|
||||
void LoadVSFilter();
|
||||
|
||||
public:
|
||||
VideoProvider(wxString _filename, wxString _subfilename, double _zoom, bool &usedDirectshow, bool mpeg2dec3_priority = true);
|
||||
~VideoProvider();
|
||||
|
||||
void RefreshSubtitles();
|
||||
void SetDAR(double _dar);
|
||||
void SetZoom(double _zoom);
|
||||
|
||||
wxBitmap GetFrame(int n) { return GetFrame(n,false); };
|
||||
|
||||
// properties
|
||||
int GetPosition() { return last_fnum; };
|
||||
int GetFrameCount() { return vi.num_frames; };
|
||||
double GetFPS() { return (double)vi.fps_numerator/(double)vi.fps_denominator; };
|
||||
|
||||
int GetWidth() { return vi.width; };
|
||||
int GetHeight() { return vi.height; };
|
||||
|
||||
int GetSourceWidth() { return RGB32Video->GetVideoInfo().width; };
|
||||
int GetSourceHeight() { return RGB32Video->GetVideoInfo().height; };
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue