From 98ce168b3128ae020762847ad22aca8732620364 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Sun, 21 Jan 2007 06:30:19 +0000 Subject: [PATCH] Merged opengl branch from 806 to 859 Originally committed to SVN as r860. --- aegisub/VideoSink.cpp | 569 +++++++++++++++ aegisub/VideoSink.h | 7 +- aegisub/ass_exporter.cpp | 30 +- aegisub/ass_exporter.h | 3 +- aegisub/ass_file.cpp | 2 +- aegisub/ass_override.cpp | 1 + aegisub/audio_display.cpp | 29 +- aegisub/base_grid.cpp | 12 +- aegisub/csri/csri.h | 300 ++++++++ aegisub/csri/loader.h | 95 +++ aegisub/dialog_about.cpp | 5 +- aegisub/dialog_jumpto.cpp | 6 +- aegisub/dialog_options.cpp | 7 +- aegisub/dialog_properties.cpp | 6 +- aegisub/dialog_resample.cpp | 6 +- aegisub/dialog_styling_assistant.cpp | 4 +- aegisub/dialog_timing_processor.cpp | 6 +- aegisub/dialog_translation.cpp | 6 +- aegisub/factory.h | 74 ++ aegisub/frame_main.cpp | 58 +- aegisub/frame_main_events.cpp | 104 +-- aegisub/gl_wrap.cpp | 224 ++++++ aegisub/gl_wrap.h | 58 ++ aegisub/main.cpp | 2 + aegisub/options.cpp | 4 +- aegisub/setup.cpp | 13 + aegisub/stdwx.h | 1 + aegisub/subs_edit_box.cpp | 8 +- aegisub/subs_grid.cpp | 30 +- aegisub/subtitle_format_prs.cpp | 4 +- aegisub/subtitle_provider_asa.cpp | 2 +- aegisub/subtitles_provider.cpp | 84 +++ ...btitle_provider.h => subtitles_provider.h} | 68 +- aegisub/subtitles_provider_csri.cpp | 124 ++++ ...provider.cpp => subtitles_provider_csri.h} | 39 +- aegisub/utils.cpp | 15 + aegisub/utils.h | 15 +- aegisub/video_box.cpp | 265 +------ aegisub/video_box.h | 38 +- aegisub/video_context.cpp | 670 ++++++++++++++++++ aegisub/video_context.h | 171 +++++ aegisub/video_display.cpp | 612 ++++------------ aegisub/video_display.h | 82 +-- aegisub/video_display_fextracker.cpp | 434 ++++++++++++ aegisub/video_display_fextracker.h | 79 +++ aegisub/video_display_visual.cpp | 616 ++++++++-------- aegisub/video_display_visual.h | 10 +- aegisub/video_frame.cpp | 212 ++++++ aegisub/video_frame.h | 77 ++ aegisub/video_provider.cpp | 190 ++--- aegisub/video_provider.h | 83 ++- aegisub/video_provider_avs.cpp | 301 +++----- aegisub/video_provider_avs.h | 38 +- aegisub/video_provider_dshow.cpp | 208 +++--- aegisub/video_provider_dshow.h | 31 +- aegisub/video_slider.cpp | 85 ++- aegisub/video_slider.h | 1 + lua51/src/loslib.c | 2 +- 58 files changed, 4356 insertions(+), 1870 deletions(-) create mode 100644 aegisub/VideoSink.cpp create mode 100644 aegisub/csri/csri.h create mode 100644 aegisub/csri/loader.h create mode 100644 aegisub/factory.h create mode 100644 aegisub/gl_wrap.cpp create mode 100644 aegisub/gl_wrap.h create mode 100644 aegisub/subtitles_provider.cpp rename aegisub/{subtitle_provider.h => subtitles_provider.h} (55%) create mode 100644 aegisub/subtitles_provider_csri.cpp rename aegisub/{subtitle_provider.cpp => subtitles_provider_csri.h} (74%) create mode 100644 aegisub/video_context.cpp create mode 100644 aegisub/video_context.h create mode 100644 aegisub/video_display_fextracker.cpp create mode 100644 aegisub/video_display_fextracker.h create mode 100644 aegisub/video_frame.cpp create mode 100644 aegisub/video_frame.h diff --git a/aegisub/VideoSink.cpp b/aegisub/VideoSink.cpp new file mode 100644 index 000000000..033d1ae07 --- /dev/null +++ b/aegisub/VideoSink.cpp @@ -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 +#ifdef __WXDEBUG__ +#undef __WXDEBUG__ +#endif +typedef TCHAR* PTCHAR; +#include +#include +#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 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 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 m_sample; + HANDLE m_hEvent1, m_hEvent2, m_hNotify; + CComPtr 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 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(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 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 diff --git a/aegisub/VideoSink.h b/aegisub/VideoSink.h index 8ba11cf9a..77fd1fa58 100644 --- a/aegisub/VideoSink.h +++ b/aegisub/VideoSink.h @@ -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 \ No newline at end of file diff --git a/aegisub/ass_exporter.cpp b/aegisub/ass_exporter.cpp index 9b784986c..a89b7e34d 100644 --- a/aegisub/ass_exporter.cpp +++ b/aegisub/ass_exporter.cpp @@ -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); diff --git a/aegisub/ass_exporter.h b/aegisub/ass_exporter.h index 286ad44b4..e4714ebc5 100644 --- a/aegisub/ass_exporter.h +++ b/aegisub/ass_exporter.h @@ -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); }; diff --git a/aegisub/ass_file.cpp b/aegisub/ass_file.cpp index 5e6ce86f1..2afcbde13 100644 --- a/aegisub/ass_file.cpp +++ b/aegisub/ass_file.cpp @@ -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")); } diff --git a/aegisub/ass_override.cpp b/aegisub/ass_override.cpp index d2be87fdd..ade63da6f 100644 --- a/aegisub/ass_override.cpp +++ b/aegisub/ass_override.cpp @@ -53,6 +53,7 @@ AssOverrideParameter::AssOverrideParameter () { ////////////// // Destructor AssOverrideParameter::~AssOverrideParameter () { + DeleteValue(); } diff --git a/aegisub/audio_display.cpp b/aegisub/audio_display.cpp index fa291ccca..a615f945c 100644 --- a/aegisub/audio_display.cpp +++ b/aegisub/audio_display.cpp @@ -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;ilinen != 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(); } diff --git a/aegisub/csri/csri.h b/aegisub/csri/csri.h new file mode 100644 index 000000000..edf5a97c7 --- /dev/null +++ b/aegisub/csri/csri.h @@ -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 /* 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 */ diff --git a/aegisub/csri/loader.h b/aegisub/csri/loader.h new file mode 100644 index 000000000..6618b1171 --- /dev/null +++ b/aegisub/csri/loader.h @@ -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. + * + * Renderers must implement these functions as well. + * + * 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 */ + diff --git a/aegisub/dialog_about.cpp b/aegisub/dialog_about.cpp index dfa9dedf5..3b94ab6b3 100644 --- a/aegisub/dialog_about.cpp +++ b/aegisub/dialog_about.cpp @@ -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"); diff --git a/aegisub/dialog_jumpto.cpp b/aegisub/dialog_jumpto.cpp index e42c1a40d..ec3cd78e0 100644 --- a/aegisub/dialog_jumpto.cpp +++ b/aegisub/dialog_jumpto.cpp @@ -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); } diff --git a/aegisub/dialog_options.cpp b/aegisub/dialog_options.cpp index 405f28138..21d7bf122 100644 --- a/aegisub/dialog_options.cpp +++ b/aegisub/dialog_options.cpp @@ -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")); diff --git a/aegisub/dialog_properties.cpp b/aegisub/dialog_properties.cpp index e3306b2a5..a1fe3d65c 100644 --- a/aegisub/dialog_properties.cpp +++ b/aegisub/dialog_properties.cpp @@ -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(); } diff --git a/aegisub/dialog_resample.cpp b/aegisub/dialog_resample.cpp index dabcab943..103bcee1d 100644 --- a/aegisub/dialog_resample.cpp +++ b/aegisub/dialog_resample.cpp @@ -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())); } diff --git a/aegisub/dialog_styling_assistant.cpp b/aegisub/dialog_styling_assistant.cpp index 0c3117270..54387a490 100644 --- a/aegisub/dialog_styling_assistant.cpp +++ b/aegisub/dialog_styling_assistant.cpp @@ -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)); } diff --git a/aegisub/dialog_timing_processor.cpp b/aegisub/dialog_timing_processor.cpp index 3294b80d3..6bbf4abbc 100644 --- a/aegisub/dialog_timing_processor.cpp +++ b/aegisub/dialog_timing_processor.cpp @@ -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; diff --git a/aegisub/dialog_translation.cpp b/aegisub/dialog_translation.cpp index 8ad50295c..8838f6a20 100644 --- a/aegisub/dialog_translation.cpp +++ b/aegisub/dialog_translation.cpp @@ -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 (...) { diff --git a/aegisub/factory.h b/aegisub/factory.h new file mode 100644 index 000000000..3931305cd --- /dev/null +++ b/aegisub/factory.h @@ -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 + + +///////////////// +// Factory class +template +class AegisubFactory { +protected: + static std::map *factories; + void RegisterFactory(wxString name) { + if (factories == NULL) factories = new std::map; + factories->insert(std::make_pair(name.Lower(),(T*)this)); + } + static T *GetFactory(wxString name) { + if (factories == NULL) { + factories = new std::map; + return NULL; + } + std::map::iterator res = factories->find(name.Lower()); + if (res != factories->end()) return res->second; + return NULL; + } + +public: + static wxArrayString GetFactoryList() { + wxArrayString list; + for (std::map::iterator cur=factories->begin();cur!=factories->end();cur++) { + list.Add(cur->first); + } + return list; + } + virtual ~AegisubFactory() {} +}; diff --git a/aegisub/frame_main.cpp b/aegisub/frame_main.cpp index 05ca842a6..cd8dea260 100644 --- a/aegisub/frame_main.cpp +++ b/aegisub/frame_main.cpp @@ -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;iaudioDisplay->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;ivideoDisplay->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;iIsKindOf(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); } diff --git a/aegisub/gl_wrap.cpp b/aegisub/gl_wrap.cpp new file mode 100644 index 000000000..8eaed4036 --- /dev/null +++ b/aegisub/gl_wrap.cpp @@ -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 +#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 #include #include +#include /////////////// diff --git a/aegisub/subs_edit_box.cpp b/aegisub/subs_edit_box.cpp index 8d9f71607..5ab43bce8 100644 --- a/aegisub/subs_edit_box.cpp +++ b/aegisub/subs_edit_box.cpp @@ -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)); } } } diff --git a/aegisub/subs_grid.cpp b/aegisub/subs_grid.cpp index f25c580dc..ffe95c9f5 100644 --- a/aegisub/subs_grid.cpp +++ b/aegisub/subs_grid.cpp @@ -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)); } } diff --git a/aegisub/subtitle_format_prs.cpp b/aegisub/subtitle_format_prs.cpp index 05316a440..2f085a52f 100644 --- a/aegisub/subtitle_format_prs.cpp +++ b/aegisub/subtitle_format_prs.cpp @@ -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]; diff --git a/aegisub/subtitle_provider_asa.cpp b/aegisub/subtitle_provider_asa.cpp index 642a27554..165fabae2 100644 --- a/aegisub/subtitle_provider_asa.cpp +++ b/aegisub/subtitle_provider_asa.cpp @@ -36,8 +36,8 @@ /////////// // Headers +#include "setup.h" #ifdef HAVE_ASA - #include #include #include "subtitle_provider.h" diff --git a/aegisub/subtitles_provider.cpp b/aegisub/subtitles_provider.cpp new file mode 100644 index 000000000..2ae355a4f --- /dev/null +++ b/aegisub/subtitles_provider.cpp @@ -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;iCreateProvider(); + 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* AegisubFactory::factories=NULL; diff --git a/aegisub/subtitle_provider.h b/aegisub/subtitles_provider.h similarity index 55% rename from aegisub/subtitle_provider.h rename to aegisub/subtitles_provider.h index 26b89b763..409e2c5ac 100644 --- a/aegisub/subtitle_provider.h +++ b/aegisub/subtitles_provider.h @@ -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 +/////////// +// Headers #include +#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 *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 { +protected: + virtual SubtitlesProvider *CreateProvider()=0; + SubtitlesProviderFactory(wxString name) { RegisterFactory(name); } + +public: + virtual ~SubtitlesProviderFactory() {} + static SubtitlesProvider *GetProvider(); }; diff --git a/aegisub/subtitles_provider_csri.cpp b/aegisub/subtitles_provider_csri.cpp new file mode 100644 index 000000000..c0d6fbad5 --- /dev/null +++ b/aegisub/subtitles_provider_csri.cpp @@ -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); +} diff --git a/aegisub/subtitle_provider.cpp b/aegisub/subtitles_provider_csri.h similarity index 74% rename from aegisub/subtitle_provider.cpp rename to aegisub/subtitles_provider_csri.h index d2e299cc8..f87c09aa7 100644 --- a/aegisub/subtitle_provider.cpp +++ b/aegisub/subtitles_provider_csri.h @@ -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 *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(); - (*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); +}; diff --git a/aegisub/utils.cpp b/aegisub/utils.cpp index be9aecdb3..c6725a408 100644 --- a/aegisub/utils.cpp +++ b/aegisub/utils.cpp @@ -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; +} diff --git a/aegisub/utils.h b/aegisub/utils.h index d0932e8cc..afd76a019 100644 --- a/aegisub/utils.h +++ b/aegisub/utils.h @@ -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 diff --git a/aegisub/video_box.cpp b/aegisub/video_box.cpp index d829b9786..4833ef087 100644 --- a/aegisub/video_box.cpp +++ b/aegisub/video_box.cpp @@ -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;iMovement->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 diff --git a/aegisub/video_box.h b/aegisub/video_box.h index 5cee81fe3..33460d57e 100644 --- a/aegisub/video_box.h +++ b/aegisub/video_box.h @@ -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 diff --git a/aegisub/video_context.cpp b/aegisub/video_context.cpp new file mode 100644 index 000000000..9833b747b --- /dev/null +++ b/aegisub/video_context.cpp @@ -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 +#include +#include +#include +#include +#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::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::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; +} diff --git a/aegisub/video_context.h b/aegisub/video_context.h new file mode 100644 index 000000000..7939ee95f --- /dev/null +++ b/aegisub/video_context.h @@ -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 +#include +#include +#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 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() +}; diff --git a/aegisub/video_display.cpp b/aegisub/video_display.cpp index 310480f61..a0731268b 100644 --- a/aegisub/video_display.cpp +++ b/aegisub/video_display.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #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; -} diff --git a/aegisub/video_display.h b/aegisub/video_display.h index d06776b5b..2c0f4ff88 100644 --- a/aegisub/video_display.h +++ b/aegisub/video_display.h @@ -34,8 +34,7 @@ // -#ifndef VIDEO_DISPLAY_H -#define VIDEO_DISPLAY_H +#pragma once /////////// @@ -45,6 +44,7 @@ #include #endif #include +#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 diff --git a/aegisub/video_display_fextracker.cpp b/aegisub/video_display_fextracker.cpp new file mode 100644 index 000000000..c2f824c73 --- /dev/null +++ b/aegisub/video_display_fextracker.cpp @@ -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;iMovement->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_nEndFrame) return; + + int localframe = frame_n - StartFrame; + + if (curline->Tracker) { + if (curline->Tracker->GetFrame() <= localframe) return; + + // Draw ticks + for (int i=0;iTracker->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( ++localframeMovement->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;iMovement->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 diff --git a/aegisub/video_display_fextracker.h b/aegisub/video_display_fextracker.h new file mode 100644 index 000000000..9129c8b03 --- /dev/null +++ b/aegisub/video_display_fextracker.h @@ -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() +}; diff --git a/aegisub/video_display_visual.cpp b/aegisub/video_display_visual.cpp index 31f573549..0011381ec 100644 --- a/aegisub/video_display_visual.cpp +++ b/aegisub/video_display_visual.cpp @@ -36,8 +36,11 @@ ////////////// // Headers +#include +#include #include #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;igrid->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;igrid->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 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_nEndFrame ) return; - - int localframe = frame_n - StartFrame; - - if( curline->Tracker ) - { - if( curline->Tracker->GetFrame() <= localframe ) return; - - dc.SetLogicalFunction(wxCOPY); - - for( int i=0;iTracker->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( ++localframeMovement->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;iMovement->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;iMovement->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(); } } diff --git a/aegisub/video_display_visual.h b/aegisub/video_display_visual.h index d8e4c4023..535ff62c0 100644 --- a/aegisub/video_display_visual.h +++ b/aegisub/video_display_visual.h @@ -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); diff --git a/aegisub/video_frame.cpp b/aegisub/video_frame.cpp new file mode 100644 index 000000000..0d88da591 --- /dev/null +++ b/aegisub/video_frame.cpp @@ -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::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;iCreateProvider(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* AegisubFactory::factories=NULL; diff --git a/aegisub/video_provider.h b/aegisub/video_provider.h index 9965a9a34..fe0e82a65 100644 --- a/aegisub/video_provider.h +++ b/aegisub/video_provider.h @@ -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 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 { +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); }; diff --git a/aegisub/video_provider_avs.cpp b/aegisub/video_provider_avs.cpp index 82cfd5f23..70bf70516 100644 --- a/aegisub/video_provider_avs.cpp +++ b/aegisub/video_provider_avs.cpp @@ -33,36 +33,40 @@ // Contact: mailto:zeratul@cellosoft.com // +#include #include #include #include #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>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; xGetVideoInfo(); + AVSTRACE(_T("AvisynthVideoProvider: Got video info")); } diff --git a/aegisub/video_provider_avs.h b/aegisub/video_provider_avs.h index e99cd1b6c..0027dfac6 100644 --- a/aegisub/video_provider_avs.h +++ b/aegisub/video_provider_avs.h @@ -41,9 +41,10 @@ // Headers #include -#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); }; diff --git a/aegisub/video_provider_dshow.cpp b/aegisub/video_provider_dshow.cpp index b219f5117..23b065935 100644 --- a/aegisub/video_provider_dshow.cpp +++ b/aegisub/video_provider_dshow.cpp @@ -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 pR; - CLSID CLSID_VideoSink; - CLSIDFromString(L"{F13D3732-96BD-4108-AFEB-E85F68FF64DC}",&CLSID_VideoSink); - if (FAILED(hr = pR.CoCreateInstance(CLSID_VideoSink))) return hr; + //CComPtr pR; + //CLSID CLSID_VideoSink; + //CLSIDFromString(L"{F13D3732-96BD-4108-AFEB-E85F68FF64DC}",&CLSID_VideoSink); + //if (FAILED(hr = pR.CoCreateInstance(CLSID_VideoSink))) return hr; + + CComPtr 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 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 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) { diff --git a/aegisub/video_provider_dshow.h b/aegisub/video_provider_dshow.h index 69b2a549b..94da58cab 100644 --- a/aegisub/video_provider_dshow.h +++ b/aegisub/video_provider_dshow.h @@ -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); }; diff --git a/aegisub/video_slider.cpp b/aegisub/video_slider.cpp index ea7334471..eb5ba017f 100644 --- a/aegisub/video_slider.cpp +++ b/aegisub/video_slider.cpp @@ -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