forked from mia/Aegisub
Merged opengl branch from 806 to 859
Originally committed to SVN as r860.
This commit is contained in:
parent
3c7d5fe033
commit
98ce168b31
58 changed files with 4356 additions and 1870 deletions
569
aegisub/VideoSink.cpp
Normal file
569
aegisub/VideoSink.cpp
Normal 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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ AssOverrideParameter::AssOverrideParameter () {
|
|||
//////////////
|
||||
// Destructor
|
||||
AssOverrideParameter::~AssOverrideParameter () {
|
||||
DeleteValue();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
300
aegisub/csri/csri.h
Normal 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
95
aegisub/csri/loader.h
Normal 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 */
|
||||
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
74
aegisub/factory.h
Normal 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() {}
|
||||
};
|
|
@ -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++) {
|
||||
|
|
|
@ -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
224
aegisub/gl_wrap.cpp
Normal 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
58
aegisub/gl_wrap.h
Normal 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);
|
||||
};
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include <wx/event.h>
|
||||
#include <wx/wxscintilla.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
|
||||
///////////////
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
|
||||
///////////
|
||||
// Headers
|
||||
#include "setup.h"
|
||||
#ifdef HAVE_ASA
|
||||
|
||||
#include <wx/wxprec.h>
|
||||
#include <wx/image.h>
|
||||
#include "subtitle_provider.h"
|
||||
|
|
84
aegisub/subtitles_provider.cpp
Normal file
84
aegisub/subtitles_provider.cpp
Normal 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;
|
|
@ -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();
|
||||
};
|
124
aegisub/subtitles_provider_csri.cpp
Normal file
124
aegisub/subtitles_provider_csri.cpp
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
670
aegisub/video_context.cpp
Normal 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
171
aegisub/video_context.h
Normal 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()
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
434
aegisub/video_display_fextracker.cpp
Normal file
434
aegisub/video_display_fextracker.cpp
Normal 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
|
79
aegisub/video_display_fextracker.h
Normal file
79
aegisub/video_display_fextracker.h
Normal 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()
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
212
aegisub/video_frame.cpp
Normal 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
77
aegisub/video_frame.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ private:
|
|||
void OnKeyDown(wxKeyEvent &event);
|
||||
void OnPaint(wxPaintEvent &event);
|
||||
void OnFocus(wxFocusEvent &event);
|
||||
void OnEraseBackground(wxEraseEvent &event) {}
|
||||
|
||||
public:
|
||||
VideoDisplay *Display;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue