mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Replaced QuickTimeMovieComponent with MovieComponent, using AVFoundation on OSX
This commit is contained in:
parent
f91401612a
commit
1c0b935bf6
8 changed files with 298 additions and 1056 deletions
|
|
@ -38,9 +38,7 @@
|
|||
#include "juce_video.h"
|
||||
|
||||
#if JUCE_MAC
|
||||
#if JUCE_QUICKTIME
|
||||
#import <QTKit/QTKit.h>
|
||||
#endif
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
|
|
@ -104,9 +102,7 @@ namespace juce
|
|||
#include "native/juce_mac_CameraDevice.mm"
|
||||
#endif
|
||||
|
||||
#if JUCE_QUICKTIME
|
||||
#include "native/juce_mac_QuickTimeMovieComponent.mm"
|
||||
#endif
|
||||
#include "native/juce_mac_MovieComponent.mm"
|
||||
|
||||
#elif JUCE_WINDOWS
|
||||
|
||||
|
|
@ -118,10 +114,6 @@ namespace juce
|
|||
#include "native/juce_win32_DirectShowComponent.cpp"
|
||||
#endif
|
||||
|
||||
#if JUCE_QUICKTIME
|
||||
#include "native/juce_win32_QuickTimeMovieComponent.cpp"
|
||||
#endif
|
||||
|
||||
#elif JUCE_LINUX
|
||||
|
||||
#elif JUCE_ANDROID
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
license: GPL/Commercial
|
||||
|
||||
dependencies: juce_data_structures juce_cryptography
|
||||
OSXFrameworks: QTKit QuickTime
|
||||
OSXFrameworks: AVFoundation CoreMedia
|
||||
|
||||
END_JUCE_MODULE_DECLARATION
|
||||
|
||||
|
|
@ -99,8 +99,14 @@
|
|||
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"
|
||||
|
||||
}
|
||||
|
|
|
|||
222
modules/juce_video/native/juce_mac_MovieComponent.mm
Normal file
222
modules/juce_video/native/juce_mac_MovieComponent.mm
Normal file
|
|
@ -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
|
||||
#define JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED
|
||||
|
||||
#if JUCE_DIRECTSHOW || DOXYGEN
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -212,5 +211,4 @@ private:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent)
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // JUCE_DIRECTSHOWCOMPONENT_H_INCLUDED
|
||||
|
|
|
|||
65
modules/juce_video/playback/juce_MovieComponent.h
Normal file
65
modules/juce_video/playback/juce_MovieComponent.h
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue