Implemented a basic QuickTime video provider. Works in my simple tests on Windows, but I have no idea if it even compiles on Mac.
I leave it up to verm to add detection for it to configure; it's disabled by default (#ifdef'd out unless you #define WITH_QUICKTIME). Originally committed to SVN as r3187.
This commit is contained in:
parent
909436578d
commit
ce2a549517
7 changed files with 484 additions and 0 deletions
|
@ -1538,6 +1538,14 @@
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\video_provider_manager.h"
|
RelativePath="..\..\src\video_provider_manager.h"
|
||||||
>
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\video_provider_quicktime.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\video_provider_quicktime.h"
|
||||||
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\video_provider_yuv4mpeg.cpp"
|
RelativePath="..\..\src\video_provider_yuv4mpeg.cpp"
|
||||||
|
|
|
@ -331,6 +331,7 @@ aegisub_2_2_SOURCES = \
|
||||||
video_provider_cache.cpp \
|
video_provider_cache.cpp \
|
||||||
video_provider_dummy.cpp \
|
video_provider_dummy.cpp \
|
||||||
video_provider_manager.cpp \
|
video_provider_manager.cpp \
|
||||||
|
video_provider_quicktime.cpp \
|
||||||
video_provider_yuv4mpeg.cpp \
|
video_provider_yuv4mpeg.cpp \
|
||||||
video_slider.cpp \
|
video_slider.cpp \
|
||||||
visual_feature.cpp \
|
visual_feature.cpp \
|
||||||
|
|
|
@ -179,3 +179,8 @@
|
||||||
// Display trace-level diagnostic messages during startup
|
// Display trace-level diagnostic messages during startup
|
||||||
// Only enable for making special builds for end users having trouble with starting Aegisub
|
// Only enable for making special builds for end users having trouble with starting Aegisub
|
||||||
//#define WITH_STARTUPLOG
|
//#define WITH_STARTUPLOG
|
||||||
|
|
||||||
|
|
||||||
|
// Enable QuickTime video provider
|
||||||
|
// Requires QuickTime SDK and (on Windows) a QuickTime7 (or later) installation
|
||||||
|
//#define WITH_QUICKTIME
|
||||||
|
|
|
@ -133,6 +133,10 @@
|
||||||
#pragma comment(lib, "ffms2.lib")
|
#pragma comment(lib, "ffms2.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_QUICKTIME
|
||||||
|
#pragma comment(lib, "QTMLClient.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_PORTAUDIO
|
#ifdef WITH_PORTAUDIO
|
||||||
#pragma comment(lib,"portaudio_x86.lib")
|
#pragma comment(lib,"portaudio_x86.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,6 +51,9 @@
|
||||||
#ifdef WITH_FFMPEGSOURCE
|
#ifdef WITH_FFMPEGSOURCE
|
||||||
#include "video_provider_ffmpegsource.h"
|
#include "video_provider_ffmpegsource.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_QUICKTIME
|
||||||
|
#include "video_provider_quicktime.h"
|
||||||
|
#endif
|
||||||
#include "video_provider_dummy.h"
|
#include "video_provider_dummy.h"
|
||||||
#include "video_provider_cache.h"
|
#include "video_provider_cache.h"
|
||||||
#include "video_provider_yuv4mpeg.h"
|
#include "video_provider_yuv4mpeg.h"
|
||||||
|
@ -127,6 +130,9 @@ void VideoProviderFactoryManager::RegisterProviders() {
|
||||||
#ifdef WITH_FFMPEGSOURCE
|
#ifdef WITH_FFMPEGSOURCE
|
||||||
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
|
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_QUICKTIME
|
||||||
|
RegisterFactory(new QuickTimeVideoProviderFactory(),_T("QuickTime"));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
335
aegisub/src/video_provider_quicktime.cpp
Normal file
335
aegisub/src/video_provider_quicktime.cpp
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
// Copyright (c) 2009, Karl Blomster
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_QUICKTIME
|
||||||
|
|
||||||
|
#include "include/aegisub/aegisub.h"
|
||||||
|
#include "aegisub_endian.h"
|
||||||
|
#include "video_provider_quicktime.h"
|
||||||
|
|
||||||
|
QuickTimeVideoProvider::QuickTimeVideoProvider(Aegisub::String filename) {
|
||||||
|
in_dataref = NULL;
|
||||||
|
movie = NULL;
|
||||||
|
gw = NULL;
|
||||||
|
gw_tmp = NULL;
|
||||||
|
w = 0;
|
||||||
|
h = 0;
|
||||||
|
cur_fn = -1;
|
||||||
|
num_frames = 0;
|
||||||
|
keyframes.clear();
|
||||||
|
|
||||||
|
qt_err = noErr;
|
||||||
|
errmsg = _T("QuickTime video provider: ");
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
qt_err = InitializeQTML(0L);
|
||||||
|
QTCheckError(qt_err, wxString(_T("QuickTime video provider: Failed to initialize QTML (do you have QuickTime installed?)")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qt_err = EnterMovies();
|
||||||
|
QTCheckError(qt_err, wxString(_T("QuickTime video provider: EnterMovies() failed")));
|
||||||
|
|
||||||
|
try {
|
||||||
|
LoadVideo(filename);
|
||||||
|
}
|
||||||
|
catch (wxString temp) {
|
||||||
|
Close();
|
||||||
|
errmsg.Append(temp);
|
||||||
|
throw errmsg;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
Close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QuickTimeVideoProvider::~QuickTimeVideoProvider() {
|
||||||
|
ExitMovies();
|
||||||
|
#ifdef WIN32
|
||||||
|
TerminateQTML();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QuickTimeVideoProvider::Close() {
|
||||||
|
if (movie)
|
||||||
|
DisposeMovie(movie);
|
||||||
|
movie = NULL;
|
||||||
|
if (gw)
|
||||||
|
DisposeGWorld(gw);
|
||||||
|
gw = NULL;
|
||||||
|
if (gw_tmp)
|
||||||
|
DisposeGWorld(gw_tmp);
|
||||||
|
gw_tmp = NULL;
|
||||||
|
if (in_dataref)
|
||||||
|
DisposeHandle(in_dataref);
|
||||||
|
in_dataref = NULL;
|
||||||
|
|
||||||
|
keyframes.Clear();
|
||||||
|
qt_timestamps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 Aegisub::String _filename) {
|
||||||
|
Close();
|
||||||
|
|
||||||
|
// convert filename, first to a CFStringRef...
|
||||||
|
wxString wx_filename = wxFileName(wxString(_filename.c_str(), wxConvFile)).GetShortPath();
|
||||||
|
CFStringRef qt_filename = CFStringCreateWithCString(NULL, wx_filename.mb_str(wxConvUTF8), kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
// and then to a data reference
|
||||||
|
OSType in_dataref_type;
|
||||||
|
qt_err = QTNewDataReferenceFromFullPathCFString(qt_filename, kQTNativeDefaultPathStyle, 0,
|
||||||
|
&in_dataref, &in_dataref_type);
|
||||||
|
QTCheckError(qt_err, wxString(_T("Failed to convert filename to data reference")));
|
||||||
|
|
||||||
|
// verify that file is openable
|
||||||
|
if (!CanOpen(in_dataref, in_dataref_type))
|
||||||
|
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
|
||||||
|
short res_id = 0;
|
||||||
|
qt_err = NewMovieFromDataRef(&movie, newMovieActive, &res_id, in_dataref, in_dataref_type);
|
||||||
|
QTCheckError(qt_err, wxString(_T("Failed to open file")));
|
||||||
|
|
||||||
|
// disable automagic screen rendering
|
||||||
|
qt_err = SetMovieVisualContext(movie, NULL);
|
||||||
|
QTCheckError(qt_err, wxString(_T("Failed to disable visual context")));
|
||||||
|
|
||||||
|
// set offscreen buffer size to actual movie dimensions
|
||||||
|
GetMovieBox(movie, &m_box);
|
||||||
|
// make sure its top left corner is at (0,0)
|
||||||
|
MacOffsetRect(&m_box, -m_box.left, -m_box.top);
|
||||||
|
SetMovieBox(movie, &m_box);
|
||||||
|
w = m_box.right;
|
||||||
|
h = m_box.bottom;
|
||||||
|
// allocate a new offscreen rendering buffer with the correct dimensions
|
||||||
|
qd_err = NewGWorld(&gw, 32, &m_box, NULL, NULL, keepLocal);
|
||||||
|
if (qd_err != noErr)
|
||||||
|
throw wxString(_T("Failed to initialize offscreen drawing buffer"));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// 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
|
||||||
|
std::vector<int> timecodes = IndexFile();
|
||||||
|
if (timecodes.size() == 0)
|
||||||
|
throw wxString(_T("QuickTime video provider: failed to index file"));
|
||||||
|
|
||||||
|
// ask about vfr override etc
|
||||||
|
vfr_fps.SetVFR(timecodes);
|
||||||
|
int override_tc = wxYES;
|
||||||
|
if (VFR_Output.IsLoaded()) {
|
||||||
|
override_tc = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION);
|
||||||
|
if (override_tc == wxYES) {
|
||||||
|
VFR_Input.SetVFR(timecodes);
|
||||||
|
VFR_Output.SetVFR(timecodes);
|
||||||
|
}
|
||||||
|
} else { // no timecodes loaded, go ahead and apply
|
||||||
|
VFR_Input.SetVFR(timecodes);
|
||||||
|
VFR_Output.SetVFR(timecodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set assumed "cfr" fps (dunno if this is actually used anywhere)
|
||||||
|
double len_s = (double)GetMovieDuration(movie) / (double)GetMovieTimeScale(movie);
|
||||||
|
assumed_fps = (double)num_frames / len_s;
|
||||||
|
|
||||||
|
cur_fn = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<int> QuickTimeVideoProvider::IndexFile() {
|
||||||
|
TimeScale scale = GetMovieTimeScale(movie);
|
||||||
|
OSType v_type[1];
|
||||||
|
v_type[0] = VisualMediaCharacteristic;
|
||||||
|
std::vector<int> timecodes;
|
||||||
|
std::map<TimeValue,int> timestamp_map; // TODO: just do a binary search instead
|
||||||
|
|
||||||
|
int framecount = 1;
|
||||||
|
TimeValue cur_timeval = 0;
|
||||||
|
|
||||||
|
// get the first frame
|
||||||
|
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
|
||||||
|
while (cur_timeval >= 0) {
|
||||||
|
qt_timestamps.push_back(cur_timeval);
|
||||||
|
timestamp_map.insert(std::pair<TimeValue,int>(cur_timeval, framecount));
|
||||||
|
timecodes.push_back((cur_timeval * 1000) / scale);
|
||||||
|
framecount++;
|
||||||
|
GetMovieNextInterestingTime(movie, nextTimeMediaSample, 1, v_type, cur_timeval, 0, &cur_timeval, NULL);
|
||||||
|
}
|
||||||
|
// GetMovieNextInterestingTime() returns -1 when there are no more interesting times,
|
||||||
|
// so we incremented framecount once too much
|
||||||
|
num_frames = --framecount;
|
||||||
|
|
||||||
|
|
||||||
|
// next, find keyframes
|
||||||
|
cur_timeval = 0;
|
||||||
|
while (cur_timeval >= 0) {
|
||||||
|
GetMovieNextInterestingTime(movie, nextTimeSyncSample, 1, v_type, cur_timeval, 0, &cur_timeval, NULL);
|
||||||
|
keyframes.push_back(timestamp_map[cur_timeval]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return timecodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const AegiVideoFrame QuickTimeVideoProvider::GetFrame(int n) {
|
||||||
|
if (n < 0)
|
||||||
|
n = 0;
|
||||||
|
if (n >= num_frames)
|
||||||
|
n = num_frames-1;
|
||||||
|
cur_fn = n;
|
||||||
|
|
||||||
|
// seek
|
||||||
|
SetMovieTimeValue(movie, qt_timestamps[n]);
|
||||||
|
qt_err = GetMoviesError();
|
||||||
|
QTCheckError(qt_err, wxString::Format(_T("QuickTime video provider: failed to seek to TimeValue %d"), qt_timestamps[n]));
|
||||||
|
|
||||||
|
// render to offscreen buffer
|
||||||
|
qt_err = UpdateMovie(movie);
|
||||||
|
QTCheckError(qt_err, wxString(_T("QuickTime video provider: failed to render frame")));
|
||||||
|
MoviesTask(movie, 0L);
|
||||||
|
qt_err = GetMoviesError();
|
||||||
|
QTCheckError(qt_err, wxString(_T("QuickTime video provider: failed to render frame")));
|
||||||
|
|
||||||
|
// set up destination
|
||||||
|
AegiVideoFrame dst_frame;
|
||||||
|
dst_frame.format = FORMAT_RGB32;
|
||||||
|
dst_frame.w = w;
|
||||||
|
dst_frame.h = h;
|
||||||
|
dst_frame.invertChannels = true;
|
||||||
|
dst_frame.flipped = false;
|
||||||
|
dst_frame.pitch[0] = w * 4; // 4 bytes per sample
|
||||||
|
dst_frame.Allocate();
|
||||||
|
|
||||||
|
// copy data from offscreen buffer
|
||||||
|
Ptr src_ptr8 = GetPixBaseAddr(GetGWorldPixMap(gw));
|
||||||
|
uint32_t *src_ptr = reinterpret_cast<uint32_t *>(src_ptr8);
|
||||||
|
uint32_t *dst_ptr = reinterpret_cast<uint32_t *>(dst_frame.data[0]);
|
||||||
|
for (int i=0; i<(w*h); i++)
|
||||||
|
// swap endian if needed; quickdraw always renders big-endian
|
||||||
|
*dst_ptr++ = Endian::BigToMachine(*src_ptr++); // fun with pointers!
|
||||||
|
|
||||||
|
return dst_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// Utility functions
|
||||||
|
|
||||||
|
void QuickTimeVideoProvider::QTCheckError(OSErr err, wxString errmsg) {
|
||||||
|
if (err != noErr)
|
||||||
|
throw errmsg;
|
||||||
|
/* CheckError(err, errmsg.c_str()); // I wonder if this actually works on Mac, and if so, what it does */
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuickTimeVideoProvider::GetWidth() {
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuickTimeVideoProvider::GetHeight() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuickTimeVideoProvider::GetFrameCount() {
|
||||||
|
return num_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuickTimeVideoProvider::GetPosition() {
|
||||||
|
return cur_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
double QuickTimeVideoProvider::GetFPS() {
|
||||||
|
return assumed_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QuickTimeVideoProvider::AreKeyFramesLoaded() {
|
||||||
|
if (keyframes.GetCount() > 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxArrayInt QuickTimeVideoProvider::GetKeyFrames() {
|
||||||
|
return keyframes;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameRate QuickTimeVideoProvider::GetTrueFrameRate() {
|
||||||
|
return vfr_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* WITH_QUICKTIME */
|
125
aegisub/src/video_provider_quicktime.h
Normal file
125
aegisub/src/video_provider_quicktime.h
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright (c) 2009, Karl Blomster
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <wx/wxprec.h>
|
||||||
|
|
||||||
|
#ifdef WITH_QUICKTIME
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// avoid conflicts between MSVC's stdint.h and QT's stdint.h
|
||||||
|
#define _STDINT_H
|
||||||
|
// get MSVC to shut up about a macro redefinition in QT's ConditionalMacros.h
|
||||||
|
#pragma warning(disable: 4004)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#define MacOffsetRect OffsetRect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "include/aegisub/video_provider.h"
|
||||||
|
extern "C" {
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <QTML.h>
|
||||||
|
#include <Movies.h>
|
||||||
|
#include <Files.h>
|
||||||
|
#include <QDOffscreen.h>
|
||||||
|
#else
|
||||||
|
#include <QuickTime/QuickTime.h> // not sure about this path, someone on mac needs to test it
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#include <wx/dynarray.h>
|
||||||
|
#include <wx/filename.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "vfr.h"
|
||||||
|
|
||||||
|
|
||||||
|
class QuickTimeVideoProvider : public VideoProvider {
|
||||||
|
private:
|
||||||
|
Movie movie; // source object
|
||||||
|
GWorldPtr gw, gw_tmp; // render buffers
|
||||||
|
Handle in_dataref; // input data handle
|
||||||
|
|
||||||
|
int w, h; // width/height
|
||||||
|
int num_frames; // length of file in frames
|
||||||
|
int cur_fn; // current frame number
|
||||||
|
FrameRate vfr_fps; // vfr framerate
|
||||||
|
double assumed_fps; // average framerate
|
||||||
|
wxArrayInt keyframes; // list of keyframes
|
||||||
|
std::vector<int> qt_timestamps; // qt timestamps (used for seeking)
|
||||||
|
|
||||||
|
OSErr qt_err; // quicktime error code
|
||||||
|
wxString errmsg; // aegisub error message
|
||||||
|
|
||||||
|
bool CanOpen(const Handle& dataref, const OSType dataref_type);
|
||||||
|
void LoadVideo(const Aegisub::String filename);
|
||||||
|
std::vector<int> IndexFile();
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
void QTCheckError(OSErr err, wxString errmsg);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QuickTimeVideoProvider(Aegisub::String filename);
|
||||||
|
~QuickTimeVideoProvider();
|
||||||
|
|
||||||
|
const AegiVideoFrame GetFrame(int n);
|
||||||
|
int GetPosition();
|
||||||
|
int GetFrameCount();
|
||||||
|
|
||||||
|
int GetWidth();
|
||||||
|
int GetHeight();
|
||||||
|
double GetFPS();
|
||||||
|
bool IsVFR() { return true; };
|
||||||
|
FrameRate GetTrueFrameRate();
|
||||||
|
wxArrayInt GetKeyFrames();
|
||||||
|
bool QuickTimeVideoProvider::AreKeyFramesLoaded();
|
||||||
|
Aegisub::String GetDecoderName() { return L"QuickTime"; };
|
||||||
|
bool IsNativelyByFrames() { return true; };
|
||||||
|
int GetDesiredCacheSize() { return 8; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QuickTimeVideoProviderFactory : public VideoProviderFactory {
|
||||||
|
public:
|
||||||
|
VideoProvider *CreateProvider(Aegisub::String video) { return new QuickTimeVideoProvider(video); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* WITH_QUICKTIME */
|
Loading…
Reference in a new issue