Move more stuff to the common QT provider class and generalize initializing/de-initializing QuickTime.

Originally committed to SVN as r3243.
This commit is contained in:
Karl Blomster 2009-07-23 23:57:12 +00:00
parent 87e96be4b5
commit 7149e01888
4 changed files with 97 additions and 61 deletions

View file

@ -34,11 +34,56 @@
// //
#include <wx/wxprec.h> #include "quicktime_common.h"
#include "config.h"
#ifdef WITH_QUICKTIME #ifdef WITH_QUICKTIME
#include "quicktime_common.h" #include <wx/wxprec.h>
// static fun
int QuickTimeProvider::qt_initcount = 0;
GWorldPtr QuickTimeProvider::default_gworld = NULL;
void QuickTimeProvider::InitQuickTime() {
OSErr qt_err;
#ifdef WIN32
qt_err = InitializeQTML(0L);
QTCheckError(qt_err, wxString(_T("Failed to initialize QTML (do you have QuickTime installed?)")));
#endif
qt_err = EnterMovies();
QTCheckError(qt_err, wxString(_T("EnterMovies() failed")));
// have we been inited before?
if (qt_initcount <= 0) {
// we haven't, allocate an offscreen graphics world
// we need to do this before we actually open anything, or quicktime may crash (heh)
Rect def_box;
def_box.top = 0;
def_box.left = 0;
def_box.bottom = 320; // pick some random dimensions for now;
def_box.right = 240; // we won't actually use this buffer to render anything
QDErr qd_err = NewGWorld(&default_gworld, 32, &def_box, NULL, NULL, keepLocal);
if (qd_err != noErr)
throw wxString(_T("Failed to initialize temporary offscreen drawing buffer"));
SetGWorld(default_gworld, NULL);
}
qt_initcount++;
}
void QuickTimeProvider::DeInitQuickTime() {
#ifdef WIN32
TerminateQTML();
#endif
qt_initcount--;
if (qt_initcount <= 0) {
ExitMovies();
DisposeGWorld(default_gworld);
}
}
void QuickTimeProvider::wxStringToDataRef(const wxString &string, Handle *dataref, OSType *dataref_type) { void QuickTimeProvider::wxStringToDataRef(const wxString &string, Handle *dataref, OSType *dataref_type) {
@ -53,10 +98,26 @@ void QuickTimeProvider::wxStringToDataRef(const wxString &string, Handle *datare
} }
// check if this error code signifies an error, and if it does, throw an exception
void QuickTimeProvider::QTCheckError(OSErr err, wxString errmsg) { void QuickTimeProvider::QTCheckError(OSErr err, wxString errmsg) {
if (err != noErr) if (err != noErr)
throw errmsg; throw errmsg;
/* CheckError(err, errmsg.c_str()); // I wonder if this actually works on Mac, and if so, what it does */ /* CheckError(err, errmsg.c_str()); // I wonder if this actually works on Mac, and if so, what it does */
} }
bool QuickTimeProvider::CanOpen(const Handle& dataref, const OSType dataref_type) {
Boolean can_open;
Boolean prefer_img;
OSErr qt_err = CanQuickTimeOpenDataRef(dataref, dataref_type, NULL, &can_open, &prefer_img, 0);
QTCheckError(qt_err, wxString(_T("Checking if file is openable failed")));
// don't bother trying to open things quicktime considers images
if (can_open && !prefer_img)
return true;
else
return false;
}
#endif /* WITH_QUICKTIME */ #endif /* WITH_QUICKTIME */

View file

@ -37,18 +37,19 @@
#pragma once #pragma once
#include "config.h" #include "config.h"
#include <wx/wxprec.h>
#ifdef WITH_QUICKTIME #ifdef WITH_QUICKTIME
#include <wx/wxprec.h>
#include <wx/thread.h>
#include "include/aegisub/aegisub.h"
// qt stuff
#ifdef _MSC_VER #ifdef _MSC_VER
// avoid conflicts between MSVC's stdint.h and QT's stdint.h // avoid conflicts between MSVC's stdint.h and QT's stdint.h
#define _STDINT_H #define _STDINT_H
// get MSVC to shut up about a macro redefinition in QT's ConditionalMacros.h // get MSVC to shut up about a macro redefinition in QT's ConditionalMacros.h
#pragma warning(disable: 4004) #pragma warning(disable: 4004)
#endif #endif
#include "include/aegisub/aegisub.h"
extern "C" { extern "C" {
#ifdef WIN32 #ifdef WIN32
#include <QTML.h> #include <QTML.h>
@ -63,9 +64,15 @@ extern "C" {
class QuickTimeProvider { class QuickTimeProvider {
public: public:
void InitQuickTime();
void DeInitQuickTime();
void wxStringToDataRef(const wxString &string, Handle *dataref, OSType *dataref_type); void wxStringToDataRef(const wxString &string, Handle *dataref, OSType *dataref_type);
bool CanOpen(const Handle& dataref, const OSType dataref_type);
void QTCheckError(OSErr err, wxString errmsg); void QTCheckError(OSErr err, wxString errmsg);
static int qt_initcount;
static GWorldPtr default_gworld;
virtual ~QuickTimeProvider() {}; virtual ~QuickTimeProvider() {};
}; };

View file

@ -33,12 +33,13 @@
// Contact: mailto:zeratul@cellosoft.com // Contact: mailto:zeratul@cellosoft.com
// //
#include "video_provider_quicktime.h"
#ifdef WITH_QUICKTIME #ifdef WITH_QUICKTIME
#include "video_provider_quicktime.h"
#include "aegisub_endian.h" #include "aegisub_endian.h"
// this function has a different name on win32 because the original name
// conflicts with a windows api function
#ifndef WIN32 #ifndef WIN32
#define MacOffsetRect OffsetRect #define MacOffsetRect OffsetRect
#endif #endif
@ -48,7 +49,6 @@ QuickTimeVideoProvider::QuickTimeVideoProvider(wxString filename) {
in_dataref = NULL; in_dataref = NULL;
movie = NULL; movie = NULL;
gw = NULL; gw = NULL;
gw_tmp = NULL;
w = 0; w = 0;
h = 0; h = 0;
cur_fn = -1; cur_fn = -1;
@ -58,14 +58,19 @@ QuickTimeVideoProvider::QuickTimeVideoProvider(wxString filename) {
qt_err = noErr; qt_err = noErr;
errmsg = _T("QuickTime video provider: "); errmsg = _T("QuickTime video provider: ");
#ifdef WIN32 // try to init quicktime
qt_err = InitializeQTML(0L); try {
QTCheckError(qt_err, wxString(_T("QuickTime video provider: Failed to initialize QTML (do you have QuickTime installed?)"))); InitQuickTime();
#endif }
catch (wxString temp) {
qt_err = EnterMovies(); errmsg.Append(temp);
QTCheckError(qt_err, wxString(_T("QuickTime video provider: EnterMovies() failed"))); throw errmsg;
}
catch (...) {
throw;
}
// try loading the file
try { try {
LoadVideo(filename); LoadVideo(filename);
} }
@ -83,10 +88,7 @@ QuickTimeVideoProvider::QuickTimeVideoProvider(wxString filename) {
QuickTimeVideoProvider::~QuickTimeVideoProvider() { QuickTimeVideoProvider::~QuickTimeVideoProvider() {
Close(); Close();
ExitMovies(); DeInitQuickTime();
#ifdef WIN32
TerminateQTML();
#endif
} }
@ -97,9 +99,6 @@ void QuickTimeVideoProvider::Close() {
if (gw) if (gw)
DisposeGWorld(gw); DisposeGWorld(gw);
gw = NULL; gw = NULL;
if (gw_tmp)
DisposeGWorld(gw_tmp);
gw_tmp = NULL;
if (in_dataref) if (in_dataref)
DisposeHandle(in_dataref); DisposeHandle(in_dataref);
in_dataref = NULL; in_dataref = NULL;
@ -109,18 +108,7 @@ void QuickTimeVideoProvider::Close() {
} }
bool QuickTimeVideoProvider::CanOpen(const Handle& dataref, const OSType dataref_type) {
Boolean can_open;
Boolean prefer_img;
qt_err = CanQuickTimeOpenDataRef(dataref, dataref_type, NULL, &can_open, &prefer_img, 0);
QTCheckError(qt_err, wxString(_T("Checking if file is openable failed")));
// don't bother trying to open things quicktime considers images
if (can_open && !prefer_img)
return true;
else
return false;
}
void QuickTimeVideoProvider::LoadVideo(const wxString _filename) { void QuickTimeVideoProvider::LoadVideo(const wxString _filename) {
@ -133,18 +121,6 @@ void QuickTimeVideoProvider::LoadVideo(const wxString _filename) {
if (!CanOpen(in_dataref, in_dataref_type)) if (!CanOpen(in_dataref, in_dataref_type))
throw wxString(_T("QuickTime cannot open file as video")); throw wxString(_T("QuickTime cannot open file as video"));
// allocate an offscreen graphics world
// we need to do this before we actually open the movie, or quicktime may crash (heh)
Rect m_box; // movie render rectangle
m_box.top = 0;
m_box.left = 0;
m_box.bottom = 320; // pick some random dimensions for now;
m_box.right = 240; // we won't actually use this buffer to render anything
QDErr qd_err = NewGWorld(&gw_tmp, 32, &m_box, NULL, NULL, keepLocal);
if (qd_err != noErr)
throw wxString(_T("Failed to initialize temporary offscreen drawing buffer"));
SetGWorld(gw_tmp, NULL);
// actually open file // actually open file
short res_id = 0; short res_id = 0;
qt_err = NewMovieFromDataRef(&movie, newMovieActive, &res_id, in_dataref, in_dataref_type); qt_err = NewMovieFromDataRef(&movie, newMovieActive, &res_id, in_dataref, in_dataref_type);
@ -155,6 +131,7 @@ void QuickTimeVideoProvider::LoadVideo(const wxString _filename) {
QTCheckError(qt_err, wxString(_T("Failed to disable visual context"))); QTCheckError(qt_err, wxString(_T("Failed to disable visual context")));
// set offscreen buffer size to actual movie dimensions // set offscreen buffer size to actual movie dimensions
Rect m_box;
GetMovieBox(movie, &m_box); GetMovieBox(movie, &m_box);
// make sure its top left corner is at (0,0) // make sure its top left corner is at (0,0)
MacOffsetRect(&m_box, -m_box.left, -m_box.top); MacOffsetRect(&m_box, -m_box.left, -m_box.top);
@ -162,20 +139,12 @@ void QuickTimeVideoProvider::LoadVideo(const wxString _filename) {
w = m_box.right; w = m_box.right;
h = m_box.bottom; h = m_box.bottom;
// allocate a new offscreen rendering buffer with the correct dimensions // allocate a new offscreen rendering buffer with the correct dimensions
qd_err = NewGWorld(&gw, 32, &m_box, NULL, NULL, keepLocal); QDErr qd_err = NewGWorld(&gw, 32, &m_box, NULL, NULL, keepLocal);
if (qd_err != noErr) if (qd_err != noErr)
throw wxString(_T("Failed to initialize offscreen drawing buffer")); throw wxString(_T("Failed to initialize offscreen drawing buffer"));
// select our new offscreen render target // select our new offscreen render target
SetGWorld(gw, NULL); // make sure the old one isn't used, since we're about to kill it
SetMovieGWorld(movie, gw, NULL); SetMovieGWorld(movie, gw, NULL);
// Get rid of our old temporary rendering buffer.
// All this ridicolous hoop-jumping with two buffers is because no matter what I've tried,
// UpdateGWorld() either doesn't update the buffer, or if it does, trying to render to the
// updated buffer causes access violations.
// :argh: QuickDraw :argh:
DisposeGWorld(gw_tmp);
gw_tmp = NULL;
// get timestamps, keyframes and framecount // get timestamps, keyframes and framecount
std::vector<int> timecodes = IndexFile(); std::vector<int> timecodes = IndexFile();
@ -216,7 +185,6 @@ std::vector<int> QuickTimeVideoProvider::IndexFile() {
// get the first frame // get the first frame
GetMovieNextInterestingTime(movie, nextTimeMediaSample + nextTimeEdgeOK, 1, v_type, cur_timeval, 0, &cur_timeval, NULL); GetMovieNextInterestingTime(movie, nextTimeMediaSample + nextTimeEdgeOK, 1, v_type, cur_timeval, 0, &cur_timeval, NULL);
keyframes.push_back(0); // interesting assumption?
// first, find timestamps and count frames // first, find timestamps and count frames
while (cur_timeval >= 0) { while (cur_timeval >= 0) {
@ -233,6 +201,7 @@ std::vector<int> QuickTimeVideoProvider::IndexFile() {
// next, find keyframes // next, find keyframes
cur_timeval = 0; cur_timeval = 0;
keyframes.push_back(0); // interesting assumption?
while (cur_timeval >= 0) { while (cur_timeval >= 0) {
GetMovieNextInterestingTime(movie, nextTimeSyncSample, 1, v_type, cur_timeval, 0, &cur_timeval, NULL); GetMovieNextInterestingTime(movie, nextTimeSyncSample, 1, v_type, cur_timeval, 0, &cur_timeval, NULL);
keyframes.push_back(timestamp_map[cur_timeval]); keyframes.push_back(timestamp_map[cur_timeval]);

View file

@ -36,22 +36,22 @@
#pragma once #pragma once
#include <wx/wxprec.h> #include "quicktime_common.h"
#ifdef WITH_QUICKTIME #ifdef WITH_QUICKTIME
#include "include/aegisub/video_provider.h" #include <wx/wxprec.h>
#include "quicktime_common.h"
#include <wx/dynarray.h> #include <wx/dynarray.h>
#include <wx/filename.h> #include <wx/filename.h>
#include <vector> #include <vector>
#include <map> #include <map>
#include "include/aegisub/video_provider.h"
#include "vfr.h" #include "vfr.h"
class QuickTimeVideoProvider : public VideoProvider, QuickTimeProvider { class QuickTimeVideoProvider : public VideoProvider, QuickTimeProvider {
private: private:
Movie movie; // source object Movie movie; // source object
GWorldPtr gw, gw_tmp; // render buffers GWorldPtr gw; // render buffer
Handle in_dataref; // input data handle Handle in_dataref; // input data handle
int w, h; // width/height int w, h; // width/height
@ -65,7 +65,6 @@ private:
OSErr qt_err; // quicktime error code OSErr qt_err; // quicktime error code
wxString errmsg; // aegisub error message wxString errmsg; // aegisub error message
bool CanOpen(const Handle& dataref, const OSType dataref_type);
void LoadVideo(const wxString filename); void LoadVideo(const wxString filename);
std::vector<int> IndexFile(); std::vector<int> IndexFile();
void Close(); void Close();