|
- /*
- ==============================================================================
-
- 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.
-
- ==============================================================================
- */
-
- // (This file gets included by juce_win32_NativeCode.cpp, rather than being
- // compiled on its own).
- #if JUCE_INCLUDED_FILE && JUCE_QUICKTIME
-
- using namespace QTOLibrary;
- using namespace QTOControlLib;
-
- bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle);
-
- static bool hasLoadedQT = false;
- static bool isQTAvailable = false;
-
-
- //==============================================================================
- struct QTMovieCompInternal
- {
- QTMovieCompInternal()
- : dataHandle (0)
- {
- }
-
- ~QTMovieCompInternal()
- {
- clearHandle();
- }
-
- IQTControlPtr qtControlInternal;
- IQTMoviePtr qtMovieInternal;
-
- Handle dataHandle;
-
- void clearHandle()
- {
- if (dataHandle != 0)
- {
- DisposeHandle (dataHandle);
- dataHandle = 0;
- }
- }
- };
-
- #define qtControl (((QTMovieCompInternal*) internal)->qtControlInternal)
- #define qtMovie (((QTMovieCompInternal*) internal)->qtMovieInternal)
-
- //==============================================================================
- QuickTimeMovieComponent::QuickTimeMovieComponent()
- : movieLoaded (false),
- controllerVisible (true)
- {
- internal = new QTMovieCompInternal();
- setMouseEventsAllowed (false);
- }
-
- QuickTimeMovieComponent::~QuickTimeMovieComponent()
- {
- closeMovie();
- qtControl = 0;
-
- deleteControl();
-
- delete internal;
- internal = 0;
- }
-
- bool QuickTimeMovieComponent::isQuickTimeAvailable() throw()
- {
- if (! hasLoadedQT)
- {
- hasLoadedQT = true;
-
- isQTAvailable = (InitializeQTML (0) == noErr)
- && (EnterMovies() == noErr);
- }
-
- return isQTAvailable;
- }
-
- //==============================================================================
- void QuickTimeMovieComponent::createControlIfNeeded()
- {
- if (isShowing() && ! isControlCreated())
- {
- const IID qtIID = __uuidof (QTControl);
-
- if (createControl (&qtIID))
- {
- const IID qtInterfaceIID = __uuidof (IQTControl);
- qtControl = (IQTControl*) queryInterface (&qtInterfaceIID);
-
- if (qtControl != 0)
- {
- qtControl->Release(); // it has one ref too many at this point
-
- qtControl->QuickTimeInitialize();
- qtControl->PutSizing (qtMovieFitsControl);
-
- if (movieFile != File::nonexistent)
- loadMovie (movieFile, controllerVisible);
- }
- }
- }
- }
-
- bool QuickTimeMovieComponent::isControlCreated() const
- {
- return isControlOpen();
- }
-
- bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream,
- const bool isControllerVisible)
- {
- movieFile = File::nonexistent;
- movieLoaded = false;
- qtMovie = 0;
- controllerVisible = isControllerVisible;
- createControlIfNeeded();
-
- if (isControlCreated())
- {
- if (qtControl != 0)
- {
- 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 (movie == 0)
- ((QTMovieCompInternal*) internal)->clearHandle();
- }
-
- movieLoaded = (qtMovie != 0);
- }
- 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
- }
-
- delete movieStream;
- return movieLoaded;
- }
-
- void QuickTimeMovieComponent::closeMovie()
- {
- stop();
- movieFile = File::nonexistent;
- movieLoaded = false;
- qtMovie = 0;
-
- if (qtControl != 0)
- qtControl->Put_MovieHandle (0);
-
- ((QTMovieCompInternal*) internal)->clearHandle();
- }
-
- const File QuickTimeMovieComponent::getCurrentMovieFile() const
- {
- return movieFile;
- }
-
- bool QuickTimeMovieComponent::isMovieOpen() const
- {
- return movieLoaded;
- }
-
- double QuickTimeMovieComponent::getMovieDuration() const
- {
- if (qtMovie != 0)
- return qtMovie->GetDuration() / (double) qtMovie->GetTimeScale();
-
- return 0.0;
- }
-
- void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const
- {
- if (qtMovie != 0)
- {
- struct QTRECT r = qtMovie->GetNaturalRect();
-
- width = r.right - r.left;
- height = r.bottom - r.top;
- }
- else
- {
- width = height = 0;
- }
- }
-
- void QuickTimeMovieComponent::play()
- {
- if (qtMovie != 0)
- qtMovie->Play();
- }
-
- void QuickTimeMovieComponent::stop()
- {
- if (qtMovie != 0)
- qtMovie->Stop();
- }
-
- bool QuickTimeMovieComponent::isPlaying() const
- {
- return qtMovie != 0 && qtMovie->GetRate() != 0.0f;
- }
-
- void QuickTimeMovieComponent::setPosition (const double seconds)
- {
- if (qtMovie != 0)
- qtMovie->PutTime ((long) (seconds * qtMovie->GetTimeScale()));
- }
-
- double QuickTimeMovieComponent::getPosition() const
- {
- if (qtMovie != 0)
- return qtMovie->GetTime() / (double) qtMovie->GetTimeScale();
-
- return 0.0;
- }
-
- void QuickTimeMovieComponent::setSpeed (const float newSpeed)
- {
- if (qtMovie != 0)
- qtMovie->PutRate (newSpeed);
- }
-
- void QuickTimeMovieComponent::setMovieVolume (const float newVolume)
- {
- if (qtMovie != 0)
- {
- qtMovie->PutAudioVolume (newVolume);
- qtMovie->PutAudioMute (newVolume <= 0);
- }
- }
-
- float QuickTimeMovieComponent::getMovieVolume() const
- {
- if (qtMovie != 0)
- return qtMovie->GetAudioVolume();
-
- return 0.0f;
- }
-
- void QuickTimeMovieComponent::setLooping (const bool shouldLoop)
- {
- if (qtMovie != 0)
- qtMovie->PutLoop (shouldLoop);
- }
-
- bool QuickTimeMovieComponent::isLooping() const
- {
- return qtMovie != 0 && qtMovie->GetLoop();
- }
-
- bool QuickTimeMovieComponent::isControllerVisible() const
- {
- return controllerVisible;
- }
-
- void QuickTimeMovieComponent::parentHierarchyChanged()
- {
- createControlIfNeeded();
- QTCompBaseClass::parentHierarchyChanged();
- }
-
- void QuickTimeMovieComponent::visibilityChanged()
- {
- createControlIfNeeded();
- QTCompBaseClass::visibilityChanged();
- }
-
- void QuickTimeMovieComponent::paint (Graphics& g)
- {
- if (! isControlCreated())
- g.fillAll (Colours::black);
- }
-
-
- //==============================================================================
- static Handle createHandleDataRef (Handle dataHandle, const char* fileName)
- {
- Handle dataRef = 0;
- OSStatus err = PtrToHand (&dataHandle, &dataRef, sizeof (Handle));
- if (err == noErr)
- {
- Str255 suffix;
-
- CharacterFunctions::copy ((char*) suffix, fileName, 128);
-
- 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;
-
- MacSetPort (0);
-
- 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 <FileInputStream*> (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);
- }
-
- void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
- const RectanglePlacement& placement)
- {
- int normalWidth, normalHeight;
- getMovieNormalSize (normalWidth, normalHeight);
-
- if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty())
- {
- double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight;
-
- placement.applyTo (x, y, w, h,
- spaceToFitWithin.getX(), spaceToFitWithin.getY(),
- spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight());
-
- if (w > 0 && h > 0)
- {
- setBounds (roundDoubleToInt (x), roundDoubleToInt (y),
- roundDoubleToInt (w), roundDoubleToInt (h));
- }
- }
- else
- {
- setBounds (spaceToFitWithin);
- }
- }
-
- #endif
|