From 1ca5d737338406515dd06144025d83ff92b5fe8e Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 2 Apr 2008 11:51:16 +0000 Subject: [PATCH] --- .../juce_win32_SystemStats.cpp | 2 +- juce.h | 2 +- juce_Config.h | 18 +- .../juce_QuickTimeAudioFormat.cpp | 967 ++++++++---------- .../juce_QuickTimeAudioFormat.h | 2 +- .../special/juce_QuickTimeMovieComponent.cpp | 355 +++++-- .../special/juce_QuickTimeMovieComponent.h | 11 +- 7 files changed, 706 insertions(+), 651 deletions(-) diff --git a/build/win32/platform_specific_code/juce_win32_SystemStats.cpp b/build/win32/platform_specific_code/juce_win32_SystemStats.cpp index c2f41fbb83..8c41592d7e 100644 --- a/build/win32/platform_specific_code/juce_win32_SystemStats.cpp +++ b/build/win32/platform_specific_code/juce_win32_SystemStats.cpp @@ -54,7 +54,7 @@ #pragma comment(lib, "GlU32.Lib") #endif - #if JUCE_QUICKTIME_AUDIOFORMAT + #if JUCE_QUICKTIME #pragma comment(lib, "QTMLClient.lib") #endif #endif diff --git a/juce.h b/juce.h index ab754a92a1..f596b72fee 100644 --- a/juce.h +++ b/juce.h @@ -177,7 +177,7 @@ END_JUCE_NAMESPACE #pragma comment(lib, "GlU32.Lib") #endif - #if JUCE_QUICKTIME_AUDIOFORMAT + #if JUCE_QUICKTIME #pragma comment (lib, "QTMLClient.lib") #endif diff --git a/juce_Config.h b/juce_Config.h index c599d7de6e..99efe67fa2 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -78,24 +78,18 @@ //============================================================================= /** Comment out this macro if you don't want to enable QuickTime or if you don't - have QuickTime installed. If it's not enabled, the QuickTimeWindow class will - be unavailable. + have the SDK installed. + + If this flag is not enabled, the QuickTimeMovieComponent and QuickTimeAudioFormat + classes will be unavailable. - On Windows, if you enable this, you'll need to make sure the Apple Quicktime.dll - file is found on your include path. By default the Quicktime installer will have - put this in the "/Program Files/QuickTime" folder. Only QuickTime version 7 or later - is currently supported. + On Windows, if you enable this, you'll need to have the QuickTime SDK + installed, and its header files will need to be on your include path. */ #if ! (defined (JUCE_QUICKTIME) || defined (LINUX) || (defined (_WIN32) && ! defined (_MSC_VER))) #define JUCE_QUICKTIME 1 #endif -/** This lets you enable the QuickTimeAudioFormat class. - If you're using this on win32, you'll need to have installed the QuickTime SDK. -*/ -#if ! (defined (JUCE_QUICKTIME_AUDIOFORMAT) || defined (LINUX) || (defined (_WIN32) && ! defined (_MSC_VER))) -// #define JUCE_QUICKTIME_AUDIOFORMAT 1 -#endif //============================================================================= /** Comment out this macro if you don't want to enable OpenGL or if you don't diff --git a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp index 5a9e48d4ed..7d01f1c260 100644 --- a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp +++ b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp @@ -1,561 +1,406 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#include "../../../../juce_Config.h" - -#if JUCE_QUICKTIME_AUDIOFORMAT - -#if ! defined (_WIN32) - #include - #include - #include - #include - #include -#else - #ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable : 4100) - #endif - - #include - #include - #include - #include - #include - - #ifdef _MSC_VER - #pragma warning (pop) - #endif -#endif - -#include "../../../juce_core/basics/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_QuickTimeAudioFormat.h" -#include "../../../juce_core/text/juce_LocalisedStrings.h" -#include "../../../juce_core/threads/juce_Thread.h" -#include "../../../juce_core/io/files/juce_FileInputStream.h" -#include "../../../juce_core/io/network/juce_URL.h" - -#define qtFormatName TRANS("QuickTime file") -static const tchar* const extensions[] = { T(".mov"), T(".mp3"), 0 }; - -//============================================================================== -class QTAudioReader : public AudioFormatReader -{ -public: - QTAudioReader (InputStream* const input_, const int trackNum_) - : AudioFormatReader (input_, qtFormatName), - ok (false), - movie (0), - trackNum (trackNum_), - extractor (0), - lastSampleRead (0), - lastThreadId (0) - { - bufferList = (AudioBufferList*) juce_calloc (256); - -#ifdef WIN32 - if (InitializeQTML (0) != noErr) - return; -#endif - if (EnterMovies() != noErr) - return; - -#if JUCE_MAC - EnterMoviesOnThread (0); -#endif - - if (! openMovie (input_)) - return; - - { - const int numTracks = GetMovieTrackCount (movie); - int trackCount = 0; - - for (int i = 1; i <= numTracks; ++i) - { - track = GetMovieIndTrack (movie, i); - media = GetTrackMedia (track); - - OSType mediaType; - GetMediaHandlerDescription (media, &mediaType, 0, 0); - - if (mediaType == SoundMediaType - && trackCount++ == trackNum_) - { - ok = true; - break; - } - } - } - - if (! ok) - return; - - ok = false; - - lengthInSamples = GetMediaDecodeDuration (media); - usesFloatingPointData = false; - - samplesPerFrame = (int) (GetMediaDecodeDuration (media) / GetMediaSampleCount (media)); - - trackUnitsPerFrame = GetMovieTimeScale (movie) * samplesPerFrame - / GetMediaTimeScale (media); - - OSStatus err = MovieAudioExtractionBegin (movie, 0, &extractor); - - unsigned long output_layout_size; - err = MovieAudioExtractionGetPropertyInfo (extractor, - kQTPropertyClass_MovieAudioExtraction_Audio, - kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, - 0, &output_layout_size, 0); - if (err != noErr) - return; - - AudioChannelLayout* const qt_audio_channel_layout - = (AudioChannelLayout*) juce_calloc (output_layout_size); - - err = MovieAudioExtractionGetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Audio, - kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, - output_layout_size, qt_audio_channel_layout, 0); - - qt_audio_channel_layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; - - err = MovieAudioExtractionSetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Audio, - kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, - sizeof (qt_audio_channel_layout), - qt_audio_channel_layout); - - juce_free (qt_audio_channel_layout); - - err = MovieAudioExtractionGetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Audio, - kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, - sizeof (inputStreamDesc), - &inputStreamDesc, 0); - if (err != noErr) - return; - - inputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger - | kAudioFormatFlagIsPacked - | kAudioFormatFlagsNativeEndian; - inputStreamDesc.mBitsPerChannel = sizeof (SInt16) * 8; - inputStreamDesc.mChannelsPerFrame = jmin (2, inputStreamDesc.mChannelsPerFrame); - inputStreamDesc.mBytesPerFrame = sizeof (SInt16) * inputStreamDesc.mChannelsPerFrame; - inputStreamDesc.mBytesPerPacket = inputStreamDesc.mBytesPerFrame; - - err = MovieAudioExtractionSetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Audio, - kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, - sizeof (inputStreamDesc), - &inputStreamDesc); - if (err != noErr) - return; - - Boolean allChannelsDiscrete = false; - err = MovieAudioExtractionSetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Movie, - kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, - sizeof (allChannelsDiscrete), - &allChannelsDiscrete); - - if (err != noErr) - return; - - bufferList->mNumberBuffers = 1; - bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame; - bufferList->mBuffers[0].mDataByteSize = (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16; - bufferList->mBuffers[0].mData = malloc (bufferList->mBuffers[0].mDataByteSize); - - sampleRate = inputStreamDesc.mSampleRate; - bitsPerSample = 16; - numChannels = inputStreamDesc.mChannelsPerFrame; - - detachThread(); - ok = true; - } - - ~QTAudioReader() - { - if (extractor != 0) - { - MovieAudioExtractionEnd (extractor); - extractor = 0; - } - - checkThreadIsAttached(); - DisposeMovie (movie); - - juce_free (bufferList->mBuffers[0].mData); - juce_free (bufferList); - } - - bool read (int** destSamples, - int64 startSample, - int numSamples) - { - checkThreadIsAttached(); - int done = 0; - - while (numSamples > 0) - { - if (! loadFrame ((int) startSample)) - return false; - - const int numToDo = jmin (numSamples, samplesPerFrame); - - for (unsigned int j = 0; j < inputStreamDesc.mChannelsPerFrame; ++j) - { - if (destSamples[j] != 0) - { - const short* const src = ((const short*) bufferList->mBuffers[0].mData) + j; - - for (int i = 0; i < numToDo; ++i) - destSamples[j][done + i] = src [i << 1] << 16; - } - } - - done += numToDo; - startSample += numToDo; - numSamples -= numToDo; - } - - detachThread(); - return true; - } - - bool loadFrame (const int sampleNum) - { - if (lastSampleRead != sampleNum) - { - TimeRecord time; - time.scale = (TimeScale) inputStreamDesc.mSampleRate; - time.base = 0; - time.value.hi = 0; - time.value.lo = (UInt32) sampleNum; - - OSStatus err = MovieAudioExtractionSetProperty (extractor, - kQTPropertyClass_MovieAudioExtraction_Movie, - kQTMovieAudioExtractionMoviePropertyID_CurrentTime, - sizeof (time), &time); - - if (err != noErr) - return false; - } - - bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * samplesPerFrame; - - UInt32 outFlags = 0; - UInt32 actualNumSamples = samplesPerFrame; - OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumSamples, - bufferList, &outFlags); - - lastSampleRead = sampleNum + samplesPerFrame; - - return err == noErr; - } - - juce_UseDebuggingNewOperator - - bool ok; - -private: - Movie movie; - Media media; - Track track; - const int trackNum; - double trackUnitsPerFrame; - int samplesPerFrame; - int lastSampleRead, lastThreadId; - MovieAudioExtractionRef extractor; - AudioStreamBasicDescription inputStreamDesc; - AudioBufferList* bufferList; - - /*OSErr readMovieStream (long offset, long size, void* dataPtr) - { - input->setPosition (offset); - input->read (dataPtr, size); - return noErr; - } - - static OSErr readMovieStreamProc (long offset, long size, void* dataPtr, void* userRef) - { - return ((QTAudioReader*) userRef)->readMovieStream (offset, size, dataPtr); - }*/ - - static Handle createHandleDataRef (Handle dataHandle, const char* fileName) - { - Handle dataRef = 0; - OSStatus err = PtrToHand (&dataHandle, &dataRef, sizeof (Handle)); - if (err == noErr) - { - Str255 suffix; -#if JUCE_WIN32 - strcpy_s ((char*) suffix, 128, fileName); -#else - strcpy ((char*) suffix, fileName); -#endif - StringPtr name = suffix; - err = PtrAndHand (name, dataRef, name[0]+1); - - if (err == noErr) - { - long atoms[3]; - atoms[0] = EndianU32_NtoB (3 * sizeof (long)); - atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); - atoms[2] = EndianU32_NtoB (MovieFileType); - - err = PtrAndHand (atoms, dataRef, 3 * sizeof (long)); - - if (err == noErr) - return dataRef; - } - - DisposeHandle (dataRef); - } - - return 0; - } - - static CFStringRef juceStringToCFString (const String& s) - { - const int len = s.length(); - const juce_wchar* const t = (const juce_wchar*) s; - - UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); - - for (int i = 0; i <= len; ++i) - temp[i] = t[i]; - - CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); - juce_free (temp); - - return result; - } - - //============================================================================== - bool openMovie (InputStream* const input) - { - bool ok = false; - - QTNewMoviePropertyElement props[5]; - zeromem (props, sizeof (props)); - int prop = 0; - - DataReferenceRecord dr; - props[prop].propClass = kQTPropertyClass_DataLocation; - props[prop].propID = kQTDataLocationPropertyID_DataReference; - props[prop].propValueSize = sizeof (dr); - props[prop].propValueAddress = (void*) &dr; - ++prop; - - FileInputStream* const fin = dynamic_cast (input); - - if (fin != 0) - { - CFStringRef filePath = juceStringToCFString (fin->getFile().getFullPathName()); - - QTNewDataReferenceFromFullPathCFString (filePath, (QTPathStyle) kQTNativeDefaultPathStyle, 0, - &dr.dataRef, &dr.dataRefType); - - - ok = openMovie (props, prop); - - DisposeHandle (dr.dataRef); - CFRelease (filePath); - } - else - { - // sanity-check because this currently needs to load the whole stream into memory.. - jassert (input->getTotalLength() < 50 * 1024 * 1024); - - Handle dataHandle = NewHandle ((Size) input->getTotalLength()); - HLock (dataHandle); - // read the entire stream into memory - this is a pain, but can't get it to work - // properly using a custom callback to supply the data. - input->read (*dataHandle, (int) input->getTotalLength()); - HUnlock (dataHandle); - - // different types to get QT to try. (We should really be a bit smarter here by - // working out in advance which one the stream contains, rather than just trying - // each one) - const char* const suffixesToTry[] = { "\04.mov", "\04.mp3", - "\04.avi", "\04.m4a" }; - - for (int i = 0; i < numElementsInArray (suffixesToTry) && ! ok; ++i) - { - dr.dataRef = createHandleDataRef (dataHandle, suffixesToTry [i]); - - /* // this fails for some bizarre reason - it can be bodged to work with - // movies, but can't seem to do it for other file types.. - QTNewMovieUserProcRecord procInfo; - procInfo.getMovieUserProc = NewGetMovieUPP (readMovieStreamProc); - procInfo.getMovieUserProcRefcon = this; - procInfo.defaultDataRef.dataRef = dataRef; - procInfo.defaultDataRef.dataRefType = HandleDataHandlerSubType; - - props[prop].propClass = kQTPropertyClass_DataLocation; - props[prop].propID = kQTDataLocationPropertyID_MovieUserProc; - props[prop].propValueSize = sizeof (procInfo); - props[prop].propValueAddress = (void*) &procInfo; - ++prop; */ - - dr.dataRefType = HandleDataHandlerSubType; - ok = openMovie (props, prop); - - DisposeHandle (dr.dataRef); - } - - DisposeHandle (dataHandle); - } - - return ok; - } - - bool openMovie (QTNewMoviePropertyElement* props, int prop) - { - Boolean trueBool = true; - props[prop].propClass = kQTPropertyClass_MovieInstantiation; - props[prop].propID = kQTMovieInstantiationPropertyID_DontResolveDataRefs; - props[prop].propValueSize = sizeof (trueBool); - props[prop].propValueAddress = &trueBool; - ++prop; - - props[prop].propClass = kQTPropertyClass_MovieInstantiation; - props[prop].propID = kQTMovieInstantiationPropertyID_AsyncOK; - props[prop].propValueSize = sizeof (trueBool); - props[prop].propValueAddress = &trueBool; - ++prop; - - Boolean isActive = true; - props[prop].propClass = kQTPropertyClass_NewMovieProperty; - props[prop].propID = kQTNewMoviePropertyID_Active; - props[prop].propValueSize = sizeof (isActive); - props[prop].propValueAddress = &isActive; - ++prop; - -#if JUCE_MAC - SetPort (0); -#else - MacSetPort (0); -#endif - - jassert (prop <= 5); - OSStatus err = NewMovieFromProperties (prop, props, 0, 0, &movie); - - return err == noErr; - } - - //============================================================================== - void checkThreadIsAttached() - { -#if JUCE_MAC - if (Thread::getCurrentThreadId() != lastThreadId) - EnterMoviesOnThread (0); - AttachMovieToCurrentThread (movie); -#endif - } - - void detachThread() - { -#if JUCE_MAC - DetachMovieFromCurrentThread (movie); -#endif - } -}; - - -//============================================================================== -QuickTimeAudioFormat::QuickTimeAudioFormat() - : AudioFormat (qtFormatName, (const tchar**) extensions) -{ -} - -QuickTimeAudioFormat::~QuickTimeAudioFormat() -{ -} - -const Array QuickTimeAudioFormat::getPossibleSampleRates() -{ - return Array(); -} - -const Array QuickTimeAudioFormat::getPossibleBitDepths() -{ - return Array(); -} - -bool QuickTimeAudioFormat::canDoStereo() -{ - return true; -} - -bool QuickTimeAudioFormat::canDoMono() -{ - return true; -} - -//============================================================================== -AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails) -{ - QTAudioReader* r = new QTAudioReader (sourceStream, 0); - - if (! r->ok) - { - if (! deleteStreamIfOpeningFails) - r->input = 0; - - deleteAndZero (r); - } - - return r; -} - -AudioFormatWriter* QuickTimeAudioFormat::createWriterFor (OutputStream* /*streamToWriteTo*/, - double /*sampleRateToUse*/, - unsigned int /*numberOfChannels*/, - int /*bitsPerSample*/, - const StringPairArray& /*metadataValues*/, - int /*qualityOptionIndex*/) -{ - jassertfalse // not yet implemented! - return 0; -} - - -END_JUCE_NAMESPACE - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#include "../../../../juce_Config.h" + +#if JUCE_QUICKTIME + +#if ! defined (_WIN32) + #include + #include + #include + #include + #include +#else + #ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4100) + #endif + + #include + #include + #include + #include + #include + + #ifdef _MSC_VER + #pragma warning (pop) + #endif +#endif + +#include "../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_QuickTimeAudioFormat.h" +#include "../../../juce_core/text/juce_LocalisedStrings.h" +#include "../../../juce_core/threads/juce_Thread.h" +#include "../../../juce_core/io/network/juce_URL.h" + +bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); + +#define qtFormatName TRANS("QuickTime file") +static const tchar* const extensions[] = { T(".mov"), T(".mp3"), 0 }; + +//============================================================================== +class QTAudioReader : public AudioFormatReader +{ +public: + QTAudioReader (InputStream* const input_, const int trackNum_) + : AudioFormatReader (input_, qtFormatName), + ok (false), + movie (0), + trackNum (trackNum_), + extractor (0), + lastSampleRead (0), + lastThreadId (0), + dataHandle (0) + { + bufferList = (AudioBufferList*) juce_calloc (256); + +#ifdef WIN32 + if (InitializeQTML (0) != noErr) + return; +#endif + if (EnterMovies() != noErr) + return; + +#if JUCE_MAC + EnterMoviesOnThread (0); +#endif + + bool opened = juce_OpenQuickTimeMovieFromStream (input_, movie, dataHandle); + + if (! opened) + return; + + { + const int numTracks = GetMovieTrackCount (movie); + int trackCount = 0; + + for (int i = 1; i <= numTracks; ++i) + { + track = GetMovieIndTrack (movie, i); + media = GetTrackMedia (track); + + OSType mediaType; + GetMediaHandlerDescription (media, &mediaType, 0, 0); + + if (mediaType == SoundMediaType + && trackCount++ == trackNum_) + { + ok = true; + break; + } + } + } + + if (! ok) + return; + + ok = false; + + lengthInSamples = GetMediaDecodeDuration (media); + usesFloatingPointData = false; + + samplesPerFrame = (int) (GetMediaDecodeDuration (media) / GetMediaSampleCount (media)); + + trackUnitsPerFrame = GetMovieTimeScale (movie) * samplesPerFrame + / GetMediaTimeScale (media); + + OSStatus err = MovieAudioExtractionBegin (movie, 0, &extractor); + + unsigned long output_layout_size; + err = MovieAudioExtractionGetPropertyInfo (extractor, + kQTPropertyClass_MovieAudioExtraction_Audio, + kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, + 0, &output_layout_size, 0); + if (err != noErr) + return; + + AudioChannelLayout* const qt_audio_channel_layout + = (AudioChannelLayout*) juce_calloc (output_layout_size); + + err = MovieAudioExtractionGetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Audio, + kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, + output_layout_size, qt_audio_channel_layout, 0); + + qt_audio_channel_layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; + + err = MovieAudioExtractionSetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Audio, + kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, + sizeof (qt_audio_channel_layout), + qt_audio_channel_layout); + + juce_free (qt_audio_channel_layout); + + err = MovieAudioExtractionGetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Audio, + kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, + sizeof (inputStreamDesc), + &inputStreamDesc, 0); + if (err != noErr) + return; + + inputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger + | kAudioFormatFlagIsPacked + | kAudioFormatFlagsNativeEndian; + inputStreamDesc.mBitsPerChannel = sizeof (SInt16) * 8; + inputStreamDesc.mChannelsPerFrame = jmin (2, inputStreamDesc.mChannelsPerFrame); + inputStreamDesc.mBytesPerFrame = sizeof (SInt16) * inputStreamDesc.mChannelsPerFrame; + inputStreamDesc.mBytesPerPacket = inputStreamDesc.mBytesPerFrame; + + err = MovieAudioExtractionSetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Audio, + kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, + sizeof (inputStreamDesc), + &inputStreamDesc); + if (err != noErr) + return; + + Boolean allChannelsDiscrete = false; + err = MovieAudioExtractionSetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Movie, + kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, + sizeof (allChannelsDiscrete), + &allChannelsDiscrete); + + if (err != noErr) + return; + + bufferList->mNumberBuffers = 1; + bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame; + bufferList->mBuffers[0].mDataByteSize = (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16; + bufferList->mBuffers[0].mData = malloc (bufferList->mBuffers[0].mDataByteSize); + + sampleRate = inputStreamDesc.mSampleRate; + bitsPerSample = 16; + numChannels = inputStreamDesc.mChannelsPerFrame; + + detachThread(); + ok = true; + } + + ~QTAudioReader() + { + if (dataHandle != 0) + DisposeHandle (dataHandle); + + if (extractor != 0) + { + MovieAudioExtractionEnd (extractor); + extractor = 0; + } + + checkThreadIsAttached(); + DisposeMovie (movie); + + juce_free (bufferList->mBuffers[0].mData); + juce_free (bufferList); + } + + bool read (int** destSamples, + int64 startSample, + int numSamples) + { + checkThreadIsAttached(); + int done = 0; + + while (numSamples > 0) + { + if (! loadFrame ((int) startSample)) + return false; + + const int numToDo = jmin (numSamples, samplesPerFrame); + + for (unsigned int j = 0; j < inputStreamDesc.mChannelsPerFrame; ++j) + { + if (destSamples[j] != 0) + { + const short* const src = ((const short*) bufferList->mBuffers[0].mData) + j; + + for (int i = 0; i < numToDo; ++i) + destSamples[j][done + i] = src [i << 1] << 16; + } + } + + done += numToDo; + startSample += numToDo; + numSamples -= numToDo; + } + + detachThread(); + return true; + } + + bool loadFrame (const int sampleNum) + { + if (lastSampleRead != sampleNum) + { + TimeRecord time; + time.scale = (TimeScale) inputStreamDesc.mSampleRate; + time.base = 0; + time.value.hi = 0; + time.value.lo = (UInt32) sampleNum; + + OSStatus err = MovieAudioExtractionSetProperty (extractor, + kQTPropertyClass_MovieAudioExtraction_Movie, + kQTMovieAudioExtractionMoviePropertyID_CurrentTime, + sizeof (time), &time); + + if (err != noErr) + return false; + } + + bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * samplesPerFrame; + + UInt32 outFlags = 0; + UInt32 actualNumSamples = samplesPerFrame; + OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumSamples, + bufferList, &outFlags); + + lastSampleRead = sampleNum + samplesPerFrame; + + return err == noErr; + } + + juce_UseDebuggingNewOperator + + bool ok; + +private: + Movie movie; + Media media; + Track track; + const int trackNum; + double trackUnitsPerFrame; + int samplesPerFrame; + int lastSampleRead, lastThreadId; + MovieAudioExtractionRef extractor; + AudioStreamBasicDescription inputStreamDesc; + AudioBufferList* bufferList; + Handle dataHandle; + + /*OSErr readMovieStream (long offset, long size, void* dataPtr) + { + input->setPosition (offset); + input->read (dataPtr, size); + return noErr; + } + + static OSErr readMovieStreamProc (long offset, long size, void* dataPtr, void* userRef) + { + return ((QTAudioReader*) userRef)->readMovieStream (offset, size, dataPtr); + }*/ + + //============================================================================== + void checkThreadIsAttached() + { +#if JUCE_MAC + if (Thread::getCurrentThreadId() != lastThreadId) + EnterMoviesOnThread (0); + AttachMovieToCurrentThread (movie); +#endif + } + + void detachThread() + { +#if JUCE_MAC + DetachMovieFromCurrentThread (movie); +#endif + } +}; + + +//============================================================================== +QuickTimeAudioFormat::QuickTimeAudioFormat() + : AudioFormat (qtFormatName, (const tchar**) extensions) +{ +} + +QuickTimeAudioFormat::~QuickTimeAudioFormat() +{ +} + +const Array QuickTimeAudioFormat::getPossibleSampleRates() +{ + return Array(); +} + +const Array QuickTimeAudioFormat::getPossibleBitDepths() +{ + return Array(); +} + +bool QuickTimeAudioFormat::canDoStereo() +{ + return true; +} + +bool QuickTimeAudioFormat::canDoMono() +{ + return true; +} + +//============================================================================== +AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails) +{ + QTAudioReader* r = new QTAudioReader (sourceStream, 0); + + if (! r->ok) + { + if (! deleteStreamIfOpeningFails) + r->input = 0; + + deleteAndZero (r); + } + + return r; +} + +AudioFormatWriter* QuickTimeAudioFormat::createWriterFor (OutputStream* /*streamToWriteTo*/, + double /*sampleRateToUse*/, + unsigned int /*numberOfChannels*/, + int /*bitsPerSample*/, + const StringPairArray& /*metadataValues*/, + int /*qualityOptionIndex*/) +{ + jassertfalse // not yet implemented! + return 0; +} + + +END_JUCE_NAMESPACE + +#endif diff --git a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.h b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.h index e079dba3e1..0691cb7f64 100644 --- a/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.h +++ b/src/juce_appframework/audio/audio_file_formats/juce_QuickTimeAudioFormat.h @@ -33,7 +33,7 @@ #define __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ #include "juce_AudioFormat.h" -#if JUCE_QUICKTIME_AUDIOFORMAT +#if JUCE_QUICKTIME //============================================================================== diff --git a/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.cpp b/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.cpp index c3028e2f6e..3acdf88444 100644 --- a/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.cpp @@ -40,6 +40,21 @@ #ifdef _WIN32 #include + #ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4100) + #endif + + #include + #include + #include + #include + #include + + #ifdef _MSC_VER + #pragma warning (pop) + #endif + // If you've got QuickTime 7 installed, then these COM objects should be found in // the "\Program Files\Quicktime" directory. You'll need to add this directory to // your include search path to make these import statements work. @@ -51,6 +66,8 @@ #else #include #include + #include + #include #endif #include "../../../../juce_core/basics/juce_StandardHeader.h" @@ -58,17 +75,50 @@ BEGIN_JUCE_NAMESPACE #include "juce_QuickTimeMovieComponent.h" +#include "../../../../juce_core/io/files/juce_FileInputStream.h" +bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); -//============================================================================== -#if JUCE_WIN32 +//============================================================================== struct QTMovieCompInternal { + QTMovieCompInternal() + : dataHandle (0) + { +#if JUCE_MAC + movie = 0; + controller = 0; +#endif + } + + ~QTMovieCompInternal() + { + clearHandle(); + } + +#if JUCE_MAC + Movie movie; + MovieController controller; +#else IQTControlPtr qtControlInternal; IQTMoviePtr qtMovieInternal; +#endif + + Handle dataHandle; + + void clearHandle() + { + if (dataHandle != 0) + { + DisposeHandle (dataHandle); + dataHandle = 0; + } + } }; +#if JUCE_WIN32 + #define qtControl (((QTMovieCompInternal*) internal)->qtControlInternal) #define qtMovie (((QTMovieCompInternal*) internal)->qtMovieInternal) @@ -122,10 +172,10 @@ bool QuickTimeMovieComponent::isControlCreated() const return isControlOpen(); } -bool QuickTimeMovieComponent::loadMovie (const File& movieFile_, +bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, const bool isControllerVisible) { - movieFile = movieFile_; + movieFile = File::nonexistent; movieLoaded = false; qtMovie = 0; controllerVisible = isControllerVisible; @@ -135,24 +185,36 @@ bool QuickTimeMovieComponent::loadMovie (const File& movieFile_, { if (qtControl != 0) { - qtControl->PutURL ((const WCHAR*) movieFile_.getFullPathName()); - qtMovie = qtControl->GetMovie(); + qtControl->Put_MovieHandle (0); + ((QTMovieCompInternal*) internal)->clearHandle(); + + Movie movie; + if (juce_OpenQuickTimeMovieFromStream (movieStream, movie, ((QTMovieCompInternal*) internal)->dataHandle)) + { + qtControl->Put_MovieHandle ((long) (pointer_sized_int) movie); + + qtMovie = qtControl->GetMovie(); - if (qtMovie != 0) - qtMovie->PutMovieControllerType (isControllerVisible ? qtMovieControllerTypeStandard - : qtMovieControllerTypeNone); + if (qtMovie != 0) + qtMovie->PutMovieControllerType (isControllerVisible ? qtMovieControllerTypeStandard + : qtMovieControllerTypeNone); + } + + if (movie == 0) + ((QTMovieCompInternal*) internal)->clearHandle(); } movieLoaded = (qtMovie != 0); - return movieLoaded; } else { // You're trying to open a movie when the control hasn't yet been created, probably because // you've not yet added this component to a Window and made the whole component hierarchy visible. jassertfalse - return false; } + + delete movieStream; + return movieLoaded; } void QuickTimeMovieComponent::closeMovie() @@ -163,7 +225,10 @@ void QuickTimeMovieComponent::closeMovie() qtMovie = 0; if (qtControl != 0) - qtControl->PutURL (L""); + qtControl->Put_MovieHandle (0); + //qtControl->PutURL (L""); + + ((QTMovieCompInternal*) internal)->clearHandle(); } const File QuickTimeMovieComponent::getCurrentMovieFile() const @@ -327,25 +392,14 @@ void OfferMouseClickToQuickTime (WindowRef window, } } -//============================================================================== -struct InternalData -{ - Movie movie; - MovieController controller; -}; - //============================================================================== QuickTimeMovieComponent::QuickTimeMovieComponent() - : internal (new InternalData()), + : internal (new QTMovieCompInternal()), associatedWindow (0), controllerVisible (false), controllerAssignedToWindow (false), reentrant (false) { - InternalData* const id = (InternalData*) internal; - id->movie = 0; - id->controller = 0; - if (! hasLoadedQT) { hasLoadedQT = true; @@ -364,7 +418,7 @@ QuickTimeMovieComponent::~QuickTimeMovieComponent() activeQTWindows.removeValue ((void*) this); - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; delete id; if (activeQTWindows.size() == 0 && isQTAvailable) @@ -376,13 +430,14 @@ QuickTimeMovieComponent::~QuickTimeMovieComponent() } } -bool QuickTimeMovieComponent::loadMovie (const File& f, +bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, const bool controllerVisible_) { - if (! (isQTAvailable && f.existsAsFile())) + if (! isQTAvailable) return false; closeMovie(); + movieFile = File::nonexistent; if (getPeer() == 0) { @@ -394,45 +449,30 @@ bool QuickTimeMovieComponent::loadMovie (const File& f, controllerVisible = controllerVisible_; - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; GrafPtr savedPort; GetPort (&savedPort); bool result = false; - FSSpec fsSpec; - - PlatformUtilities::makeFSSpecFromPath (&fsSpec, f.getFullPathName()); - - short refNum = -1; - OSErr err; - - if ((err = OpenMovieFile (&fsSpec, &refNum, fsRdWrPerm)) == noErr - || (err = OpenMovieFile (&fsSpec, &refNum, fsRdPerm)) == noErr) + if (juce_OpenQuickTimeMovieFromStream (movieStream, id->movie, id->dataHandle)) { id->controller = 0; - short resID = 0; + void* window = getWindowHandle(); - if (NewMovieFromFile (&id->movie, refNum, &resID, 0, newMovieActive, 0) == noErr - && id->movie != 0) - { - void* window = getWindowHandle(); - - if (window != associatedWindow && window != 0) - associatedWindow = window; + if (window != associatedWindow && window != 0) + associatedWindow = window; - assignMovieToWindow(); + assignMovieToWindow(); - SetMovieActive (id->movie, true); - SetMovieProgressProc (id->movie, (MovieProgressUPP) -1, 0); + SetMovieActive (id->movie, true); + SetMovieProgressProc (id->movie, (MovieProgressUPP) -1, 0); - movieFile = f; - startTimer (1000 / 50); // this needs to be quite a high frequency for smooth playback - result = true; + startTimer (1000 / 50); // this needs to be quite a high frequency for smooth playback + result = true; - repaint(); - } + repaint(); } MacSetPort (savedPort); @@ -444,7 +484,7 @@ void QuickTimeMovieComponent::closeMovie() { stop(); - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0) { @@ -458,13 +498,15 @@ void QuickTimeMovieComponent::closeMovie() id->movie = 0; } + id->clearHandle(); + stopTimer(); movieFile = File::nonexistent; } bool QuickTimeMovieComponent::isMovieOpen() const { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; return id->movie != 0 && id->controller != 0; } @@ -488,7 +530,7 @@ void QuickTimeMovieComponent::assignMovieToWindow() reentrant = true; - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0) { DisposeMovieController (id->controller); @@ -550,7 +592,7 @@ void QuickTimeMovieComponent::assignMovieToWindow() void QuickTimeMovieComponent::play() { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) StartMovie (id->movie); @@ -558,7 +600,7 @@ void QuickTimeMovieComponent::play() void QuickTimeMovieComponent::stop() { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) StopMovie (id->movie); @@ -566,14 +608,14 @@ void QuickTimeMovieComponent::stop() bool QuickTimeMovieComponent::isPlaying() const { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; return id->movie != 0 && GetMovieRate (id->movie) != 0; } void QuickTimeMovieComponent::setPosition (const double seconds) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0) { @@ -595,7 +637,7 @@ void QuickTimeMovieComponent::setPosition (const double seconds) double QuickTimeMovieComponent::getPosition() const { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) { @@ -611,7 +653,7 @@ double QuickTimeMovieComponent::getPosition() const void QuickTimeMovieComponent::setSpeed (const float newSpeed) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) SetMovieRate (id->movie, (Fixed) (newSpeed * (Fixed) 0x00010000L)); @@ -619,7 +661,7 @@ void QuickTimeMovieComponent::setSpeed (const float newSpeed) double QuickTimeMovieComponent::getMovieDuration() const { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) return GetMovieDuration (id->movie) / (double) GetMovieTimeScale (id->movie); @@ -629,7 +671,7 @@ double QuickTimeMovieComponent::getMovieDuration() const void QuickTimeMovieComponent::setLooping (const bool shouldLoop) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; looping = shouldLoop; if (id->controller != 0) @@ -643,7 +685,7 @@ bool QuickTimeMovieComponent::isLooping() const void QuickTimeMovieComponent::setMovieVolume (const float newVolume) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) SetMovieVolume (id->movie, jlimit ((short) 0, (short) 0x100, (short) (newVolume * 0x0100))); @@ -651,7 +693,7 @@ void QuickTimeMovieComponent::setMovieVolume (const float newVolume) float QuickTimeMovieComponent::getMovieVolume() const { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) return jmax (0.0f, GetMovieVolume (id->movie) / (float) 0x0100); @@ -664,7 +706,7 @@ void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const width = 0; height = 0; - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie != 0) { @@ -677,7 +719,7 @@ void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const void QuickTimeMovieComponent::paint (Graphics& g) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->movie == 0 || id->controller == 0) { @@ -720,7 +762,7 @@ void QuickTimeMovieComponent::moved() void QuickTimeMovieComponent::resized() { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0 && isShowing()) { @@ -767,7 +809,7 @@ void QuickTimeMovieComponent::visibilityChanged() void QuickTimeMovieComponent::timerCallback() { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0) { @@ -800,7 +842,7 @@ void QuickTimeMovieComponent::parentHierarchyChanged() void QuickTimeMovieComponent::handleMCEvent (void* ev) { - InternalData* const id = (InternalData*) internal; + QTMovieCompInternal* const id = (QTMovieCompInternal*) internal; if (id->controller != 0 && isShowing()) { @@ -833,6 +875,177 @@ void QuickTimeMovieComponent::handleMCEvent (void* ev) //============================================================================== // (methods common to both platforms..) +static Handle createHandleDataRef (Handle dataHandle, const char* fileName) +{ + Handle dataRef = 0; + OSStatus err = PtrToHand (&dataHandle, &dataRef, sizeof (Handle)); + if (err == noErr) + { + Str255 suffix; +#if JUCE_WIN32 + strcpy_s ((char*) suffix, 128, fileName); +#else + strcpy ((char*) suffix, fileName); +#endif + StringPtr name = suffix; + err = PtrAndHand (name, dataRef, name[0] + 1); + + if (err == noErr) + { + long atoms[3]; + atoms[0] = EndianU32_NtoB (3 * sizeof (long)); + atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); + atoms[2] = EndianU32_NtoB (MovieFileType); + + err = PtrAndHand (atoms, dataRef, 3 * sizeof (long)); + + if (err == noErr) + return dataRef; + } + + DisposeHandle (dataRef); + } + + return 0; +} + +static CFStringRef juceStringToCFString (const String& s) +{ + const int len = s.length(); + const juce_wchar* const t = (const juce_wchar*) s; + + UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); + + for (int i = 0; i <= len; ++i) + temp[i] = t[i]; + + CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); + juce_free (temp); + + return result; +} + +static bool openMovie (QTNewMoviePropertyElement* props, int prop, Movie& movie) +{ + Boolean trueBool = true; + props[prop].propClass = kQTPropertyClass_MovieInstantiation; + props[prop].propID = kQTMovieInstantiationPropertyID_DontResolveDataRefs; + props[prop].propValueSize = sizeof (trueBool); + props[prop].propValueAddress = &trueBool; + ++prop; + + props[prop].propClass = kQTPropertyClass_MovieInstantiation; + props[prop].propID = kQTMovieInstantiationPropertyID_AsyncOK; + props[prop].propValueSize = sizeof (trueBool); + props[prop].propValueAddress = &trueBool; + ++prop; + + Boolean isActive = true; + props[prop].propClass = kQTPropertyClass_NewMovieProperty; + props[prop].propID = kQTNewMoviePropertyID_Active; + props[prop].propValueSize = sizeof (isActive); + props[prop].propValueAddress = &isActive; + ++prop; + +#if JUCE_MAC + SetPort (0); +#else + MacSetPort (0); +#endif + + jassert (prop <= 5); + OSStatus err = NewMovieFromProperties (prop, props, 0, 0, &movie); + + return err == noErr; +} + +bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle) +{ + if (input == 0) + return false; + + dataHandle = 0; + bool ok = false; + + QTNewMoviePropertyElement props[5]; + zeromem (props, sizeof (props)); + int prop = 0; + + DataReferenceRecord dr; + props[prop].propClass = kQTPropertyClass_DataLocation; + props[prop].propID = kQTDataLocationPropertyID_DataReference; + props[prop].propValueSize = sizeof (dr); + props[prop].propValueAddress = (void*) &dr; + ++prop; + + FileInputStream* const fin = dynamic_cast (input); + + if (fin != 0) + { + CFStringRef filePath = juceStringToCFString (fin->getFile().getFullPathName()); + + QTNewDataReferenceFromFullPathCFString (filePath, (QTPathStyle) kQTNativeDefaultPathStyle, 0, + &dr.dataRef, &dr.dataRefType); + + + ok = openMovie (props, prop, movie); + + DisposeHandle (dr.dataRef); + CFRelease (filePath); + } + else + { + // sanity-check because this currently needs to load the whole stream into memory.. + jassert (input->getTotalLength() < 50 * 1024 * 1024); + + dataHandle = NewHandle ((Size) input->getTotalLength()); + HLock (dataHandle); + // read the entire stream into memory - this is a pain, but can't get it to work + // properly using a custom callback to supply the data. + input->read (*dataHandle, (int) input->getTotalLength()); + HUnlock (dataHandle); + + // different types to get QT to try. (We should really be a bit smarter here by + // working out in advance which one the stream contains, rather than just trying + // each one) + const char* const suffixesToTry[] = { "\04.mov", "\04.mp3", + "\04.avi", "\04.m4a" }; + + for (int i = 0; i < numElementsInArray (suffixesToTry) && ! ok; ++i) + { + /* // this fails for some bizarre reason - it can be bodged to work with + // movies, but can't seem to do it for other file types.. + QTNewMovieUserProcRecord procInfo; + procInfo.getMovieUserProc = NewGetMovieUPP (readMovieStreamProc); + procInfo.getMovieUserProcRefcon = this; + procInfo.defaultDataRef.dataRef = dataRef; + procInfo.defaultDataRef.dataRefType = HandleDataHandlerSubType; + + props[prop].propClass = kQTPropertyClass_DataLocation; + props[prop].propID = kQTDataLocationPropertyID_MovieUserProc; + props[prop].propValueSize = sizeof (procInfo); + props[prop].propValueAddress = (void*) &procInfo; + ++prop; */ + + dr.dataRef = createHandleDataRef (dataHandle, suffixesToTry [i]); + dr.dataRefType = HandleDataHandlerSubType; + ok = openMovie (props, prop, movie); + + DisposeHandle (dr.dataRef); + } + } + + return ok; +} + +bool QuickTimeMovieComponent::loadMovie (const File& movieFile_, + const bool isControllerVisible) +{ + const bool ok = loadMovie ((InputStream*) movieFile_.createInputStream(), isControllerVisible); + movieFile = movieFile_; + return ok; +} + void QuickTimeMovieComponent::goToStart() { setPosition (0.0); diff --git a/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.h b/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.h index 34d7ea706a..699622e807 100644 --- a/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.h +++ b/src/juce_appframework/gui/components/special/juce_QuickTimeMovieComponent.h @@ -85,6 +85,9 @@ public: bool loadMovie (const File& movieFile, const bool isControllerVisible); + bool loadMovie (InputStream* movieStream, + const bool isControllerVisible); + /** Closes the movie, if one is open. */ void closeMovie(); @@ -137,9 +140,9 @@ public: /** Returns the current play position of the movie. */ double getPosition() const; - /** Changes the movie playback rate. - - A value of 1 is normal speed, greater values play it proportionately faster, + /** Changes the movie playback rate. + + A value of 1 is normal speed, greater values play it proportionately faster, smaller values play it slower. */ void setSpeed (const float newSpeed); @@ -191,7 +194,7 @@ public: /** @internal */ void resized(); #endif - + juce_UseDebuggingNewOperator private: