| @@ -38,9 +38,7 @@ | |||||
| #include "juce_video.h" | #include "juce_video.h" | ||||
| #if JUCE_MAC | #if JUCE_MAC | ||||
| #if JUCE_QUICKTIME | |||||
| #import <QTKit/QTKit.h> | |||||
| #endif | |||||
| #import <AVFoundation/AVFoundation.h> | |||||
| //============================================================================== | //============================================================================== | ||||
| #elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
| @@ -104,9 +102,7 @@ namespace juce | |||||
| #include "native/juce_mac_CameraDevice.mm" | #include "native/juce_mac_CameraDevice.mm" | ||||
| #endif | #endif | ||||
| #if JUCE_QUICKTIME | |||||
| #include "native/juce_mac_QuickTimeMovieComponent.mm" | |||||
| #endif | |||||
| #include "native/juce_mac_MovieComponent.mm" | |||||
| #elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
| @@ -118,10 +114,6 @@ namespace juce | |||||
| #include "native/juce_win32_DirectShowComponent.cpp" | #include "native/juce_win32_DirectShowComponent.cpp" | ||||
| #endif | #endif | ||||
| #if JUCE_QUICKTIME | |||||
| #include "native/juce_win32_QuickTimeMovieComponent.cpp" | |||||
| #endif | |||||
| #elif JUCE_LINUX | #elif JUCE_LINUX | ||||
| #elif JUCE_ANDROID | #elif JUCE_ANDROID | ||||
| @@ -41,7 +41,7 @@ | |||||
| license: GPL/Commercial | license: GPL/Commercial | ||||
| dependencies: juce_data_structures juce_cryptography | dependencies: juce_data_structures juce_cryptography | ||||
| OSXFrameworks: QTKit QuickTime | |||||
| OSXFrameworks: AVFoundation CoreMedia | |||||
| END_JUCE_MODULE_DECLARATION | END_JUCE_MODULE_DECLARATION | ||||
| @@ -99,8 +99,14 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| #include "playback/juce_DirectShowComponent.h" | |||||
| #include "playback/juce_QuickTimeMovieComponent.h" | |||||
| #if JUCE_DIRECTSHOW || DOXYGEN | |||||
| #include "playback/juce_DirectShowComponent.h" | |||||
| #endif | |||||
| #if JUCE_MAC || DOXYGEN | |||||
| #include "playback/juce_MovieComponent.h" | |||||
| #endif | |||||
| #include "capture/juce_CameraDevice.h" | #include "capture/juce_CameraDevice.h" | ||||
| } | } | ||||
| @@ -0,0 +1,222 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2015 - ROLI Ltd. | |||||
| Permission is granted to use this software under the terms of either: | |||||
| a) the GPL v2 (or any later version) | |||||
| b) the Affero GPL v3 | |||||
| Details of these licenses can be found at: www.gnu.org/licenses | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.juce.com for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| struct MovieComponent::Pimpl | |||||
| { | |||||
| bool open (MovieComponent& parent, const String& newPath) | |||||
| { | |||||
| JUCE_AUTORELEASEPOOL | |||||
| { | |||||
| close(); | |||||
| NSString* videoFile = [NSString stringWithUTF8String: newPath.toUTF8()]; | |||||
| NSURL* url = [NSURL fileURLWithPath: videoFile]; | |||||
| AVAsset* asset = [AVAsset assetWithURL: url]; | |||||
| duration = CMTimeGetSeconds (asset.duration); | |||||
| nativeSize = [[[asset tracksWithMediaType: AVMediaTypeVideo] objectAtIndex: 0] naturalSize]; | |||||
| if (duration <= 0) | |||||
| return false; | |||||
| auto frame = CGRectMake (0, 0, nativeSize.width, nativeSize.height); | |||||
| view = [[NSView alloc] initWithFrame: frame]; | |||||
| [view setHidden: NO]; | |||||
| [view setNeedsDisplay: YES]; | |||||
| [view setWantsLayer: YES]; | |||||
| [view makeBackingLayer]; | |||||
| parent.setView (view); | |||||
| path = newPath; | |||||
| player = [[AVPlayer alloc] initWithURL: url]; | |||||
| player.actionAtItemEnd = AVPlayerActionAtItemEndPause; | |||||
| player.masterClock = CMClockGetHostTimeClock(); | |||||
| player.automaticallyWaitsToMinimizeStalling = NO; | |||||
| [player pause]; | |||||
| playerLayer = [[AVPlayerLayer playerLayerWithPlayer: player] retain]; | |||||
| [playerLayer setFrame: frame]; | |||||
| [playerLayer setHidden: NO]; | |||||
| [[view layer] addSublayer: playerLayer]; | |||||
| parent.resized(); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void close() | |||||
| { | |||||
| [playerLayer release]; | |||||
| playerLayer = nil; | |||||
| [player release]; | |||||
| player = nil; | |||||
| [view release]; | |||||
| view = nil; | |||||
| playing = false; | |||||
| duration = 0; | |||||
| nativeSize = { 0, 0 }; | |||||
| path = {}; | |||||
| } | |||||
| String path; | |||||
| NSView* view = nil; | |||||
| AVPlayer* player = nil; | |||||
| AVPlayerLayer* playerLayer = nil; | |||||
| double duration = 0; | |||||
| CGSize nativeSize = { 0, 0 }; | |||||
| bool playing = false; | |||||
| }; | |||||
| MovieComponent::MovieComponent() : pimpl (new Pimpl()) {} | |||||
| MovieComponent::~MovieComponent() | |||||
| { | |||||
| closeMovie(); | |||||
| pimpl = nullptr; | |||||
| } | |||||
| bool MovieComponent::loadMovie (const File& file) | |||||
| { | |||||
| return file.existsAsFile() | |||||
| && pimpl->open (*this, file.getFullPathName()); | |||||
| } | |||||
| bool MovieComponent::loadMovie (const URL& file) | |||||
| { | |||||
| return pimpl->open (*this, file.toString (true)); | |||||
| } | |||||
| void MovieComponent::closeMovie() | |||||
| { | |||||
| setView (nullptr); | |||||
| pimpl->close(); | |||||
| } | |||||
| bool MovieComponent::isMovieOpen() const | |||||
| { | |||||
| return pimpl->player != nil && pimpl->player.status != AVPlayerStatusFailed; | |||||
| } | |||||
| String MovieComponent::getCurrentMoviePath() const | |||||
| { | |||||
| return pimpl->path; | |||||
| } | |||||
| void MovieComponent::play() | |||||
| { | |||||
| pimpl->playing = true; | |||||
| [pimpl->player play]; | |||||
| } | |||||
| void MovieComponent::stop() | |||||
| { | |||||
| pimpl->playing = false; | |||||
| [pimpl->player pause]; | |||||
| } | |||||
| double MovieComponent::getDuration() const | |||||
| { | |||||
| return pimpl->duration; | |||||
| } | |||||
| double MovieComponent::getPosition() const | |||||
| { | |||||
| return CMTimeGetSeconds ([pimpl->player currentTime]); | |||||
| } | |||||
| void MovieComponent::setPosition (double seconds) | |||||
| { | |||||
| auto delta = std::abs (seconds - getPosition()); | |||||
| auto newTime = CMTimeMakeWithSeconds (seconds, 600); | |||||
| if (! pimpl->playing) | |||||
| { | |||||
| [pimpl->player seekToTime: newTime | |||||
| toleranceBefore: kCMTimeZero | |||||
| toleranceAfter: kCMTimeZero]; | |||||
| } | |||||
| else if (delta > 0.035) | |||||
| { | |||||
| auto masterClock = CMClockGetTime (CMClockGetHostTimeClock()); | |||||
| try | |||||
| { | |||||
| [pimpl->player setRate: 1.0f | |||||
| time: newTime | |||||
| atHostTime: masterClock]; | |||||
| } | |||||
| catch (...) | |||||
| { | |||||
| // We should never end up in here, unless somehow automaticallyWaitsToMinimizeStalling | |||||
| // got reset to YES | |||||
| jassertfalse; | |||||
| if (delta > 0.3) | |||||
| [pimpl->player seekToTime: newTime | |||||
| toleranceBefore: kCMTimeZero | |||||
| toleranceAfter: kCMTimeZero]; | |||||
| } | |||||
| } | |||||
| } | |||||
| void MovieComponent::setVolume (float newVolume) | |||||
| { | |||||
| pimpl->player.volume = (CGFloat) newVolume; | |||||
| } | |||||
| float MovieComponent::getVolume() const | |||||
| { | |||||
| return (float) pimpl->player.volume; | |||||
| } | |||||
| Rectangle<int> MovieComponent::getNativeSize() const | |||||
| { | |||||
| return { 0, 0, roundToInt (pimpl->nativeSize.width), roundToInt (pimpl->nativeSize.height) }; | |||||
| } | |||||
| void MovieComponent::setBoundsWithCorrectAspectRatio (Rectangle<int> spaceToFitWithin, RectanglePlacement placement) | |||||
| { | |||||
| auto nativeSize = getNativeSize(); | |||||
| setBounds ((spaceToFitWithin.isEmpty() || nativeSize.isEmpty()) | |||||
| ? spaceToFitWithin | |||||
| : placement.appliedTo (nativeSize, spaceToFitWithin)); | |||||
| } | |||||
| void MovieComponent::resized() | |||||
| { | |||||
| JUCE_AUTORELEASEPOOL | |||||
| { | |||||
| auto frame = CGRectMake (0, 0, (CGFloat) getWidth(), (CGFloat) getHeight()); | |||||
| [pimpl->view setFrame: frame]; | |||||
| [pimpl->playerLayer setFrame: frame]; | |||||
| } | |||||
| } | |||||
| @@ -1,341 +0,0 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2015 - ROLI Ltd. | |||||
| Permission is granted to use this software under the terms of either: | |||||
| a) the GPL v2 (or any later version) | |||||
| b) the Affero GPL v3 | |||||
| Details of these licenses can be found at: www.gnu.org/licenses | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.juce.com for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #if JUCE_QUICKTIME | |||||
| struct NonInterceptingQTMovieViewClass : public ObjCClass <QTMovieView> | |||||
| { | |||||
| NonInterceptingQTMovieViewClass() : ObjCClass <QTMovieView> ("JUCEQTMovieView_") | |||||
| { | |||||
| addMethod (@selector (hitTest:), hitTest, "@@:", @encode (NSPoint)); | |||||
| addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "c@:@"); | |||||
| registerClass(); | |||||
| } | |||||
| private: | |||||
| static NSView* hitTest (id self, SEL, NSPoint point) | |||||
| { | |||||
| if (! [(QTMovieView*) self isControllerVisible]) | |||||
| return nil; | |||||
| objc_super s = { self, [QTMovieView class] }; | |||||
| return objc_msgSendSuper (&s, @selector (hitTest:), point); | |||||
| } | |||||
| static BOOL acceptsFirstMouse (id, SEL, NSEvent*) | |||||
| { | |||||
| return YES; | |||||
| } | |||||
| }; | |||||
| //============================================================================== | |||||
| #define theMovie (static_cast<QTMovie*> (movie)) | |||||
| //============================================================================== | |||||
| QuickTimeMovieComponent::QuickTimeMovieComponent() | |||||
| : movie (0) | |||||
| { | |||||
| setOpaque (true); | |||||
| setVisible (true); | |||||
| static NonInterceptingQTMovieViewClass cls; | |||||
| QTMovieView* view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)]; | |||||
| setView (view); | |||||
| [view setNextResponder: [view superview]]; | |||||
| [view setWantsLayer: YES]; // prevents the view failing to redraw correctly when paused. | |||||
| [view release]; | |||||
| } | |||||
| QuickTimeMovieComponent::~QuickTimeMovieComponent() | |||||
| { | |||||
| closeMovie(); | |||||
| setView (nil); | |||||
| } | |||||
| bool QuickTimeMovieComponent::isQuickTimeAvailable() noexcept | |||||
| { | |||||
| return true; | |||||
| } | |||||
| static QTMovie* openMovieFromStream (InputStream* movieStream, File& movieFile) | |||||
| { | |||||
| // unfortunately, QTMovie objects can only be created on the main thread.. | |||||
| jassert (MessageManager::getInstance()->isThisTheMessageThread()); | |||||
| QTMovie* movie = nil; | |||||
| if (FileInputStream* const fin = dynamic_cast<FileInputStream*> (movieStream)) | |||||
| { | |||||
| movieFile = fin->getFile(); | |||||
| movie = [QTMovie movieWithFile: juceStringToNS (movieFile.getFullPathName()) | |||||
| error: nil]; | |||||
| } | |||||
| else | |||||
| { | |||||
| MemoryBlock temp; | |||||
| movieStream->readIntoMemoryBlock (temp); | |||||
| static const char* const suffixesToTry[] = { ".mov", ".mp3", ".avi", ".m4a" }; | |||||
| for (int i = 0; i < numElementsInArray (suffixesToTry); ++i) | |||||
| { | |||||
| movie = [QTMovie movieWithDataReference: [QTDataReference dataReferenceWithReferenceToData: [NSData dataWithBytes: temp.getData() | |||||
| length: temp.getSize()] | |||||
| name: [NSString stringWithUTF8String: suffixesToTry[i]] | |||||
| MIMEType: nsEmptyString()] | |||||
| error: nil]; | |||||
| if (movie != 0) | |||||
| break; | |||||
| } | |||||
| } | |||||
| return movie; | |||||
| } | |||||
| bool QuickTimeMovieComponent::loadMovie (const File& file, const bool showController) | |||||
| { | |||||
| return loadMovie (file.createInputStream(), showController); | |||||
| } | |||||
| bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, const bool showController) | |||||
| { | |||||
| const ScopedPointer<InputStream> movieStreamDeleter (movieStream); | |||||
| closeMovie(); | |||||
| if (getPeer() == nullptr) | |||||
| { | |||||
| // To open a movie, this component must be visible inside a functioning window, so that | |||||
| // the QT control can be assigned to the window. | |||||
| jassertfalse; | |||||
| return false; | |||||
| } | |||||
| if (movieStream == nullptr) | |||||
| return false; | |||||
| movie = openMovieFromStream (movieStream, movieFile); | |||||
| [theMovie retain]; | |||||
| QTMovieView* view = (QTMovieView*) getView(); | |||||
| [view setMovie: theMovie]; | |||||
| controllerVisible = showController; | |||||
| [view setControllerVisible: controllerVisible]; | |||||
| setLooping (looping); | |||||
| return movie != nil; | |||||
| } | |||||
| bool QuickTimeMovieComponent::loadMovie (const URL& movieURL, const bool showController) | |||||
| { | |||||
| // unfortunately, QTMovie objects can only be created on the main thread.. | |||||
| jassert (MessageManager::getInstance()->isThisTheMessageThread()); | |||||
| closeMovie(); | |||||
| if (getPeer() == nullptr) | |||||
| { | |||||
| // To open a movie, this component must be visible inside a functioning window, so that | |||||
| // the QT control can be assigned to the window. | |||||
| jassertfalse; | |||||
| return false; | |||||
| } | |||||
| NSURL* url = [NSURL URLWithString: juceStringToNS (movieURL.toString (true))]; | |||||
| NSError* err; | |||||
| if ([QTMovie canInitWithURL: url]) | |||||
| movie = [QTMovie movieWithURL: url error: &err]; | |||||
| [theMovie retain]; | |||||
| QTMovieView* view = (QTMovieView*) getView(); | |||||
| [view setMovie: theMovie]; | |||||
| controllerVisible = showController; | |||||
| [view setControllerVisible: controllerVisible]; | |||||
| setLooping (looping); | |||||
| return movie != nil; | |||||
| } | |||||
| void QuickTimeMovieComponent::closeMovie() | |||||
| { | |||||
| stop(); | |||||
| QTMovieView* view = (QTMovieView*) getView(); | |||||
| [view setMovie: nil]; | |||||
| [theMovie release]; | |||||
| movie = 0; | |||||
| movieFile = File(); | |||||
| } | |||||
| bool QuickTimeMovieComponent::isMovieOpen() const | |||||
| { | |||||
| return movie != nil; | |||||
| } | |||||
| File QuickTimeMovieComponent::getCurrentMovieFile() const | |||||
| { | |||||
| return movieFile; | |||||
| } | |||||
| void QuickTimeMovieComponent::play() | |||||
| { | |||||
| [theMovie play]; | |||||
| } | |||||
| void QuickTimeMovieComponent::stop() | |||||
| { | |||||
| [theMovie stop]; | |||||
| } | |||||
| bool QuickTimeMovieComponent::isPlaying() const | |||||
| { | |||||
| return movie != 0 && [theMovie rate] != 0; | |||||
| } | |||||
| void QuickTimeMovieComponent::setPosition (const double seconds) | |||||
| { | |||||
| if (movie != 0) | |||||
| { | |||||
| QTTime t; | |||||
| t.timeValue = (long long) (100000.0 * seconds); | |||||
| t.timeScale = 100000; | |||||
| t.flags = 0; | |||||
| [theMovie setCurrentTime: t]; | |||||
| } | |||||
| } | |||||
| double QuickTimeMovieComponent::getPosition() const | |||||
| { | |||||
| if (movie == 0) | |||||
| return 0.0; | |||||
| QTTime t = [theMovie currentTime]; | |||||
| return t.timeValue / (double) t.timeScale; | |||||
| } | |||||
| void QuickTimeMovieComponent::setSpeed (const float newSpeed) | |||||
| { | |||||
| [theMovie setRate: newSpeed]; | |||||
| } | |||||
| double QuickTimeMovieComponent::getMovieDuration() const | |||||
| { | |||||
| if (movie == 0) | |||||
| return 0.0; | |||||
| QTTime t = [theMovie duration]; | |||||
| return t.timeValue / (double) t.timeScale; | |||||
| } | |||||
| void QuickTimeMovieComponent::setLooping (const bool shouldLoop) | |||||
| { | |||||
| looping = shouldLoop; | |||||
| [theMovie setAttribute: [NSNumber numberWithBool: shouldLoop] | |||||
| forKey: QTMovieLoopsAttribute]; | |||||
| } | |||||
| bool QuickTimeMovieComponent::isLooping() const | |||||
| { | |||||
| return looping; | |||||
| } | |||||
| void QuickTimeMovieComponent::setMovieVolume (const float newVolume) | |||||
| { | |||||
| [theMovie setVolume: newVolume]; | |||||
| } | |||||
| float QuickTimeMovieComponent::getMovieVolume() const | |||||
| { | |||||
| return movie != 0 ? [theMovie volume] : 0.0f; | |||||
| } | |||||
| void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const | |||||
| { | |||||
| width = 0; | |||||
| height = 0; | |||||
| if (movie != 0) | |||||
| { | |||||
| NSSize s = [[theMovie attributeForKey: QTMovieNaturalSizeAttribute] sizeValue]; | |||||
| width = (int) s.width; | |||||
| height = (int) s.height; | |||||
| } | |||||
| } | |||||
| void QuickTimeMovieComponent::paint (Graphics& g) | |||||
| { | |||||
| if (movie == 0) | |||||
| g.fillAll (Colours::black); | |||||
| } | |||||
| bool QuickTimeMovieComponent::isControllerVisible() const | |||||
| { | |||||
| return controllerVisible; | |||||
| } | |||||
| //============================================================================== | |||||
| void QuickTimeMovieComponent::goToStart() | |||||
| { | |||||
| setPosition (0.0); | |||||
| } | |||||
| void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin, | |||||
| RectanglePlacement placement) | |||||
| { | |||||
| int normalWidth, normalHeight; | |||||
| getMovieNormalSize (normalWidth, normalHeight); | |||||
| const Rectangle<int> normalSize (normalWidth, normalHeight); | |||||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||||
| else | |||||
| setBounds (spaceToFitWithin); | |||||
| } | |||||
| //============================================================================== | |||||
| #if ! (JUCE_MAC && JUCE_64BIT) | |||||
| bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, Handle&) | |||||
| { | |||||
| if (movieStream == nullptr) | |||||
| return false; | |||||
| File file; | |||||
| QTMovie* movie = openMovieFromStream (movieStream, file); | |||||
| if (movie != nil) | |||||
| result = [movie quickTimeMovie]; | |||||
| return movie != nil; | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -1,483 +0,0 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2015 - ROLI Ltd. | |||||
| Permission is granted to use this software under the terms of either: | |||||
| a) the GPL v2 (or any later version) | |||||
| b) the Affero GPL v3 | |||||
| Details of these licenses can be found at: www.gnu.org/licenses | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.juce.com for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| using namespace QTOLibrary; | |||||
| using namespace QTOControlLib; | |||||
| bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); | |||||
| static bool isQTAvailable = false; | |||||
| //============================================================================== | |||||
| class QuickTimeMovieComponent::Pimpl | |||||
| { | |||||
| public: | |||||
| Pimpl() : dataHandle (0) | |||||
| { | |||||
| } | |||||
| ~Pimpl() | |||||
| { | |||||
| clearHandle(); | |||||
| } | |||||
| void clearHandle() | |||||
| { | |||||
| if (dataHandle != 0) | |||||
| { | |||||
| DisposeHandle (dataHandle); | |||||
| dataHandle = 0; | |||||
| } | |||||
| } | |||||
| IQTControlPtr qtControl; | |||||
| IQTMoviePtr qtMovie; | |||||
| Handle dataHandle; | |||||
| }; | |||||
| //============================================================================== | |||||
| QuickTimeMovieComponent::QuickTimeMovieComponent() | |||||
| : movieLoaded (false), | |||||
| controllerVisible (true) | |||||
| { | |||||
| pimpl = new Pimpl(); | |||||
| setMouseEventsAllowed (false); | |||||
| } | |||||
| QuickTimeMovieComponent::~QuickTimeMovieComponent() | |||||
| { | |||||
| closeMovie(); | |||||
| pimpl->qtControl = 0; | |||||
| deleteControl(); | |||||
| pimpl = nullptr; | |||||
| } | |||||
| bool QuickTimeMovieComponent::isQuickTimeAvailable() noexcept | |||||
| { | |||||
| if (! isQTAvailable) | |||||
| 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); | |||||
| pimpl->qtControl = (IQTControl*) queryInterface (&qtInterfaceIID); | |||||
| if (pimpl->qtControl != nullptr) | |||||
| { | |||||
| pimpl->qtControl->Release(); // it has one ref too many at this point | |||||
| pimpl->qtControl->QuickTimeInitialize(); | |||||
| pimpl->qtControl->PutSizing (qtMovieFitsControl); | |||||
| if (movieFile != File()) | |||||
| loadMovie (movieFile, controllerVisible); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bool QuickTimeMovieComponent::isControlCreated() const | |||||
| { | |||||
| return isControlOpen(); | |||||
| } | |||||
| bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, | |||||
| const bool isControllerVisible) | |||||
| { | |||||
| const ScopedPointer<InputStream> movieStreamDeleter (movieStream); | |||||
| movieFile = File(); | |||||
| movieLoaded = false; | |||||
| pimpl->qtMovie = 0; | |||||
| controllerVisible = isControllerVisible; | |||||
| createControlIfNeeded(); | |||||
| if (isControlCreated()) | |||||
| { | |||||
| if (pimpl->qtControl != 0) | |||||
| { | |||||
| pimpl->qtControl->Put_MovieHandle (0); | |||||
| pimpl->clearHandle(); | |||||
| Movie movie; | |||||
| if (juce_OpenQuickTimeMovieFromStream (movieStream, movie, pimpl->dataHandle)) | |||||
| { | |||||
| pimpl->qtControl->Put_MovieHandle ((long) (pointer_sized_int) movie); | |||||
| pimpl->qtMovie = pimpl->qtControl->GetMovie(); | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->PutMovieControllerType (isControllerVisible ? qtMovieControllerTypeStandard | |||||
| : qtMovieControllerTypeNone); | |||||
| } | |||||
| if (movie == 0) | |||||
| pimpl->clearHandle(); | |||||
| } | |||||
| movieLoaded = (pimpl->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; | |||||
| } | |||||
| return movieLoaded; | |||||
| } | |||||
| void QuickTimeMovieComponent::closeMovie() | |||||
| { | |||||
| stop(); | |||||
| movieFile = File(); | |||||
| movieLoaded = false; | |||||
| pimpl->qtMovie = 0; | |||||
| if (pimpl->qtControl != 0) | |||||
| pimpl->qtControl->Put_MovieHandle (0); | |||||
| pimpl->clearHandle(); | |||||
| } | |||||
| File QuickTimeMovieComponent::getCurrentMovieFile() const | |||||
| { | |||||
| return movieFile; | |||||
| } | |||||
| bool QuickTimeMovieComponent::isMovieOpen() const | |||||
| { | |||||
| return movieLoaded; | |||||
| } | |||||
| double QuickTimeMovieComponent::getMovieDuration() const | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| return pimpl->qtMovie->GetDuration() / (double) pimpl->qtMovie->GetTimeScale(); | |||||
| return 0.0; | |||||
| } | |||||
| void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| { | |||||
| struct QTRECT r = pimpl->qtMovie->GetNaturalRect(); | |||||
| width = r.right - r.left; | |||||
| height = r.bottom - r.top; | |||||
| } | |||||
| else | |||||
| { | |||||
| width = height = 0; | |||||
| } | |||||
| } | |||||
| void QuickTimeMovieComponent::play() | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->Play(); | |||||
| } | |||||
| void QuickTimeMovieComponent::stop() | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->Stop(); | |||||
| } | |||||
| bool QuickTimeMovieComponent::isPlaying() const | |||||
| { | |||||
| return pimpl->qtMovie != 0 && pimpl->qtMovie->GetRate() != 0.0f; | |||||
| } | |||||
| void QuickTimeMovieComponent::setPosition (const double seconds) | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->PutTime ((long) (seconds * pimpl->qtMovie->GetTimeScale())); | |||||
| } | |||||
| double QuickTimeMovieComponent::getPosition() const | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| return pimpl->qtMovie->GetTime() / (double) pimpl->qtMovie->GetTimeScale(); | |||||
| return 0.0; | |||||
| } | |||||
| void QuickTimeMovieComponent::setSpeed (const float newSpeed) | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->PutRate (newSpeed); | |||||
| } | |||||
| void QuickTimeMovieComponent::setMovieVolume (const float newVolume) | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| { | |||||
| pimpl->qtMovie->PutAudioVolume (newVolume); | |||||
| pimpl->qtMovie->PutAudioMute (newVolume <= 0); | |||||
| } | |||||
| } | |||||
| float QuickTimeMovieComponent::getMovieVolume() const | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| return pimpl->qtMovie->GetAudioVolume(); | |||||
| return 0.0f; | |||||
| } | |||||
| void QuickTimeMovieComponent::setLooping (const bool shouldLoop) | |||||
| { | |||||
| if (pimpl->qtMovie != 0) | |||||
| pimpl->qtMovie->PutLoop (shouldLoop); | |||||
| } | |||||
| bool QuickTimeMovieComponent::isLooping() const | |||||
| { | |||||
| return pimpl->qtMovie != 0 && pimpl->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; | |||||
| #if JUCE_MSVC | |||||
| #pragma warning (push) | |||||
| #pragma warning (disable: 4244 4996) | |||||
| #endif | |||||
| suffix[0] = strlen (fileName); | |||||
| strncpy ((char*) suffix + 1, fileName, 128); | |||||
| #if JUCE_MSVC | |||||
| #pragma warning (pop) | |||||
| #endif | |||||
| err = PtrAndHand (suffix, dataRef, suffix[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) | |||||
| { | |||||
| return CFStringCreateWithCString (kCFAllocatorDefault, s.toUTF8(), kCFStringEncodingUTF8); | |||||
| } | |||||
| 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 == nullptr) | |||||
| return false; | |||||
| dataHandle = 0; | |||||
| bool ok = false; | |||||
| QTNewMoviePropertyElement props[5] = { 0 }; | |||||
| int prop = 0; | |||||
| DataReferenceRecord dr; | |||||
| props[prop].propClass = kQTPropertyClass_DataLocation; | |||||
| props[prop].propID = kQTDataLocationPropertyID_DataReference; | |||||
| props[prop].propValueSize = sizeof (dr); | |||||
| props[prop].propValueAddress = &dr; | |||||
| ++prop; | |||||
| FileInputStream* const fin = dynamic_cast<FileInputStream*> (input); | |||||
| if (fin != nullptr) | |||||
| { | |||||
| 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) | |||||
| static 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 (static_cast<InputStream*> (movieFile_.createInputStream()), isControllerVisible); | |||||
| movieFile = movieFile_; | |||||
| return ok; | |||||
| } | |||||
| bool QuickTimeMovieComponent::loadMovie (const URL& movieURL, | |||||
| const bool isControllerVisible) | |||||
| { | |||||
| return loadMovie (static_cast<InputStream*> (movieURL.createInputStream (false)), isControllerVisible); | |||||
| } | |||||
| void QuickTimeMovieComponent::goToStart() | |||||
| { | |||||
| setPosition (0.0); | |||||
| } | |||||
| void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin, | |||||
| RectanglePlacement placement) | |||||
| { | |||||
| int normalWidth, normalHeight; | |||||
| getMovieNormalSize (normalWidth, normalHeight); | |||||
| const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight); | |||||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||||
| else | |||||
| setBounds (spaceToFitWithin); | |||||
| } | |||||
| @@ -25,7 +25,6 @@ | |||||
| #ifndef JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | #ifndef JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | ||||
| #define JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | #define JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | ||||
| #if JUCE_DIRECTSHOW || DOXYGEN | |||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| @@ -212,5 +211,4 @@ private: | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent) | ||||
| }; | }; | ||||
| #endif | |||||
| #endif // JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | #endif // JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED | ||||
| @@ -0,0 +1,65 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2015 - ROLI Ltd. | |||||
| Permission is granted to use this software under the terms of either: | |||||
| a) the GPL v2 (or any later version) | |||||
| b) the Affero GPL v3 | |||||
| Details of these licenses can be found at: www.gnu.org/licenses | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.juce.com for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #pragma once | |||||
| //============================================================================== | |||||
| /** | |||||
| A component that can play back a video file. | |||||
| */ | |||||
| class JUCE_API MovieComponent : public NSViewComponent | |||||
| { | |||||
| public: | |||||
| MovieComponent(); | |||||
| ~MovieComponent(); | |||||
| bool loadMovie (const File& file); | |||||
| bool loadMovie (const URL& file); | |||||
| void closeMovie(); | |||||
| bool isMovieOpen() const; | |||||
| String getCurrentMoviePath() const; | |||||
| void play(); | |||||
| void stop(); | |||||
| double getDuration() const; | |||||
| double getPosition() const; | |||||
| void setPosition (double seconds); | |||||
| void setVolume (float newVolume); | |||||
| float getVolume() const; | |||||
| Rectangle<int> getNativeSize() const; | |||||
| void setBoundsWithCorrectAspectRatio (Rectangle<int> spaceToFitWithin, | |||||
| RectanglePlacement placement); | |||||
| protected: | |||||
| void resized() override; | |||||
| private: | |||||
| struct Pimpl; | |||||
| ScopedPointer<Pimpl> pimpl; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MovieComponent) | |||||
| }; | |||||
| @@ -1,217 +0,0 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2015 - ROLI Ltd. | |||||
| Permission is granted to use this software under the terms of either: | |||||
| a) the GPL v2 (or any later version) | |||||
| b) the Affero GPL v3 | |||||
| Details of these licenses can be found at: www.gnu.org/licenses | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.juce.com for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef JUCE_QUICKTIMEMOVIECOMPONENT_H_INCLUDED | |||||
| #define JUCE_QUICKTIMEMOVIECOMPONENT_H_INCLUDED | |||||
| #ifndef DOXYGEN | |||||
| #if JUCE_WINDOWS | |||||
| typedef ActiveXControlComponent QTCompBaseClass; | |||||
| #elif JUCE_MAC | |||||
| typedef NSViewComponent QTCompBaseClass; | |||||
| #endif | |||||
| #endif | |||||
| #if JUCE_QUICKTIME || DOXYGEN | |||||
| //============================================================================== | |||||
| /** | |||||
| A window that can play back a QuickTime movie. | |||||
| */ | |||||
| class JUCE_API QuickTimeMovieComponent : public QTCompBaseClass | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates a QuickTimeMovieComponent, initially blank. | |||||
| Use the loadMovie() method to load a movie once you've added the | |||||
| component to a window, (or put it on the desktop as a heavyweight window). | |||||
| Loading a movie when the component isn't visible can cause problems, as | |||||
| QuickTime needs a window handle to initialise properly. | |||||
| */ | |||||
| QuickTimeMovieComponent(); | |||||
| /** Destructor. */ | |||||
| ~QuickTimeMovieComponent(); | |||||
| /** Returns true if QT is installed and working on this machine. | |||||
| */ | |||||
| static bool isQuickTimeAvailable() noexcept; | |||||
| //============================================================================== | |||||
| /** Tries to load a QuickTime movie from a file into the player. | |||||
| It's best to call this function once you've added the component to a window, | |||||
| (or put it on the desktop as a heavyweight window). Loading a movie when the | |||||
| component isn't visible can cause problems, because QuickTime needs a window | |||||
| handle to do its stuff. | |||||
| @param movieFile the .mov file to open | |||||
| @param isControllerVisible whether to show a controller bar at the bottom | |||||
| @returns true if the movie opens successfully | |||||
| */ | |||||
| bool loadMovie (const File& movieFile, | |||||
| bool isControllerVisible); | |||||
| /** Tries to load a QuickTime movie from a URL into the player. | |||||
| It's best to call this function once you've added the component to a window, | |||||
| (or put it on the desktop as a heavyweight window). Loading a movie when the | |||||
| component isn't visible can cause problems, because QuickTime needs a window | |||||
| handle to do its stuff. | |||||
| @param movieURL the .mov file to open | |||||
| @param isControllerVisible whether to show a controller bar at the bottom | |||||
| @returns true if the movie opens successfully | |||||
| */ | |||||
| bool loadMovie (const URL& movieURL, | |||||
| bool isControllerVisible); | |||||
| /** Tries to load a QuickTime movie from a stream into the player. | |||||
| It's best to call this function once you've added the component to a window, | |||||
| (or put it on the desktop as a heavyweight window). Loading a movie when the | |||||
| component isn't visible can cause problems, because QuickTime needs a window | |||||
| handle to do its stuff. | |||||
| @param movieStream a stream containing a .mov file. The component may try | |||||
| to read the whole stream before playing, rather than | |||||
| streaming from it. | |||||
| @param isControllerVisible whether to show a controller bar at the bottom | |||||
| @returns true if the movie opens successfully | |||||
| */ | |||||
| bool loadMovie (InputStream* movieStream, | |||||
| bool isControllerVisible); | |||||
| /** Closes the movie, if one is open. */ | |||||
| void closeMovie(); | |||||
| /** Returns the movie file that is currently open. | |||||
| If there isn't one, this returns File() | |||||
| */ | |||||
| File getCurrentMovieFile() const; | |||||
| /** Returns true if there's currently a movie open. */ | |||||
| bool isMovieOpen() const; | |||||
| /** Returns the length of the movie, in seconds. */ | |||||
| double getMovieDuration() const; | |||||
| /** Returns the movie's natural size, in pixels. | |||||
| You can use this to resize the component to show the movie at its preferred | |||||
| scale. | |||||
| If no movie is loaded, the size returned will be 0 x 0. | |||||
| */ | |||||
| void getMovieNormalSize (int& width, int& height) const; | |||||
| /** This will position the component within a given area, keeping its aspect | |||||
| ratio correct according to the movie's normal size. | |||||
| The component will be made as large as it can go within the space, and will | |||||
| be aligned according to the justification value if this means there are gaps at | |||||
| the top or sides. | |||||
| */ | |||||
| void setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin, | |||||
| RectanglePlacement placement); | |||||
| /** Starts the movie playing. */ | |||||
| void play(); | |||||
| /** Stops the movie playing. */ | |||||
| void stop(); | |||||
| /** Returns true if the movie is currently playing. */ | |||||
| bool isPlaying() const; | |||||
| /** Moves the movie's position back to the start. */ | |||||
| void goToStart(); | |||||
| /** Sets the movie's position to a given time. */ | |||||
| void setPosition (double seconds); | |||||
| /** 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, | |||||
| smaller values play it slower. | |||||
| */ | |||||
| void setSpeed (float newSpeed); | |||||
| /** Changes the movie's playback volume. | |||||
| @param newVolume the volume in the range 0 (silent) to 1.0 (full) | |||||
| */ | |||||
| void setMovieVolume (float newVolume); | |||||
| /** Returns the movie's playback volume. | |||||
| @returns the volume in the range 0 (silent) to 1.0 (full) | |||||
| */ | |||||
| float getMovieVolume() const; | |||||
| /** Tells the movie whether it should loop. */ | |||||
| void setLooping (bool shouldLoop); | |||||
| /** Returns true if the movie is currently looping. | |||||
| @see setLooping | |||||
| */ | |||||
| bool isLooping() const; | |||||
| /** True if the native QuickTime controller bar is shown in the window. | |||||
| @see loadMovie | |||||
| */ | |||||
| bool isControllerVisible() const; | |||||
| //============================================================================== | |||||
| /** @internal */ | |||||
| void paint (Graphics&) override; | |||||
| private: | |||||
| //============================================================================== | |||||
| File movieFile; | |||||
| bool movieLoaded, controllerVisible, looping; | |||||
| #if JUCE_WINDOWS | |||||
| void parentHierarchyChanged() override; | |||||
| void visibilityChanged() override; | |||||
| void createControlIfNeeded(); | |||||
| bool isControlCreated() const; | |||||
| class Pimpl; | |||||
| friend struct ContainerDeletePolicy<Pimpl>; | |||||
| ScopedPointer<Pimpl> pimpl; | |||||
| #else | |||||
| void* movie; | |||||
| #endif | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (QuickTimeMovieComponent) | |||||
| }; | |||||
| #endif | |||||
| #endif // JUCE_QUICKTIMEMOVIECOMPONENT_H_INCLUDED | |||||