Merged opengl branch from 806 to 859

Originally committed to SVN as r860.
This commit is contained in:
Rodrigo Braz Monteiro 2007-01-21 06:30:19 +00:00
parent 3c7d5fe033
commit 98ce168b31
58 changed files with 4356 additions and 1870 deletions

569
aegisub/VideoSink.cpp Normal file
View file

@ -0,0 +1,569 @@
/*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
*
* $Id: VideoSink.cpp,v 1.8 2007/01/17 23:40:51 mike Exp $
*
*/
#include "setup.h"
#if USE_DIRECTSHOW == 1
#include <windows.h>
#ifdef __WXDEBUG__
#undef __WXDEBUG__
#endif
typedef TCHAR* PTCHAR;
#include <streams.h>
#include <dvdmedia.h>
#include "VideoSink.h"
#include "initguid.h"
class CVideoSink;
// CLSID for videosink: {F13D3732-96BD-4108-AFEB-E85F68FF64DC}
//DEFINE_GUID(CLSID_AegiVideoSink, 0xf13d3732, 0x96bd, 0x4108, 0xaf, 0xeb, 0xe8, 0x5f, 0x68, 0xff, 0x64, 0xdc);
// {E9C80780-4C07-4b36-87D4-5241CD0C6FE2}
DEFINE_GUID(CLSID_AegiVideoSink, 0xe9c80780, 0x4c07, 0x4b36, 0x87, 0xd4, 0x52, 0x41, 0xcd, 0xc, 0x6f, 0xe2);
static int GetBPP(const BITMAPINFOHEADER& h) {
switch (h.biCompression) {
case MAKEFOURCC('Y','U','Y','2'): return 16;
case MAKEFOURCC('Y','V','1','2'): return 12;
case 0: return h.biBitCount;
}
return 0;
}
[uuid("2EE04A02-4AF5-43f8-B05B-5DEB66473419")]
interface IVSAllocator : public IUnknown {
STDMETHOD(SetNextMT)(const AM_MEDIA_TYPE *pMT) = 0;
};
class CVSAllocator : public CMemAllocator, public IVSAllocator {
CMediaType *m_nextmt;
public:
CVSAllocator(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr) : CMemAllocator(pName, pUnk, phr), m_nextmt(NULL) { }
~CVSAllocator() {
delete m_nextmt;
}
STDMETHOD(SetNextMT)(const AM_MEDIA_TYPE *pMT) {
CMediaType *newMT = new CMediaType(*pMT);
newMT = (CMediaType *)InterlockedExchangePointer((void **)&m_nextmt, newMT);
if (newMT != NULL)
delete pMT;
return S_OK;
}
STDMETHOD(GetBuffer)(IMediaSample **ppS, REFERENCE_TIME *pStart, REFERENCE_TIME *pStop, DWORD dwFlags) {
CMediaType *pMT = (CMediaType *)InterlockedExchangePointer((void **)&m_nextmt, NULL);
if (pMT != NULL) {
BITMAPINFOHEADER *bmh = NULL;
if (pMT->formattype == FORMAT_VideoInfo)
bmh = &((VIDEOINFOHEADER *)pMT->pbFormat)->bmiHeader;
else if (pMT->formattype == FORMAT_VideoInfo2)
bmh = &((VIDEOINFOHEADER2 *)pMT->pbFormat)->bmiHeader;
if (bmh != NULL) {
ALLOCATOR_PROPERTIES ap, act;
Decommit();
GetProperties(&ap);
long newsize = (bmh->biWidth * abs(bmh->biHeight) * GetBPP(*bmh)) >> 3;
if (ap.cbBuffer < newsize)
ap.cbBuffer = newsize;
SetProperties(&ap, &act);
Commit();
}
}
HRESULT hr = CMemAllocator::GetBuffer(ppS, pStart, pStop, dwFlags);
if (SUCCEEDED(hr) && pMT != NULL)
(*ppS)->SetMediaType(pMT);
if (pMT != NULL)
delete pMT;
return hr;
}
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
if (riid == __uuidof(IVSAllocator))
return GetInterface((IVSAllocator *)this, ppv);
return CMemAllocator::NonDelegatingQueryInterface(riid, ppv);
}
};
class CVideoSinkPin : public CRenderedInputPin {
bool m_changedmt;
unsigned m_types;
CVideoSink *m_sink;
HRESULT CheckMediaType(const CMediaType *pMT) {
if (pMT->majortype != MEDIATYPE_Video ||
(pMT->formattype != FORMAT_VideoInfo && pMT->formattype != FORMAT_VideoInfo2))
return VFW_E_TYPE_NOT_ACCEPTED;
if (pMT->subtype == MEDIASUBTYPE_RGB24 && m_types & IVS_RGB24)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_RGB32 && m_types & IVS_RGB32)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_YUY2 && m_types & IVS_YUY2)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_YV12 && m_types & IVS_YV12)
return S_OK;
return VFW_E_TYPE_NOT_ACCEPTED;
}
STDMETHOD(Receive)(IMediaSample *pS);
STDMETHOD(EndOfStream)();
STDMETHOD(BeginFlush)();
public:
CVideoSinkPin(CVideoSink *sink, HRESULT *phr);
STDMETHOD(GetAllocator)(IMemAllocator **ppAllocator) {
CAutoLock cObjectLock(m_pLock);
if (m_pAllocator == NULL) {
HRESULT hr = S_OK;
m_pAllocator = new CVSAllocator(NAME("CVSAllocator"), NULL, &hr);
if (FAILED(hr)) {
delete m_pAllocator;
m_pAllocator = NULL;
return hr;
}
m_pAllocator->AddRef();
}
ASSERT(m_pAllocator != NULL);
*ppAllocator = m_pAllocator;
m_pAllocator->AddRef();
return NOERROR;
}
STDMETHOD(NotifyAllocator)(IMemAllocator *pAlloc, BOOL bReadOnly) {
CAutoLock cObjectLock(m_pLock);
CComQIPtr<IVSAllocator> pVSA(pAlloc);
if (!pVSA)
return E_NOINTERFACE;
if (m_changedmt) {
m_changedmt = false;
pVSA->SetNextMT(&m_mt);
}
return CRenderedInputPin::NotifyAllocator(pAlloc, bReadOnly);
}
HRESULT SetMediaType(const CMediaType *pMT) {
HRESULT hr = CRenderedInputPin::SetMediaType(pMT);
if (FAILED(hr))
return hr;
unsigned type, width, height, bpp, arx, ary;
int stride;
if (FAILED(hr = GetFrameFormat(&type, &width, &height, &stride, &bpp, &arx, &ary, NULL)))
return hr;
if ((stride & 15) != 0) { // extend
CMediaType newMT(m_mt);
if (newMT.formattype == FORMAT_VideoInfo) {
VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)newMT.pbFormat;
vh->bmiHeader.biWidth = ((abs(stride) + 15) & ~15) / bpp;
vh->rcTarget.left = vh->rcTarget.top = 0;
vh->rcTarget.right = width;
vh->rcTarget.bottom = height;
vh->rcSource = vh->rcTarget;
} else if (newMT.formattype == FORMAT_VideoInfo2) {
VIDEOINFOHEADER2 *vh = (VIDEOINFOHEADER2 *)newMT.pbFormat;
vh->bmiHeader.biWidth = ((abs(stride) + 15) & ~15) / bpp;
vh->rcTarget.left = vh->rcTarget.top = 0;
vh->rcTarget.right = width;
vh->rcTarget.bottom = height;
vh->rcSource = vh->rcTarget;
} else
return E_FAIL;
hr = m_Connected->QueryAccept(&newMT);
if (SUCCEEDED(hr)) {
hr = CRenderedInputPin::SetMediaType(&newMT);
if (FAILED(hr))
return hr;
CComQIPtr<IVSAllocator> pVSA(m_pAllocator);
if (pVSA)
pVSA->SetNextMT(&newMT);
else
m_changedmt = true;
}
}
return S_OK;
}
BOOL AtEOF() { return m_bAtEndOfStream; }
REFERENCE_TIME SegStartTime() { return m_tStart; }
unsigned GetTypes() { return m_types; }
void SetTypes(unsigned t) { m_types = t; }
HRESULT GetFrameFormat(unsigned *type, unsigned *width, unsigned *height, int *stride,
unsigned *pbpp, unsigned *arx, unsigned *ary, long long *def_duration)
{
if (!IsConnected())
return VFW_E_NOT_CONNECTED;
unsigned bpp;
if (m_mt.subtype == MEDIASUBTYPE_RGB24)
*type = IVS_RGB24, bpp = 3;
else if (m_mt.subtype == MEDIASUBTYPE_RGB32)
*type = IVS_RGB32, bpp = 4;
else if (m_mt.subtype == MEDIASUBTYPE_YUY2)
*type = IVS_YUY2, bpp = 2;
else if (m_mt.subtype == MEDIASUBTYPE_YV12)
*type = IVS_YV12, bpp = 1;
else
return VFW_E_INVALID_MEDIA_TYPE;
if (pbpp)
*pbpp = bpp;
BITMAPINFOHEADER *bmh;
RECT rct;
if (m_mt.formattype == FORMAT_VideoInfo && m_mt.FormatLength() >= sizeof(VIDEOINFOHEADER)) {
VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)m_mt.Format();
bmh = &vh->bmiHeader;
rct = vh->rcTarget;
if (arx)
*arx = 1;
if (*ary)
*ary = 1;
if (def_duration)
*def_duration = vh->AvgTimePerFrame;
} else if (m_mt.formattype == FORMAT_VideoInfo2 && m_mt.FormatLength() >= sizeof(VIDEOINFOHEADER2)) {
VIDEOINFOHEADER2 *vh = (VIDEOINFOHEADER2 *)m_mt.Format();
bmh = &vh->bmiHeader;
rct = vh->rcTarget;
if (arx)
*arx = vh->dwPictAspectRatioX;
if (ary)
*ary = vh->dwPictAspectRatioY;
if (def_duration)
*def_duration = vh->AvgTimePerFrame;
} else
return VFW_E_INVALID_MEDIA_TYPE;
if (stride)
*stride = (bmh->biHeight > 0 && bmh->biCompression == 0 ? -1 : 1) * (int)bmh->biWidth * (int)bpp;
if (rct.right != 0)
*width = rct.right - rct.left;
else
*width = bmh->biWidth;
if (rct.bottom != 0)
*height = rct.bottom - rct.top;
else
*height = abs(bmh->biHeight);
return S_OK;
}
DECLARE_IUNKNOWN;
};
class CVideoSink :
public CBaseFilter,
public IVideoSink,
public IVideoSink2,
public IAMFilterMiscFlags
{
CVideoSinkPin *m_pin;
CRendererPosPassThru *m_rpp;
CCritSec m_lock;
int GetPinCount() { return 1; }
CBasePin *GetPin(int n) { return n == 0 ? m_pin : NULL; }
CComPtr<IMediaSample> m_sample;
HANDLE m_hEvent1, m_hEvent2, m_hNotify;
CComPtr<IVideoSinkNotify> m_notify;
public:
CVideoSink(IUnknown *pUnk, HRESULT *phr) :
CBaseFilter(_T("CVideoSink"), pUnk, &m_lock, CLSID_AegiVideoSink),
m_pin(NULL),
m_rpp(NULL)
{
m_pin = new CVideoSinkPin(this, phr);
if (FAILED(*phr))
return;
m_rpp = new CRendererPosPassThru(NAME("CVideoSink PosPassThru"), CBaseFilter::GetOwner(), phr, m_pin);
if (FAILED(*phr))
return;
m_hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hNotify = NULL;
}
~CVideoSink() {
m_sample = NULL;
delete m_rpp;
delete m_pin;
CloseHandle(m_hEvent1);
CloseHandle(m_hEvent2);
}
CCritSec *pStateLock() { return m_pLock; }
// called when lock is held
HRESULT Receive(IMediaSample *pS) {
if (pS == NULL)
m_rpp->EOS();
else
m_rpp->RegisterMediaTime(pS);
// notify callback
CComPtr<IVideoSinkNotify> notify = m_notify;
HANDLE hNotify = m_hNotify;
if (notify || hNotify) {
// save our sample
m_sample = pS;
// notify receiver
SetEvent(m_hEvent1);
}
pStateLock()->Unlock();
if (notify || hNotify) {
if (notify)
notify->FrameReady();
if (hNotify)
SetEvent(hNotify);
// wait until the thing is processed
WaitForSingleObject(m_hEvent2, INFINITE);
}
if (pS == NULL)
NotifyEvent(EC_COMPLETE, 0, (LONG_PTR)static_cast<IBaseFilter*>(this));
return S_OK;
}
HRESULT BeginFlush() {
CAutoLock lock(pStateLock());
ResetEvent(m_hEvent1);
m_sample = NULL;
SetEvent(m_hEvent2);
return S_OK;
}
STDMETHOD(Stop)() {
BeginFlush();
return CBaseFilter::Stop();
}
// IVideoSink
STDMETHOD(SetAllowedTypes)(unsigned types) {
CAutoLock lock(pStateLock());
m_pin->SetTypes(types);
return S_OK;
}
STDMETHOD(GetAllowedTypes)(unsigned *types) {
CheckPointer(types, E_POINTER);
CAutoLock lock(pStateLock());
*types = m_pin->GetTypes();
return S_OK;
}
STDMETHOD(NotifyFrame)(IVideoSinkNotify *notify) {
CAutoLock lock(pStateLock());
m_notify = notify;
return S_OK;
}
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary) {
CheckPointer(type, E_POINTER);
CheckPointer(width, E_POINTER);
CheckPointer(height, E_POINTER);
CAutoLock lock(pStateLock());
return m_pin->GetFrameFormat(type, width, height, NULL, NULL, arx, ary, NULL);
}
STDMETHOD(ReadFrame)(ReadFrameFunc f, void *arg) {
{
CAutoLock lock(pStateLock());
if (m_pin->AtEOF()) {
if (WaitForSingleObject(m_hEvent1, 0) == WAIT_OBJECT_0)
SetEvent(m_hEvent2);
return S_FALSE;
}
}
WaitForSingleObject(m_hEvent1, INFINITE);
HRESULT hr = S_OK;
{
CAutoLock lock(pStateLock());
CComPtr<IMediaSample> pS(m_sample);
m_sample = NULL;
if (!pS)
hr = S_FALSE;
else {
REFERENCE_TIME rtS, rtE;
if (SUCCEEDED(pS->GetTime(&rtS, &rtE)))
rtS += m_pin->SegStartTime();
else
rtS = -1;
if (f) {
unsigned type, srcW, srcH, arx, ary, srcBPP;
int srcS;
BYTE *srcP;
if (FAILED(m_pin->GetFrameFormat(&type, &srcW, &srcH, &srcS, &srcBPP, &arx, &ary, NULL)) ||
FAILED(pS->GetPointer(&srcP)))
hr = E_FAIL;
else {
if (srcS < 0)
srcP += abs(srcS) * (srcH - 1);
f(rtS, type, srcBPP, srcP, srcW, srcH, srcS, arx, ary, arg);
}
}
}
}
SetEvent(m_hEvent2);
return hr;
}
// IVideoSink2
STDMETHOD(NotifyFrame)(HANDLE hEvent) {
m_hNotify = hEvent;
return S_OK;
}
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary, long long *def_duration) {
CheckPointer(type, E_POINTER);
CheckPointer(width, E_POINTER);
CheckPointer(height, E_POINTER);
CAutoLock lock(pStateLock());
return m_pin->GetFrameFormat(type, width, height, NULL, NULL, arx, ary, def_duration);
}
// IAMFilterMiscFlags
STDMETHOD_(ULONG, GetMiscFlags)() { return AM_FILTER_MISC_FLAGS_IS_RENDERER; }
// COM
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
CAutoLock lock(pStateLock());
if (riid == __uuidof(IVideoSink))
return GetInterface((IVideoSink *)this, ppv);
if (riid == __uuidof(IVideoSink2))
return GetInterface((IVideoSink2 *)this, ppv);
if (riid == __uuidof(IAMFilterMiscFlags))
return GetInterface((IAMFilterMiscFlags *)this, ppv);
if (riid == IID_IMediaSeeking || riid == IID_IMediaPosition)
return m_rpp->NonDelegatingQueryInterface(riid, ppv);
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
};
CVideoSinkPin::CVideoSinkPin(CVideoSink *sink, HRESULT *phr) :
CRenderedInputPin(_T("CVideoSinkPin"), sink, sink->pStateLock(), phr, L"Input"),
m_types(IVS_RGB32),
m_sink(sink),
m_changedmt(false)
{
}
HRESULT CVideoSinkPin::Receive(IMediaSample *pS) {
m_pLock->Lock();
if (m_bFlushing) {
m_pLock->Unlock();
return S_FALSE;
}
CMediaType MT;
AM_MEDIA_TYPE *pMT;
if (SUCCEEDED(pS->GetMediaType(&pMT)) && pMT != NULL) {
MT.Set(*pMT); DeleteMediaType(pMT);
HRESULT hr = CheckMediaType(&MT);
if (FAILED(hr)) {
m_pLock->Unlock();
return hr;
}
SetMediaType(&MT);
}
if (pS->IsPreroll() == S_OK) {
m_pLock->Unlock();
return S_OK;
}
return m_sink->Receive(pS);
}
HRESULT CVideoSinkPin::EndOfStream() {
HRESULT hr1, hr2;
m_pLock->Lock();
hr1 = CRenderedInputPin::EndOfStream();
if (m_bFlushing) {
m_pLock->Unlock();
return hr1;
}
hr2 = m_sink->Receive(NULL);
if (FAILED(hr1))
return hr1;
return hr2;
}
HRESULT CVideoSinkPin::BeginFlush() {
HRESULT hr = CRenderedInputPin::BeginFlush();
m_sink->BeginFlush();
return hr;
}
//CUnknown * WINAPI CreateVideoSink(IUnknown *pUnk, HRESULT *phr) {
// CVideoSink *vs = new CVideoSink(pUnk, phr);
// if (vs == NULL)
// *phr = E_OUTOFMEMORY;
// else if (FAILED(*phr)) {
// delete vs;
// vs = NULL;
// }
// return vs;
//}
HRESULT CreateVideoSink(IBaseFilter **pVS) {
HRESULT hr = S_OK;
CVideoSink *vs = new CVideoSink(NULL,&hr);
if (vs == NULL) hr = E_OUTOFMEMORY;
else if (FAILED(hr)) {
delete vs;
vs = NULL;
}
vs->AddRef();
*pVS = vs;
return hr;
}
#endif

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
*
* $Id: VideoSink.h,v 1.4 2006/11/12 18:00:20 mike Exp $
* $Id: VideoSink.h,v 1.5 2007/01/17 23:40:51 mike Exp $
*
*/
@ -22,7 +22,7 @@ interface IVideoSinkNotify : public IUnknown {
#define IVS_YV12 8
typedef void (*ReadFrameFunc)(long long timestamp, unsigned format, unsigned bpp,
const unsigned char *frame, unsigned width, unsigned height, unsigned stride,
const unsigned char *frame, unsigned width, unsigned height, int stride,
unsigned arx, unsigned ary,
void *arg);
@ -46,4 +46,7 @@ interface IVideoSink2 : public IUnknown {
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary, long long *def_duration) = 0;
};
HRESULT CreateVideoSink(IBaseFilter **pVS);
#endif

View file

@ -124,9 +124,9 @@ wxArrayString AssExporter::GetAllFilterNames() {
}
//////////
// Export
void AssExporter::Export(wxString filename, wxString charset, wxWindow *export_dialog) {
////////////////////////
// Transform for export
AssFile *AssExporter::ExportTransform(wxWindow *export_dialog) {
// Copy
AssFile *Subs = new AssFile(*OriginalSubs);
@ -136,20 +136,16 @@ void AssExporter::Export(wxString filename, wxString charset, wxWindow *export_d
(*cur)->ProcessSubs(Subs, export_dialog);
}
/*
// Set charset
bool withCharset = !IsDefault;
wxString charset = _T("");
if (withCharset) {
wxArrayString choices = FrameMain::GetEncodings();
charset = wxGetSingleChoice(_T("Choose charset code:"), _T("Charset"),choices,NULL,-1, -1,true,250,200);
if (charset.IsEmpty()) {
delete Subs;
return;
}
}
*/
// *FIXME* (or is it?) We assume charset argument is valid here
// Done
return Subs;
}
//////////
// Export
void AssExporter::Export(wxString filename, wxString charset, wxWindow *export_dialog) {
// Get transformation
AssFile *Subs = ExportTransform(export_dialog);
// Save
Subs->Save(filename,false,false,charset);

View file

@ -73,8 +73,9 @@ public:
void AddFilter(wxString name);
void AddAutoFilters();
void DrawSettings(wxWindow *parent,wxSizer *AddTo);
void Export(wxString file, wxString charset, wxWindow *export_dialog=NULL);
AssFile *ExportTransform(wxWindow *export_dialog=NULL);
wxSizer *GetSettingsSizer(wxString name);
void Export(wxString file, wxString charset, wxWindow *export_dialog);
AssFile *GetOriginalSubs() { return OriginalSubs; }
wxString GetDescription(wxString name);
};

View file

@ -182,7 +182,7 @@ void AssFile::Save(wxString _filename,bool setfilename,bool addToRecent,const wx
void AssFile::Export(wxString _filename) {
AssExporter exporter(this);
exporter.AddAutoFilters();
exporter.Export(_filename,_T("UTF-8"), 0);
exporter.Export(_filename,_T("UTF-8"));
}

View file

@ -53,6 +53,7 @@ AssOverrideParameter::AssOverrideParameter () {
//////////////
// Destructor
AssOverrideParameter::~AssOverrideParameter () {
DeleteValue();
}

View file

@ -120,6 +120,14 @@ AudioDisplay::~AudioDisplay() {
delete spectrumDisplaySelected;
delete peak;
delete min;
provider = NULL;
player = NULL;
origImage = NULL;
spectrumRenderer = NULL;
spectrumDisplay = NULL;
spectrumDisplaySelected = NULL;
peak = NULL;
min = NULL;
}
@ -237,8 +245,8 @@ void AudioDisplay::UpdateImage(bool weak) {
}
// Draw keyframes
if (video->KeyFramesLoaded() && draw_boundary_lines) {
wxArrayInt KeyFrames = video->GetKeyFrames();
if (VideoContext::Get()->KeyFramesLoaded() && draw_boundary_lines) {
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
int nKeys = (int)KeyFrames.Count();
dc.SetPen(wxPen(wxColour(255,0,255),1));
@ -784,12 +792,11 @@ void AudioDisplay::SetFile(wxString file, VideoProvider *vprovider) {
///////////////////
// Load from video
void AudioDisplay::SetFromVideo() {
if (video->loaded) {
wxString extension = video->videoName.Right(4);
if (VideoContext::Get()->IsLoaded()) {
wxString extension = VideoContext::Get()->videoName.Right(4);
extension.LowerCase();
if (extension != _T(".d2v"))
SetFile(video->videoName, video->provider);
if (extension != _T(".d2v")) SetFile(VideoContext::Get()->videoName, VideoContext::Get()->GetProvider());
}
}
@ -853,10 +860,10 @@ void AudioDisplay::Play(int start,int end) {
// Check provider
if (!provider) {
// Load temporary provider from video
if (video->loaded) {
if (VideoContext::Get()->IsLoaded()) {
try {
// Get provider
provider = AudioProvider::GetAudioProvider(video->videoName, this, video->provider,0);
provider = AudioProvider::GetAudioProvider(VideoContext::Get()->videoName, this, VideoContext::Get()->GetProvider(),0);
// Get player
player = AudioPlayer::GetAudioPlayer();
@ -896,7 +903,7 @@ void AudioDisplay::Stop() {
if (!player) return;
player->Stop();
if (video && video->IsPlaying) video->Stop();
if (video && VideoContext::Get()->IsPlaying()) VideoContext::Get()->Stop();
}
@ -1501,9 +1508,9 @@ int AudioDisplay::GetBoundarySnap(int ms,int rangeX,bool start) {
// Find the snap boundaries
wxArrayInt boundaries;
if (video->KeyFramesLoaded() && Options.AsBool(_T("Audio Draw Secondary Lines"))) {
if (VideoContext::Get()->KeyFramesLoaded() && Options.AsBool(_T("Audio Draw Secondary Lines"))) {
__int64 keyMS;
wxArrayInt keyFrames = video->GetKeyFrames();
wxArrayInt keyFrames = VideoContext::Get()->GetKeyFrames();
int frame;
for (unsigned int i=0;i<keyFrames.Count();i++) {
frame = keyFrames[i];

View file

@ -640,7 +640,7 @@ void BaseGrid::OnMouseEvent(wxMouseEvent &event) {
// Normal click
if ((click || dclick) && !shift && !ctrl && !alt) {
if (editBox->linen != row) editBox->SetToLine(row);
if (dclick) video->JumpToFrame(VFR_Output.GetFrameAtTime(GetDialogue(row)->Start.GetMS(),true));
if (dclick) VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(GetDialogue(row)->Start.GetMS(),true));
SelectRow(row,false);
parentFrame->UpdateToolbar();
lastRow = row;
@ -875,10 +875,10 @@ AssDialogue *BaseGrid::GetDialogue(int n) {
////////////////////////////////////
// Check if line is being displayed
bool BaseGrid::IsDisplayed(AssDialogue *line) {
if (!video->loaded) return false;
if (!VideoContext::Get()->IsLoaded()) return false;
int f1 = VFR_Output.GetFrameAtTime(line->Start.GetMS(),true);
int f2 = VFR_Output.GetFrameAtTime(line->End.GetMS(),false);
if (f1 <= video->frame_n && f2 >= video->frame_n) return true;
if (f1 <= VideoContext::Get()->GetFrameN() && f2 >= VideoContext::Get()->GetFrameN()) return true;
return false;
}
@ -944,7 +944,7 @@ void BaseGrid::OnKeyPress(wxKeyEvent &event) {
// Left/right, forward to seek bar if video is loaded
if (key == WXK_LEFT || key == WXK_RIGHT) {
if (video->loaded) {
if (VideoContext::Get()->IsLoaded()) {
video->ControlSlider->SetFocus();
video->ControlSlider->AddPendingEvent(event);
return;
@ -1036,8 +1036,8 @@ void BaseGrid::OnKeyPress(wxKeyEvent &event) {
}
// Other events, send to audio display
if (video->audio->loaded) {
video->audio->AddPendingEvent(event);
if (VideoContext::Get()->audio->loaded) {
VideoContext::Get()->audio->AddPendingEvent(event);
}
else event.Skip();
}

300
aegisub/csri/csri.h Normal file
View file

@ -0,0 +1,300 @@
/*****************************************************************************
* csri: common subtitle renderer interface
*****************************************************************************
* Copyright (C) 2007 David Lamparter
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
****************************************************************************/
/** \file csri.h - main CSRI (common subtitle renderer interface) include.
* $Id: csri.h 5 2007-01-19 17:50:13Z equinox $ */
#ifndef _CSRI_H
/** \cond */
#define _CSRI_H 20070119
/** \endcond */
#include <stddef.h> /* ptrdiff_t */
#ifdef __cplusplus
extern "C" {
#endif
#ifndef CSRIAPI
#if defined(WIN32) || defined(DOXYGEN)
/** CSRI API attributes.
* defaults to \c extern / \c extern \c __cdecl on Windows.
*/
#define CSRIAPI extern __cdecl
#else
#define CSRIAPI extern
#endif
#endif
/** \defgroup base CSRI base API. */
/*@{*/
/** pixel format specification for frames */
enum csri_pixfmt {
CSRI_F_RGBA = 0,
CSRI_F_ARGB,
CSRI_F_BGRA,
CSRI_F_ABGR,
CSRI_F_RGB_ = 0x100,
CSRI_F__RGB,
CSRI_F_BGR_, /**< Windows "RGB32" */
CSRI_F__BGR,
CSRI_F_RGB = 0x200,
CSRI_F_BGR, /**< Windows "RGB24" */
CSRI_F_AYUV = 0x1000,
CSRI_F_YUVA,
CSRI_F_YVUA,
CSRI_F_YUY2 = 0x1100,
CSRI_F_YV12A = 0x2011, /**< planar YUV 2x2 + alpha plane */
CSRI_F_YV12 = 0x2111 /**< planar YUV 2x2 */
};
#define csri_is_rgb(x) ((x) < 0x1000)
#define csri_is_yuv(x) ((x) >= 0x1000)
#define csri_is_yuv_planar(x) ((x) >= 0x2000)
#define csri_get_yuv_planar_xred(x) (0xf & (x))
#define csri_get_yuv_planar_yred(x) (0xf & ((x) >> 4))
#define csri_is_yuv_packed(x) ((x) >= 0x1000 && (x) < 0x2000)
#define csri_has_alpha(x) (((x) & 0xfff) < 0x100)
/** frame/image format specification pre-fed to the renderer */
struct csri_fmt {
/** format to be used */
enum csri_pixfmt pixfmt;
/** image width, full frame.
*
* This should specify the full size of the frame.
* Specifying the video sub-size (in case of added black
* borders) is left to an extension.
*/
unsigned width;
/** image height */
unsigned height;
};
/** single frame to be fed to the renderer. */
struct csri_frame {
/** frame format.
* It is an application bug if this differs from the one
* passed in struct #csri_fmt to csri_query_fmt()
*/
enum csri_pixfmt pixfmt;
/** the frame's data.
* Packed formats only use planes[0]; planar formats
* have the data ordered as Y, U, V[, A].
*
* Also note that the topmost line always comes first.
* The Windows biHeight strange-ity is \a NOT duplicated.
*/
unsigned char *planes[4];
/** strides for the individual planes.
* Stride means full byte offset, i.e. do \a not add
* frame width
*/
ptrdiff_t strides[4];
};
#ifndef CSRI_OWN_HANDLES
/** opaque renderer data */
typedef void csri_rend;
/** opaque instance data */
typedef void csri_inst;
#endif
#ifdef DOXYGEN
/** disable the emission of the csri_rend and csri_inst typedefs.
* define this if you are in a renderer and are typedef'ing
* csri_rend and csri_inst to your own structs.
*/
#define CSRI_OWN_HANDLES
#endif
/** renderer description */
struct csri_info {
/** an identifier for the renderer.
* - MUST match the regular expression
* \code ^[a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])? \endcode
* i.e. consists only of letters, numbers and underscores;
* must start with a letter and doesnt have an underscore
* as the last character.
*/
const char *name;
/** an identifier to the exact version of the renderer.
* most likely a version number or revision identifier.
*
* The helper library does a strcmp over this field in order
* to order multiple instances of the same renderer. Use
* higher-byte-value strings for newer renderers.
*/
const char *specific;
/** a nice name to be presented to the user */
const char *longname;
/** the renderer's author */
const char *author;
/** a copyright string. Copyright (c) 2042 by Mr. Nice Guy */
const char *copyright;
};
/** data of extension-dependent type.
* The field to be used MUST be specified in the extension where it is used.
*/
union csri_vardata {
long lval;
double dval;
const char *utf8val;
void *otherval;
};
/** extension identifier.
* This follows reverse DNS syntax, i.e.:
* \code root.branch.leaf \endcode
* you can either reverse a registered domain name, e.g.
* \code com.microsoft.csri.usegdiplus \endcode
* or ask the CSRI maintainers to assign a namespace to you.
*
* currently registered namespaces are:
*
* \code
* csri.* - official extensions
* asa.* - custom extensions of the asa renderer
* \endcode
*/
typedef const char *csri_ext_id;
/** script loading parameters.
* each flag MUST have an associated extension, which can be queried
* with csri_query_ext(). If the open flag constitutes an extension on its
* sole own, csri_query_ext() can return a meaningless non-NULL value for
* it.
*
* The data field used must be specified.
*
* An extension can have multiple flags. In that case, the flags should have
* the extension name as common prefix, separated with a dot.
*
* A renderer MUST ignore unknown open flags. It MUST NOT return an error
* just because it does not support a particular flag.
*/
struct csri_openflag {
/** flag name */
csri_ext_id name;
/** flag data argument */
union csri_vardata data;
/** link to next flag */
struct csri_openflag *next;
};
/** load a script from a file.
* \param renderer the handle to the renderer
* \param filename the path to the file to be loaded. \n
* The filename should be encoded as UTF-8. Windows renderers are
* expected to convert it to UTF-16 and use the Unicode Windows API
* functions.
* \param flags a linked list of open flags. \n
* The caller manages memory allocation, i.e. static allocation is OK.
* \return the renderer instance handle, or NULL on error.
*/
CSRIAPI csri_inst *csri_open_file(csri_rend *renderer,
const char *filename, struct csri_openflag *flags);
/** load a script from memory.
* \param renderer the handle to the renderer
* \param data pointer to the first data byte. \n
* The caller manages memory allocation and should free the data after
* calling csri_open_mem(). If the renderer needs to keep the data, it
* must copy it. \n
* The renderer is not allowed to write to the data.
* \param length length, in bytes, of the data
* \param flags see csri_open_file()
* \return the render instance handle, or NULL on error.
*/
CSRIAPI csri_inst *csri_open_mem(csri_rend *renderer,
const void *data, size_t length, struct csri_openflag *flags);
/** close a renderer instance.
* \param inst the instance handle.
*/
CSRIAPI void csri_close(csri_inst *inst);
/** query / set the image format and size.
* \param inst the renderer instance handle
* \param fmt the format and image size to be used
* \return 0 if the format was successfully set,
* any other value in case of error.
*/
CSRIAPI int csri_query_fmt(csri_inst *inst, const struct csri_fmt *fmt);
/** render a single frame
* \param inst the renderer instance handle
* \param frame frame data to render to
* \param time associated timestamp of the frame
*/
CSRIAPI void csri_render(csri_inst *inst, struct csri_frame *frame,
double time);
/** query for an extension.
* \param rend the renderer handle
* \param extname the extension's identifier
* \return NULL if the extension is not supported,
* a pointer to extension-specific data otherwise
*
* The data pointed to by the return value does not neccessarily need to
* have any meaning; An extension that does not need to return data
* can return a pointer to whatever it wants, as long as that pointer is
* not NULL.
*
* In the usual case, the pointer is supposed to point to a struct with
* function pointers and other information as needed.
*/
CSRIAPI void *csri_query_ext(csri_rend *rend, csri_ext_id extname);
/** get renderer information
* \param rend the renderer handle
* \return information about the renderer, or NULL in case the renderer
* encountered an internal error.
*/
CSRIAPI struct csri_info *csri_renderer_info(csri_rend *rend);
/*@}*/
#ifdef __cplusplus
}
#endif
#endif /* _CSRI_H */

95
aegisub/csri/loader.h Normal file
View file

@ -0,0 +1,95 @@
/*****************************************************************************
* csri: common subtitle renderer interface
*****************************************************************************
* Copyright (C) 2007 David Lamparter
* 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
****************************************************************************/
/** \file loader.h - CSRI helper library functions.
* $Id: loader.h 3 2007-01-19 12:04:43Z equinox $ */
#ifndef _CSRI_HELPER_H
/** \cond */
#define _CSRI_HELPER_H 20070119
/** \endcond */
#if _CSRI_HELPER_H != _CSRI_H
#error CSRI helper API header doesn't match CSRI header
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup help CSRI helper/loader API.
*
* These functions locate renderers based on given parameters.
*
* <b>Renderers must implement these functions as well.</b>
*
* They are used by the library to grab renderer information
* from a shared object; and also this way a single renderer
* can be linked directly into an appliaction.
*/
/*@{*/
/** try to load a given renderer
* \param name the name of the renderer, as in csri_info.name
* \param specific the specific version of the renderer,
* as in csri_info.specific;\n
* alternatively NULL if any version of the renderer is ok.
* \return a handle to the renderer if it was successfully loaded,
* NULL otherwise.
*/
CSRIAPI csri_rend *csri_renderer_byname(const char *name,
const char *specific);
/** get the default (highest priority) renderer
* \return a handle to the default renderer, or NULL if
* no renderer is installed.
*
* Together with csri_renderer_next(), this can be used
* to enumerate all installed renderers.
*/
CSRIAPI csri_rend *csri_renderer_default();
/** get the next lower priority renderer
* \param prev the current renderer
* \return the renderer with the next lower priority than
* the one named in prev, or NULL if prev is the last
* renderer installed.
*/
CSRIAPI csri_rend *csri_renderer_next(csri_rend *prev);
/*@}*/
#ifdef __cplusplus
}
#endif
#endif /* _CSRI_HELPER_H */

View file

@ -78,6 +78,7 @@ AboutScreen::AboutScreen(wxWindow *parent)
libString += _T("asa - Copyright (c) 2004-2007, David Lamparter;\n");
#endif
libString += _T("MyThes - Copyright (c) 2003 Kevin B. Hendricks, Stratford, Ontario, Canada\n");
libString += _T("Matroska Parser and VideoSink - Copyright (c) 2004-2007 Mike Matsnev\n");
// Generate about string
wxString aboutString;
@ -88,13 +89,13 @@ AboutScreen::AboutScreen(wxWindow *parent)
aboutString += _T("Automation - Copyright (c) 2005-2007 Niels Martin Hansen (aka jfs).\n");
aboutString += _T("Motion Tracker - Copyright (c) 2006 Hajo Krabbenhoeft (aka Tentacle).\n");
aboutString += _("Programmers: ");
aboutString += _T(" ArchMageZeratuL, jfs, Myrsloik, equinox, Tentacle, Yuvi,\n Azzy, Pomyk, Motoko-chan, Dansolo.\n");
aboutString += _T(" ArchMageZeratuL, jfs, Myrsloik, equinox, Tentacle, Yuvi,\n Azzy, Pomyk, Motoko-chan, Dansolo, Haali.\n");
aboutString += _("Manual by: ");
aboutString += _T("ArchMage ZeratuL, jfs, movax, Kobi, TheFluff, Jcubed.\n");
aboutString += _("Forum, wiki and bug tracker hosting by: ");
aboutString += _T("Bot1.\n");
aboutString += _("SVN hosting by: ");
aboutString += _T("BerliOS, Mentar.\n");
aboutString += _T("equinox, BerliOS, Mentar.\n");
aboutString += translatorCredit;
aboutString += _T("\n") + libString;
aboutString += _("\nSee the help file for full credits.\n");

View file

@ -49,7 +49,7 @@ DialogJumpTo::DialogJumpTo (wxWindow *parent,VideoDisplay *_vid)
// Set initial values
ready = false;
vid = _vid;
jumpframe = vid->frame_n;
jumpframe = VideoContext::Get()->GetFrameN();
jumptime.SetMS(VFR_Output.GetTimeAtFrame(jumpframe));
// Times
@ -122,7 +122,7 @@ void DialogJumpToEvent::OnEditFrame (wxCommandEvent &event) { control->OnEditFra
void DialogJumpTo::OnKey(wxKeyEvent &event) {
int key = event.GetKeyCode();
if (key == WXK_RETURN) {
vid->JumpToFrame(jumpframe);
VideoContext::Get()->JumpToFrame(jumpframe);
EndModal(0);
return;
}
@ -133,7 +133,7 @@ void DialogJumpTo::OnKey(wxKeyEvent &event) {
////////////////////////
// On OK button pressed
void DialogJumpTo::OnClose(bool ok) {
if (ok) vid->JumpToFrame(jumpframe);
if (ok) VideoContext::Get()->JumpToFrame(jumpframe);
EndModal(0);
}

View file

@ -317,7 +317,7 @@ DialogOptions::DialogOptions(wxWindow *parent)
wxSizer *videoSizer1 = new wxStaticBoxSizer(wxVERTICAL,videoPage,_("Options"));
wxSizer *videoSizer2 = new wxStaticBoxSizer(wxVERTICAL,videoPage,_("Advanced - EXPERT USERS ONLY"));
wxFlexGridSizer *videoSizer3 = new wxFlexGridSizer(5,2,5,5);
wxFlexGridSizer *videoSizer4 = new wxFlexGridSizer(4,2,5,5);
wxFlexGridSizer *videoSizer4 = new wxFlexGridSizer(3,2,5,5);
wxControl *control;
// First sizer
@ -367,11 +367,6 @@ DialogOptions::DialogOptions(wxWindow *parent)
control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,choices4,wxCB_DROPDOWN | wxCB_READONLY);
Bind(control,_T("Video provider"),1);
videoSizer4->Add(control,1,wxEXPAND);
videoSizer4->Add(new wxStaticText(videoPage,-1,_("Avisynth video resizer: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10);
wxString choices5[3] = { _T("BilinearResize"), _T("BicubicResize"), _T("LanczosResize") };
control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,3,choices5,wxCB_DROPDOWN);
Bind(control,_T("Video resizer"));
videoSizer4->Add(control,1,wxEXPAND);
videoSizer4->Add(new wxStaticText(videoPage,-1,_("Avisynth memory limit: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10);
control = new wxTextCtrl(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,0,NumValidator(NULL,false));
Bind(control,_T("Avisynth memorymax"));

View file

@ -99,7 +99,7 @@ DialogProperties::DialogProperties (wxWindow *parent, VideoDisplay *_vid)
ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue));
wxStaticText *ResText = new wxStaticText(this,-1,_T("x"));
wxButton *FromVideo = new wxButton(this,BUTTON_FROM_VIDEO,_("From video"));
if (!vid->loaded) FromVideo->Enable(false);
if (!VideoContext::Get()->IsLoaded()) FromVideo->Enable(false);
ResSizer->Add(ResX,1,wxRIGHT,5);
ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5);
ResSizer->Add(ResY,1,wxRIGHT,5);
@ -209,7 +209,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->provider->GetSourceWidth()));
ResY->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceHeight()));
ResX->SetValue(wxString::Format(_T("%i"),VideoContext::Get()->GetWidth()));
ResY->SetValue(wxString::Format(_T("%i"),VideoContext::Get()->GetHeight()));
event.Skip();
}

View file

@ -68,7 +68,7 @@ DialogResample::DialogResample(wxWindow *parent, SubtitlesGrid *_grid)
ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue));
wxStaticText *ResText = new wxStaticText(this,-1,_("x"));
wxButton *FromVideo = new wxButton(this,BUTTON_DEST_FROM_VIDEO,_("From video"));
if (!vid->loaded) FromVideo->Enable(false);
if (!VideoContext::Get()->IsLoaded()) FromVideo->Enable(false);
ResSizer->Add(ResX,1,wxRIGHT,5);
ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5);
ResSizer->Add(ResY,1,wxRIGHT,5);
@ -244,8 +244,8 @@ void DialogResample::OnResample (wxCommandEvent &event) {
/////////////////////////////////////////
// Get destination resolution from video
void DialogResample::OnGetDestRes (wxCommandEvent &event) {
ResX->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceWidth()));
ResY->SetValue(wxString::Format(_T("%i"),vid->provider->GetSourceHeight()));
ResX->SetValue(wxString::Format(_T("%i"),VideoContext::Get()->GetWidth()));
ResY->SetValue(wxString::Format(_T("%i"),VideoContext::Get()->GetHeight()));
}

View file

@ -57,7 +57,7 @@ wxDialog (parent, -1, _("Styling assistant"), wxDefaultPosition, wxDefaultSize,
{
// Variables
grid = _grid;
audio = grid->video->audio->box->audioDisplay;
audio = VideoContext::Get()->audio->box->audioDisplay;
needCommit = false;
linen = -1;
@ -181,7 +181,7 @@ void DialogStyling::JumpToLine(int n) {
grid->MakeCellVisible(linen,0);
// Update display
if (PreviewCheck->IsChecked()) grid->video->JumpToFrame(VFR_Output.GetFrameAtTime(line->Start.GetMS(),true));
if (PreviewCheck->IsChecked()) VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(line->Start.GetMS(),true));
}

View file

@ -205,7 +205,7 @@ void DialogTimingProcessor::UpdateControls() {
adjascentBias->Enable(adjsEnable->IsChecked());
// Keyframes are only available if timecodes are loaded
bool keysAvailable = grid->video->KeyFramesLoaded();
bool keysAvailable = VideoContext::Get()->KeyFramesLoaded();
bool enableKeys = keysEnable->IsChecked() && keysAvailable;
keysStartBefore->Enable(enableKeys);
keysStartAfter->Enable(enableKeys);
@ -513,8 +513,8 @@ void DialogTimingProcessor::Process() {
// Keyframe snapping
if (keysEnable->IsChecked()) {
// Get keyframes
KeyFrames = grid->video->GetKeyFrames();
KeyFrames.Add(grid->video->length-1);
KeyFrames = VideoContext::Get()->GetKeyFrames();
KeyFrames.Add(VideoContext::Get()->GetLength()-1);
// Variables
int startF,endF;

View file

@ -60,7 +60,7 @@ DialogTranslation::DialogTranslation (wxWindow *parent,AssFile *_subs,SubtitlesG
main = parent;
subs = _subs;
grid = _grid;
audio = grid->video->audio;
audio = VideoContext::Get()->audio;
// Translation box
wxSizer *TranslationSizer = new wxBoxSizer(wxVERTICAL);
@ -219,9 +219,9 @@ bool DialogTranslation::JumpToLine(int n,int block) {
void DialogTranslation::UpdatePreview () {
if (enablePreview) {
try {
if (grid->video->loaded) {
if (VideoContext::Get()->IsLoaded()) {
AssDialogue *cur = grid->GetDialogue(curline);
grid->video->JumpToTime(cur->Start.GetMS());
VideoContext::Get()->JumpToTime(cur->Start.GetMS());
}
}
catch (...) {

74
aegisub/factory.h Normal file
View file

@ -0,0 +1,74 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
///////////
// Headers
#include <map>
/////////////////
// Factory class
template <class T>
class AegisubFactory {
protected:
static std::map<wxString,T*> *factories;
void RegisterFactory(wxString name) {
if (factories == NULL) factories = new std::map<wxString,T*>;
factories->insert(std::make_pair(name.Lower(),(T*)this));
}
static T *GetFactory(wxString name) {
if (factories == NULL) {
factories = new std::map<wxString,T*>;
return NULL;
}
std::map<wxString,T*>::iterator res = factories->find(name.Lower());
if (res != factories->end()) return res->second;
return NULL;
}
public:
static wxArrayString GetFactoryList() {
wxArrayString list;
for (std::map<wxString,T*>::iterator cur=factories->begin();cur!=factories->end();cur++) {
list.Add(cur->first);
}
return list;
}
virtual ~AegisubFactory() {}
};

View file

@ -450,14 +450,14 @@ void FrameMain::InitContents() {
BottomSizer->Add(SubsBox,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,0);
AssFile::StackReset();
videoBox->videoSlider->grid = SubsBox;
videoBox->videoDisplay->grid = SubsBox;
VideoContext::Get()->grid = SubsBox;
videoBox->videoDisplay->SetZoomPos(Options.AsInt(_T("Video Default Zoom")));
Search.grid = SubsBox;
// Audio area
audioBox = new AudioBox(Panel,videoBox->videoDisplay);
audioBox->frameMain = this;
videoBox->videoDisplay->audio = audioBox->audioDisplay;
VideoContext::Get()->audio = audioBox->audioDisplay;
// Top sizer
EditBox = new SubsEditBox(Panel,SubsBox);
@ -646,7 +646,7 @@ bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) {
// Failed, ask user
if (filename.IsEmpty()) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
wxString path = Options.AsText(_T("Last open subtitles path"));
wxFileName origPath(AssFile::top->filename);
filename = wxFileSelector(_("Save subtitles file"),path,origPath.GetName() + _T(".ass"),_T("ass"),AssFile::GetWildcardList(1),wxSAVE | wxOVERWRITE_PROMPT,this);
@ -718,13 +718,13 @@ int FrameMain::TryToCloseSubs(bool enableCancel) {
// 2: audio
void FrameMain::SetDisplayMode(int mode) {
Freeze();
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
if (mode != curMode) {
// Automatic mode
bool showVid=false, showAudio=false;
if (mode == -1) {
// See what's loaded
if (videoBox->videoDisplay->loaded) showVid = true;
if (VideoContext::Get()->IsLoaded()) showVid = true;
if (audioBox->loaded) showAudio = true;
// Set mode
@ -836,8 +836,8 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
bool hasToLoad = false;
if (curSubsAudio != audioBox->audioName ||
curSubsVFR != VFR_Output.GetFilename() ||
curSubsVideo != videoBox->videoDisplay->videoName ||
curSubsKeyframes != videoBox->videoDisplay->GetKeyFramesName() ||
curSubsVideo != VideoContext::Get()->videoName ||
curSubsKeyframes != VideoContext::Get()->GetKeyFramesName() ||
!AutoScriptString.IsEmpty() ||
local_scripts->GetScripts().size() > 0) {
hasToLoad = true;
@ -858,13 +858,13 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
LoadVFR(curSubsVFR);
// Video
if (curSubsVideo != videoBox->videoDisplay->videoName) {
if (curSubsVideo != VideoContext::Get()->videoName) {
if (curSubsVideo != _T("")) {
LoadVideo(curSubsVideo);
if (videoBox->videoDisplay->loaded) {
videoBox->videoDisplay->JumpToFrame(videoPos);
if (VideoContext::Get()->IsLoaded()) {
videoBox->videoDisplay->SetAspectRatio(videoAr,videoArValue);
videoBox->videoDisplay->SetZoomPos(videoZoom-1);
VideoContext::Get()->JumpToFrame(videoPos);
}
}
}
@ -921,7 +921,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
wxString seekpos = _T("0");
wxString ar = _T("0");
wxString zoom = _T("6");
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
seekpos = wxString::Format(_T("%i"),videoBox->videoDisplay->ControlSlider->GetValue());
zoom = wxString::Format(_T("%i"),videoBox->videoDisplay->zoomBox->GetSelection()+1);
@ -934,12 +934,12 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
subs->SetScriptInfo(_T("Audio File"),MakeRelativePath(audioBox->audioName,AssFile::top->filename));
// Store video data
subs->SetScriptInfo(_T("Video File"),MakeRelativePath(videoBox->videoDisplay->videoName,AssFile::top->filename));
subs->SetScriptInfo(_T("Video File"),MakeRelativePath(VideoContext::Get()->videoName,AssFile::top->filename));
subs->SetScriptInfo(_T("Video Aspect Ratio"),ar);
subs->SetScriptInfo(_T("Video Zoom"),zoom);
subs->SetScriptInfo(_T("Video Position"),seekpos);
subs->SetScriptInfo(_T("VFR File"),MakeRelativePath(VFR_Output.GetFilename(),AssFile::top->filename));
subs->SetScriptInfo(_T("Keyframes File"),MakeRelativePath(videoBox->videoDisplay->GetKeyFramesName(),AssFile::top->filename));
subs->SetScriptInfo(_T("Keyframes File"),MakeRelativePath(VideoContext::Get()->GetKeyFramesName(),AssFile::top->filename));
// Store Automation script data
// Algorithm:
@ -981,15 +981,15 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
// Loads video
void FrameMain::LoadVideo(wxString file,bool autoload) {
if (blockVideoLoad) return;
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
try {
if (videoBox->videoDisplay->loaded && VFR_Output.GetFrameRateType() == VFR && !autoload) {
if (VideoContext::Get()->IsLoaded() && VFR_Output.GetFrameRateType() == VFR && !autoload) {
int result = wxMessageBox(_("You have timecodes loaded currently. Would you like to unload them?"), _("Unload timecodes?"), wxYES_NO, this);
if (result == wxYES) {
VFR_Output.Unload();
}
}
videoBox->videoDisplay->SetVideo(file);
VideoContext::Get()->SetVideo(file);
}
catch (const wchar_t *error) {
wxString err(error);
@ -1000,10 +1000,10 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
}
// Check that the video size matches the script video size specified
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
int scriptx = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResX"));
int scripty = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResY"));
int vidx = videoBox->videoDisplay->provider->GetSourceWidth(), vidy = videoBox->videoDisplay->provider->GetSourceHeight();
int vidx = VideoContext::Get()->GetWidth(), vidy = VideoContext::Get()->GetHeight();
if (scriptx != vidx || scripty != vidy) {
switch (Options.AsInt(_T("Video Check Script Res"))) {
case 1:
@ -1034,7 +1034,7 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
// Loads audio
void FrameMain::LoadAudio(wxString filename,bool FromVideo) {
if (blockAudioLoad) return;
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
try {
audioBox->SetFile(filename,FromVideo);
SetDisplayMode(-1);
@ -1058,7 +1058,7 @@ void FrameMain::LoadAudio(wxString filename,bool FromVideo) {
/////////////
// Loads VFR
void FrameMain::LoadVFR(wxString filename) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
if (filename != _T("")) {
try {
VFR_Output.Load(filename);
@ -1077,8 +1077,8 @@ void FrameMain::LoadVFR(wxString filename) {
else {
VFR_Output.Unload();
if (videoBox->videoDisplay->loaded && !VFR_Output.IsLoaded()) {
VFR_Output.SetCFR(videoBox->videoDisplay->fps);
if (VideoContext::Get()->IsLoaded() && !VFR_Output.IsLoaded()) {
VFR_Output.SetCFR(VideoContext::Get()->GetFPS());
}
}
@ -1094,7 +1094,7 @@ void FrameMain::LoadKeyframes(wxString filename) {
if (filename.IsEmpty()) {
wxArrayInt keyFrames;
keyFrames.Empty();
videoBox->videoDisplay->CloseOverKeyFrames();
VideoContext::Get()->CloseOverKeyFrames();
videoBox->videoSlider->Refresh();
Refresh();
return;
@ -1128,12 +1128,12 @@ void FrameMain::LoadKeyframes(wxString filename) {
}
// Set keyframes
videoBox->videoDisplay->SetOverKeyFrames(keyFrames);
videoBox->videoDisplay->SetKeyFramesName(filename);
VideoContext::Get()->SetOverKeyFrames(keyFrames);
VideoContext::Get()->SetKeyFramesName(filename);
// Set FPS
if (!videoBox->videoDisplay->loaded) {
videoBox->videoDisplay->fps = fps;
if (!VideoContext::Get()->IsLoaded()) {
VideoContext::Get()->SetFPS(fps);
VFR_Input.SetCFR(fps);
if (!VFR_Output.IsLoaded()) VFR_Output.SetCFR(fps);
}
@ -1160,12 +1160,12 @@ void FrameMain::LoadKeyframes(wxString filename) {
// Save Keyframes
void FrameMain::SaveKeyframes(wxString filename) {
// Get keyframes
wxArrayInt keyFrames = videoBox->videoDisplay->GetKeyFrames();
wxArrayInt keyFrames = VideoContext::Get()->GetKeyFrames();
// Write header
TextFileWriter file(filename,_T("ASCII"));
file.WriteLineToFile(_T("# keyframe format v1"));
file.WriteLineToFile(wxString::Format(_T("fps %f"),videoBox->videoDisplay->fps));
file.WriteLineToFile(wxString::Format(_T("fps %f"),VideoContext::Get()->GetFPS()));
// Write keyframes
for (unsigned int i=0;i<keyFrames.Count();i++) {

View file

@ -256,7 +256,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
else if (curMenu == viewMenu) {
// Flags
bool aud = audioBox->audioDisplay->loaded;
bool vid = videoBox->videoDisplay->loaded;
bool vid = VideoContext::Get()->IsLoaded();
// Set states
MenuBar->Enable(Menu_View_Audio,aud);
@ -272,7 +272,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
// Video menu
else if (curMenu == videoMenu) {
bool state = videoBox->videoDisplay->loaded;
bool state = VideoContext::Get()->IsLoaded();
// Rebuild icons
RebuildMenuItem(videoMenu,Menu_Video_JumpTo,wxBITMAP(jumpto_button),wxBITMAP(jumpto_disable_button),state);
@ -292,8 +292,8 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
MenuBar->Enable(Menu_Video_AR_235,state);
MenuBar->Enable(Menu_Video_AR_Custom,state);
MenuBar->Enable(Menu_File_Close_VFR,VFR_Output.GetFrameRateType() == VFR);
MenuBar->Enable(Menu_Video_Close_Keyframes,videoBox->videoDisplay->OverKeyFramesLoaded());
MenuBar->Enable(Menu_Video_Save_Keyframes,videoBox->videoDisplay->KeyFramesLoaded());
MenuBar->Enable(Menu_Video_Close_Keyframes,VideoContext::Get()->OverKeyFramesLoaded());
MenuBar->Enable(Menu_Video_Save_Keyframes,VideoContext::Get()->KeyFramesLoaded());
// Set AR radio
int arType = videoBox->videoDisplay->GetAspectRatioType();
@ -368,7 +368,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
// Audio menu
else if (curMenu == audioMenu) {
bool state = audioBox->loaded;
bool vidstate = videoBox->videoDisplay->loaded;
bool vidstate = VideoContext::Get()->IsLoaded();
MenuBar->Enable(Menu_Audio_Open_From_Video,vidstate);
MenuBar->Enable(Menu_Audio_Close,state);
@ -408,7 +408,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
MenuBar->Enable(MENU_INSERT_AFTER,state);
MenuBar->Enable(MENU_SPLIT_BY_KARAOKE,state);
RebuildMenuItem(subtitlesMenu,MENU_DELETE,wxBITMAP(delete_button),wxBITMAP(delete_disable_button),state);
state2 = count > 0 && videoBox->videoDisplay->loaded;
state2 = count > 0 && VideoContext::Get()->IsLoaded();
MenuBar->Enable(MENU_INSERT_BEFORE_VIDEO,state2);
MenuBar->Enable(MENU_INSERT_AFTER_VIDEO,state2);
MenuBar->Enable(Menu_Subtitles_Insert,state);
@ -435,7 +435,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
int count = sels.Count();
// Video related
bool state = videoBox->videoDisplay->loaded;
bool state = VideoContext::Get()->IsLoaded();
RebuildMenuItem(timingMenu,Menu_Subs_Snap_Start_To_Video,wxBITMAP(substart_to_video),wxBITMAP(substart_to_video_disable),state);
RebuildMenuItem(timingMenu,Menu_Subs_Snap_End_To_Video,wxBITMAP(subend_to_video),wxBITMAP(subend_to_video_disable),state);
RebuildMenuItem(timingMenu,Menu_Video_Snap_To_Scene,wxBITMAP(snap_subs_to_scene),wxBITMAP(snap_subs_to_scene_disable),state);
@ -617,7 +617,7 @@ void FrameMain::OnIRCChannel(wxCommandEvent& WXUNUSED(event)) {
//////////////
// Play video
void FrameMain::OnVideoPlay(wxCommandEvent &event) {
videoBox->videoDisplay->Play();
VideoContext::Get()->Play();
}
@ -816,31 +816,31 @@ void FrameMain::OnSaveKeyframes (wxCommandEvent &event) {
///////////////
// Zoom levels
void FrameMain::OnSetZoom50(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->zoomBox->SetSelection(3);
videoBox->videoDisplay->SetZoomPos(3);
}
void FrameMain::OnSetZoom100(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->zoomBox->SetSelection(7);
videoBox->videoDisplay->SetZoomPos(7);
}
void FrameMain::OnSetZoom200(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->zoomBox->SetSelection(15);
videoBox->videoDisplay->SetZoomPos(15);
}
void FrameMain::OnZoomIn (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->zoomBox->SetSelection(videoBox->videoDisplay->zoomBox->GetSelection()+1);
videoBox->videoDisplay->SetZoomPos(videoBox->videoDisplay->zoomBox->GetSelection());
}
void FrameMain::OnZoomOut (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
int selTo = videoBox->videoDisplay->zoomBox->GetSelection()-1;
if (selTo < 0) selTo = 0;
videoBox->videoDisplay->zoomBox->SetSelection(selTo);
@ -856,8 +856,8 @@ void FrameMain::OnSetZoom(wxCommandEvent &event) {
///////////////////////
// Open jump to dialog
void FrameMain::OnJumpTo(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
if (videoBox->videoDisplay->loaded) {
VideoContext::Get()->Stop();
if (VideoContext::Get()->IsLoaded()) {
DialogJumpTo JumpTo(this,videoBox->videoDisplay);
JumpTo.ShowModal();
videoBox->videoSlider->SetFocus();
@ -868,7 +868,7 @@ void FrameMain::OnJumpTo(wxCommandEvent& WXUNUSED(event)) {
/////////////////////
// Open shift dialog
void FrameMain::OnShift(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogShiftTimes Shift(this,SubsBox,videoBox->videoDisplay);
Shift.ShowModal();
}
@ -877,7 +877,7 @@ void FrameMain::OnShift(wxCommandEvent& WXUNUSED(event)) {
///////////////////
// Open properties
void FrameMain::OnOpenProperties (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogProperties Properties(this, videoBox->videoDisplay);
int res = Properties.ShowModal();
if (res) {
@ -889,7 +889,7 @@ void FrameMain::OnOpenProperties (wxCommandEvent &event) {
///////////////////////
// Open styles manager
void FrameMain::OnOpenStylesManager(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogStyleManager StyleManager(this,SubsBox);
StyleManager.ShowModal();
EditBox->UpdateGlobals();
@ -900,7 +900,7 @@ void FrameMain::OnOpenStylesManager(wxCommandEvent& WXUNUSED(event)) {
////////////////////
// Open attachments
void FrameMain::OnOpenAttachments(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogAttachments attachments(this);
attachments.ShowModal();
}
@ -909,7 +909,7 @@ void FrameMain::OnOpenAttachments(wxCommandEvent& WXUNUSED(event)) {
//////////////////////////////
// Open translation assistant
void FrameMain::OnOpenTranslation(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
int start = SubsBox->GetFirstSelRow();
if (start == -1) start = 0;
DialogTranslation Trans(this,AssFile::top,SubsBox,start,true);
@ -920,7 +920,7 @@ void FrameMain::OnOpenTranslation(wxCommandEvent& WXUNUSED(event)) {
//////////////////////
// Open Spell Checker
void FrameMain::OnOpenSpellCheck (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
wxMessageBox(_T("TODO!"),_T("Spellchecker"));
}
@ -928,7 +928,7 @@ void FrameMain::OnOpenSpellCheck (wxCommandEvent &event) {
////////////////////////
// Open Fonts Collector
void FrameMain::OnOpenFontsCollector (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogFontsCollector Collector(this);
Collector.ShowModal();
}
@ -937,7 +937,7 @@ void FrameMain::OnOpenFontsCollector (wxCommandEvent &event) {
/////////////////////////////
// Open Resolution Resampler
void FrameMain::OnOpenResample (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogResample diag(this, SubsBox);
diag.ShowModal();
}
@ -975,7 +975,7 @@ void FrameMain::OnOpenOptions (wxCommandEvent &event) {
///////////////////
// Open Automation
void FrameMain::OnOpenAutomation (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogAutomation dlg(this, local_scripts);
dlg.ShowModal();
}
@ -996,7 +996,7 @@ void FrameMain::OnAutomationMacro (wxCommandEvent &event) {
//////////////////////
// Snap subs to video
void FrameMain::OnSnapSubsStartToVid (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
wxArrayInt sel = SubsBox->GetSelection();
if (sel.Count() > 0) {
wxCommandEvent dummy;
@ -1006,7 +1006,7 @@ void FrameMain::OnSnapSubsStartToVid (wxCommandEvent &event) {
}
void FrameMain::OnSnapSubsEndToVid (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
wxArrayInt sel = SubsBox->GetSelection();
if (sel.Count() > 0) {
wxCommandEvent dummy;
@ -1019,7 +1019,7 @@ void FrameMain::OnSnapSubsEndToVid (wxCommandEvent &event) {
//////////////////////
// Jump video to subs
void FrameMain::OnSnapVidToSubsStart (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
wxArrayInt sel = SubsBox->GetSelection();
if (sel.Count() > 0) {
wxCommandEvent dummy;
@ -1029,7 +1029,7 @@ void FrameMain::OnSnapVidToSubsStart (wxCommandEvent &event) {
}
void FrameMain::OnSnapVidToSubsEnd (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
wxArrayInt sel = SubsBox->GetSelection();
if (sel.Count() > 0) {
wxCommandEvent dummy;
@ -1042,14 +1042,14 @@ void FrameMain::OnSnapVidToSubsEnd (wxCommandEvent &event) {
/////////////////
// Snap to scene
void FrameMain::OnSnapToScene (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
// Get frames
wxArrayInt sel = SubsBox->GetSelection();
int curFrame = videoBox->videoDisplay->frame_n;
int curFrame = VideoContext::Get()->GetFrameN();
int prev = 0;
int next = 0;
int frame = 0;
wxArrayInt keyframes = videoBox->videoDisplay->GetKeyFrames();
wxArrayInt keyframes = VideoContext::Get()->GetKeyFrames();
size_t n = keyframes.Count();
bool found = false;
for (size_t i=0;i<n;i++) {
@ -1058,7 +1058,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &event) {
if (frame == curFrame) {
prev = frame;
if (i < n-1) next = keyframes[i+1];
else next = videoBox->videoDisplay->length;
else next = VideoContext::Get()->GetLength();
found = true;
break;
}
@ -1076,7 +1076,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &event) {
if (!found) {
if (n > 0) prev = keyframes[n-1];
else prev = 0;
next = videoBox->videoDisplay->length;
next = VideoContext::Get()->GetLength();
}
// Get times
@ -1102,7 +1102,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &event) {
//////////////////
// Shift to frame
void FrameMain::OnShiftToFrame (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
if (VideoContext::Get()->IsLoaded()) {
// Get selection
wxArrayInt sels = SubsBox->GetSelection();
size_t n=sels.Count();
@ -1111,7 +1111,7 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &event) {
// Get shifting in ms
AssDialogue *cur = SubsBox->GetDialogue(sels[0]);
if (!cur) return;
int shiftBy = VFR_Output.GetTimeAtFrame(videoBox->videoDisplay->frame_n,true) - cur->Start.GetMS();
int shiftBy = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true) - cur->Start.GetMS();
// Update
for (size_t i=0;i<n;i++) {
@ -1137,7 +1137,7 @@ void FrameMain::OnUndo(wxCommandEvent& WXUNUSED(event)) {
//wxWindow *focused = wxWindow::FindFocus();
//if (focused && focused->IsKindOf(CLASSINFO(wxTextCtrl))) return;
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
AssFile::StackPop();
SubsBox->LoadFromAss(AssFile::top,true);
AssFile::Popping = false;
@ -1147,7 +1147,7 @@ void FrameMain::OnUndo(wxCommandEvent& WXUNUSED(event)) {
////////
// Redo
void FrameMain::OnRedo(wxCommandEvent& WXUNUSED(event)) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
AssFile::StackRedo();
SubsBox->LoadFromAss(AssFile::top,true);
AssFile::Popping = false;
@ -1157,7 +1157,7 @@ void FrameMain::OnRedo(wxCommandEvent& WXUNUSED(event)) {
////////
// Find
void FrameMain::OnFind(wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
Search.OpenDialog(false);
}
@ -1165,7 +1165,7 @@ void FrameMain::OnFind(wxCommandEvent &event) {
/////////////
// Find next
void FrameMain::OnFindNext(wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
Search.FindNext();
}
@ -1173,7 +1173,7 @@ void FrameMain::OnFindNext(wxCommandEvent &event) {
//////////////////
// Find & replace
void FrameMain::OnReplace(wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
Search.OpenDialog(true);
}
@ -1181,7 +1181,7 @@ void FrameMain::OnReplace(wxCommandEvent &event) {
//////////////////////////////////
// Change aspect ratio to default
void FrameMain::OnSetARDefault (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->SetAspectRatio(0);
SetDisplayMode(-1);
}
@ -1190,7 +1190,7 @@ void FrameMain::OnSetARDefault (wxCommandEvent &event) {
/////////////////////////////////////
// Change aspect ratio to fullscreen
void FrameMain::OnSetARFull (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->SetAspectRatio(1);
SetDisplayMode(-1);
}
@ -1199,7 +1199,7 @@ void FrameMain::OnSetARFull (wxCommandEvent &event) {
/////////////////////////////////////
// Change aspect ratio to widescreen
void FrameMain::OnSetARWide (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->SetAspectRatio(2);
SetDisplayMode(-1);
}
@ -1208,7 +1208,7 @@ void FrameMain::OnSetARWide (wxCommandEvent &event) {
///////////////////////////////
// Change aspect ratio to 2:35
void FrameMain::OnSetAR235 (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
videoBox->videoDisplay->SetAspectRatio(3);
SetDisplayMode(-1);
}
@ -1218,7 +1218,7 @@ void FrameMain::OnSetAR235 (wxCommandEvent &event) {
// Change aspect ratio to a custom value
void FrameMain::OnSetARCustom (wxCommandEvent &event) {
// Get text
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
wxString value = wxGetTextFromUser(_("Enter aspect ratio in either decimal (e.g. 2.35) or fractional (e.g. 16:9) form. Enter a value like 853x480 to set a specific resolution."),_("Enter aspect ratio"),FloatToString(videoBox->videoDisplay->GetAspectRatioValue()));
if (value.IsEmpty()) return;
@ -1248,7 +1248,7 @@ void FrameMain::OnSetARCustom (wxCommandEvent &event) {
wxString denum = value.Mid(pos+1);
if (num.ToDouble(&a) && denum.ToDouble(&b) && b!=0) {
numval = a/b;
if (scale) videoBox->videoDisplay->SetZoom(b / videoBox->videoDisplay->h);
if (scale) videoBox->videoDisplay->SetZoom(b / VideoContext::Get()->GetHeight());
}
}
else numval = 0.0;
@ -1269,7 +1269,7 @@ void FrameMain::OnSetARCustom (wxCommandEvent &event) {
// Window is attempted to be closed
void FrameMain::OnCloseWindow (wxCloseEvent &event) {
// Stop audio and video
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
audioBox->audioDisplay->Stop();
// Ask user if he wants to save first
@ -1326,7 +1326,7 @@ void FrameMain::OnPasteOver (wxCommandEvent &event) {
////////////////////////
// Select visible lines
void FrameMain::OnSelectVisible (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
SubsBox->SelectVisible();
}
@ -1334,7 +1334,7 @@ void FrameMain::OnSelectVisible (wxCommandEvent &event) {
//////////////////////
// Open select dialog
void FrameMain::OnSelect (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogSelection select(this, SubsBox);
select.ShowModal();
}
@ -1365,7 +1365,7 @@ void FrameMain::OnSort (wxCommandEvent &event) {
//////////////////////////
// Open styling assistant
void FrameMain::OnOpenStylingAssistant (wxCommandEvent &event) {
videoBox->videoDisplay->Stop();
VideoContext::Get()->Stop();
DialogStyling styling(this,SubsBox);
styling.ShowModal();
}
@ -1557,7 +1557,7 @@ void FrameMain::OnChooseLanguage (wxCommandEvent &event) {
/////////////////
// View standard
void FrameMain::OnViewStandard (wxCommandEvent &event) {
if (!audioBox->audioDisplay->loaded || !videoBox->videoDisplay->loaded) return;
if (!audioBox->audioDisplay->loaded || !VideoContext::Get()->IsLoaded()) return;
SetDisplayMode(2);
}
@ -1565,7 +1565,7 @@ void FrameMain::OnViewStandard (wxCommandEvent &event) {
//////////////
// View video
void FrameMain::OnViewVideo (wxCommandEvent &event) {
if (!videoBox->videoDisplay->loaded) return;
if (!VideoContext::Get()->IsLoaded()) return;
SetDisplayMode(1);
}

224
aegisub/gl_wrap.cpp Normal file
View file

@ -0,0 +1,224 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include <GL/gl.h>
#include "gl_wrap.h"
/////////////
// Draw line
void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) {
SetModeLine();
glBegin(GL_LINES);
glVertex2f(x1,y1);
glVertex2f(x2,y2);
glEnd();
}
///////////////
// Draw circle
void OpenGLWrapper::DrawEllipse(float x,float y,float radiusX,float radiusY) {
DrawRing(x,y,radiusY,radiusY,radiusX/radiusY);
}
//////////////////
// Draw rectangle
void OpenGLWrapper::DrawRectangle(float x1,float y1,float x2,float y2) {
// Fill
if (a2 != 0.0) {
SetModeFill();
glBegin(GL_QUADS);
glVertex2f(x1,y1);
glVertex2f(x2,y1);
glVertex2f(x2,y2);
glVertex2f(x1,y2);
glEnd();
}
// Outline
if (a1 != 0.0) {
SetModeLine();
glBegin(GL_LINE_LOOP);
glVertex2f(x1,y1);
glVertex2f(x2,y1);
glVertex2f(x2,y2);
glVertex2f(x1,y2);
glEnd();
}
}
///////////////////////
// Draw ring (annulus)
void OpenGLWrapper::DrawRing(float x,float y,float r1,float r2,float ar,float arcStart,float arcEnd) {
// Make r1 bigger
if (r2 > r1) {
float temp = r1;
r1 = r2;
r2 = temp;
}
// Arc range
bool hasEnds = arcStart != arcEnd;
float pi = 3.1415926535897932384626433832795f;
arcEnd *= pi / 180.f;
arcStart *= pi / 180.f;
if (arcEnd <= arcStart) arcEnd += 2.0f*pi;
float range = arcEnd - arcStart;
// Math
int steps = int((r1 + r1*ar) * range / (2.0f*pi))*4;
if (steps < 12) steps = 12;
float end = arcEnd;
float step = range/steps;
float curAngle = arcStart;
// Fill
if (a2 != 0.0) {
SetModeFill();
// Annulus
if (r1 != r2) {
glBegin(GL_QUADS);
for (int i=0;i<steps;i++) {
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
curAngle += step;
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
}
glEnd();
}
// Circle
else {
glBegin(GL_POLYGON);
for (int i=0;i<steps;i++) {
glVertex2f(x+sin(curAngle)*r1,y+cos(curAngle)*r1);
curAngle += step;
}
glEnd();
}
// Reset angle
curAngle = arcStart;
}
// Outlines
if (a1 != 0.0) {
// Outer
steps++;
SetModeLine();
glBegin(GL_LINE_STRIP);
for (int i=0;i<steps;i++) {
glVertex2f(x+sin(curAngle)*r1,y+cos(curAngle)*r1);
curAngle += step;
}
glEnd();
// Inner
if (r1 != r2) {
curAngle = arcStart;
glBegin(GL_LINE_STRIP);
for (int i=0;i<steps;i++) {
glVertex2f(x+sin(curAngle)*r2,y+cos(curAngle)*r2);
curAngle += step;
}
glEnd();
// End caps
if (hasEnds) {
glBegin(GL_LINES);
glVertex2f(x+sin(arcStart)*r1,y+cos(arcStart)*r1);
glVertex2f(x+sin(arcStart)*r2,y+cos(arcStart)*r2);
glVertex2f(x+sin(arcEnd)*r1,y+cos(arcEnd)*r1);
glVertex2f(x+sin(arcEnd)*r2,y+cos(arcEnd)*r2);
glEnd();
}
}
}
}
///////////////////
// Set line colour
void OpenGLWrapper::SetLineColour(wxColour col,float alpha,int width) {
r1 = col.Red()/255.0f;
g1 = col.Green()/255.0f;
b1 = col.Blue()/255.0f;
a1 = alpha;
lw = width;
}
///////////////////
// Set fill colour
void OpenGLWrapper::SetFillColour(wxColour col,float alpha) {
r2 = col.Red()/255.0f;
g2 = col.Green()/255.0f;
b2 = col.Blue()/255.0f;
a2 = alpha;
}
////////
// Line
void OpenGLWrapper::SetModeLine() {
glColor4f(r1,g1,b1,a1);
if (a1 == 1.0f) glDisable(GL_BLEND);
else {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
glLineWidth(lw);
//glEnable(GL_LINE_SMOOTH);
}
////////
// Fill
void OpenGLWrapper::SetModeFill() {
glColor4f(r2,g2,b2,a2);
if (a2 == 1.0f) glDisable(GL_BLEND);
else {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
}

58
aegisub/gl_wrap.h Normal file
View file

@ -0,0 +1,58 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
//////////////////
// OpenGL Wrapper
class OpenGLWrapper {
private:
float r1,g1,b1,a1;
float r2,g2,b2,a2;
int lw;
public:
void SetLineColour(wxColour col,float alpha=1.0f,int width=1);
void SetFillColour(wxColour col,float alpha=1.0f);
void SetModeLine();
void SetModeFill();
void DrawLine(float x1,float y1,float x2,float y2);
void DrawEllipse(float x,float y,float radiusX,float radiusY);
void DrawCircle(float x,float y,float radius) { DrawEllipse(x,y,radius,radius); }
void DrawRectangle(float x1,float y1,float x2,float y2);
void DrawRing(float x,float y,float r1,float r2,float ar=1.0f,float arcStart=0.0f,float arcEnd=0.0f);
};

View file

@ -56,6 +56,7 @@
#include "subs_grid.h"
#include "auto4_base.h"
#include "subtitle_format.h"
#include "video_context.h"
///////////////////
@ -140,6 +141,7 @@ bool AegisubApp::OnInit() {
// Exit
int AegisubApp::OnExit() {
SubtitleFormat::DestroyFormats();
VideoContext::Clear();
Options.Clear();
delete global_scripts;
return wxApp::OnExit();

View file

@ -147,7 +147,7 @@ void OptionsManager::LoadDefaults() {
SetModificationType(MOD_AUTOMATIC);
SetBool(_T("Allow Ancient Avisynth"),false);
SetText(_T("Video Provider"),_T("Avisynth"));
SetText(_T("Video resizer"),_T("BilinearResize"));
SetText(_T("Subtitles Provider"),_T("CSRI"));
// Audio Options
SetBool(_T("Audio Next Line on Commit"),true);
@ -291,7 +291,7 @@ void OptionsManager::LoadDefaults() {
SetBool(_T("Audio Spectrum"),false);
SetInt(_T("Audio Sample Rate"),0);
SetBool(_T("Video Visual Realtime"),false);
SetBool(_T("Video Visual Realtime"),true);
SetInt(_T("Timing processor key start before thres"),5);
SetInt(_T("Timing processor key start after thres"),4);

View file

@ -63,6 +63,7 @@
#pragma comment(lib, "wxmsw28ud_media.lib")
#pragma comment(lib, "wxmsw28ud_core.lib")
#pragma comment(lib, "wxmsw28ud_adv.lib")
#pragma comment(lib, "wxmsw28ud_gl.lib")
#else
#pragma comment(lib, "wxregexu.lib")
#pragma comment(lib, "wxbase28u.lib")
@ -70,6 +71,7 @@
#pragma comment(lib, "wxmsw28u_media.lib")
#pragma comment(lib, "wxmsw28u_core.lib")
#pragma comment(lib, "wxmsw28u_adv.lib")
#pragma comment(lib, "wxmsw28u_gl.lib")
#endif
#else
@ -135,6 +137,17 @@
#endif
//////////////
// DirectShow
#if USE_DIRECTSHOW == 1
#ifdef __WXDEBUG__
#pragma comment(lib, "strmbasdu.lib")
#else
#pragma comment(lib, "strmbaseu.lib")
#endif
#endif
/////////////
// PortAudio
#if USE_PORTAUDIO == 1

View file

@ -78,6 +78,7 @@
#include <wx/event.h>
#include <wx/wxscintilla.h>
#include <wx/string.h>
#include <wx/glcanvas.h>
///////////////

View file

@ -267,7 +267,7 @@ void SubsEditBox::Update (bool timeOnly,bool weak) {
if (!weak) audio->SetDialogue(grid,curdiag,linen);
// Video
video->curLine = curdiag;
VideoContext::Get()->curLine = curdiag;
video->UpdateSubsRelativeTime();
}
else enabled = false;
@ -329,15 +329,15 @@ void SubsEditBox::SetToLine(int n,bool weak) {
Update();
// Set video
if (video->loaded && !weak) {
if (VideoContext::Get()->IsLoaded() && !weak) {
wxString sync;
if (Search.hasFocus) sync = _T("Find update video");
else sync = _T("Sync video with subs");
if (Options.AsBool(sync) == true) {
video->Stop();
VideoContext::Get()->Stop();
AssDialogue *cur = grid->GetDialogue(n);
if (cur) video->JumpToFrame(VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true));
if (cur) VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true));
}
}
}

View file

@ -148,13 +148,13 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
state = (sels == 1);
menu.Append(MENU_INSERT_BEFORE,_("&Insert (before)"),_T("Inserts a line before current"))->Enable(state);
menu.Append(MENU_INSERT_AFTER,_("Insert (after)"),_T("Inserts a line after current"))->Enable(state);
state = (sels == 1 && video && video->loaded);
state = (sels == 1 && video && VideoContext::Get()->IsLoaded());
menu.Append(MENU_INSERT_BEFORE_VIDEO,_("Insert at video time (before)"),_T("Inserts a line after current, starting at video time"))->Enable(state);
menu.Append(MENU_INSERT_AFTER_VIDEO,_("Insert at video time (after)"),_T("Inserts a line after current, starting at video time"))->Enable(state);
menu.AppendSeparator();
// Video/time sync
//state = (video && video->loaded);
//state = (video && VideoContext::Get()->IsLoaded());
//menu.Append(MENU_SET_VIDEO_TO_START,_("Jump video to start"),_T("Sets current video time to start time"))->Enable(state);
//menu.Append(MENU_SET_VIDEO_TO_END,_("Jump video to end"),_T("Sets current video time to end time"))->Enable(state);
//menu.Append(MENU_SET_START_TO_VIDEO,_("Set start to video"),_T("Sets start times to current video time"))->Enable(state);
@ -467,7 +467,7 @@ void SubtitlesGrid::OnInsertBeforeVideo (wxCommandEvent &event) {
// Create line to add
AssDialogue *def = new AssDialogue;
int video_ms = VFR_Output.GetTimeAtFrame(video->frame_n,true);
int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true);
def->Start.SetMS(video_ms);
def->End.SetMS(video_ms+5000);
def->Style = GetDialogue(n)->Style;
@ -489,7 +489,7 @@ void SubtitlesGrid::OnInsertAfterVideo (wxCommandEvent &event) {
// Create line to add
AssDialogue *def = new AssDialogue;
int video_ms = VFR_Output.GetTimeAtFrame(video->frame_n,true);
int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true);
def->Start.SetMS(video_ms);
def->End.SetMS(video_ms+5000);
def->Style = GetDialogue(n)->Style;
@ -1336,23 +1336,23 @@ void SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
// --------------
// This will save the work .ass and refresh it
void SubtitlesGrid::CommitChanges(bool force,bool videoOnly) {
if (video->loaded || force) {
if (VideoContext::Get()->IsLoaded() || force) {
// Check if it's playing
bool playing = false;
if (video->IsPlaying) {
if (VideoContext::Get()->IsPlaying()) {
playing = true;
video->Stop();
VideoContext::Get()->Stop();
}
// Export
wxString workfile = video->GetTempWorkFile();
ass->Export(workfile);
//wxString workfile = VideoContext::Get()->GetTempWorkFile();
//ass->Export(workfile);
if (video->loaded)
video->RefreshSubtitles();
// Update video
if (VideoContext::Get()->IsLoaded()) VideoContext::Get()->Refresh(false,true);
// Resume play
if (playing) video->Play();
if (playing) VideoContext::Get()->Play();
}
if (!videoOnly) {
@ -1376,7 +1376,7 @@ void SubtitlesGrid::SetSubsToVideo(bool start) {
if (!VFR_Output.IsLoaded()) return;
// Get new time
int ms = VFR_Output.GetTimeAtFrame(video->frame_n,start);
int ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),start);
// Update selection
wxArrayInt sel = GetSelection();
@ -1409,9 +1409,9 @@ void SubtitlesGrid::SetVideoToSubs(bool start) {
AssDialogue *cur = GetDialogue(sel[0]);
if (cur) {
if (start)
video->JumpToFrame(VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true));
VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true));
else
video->JumpToFrame(VFR_Output.GetFrameAtTime(cur->End.GetMS(),false));
VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(cur->End.GetMS(),false));
}
}

View file

@ -93,7 +93,7 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
#ifdef __WINDOWS__
// Video loaded?
VideoDisplay *display = ((AegisubApp*)wxTheApp)->frame->videoBox->videoDisplay;
if (!display->loaded) throw _T("Video not loaded!");
if (VideoContext::Get()->IsLoaded()) throw _T("Video not loaded!");
// Create the PRS file
PRSFile file;
@ -110,7 +110,7 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
IScriptEnvironment *env2 = avs2.GetEnv();
// Prepare the Avisynth environments, that is, generate blank clips and hardsub into them
wxString val = wxString::Format(_T("BlankClip(pixel_type=\"RGB32\",length=%i,width=%i,height=%i,fps=%f"),display->provider->GetFrameCount(),display->provider->GetSourceWidth(),display->provider->GetSourceHeight(),display->provider->GetFPS());
wxString val = wxString::Format(_T("BlankClip(pixel_type=\"RGB32\",length=%i,width=%i,height=%i,fps=%f"),VideoContext::Get()->GetLength(),VideoContext::Get()->GetWidth(),VideoContext::Get()->GetHeight(),VideoContext::Get()->GetFPS());
AVSValue script1 = env1->Invoke("Eval",AVSValue(wxString(val + _T(",color=$000000)")).mb_str(wxConvUTF8)));
AVSValue script2 = env2->Invoke("Eval",AVSValue(wxString(val + _T(",color=$FFFFFF)")).mb_str(wxConvUTF8)));
char temp[512];

View file

@ -36,8 +36,8 @@
///////////
// Headers
#include "setup.h"
#ifdef HAVE_ASA
#include <wx/wxprec.h>
#include <wx/image.h>
#include "subtitle_provider.h"

View file

@ -0,0 +1,84 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "subtitles_provider.h"
#include "options.h"
//////////////
// Destructor
SubtitlesProvider::~SubtitlesProvider() {
}
////////////////
// Get provider
SubtitlesProvider* SubtitlesProviderFactory::GetProvider() {
// List of providers
wxArrayString list = GetFactoryList();
// None available
if (list.Count() == 0) throw _T("No video providers are available.");
// Put preffered on top
wxString preffered = Options.AsText(_T("Subtitles provider")).Lower();
if (list.Index(preffered) != wxNOT_FOUND) {
list.Remove(preffered);
list.Insert(preffered,0);
}
// Get provider
wxString error;
for (unsigned int i=0;i<list.Count();i++) {
try {
SubtitlesProvider *provider = GetFactory(list[i])->CreateProvider();
if (provider) return provider;
}
catch (wxString err) { error += list[i] + _T(" factory: ") + err + _T("\n"); }
catch (const wxChar *err) { error += list[i] + _T(" factory: ") + wxString(err) + _T("\n"); }
catch (...) { error += list[i] + _T(" factory: Unknown error\n"); }
}
// Failed
throw error;
}
//////////
// Static
std::map<wxString,SubtitlesProviderFactory*>* AegisubFactory<SubtitlesProviderFactory>::factories=NULL;

View file

@ -1,4 +1,4 @@
// Copyright (c) 2006, David Lamparter
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -37,51 +37,39 @@
#pragma once
#include <map>
///////////
// Headers
#include <wx/wxprec.h>
#include "video_frame.h"
#include "factory.h"
class VideoProvider;
//////////////
// Prototypes
class AssFile;
/////////////////////////////////////////
// Subtitle provider (renderer) interface
class SubtitleProvider {
////////////////////////////////
// Subtitles provider interface
class SubtitlesProvider {
public:
// Video overlay interface. Renderers MAY implement it,
// but do not need to. VideoProvider::SetOverlay takes it.
class Overlay {
public:
virtual void SetParams(int width, int height) = 0;
virtual void Render(wxImage &frame, int ms) = 0;
virtual void Unbind() = 0; // Called when VideoProvider is destroyed
virtual ~Overlay() { };
};
virtual ~SubtitlesProvider();
// Renderer Class. Manages the different types of renderers.
// Derivate a class off it, override its Get method and its constructor,
// and create one single instance of it for your renderer,
// as a static element in your SubtitleProvider derivated class. Example:
// class MyFancyRenderer : public SubtitleProvider {
// class MyClass : public Class { public:
// MyClass() : Class("FancyRenderer") { };
// virtual SubtitleProvider *Get(AssFile *subs) { return new MyFancyRenderer(subs); };
// };
// static MyClass me;
// };
class Class {
private:
static std::map<wxString, SubtitleProvider::Class *> *classes;
virtual bool CanRaster() { return false; }
public:
Class(wxString name);
virtual SubtitleProvider *Get(AssFile *subs) = 0;
virtual ~Class() {};
static SubtitleProvider *GetProvider(wxString provider_name, AssFile *subs);
};
virtual ~SubtitleProvider() { };
virtual void Bind(VideoProvider *vpro) = 0;
virtual void LoadSubtitles(AssFile *subs)=0;
virtual void DrawSubtitles(AegiVideoFrame &dst,double time) {}
};
///////////
// Factory
class SubtitlesProviderFactory : public AegisubFactory<SubtitlesProviderFactory> {
protected:
virtual SubtitlesProvider *CreateProvider()=0;
SubtitlesProviderFactory(wxString name) { RegisterFactory(name); }
public:
virtual ~SubtitlesProviderFactory() {}
static SubtitlesProvider *GetProvider();
};

View file

@ -0,0 +1,124 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "subtitles_provider_csri.h"
#include "ass_file.h"
#include "video_context.h"
#if __VISUALC__ >= 1200
#pragma comment(lib,"asa.lib")
#endif
///////////
// Factory
class CSRISubtitlesProviderFactory : public SubtitlesProviderFactory {
public:
SubtitlesProvider *CreateProvider() { return new CSRISubtitlesProvider(); }
CSRISubtitlesProviderFactory() : SubtitlesProviderFactory(_T("csri")) {}
} registerCSRI;
///////////////
// Constructor
CSRISubtitlesProvider::CSRISubtitlesProvider() {
instance = NULL;
}
//////////////
// Destructor
CSRISubtitlesProvider::~CSRISubtitlesProvider() {
if (instance) csri_close(instance);
instance = NULL;
}
//////////////////
// Load subtitles
void CSRISubtitlesProvider::LoadSubtitles(AssFile *subs) {
// Close
// HACK: REMOVE THE FOLLOWING LINE
if (instance) return;
if (instance) csri_close(instance);
instance = NULL;
// Prepare subtitles
wxString subsfilename = VideoContext::Get()->GetTempWorkFile();
subs->Save(subsfilename,false,false,_T("UTF-8"));
delete subs;
// Open
instance = csri_open_file(csri_renderer_default(),subsfilename.mb_str(wxConvUTF8),NULL);
}
//////////////////
// Draw subtitles
void CSRISubtitlesProvider::DrawSubtitles(AegiVideoFrame &dst,double time) {
// Check if CSRI loaded properly
if (!instance) return;
// Load data into frame
csri_frame frame;
for (int i=0;i<4;i++) {
if (dst.flipped) {
frame.planes[i] = dst.data[i] + (dst.h-1) * dst.pitch[i];
frame.strides[i] = -(signed)dst.pitch[i];
}
else {
frame.planes[i] = dst.data[i];
frame.strides[i] = dst.pitch[i];
}
}
switch (dst.format) {
case FORMAT_RGB32: frame.pixfmt = CSRI_F_BGR_; break;
case FORMAT_RGB24: frame.pixfmt = CSRI_F_BGR; break;
}
// Set format
csri_fmt format;
format.width = dst.w;
format.height = dst.h;
format.pixfmt = frame.pixfmt;
int error = csri_query_fmt(instance,&format);
if (error) return;
// Render
csri_render(instance,&frame,time);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2006, David Lamparter
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -34,28 +34,29 @@
//
#pragma once
///////////
// Headers
#include "subtitle_provider.h"
#include "subtitles_provider.h"
#define CSRIAPI __declspec(dllexport)
#include "csri/csri.h"
#include "csri/loader.h"
std::map<wxString, SubtitleProvider::Class *> *SubtitleProvider::Class::classes = NULL;
/////////////////////////////////////////////////
// Common Subtitles Rendering Interface provider
class CSRISubtitlesProvider : public SubtitlesProvider {
private:
csri_inst *instance;
SubtitleProvider::Class::Class(wxString name)
{
if (!classes)
classes = new std::map<wxString, SubtitleProvider::Class *>();
(*classes)[name] = this;
}
public:
CSRISubtitlesProvider();
~CSRISubtitlesProvider();
SubtitleProvider *SubtitleProvider::Class::GetProvider(wxString provider_name, AssFile *subs)
{
SubtitleProvider::Class *sp;
if (!classes)
throw _T("Subtitle provider not found");
sp = (*classes)[provider_name];
if (!sp)
throw _T("Subtitle provider not found");
return sp->Get(subs);
}
bool CanRaster() { return true; }
void LoadSubtitles(AssFile *subs);
void DrawSubtitles(AegiVideoFrame &dst,double time);
};

View file

@ -192,3 +192,18 @@ void AppendBitmapMenuItem (wxMenu* parentMenu,int id,wxString text,wxString help
cur->SetBitmap(bmp);
parentMenu->Append(cur);
}
///////////////////////////////////////////////////////////////
// Get the smallest power of two that is greater or equal to x
// Code from http://bob.allegronetwork.com/prog/tricks.html
int SmallestPowerOf2(int x) {
x--;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x++;
return x;
}

View file

@ -34,6 +34,9 @@
//
#pragma once;
///////////////////////
// Function prototypes
#ifndef __LINUX__
@ -49,6 +52,16 @@ wxString FloatToString(double value);
wxString IntegerToString(int value);
wxString PrettySize(int bytes);
void AppendBitmapMenuItem (wxMenu* parentMenu,int id,wxString text,wxString help,wxBitmap bmp);
int SmallestPowerOf2(int x);
///////////
// Inlines
inline void IntSwap(int &a,int &b) {
int c = a;
a = b;
b = c;
}
//////////
@ -62,5 +75,5 @@ void AppendBitmapMenuItem (wxMenu* parentMenu,int id,wxString text,wxString help
#endif
#ifndef MID
#define MID(a,b,c) MAX(a,MIN(b,c))
#define MID(a,b,c) MAX((a),MIN((b),(c)))
#endif

View file

@ -44,6 +44,7 @@
#include "video_box.h"
#include "video_display.h"
#include "video_display_visual.h"
#include "video_display_fextracker.h"
#include "video_zoom.h"
#include "video_slider.h"
#include "frame_main.h"
@ -56,11 +57,6 @@
#include "ass_dialogue.h"
#include "vfr.h"
#include "subs_edit_box.h"
#include "../FexTrackerSource/FexTracker.h"
#include "../FexTrackerSource/FexTrackingFeature.h"
#include "../FexTrackerSource/FexMovement.h"
#include "dialog_progress.h"
#include "dialog_fextracker.h"
#include "utils.h"
#include "main.h"
#include "toggle_bitmap.h"
@ -88,9 +84,9 @@ VideoBox::VideoBox(wxWindow *parent)
// Fextracker
#if USE_FEXTRACKER == 1
wxBitmapButton *VideoTrackerMenuButton = new wxBitmapButton(videoPage,Video_Tracker_Menu,wxBITMAP(button_track_points),wxDefaultPosition,wxSize(25,-1));
wxBitmapButton *VideoTrackerMenuButton = new wxBitmapButton(videoPage,Video_Tracker_Menu,wxBITMAP(button_track_points));
VideoTrackerMenuButton->SetToolTip(_("FexTracker"));
wxBitmapButton *VideoTrackerMenu2Button = new wxBitmapButton(videoPage,Video_Tracker_Menu2,wxBITMAP(button_track_trail),wxDefaultPosition,wxSize(25,-1));
wxBitmapButton *VideoTrackerMenu2Button = new wxBitmapButton(videoPage,Video_Tracker_Menu2,wxBITMAP(button_track_trail));
VideoTrackerMenu2Button->SetToolTip(_("FexMovement"));
#endif
@ -112,6 +108,7 @@ VideoBox::VideoBox(wxWindow *parent)
videoDisplay->PositionDisplay = VideoPosition;
videoDisplay->SubsPosition = VideoSubsPos;
videoDisplay->box = this;
VideoContext::Get()->AddDisplay(videoDisplay);
videoDisplay->Reset();
// Set display
@ -142,6 +139,11 @@ VideoBox::VideoBox(wxWindow *parent)
typeSizer->Add(scale,0,wxEXPAND,0);
typeSizer->Add(clip,0,wxEXPAND | wxBOTTOM,5);
typeSizer->Add(realtime,0,wxEXPAND,0);
#if USE_FEXTRACKER == 1
typeSizer->Add(new wxStaticLine(videoPage),0,wxEXPAND|wxBOTTOM|wxTOP,5);
typeSizer->Add(VideoTrackerMenuButton,0,wxEXPAND,0);
typeSizer->Add(VideoTrackerMenu2Button,0,wxEXPAND,0);
#endif
typeSizer->AddStretchSpacer(1);
// Top sizer
@ -158,10 +160,6 @@ VideoBox::VideoBox(wxWindow *parent)
videoBottomSizer->Add(VideoPlayLineButton,0,wxTOP|wxBOTTOM|wxALIGN_CENTER,2);
videoBottomSizer->Add(VideoStopButton,0,wxTOP|wxBOTTOM|wxALIGN_CENTER,2);
videoBottomSizer->Add(AutoScroll,0,wxTOP|wxBOTTOM|wxALIGN_CENTER|wxEXPAND,2);
#if USE_FEXTRACKER == 1
videoBottomSizer->Add(VideoTrackerMenuButton,0,wxTOP|wxBOTTOM|wxALIGN_CENTER|wxEXPAND,2);
videoBottomSizer->Add(VideoTrackerMenu2Button,0,wxTOP|wxBOTTOM|wxALIGN_CENTER|wxEXPAND,2);
#endif
videoBottomSizer->Add(VideoPosition,1,wxLEFT|wxALIGN_CENTER,5);
videoBottomSizer->Add(VideoSubsPos,1,wxALIGN_CENTER,0);
VideoSizer = new wxBoxSizer(wxVERTICAL);
@ -190,18 +188,8 @@ BEGIN_EVENT_TABLE(VideoBox, wxPanel)
#if USE_FEXTRACKER == 1
EVT_BUTTON(Video_Tracker_Menu, VideoBox::OnVideoTrackerMenu)
EVT_MENU(Video_Track_Points, VideoBox::OnVideoTrackPoints)
EVT_MENU(Video_Track_Point_Add, VideoBox::OnVideoTrackPointAdd)
EVT_MENU(Video_Track_Point_Del, VideoBox::OnVideoTrackPointDel)
EVT_MENU(Video_Track_Movement, VideoBox::OnVideoTrackMovement)
EVT_BUTTON(Video_Tracker_Menu2, VideoBox::OnVideoTrackerMenu2)
EVT_MENU(Video_Track_Movement_MoveAll, VideoBox::OnVideoTrackMovementMoveAll)
EVT_MENU(Video_Track_Movement_MoveOne, VideoBox::OnVideoTrackMovementMoveOne)
EVT_MENU(Video_Track_Movement_MoveBefore, VideoBox::OnVideoTrackMovementMoveBefore)
EVT_MENU(Video_Track_Movement_MoveAfter, VideoBox::OnVideoTrackMovementMoveAfter)
EVT_MENU(Video_Track_Split_Line, VideoBox::OnVideoTrackSplitLine)
EVT_MENU(Video_Track_Link_File, VideoBox::OnVideoTrackLinkFile)
EVT_MENU(Video_Track_Movement_Empty, VideoBox::OnVideoTrackMovementEmpty)
EVT_MENU_RANGE(Video_Tracker_START,Video_Tracker_END, VideoBox::OnTrackerOption)
#endif
END_EVENT_TABLE()
@ -209,21 +197,21 @@ END_EVENT_TABLE()
//////////////
// Play video
void VideoBox::OnVideoPlay(wxCommandEvent &event) {
videoDisplay->Play();
VideoContext::Get()->Play();
}
///////////////////
// Play video line
void VideoBox::OnVideoPlayLine(wxCommandEvent &event) {
videoDisplay->PlayLine();
VideoContext::Get()->PlayLine();
}
//////////////
// Stop video
void VideoBox::OnVideoStop(wxCommandEvent &event) {
videoDisplay->Stop();
VideoContext::Get()->Stop();
}
@ -286,8 +274,6 @@ void VideoBox::OnToggleRealtime(wxCommandEvent &event) {
/////////////////////// HERE BE DRAGONS //////////////////////////////
#if USE_FEXTRACKER == 1
///////////////////
// Tracker Menu
@ -321,228 +307,11 @@ void VideoBox::OnVideoTrackerMenu2(wxCommandEvent &event) {
PopupMenu(&menu);
}
///////////////////
// Track current line
void VideoBox::OnVideoTrackPoints(wxCommandEvent &event) {
videoDisplay->Stop();
// Get line
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
FexTrackerConfig config;
DialogFexTracker configDlg( this, &config );
configDlg.ShowModal();
if( !config.FeatureNumber ) return;
// Get Video
VideoProvider *movie = VideoProvider::GetProvider(videoDisplay->videoName, wxString(_T("")));
// Create Tracker
if( curline->Tracker ) delete curline->Tracker;
curline->Tracker = new FexTracker( movie->GetWidth(), movie->GetHeight(), config.FeatureNumber );
curline->Tracker->minFeatures = config.FeatureNumber;
curline->Tracker->Cfg = config;
// Start progress
volatile bool canceled = false;
DialogProgress *progress = new DialogProgress(this,_("FexTracker"),&canceled,_("Tracking points"),0,1);
progress->Show();
// Allocate temp image
float* FloatImg = new float[ movie->GetWidth()*movie->GetHeight() ];
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
for( int Frame = StartFrame; Frame <= EndFrame; Frame ++ )
{
progress->SetProgress( Frame-StartFrame, EndFrame-StartFrame );
if( canceled ) break;
movie->GetFloatFrame( FloatImg, Frame );
curline->Tracker->ProcessImage( FloatImg );
}
delete FloatImg;
delete movie;
// Clean up progress
if (!canceled)
progress->Destroy();
else
{
delete curline->Tracker;
curline->Tracker = 0;
}
videoDisplay->RefreshVideo();
}
///////////////////
// Track current line
void VideoBox::OnVideoTrackMovement(wxCommandEvent &event) {
videoDisplay->Stop();
// Get line
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( !curline->Tracker ) return;
// Create Movement
if( curline->Movement ) DeleteMovement( curline->Movement );
curline->Movement = curline->Tracker->GetMovement();
videoDisplay->RefreshVideo();
}
///////////////////
// split current line
void VideoBox::OnVideoTrackSplitLine(wxCommandEvent &event) {
videoDisplay->Stop();
// Get line
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( !curline->Movement ) return;
// Create split lines
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
AssFile *subs = AssFile::top;
int ResXValue,ResYValue;
swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue );
swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue );
int SrcXValue = videoDisplay->provider->GetSourceWidth();
int SrcYValue = videoDisplay->provider->GetSourceHeight();
float sx = float(ResXValue)/float(SrcXValue);
float sy = float(ResYValue)/float(SrcYValue);
for( int Frame = StartFrame; Frame < EndFrame; Frame ++ )
{
int localframe = Frame - StartFrame;
while( curline->Movement->Frames.size() <= localframe ) localframe--;
FexMovementFrame f = curline->Movement->Frames[localframe];
// f.Pos.x /= videoDisplay->GetW
AssDialogue *cur = new AssDialogue( curline->GetEntryData() );
cur->Start.SetMS(VFR_Output.GetTimeAtFrame(Frame,true));
cur->End.SetMS(VFR_Output.GetTimeAtFrame(Frame,false));
cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text;
cur->UpdateData();
frame->SubsBox->InsertLine(cur,frame->EditBox->linen + Frame - StartFrame,true,false);
}
// Remove Movement
DeleteMovement( curline->Movement );
curline->Movement = 0;
// Remove Tracker
delete curline->Tracker;
curline->Tracker = 0;
// Remove this line
frame->SubsBox->DeleteLines(frame->SubsBox->GetRangeArray(frame->EditBox->linen, frame->EditBox->linen));
videoDisplay->RefreshVideo();
}
///////////////////
// generate empty movement
void VideoBox::OnVideoTrackMovementEmpty(wxCommandEvent &event) {
// Get line
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( curline->Movement ) DeleteMovement( curline->Movement );
curline->Movement = CreateMovement();
// Create split lines
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
FexMovementFrame f;
memset( &f, 0x00, sizeof(f) );
f.Scale.x = f.Scale.y = 1;
for( int i=StartFrame;i<EndFrame;i++ )
curline->Movement->Frames.Add( f );
}
///////////////////
// link line to move file
void VideoBox::OnVideoTrackLinkFile(wxCommandEvent &event) {
videoDisplay->Stop();
// Get line
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
wxString link = wxGetTextFromUser(_("Link name:"), _("Link line to movement file"), curline->Movement?curline->Movement->FileName:_T(""), this);
if( link.empty() ) curline->Effect = _T("");
else curline->Effect = _T("FexMovement:")+link;
curline->UpdateData();
if( !curline->Effect.empty() && curline->Movement )
SaveMovement( curline->Movement, curline->Effect.AfterFirst(':').c_str() );
}
///////////////////
// Increase Influence
void VideoBox::OnVideoTrackPointAdd(wxCommandEvent &event) {
videoDisplay->TrackerEdit = 1;
videoDisplay->bTrackerEditing = 0;
}
///////////////////
// Decrease Influence
void VideoBox::OnVideoTrackPointDel(wxCommandEvent &event) {
videoDisplay->TrackerEdit = -1;
videoDisplay->bTrackerEditing = 0;
}
///////////////////
// Move All
void VideoBox::OnVideoTrackMovementMoveAll(wxCommandEvent &event) {
videoDisplay->MovementEdit = 1;
videoDisplay->bTrackerEditing = 0;
}
///////////////////
// Move One
void VideoBox::OnVideoTrackMovementMoveOne(wxCommandEvent &event) {
videoDisplay->MovementEdit = 2;
videoDisplay->bTrackerEditing = 0;
}
///////////////////
// Move Before
void VideoBox::OnVideoTrackMovementMoveBefore(wxCommandEvent &event) {
videoDisplay->MovementEdit = 3;
videoDisplay->bTrackerEditing = 0;
}
///////////////////
// Move After
void VideoBox::OnVideoTrackMovementMoveAfter(wxCommandEvent &event) {
videoDisplay->MovementEdit = 4;
videoDisplay->bTrackerEditing = 0;
////////////////////
// Forward options
void VideoBox::OnTrackerOption(wxCommandEvent &event) {
videoDisplay->tracker->AddPendingEvent(event);
}
#endif

View file

@ -69,6 +69,10 @@ private:
void OnVideoStop(wxCommandEvent &event);
void OnVideoToggleScroll(wxCommandEvent &event);
void OnVideoTrackerMenu(wxCommandEvent &event);
void OnVideoTrackerMenu2(wxCommandEvent &event);
void OnTrackerOption(wxCommandEvent &event);
void OnModeStandard(wxCommandEvent &event);
void OnModeDrag(wxCommandEvent &event);
void OnModeRotateZ(wxCommandEvent &event);
@ -77,20 +81,6 @@ private:
void OnModeClip(wxCommandEvent &event);
void OnToggleRealtime(wxCommandEvent &event);
void OnVideoTrackerMenu(wxCommandEvent &event);
void OnVideoTrackPoints(wxCommandEvent &event);
void OnVideoTrackPointAdd(wxCommandEvent &event);
void OnVideoTrackPointDel(wxCommandEvent &event);
void OnVideoTrackerMenu2(wxCommandEvent &event);
void OnVideoTrackMovement(wxCommandEvent &event);
void OnVideoTrackMovementMoveAll(wxCommandEvent &event);
void OnVideoTrackMovementMoveOne(wxCommandEvent &event);
void OnVideoTrackMovementMoveBefore(wxCommandEvent &event);
void OnVideoTrackMovementMoveAfter(wxCommandEvent &event);
void OnVideoTrackSplitLine(wxCommandEvent &event);
void OnVideoTrackLinkFile(wxCommandEvent &event);
void OnVideoTrackMovementEmpty(wxCommandEvent &event);
public:
ToggleBitmap *AutoScroll;
wxBoxSizer *VideoSizer;
@ -116,11 +106,20 @@ enum {
Video_Stop,
Video_Auto_Scroll,
Video_Mode_Standard,
Video_Mode_Drag,
Video_Mode_Rotate_Z,
Video_Mode_Rotate_XY,
Video_Mode_Scale,
Video_Mode_Clip,
Video_Mode_Realtime,
Video_Tracker_Menu,
Video_Tracker_Menu2,
Video_Tracker_START = 1000,
Video_Track_Points,
Video_Track_Point_Add,
Video_Track_Point_Del,
Video_Tracker_Menu2,
Video_Track_Movement,
Video_Track_Movement_MoveAll,
Video_Track_Movement_MoveOne,
@ -129,14 +128,7 @@ enum {
Video_Track_Split_Line,
Video_Track_Link_File,
Video_Track_Movement_Empty,
Video_Mode_Standard,
Video_Mode_Drag,
Video_Mode_Rotate_Z,
Video_Mode_Rotate_XY,
Video_Mode_Scale,
Video_Mode_Clip,
Video_Mode_Realtime
Video_Tracker_END
};
#endif

670
aegisub/video_context.cpp Normal file
View file

@ -0,0 +1,670 @@
// Copyright (c) 2005-2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
////////////
// Includes
#include "setup.h"
#include <wx/image.h>
#include <string.h>
#include <wx/clipbrd.h>
#include <wx/filename.h>
#include <wx/config.h>
#include "utils.h"
#include "video_display.h"
#include "video_context.h"
#include "video_provider.h"
#include "subtitles_provider.h"
#include "vfr.h"
#include "ass_file.h"
#include "ass_exporter.h"
#include "ass_time.h"
#include "ass_dialogue.h"
#include "ass_style.h"
#include "subs_grid.h"
#include "vfw_wrap.h"
#include "mkv_wrap.h"
#include "options.h"
#include "subs_edit_box.h"
#include "audio_display.h"
#include "main.h"
#include "video_slider.h"
#include "video_box.h"
#include "utils.h"
///////
// IDs
enum {
VIDEO_PLAY_TIMER = 1300
};
///////////////
// Event table
BEGIN_EVENT_TABLE(VideoContext, wxEvtHandler)
EVT_TIMER(VIDEO_PLAY_TIMER,VideoContext::OnPlayTimer)
END_EVENT_TABLE()
////////////
// Instance
VideoContext *VideoContext::instance = NULL;
///////////////
// Constructor
VideoContext::VideoContext() {
// Set GL context
glContext = NULL;
lastTex = 0;
lastFrame = -1;
// Set options
audio = NULL;
provider = NULL;
subsProvider = NULL;
curLine = NULL;
loaded = false;
keyFramesLoaded = false;
overKeyFramesLoaded = false;
frame_n = 0;
isPlaying = false;
threaded = Options.AsBool(_T("Threaded Video"));
nextFrame = -1;
}
//////////////
// Destructor
VideoContext::~VideoContext () {
Reset();
delete glContext;
glContext = NULL;
}
////////////////
// Get Instance
VideoContext *VideoContext::Get() {
if (!instance) instance = new VideoContext;
return instance;
}
/////////
// Clear
void VideoContext::Clear() {
instance->audio = NULL;
delete instance;
instance = NULL;
}
/////////
// Reset
void VideoContext::Reset() {
// Clear keyframes
KeyFrames.Clear();
keyFramesLoaded = false;
// Remove temporary audio provider
if (audio && audio->temporary) {
delete audio->provider;
audio->provider = NULL;
delete audio->player;
audio->player = NULL;
audio->temporary = false;
}
// Remove video data
loaded = false;
frame_n = 0;
keyFramesLoaded = false;
overKeyFramesLoaded = false;
isPlaying = false;
nextFrame = -1;
// Update displays
UpdateDisplays(true);
// Remove textures
UnloadTexture();
// Clean up video data
wxRemoveFile(tempfile);
tempfile = _T("");
videoName = _T("");
tempFrame.Clear();
// Remove provider
if (provider && subsProvider && provider->GetAsSubtitlesProvider() != subsProvider) delete subsProvider;
subsProvider = NULL;
delete provider;
provider = NULL;
}
//////////////////
// Unload texture
void VideoContext::UnloadTexture() {
// Remove textures
if (lastTex != 0) {
glDeleteTextures(1,&lastTex);
lastTex = 0;
}
lastFrame = -1;
}
///////////////////////
// Sets video filename
void VideoContext::SetVideo(const wxString &filename) {
// Unload video
Reset();
// Load video
if (!filename.IsEmpty()) {
try {
grid->CommitChanges(true);
bool isVfr = false;
double overFps = 0;
FrameRate temp;
// Unload timecodes
//int unload = wxYES;
//if (VFR_Output.IsLoaded()) unload = wxMessageBox(_("Do you want to unload timecodes, too?"),_("Unload timecodes?"),wxYES_NO | wxICON_QUESTION);
//if (unload == wxYES) VFR_Output.Unload();
// Read extra data from file
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
wxString ext = filename.Right(4).Lower();
KeyFrames.Clear();
if (ext == _T(".mkv") || mkvOpen) {
// Parse mkv
if (!mkvOpen) MatroskaWrapper::wrapper.Open(filename);
// Get keyframes
KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
keyFramesLoaded = true;
// Ask to override timecodes
int override = wxYES;
if (VFR_Output.IsLoaded()) override = wxMessageBox(_("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
if (override == wxYES) {
MatroskaWrapper::wrapper.SetToTimecodes(temp);
isVfr = temp.GetFrameRateType() == VFR;
if (isVfr) {
overFps = temp.GetCommonFPS();
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
}
}
// Close mkv
MatroskaWrapper::wrapper.Close();
}
#ifdef __WINDOWS__
else if (ext == _T(".avi")) {
KeyFrames = VFWWrapper::GetKeyFrames(filename);
keyFramesLoaded = true;
}
#endif
// Choose a provider
provider = VideoProviderFactory::GetProvider(filename,overFps);
loaded = provider != NULL;
// Get subtitles provider
subsProvider = provider->GetAsSubtitlesProvider();
if (!subsProvider) subsProvider = SubtitlesProviderFactory::GetProvider();
// Set frame rate
fps = provider->GetFPS();
if (!isVfr) {
VFR_Input.SetCFR(fps);
if (VFR_Output.GetFrameRateType() != VFR) VFR_Output.SetCFR(fps);
}
else provider->OverrideFrameTimeList(temp.GetFrameTimeList());
// Gather video parameters
length = provider->GetFrameCount();
w = provider->GetWidth();
h = provider->GetHeight();
// Set filename
videoName = filename;
Options.AddToRecentList(filename,_T("Recent vid"));
// Get frame
UpdateDisplays(true);
frame_n = 0;
Refresh(true,true);
}
catch (wxString &e) {
wxMessageBox(e,_T("Error setting video"),wxICON_ERROR | wxOK);
}
}
loaded = provider != NULL;
}
///////////////////
// Add new display
void VideoContext::AddDisplay(VideoDisplay *display) {
for (std::list<VideoDisplay*>::iterator cur=displayList.begin();cur!=displayList.end();cur++) {
if ((*cur) == display) return;
}
displayList.push_back(display);
}
//////////////////
// Remove display
void VideoContext::RemoveDisplay(VideoDisplay *display) {
displayList.remove(display);
}
///////////////////
// Update displays
void VideoContext::UpdateDisplays(bool full) {
for (std::list<VideoDisplay*>::iterator cur=displayList.begin();cur!=displayList.end();cur++) {
VideoDisplay *display = *cur;
if (full) {
display->UpdateSize();
display->ControlSlider->SetRange(0,GetLength()-1);
}
display->ControlSlider->SetValue(GetFrameN());
display->UpdatePositionDisplay();
display->Refresh();
display->Update();
}
}
/////////////////////
// Refresh subtitles
void VideoContext::Refresh (bool video, bool subtitles) {
// Reset frame
lastFrame = -1;
// Get provider
if (subtitles && subsProvider) {
AssExporter exporter(grid->ass);
exporter.AddAutoFilters();
subsProvider->LoadSubtitles(exporter.ExportTransform());
}
// Jump to frame
JumpToFrame(frame_n);
}
///////////////////////////////////////
// Jumps to a frame and update display
void VideoContext::JumpToFrame(int n) {
// Loaded?
if (!loaded) return;
// Prevent intervention during playback
if (isPlaying && n != playNextFrame) return;
// Set frame number
frame_n = n;
GetFrameAsTexture(n);
// Display
UpdateDisplays(false);
// Update grid
if (!isPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false);
}
////////////////////////////
// Jumps to a specific time
void VideoContext::JumpToTime(int ms) {
JumpToFrame(VFR_Output.GetFrameAtTime(ms));
}
//////////////////
// Get GL context
wxGLContext *VideoContext::GetGLContext(wxGLCanvas *canvas) {
if (!glContext) glContext = new wxGLContext(canvas);
return glContext;
}
///////////////////////////
// Get GL Texture of frame
GLuint VideoContext::GetFrameAsTexture(int n) {
// Already uploaded
if (n == lastFrame) return lastTex;
// Get frame
AegiVideoFrame frame = GetFrame(n);
// Set frame
lastFrame = n;
// Image type
GLenum format;
if (frame.format == FORMAT_RGB32) {
if (frame.invertChannels) format = GL_BGRA_EXT;
else format = GL_RGBA;
}
else if (frame.format == FORMAT_RGB24) {
if (frame.invertChannels) format = GL_BGR_EXT;
else format = GL_RGB;
}
else if (frame.format == FORMAT_YV12) {
format = GL_LUMINANCE;
}
isInverted = frame.flipped;
// Set context
GetGLContext(displayList.front())->SetCurrent(*displayList.front());
glEnable(GL_TEXTURE_2D);
if (lastTex == 0) {
// Enable
glShadeModel(GL_FLAT);
// Generate texture with GL
glGenTextures(1, &lastTex);
glBindTexture(GL_TEXTURE_2D, lastTex);
// Load image data into texture
int height = frame.h;
if (frame.format == FORMAT_YV12) height = frame.h * 3 / 2;
int tw = SmallestPowerOf2(frame.w);
int th = SmallestPowerOf2(frame.h);
texW = float(frame.w)/float(tw);
texH = float(frame.h)/float(th);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,tw,th,0,format,GL_UNSIGNED_BYTE,NULL);
// Set texture
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
}
// Load texture data
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,frame.w,frame.h,format,GL_UNSIGNED_BYTE,frame.data[0]);
// UV planes for YV12
if (frame.format == FORMAT_YV12) {
glTexSubImage2D(GL_TEXTURE_2D,0,0,frame.h,frame.w/2,frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[1]);
glTexSubImage2D(GL_TEXTURE_2D,0,frame.w/2,frame.h,frame.w/2,frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[2]);
}
// Return texture number
return lastTex;
}
/////////////////
// Save snapshot
void VideoContext::SaveSnapshot() {
// Get folder
wxString option = Options.AsText(_("Video Screenshot Path"));
wxFileName videoFile(videoName);
wxString basepath;
if (option == _T("?video")) {
basepath = videoFile.GetPath();
}
else if (option == _T("?script")) {
if (grid->ass->filename.IsEmpty()) basepath = videoFile.GetPath();
else {
wxFileName file2(grid->ass->filename);
basepath = file2.GetPath();
}
}
else basepath = DecodeRelativePath(option,((AegisubApp*)wxTheApp)->folderName);
basepath += _T("/") + videoFile.GetName();
// Get full path
int session_shot_count = 1;
wxString path;
while (1) {
path = basepath + wxString::Format(_T("_%03i_%i.png"),session_shot_count,frame_n);
++session_shot_count;
wxFileName tryPath(path);
if (!tryPath.FileExists()) break;
}
// Save
GetFrame(frame_n).GetImage().SaveFile(path,wxBITMAP_TYPE_PNG);
}
////////////////////////
// Requests a new frame
AegiVideoFrame VideoContext::GetFrame(int n) {
if (n == -1) n = frame_n;
AegiVideoFrame frame = provider->GetFrame(n);
if (subsProvider && subsProvider->CanRaster()) {
tempFrame.CopyFrom(frame);
subsProvider->DrawSubtitles(tempFrame,VFR_Input.GetTimeAtFrame(n,true,true)/1000.0);
return tempFrame;
}
else return frame;
}
////////////////////////////
// Get dimensions of script
void VideoContext::GetScriptSize(int &sw,int &sh) {
grid->ass->GetResolution(sw,sh);
}
////////
// Play
void VideoContext::Play() {
// Stop if already playing
if (isPlaying) {
Stop();
return;
}
// Set variables
isPlaying = true;
startFrame = frame_n;
endFrame = -1;
// Start playing audio
audio->Play(VFR_Output.GetTimeAtFrame(startFrame),-1);
// Start timer
startTime = clock();
playTime = startTime;
playback.SetOwner(this,VIDEO_PLAY_TIMER);
playback.Start(1);
}
/////////////
// Play line
void VideoContext::PlayLine() {
// Get line
AssDialogue *curline = grid->GetDialogue(grid->editBox->linen);
if (!curline) return;
// Start playing audio
audio->Play(curline->Start.GetMS(),curline->End.GetMS());
// Set variables
isPlaying = true;
startFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
endFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
// Jump to start
playNextFrame = startFrame;
JumpToFrame(startFrame);
// Set other variables
startTime = clock();
playTime = startTime;
// Start timer
playback.SetOwner(this,VIDEO_PLAY_TIMER);
playback.Start(1);
}
////////
// Stop
void VideoContext::Stop() {
if (isPlaying) {
playback.Stop();
isPlaying = false;
audio->Stop();
}
}
//////////////
// Play timer
void VideoContext::OnPlayTimer(wxTimerEvent &event) {
// Lock
wxMutexError res = playMutex.TryLock();
if (res == wxMUTEX_BUSY) return;
playMutex.Unlock();
wxMutexLocker lock(playMutex);
// Get time difference
clock_t cur = clock();
clock_t dif = (clock() - startTime)*1000/CLOCKS_PER_SEC;
playTime = cur;
// Find next frame
int startMs = VFR_Output.GetTimeAtFrame(startFrame);
int nextFrame = frame_n;
int i=0;
for (i=0;i<10;i++) {
if (nextFrame >= length) break;
if (dif < VFR_Output.GetTimeAtFrame(nextFrame) - startMs) {
break;
}
nextFrame++;
}
// End
if (nextFrame >= length || (endFrame != -1 && nextFrame > endFrame)) {
Stop();
return;
}
// Same frame
if (nextFrame == frame_n) return;
// Next frame is before or over 2 frames ahead, so force audio resync
if (nextFrame < frame_n || nextFrame > frame_n + 2) audio->player->SetCurrentPosition(audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame)));
// Jump to next frame
playNextFrame = nextFrame;
frame_n = nextFrame;
JumpToFrame(nextFrame);
// Sync audio
if (nextFrame % 10 == 0) {
__int64 audPos = audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame));
__int64 curPos = audio->player->GetCurrentPosition();
int delta = int(audPos-curPos);
if (delta < 0) delta = -delta;
int maxDelta = audio->provider->GetSampleRate();
if (delta > maxDelta) audio->player->SetCurrentPosition(audPos);
}
}
//////////////////////////////
// Get name of temp work file
wxString VideoContext::GetTempWorkFile () {
if (tempfile.IsEmpty()) {
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
wxRemoveFile(tempfile);
tempfile += _T(".ass");
}
return tempfile;
}
/////////////////
// Get keyframes
wxArrayInt VideoContext::GetKeyFrames() {
if (OverKeyFramesLoaded()) return overKeyFrames;
return KeyFrames;
}
/////////////////
// Set keyframes
void VideoContext::SetKeyFrames(wxArrayInt frames) {
KeyFrames = frames;
}
/////////////////////////
// Set keyframe override
void VideoContext::SetOverKeyFrames(wxArrayInt frames) {
overKeyFrames = frames;
overKeyFramesLoaded = true;
}
///////////////////
// Close keyframes
void VideoContext::CloseOverKeyFrames() {
overKeyFrames.Clear();
overKeyFramesLoaded = false;
}
//////////////////////////////////////////
// Check if override keyframes are loaded
bool VideoContext::OverKeyFramesLoaded() {
return overKeyFramesLoaded;
}
/////////////////////////////////
// Check if keyframes are loaded
bool VideoContext::KeyFramesLoaded() {
return overKeyFramesLoaded || keyFramesLoaded;
}

171
aegisub/video_context.h Normal file
View file

@ -0,0 +1,171 @@
// Copyright (c) 2005-2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
///////////
// Headers
#include <wx/wxprec.h>
#include <time.h>
#include <wx/glcanvas.h>
#include "video_frame.h"
//////////////
// Prototypes
class SubtitlesGrid;
class AudioProvider;
class AudioDisplay;
class AssDialogue;
class VideoProvider;
class VideoDisplay;
class SubtitlesProvider;
//////////////
// Main class
class VideoContext : public wxEvtHandler {
friend class AudioProvider;
friend class VideoDisplayVisual;
private:
static VideoContext *instance;
std::list<VideoDisplay*> displayList;
GLuint lastTex;
int lastFrame;
wxGLContext *glContext;
VideoFrameFormat vidFormat;
AegiVideoFrame tempFrame;
wxString tempfile;
VideoProvider *provider;
SubtitlesProvider *subsProvider;
bool keyFramesLoaded;
bool overKeyFramesLoaded;
wxArrayInt KeyFrames;
wxArrayInt overKeyFrames;
wxString keyFramesFilename;
wxMutex playMutex;
wxTimer playback;
clock_t playTime;
clock_t startTime;
int startFrame;
int endFrame;
int playNextFrame;
int nextFrame;
bool threaded;
bool loaded;
bool isInverted;
bool isPlaying;
float texW,texH;
int w,h;
int frame_n;
int length;
double fps;
void UnloadTexture();
void OnPlayTimer(wxTimerEvent &event);
public:
SubtitlesGrid *grid;
wxString videoName;
AssDialogue *curLine;
AudioDisplay *audio;
VideoContext();
~VideoContext();
void AddDisplay(VideoDisplay *display);
void RemoveDisplay(VideoDisplay *display);
VideoProvider *GetProvider() { return provider; }
AegiVideoFrame GetFrame(int n);
void SaveSnapshot();
wxGLContext *GetGLContext(wxGLCanvas *canvas);
GLuint GetFrameAsTexture(int n);
float GetTexW() { return texW; }
float GetTexH() { return texH; }
VideoFrameFormat GetFormat() { return vidFormat; }
bool IsLoaded() { return loaded; }
bool IsPlaying() { return isPlaying; }
bool IsInverted() { return isInverted; }
int GetWidth() { return w; }
int GetHeight() { return h; }
int GetLength() { return length; }
int GetFrameN() { return frame_n; }
double GetFPS() { return fps; }
void SetFPS(double _fps) { fps = _fps; }
void SetVideo(const wxString &filename);
void Reset();
void JumpToFrame(int n);
void JumpToTime(int ms);
void Refresh(bool video,bool subtitles);
void UpdateDisplays(bool full);
void GetScriptSize(int &w,int &h);
wxString GetTempWorkFile ();
void Play();
void PlayLine();
void Stop();
wxArrayInt GetKeyFrames();
void SetKeyFrames(wxArrayInt frames);
void SetOverKeyFrames(wxArrayInt frames);
void CloseOverKeyFrames();
bool OverKeyFramesLoaded();
bool KeyFramesLoaded();
wxString GetKeyFramesName() { return keyFramesFilename; }
void SetKeyFramesName(wxString name) { keyFramesFilename = name; }
static VideoContext *Get();
static void Clear();
DECLARE_EVENT_TABLE()
};

View file

@ -42,6 +42,7 @@
#include <wx/clipbrd.h>
#include <wx/filename.h>
#include <wx/config.h>
#include <GL/glu.h>
#include "utils.h"
#include "video_display.h"
#include "video_display_visual.h"
@ -60,11 +61,7 @@
#include "main.h"
#include "video_slider.h"
#include "video_box.h"
#if USE_FEXTRACKER == 1
#include "../FexTrackerSource/FexTracker.h"
#include "../FexTrackerSource/FexTrackingFeature.h"
#include "../FexTrackerSource/FexMovement.h"
#endif
#include "video_display_fextracker.h"
///////
@ -73,19 +70,17 @@ enum {
VIDEO_MENU_COPY_TO_CLIPBOARD = 1230,
VIDEO_MENU_COPY_COORDS,
VIDEO_MENU_SAVE_SNAPSHOT,
VIDEO_PLAY_TIMER
};
///////////////
// Event table
BEGIN_EVENT_TABLE(VideoDisplay, wxWindow)
EVT_MOUSE_EVENTS(VideoDisplay::OnMouseEvent)
BEGIN_EVENT_TABLE(VideoDisplay, wxGLCanvas)
EVT_MOUSE_EVENTS(VideoDisplay::OnMouseEvent)
EVT_KEY_DOWN(VideoDisplay::OnKey)
EVT_LEAVE_WINDOW(VideoDisplay::OnMouseLeave)
EVT_PAINT(VideoDisplay::OnPaint)
EVT_TIMER(VIDEO_PLAY_TIMER,VideoDisplay::OnPlayTimer)
EVT_PAINT(VideoDisplay::OnPaint)
EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground)
EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard)
EVT_MENU(VIDEO_MENU_SAVE_SNAPSHOT,VideoDisplay::OnSaveSnapshot)
@ -96,183 +91,145 @@ END_EVENT_TABLE()
///////////////
// Constructor
VideoDisplay::VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
: wxWindow (parent, id, pos, size, style, name)
: wxGLCanvas (parent, id, NULL, pos, size, style, name)
{
audio = NULL;
provider = NULL;
curLine = NULL;
// Set options
ControlSlider = NULL;
PositionDisplay = NULL;
loaded = false;
keyFramesLoaded = false;
overKeyFramesLoaded = false;
frame_n = 0;
origSize = size;
arType = 0;
IsPlaying = false;
threaded = Options.AsBool(_T("Threaded Video"));
nextFrame = -1;
zoomValue = 0.5;
arValue = 1.0;
zoomValue = 1.0;
visual = new VideoDisplayVisual(this);
tracker = NULL;
#if USE_FEXTRACKER == 1
tracker = new VideoDisplayFexTracker(this);
#endif
SetCursor(wxNullCursor);
}
//////////////
// Destructor
VideoDisplay::~VideoDisplay () {
wxRemoveFile(tempfile);
tempfile = _T("");
SetVideo(_T(""));
delete visual;
#if USE_FEXTRACKER == 1
delete tracker;
#endif
VideoContext::Get()->RemoveDisplay(this);
}
void VideoDisplay::UpdateSize() {
if (provider) {
w = provider->GetWidth();
h = provider->GetHeight();
// Set the size for this control
SetSizeHints(w,h,w,h);
SetClientSize(w,h);
int _w,_h;
GetSize(&_w,&_h);
SetSizeHints(_w,_h,_w,_h);
//////////
// Render
void VideoDisplay::Render() {
// Is shown?
if (!GetParent()->IsShown()) return;
box->VideoSizer->Fit(box);
// Set GL context
VideoContext *context = VideoContext::Get();
SetCurrent(*context->GetGLContext(this));
// Get sizes
int w,h,sw,sh,pw,ph;
GetClientSize(&w,&h);
context->GetScriptSize(sw,sh);
pw = context->GetWidth();
ph = context->GetHeight();
// Set viewport
glEnable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0,0,w,h);
glOrtho(0.0f,sw,sh,0.0f,-1000.0f,1000.0f);
glMatrixMode(GL_MODELVIEW);
// Texture mode
if (w != pw || h != ph) {
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
else {
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
}
// Texture coordinates
float top = 0.0f;
float bot = context->GetTexH();
if (context->IsInverted()) {
top = context->GetTexH();
bot = 0.0f;
}
float left = 0.0;
float right = context->GetTexW();
// Draw interleaved frame or luma of YV12
glDisable(GL_BLEND);
glColor4f(1.0f,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);
// Top-left
glTexCoord2f(left,top);
glVertex2f(0,0);
// Top-right
glTexCoord2f(right,top);
glVertex2f(sw,0);
// Bottom-right
glTexCoord2f(right,bot);
glVertex2f(sw,sh);
// Bottom-left
glTexCoord2f(left,bot);
glVertex2f(0,sh);
glEnd();
// Draw UV planes
if (context->GetFormat() == FORMAT_YV12) {
}
// Draw overlay
visual->DrawOverlay();
// Swap buffers
SwapBuffers();
}
///////////////
// Update size
void VideoDisplay::UpdateSize() {
// Get size
if (arType == 0) w = VideoContext::Get()->GetWidth() * zoomValue;
else w = VideoContext::Get()->GetHeight() * zoomValue * arValue;
h = VideoContext::Get()->GetHeight() * zoomValue;
int _w,_h;
// Set the size for this control
SetSizeHints(w,h,w,h);
SetClientSize(w,h);
GetSize(&_w,&_h);
SetSizeHints(_w,_h,_w,_h);
box->VideoSizer->Fit(box);
// Layout
box->GetParent()->Layout();
SetClientSize(w,h);
// Refresh
Refresh(false);
}
//////////
// Resets
void VideoDisplay::Reset() {
w = origSize.GetX();
h = origSize.GetY();
int w = origSize.GetX();
int h = origSize.GetY();
SetClientSize(w,h);
int _w,_h;
GetSize(&_w,&_h);
SetSizeHints(_w,_h,_w,_h);
KeyFrames.Clear();
keyFramesLoaded = false;
// Remove temporary audio provider
if (audio && audio->temporary) {
delete audio->provider;
audio->provider = NULL;
delete audio->player;
audio->player = NULL;
audio->temporary = false;
}
}
///////////////////////
// Sets video filename
void VideoDisplay::SetVideo(const wxString &filename) {
// Unload video
delete provider;
provider = NULL;
//if (VFR_Output.GetFrameRateType() == VFR) VFR_Output.Unload();
//VFR_Input.Unload();
videoName = _T("");
loaded = false;
frame_n = 0;
Reset();
// Load video
if (!filename.IsEmpty()) {
try {
grid->CommitChanges(true);
bool isVfr = false;
double overFps = 0;
FrameRate temp;
// Unload timecodes
//int unload = wxYES;
//if (VFR_Output.IsLoaded()) unload = wxMessageBox(_("Do you want to unload timecodes, too?"),_("Unload timecodes?"),wxYES_NO | wxICON_QUESTION);
//if (unload == wxYES) VFR_Output.Unload();
// Read extra data from file
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
wxString ext = filename.Right(4).Lower();
KeyFrames.Clear();
if (ext == _T(".mkv") || mkvOpen) {
// Parse mkv
if (!mkvOpen) MatroskaWrapper::wrapper.Open(filename);
// Get keyframes
KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
keyFramesLoaded = true;
// Ask to override timecodes
int override = wxYES;
if (VFR_Output.IsLoaded()) override = wxMessageBox(_("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
if (override == wxYES) {
MatroskaWrapper::wrapper.SetToTimecodes(temp);
isVfr = temp.GetFrameRateType() == VFR;
if (isVfr) {
overFps = temp.GetCommonFPS();
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
}
}
// Close mkv
MatroskaWrapper::wrapper.Close();
}
#ifdef __WINDOWS__
else if (ext == _T(".avi")) {
KeyFrames = VFWWrapper::GetKeyFrames(filename);
keyFramesLoaded = true;
}
#endif
// Choose a provider
provider = VideoProvider::GetProvider(filename,GetTempWorkFile(),overFps);
if (isVfr) provider->OverrideFrameTimeList(temp.GetFrameTimeList());
provider->SetZoom(zoomValue);
if (arType != 4) arValue = GetARFromType(arType); // 4 = custom
provider->SetDAR(arValue);
// Update size
UpdateSize();
//Gather video parameters
length = provider->GetFrameCount();
fps = provider->GetFPS();
if (!isVfr) {
VFR_Input.SetCFR(fps);
if (VFR_Output.GetFrameRateType() != VFR) VFR_Output.SetCFR(fps);
}
// Set range of slider
ControlSlider->SetRange(0,length-1);
ControlSlider->SetValue(0);
videoName = filename;
// Add to recent
Options.AddToRecentList(filename,_T("Recent vid"));
RefreshVideo();
UpdatePositionDisplay();
}
catch (wxString &e) {
wxMessageBox(e,_T("Error setting video"),wxICON_ERROR | wxOK);
}
}
loaded = provider != NULL;
}
/////////////////////
// Refresh subtitles
void VideoDisplay::RefreshSubtitles() {
provider->RefreshSubtitles();
RefreshVideo();
}
@ -282,7 +239,7 @@ void VideoDisplay::OnPaint(wxPaintEvent& event) {
wxPaintDC dc(this);
// Draw frame
if (provider) dc.DrawBitmap(GetFrame(frame_n),0,0);
Render();
}
@ -290,7 +247,7 @@ void VideoDisplay::OnPaint(wxPaintEvent& event) {
// Mouse stuff
void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
// Disable when playing
if (IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
if (event.Leaving()) {
// OnMouseLeave isn't called as long as we have an OnMouseEvent
@ -331,42 +288,9 @@ void VideoDisplay::OnKey(wxKeyEvent &event) {
//////////////////////
// Mouse left display
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
if (IsPlaying) return;
bTrackerEditing = 0;
RefreshVideo();
}
///////////////////////////////////////
// Jumps to a frame and update display
void VideoDisplay::JumpToFrame(int n) {
// Loaded?
if (!loaded) return;
// Prevent intervention during playback
if (IsPlaying && n != PlayNextFrame) return;
// Set frame
GetFrame(n);
// Display
RefreshVideo();
UpdatePositionDisplay();
// Update slider
ControlSlider->SetValue(n);
// Update grid
if (!IsPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false);
}
////////////////////////////
// Jumps to a specific time
void VideoDisplay::JumpToTime(int ms) {
JumpToFrame(VFR_Output.GetFrameAtTime(ms));
if (VideoContext::Get()->IsPlaying()) return;
visual->OnMouseEvent(event);
tracker->bTrackerEditing = 0;
}
@ -374,12 +298,7 @@ void VideoDisplay::JumpToTime(int ms) {
// Sets zoom level
void VideoDisplay::SetZoom(double value) {
zoomValue = value;
if (provider) {
provider->SetZoom(value);
UpdateSize();
RefreshVideo();
box->GetParent()->Layout();
}
UpdateSize();
}
@ -396,7 +315,7 @@ void VideoDisplay::SetZoomPos(int value) {
//////////////////////////
// Calculate aspect ratio
double VideoDisplay::GetARFromType(int type) {
if (type == 0) return (double)provider->GetSourceWidth()/(double)provider->GetSourceHeight();
if (type == 0) return (double)VideoContext::Get()->GetWidth()/(double)VideoContext::Get()->GetHeight();
if (type == 1) return 4.0/3.0;
if (type == 2) return 16.0/9.0;
if (type == 3) return 2.35;
@ -407,20 +326,15 @@ double VideoDisplay::GetARFromType(int type) {
/////////////////////
// Sets aspect ratio
void VideoDisplay::SetAspectRatio(int _type, double value) {
if (provider) {
// Get value
if (_type != 4) value = GetARFromType(_type);
if (value < 0.5) value = 0.5;
if (value > 5.0) value = 5.0;
// Get value
if (_type != 4) value = GetARFromType(_type);
if (value < 0.5) value = 0.5;
if (value > 5.0) value = 5.0;
// Set
provider->SetDAR(value);
arType = _type;
arValue = value;
UpdateSize();
RefreshVideo();
GetParent()->Layout();
}
// Set
arType = _type;
arValue = value;
UpdateSize();
}
@ -433,6 +347,7 @@ void VideoDisplay::UpdatePositionDisplay() {
}
// Get time
int frame_n = VideoContext::Get()->GetFrameN();
int time = VFR_Output.GetTimeAtFrame(frame_n,true,true);
int temp = time;
int h=0, m=0, s=0, ms=0;
@ -452,7 +367,7 @@ void VideoDisplay::UpdatePositionDisplay() {
// Position display update
PositionDisplay->SetValue(wxString::Format(_T("%01i:%02i:%02i.%03i - %i"),h,m,s,ms,frame_n));
if (GetKeyFrames().Index(frame_n) != wxNOT_FOUND) {
if (VideoContext::Get()->GetKeyFrames().Index(frame_n) != wxNOT_FOUND) {
PositionDisplay->SetBackgroundColour(Options.AsColour(_T("Grid selection background")));
PositionDisplay->SetForegroundColour(Options.AsColour(_T("Grid selection foreground")));
}
@ -473,6 +388,8 @@ void VideoDisplay::UpdateSubsRelativeTime() {
wxString startSign;
wxString endSign;
int startOff,endOff;
int frame_n = VideoContext::Get()->GetFrameN();
AssDialogue *curLine = VideoContext::Get()->curLine;
// Set start/end
if (curLine) {
@ -500,7 +417,7 @@ void VideoDisplay::UpdateSubsRelativeTime() {
// Copy to clipboard
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &event) {
if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new wxBitmapDataObject(GetFrame(frame_n)));
wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(-1).GetImage(),24)));
wxTheClipboard->Close();
}
}
@ -509,39 +426,7 @@ void VideoDisplay::OnCopyToClipboard(wxCommandEvent &event) {
/////////////////
// Save snapshot
void VideoDisplay::OnSaveSnapshot(wxCommandEvent &event) {
SaveSnapshot();
}
void VideoDisplay::SaveSnapshot() {
// Get folder
wxString option = Options.AsText(_("Video Screenshot Path"));
wxFileName videoFile(videoName);
wxString basepath;
if (option == _T("?video")) {
basepath = videoFile.GetPath();
}
else if (option == _T("?script")) {
if (grid->ass->filename.IsEmpty()) basepath = videoFile.GetPath();
else {
wxFileName file2(grid->ass->filename);
basepath = file2.GetPath();
}
}
else basepath = DecodeRelativePath(option,((AegisubApp*)wxTheApp)->folderName);
basepath += _T("/") + videoFile.GetName();
// Get full path
int session_shot_count = 1;
wxString path;
while (1) {
path = basepath + wxString::Format(_T("_%03i_%i.png"),session_shot_count,frame_n);
++session_shot_count;
wxFileName tryPath(path);
if (!tryPath.FileExists()) break;
}
// Save
GetFrame(frame_n).ConvertToImage().SaveFile(path,wxBITMAP_TYPE_PNG);
VideoContext::Get()->SaveSnapshot();
}
@ -550,7 +435,7 @@ void VideoDisplay::SaveSnapshot() {
void VideoDisplay::OnCopyCoords(wxCommandEvent &event) {
if (wxTheClipboard->Open()) {
int sw,sh;
GetScriptSize(sw,sh);
VideoContext::Get()->GetScriptSize(sw,sh);
int vx = (sw * visual->mouseX + w/2) / w;
int vy = (sh * visual->mouseY + h/2) / h;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%i,%i"),vx,vy)));
@ -559,216 +444,19 @@ void VideoDisplay::OnCopyCoords(wxCommandEvent &event) {
}
//////////////////
// Refresh screen
void VideoDisplay::RefreshVideo() {
// Draw frame
wxClientDC dc(this);
dc.DrawBitmap(GetFrame(),0,0);
// Draw the control points for FexTracker
visual->DrawTrackingOverlay(dc);
}
//////////////////
// DrawVideoWithOverlay
void VideoDisplay::DrawText( wxPoint Pos, wxString text ) {
// Draw frame
wxClientDC dc(this);
dc.SetBrush(wxBrush(wxColour(128,128,128),wxSOLID));
dc.DrawRectangle( 0,0, provider->GetWidth(), provider->GetHeight() );
dc.SetTextForeground(wxColour(64,64,64));
dc.DrawText(text,Pos.x+1,Pos.y-1);
dc.DrawText(text,Pos.x+1,Pos.y+1);
dc.DrawText(text,Pos.x-1,Pos.y-1);
dc.DrawText(text,Pos.x-1,Pos.y+1);
dc.SetTextForeground(wxColour(255,255,255));
dc.DrawText(text,Pos.x,Pos.y);
//// Draw frame
//wxClientDC dc(this);
//dc.SetBrush(wxBrush(wxColour(128,128,128),wxSOLID));
//dc.DrawRectangle( 0,0, provider->GetWidth(), provider->GetHeight() );
//dc.SetTextForeground(wxColour(64,64,64));
//dc.DrawText(text,Pos.x+1,Pos.y-1);
//dc.DrawText(text,Pos.x+1,Pos.y+1);
//dc.DrawText(text,Pos.x-1,Pos.y-1);
//dc.DrawText(text,Pos.x-1,Pos.y+1);
//dc.SetTextForeground(wxColour(255,255,255));
//dc.DrawText(text,Pos.x,Pos.y);
}
////////////////////////
// Requests a new frame
wxBitmap VideoDisplay::GetFrame(int n) {
frame_n = n;
return provider->GetFrame(n);
RefreshVideo();
}
////////////////////////////
// Get dimensions of script
void VideoDisplay::GetScriptSize(int &sw,int &sh) {
grid->ass->GetResolution(sw,sh);
}
////////
// Play
void VideoDisplay::Play() {
// Stop if already playing
if (IsPlaying) {
Stop();
return;
}
// Set variables
IsPlaying = true;
StartFrame = frame_n;
EndFrame = -1;
// Start playing audio
audio->Play(VFR_Output.GetTimeAtFrame(StartFrame),-1);
// Start timer
StartTime = clock();
PlayTime = StartTime;
Playback.SetOwner(this,VIDEO_PLAY_TIMER);
Playback.Start(1);
}
/////////////
// Play line
void VideoDisplay::PlayLine() {
// Get line
AssDialogue *curline = grid->GetDialogue(grid->editBox->linen);
if (!curline) return;
// Start playing audio
audio->Play(curline->Start.GetMS(),curline->End.GetMS());
// Set variables
IsPlaying = true;
StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
// Jump to start
PlayNextFrame = StartFrame;
JumpToFrame(StartFrame);
// Set other variables
StartTime = clock();
PlayTime = StartTime;
// Start timer
Playback.SetOwner(this,VIDEO_PLAY_TIMER);
Playback.Start(1);
}
////////
// Stop
void VideoDisplay::Stop() {
if (IsPlaying) {
Playback.Stop();
IsPlaying = false;
audio->Stop();
}
}
//////////////
// Play timer
void VideoDisplay::OnPlayTimer(wxTimerEvent &event) {
// Get time difference
clock_t cur = clock();
int dif = (clock() - StartTime)*1000/CLOCKS_PER_SEC;
if (!dif) return;
PlayTime = cur;
// Find next frame
int startMs = VFR_Output.GetTimeAtFrame(StartFrame);
int nextFrame = frame_n;
for (int i=0;i<10;i++) {
if (nextFrame >= length) break;
if (dif < VFR_Output.GetTimeAtFrame(nextFrame) - startMs) {
break;
}
nextFrame++;
}
// Same frame
if (nextFrame == frame_n) return;
// End
if (nextFrame >= length || (EndFrame != -1 && nextFrame > EndFrame)) {
Stop();
return;
}
// Next frame is before or over 2 frames ahead, so force audio resync
if (nextFrame < frame_n || nextFrame > frame_n + 2) audio->player->SetCurrentPosition(audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame)));
// Jump to next frame
PlayNextFrame = nextFrame;
JumpToFrame(nextFrame);
// Sync audio
if (nextFrame % 10 == 0) {
__int64 audPos = audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame));
__int64 curPos = audio->player->GetCurrentPosition();
int delta = int(audPos-curPos);
if (delta < 0) delta = -delta;
int maxDelta = audio->provider->GetSampleRate();
if (delta > maxDelta) audio->player->SetCurrentPosition(audPos);
}
}
//////////////////////////////
// Get name of temp work file
wxString VideoDisplay::GetTempWorkFile () {
if (tempfile.IsEmpty()) {
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
wxRemoveFile(tempfile);
tempfile += _T(".ass");
}
return tempfile;
}
/////////////////
// Get keyframes
wxArrayInt VideoDisplay::GetKeyFrames() {
if (OverKeyFramesLoaded()) return overKeyFrames;
return KeyFrames;
}
/////////////////
// Set keyframes
void VideoDisplay::SetKeyFrames(wxArrayInt frames) {
KeyFrames = frames;
}
/////////////////////////
// Set keyframe override
void VideoDisplay::SetOverKeyFrames(wxArrayInt frames) {
overKeyFrames = frames;
overKeyFramesLoaded = true;
}
///////////////////
// Close keyframes
void VideoDisplay::CloseOverKeyFrames() {
overKeyFrames.Clear();
overKeyFramesLoaded = false;
}
//////////////////////////////////////////
// Check if override keyframes are loaded
bool VideoDisplay::OverKeyFramesLoaded() {
return overKeyFramesLoaded;
}
/////////////////////////////////
// Check if keyframes are loaded
bool VideoDisplay::KeyFramesLoaded() {
return overKeyFramesLoaded || keyFramesLoaded;
}

View file

@ -34,8 +34,7 @@
//
#ifndef VIDEO_DISPLAY_H
#define VIDEO_DISPLAY_H
#pragma once
///////////
@ -45,6 +44,7 @@
#include <windows.h>
#endif
#include <time.h>
#include "video_context.h"
//////////////
@ -56,42 +56,19 @@ class AudioDisplay;
class AssDialogue;
class VideoProvider;
class VideoDisplayVisual;
class VideoDisplayFexTracker;
class VideoBox;
//////////////
// Main class
class VideoDisplay: public wxWindow {
class VideoDisplay: public wxGLCanvas {
friend class AudioProvider;
friend class VideoDisplayVisual;
private:
wxString tempfile;
wxSize origSize;
bool threaded;
int nextFrame;
bool keyFramesLoaded;
bool overKeyFramesLoaded;
wxArrayInt KeyFrames;
wxArrayInt overKeyFrames;
wxString keyFramesFilename;
clock_t PlayTime;
clock_t StartTime;
wxTimer Playback;
int StartFrame;
int EndFrame;
int PlayNextFrame;
double arValue;
int arType;
wxBitmap GetFrame(int n);
wxBitmap GetFrame() { return GetFrame(frame_n); };
void UpdateSize();
void SaveSnapshot();
int w,h;
void OnPaint(wxPaintEvent& event);
void OnKey(wxKeyEvent &event);
@ -100,73 +77,40 @@ private:
void OnCopyToClipboard(wxCommandEvent &event);
void OnSaveSnapshot(wxCommandEvent &event);
void OnCopyCoords(wxCommandEvent &event);
void OnPlayTimer(wxTimerEvent &event);
void OnEraseBackground(wxEraseEvent &event) {}
public:
wxArrayInt GetKeyFrames();
void SetKeyFrames(wxArrayInt frames);
void SetOverKeyFrames(wxArrayInt frames);
void CloseOverKeyFrames();
bool OverKeyFramesLoaded();
bool KeyFramesLoaded();
wxString GetKeyFramesName() { return keyFramesFilename; }
void SetKeyFramesName(wxString name) { keyFramesFilename = name; }
VideoDisplayVisual *visual;
VideoProvider *provider;
VideoDisplayFexTracker *tracker;
VideoBox *box;
SubtitlesGrid *grid;
wxString videoName;
int w,h;
int frame_n;
int length;
bool loaded;
bool IsPlaying;
double fps;
double arValue;
int arType;
double zoomValue;
bool bTrackerEditing;
int MovementEdit;
double TrackerEdit;
int MouseDownX, MouseDownY;
VideoSlider *ControlSlider;
wxComboBox *zoomBox;
wxTextCtrl *PositionDisplay;
wxTextCtrl *SubsPosition;
AssDialogue *curLine;
AudioDisplay *audio;
VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr);
~VideoDisplay();
void SetVideo(const wxString &filename);
void Reset();
void Unload();
void JumpToFrame(int n);
void JumpToTime(int ms);
void RefreshSubtitles();
void RefreshVideo();
void Render();
void DrawText(wxPoint Pos, wxString Text);
void UpdatePositionDisplay();
void UpdateSize();
void SetZoom(double value);
void SetZoomPos(int pos);
void UpdateSubsRelativeTime();
void GetScriptSize(int &w,int &h);
wxString GetTempWorkFile ();
double GetARFromType(int type);
void SetAspectRatio(int type,double value=1.0);
int GetAspectRatioType() { return arType; }
double GetAspectRatioValue() { return arValue; }
void Play();
void PlayLine();
void Stop();
DECLARE_EVENT_TABLE()
};
#endif

View file

@ -0,0 +1,434 @@
// Copyright (c) 2005-2007, Rodrigo Braz Monteiro, Hajo Krabbenhöft
// 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
//
////////////////////////////// HERE BE DRAGONS //////////////////////////////
///////////
// Headers
#include "setup.h"
#if USE_FEXTRACKER == 1
#include "video_display_fextracker.h"
#include "../FexTrackerSource/FexTracker.h"
#include "../FexTrackerSource/FexTrackingFeature.h"
#include "../FexTrackerSource/FexMovement.h"
#include "dialog_progress.h"
#include "dialog_fextracker.h"
#include "ass_dialogue.h"
#include "video_box.h"
#include "video_context.h"
#include "video_display.h"
#include "subs_grid.h"
#include "subs_edit_box.h"
#include "vfr.h"
#include "main.h"
#include "frame_main.h"
#include "video_provider.h"
#include "ass_file.h"
///////////////
// Event table
BEGIN_EVENT_TABLE(VideoDisplayFexTracker,wxEvtHandler)
EVT_MENU(Video_Track_Points, VideoDisplayFexTracker::OnVideoTrackPoints)
EVT_MENU(Video_Track_Point_Add, VideoDisplayFexTracker::OnVideoTrackPointAdd)
EVT_MENU(Video_Track_Point_Del, VideoDisplayFexTracker::OnVideoTrackPointDel)
EVT_MENU(Video_Track_Movement, VideoDisplayFexTracker::OnVideoTrackMovement)
EVT_MENU(Video_Track_Movement_MoveAll, VideoDisplayFexTracker::OnVideoTrackMovementMoveAll)
EVT_MENU(Video_Track_Movement_MoveOne, VideoDisplayFexTracker::OnVideoTrackMovementMoveOne)
EVT_MENU(Video_Track_Movement_MoveBefore, VideoDisplayFexTracker::OnVideoTrackMovementMoveBefore)
EVT_MENU(Video_Track_Movement_MoveAfter, VideoDisplayFexTracker::OnVideoTrackMovementMoveAfter)
EVT_MENU(Video_Track_Split_Line, VideoDisplayFexTracker::OnVideoTrackSplitLine)
EVT_MENU(Video_Track_Link_File, VideoDisplayFexTracker::OnVideoTrackLinkFile)
EVT_MENU(Video_Track_Movement_Empty, VideoDisplayFexTracker::OnVideoTrackMovementEmpty)
END_EVENT_TABLE()
///////////////
// Constructor
VideoDisplayFexTracker::VideoDisplayFexTracker(VideoDisplay *par) {
parent = par;
}
///////////////
// Mouse event
void VideoDisplayFexTracker::OnMouseEvent(wxMouseEvent &event) {
// Variables
int frame_n = VideoContext::Get()->GetFrameN();
int dw,dh;
parent->GetClientSize(&dw,&dh);
int x = event.GetX();
int y = event.GetY();
int mx = x * VideoContext::Get()->GetWidth() / dw;
int my = y * VideoContext::Get()->GetHeight() / dh;
// Click
if (event.ButtonDown(wxMOUSE_BTN_LEFT)) {
MouseDownX = mx;
MouseDownY = my;
bTrackerEditing = 1;
}
if (event.ButtonUp(wxMOUSE_BTN_LEFT)) bTrackerEditing = 0;
// Do tracker influence if needed
if( bTrackerEditing ) {
AssDialogue *curline = VideoContext::Get()->grid->GetDialogue(VideoContext::Get()->grid->editBox->linen);
int StartFrame, EndFrame, localframe;
// Visible?
if (curline && (StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true)) <= frame_n && (EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false)) >= frame_n ) {
localframe = frame_n - StartFrame;
if (TrackerEdit!=0 && curline->Tracker && localframe < curline->Tracker->GetFrame())
curline->Tracker->InfluenceFeatures (localframe, float(mx), float(my), TrackerEdit);
if (MovementEdit!=0 && curline->Movement && localframe < curline->Movement->Frames.size()) {
// Set start/end
int movMode = MovementEdit;
int start = 0;
int end = localframe+1;
if (movMode == 2 || movMode == 4) start = localframe;
if (movMode == 1 || movMode == 4) end = curline->Movement->Frames.size();
// Apply
for (int i=0;i<curline->Movement->Frames.size();i++) {
curline->Movement->Frames[i].Pos.x += float(mx-MouseDownX);
curline->Movement->Frames[i].Pos.y += float(my-MouseDownY);
}
}
MouseDownX = mx;
MouseDownY = my;
}
}
}
/////////////////////////
// Draw tracking overlay
void VideoDisplayFexTracker::Render() {
int frame_n = VideoContext::Get()->GetFrameN();
// Get line
AssDialogue *curline = VideoContext::Get()->grid->GetDialogue(VideoContext::Get()->grid->editBox->linen);
if (!curline) return;
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
if (frame_n<StartFrame || frame_n>EndFrame) return;
int localframe = frame_n - StartFrame;
if (curline->Tracker) {
if (curline->Tracker->GetFrame() <= localframe) return;
// Draw ticks
for (int i=0;i<curline->Tracker->GetCount();i++) {
FexTrackingFeature* f = (*curline->Tracker)[i];
if (f->StartTime > localframe) continue;
int llf = localframe - f->StartTime;
if (f->Pos.size() <= llf) continue;
vec2 pt = f->Pos[llf];
SetLineColour(wxColour(255*(1-f->Influence),255*f->Influence,0),1);
DrawLine (pt.x-2, pt.y, pt.x, pt.y);
DrawLine (pt.x, pt.y-2, pt.x, pt.y);
DrawLine (pt.x+1, pt.y, pt.x+3, pt.y);
DrawLine (pt.x, pt.y+1, pt.x, pt.y+3);
}
}
if (curline->Movement) {
if (curline->Movement->Frames.size() <= localframe) return;
FexMovementFrame f = curline->Movement->Frames.lVal[localframe];
f.Scale.x *= 30;
f.Scale.y *= 30;
FexMovementFrame f3 = f;
SetLineColour(wxColour(0,0,255),1);
int nBack = 8;
while (--localframe>0 && nBack-- >0) {
FexMovementFrame f2 = curline->Movement->Frames.lVal[localframe];
DrawLine (f2.Pos.x, f2.Pos.y, f3.Pos.x, f3.Pos.y);
f3 = f2;
}
SetLineColour(wxColour(200,0,0),2);
DrawLine (f.Pos.x-f.Scale.x, f.Pos.y, f.Pos.x+f.Scale.x+1, f.Pos.y);
DrawLine (f.Pos.x, f.Pos.y-f.Scale.y, f.Pos.x, f.Pos.y+f.Scale.y+1);
f3 = f;
SetLineColour(wxColour(0,255,0),1);
int nFront = 8;
localframe = frame_n - StartFrame;
while( ++localframe<curline->Movement->Frames.size() && nFront-- >0 ) {
FexMovementFrame f2 = curline->Movement->Frames.lVal[localframe];
DrawLine (f2.Pos.x, f2.Pos.y, f3.Pos.x, f3.Pos.y);
f3 = f2;
}
}
}
///////////////////
// Track current line
void VideoDisplayFexTracker::OnVideoTrackPoints(wxCommandEvent &event) {
VideoContext::Get()->Stop();
// Get line
FrameMain *frame = AegisubApp::Get()->frame;
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
FexTrackerConfig config;
DialogFexTracker configDlg (frame, &config);
configDlg.ShowModal();
if (!config.FeatureNumber) return;
// Get Video
VideoProvider *movie = VideoProviderFactory::GetProvider(VideoContext::Get()->videoName);
// Create Tracker
if( curline->Tracker ) delete curline->Tracker;
curline->Tracker = new FexTracker( movie->GetWidth(), movie->GetHeight(), config.FeatureNumber );
curline->Tracker->minFeatures = config.FeatureNumber;
curline->Tracker->Cfg = config;
// Start progress
volatile bool canceled = false;
DialogProgress *progress = new DialogProgress(frame,_("FexTracker"),&canceled,_("Tracking points"),0,1);
progress->Show();
// Allocate temp image
float* FloatImg = new float[ movie->GetWidth()*movie->GetHeight() ];
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
for( int Frame = StartFrame; Frame <= EndFrame; Frame ++ )
{
progress->SetProgress( Frame-StartFrame, EndFrame-StartFrame );
if( canceled ) break;
movie->GetFloatFrame( FloatImg, Frame );
curline->Tracker->ProcessImage( FloatImg );
}
delete FloatImg;
delete movie;
// Clean up progress
if (!canceled)
progress->Destroy();
else
{
delete curline->Tracker;
curline->Tracker = 0;
}
VideoContext::Get()->Refresh(true,false);
}
///////////////////
// Track current line
void VideoDisplayFexTracker::OnVideoTrackMovement(wxCommandEvent &event) {
VideoContext::Get()->Stop();
// Get line
FrameMain *frame = AegisubApp::Get()->frame;
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( !curline->Tracker ) return;
// Create Movement
if( curline->Movement ) DeleteMovement( curline->Movement );
curline->Movement = curline->Tracker->GetMovement();
VideoContext::Get()->Refresh(true,false);
}
///////////////////
// split current line
void VideoDisplayFexTracker::OnVideoTrackSplitLine(wxCommandEvent &event) {
VideoContext::Get()->Stop();
// Get line
FrameMain *frame = AegisubApp::Get()->frame;
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( !curline->Movement ) return;
// Create split lines
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
AssFile *subs = AssFile::top;
int ResXValue,ResYValue;
swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue );
swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue );
int SrcXValue = VideoContext::Get()->GetWidth();
int SrcYValue = VideoContext::Get()->GetHeight();
float sx = float(ResXValue)/float(SrcXValue);
float sy = float(ResYValue)/float(SrcYValue);
for( int Frame = StartFrame; Frame < EndFrame; Frame ++ )
{
int localframe = Frame - StartFrame;
while( curline->Movement->Frames.size() <= localframe ) localframe--;
FexMovementFrame f = curline->Movement->Frames[localframe];
// f.Pos.x /= videoDisplay->GetW
AssDialogue *cur = new AssDialogue( curline->GetEntryData() );
cur->Start.SetMS(VFR_Output.GetTimeAtFrame(Frame,true));
cur->End.SetMS(VFR_Output.GetTimeAtFrame(Frame,false));
cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text;
cur->UpdateData();
frame->SubsBox->InsertLine(cur,frame->EditBox->linen + Frame - StartFrame,true,false);
}
// Remove Movement
DeleteMovement( curline->Movement );
curline->Movement = 0;
// Remove Tracker
delete curline->Tracker;
curline->Tracker = 0;
// Remove this line
frame->SubsBox->DeleteLines(frame->SubsBox->GetRangeArray(frame->EditBox->linen, frame->EditBox->linen));
VideoContext::Get()->Refresh(true,false);
}
///////////////////
// generate empty movement
void VideoDisplayFexTracker::OnVideoTrackMovementEmpty(wxCommandEvent &event) {
// Get line
FrameMain *frame = AegisubApp::Get()->frame;
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
if( curline->Movement ) DeleteMovement( curline->Movement );
curline->Movement = CreateMovement();
// Create split lines
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
FexMovementFrame f;
memset( &f, 0x00, sizeof(f) );
f.Scale.x = f.Scale.y = 1;
for( int i=StartFrame;i<EndFrame;i++ )
curline->Movement->Frames.Add( f );
}
///////////////////
// link line to move file
void VideoDisplayFexTracker::OnVideoTrackLinkFile(wxCommandEvent &event) {
VideoContext::Get()->Stop();
// Get line
FrameMain *frame = AegisubApp::Get()->frame;
AssDialogue *curline = frame->SubsBox->GetDialogue(frame->EditBox->linen);
if (!curline) return;
wxString link = wxGetTextFromUser(_("Link name:"), _("Link line to movement file"), curline->Movement?curline->Movement->FileName:_T(""), frame);
if( link.empty() ) curline->Effect = _T("");
else curline->Effect = _T("FexMovement:")+link;
curline->UpdateData();
if( !curline->Effect.empty() && curline->Movement )
SaveMovement( curline->Movement, curline->Effect.AfterFirst(':').c_str() );
}
//////////////////////
// Increase Influence
void VideoDisplayFexTracker::OnVideoTrackPointAdd(wxCommandEvent &event) {
TrackerEdit = 1;
bTrackerEditing = 0;
}
//////////////////////
// Decrease Influence
void VideoDisplayFexTracker::OnVideoTrackPointDel(wxCommandEvent &event) {
TrackerEdit = -1;
bTrackerEditing = 0;
}
////////////
// Move All
void VideoDisplayFexTracker::OnVideoTrackMovementMoveAll(wxCommandEvent &event) {
MovementEdit = 1;
bTrackerEditing = 0;
}
////////////
// Move One
void VideoDisplayFexTracker::OnVideoTrackMovementMoveOne(wxCommandEvent &event) {
MovementEdit = 2;
bTrackerEditing = 0;
}
///////////////
// Move Before
void VideoDisplayFexTracker::OnVideoTrackMovementMoveBefore(wxCommandEvent &event) {
MovementEdit = 3;
bTrackerEditing = 0;
}
//////////////
// Move After
void VideoDisplayFexTracker::OnVideoTrackMovementMoveAfter(wxCommandEvent &event) {
MovementEdit = 4;
bTrackerEditing = 0;
}
#endif

View file

@ -0,0 +1,79 @@
// Copyright (c) 2005-2007, Rodrigo Braz Monteiro, Hajo Krabbenhöft
// 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
//
#pragma once
///////////
// Headers
#include "gl_wrap.h"
//////////////
// Prototypes
class VideoDisplay;
///////////////////////////////
// Fex tracker video interface
class VideoDisplayFexTracker : public wxEvtHandler, public OpenGLWrapper {
public:
bool bTrackerEditing;
int MovementEdit;
double TrackerEdit;
int MouseDownX, MouseDownY;
VideoDisplay *parent;
VideoDisplayFexTracker(VideoDisplay *parent);
void OnMouseEvent(wxMouseEvent &event);
void Render();
void OnVideoTrackPoints(wxCommandEvent &event);
void OnVideoTrackPointAdd(wxCommandEvent &event);
void OnVideoTrackPointDel(wxCommandEvent &event);
void OnVideoTrackMovement(wxCommandEvent &event);
void OnVideoTrackMovementMoveAll(wxCommandEvent &event);
void OnVideoTrackMovementMoveOne(wxCommandEvent &event);
void OnVideoTrackMovementMoveBefore(wxCommandEvent &event);
void OnVideoTrackMovementMoveAfter(wxCommandEvent &event);
void OnVideoTrackSplitLine(wxCommandEvent &event);
void OnVideoTrackLinkFile(wxCommandEvent &event);
void OnVideoTrackMovementEmpty(wxCommandEvent &event);
DECLARE_EVENT_TABLE()
};

View file

@ -36,8 +36,11 @@
//////////////
// Headers
#include <wx/glcanvas.h>
#include <GL/glu.h>
#include <wx/wxprec.h>
#include "video_display_visual.h"
#include "video_display_fextracker.h"
#include "video_display.h"
#include "video_provider.h"
#include "vfr.h"
@ -51,18 +54,12 @@
#include "subs_edit_box.h"
#include "export_visible_lines.h"
#include "utils.h"
#if USE_FEXTRACKER == 1
#include "../FexTrackerSource/FexTracker.h"
#include "../FexTrackerSource/FexTrackingFeature.h"
#include "../FexTrackerSource/FexMovement.h"
#endif
///////////////
// Constructor
VideoDisplayVisual::VideoDisplayVisual(VideoDisplay *par) {
parent = par;
backbuffer = NULL;
curSelection = NULL;
holding = false;
mode = -1;
@ -77,7 +74,6 @@ VideoDisplayVisual::VideoDisplayVisual(VideoDisplay *par) {
//////////////
// Destructor
VideoDisplayVisual::~VideoDisplayVisual() {
delete backbuffer;
}
@ -110,36 +106,23 @@ void VideoDisplayVisual::SetMode(int _mode) {
// Draw overlay
void VideoDisplayVisual::DrawOverlay() {
// Variables
int frame_n = VideoContext::Get()->GetFrameN();
int w,h;
parent->GetClientSize(&w,&h);
int sw,sh;
VideoContext::Get()->GetScriptSize(sw,sh);
int x = mouseX;
int y = mouseY;
int w = parent->w;
int h = parent->h;
int frame_n = parent->frame_n;
int sw,sh;
parent->GetScriptSize(sw,sh);
// Create backbuffer if needed
bool needCreate = false;
if (!backbuffer) needCreate = true;
else if (backbuffer->GetWidth() != w || backbuffer->GetHeight() != h) {
needCreate = true;
delete backbuffer;
}
if (needCreate) backbuffer = new wxBitmap(w,h);
// Prepare drawing
wxMemoryDC dc;
dc.SelectObject(*backbuffer);
// Draw frame
dc.DrawBitmap(parent->GetFrame(frame_n),0,0);
int mx = mouseX * sw / w;
int my = mouseY * sh / h;
// Draw the control points for FexTracker
DrawTrackingOverlay(dc);
glDisable(GL_TEXTURE_2D);
parent->tracker->Render();
// Draw lines
if (mode != 0) {
int numRows = parent->grid->GetRows();
int numRows = VideoContext::Get()->grid->GetRows();
AssDialogue *diag;
AssDialogue *diagHigh = NULL;
@ -147,7 +130,7 @@ void VideoDisplayVisual::DrawOverlay() {
if (mode == 1) {
int dx,dy;
for (int i=0;i<numRows;i++) {
diag = parent->grid->GetDialogue(i);
diag = VideoContext::Get()->grid->GetDialogue(i);
if (diag) {
if (VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true) <= frame_n && VFR_Output.GetFrameAtTime(diag->End.GetMS(),false) >= frame_n) {
GetLinePosition(diag,dx,dy);
@ -163,7 +146,7 @@ void VideoDisplayVisual::DrawOverlay() {
// For each line
for (int i=0;i<numRows;i++) {
diag = parent->grid->GetDialogue(i);
diag = VideoContext::Get()->grid->GetDialogue(i);
if (diag) {
// Draw?
bool draw = false;
@ -172,7 +155,7 @@ void VideoDisplayVisual::DrawOverlay() {
bool timeVisible = VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true) <= frame_n && VFR_Output.GetFrameAtTime(diag->End.GetMS(),false) >= frame_n;
bool show = timeVisible;
if (mode != 1) {
show = diag == parent->grid->GetDialogue(parent->grid->editBox->linen) && timeVisible;
show = diag == VideoContext::Get()->grid->GetDialogue(VideoContext::Get()->grid->editBox->linen) && timeVisible;
}
// Variables
@ -198,6 +181,13 @@ void VideoDisplayVisual::DrawOverlay() {
}
else GetLinePosition(diag,dx,dy,orgx,orgy);
// Get scale
if (isCur && mode == 4) {
scalX = curScaleX;
scalY = curScaleY;
}
else GetLineScale(diag,scalX,scalY);
// Mouse over?
if (diag == diagHigh) {
high = true;
@ -206,21 +196,20 @@ void VideoDisplayVisual::DrawOverlay() {
// Highlight
int brushCol = 1;
if (high) brushCol = 2;
dc.SetBrush(wxBrush(colour[brushCol]));
dc.SetPen(wxPen(colour[0],1));
SetLineColour(colour[0]);
SetFillColour(colour[brushCol],0.3f);
// Set drawing coordinates
int radius = (int) sqrt(double((dx-orgx)*(dx-orgx)+(dy-orgy)*(dy-orgy)));
dx = dx * w / sw;
dy = dy * h / sh;
orgx = orgx * w / sw;
orgy = orgy * h / sh;
// Drag
if (mode == 1) {
dc.DrawRectangle(dx-8,dy-8,17,17);
dc.DrawLine(dx,dy-16,dx,dy+16);
dc.DrawLine(dx-16,dy,dx+16,dy);
SetFillColour(colour[brushCol],0.5f);
DrawRectangle(dx-8,dy-8,dx+8,dy+8);
SetLineColour(colour[2]);
SetModeLine();
DrawLine(dx,dy-16,dx,dy+16);
DrawLine(dx-16,dy,dx+16,dy);
}
// Rotation
@ -232,11 +221,12 @@ void VideoDisplayVisual::DrawOverlay() {
dy = orgy;
// Draw pivot
dc.DrawCircle(dx,dy,7);
dc.DrawLine(dx,dy-16,dx,dy+16);
dc.DrawLine(dx-16,dy,dx+16,dy);
DrawCircle(dx,dy,7);
DrawLine(dx,dy-16,dx,dy+16);
DrawLine(dx-16,dy,dx+16,dy);
// Get angle
GetLineRotation(diag,rx,ry,rz);
if (isCur) {
if (mode == 2) rz = curAngle;
else {
@ -244,126 +234,233 @@ void VideoDisplayVisual::DrawOverlay() {
ry = curAngle2;
}
}
else GetLineRotation(diag,rx,ry,rz);
// Rotate Z
if (mode == 2) {
// Transform
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(dx,dy,-1.0f);
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
glMultMatrixf(matrix);
glScalef(1.0f,1.0f,8.0f);
glRotatef(ry,0.0f,-1.0f,0.0f);
glRotatef(rx,-1.0f,0.0f,0.0f);
glScalef(scalX/100.0f,scalY/100.0f,1.0f);
// Calculate radii
int oRadiusX = radius * w / sw;
int oRadiusY = radius * h / sh;
int oRadius = radius;
if (radius < 50) radius = 50;
int radiusX = radius * w / sw;
int radiusY = radius * h / sh;
// Draw the circle
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawEllipse(dx-radiusX-2,dy-radiusY-2,2*radiusX+4,2*radiusY+4);
dc.DrawEllipse(dx-radiusX+2,dy-radiusY+2,2*radiusX-4,2*radiusY-4);
SetLineColour(colour[0]);
SetFillColour(colour[1],0.3f);
DrawRing(0,0,radius+4,radius-4);
// Draw line to mouse
dc.DrawLine(dx,dy,mouseX,mouseY);
// Draw markers around circle
int markers = 6;
float markStart = -90.0f / markers;
float markEnd = markStart+(180.0f/markers);
for (int i=0;i<markers;i++) {
float angle = i*(360.0f/markers);
DrawRing(0,0,radius+30,radius+12,radius/radius,angle+markStart,angle+markEnd);
}
// Get deltas
deltax = int(cos(rz*3.1415926536/180.0)*radiusX);
deltay = int(-sin(rz*3.1415926536/180.0)*radiusY);
deltax = int(cos(rz*3.1415926536/180.0)*radius);
deltay = int(-sin(rz*3.1415926536/180.0)*radius);
// Draw the baseline
dc.SetPen(wxPen(colour[3],2));
dc.DrawLine(dx+deltax,dy+deltay,dx-deltax,dy-deltay);
SetLineColour(colour[3],1.0f,2);
DrawLine(deltax,deltay,-deltax,-deltay);
// Draw the connection line
if (orgx != odx && orgy != ody) {
double angle = atan2(double(dy*sh/h-ody*sh/h),double(odx*sw/w-dx*sw/w)) + rz*3.1415926536/180.0;
int fx = dx+int(cos(angle)*oRadiusX);
int fy = dy-int(sin(angle)*oRadiusY);
dc.DrawLine(dx,dy,fx,fy);
//double angle = atan2(double(dy*sh/h-ody*sh/h),double(odx*sw/w-dx*sw/w)) + rz*3.1415926536/180.0;
double angle = atan2(double(dy-ody),double(odx-dx)) + rz*3.1415926536/180.0;
int fx = int(cos(angle)*oRadius);
int fy = -int(sin(angle)*oRadius);
DrawLine(0,0,fx,fy);
int mdx = cos(rz*3.1415926536/180.0)*20;
int mdy = -sin(rz*3.1415926536/180.0)*20;
dc.DrawLine(fx-mdx,fy-mdy,fx+mdx,fy+mdy);
DrawLine(-mdx,-mdy,mdx,mdy);
}
// Draw the rotation line
dc.SetPen(wxPen(colour[0],1));
dc.SetBrush(wxBrush(colour[brushCol]));
dc.DrawCircle(dx+deltax,dy+deltay,4);
SetLineColour(colour[0],1.0f,1);
SetFillColour(colour[brushCol],0.3f);
DrawCircle(deltax,deltay,4);
// Restore
glPopMatrix();
// Draw line to mouse
SetLineColour(colour[0]);
DrawLine(dx,dy,mx,my);
}
// Rotate XY
if (mode == 3) {
// Calculate radii
if (radius < 80) radius = 80;
int radius1X = radius * w / sw / 3;
int radius1Y = radius * h / sh;
int radius2X = radius * w / sw;
int radius2Y = radius * h / sh / 3;
// Transform grid
glPushMatrix();
glLoadIdentity();
glTranslatef(dx,dy,0.0f);
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
glMultMatrixf(matrix);
glScalef(1.0f,1.0f,8.0f);
glRotatef(ry,0.0f,-1.0f,0.0f);
glRotatef(rx,-1.0f,0.0f,0.0f);
glRotatef(rz,0.0f,0.0f,-1.0f);
// Draw the ellipses
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawEllipse(dx-radius1X-2,dy-radius1Y-2,2*radius1X+4,2*radius1Y+4);
dc.DrawEllipse(dx-radius1X+2,dy-radius1Y+2,2*radius1X-4,2*radius1Y-4);
dc.DrawEllipse(dx-radius2X-2,dy-radius2Y-2,2*radius2X+4,2*radius2Y+4);
dc.DrawEllipse(dx-radius2X+2,dy-radius2Y+2,2*radius2X-4,2*radius2Y-4);
//glScalef(0.125f,0.125f,0.125f);
//glTranslatef(8*dx,8*dy,0.0f);
//float matrix[16] = { 20000, 0, 0, 0, 0, 20000, 0, 0, 0, 0, 1, 1, 0, 0, 20000, 20000 };
//glMultMatrixf(matrix);
//glScalef(1.0f,1.0f,8.0f);
//glRotatef(ry,0.0f,-1.0f,0.0f);
//glRotatef(rx,-1.0f,0.0f,0.0f);
//glRotatef(rz,0.0f,0.0f,-1.0f);
//glScalef(8.0f,8.0f,8.0f);
// Draw line to mouse
dc.DrawLine(dx,dy,mouseX,mouseY);
dc.SetBrush(wxBrush(colour[brushCol]));
// Draw grid
glShadeModel(GL_SMOOTH);
SetLineColour(colour[0],0.5f,1);
SetModeLine();
float r = colour[0].Red()/255.0f;
float g = colour[0].Green()/255.0f;
float b = colour[0].Blue()/255.0f;
glBegin(GL_LINES);
for (int i=0;i<11;i++) {
float a = 1.0f - abs(i-5)*0.18f;
int pos = 20*(i-5);
glColor4f(r,g,b,0.0f);
glVertex2i(pos,120);
glColor4f(r,g,b,a);
glVertex2i(pos,0);
glVertex2i(pos,0);
glColor4f(r,g,b,0.0f);
glVertex2i(pos,-120);
glVertex2i(120,pos);
glColor4f(r,g,b,a);
glVertex2i(0,pos);
glVertex2i(0,pos);
glColor4f(r,g,b,0.0f);
glVertex2i(-120,pos);
}
glEnd();
// Draw Y baseline
deltax = int(cos(ry*3.1415926536/180.0)*radius2X);
deltay = int(-sin(ry*3.1415926536/180.0)*radius2Y);
dc.SetPen(wxPen(colour[3],2));
dc.DrawLine(dx+deltax,dy+deltay,dx-deltax,dy-deltay);
dc.SetPen(wxPen(colour[0],1));
dc.DrawCircle(dx+deltax,dy+deltay,4);
// Draw vectors
SetLineColour(colour[3],1.0f,2);
SetModeLine();
glBegin(GL_LINES);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(50.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,-50.0f,0.0f);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(0.0f,0.0f,-50.0f);
glEnd();
// Draw X baseline
deltax = int(cos(rx*3.1415926536/180.0)*radius1X);
deltay = int(-sin(rx*3.1415926536/180.0)*radius1Y);
dc.SetPen(wxPen(colour[3],2));
dc.DrawLine(dx+deltax,dy+deltay,dx-deltax,dy-deltay);
dc.SetPen(wxPen(colour[0],1));
dc.DrawCircle(dx+deltax,dy+deltay,4);
// Draw arrow tops
glBegin(GL_TRIANGLE_FAN);
glVertex3f(60.0f,0.0f,0.0f);
glVertex3f(50.0f,-3.0f,-3.0f);
glVertex3f(50.0f,3.0f,-3.0f);
glVertex3f(50.0f,3.0f,3.0f);
glVertex3f(50.0f,-3.0f,3.0f);
glVertex3f(50.0f,-3.0f,-3.0f);
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f,-60.0f,0.0f);
glVertex3f(-3.0f,-50.0f,-3.0f);
glVertex3f(3.0f,-50.0f,-3.0f);
glVertex3f(3.0f,-50.0f,3.0f);
glVertex3f(-3.0f,-50.0f,3.0f);
glVertex3f(-3.0f,-50.0f,-3.0f);
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f,0.0f,-60.0f);
glVertex3f(-3.0f,-3.0f,-50.0f);
glVertex3f(3.0f,-3.0f,-50.0f);
glVertex3f(3.0f,3.0f,-50.0f);
glVertex3f(-3.0f,3.0f,-50.0f);
glVertex3f(-3.0f,-3.0f,-50.0f);
glEnd();
// Restore gl's state
glPopMatrix();
glShadeModel(GL_FLAT);
//// Calculate radii
//if (radius < 80) radius = 80;
//int radius1X = radius * w / sw / 3;
//int radius1Y = radius * h / sh;
//int radius2X = radius * w / sw;
//int radius2Y = radius * h / sh / 3;
//// Draw the ellipses
//dc.SetBrush(*wxTRANSPARENT_BRUSH);
//dc.DrawEllipse(dx-radius1X-2,dy-radius1Y-2,2*radius1X+4,2*radius1Y+4);
//dc.DrawEllipse(dx-radius1X+2,dy-radius1Y+2,2*radius1X-4,2*radius1Y-4);
//dc.DrawEllipse(dx-radius2X-2,dy-radius2Y-2,2*radius2X+4,2*radius2Y+4);
//dc.DrawEllipse(dx-radius2X+2,dy-radius2Y+2,2*radius2X-4,2*radius2Y-4);
//// Draw line to mouse
//dc.DrawLine(dx,dy,mouseX,mouseY);
//dc.SetBrush(wxBrush(colour[brushCol]));
//// Draw Y baseline
//deltax = int(cos(ry*3.1415926536/180.0)*radius2X);
//deltay = int(-sin(ry*3.1415926536/180.0)*radius2Y);
//dc.SetPen(wxPen(colour[3],2));
//dc.DrawLine(dx+deltax,dy+deltay,dx-deltax,dy-deltay);
//dc.SetPen(wxPen(colour[0],1));
//dc.DrawCircle(dx+deltax,dy+deltay,4);
//// Draw X baseline
//deltax = int(cos(rx*3.1415926536/180.0)*radius1X);
//deltay = int(-sin(rx*3.1415926536/180.0)*radius1Y);
//dc.SetPen(wxPen(colour[3],2));
//dc.DrawLine(dx+deltax,dy+deltay,dx-deltax,dy-deltay);
//dc.SetPen(wxPen(colour[0],1));
//dc.DrawCircle(dx+deltax,dy+deltay,4);
}
}
// Scale
if (mode == 4) {
// Get scale
if (isCur) {
scalX = curScaleX;
scalY = curScaleY;
}
else GetLineScale(diag,scalX,scalY);
// Scale parameters
int len = 160;
int lenx = int(1.6 * scalX);
int leny = int(1.6 * scalY);
dx = MID(len/2+10,dx,sw-len/2-30);
dy = MID(len/2+10,dy,sh-len/2-30);
int drawX = dx + len/2 + 10;
int drawY = dy + len/2 + 10;
// Draw length markers
dc.SetPen(wxPen(colour[3],2));
dc.DrawLine(dx-lenx/2,drawY+10,dx+lenx/2,drawY+10);
dc.DrawLine(drawX+10,dy-leny/2,drawX+10,dy+leny/2);
dc.SetPen(wxPen(colour[0],1));
dc.SetBrush(wxBrush(colour[brushCol]));
dc.DrawCircle(dx+lenx/2,drawY+10,4);
dc.DrawCircle(drawX+10,dy-leny/2,4);
SetLineColour(colour[3],1.0f,2);
DrawLine(dx-lenx/2,drawY+10,dx+lenx/2,drawY+10);
DrawLine(drawX+10,dy-leny/2,drawX+10,dy+leny/2);
SetLineColour(colour[0],1.0f,1);
SetFillColour(colour[brushCol],0.3f);
DrawCircle(dx+lenx/2,drawY+10,4);
DrawCircle(drawX+10,dy-leny/2,4);
// Draw horizontal scale
dc.SetPen(wxPen(colour[0],1));
dc.DrawRectangle(dx-len/2,drawY,len+1,5);
dc.SetPen(wxPen(colour[0],2));
dc.DrawLine(dx-len/2+1,drawY+5,dx-len/2+1,drawY+15);
dc.DrawLine(dx+len/2,drawY+5,dx+len/2,drawY+15);
SetLineColour(colour[0],1.0f,1);
DrawRectangle(dx-len/2,drawY,dx+len/2+1,drawY+5);
SetLineColour(colour[0],1.0f,2);
DrawLine(dx-len/2+1,drawY+5,dx-len/2+1,drawY+15);
DrawLine(dx+len/2,drawY+5,dx+len/2,drawY+15);
// Draw vertical scale
dc.SetPen(wxPen(colour[0],1));
dc.DrawRectangle(drawX,dy-len/2,5,len+1);
dc.SetPen(wxPen(colour[0],2));
dc.DrawLine(drawX+5,dy-len/2+1,drawX+15,dy-len/2+1);
dc.DrawLine(drawX+5,dy+len/2,drawX+15,dy+len/2);
SetLineColour(colour[0],1.0f,1);
DrawRectangle(drawX,dy-len/2,drawX+5,dy+len/2+1);
SetLineColour(colour[0],1.0f,2);
DrawLine(drawX+5,dy-len/2+1,drawX+15,dy-len/2+1);
DrawLine(drawX+5,dy+len/2,drawX+15,dy+len/2);
}
// Clip
@ -372,31 +469,40 @@ void VideoDisplayVisual::DrawOverlay() {
// Get position
if (isCur) {
dx1 = startX;
dy1 = startY;
dx2 = x;
dy2 = y;
}
else {
GetLineClip(diag,dx1,dy1,dx2,dy2);
dx1 = dx1 * w / sw;
dx2 = dx2 * w / sw;
dy1 = dy1 * h / sh;
dy2 = dy2 * h / sh;
dx1 = startX * sw / w;
dy1 = startY * sh / h;
dx2 = mx;
dy2 = my;
}
else GetLineClip(diag,dx1,dy1,dx2,dy2);
// Swap
if (dx1 > dx2) IntSwap(dx1,dx2);
if (dy1 > dy2) IntSwap(dy1,dy2);
// Draw rectangle
dc.SetPen(wxPen(colour[3],1));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(dx1,dy1,dx2-dx1+1,dy2-dy1+1);
SetLineColour(colour[3]);
SetFillColour(colour[3],0.0f);
DrawRectangle(dx1,dy1,dx2,dy2);
// Draw outside area
SetLineColour(colour[3],0.0f);
SetFillColour(colour[3],0.3f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
DrawRectangle(0,0,sw,dy1);
DrawRectangle(0,dy2,sw,sh);
DrawRectangle(0,dy1,dx1,dy2);
DrawRectangle(dx2,dy1,sw,dy2);
glDisable(GL_BLEND);
// Draw circles
dc.SetPen(wxPen(colour[0],1));
dc.SetBrush(wxBrush(colour[brushCol]));
dc.DrawCircle(dx1,dy1,4);
dc.DrawCircle(dx1,dy2,4);
dc.DrawCircle(dx2,dy1,4);
dc.DrawCircle(dx2,dy2,4);
SetLineColour(colour[0]);
SetFillColour(colour[1],0.5);
DrawCircle(dx1,dy1,4);
DrawCircle(dx2,dy1,4);
DrawCircle(dx2,dy2,4);
DrawCircle(dx1,dy2,4);
}
}
}
@ -406,42 +512,43 @@ void VideoDisplayVisual::DrawOverlay() {
// Current position info
if (mode == 0 && x >= 0 && x < w && y >= 0 && y < h) {
// Draw cross
dc.SetPen(wxPen(colour[2],1));
dc.SetLogicalFunction(wxINVERT);
dc.DrawLine(0,y,w-1,y);
dc.DrawLine(x,0,x,h-1);
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_INVERT);
glBegin(GL_LINES);
glColor3f(1.0f,1.0f,1.0f);
glVertex2f(0,my);
glVertex2f(sw,my);
glVertex2f(mx,0);
glVertex2f(mx,sh);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
// Setup text
wxFont font(10,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_BOLD,false,_T("Verdana"));
dc.SetFont(font);
int tw,th;
parent->GetTextExtent(mouseText,&tw,&th,NULL,NULL,&font);
//// Setup text
//wxFont font(10,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_BOLD,false,_T("Verdana"));
//dc.SetFont(font);
//int tw,th;
//parent->GetTextExtent(mouseText,&tw,&th,NULL,NULL,&font);
// Inversion
bool left = x > w/2;
bool bottom = y < h/2;
//// Inversion
//bool left = x > w/2;
//bool bottom = y < h/2;
// Text draw coords
int dx = x,dy = y;
if (left) dx -= tw + 4;
else dx += 4;
if (bottom) dy += 3;
else dy -= th + 3;
//// Text draw coords
//int dx = x,dy = y;
//if (left) dx -= tw + 4;
//else dx += 4;
//if (bottom) dy += 3;
//else dy -= th + 3;
// Draw text
dc.SetTextForeground(wxColour(64,64,64));
dc.DrawText(mouseText,dx+1,dy-1);
dc.DrawText(mouseText,dx+1,dy+1);
dc.DrawText(mouseText,dx-1,dy-1);
dc.DrawText(mouseText,dx-1,dy+1);
dc.SetTextForeground(colour[2]);
dc.DrawText(mouseText,dx,dy);
//// Draw text
//dc.SetTextForeground(wxColour(64,64,64));
//dc.DrawText(mouseText,dx+1,dy-1);
//dc.DrawText(mouseText,dx+1,dy+1);
//dc.DrawText(mouseText,dx-1,dy-1);
//dc.DrawText(mouseText,dx-1,dy+1);
//dc.SetTextForeground(colour[2]);
//dc.DrawText(mouseText,dx,dy);
}
// Blit to screen
wxClientDC dcScreen(parent);
//dcScreen.DrawBitmap(backbuffer,0,0);
dcScreen.Blit(0,0,w,h,&dc,0,0);
}
@ -465,7 +572,7 @@ void VideoDisplayVisual::GetLinePosition(AssDialogue *diag,int &x, int &y, int &
int align = 2;
// Get style
AssStyle *style = parent->grid->ass->GetStyle(diag->Style);
AssStyle *style = VideoContext::Get()->grid->ass->GetStyle(diag->Style);
if (style) {
align = style->alignment;
for (int i=0;i<4;i++) {
@ -475,7 +582,7 @@ void VideoDisplayVisual::GetLinePosition(AssDialogue *diag,int &x, int &y, int &
// Script size
int sw,sh;
parent->GetScriptSize(sw,sh);
VideoContext::Get()->GetScriptSize(sw,sh);
// Process margins
margin[3] = margin[2];
@ -644,7 +751,7 @@ void VideoDisplayVisual::GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,i
// Default values
x1 = y1 = 0;
int sw,sh;
parent->GetScriptSize(sw,sh);
VideoContext::Get()->GetScriptSize(sw,sh);
x2 = sw-1;
y2 = sh-1;
@ -675,159 +782,25 @@ void VideoDisplayVisual::GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,i
}
//////////////////
// Draw Tracking Overlay
void VideoDisplayVisual::DrawTrackingOverlay( wxDC &dc )
{
#if USE_FEXTRACKER == 1
int frame_n = parent->frame_n;
VideoProvider *provider = parent->provider;
if( parent->IsPlaying ) return;
// Get line
AssDialogue *curline = parent->grid->GetDialogue(parent->grid->editBox->linen);
if( !curline ) return;
int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
if( frame_n<StartFrame || frame_n>EndFrame ) return;
int localframe = frame_n - StartFrame;
if( curline->Tracker )
{
if( curline->Tracker->GetFrame() <= localframe ) return;
dc.SetLogicalFunction(wxCOPY);
for( int i=0;i<curline->Tracker->GetCount();i++ )
{
FexTrackingFeature* f = (*curline->Tracker)[i];
if( f->StartTime > localframe ) continue;
int llf = localframe - f->StartTime;
if( f->Pos.size() <= llf ) continue;
vec2 pt = f->Pos[llf];
pt.x *= provider->GetZoom();
pt.y *= provider->GetZoom();
pt.x = int(pt.x);
pt.y = int(pt.y);
dc.SetPen(wxPen(wxColour(255*(1-f->Influence),255*f->Influence,0),1));
dc.DrawLine( pt.x-2, pt.y, pt.x, pt.y );
dc.DrawLine( pt.x, pt.y-2, pt.x, pt.y );
dc.DrawLine( pt.x+1, pt.y, pt.x+3, pt.y );
dc.DrawLine( pt.x, pt.y+1, pt.x, pt.y+3 );
}
}
if( curline->Movement )
{
if( curline->Movement->Frames.size() <= localframe ) return;
dc.SetPen(wxPen(colour[0],2));
FexMovementFrame f = curline->Movement->Frames.lVal[localframe];
f.Pos.x *= provider->GetZoom();
f.Pos.y *= provider->GetZoom();
f.Scale.x *= 30* provider->GetZoom();
f.Scale.y *= 30* provider->GetZoom();
FexMovementFrame f3 = f;
dc.SetPen(wxPen(wxColour(0,0,255),1));
int nBack = 8;
while( --localframe>0 && nBack-- >0 )
{
FexMovementFrame f2 = curline->Movement->Frames.lVal[localframe];
f2.Pos.x *= provider->GetZoom();
f2.Pos.y *= provider->GetZoom();
dc.DrawLine( f2.Pos.x, f2.Pos.y, f3.Pos.x, f3.Pos.y );
f3 = f2;
}
dc.SetPen(wxPen(colour[0],2));
dc.DrawLine( f.Pos.x-f.Scale.x, f.Pos.y, f.Pos.x+f.Scale.x+1, f.Pos.y );
dc.DrawLine( f.Pos.x, f.Pos.y-f.Scale.y, f.Pos.x, f.Pos.y+f.Scale.y+1 );
f3 = f;
dc.SetPen(wxPen(wxColour(0,255,0),1));
int nFront = 8;
localframe = frame_n - StartFrame;
while( ++localframe<curline->Movement->Frames.size() && nFront-- >0 )
{
FexMovementFrame f2 = curline->Movement->Frames.lVal[localframe];
f2.Pos.x *= provider->GetZoom();
f2.Pos.y *= provider->GetZoom();
dc.DrawLine( f2.Pos.x, f2.Pos.y, f3.Pos.x, f3.Pos.y );
f3 = f2;
}
}
#endif
}
///////////////
// Mouse event
void VideoDisplayVisual::OnMouseEvent (wxMouseEvent &event) {
// Coords
int x = event.GetX();
int y = event.GetY();
int w = parent->w;
int h = parent->h;
int w,h;
parent->GetClientSize(&w,&h);
int orgx = -1;
int orgy = -1;
int sw,sh;
parent->GetScriptSize(sw,sh);
int frame_n = parent->frame_n;
VideoProvider *provider = parent->provider;
SubtitlesGrid *grid = parent->grid;
VideoContext::Get()->GetScriptSize(sw,sh);
int mx = x * VideoContext::Get()->GetWidth() / w;
int my = y * VideoContext::Get()->GetHeight() / h;
int frame_n = VideoContext::Get()->GetFrameN();
SubtitlesGrid *grid = VideoContext::Get()->grid;
bool hasOverlay = false;
bool realTime = Options.AsBool(_T("Video Visual Realtime"));
// FexTracker
#if USE_FEXTRACKER == 1
if( event.ButtonDown(wxMOUSE_BTN_LEFT) ) {
parent->MouseDownX = x;
parent->MouseDownY = y;
parent->bTrackerEditing = 1;
}
if( event.ButtonUp(wxMOUSE_BTN_LEFT) ) parent->bTrackerEditing = 0;
// Do tracker influence if needed
if( parent->bTrackerEditing ) {
AssDialogue *curline = parent->grid->GetDialogue(parent->grid->editBox->linen);
int StartFrame, EndFrame, localframe;
if( curline && (StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true)) <= frame_n && (EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false)) >= frame_n ) {
localframe = frame_n - StartFrame;
if( parent->TrackerEdit!=0 && curline->Tracker && localframe < curline->Tracker->GetFrame() ) curline->Tracker->InfluenceFeatures( localframe, float(x)/provider->GetZoom(), float(y)/provider->GetZoom(), parent->TrackerEdit );
if( parent->MovementEdit!=0 && curline->Movement && localframe < curline->Movement->Frames.size() ) {// no /provider->GetZoom() to improve precision
if( parent->MovementEdit==1 ) {
for( int i=0;i<curline->Movement->Frames.size();i++ ) {
curline->Movement->Frames[i].Pos.x += float(x-parent->MouseDownX);
curline->Movement->Frames[i].Pos.y += float(y-parent->MouseDownY);
}
}
else if( parent->MovementEdit==2 ) {
curline->Movement->Frames[localframe].Pos.x += float(x-parent->MouseDownX);
curline->Movement->Frames[localframe].Pos.y += float(y-parent->MouseDownY);
}
else if( parent->MovementEdit==3 ) {
for( int i=0;i<=localframe;i++ ) {
curline->Movement->Frames[i].Pos.x += float(x-parent->MouseDownX);
curline->Movement->Frames[i].Pos.y += float(y-parent->MouseDownY);
}
}
else if( parent->MovementEdit==4 ) {
for( int i=localframe;i<curline->Movement->Frames.size();i++ ) {
curline->Movement->Frames[i].Pos.x += float(x-parent->MouseDownX);
curline->Movement->Frames[i].Pos.y += float(y-parent->MouseDownY);
}
}
}
parent->MouseDownX = x;
parent->MouseDownY = y;
}
}
#endif
parent->tracker->OnMouseEvent(event);
// Text of current coords
int vx = (sw * x + w/2) / w;
@ -843,14 +816,14 @@ void VideoDisplayVisual::OnMouseEvent (wxMouseEvent &event) {
// Drag
if (mode == 1) {
// For each line
int numRows = parent->grid->GetRows();
int numRows = VideoContext::Get()->grid->GetRows();
int startMs = VFR_Output.GetTimeAtFrame(frame_n,true);
int endMs = VFR_Output.GetTimeAtFrame(frame_n,false);
AssDialogue *diag;
// Don't uninvert this loop or selection will break
for (int i=numRows;--i>=0;) {
diag = parent->grid->GetDialogue(i);
diag = VideoContext::Get()->grid->GetDialogue(i);
if (diag) {
// Line visible?
int f1 = VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true);
@ -867,7 +840,7 @@ void VideoDisplayVisual::OnMouseEvent (wxMouseEvent &event) {
// Mouse over?
if (x >= lineX-8 && x <= lineX+8 && y >= lineY-8 && y <= lineY+8) {
parent->grid->editBox->SetToLine(i,true);
VideoContext::Get()->grid->editBox->SetToLine(i,true);
gotDiag = diag;
origX = lineX;
origY = lineY;
@ -883,7 +856,7 @@ void VideoDisplayVisual::OnMouseEvent (wxMouseEvent &event) {
// Pick active line
else {
// Get active
gotDiag = parent->grid->GetDialogue(parent->grid->editBox->linen);
gotDiag = VideoContext::Get()->grid->GetDialogue(VideoContext::Get()->grid->editBox->linen);
// Check if it's within range
if (gotDiag) {
@ -1161,7 +1134,8 @@ void VideoDisplayVisual::OnMouseEvent (wxMouseEvent &event) {
// Has something to draw
if (hasOverlay) {
DrawOverlay();
//DrawOverlay();
parent->Render();
}
}

View file

@ -37,6 +37,11 @@
#pragma once
///////////
// Headers
#include "gl_wrap.h"
//////////////
// Prototypes
class VideoDisplay;
@ -45,7 +50,7 @@ class AssDialogue;
////////////////////////
// Visual handler class
class VideoDisplayVisual {
class VideoDisplayVisual : public OpenGLWrapper {
friend class VideoDisplay;
private:
@ -64,10 +69,8 @@ private:
int hold;
bool holding;
wxBitmap *backbuffer;
wxString mouseText;
AssDialogue *curSelection;
VideoDisplay *parent;
void GetLinePosition(AssDialogue *diag,int &x,int &y);
@ -76,7 +79,6 @@ private:
void GetLineScale(AssDialogue *diag,float &scalX,float &scalY);
void GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2);
void DrawTrackingOverlay(wxDC &dc);
void DrawOverlay();
void OnMouseEvent(wxMouseEvent &event);
void OnKeyEvent(wxKeyEvent &event);

212
aegisub/video_frame.cpp Normal file
View file

@ -0,0 +1,212 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "video_frame.h"
///////////////
// Constructor
AegiVideoFrame::AegiVideoFrame() {
for (int i=0;i<4;i++) {
data[i] = NULL;
pitch[i] = 0;
memSize[i] = 0;
}
w = 0;
h = 0;
format = FORMAT_RGB24;
flipped = false;
cppAlloc = true;
invertChannels = true;
}
//////////////////
// Create default
AegiVideoFrame::AegiVideoFrame(int width,int height,VideoFrameFormat fmt) {
AegiVideoFrame();
format = fmt;
w = width;
h = height;
pitch[0] = w;
Allocate();
for (int i=0;i<4;i++) {
int height = h;
if (format == FORMAT_YV12 && i > 0) height/=2;
int size = pitch[i]*height;
memset(data[0],0,size);
}
}
////////////
// Allocate
void AegiVideoFrame::Allocate() {
for (int i=0;i<4;i++) {
// Get size
int height = h;
if (format == FORMAT_YV12 && i > 0) height/=2;
int size = pitch[i]*height;
// Reallocate, if necessary
if (memSize[i] != size) {
if (cppAlloc) delete[] data[i];
else free(data[i]);
data[i] = new unsigned char[size];
memSize[i] = size;
}
}
cppAlloc = true;
}
/////////
// Clear
void AegiVideoFrame::Clear() {
for (int i=0;i<4;i++) {
if (data[i]) {
if (cppAlloc) delete[] data[i];
else free(data[i]);
data[i] = NULL;
}
pitch[i] = 0;
}
w = 0;
h = 0;
format = FORMAT_RGB24;
flipped = false;
cppAlloc = true;
invertChannels = true;
}
///////////////
// Create copy
void AegiVideoFrame::CopyFrom(const AegiVideoFrame &source) {
w = source.w;
h = source.h;
format = source.format;
for (int i=0;i<4;i++) pitch[i] = source.pitch[i];
Allocate();
for (int i=0;i<4;i++) {
memcpy(data[i],source.data[i],memSize[i]);
}
flipped = source.flipped;
invertChannels = source.invertChannels;
}
///////////////
// Get wxImage
// ------
// This function is only used on screenshots, so it doesn't have to be fast
wxImage AegiVideoFrame::GetImage() const {
if (format == FORMAT_RGB32 || format == FORMAT_RGB24) {
// Create
unsigned char *buf = (unsigned char*)malloc(w*h*3);
const unsigned char *src = data[0];
unsigned char *dst = buf;
// Bytes per pixel
int Bpp = GetBpp();
// Convert
for (unsigned int y=0;y<h;y++) {
dst = buf + y*w*3;
if (flipped) src = data[0] + (h-y-1)*pitch[0];
else src = data[0] + y*pitch[0];
for (unsigned int x=0;x<w;x++) {
*dst++ = *(src+2);
*dst++ = *(src+1);
*dst++ = *(src);
src += Bpp;
}
}
// Make image
wxImage img(w,h);
img.SetData(buf);
return img;
}
else {
return wxImage(w,h);
}
}
/////////////////////////////
// Get float luminosity data
void AegiVideoFrame::GetFloat(float *buffer) const {
int Bpp = GetBpp();
const unsigned char *src = data[0];
float *dst = buffer;
float temp;
// Convert
if (format == FORMAT_RGB32 || format == FORMAT_RGB24) {
int delta = 4-Bpp;
for (unsigned int y=0;y<h;y++) {
dst = buffer + y*w;
if (flipped) src = data[0] + (h-y-1)*pitch[0]; // I think that it requires flipped data - amz
else src = data[0] + y*pitch[0];
for (unsigned int x=0;x<w;x++) {
temp = (*src++)*0.3 + (*src++)*0.4 + (*src++)*0.3;
src += delta;
*dst++ = temp;
}
}
}
}
///////////////////////
// Get Bytes per Pixel
int AegiVideoFrame::GetBpp(int plane) const {
switch (format) {
case FORMAT_RGB32: return 4;
case FORMAT_RGB24: return 3;
case FORMAT_YUY2: return 2;
case FORMAT_YV12:
if (plane == 0) return 1;
else return 0;
default: return 0;
}
}

77
aegisub/video_frame.h Normal file
View file

@ -0,0 +1,77 @@
// Copyright (c) 2007, 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
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
//////////////////////
// Video Frame format
enum VideoFrameFormat {
FORMAT_RGB24,
FORMAT_RGB32,
FORMAT_YUY2,
FORMAT_YV12
};
/////////////////////
// Video Frame class
class AegiVideoFrame {
private:
unsigned int memSize[4];
public:
unsigned char *data[4]; // Pointers to the data planes. Interleaved formats only use data[0]
VideoFrameFormat format; // Data format, one of FORMAT_RGB24, FORMAT_RGB32, FORMAT_YUY2 and FORMAT_YV12
unsigned int w; // Width in pixels
unsigned int h; // Height in pixels
unsigned int pitch[4]; // Pitch, that is, the number of bytes used by each row.
bool flipped; // First row is actually the bottom one
bool invertChannels; // Invert Red and Blue channels
bool cppAlloc; // Allocated with C++'s "new" operator, instead of "malloc"
AegiVideoFrame();
AegiVideoFrame(int width,int height,VideoFrameFormat format=FORMAT_RGB32);
void Allocate();
void Clear();
void CopyFrom(const AegiVideoFrame &source);
wxImage GetImage() const;
void GetFloat(float *buffer) const;
int GetBpp(int plane=0) const;
};

View file

@ -36,101 +36,129 @@
///////////
// Headers
#include "video_provider_avs.h"
#include "video_provider_lavc.h"
#include "video_provider_dshow.h"
#include "video_provider.h"
#include "options.h"
#include "setup.h"
#include "vfr.h"
///////////////
// Constructor
VideoProvider::VideoProvider() {
cacheMax = 0;
}
//////////////
// Destructor
VideoProvider::~VideoProvider() {
ClearCache();
}
/////////////
// Get frame
const AegiVideoFrame VideoProvider::GetFrame(int n) {
// See if frame is cached
CachedFrame cached;
for (std::list<CachedFrame>::iterator cur=cache.begin();cur!=cache.end();cur++) {
cached = *cur;
if (cached.n == n) {
cache.erase(cur);
cache.push_back(cached);
return cached.frame;
}
}
// Not cached, retrieve it
const AegiVideoFrame frame = DoGetFrame(n);
Cache(n,frame);
return frame;
}
////////////////
// Get as float
void VideoProvider::GetFloatFrame(float* buffer, int n) {
const AegiVideoFrame frame = GetFrame(n);
frame.GetFloat(buffer);
}
//////////////////////////
// Set maximum cache size
void VideoProvider::SetCacheMax(int n) {
if (n < 0) n = 0;
cacheMax = n;
}
////////////////
// Add to cache
void VideoProvider::Cache(int n,const AegiVideoFrame frame) {
// Cache enabled?
if (cacheMax == 0) return;
// Cache full, remove use frame at front
if (cache.size() >= cacheMax) {
cache.push_back(cache.front());
cache.pop_front();
}
// Cache not full, insert new one
else {
cache.push_back(CachedFrame());
}
// Cache
cache.front().n = n;
cache.front().frame.CopyFrom(frame);
}
///////////////
// Clear cache
void VideoProvider::ClearCache() {
while (cache.size()) {
cache.front().frame.Clear();
cache.pop_front();
}
}
////////////////
// Get provider
VideoProvider *VideoProvider::GetProvider(wxString video,wxString subtitles,double fps) {
// Check if avisynth is available
bool avisynthAvailable = false;
bool dshowAvailable = false;
#ifdef __WINDOWS__
dshowAvailable = true;
try {
// If avisynth.dll cannot be loaded, an exception will be thrown and avisynthAvailable will never be set to true
AviSynthWrapper avs;
avisynthAvailable = true;
}
catch (...) {}
#endif
VideoProvider *VideoProviderFactory::GetProvider(wxString video,double fps) {
// List of providers
wxArrayString list = GetFactoryList();
// Initialize to null
VideoProvider *provider = NULL;
// None available
if (list.Count() == 0) throw _T("No video providers are available.");
// Preffered provider
// Put preffered on top
wxString preffered = Options.AsText(_T("Video provider")).Lower();
// See if it's OK to use LAVC
#if USE_LAVC == 1
if (preffered == _T("ffmpeg") || (!avisynthAvailable && !dshowAvailable)) {
// Load
bool success = false;
wxString error;
try {
provider = new LAVCVideoProvider(video,subtitles);
success = true;
}
// Catch error
catch (const wchar_t *err) {
error = err;
}
catch (...) {
error = _T("Unhandled exception.");
}
if (!success) {
// Delete old provider
delete provider;
provider = NULL;
// Try to fallback to avisynth
if (avisynthAvailable) {
wxMessageBox(_T("Failed loading FFmpeg decoder for video, falling back to Avisynth.\nError message: ") + error,_T("FFmpeg error."));
provider = NULL;
}
// Out of options, rethrow
else throw error.c_str();
}
if (list.Index(preffered) != wxNOT_FOUND) {
list.Remove(preffered);
list.Insert(preffered,0);
}
#endif
#ifdef __WINDOWS__
#if USE_DIRECTSHOW == 1
// Use DirectShow provider
if (!provider && (preffered == _T("dshow") || !avisynthAvailable)) {
// Get provider
wxString error;
for (unsigned int i=0;i<list.Count();i++) {
try {
if (VFR_Input.GetFrameRateType() == VFR) provider = new DirectShowVideoProvider(video,subtitles);
else provider = new DirectShowVideoProvider(video,subtitles,fps);
}
catch (...) {
delete provider;
provider = NULL;
throw;
VideoProvider *provider = GetFactory(list[i])->CreateProvider(video,fps);
if (provider) return provider;
}
catch (wxString err) { error += list[i] + _T(" factory: ") + err + _T("\n"); }
catch (const wxChar *err) { error += list[i] + _T(" factory: ") + wxString(err) + _T("\n"); }
catch (...) { error += list[i] + _T(" factory: Unknown error\n"); }
}
#endif
// Use Avisynth provider
if (!provider) {
try {
provider = new AvisynthVideoProvider(video,subtitles,fps);
}
catch (...) {
delete provider;
provider = NULL;
throw;
}
}
#endif
// Return provider
return provider;
// Failed
throw error;
}
//////////
// Static
std::map<wxString,VideoProviderFactory*>* AegisubFactory<VideoProviderFactory>::factories=NULL;

View file

@ -1,4 +1,4 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// Copyright (c) 2006-2007, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -37,35 +37,72 @@
#pragma once
#include "subtitle_provider.h"
//////////
// Headers
#include "video_frame.h"
#include "factory.h"
//////////////
// Prototypes
class SubtitlesProvider;
////////////////
// Cached frame
class CachedFrame {
public:
AegiVideoFrame frame;
int n;
};
////////////////////////////
// Video Provider interface
class VideoProvider {
private:
unsigned int cacheMax;
std::list<CachedFrame> cache;
void Cache(int n,const AegiVideoFrame frame);
AegiVideoFrame GetCachedFrame(int n);
protected:
// Override this method to actually get frames
virtual const AegiVideoFrame DoGetFrame(int n)=0; // Get frame as AegiVideoFrame
// Cache functions
void SetCacheMax(int n_frames);
void ClearCache();
public:
virtual ~VideoProvider() {}
// Base methods
void GetFloatFrame(float* Buffer, int n); // Get frame as float
const AegiVideoFrame GetFrame(int n);
VideoProvider();
virtual ~VideoProvider();
virtual void RefreshSubtitles()=0; // Refresh subtitles display
virtual void AttachOverlay(SubtitleProvider::Overlay *overlay) = 0;
virtual wxBitmap GetFrame(int n)=0; // Get frame as bitmap
virtual void GetFloatFrame(float* Buffer, int n)=0; // Get frame as float (for FexTracker)
virtual int GetPosition()=0; // Get the current frame being displayed
virtual int GetFrameCount()=0; // Get total number of frames
virtual double GetFPS()=0; // Get framerate in frames per second
virtual void SetDAR(double dar)=0; // Set display aspect ratio (width/height)
virtual void SetZoom(double zoom)=0; // Set zoom factor
virtual int GetWidth()=0; // Returns the display width in pixels
virtual int GetHeight()=0; // Returns the display height in pixels
virtual double GetZoom()=0; // Returns the zoom factor
virtual int GetSourceWidth()=0; // Returns the original source width in pixels
virtual int GetSourceHeight()=0; // Returns the original source height in pixels
// Subtitles
virtual SubtitlesProvider *GetAsSubtitlesProvider() { return NULL; } // Get subtitles provider
// Override the following methods:
virtual int GetPosition()=0; // Get the number of the last frame loaded
virtual int GetFrameCount()=0; // Get total number of frames
virtual int GetWidth()=0; // Returns the video width in pixels
virtual int GetHeight()=0; // Returns the video height in pixels
virtual double GetFPS()=0; // Get framerate in frames per second
virtual void OverrideFrameTimeList(wxArrayInt list) {} // Override the list with the provided one, for VFR handling
static VideoProvider *GetProvider(wxString video,wxString subtitles,double fps=0.0);
};
///////////
// Factory
class VideoProviderFactory : public AegisubFactory<VideoProviderFactory> {
protected:
virtual VideoProvider *CreateProvider(wxString video,double fps=0.0)=0;
VideoProviderFactory(wxString name) { RegisterFactory(name); }
public:
virtual ~VideoProviderFactory() {}
static VideoProvider *GetProvider(wxString video,double fps=0.0);
};

View file

@ -33,36 +33,40 @@
// Contact: mailto:zeratul@cellosoft.com
//
#include <wx/wxprec.h>
#include <wx/filename.h>
#include <wx/msw/registry.h>
#include <wx/filename.h>
#include "video_provider_avs.h"
#include "video_context.h"
#include "options.h"
#include "main.h"
#include "vfr.h"
#include "ass_file.h"
#ifdef __WINDOWS__
#ifdef __WIN32__
///////////
// Factory
class AvisynthVideoProviderFactory : public VideoProviderFactory {
public:
VideoProvider *CreateProvider(wxString video,double fps=0.0) { return new AvisynthVideoProvider(video,fps); }
AvisynthVideoProviderFactory() : VideoProviderFactory(_T("avisynth")) {}
} registerAVS;
///////////////
// Constructor
AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfilename, double _fps) {
AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, double _fps) {
AVSTRACE(wxString::Format(_T("AvisynthVideoProvider: Creating new AvisynthVideoProvider: \"%s\", \"%s\""), _filename, _subfilename));
bool mpeg2dec3_priority = true;
RGB32Video = NULL;
SubtitledVideo = NULL;
ResizedVideo = NULL;
data = NULL;
fps = _fps;
depth = 0;
last_fnum = -1;
num_frames = 0;
subfilename = _subfilename;
zoom = 1.0;
last_fnum = -1;
AVSTRACE(_T("AvisynthVideoProvider: Loading Subtitles Renderer"));
LoadRenderer();
@ -72,17 +76,10 @@ AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfi
RGB32Video = OpenVideo(_filename,mpeg2dec3_priority);
AVSTRACE(_T("AvisynthVideoProvider: Video opened"));
dar = GetSourceWidth()/(double)GetSourceHeight();
AVSTRACE(_T("AvisynthVideoProvider: Calculated aspect ratio"));
if( _subfilename.IsEmpty() ) SubtitledVideo = RGB32Video;
else SubtitledVideo = ApplySubtitles(subfilename, RGB32Video);
SubtitledVideo = RGB32Video;
AVSTRACE(_T("AvisynthVideoProvider: Applied subtitles"));
ResizedVideo = ApplyDARZoom(zoom, dar, SubtitledVideo);
AVSTRACE(_T("AvisynthVideoProvider: Applied zoom"));
vi = ResizedVideo->GetVideoInfo();
vi = SubtitledVideo->GetVideoInfo();
AVSTRACE(_T("AvisynthVideoProvider: Got video info"));
AVSTRACE(_T("AvisynthVideoProvider: Done creating AvisynthVideoProvider"));
}
@ -94,56 +91,14 @@ AvisynthVideoProvider::~AvisynthVideoProvider() {
AVSTRACE(_T("AvisynthVideoProvider: Destroying AvisynthVideoProvider"));
RGB32Video = NULL;
SubtitledVideo = NULL;
ResizedVideo = NULL;
if( data ) delete data;
AVSTRACE(_T("AvisynthVideoProvider: Destroying frame"));
iframe.Clear();
AVSTRACE(_T("AvisynthVideoProvider: AvisynthVideoProvider destroyed"));
}
/////////////////////
// Refresh subtitles
void AvisynthVideoProvider::RefreshSubtitles() {
AVSTRACE(_T("AvisynthVideoProvider::RefreshSubtitles: Refreshing subtitles"));
ResizedVideo = NULL;
SubtitledVideo = NULL;
SubtitledVideo = ApplySubtitles(subfilename, RGB32Video);
ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo);
GetFrame(last_fnum,true);
AVSTRACE(_T("AvisynthVideoProvider::RefreshSubtitles: Subtitles refreshed"));
}
////////////////////////////
// Set Display Aspect Ratio
void AvisynthVideoProvider::SetDAR(double _dar) {
AVSTRACE(_T("AvisynthVideoProvider::SetDAR: Setting DAR"));
dar = _dar;
ResizedVideo = NULL;
delete data;
data = NULL;
ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo);
GetFrame(last_fnum,true);
AVSTRACE(_T("AvisynthVideoProvider::SetDAR: DAR set"));
}
////////////
// Set Zoom
void AvisynthVideoProvider::SetZoom(double _zoom) {
AVSTRACE(_T("AvisynthVideoProvider::SetZoom: Setting zoom"));
zoom = _zoom;
ResizedVideo = NULL;
delete data;
data = NULL;
ResizedVideo = ApplyDARZoom(zoom,dar,SubtitledVideo);
GetFrame(last_fnum,true);
AVSTRACE(_T("AvisynthVideoProvider::SetZoom: Zoom set"));
}
////////////////////////////////////// VIDEO PROVIDER //////////////////////////////////////
/////////////////////////////////////////
@ -301,6 +256,70 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
}
////////////////////////
// Actually get a frame
const AegiVideoFrame AvisynthVideoProvider::DoGetFrame(int _n) {
// Transform n if overriden
int n = _n;
if (frameTime.Count()) {
if (n < 0) n = 0;
if (n >= (signed) frameTime.Count()) n = frameTime.Count()-1;
int time = frameTime[n];
double curFps = (double)vi.fps_numerator/(double)vi.fps_denominator;
n = time * curFps / 1000.0;
}
// Get avs frame
AVSTRACE(_T("AvisynthVideoProvider::GetFrame"));
wxMutexLocker lock(AviSynthMutex);
PVideoFrame frame = SubtitledVideo->GetFrame(n,env);
int Bpp = vi.BitsPerPixel() / 8;
// Aegisub's video frame
AegiVideoFrame &final = iframe;
final.flipped = false;
final.cppAlloc = true;
// Format
if (vi.IsRGB32()) {
final.format = FORMAT_RGB32;
final.flipped = true;
}
else if (vi.IsRGB24()) {
final.format = FORMAT_RGB24;
final.flipped = true;
}
else if (vi.IsYV12()) final.format = FORMAT_YV12;
else if (vi.IsYUY2()) final.format = FORMAT_YUY2;
// Set size properties
int uvpitch = 0;
if (final.format == FORMAT_YV12) uvpitch = frame->GetPitch(PLANAR_U);
final.pitch[0] = frame->GetPitch();
final.pitch[1] = uvpitch;
final.pitch[2] = uvpitch;
final.w = frame->GetRowSize() / Bpp;
final.h = frame->GetHeight();
// Allocate
final.Allocate();
// Copy
memcpy(final.data[0],frame->GetReadPtr(),final.pitch[0] * final.h);
// Copy second and third planes for YV12
if (final.format == FORMAT_YV12) {
int uvh = frame->GetHeight(PLANAR_U);
memcpy(final.data[1],frame->GetReadPtr(PLANAR_U),uvpitch * uvh);
memcpy(final.data[2],frame->GetReadPtr(PLANAR_V),uvpitch * uvh);
}
// Set last number
last_fnum = n;
return final;
}
////////////////////////////////////////////////////////
// Apply VSFilter subtitles, or whatever is appropriate
PClip AvisynthVideoProvider::ApplySubtitles(wxString _filename, PClip videosource) {
@ -331,146 +350,34 @@ PClip AvisynthVideoProvider::ApplySubtitles(wxString _filename, PClip videosourc
}
/////////////////////////////////////
// Apply Display Aspect Ratio + Zoom
PClip AvisynthVideoProvider::ApplyDARZoom(double _zoom, double _dar, PClip videosource) {
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: Applying DAR zoom"));
wxMutexLocker lock(AviSynthMutex);
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: Got AVS mutex"));
AVSValue script;
VideoInfo vil = videosource->GetVideoInfo();
////////////////////////////////////// SUBTITLES PROVIDER //////////////////////////////////////
int w = vil.height * _zoom * _dar;
int h = vil.height * _zoom;
if (w == vil.width && h == vil.height) {
vi = vil;
return (env->Invoke("Cache",videosource)).AsClip();
}
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 };
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: Invoking resizing function"));
script = env->Invoke(Options.AsText(_T("Video resizer")).mb_str(wxConvLocal), AVSValue(args,3));
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: Resizer invoked successfully"));
} catch (AvisynthError &err) {
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: Avisynth error: ") + wxString(err.msg,wxConvLocal));
throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal);
}
vi = script.AsClip()->GetVideoInfo();
AVSTRACE(_T("AvisynthVideoProvider::ApplyDARZoom: DAR zoom applied successfully, AVS mutex will be released now"));
return (env->Invoke("Cache",script)).AsClip();
/////////////////////////////
// Get as subtitles provider
SubtitlesProvider *AvisynthVideoProvider::GetAsSubtitlesProvider() {
return this;
}
////////////////////////
// Actually get a frame
wxBitmap AvisynthVideoProvider::GetFrame(int _n, bool force) {
// Transform n if overriden
int n = _n;
if (frameTime.Count()) {
if (n < 0) n = 0;
if (n >= (signed) frameTime.Count()) n = frameTime.Count()-1;
int time = frameTime[n];
double curFps = (double)vi.fps_numerator/(double)vi.fps_denominator;
n = time * curFps / 1000.0;
}
/////////////////////
// Refresh subtitles
void AvisynthVideoProvider::LoadSubtitles(AssFile *subs) {
// Reset
AVSTRACE(_T("AvisynthVideoProvider::RefreshSubtitles: Refreshing subtitles"));
SubtitledVideo = NULL;
// Get frame
AVSTRACE(_T("AvisynthVideoProvider::GetFrame"));
if (n != last_fnum || force) {
wxMutexLocker lock(AviSynthMutex);
// Dump subs to disk
wxString subfilename = VideoContext::Get()->GetTempWorkFile();
subs->Save(subfilename,false,false,_T("UTF-8"));
delete subs;
PVideoFrame frame = ResizedVideo->GetFrame(n,env);
int ndepth = wxDisplayDepth();
if (depth != ndepth) {
depth = ndepth;
delete data;
data = NULL;
}
if (!data)
data = new unsigned char[vi.width*vi.height*depth/8];
unsigned char* dst = data+(vi.width*(vi.height-1)*depth/8);
if (depth == 32) {
int rs = vi.RowSize();
const unsigned char* src = frame->GetReadPtr();
int srcpitch = frame->GetPitch();
for (int y = 0; y < vi.height; y++) {
memcpy(dst,src,rs);
src+=srcpitch;
dst-=rs;
}
}
else if (depth == 24) {
//fail
}
else if (depth == 16) {
const unsigned char *read_ptr = frame->GetReadPtr();
unsigned short *write_ptr = (unsigned short*) dst;
unsigned char r,g,b;
int srcpitch = frame->GetPitch();
int rs = vi.RowSize();
for (int y = 0; y < vi.height; y++) {
for (int x=0,dx=0;x<rs;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;
}
write_ptr -= vi.width;
read_ptr += srcpitch;
}
}
else {
//fail
}
last_frame = wxBitmap((const char*)data, vi.width, vi.height, depth);
last_fnum = n;
}
return wxBitmap(last_frame);
}
///////////////////////////////////
// Get a frame intensity as floats
void AvisynthVideoProvider::GetFloatFrame(float* Buffer, int n) {
AVSTRACE(_T("AvisynthVideoProvider::GetFloatFrame"));
wxMutexLocker lock(AviSynthMutex);
PVideoFrame frame = ResizedVideo->GetFrame(n,env);
int rs = vi.RowSize();
const unsigned char* src = frame->GetReadPtr();
int srcpitch = frame->GetPitch();
for( int i = 0; i < vi.height; i++ )
{
for( int x=0; x<vi.width;x++ )
{
Buffer[(vi.height-i-1)*vi.width+x] = src[x*4+0]*0.3 + src[x*4+1]*0.4 + src[x*4+2]*0.3;
}
src+=srcpitch;
}
// Load subtitles
SubtitledVideo = ApplySubtitles(subfilename, RGB32Video);
AVSTRACE(_T("AvisynthVideoProvider::RefreshSubtitles: Subtitles refreshed"));
vi = SubtitledVideo->GetVideoInfo();
AVSTRACE(_T("AvisynthVideoProvider: Got video info"));
}

View file

@ -41,9 +41,10 @@
// Headers
#include <wx/wxprec.h>
#ifdef __WINDOWS__
#ifdef __WIN32__
#include "avisynth_wrap.h"
#include "video_provider.h"
#include "subtitles_provider.h"
/*class GetFrameVPThread: public wxThread {
private:
@ -58,61 +59,48 @@ public:
GetFrameVPThread(PClip clip);
};*/
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
////////////
// Provider
class AvisynthVideoProvider: public VideoProvider, SubtitlesProvider, AviSynthWrapper {
private:
VideoInfo vi;
AegiVideoFrame iframe;
wxString subfilename;
wxString rendererCallString;
int last_fnum;
int num_frames;
int last_fnum;
int depth;
unsigned char* data;
wxBitmap last_frame;
double dar;
double zoom;
double fps;
wxArrayInt frameTime;
PClip RGB32Video;
PClip SubtitledVideo;
PClip ResizedVideo;
PClip OpenVideo(wxString _filename, 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();
void LoadASA();
void LoadRenderer();
void AttachOverlay(SubtitleProvider::Overlay *_overlay) {}
public:
AvisynthVideoProvider(wxString _filename, wxString _subfilename, double fps=0.0);
AvisynthVideoProvider(wxString _filename, double fps=0.0);
~AvisynthVideoProvider();
void RefreshSubtitles();
void SetDAR(double _dar);
void SetZoom(double _zoom);
SubtitlesProvider *GetAsSubtitlesProvider();
void LoadSubtitles(AssFile *subs);
wxBitmap GetFrame(int n) { return GetFrame(n,false); };
const AegiVideoFrame DoGetFrame(int n);
void GetFloatFrame(float* Buffer, int n);
// properties
int GetPosition() { return last_fnum; };
int GetFrameCount() { return num_frames? num_frames: vi.num_frames; };
double GetFPS() { return (double)vi.fps_numerator/(double)vi.fps_denominator; };
int GetWidth() { return vi.width; };
int GetHeight() { return vi.height; };
double GetZoom() { return zoom; };
int GetSourceWidth() { return RGB32Video->GetVideoInfo().width; };
int GetSourceHeight() { return RGB32Video->GetVideoInfo().height; };
void OverrideFrameTimeList(wxArrayInt list);
};

View file

@ -48,19 +48,27 @@
#include "utils.h"
#include "vfr.h"
// CLSID for videosink: {F13D3732-96BD-4108-AFEB-E85F68FF64DC}
DEFINE_GUID(CLSID_VideoSink, 0xf13d3732, 0x96bd, 0x4108, 0xaf, 0xeb, 0xe8, 0x5f, 0x68, 0xff, 0x64, 0xdc);
///////////
// Factory
class DirectShowVideoProviderFactory : public VideoProviderFactory {
public:
VideoProvider *CreateProvider(wxString video,double fps=0.0) { return new DirectShowVideoProvider(video,fps); }
DirectShowVideoProviderFactory() : VideoProviderFactory(_T("dshow")) {}
} registerDShow;
///////////////
// Constructor
// Based on Haali's code for DirectShowSource2
DirectShowVideoProvider::DirectShowVideoProvider(wxString _filename, wxString _subfilename,double _fps) {
zoom = 1.0;
dar = 4.0/3.0;
DirectShowVideoProvider::DirectShowVideoProvider(wxString _filename, double _fps) {
fps = _fps;
m_registered = false;
m_hFrameReady = CreateEvent(NULL, FALSE, FALSE, NULL);
OpenVideo(_filename);
SetCacheMax(8);
HRESULT hr = OpenVideo(_filename);
if (FAILED(hr)) throw _T("Failed opening DirectShow content.");
}
@ -190,10 +198,13 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
if (FAILED(hr = pG.CoCreateInstance(CLSID_FilterGraph))) return hr;
// Create an Instance of the Video Sink
CComPtr<IBaseFilter> pR;
CLSID CLSID_VideoSink;
CLSIDFromString(L"{F13D3732-96BD-4108-AFEB-E85F68FF64DC}",&CLSID_VideoSink);
if (FAILED(hr = pR.CoCreateInstance(CLSID_VideoSink))) return hr;
//CComPtr<IBaseFilter> pR;
//CLSID CLSID_VideoSink;
//CLSIDFromString(L"{F13D3732-96BD-4108-AFEB-E85F68FF64DC}",&CLSID_VideoSink);
//if (FAILED(hr = pR.CoCreateInstance(CLSID_VideoSink))) return hr;
CComPtr<IBaseFilter> pR;
hr = CreateVideoSink(&pR);
// Add VideoSink to graph
pG->AddFilter(pR, L"VideoSink");
@ -213,7 +224,6 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
// Pass the event to sink, so it gets set when a frame is available
ResetEvent(m_hFrameReady);
sink2->NotifyFrame(m_hFrameReady);
// Create source filter and add it to graph
CComPtr<IBaseFilter> pS;
if (FAILED(hr = pG->AddSourceFilter(_filename.wc_str(), NULL, &pS))) return hr;
@ -300,6 +310,7 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
///////////////
// Close video
void DirectShowVideoProvider::CloseVideo() {
rdf.frame.Clear();
CComQIPtr<IVideoSink2> pVS2(m_pR);
if (pVS2) pVS2->NotifyFrame(NULL);
@ -313,102 +324,64 @@ void DirectShowVideoProvider::CloseVideo() {
/////////////////////////
// Read DirectShow frame
void DirectShowVideoProvider::ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, unsigned stride, unsigned arx, unsigned ary, void *arg) {
void DirectShowVideoProvider::ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, int stride, unsigned arx, unsigned ary, void *arg) {
// Set frame
DF *df = (DF*) arg;
df->timestamp = timestamp;
unsigned int w_cp = width;
unsigned int h_cp = height;
// Create data
unsigned char *data;
//data = new unsigned char[width*height*bpp];
data = (unsigned char *) malloc(width*height*bpp);
unsigned int dstride = width*bpp;
// Create frame
const unsigned char * src = frame;
if (stride < 0) {
src += stride*(height-1);
stride = -stride;
df->frame.flipped = true;
}
else df->frame.flipped = false;
df->frame.w = width;
df->frame.h = height;
df->frame.pitch[0] = stride;
df->frame.cppAlloc = false;
df->frame.invertChannels = true;
// Read RGB24 data
if (format == IVS_RGB24) {
unsigned char *dst = data + h_cp*dstride;
const unsigned char *src = frame;
//unsigned char t1,t2;
w_cp *= bpp;
for (int y=h_cp; --y>=0;) {
dst -= dstride;
for (int x=width; --x>=0;) {
//t1 = *src++;
//t2 = *src++;
*dst++ = *(src+2);
*dst++ = *(src+1);
*dst++ = *src;
src += 3;
}
dst -= dstride;
}
// Planar
if (format == IVS_YUY2) {
df->frame.format = FORMAT_YUY2;
}
// Create bitmap out of data
//df->frame = wxBitmap((const char*) data, width, height, bpp*8);
//delete data;
df->frame = wxImage(width,height,data,false);
// Interleaved
else {
unsigned int datalen = stride*height;
df->frame.Allocate();
memcpy(df->frame.data[0],src,datalen);
//else if (format == IVS_YV12 && vi->pixel_type == VideoInfo::CS_YV12) {
// // plane Y
// BYTE *dp = df->frame->GetWritePtr(PLANAR_Y);
// const unsigned char *sp = frame;
// int dstride = df->frame->GetPitch(PLANAR_Y);
// for (int y = 0; y < h_cp; ++y) {
// memcpy(dp, sp, w_cp);
// sp += stride;
// dp += dstride;
// }
// // UV
// dstride >>= 1;
// stride >>= 1;
// w_cp >>= 1;
// h_cp >>= 1;
// // plane V
// dp = df->frame->GetWritePtr(PLANAR_V);
// sp = frame + height * stride * 2;
// dstride = df->frame->GetPitch(PLANAR_V);
// for (int y = 0; y < h_cp; ++y) {
// memcpy(dp, sp, w_cp);
// sp += stride;
// dp += dstride;
// }
// // plane U
// dp = df->frame->GetWritePtr(PLANAR_U);
// sp = frame + height * stride * 2 + (height >> 1) * stride;
// dstride = df->frame->GetPitch(PLANAR_U);
// for (int y = 0; y < h_cp; ++y) {
// memcpy(dp, sp, w_cp);
// sp += stride;
// dp += dstride;
// }
//}
// Set format
if (format == IVS_RGB24) df->frame.format = FORMAT_RGB24;
else if (format == IVS_RGB32) df->frame.format = FORMAT_RGB32;
else if (format == IVS_YV12) df->frame.format = FORMAT_YV12;
}
}
/////////////////////
// Get Next DS Frame
int DirectShowVideoProvider::NextFrame(DF &_df,int &_fn) {
int DirectShowVideoProvider::NextFrame(DF &df,int &_fn) {
// Keep reading until it gets a good frame
while (true) {
// Set object and receive data
DF df;
if (WaitForSingleObject(m_hFrameReady, INFINITE) != WAIT_OBJECT_0) return 1;
// Read frame
HRESULT hr = m_pR->ReadFrame(ReadFrame, &df);
if (FAILED(hr)) return 2;
if (FAILED(hr)) {
//df.frame.Clear();
return 2;
}
// End of file
if (hr == S_FALSE) return 3;
if (hr == S_FALSE) {
//df.frame.Clear();
return 3;
}
// Valid timestamp
if (df.timestamp >= 0) {
@ -430,29 +403,25 @@ int DirectShowVideoProvider::NextFrame(DF &_df,int &_fn) {
// Got a good one
if (frameno >= 0) {
_fn = frameno;
_df = df;
if (zoom != 1.0 || dar != 1.0) {
_df.frame.Rescale(height*zoom*dar,height*zoom,wxIMAGE_QUALITY_NORMAL);
}
//_df = df;
return 0;
}
}
//df.frame.Clear();
}
}
/////////////
// Get frame
wxBitmap DirectShowVideoProvider::GetFrame(int n) {
const AegiVideoFrame DirectShowVideoProvider::DoGetFrame(int n) {
// Normalize frame number
if (n >= (signed) num_frames) n = num_frames-1;
if (n < 0) n = 0;
// Current
if (n == last_fnum) return wxBitmap(rdf.frame);
// Variables
DF df;
//DF df;
int fn;
// Time to seek to
@ -463,10 +432,10 @@ wxBitmap DirectShowVideoProvider::GetFrame(int n) {
// Is next
if (n == last_fnum + 1) {
NextFrame(df,fn);
//rdf.frame.Clear();
NextFrame(rdf,fn);
last_fnum = n;
rdf.frame = df.frame;
return wxBitmap(rdf.frame);
return rdf.frame;
}
// Not the next, reset and seek first
@ -474,33 +443,38 @@ seek:
ResetEvent(m_hFrameReady);
// Seek
if (FAILED(m_pGS->SetPositions(&cur, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning))) return wxBitmap(width,height);
if (FAILED(m_pGS->SetPositions(&cur, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning))) return AegiVideoFrame(width,height);
// Set time
rdf.timestamp = -1;
REFERENCE_TIME timestamp = -1;
// Actually get data
while (true) {
// Get frame
DF df;
int fn = -1;
int result = NextFrame(df,fn);
int result = NextFrame(rdf,fn);
// Preroll
if (result == 0 && fn < n) continue;
if (result == 0 && fn < n) {
continue;
}
// Right frame
else if (fn == n) {
// we want this frame, compare timestamps to account for decimation
// we see this for the first time
if (rdf.timestamp < 0) rdf.timestamp = df.timestamp;
if (timestamp < 0) timestamp = rdf.timestamp;
// early, ignore
if (df.timestamp < rdf.timestamp) continue;
if (rdf.timestamp < timestamp) {
continue;
}
// this is the frame we want
rdf.frame = df.frame;
break;
last_fnum = n;
//rdf.frame.Clear();
//rdf.frame = df.frame;
return rdf.frame;
}
// Passed or end of file, seek back and try again
@ -511,13 +485,9 @@ seek:
// Failed
else {
return wxBitmap(height*zoom*dar,height*zoom);
return AegiVideoFrame(width,height);
}
}
// Return frame
last_fnum = n;
return wxBitmap(rdf.frame);
}
@ -527,22 +497,6 @@ void DirectShowVideoProvider::RefreshSubtitles() {
}
///////////
// Set DAR
void DirectShowVideoProvider::SetDAR(double _dar) {
dar = _dar;
last_fnum = -2;
}
////////////
// Set Zoom
void DirectShowVideoProvider::SetZoom(double _zoom) {
zoom = _zoom;
last_fnum = -2;
}
///////////////////
// Get float frame
void DirectShowVideoProvider::GetFloatFrame(float* Buffer, int n) {

View file

@ -58,16 +58,15 @@ class DirectShowVideoProvider: public VideoProvider {
struct DF {
public:
REFERENCE_TIME timestamp; // DS timestamp that we used for this frame
wxImage frame;
AegiVideoFrame frame;
DF() : timestamp(-1) { }
DF(wxImage f) : timestamp(-1), frame(f) { }
DF(AegiVideoFrame f) : timestamp(-1), frame(f) { }
DF(const DF& f) { operator=(f); }
DF& operator=(const DF& f) { timestamp = f.timestamp; frame = f.frame; return *this; }
};
private:
wxString subfilename;
wxArrayInt frameTime;
unsigned int last_fnum;
@ -77,19 +76,10 @@ private:
double fps;
long long defd;
int depth;
double dar;
double zoom;
unsigned char* data;
wxBitmap last_frame;
void AttachOverlay(SubtitleProvider::Overlay *overlay) {}
HRESULT OpenVideo(wxString _filename);
void CloseVideo();
static void ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, unsigned stride, unsigned arx, unsigned ary, void *arg);
static void ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, int stride, unsigned arx, unsigned ary, void *arg);
int NextFrame(DF &df,int &fn);
void RegROT();
@ -105,26 +95,19 @@ private:
DWORD m_rot_cookie;
public:
DirectShowVideoProvider(wxString _filename, wxString _subfilename,double _fps=0.0);
DirectShowVideoProvider(wxString _filename, double _fps=0.0);
~DirectShowVideoProvider();
void RefreshSubtitles();
void SetDAR(double _dar);
void SetZoom(double _zoom);
wxBitmap GetFrame(int n);
const AegiVideoFrame DoGetFrame(int n);
void GetFloatFrame(float* Buffer, int n);
int GetPosition() { return last_fnum; };
int GetFrameCount() { return num_frames; };
double GetFPS() { return fps; };
int GetWidth() { return height*zoom*dar; };
int GetHeight() { return height*zoom; };
double GetZoom() { return zoom; };
int GetSourceWidth() { return width; };
int GetSourceHeight() { return height; };
int GetWidth() { return width; };
int GetHeight() { return height; };
void OverrideFrameTimeList(wxArrayInt list);
};

View file

@ -74,7 +74,6 @@ void VideoSlider::SetValue(int value) {
val = value;
if (val < min) val = min;
if (val > max) val = max;
//UpdateImage();
Refresh(false);
}
@ -82,13 +81,12 @@ void VideoSlider::SetValue(int value) {
/////////////
// Set range
void VideoSlider::SetRange(int from,int to) {
wxASSERT(from <= to);
if (from > to) from = to;
locked = false;
min = from;
max = to;
val = from;
UpdateImage();
if (val < from) val = from;
if (val > to) val = to;
}
@ -125,22 +123,24 @@ int VideoSlider::GetXAtValue(int value) {
/////////////////////
// Next frame hotkey
void VideoSlider::NextFrame() {
if (Display->IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
//don't request out of range frames
if (GetValue() < max)
Display->JumpToFrame(GetValue()+1);
if (GetValue() < max) VideoContext::Get()->JumpToFrame(GetValue()+1);
Refresh(false);
Update();
}
/////////////////////////
// Previous frame hotkey
void VideoSlider::PrevFrame() {
if (Display->IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
//don't request out of range frames
if (GetValue() > min)
Display->JumpToFrame(GetValue()-1);
if (GetValue() > min) VideoContext::Get()->JumpToFrame(GetValue()-1);
Refresh(false);
Update();
}
@ -152,6 +152,7 @@ BEGIN_EVENT_TABLE(VideoSlider, wxWindow)
EVT_PAINT(VideoSlider::OnPaint)
EVT_SET_FOCUS(VideoSlider::OnFocus)
EVT_KILL_FOCUS(VideoSlider::OnFocus)
EVT_ERASE_BACKGROUND(VideoSlider::OnEraseBackground)
END_EVENT_TABLE()
@ -159,9 +160,9 @@ END_EVENT_TABLE()
// Change position
void VideoSlider::UpdateVideo() {
if (Display) {
if (Display->IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
locked = true;
Display->JumpToFrame(GetValue());
VideoContext::Get()->JumpToFrame(GetValue());
locked = false;
}
}
@ -189,7 +190,7 @@ void VideoSlider::OnMouse(wxMouseEvent &event) {
if (canDrag) {
// Shift click to snap to keyframe
if (shift && Display) {
wxArrayInt KeyFrames = Display->GetKeyFrames();
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
int keys = KeyFrames.Count();
int clickedFrame = GetValueAtX(x);
int closest = 0;
@ -217,10 +218,10 @@ void VideoSlider::OnMouse(wxMouseEvent &event) {
Refresh(false);
// Playing?
if (Display->IsPlaying) {
Display->Stop();
if (VideoContext::Get()->IsPlaying()) {
VideoContext::Get()->Stop();
UpdateVideo();
Display->Play();
VideoContext::Get()->Play();
}
else UpdateVideo();
}
@ -235,14 +236,14 @@ void VideoSlider::OnMouse(wxMouseEvent &event) {
}
// Something else
else if (!Display->IsPlaying) event.Skip();
else if (!VideoContext::Get()->IsPlaying()) event.Skip();
}
//////////////////
// Key down event
void VideoSlider::OnKeyDown(wxKeyEvent &event) {
if (Display->IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
// Get flags
int key = event.GetKeyCode();
@ -266,9 +267,9 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
// Fast move
if (!ctrl && !shift && alt) {
if (Display->IsPlaying) return;
if (VideoContext::Get()->IsPlaying()) return;
int target = MID(min,GetValue() + direction * Options.AsInt(_T("Video Fast Jump Step")),max);
if (target != GetValue()) Display->JumpToFrame(target);
if (target != GetValue()) VideoContext::Get()->JumpToFrame(target);
return;
}
@ -294,8 +295,8 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
// Forward
if (direction == 1) {
if (Display->frame_n < target1) Display->JumpToFrame(target1);
else if (Display->frame_n < target2) Display->JumpToFrame(target2);
if (VideoContext::Get()->GetFrameN() < target1) VideoContext::Get()->JumpToFrame(target1);
else if (VideoContext::Get()->GetFrameN() < target2) VideoContext::Get()->JumpToFrame(target2);
else {
if (cur+1 >= grid->GetRows()) return;
grid->editBox->SetToLine(cur+1);
@ -310,8 +311,8 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
// Backward
else {
if (Display->frame_n > target2) Display->JumpToFrame(target2);
else if (Display->frame_n > target1) Display->JumpToFrame(target1);
if (VideoContext::Get()->GetFrameN() > target2) VideoContext::Get()->JumpToFrame(target2);
else if (VideoContext::Get()->GetFrameN() > target1) VideoContext::Get()->JumpToFrame(target1);
else {
if (cur-1 < 0) return;
grid->editBox->SetToLine(cur-1);
@ -331,10 +332,10 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
if (direction != 0) {
// Prepare
int prevKey = 0;
int nextKey = Display->length-1;
wxArrayInt KeyFrames = Display->GetKeyFrames();
int nextKey = VideoContext::Get()->GetLength()-1;
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
int keys = KeyFrames.Count();
int cur = Display->frame_n;
int cur = VideoContext::Get()->GetFrameN();
int i;
int temp;
@ -351,8 +352,8 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
if (temp > cur && temp < nextKey) nextKey = KeyFrames[i];
}
if (direction == -1) Display->JumpToFrame(prevKey);
if (direction == 1) Display->JumpToFrame(nextKey);
if (direction == -1) VideoContext::Get()->JumpToFrame(prevKey);
if (direction == 1) VideoContext::Get()->JumpToFrame(nextKey);
return;
}
}
@ -379,24 +380,30 @@ void VideoSlider::OnPaint(wxPaintEvent &event) {
//////////////
// Draw image
void VideoSlider::DrawImage(wxDC &dc) {
void VideoSlider::DrawImage(wxDC &destdc) {
// Get dimensions
int w,h;
GetClientSize(&w,&h);
// Draw background
dc.Clear();
// Back buffer
wxMemoryDC dc;
wxBitmap bmp(w,h);
dc.SelectObject(bmp);
// Colors
wxColour shad = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW);
wxColour high = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
wxColour face = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
//wxColour sel(244,198,38);
wxColour sel(123,251,232);
wxColour notSel(sel.Red()*2/5,sel.Green()*2/5,sel.Blue()*2/5);
wxColour bord(0,0,0);
int x1,x2,y1,y2;
// Background
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(face);
dc.DrawRectangle(0,0,w,h);
// Selection border
bool selected = wxWindow::FindFocus() == this;
if (selected) {
@ -421,7 +428,7 @@ void VideoSlider::DrawImage(wxDC &dc) {
int curX;
if (Display && Options.AsBool(_T("Show keyframes on video slider"))) {
dc.SetPen(wxPen(shad));
wxArrayInt KeyFrames = Display->GetKeyFrames();
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
int keys = KeyFrames.Count();
for (int i=0;i<keys;i++) {
curX = GetXAtValue(KeyFrames[i]);
@ -463,14 +470,18 @@ void VideoSlider::DrawImage(wxDC &dc) {
if (selected) dc.SetBrush(wxBrush(sel));
else dc.SetBrush(wxBrush(notSel));
dc.DrawRectangle(curX-3,y2+1,7,4);
// Draw final
destdc.Blit(0,0,w,h,&dc,0,0);
}
////////////////
// Update image
void VideoSlider::UpdateImage () {
wxClientDC dc(this);
DrawImage(dc);
//wxClientDC dc(this);
//DrawImage(dc);
Refresh(false);
}

View file

@ -67,6 +67,7 @@ private:
void OnKeyDown(wxKeyEvent &event);
void OnPaint(wxPaintEvent &event);
void OnFocus(wxFocusEvent &event);
void OnEraseBackground(wxEraseEvent &event) {}
public:
VideoDisplay *Display;

View file

@ -108,7 +108,7 @@ static int os_getenv (lua_State *L) {
wchar_t wvar[MAX_PATH+1];
char *val;
wchar_t *wval;
size_t lval;
int lval;
MultiByteToWideChar(CP_UTF8, 0, var, -1, wvar, MAX_PATH+1);
wval = _wgetenv(wvar);
lval = WideCharToMultiByte(CP_UTF8, 0, wval, -1, 0, 0, 0, 0);