The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #if JUCE_QUICKTIME
  19. } // (juce namespace)
  20. //==============================================================================
  21. #define NonInterceptingQTMovieView MakeObjCClassName(NonInterceptingQTMovieView)
  22. @interface NonInterceptingQTMovieView : QTMovieView
  23. {
  24. }
  25. - (id) initWithFrame: (NSRect) frame;
  26. - (BOOL) acceptsFirstMouse: (NSEvent*) theEvent;
  27. - (NSView*) hitTest: (NSPoint) p;
  28. @end
  29. @implementation NonInterceptingQTMovieView
  30. - (id) initWithFrame: (NSRect) frame
  31. {
  32. self = [super initWithFrame: frame];
  33. [self setNextResponder: [self superview]];
  34. return self;
  35. }
  36. - (void) dealloc
  37. {
  38. [super dealloc];
  39. }
  40. - (NSView*) hitTest: (NSPoint) point
  41. {
  42. return [self isControllerVisible] ? [super hitTest: point] : nil;
  43. }
  44. - (BOOL) acceptsFirstMouse: (NSEvent*) theEvent
  45. {
  46. return YES;
  47. }
  48. @end
  49. namespace juce
  50. {
  51. //==============================================================================
  52. #define theMovie (static_cast <QTMovie*> (movie))
  53. //==============================================================================
  54. QuickTimeMovieComponent::QuickTimeMovieComponent()
  55. : movie (0)
  56. {
  57. setOpaque (true);
  58. setVisible (true);
  59. QTMovieView* view = [[NonInterceptingQTMovieView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
  60. setView (view);
  61. [view setWantsLayer: YES]; // prevents the view failing to redraw correctly when paused.
  62. [view release];
  63. }
  64. QuickTimeMovieComponent::~QuickTimeMovieComponent()
  65. {
  66. closeMovie();
  67. setView (nil);
  68. }
  69. bool QuickTimeMovieComponent::isQuickTimeAvailable() noexcept
  70. {
  71. return true;
  72. }
  73. static QTMovie* openMovieFromStream (InputStream* movieStream, File& movieFile)
  74. {
  75. // unfortunately, QTMovie objects can only be created on the main thread..
  76. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  77. QTMovie* movie = nil;
  78. FileInputStream* const fin = dynamic_cast <FileInputStream*> (movieStream);
  79. if (fin != nullptr)
  80. {
  81. movieFile = fin->getFile();
  82. movie = [QTMovie movieWithFile: juceStringToNS (movieFile.getFullPathName())
  83. error: nil];
  84. }
  85. else
  86. {
  87. MemoryBlock temp;
  88. movieStream->readIntoMemoryBlock (temp);
  89. const char* const suffixesToTry[] = { ".mov", ".mp3", ".avi", ".m4a" };
  90. for (int i = 0; i < numElementsInArray (suffixesToTry); ++i)
  91. {
  92. movie = [QTMovie movieWithDataReference: [QTDataReference dataReferenceWithReferenceToData: [NSData dataWithBytes: temp.getData()
  93. length: temp.getSize()]
  94. name: [NSString stringWithUTF8String: suffixesToTry[i]]
  95. MIMEType: nsEmptyString()]
  96. error: nil];
  97. if (movie != 0)
  98. break;
  99. }
  100. }
  101. return movie;
  102. }
  103. bool QuickTimeMovieComponent::loadMovie (const File& movieFile_,
  104. const bool isControllerVisible_)
  105. {
  106. return loadMovie ((InputStream*) movieFile_.createInputStream(), isControllerVisible_);
  107. }
  108. bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream,
  109. const bool controllerVisible_)
  110. {
  111. closeMovie();
  112. if (getPeer() == nullptr)
  113. {
  114. // To open a movie, this component must be visible inside a functioning window, so that
  115. // the QT control can be assigned to the window.
  116. jassertfalse;
  117. return false;
  118. }
  119. movie = openMovieFromStream (movieStream, movieFile);
  120. [theMovie retain];
  121. QTMovieView* view = (QTMovieView*) getView();
  122. [view setMovie: theMovie];
  123. [view setControllerVisible: controllerVisible_];
  124. setLooping (looping);
  125. return movie != nil;
  126. }
  127. bool QuickTimeMovieComponent::loadMovie (const URL& movieURL,
  128. const bool isControllerVisible_)
  129. {
  130. // unfortunately, QTMovie objects can only be created on the main thread..
  131. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  132. closeMovie();
  133. if (getPeer() == nullptr)
  134. {
  135. // To open a movie, this component must be visible inside a functioning window, so that
  136. // the QT control can be assigned to the window.
  137. jassertfalse;
  138. return false;
  139. }
  140. NSURL* url = [NSURL URLWithString: juceStringToNS (movieURL.toString (true))];
  141. NSError* err;
  142. if ([QTMovie canInitWithURL: url])
  143. movie = [QTMovie movieWithURL: url error: &err];
  144. [theMovie retain];
  145. QTMovieView* view = (QTMovieView*) getView();
  146. [view setMovie: theMovie];
  147. [view setControllerVisible: controllerVisible];
  148. setLooping (looping);
  149. return movie != nil;
  150. }
  151. void QuickTimeMovieComponent::closeMovie()
  152. {
  153. stop();
  154. QTMovieView* view = (QTMovieView*) getView();
  155. [view setMovie: nil];
  156. [theMovie release];
  157. movie = 0;
  158. movieFile = File::nonexistent;
  159. }
  160. bool QuickTimeMovieComponent::isMovieOpen() const
  161. {
  162. return movie != nil;
  163. }
  164. File QuickTimeMovieComponent::getCurrentMovieFile() const
  165. {
  166. return movieFile;
  167. }
  168. void QuickTimeMovieComponent::play()
  169. {
  170. [theMovie play];
  171. }
  172. void QuickTimeMovieComponent::stop()
  173. {
  174. [theMovie stop];
  175. }
  176. bool QuickTimeMovieComponent::isPlaying() const
  177. {
  178. return movie != 0 && [theMovie rate] != 0;
  179. }
  180. void QuickTimeMovieComponent::setPosition (const double seconds)
  181. {
  182. if (movie != 0)
  183. {
  184. QTTime t;
  185. t.timeValue = (uint64) (100000.0 * seconds);
  186. t.timeScale = 100000;
  187. t.flags = 0;
  188. [theMovie setCurrentTime: t];
  189. }
  190. }
  191. double QuickTimeMovieComponent::getPosition() const
  192. {
  193. if (movie == 0)
  194. return 0.0;
  195. QTTime t = [theMovie currentTime];
  196. return t.timeValue / (double) t.timeScale;
  197. }
  198. void QuickTimeMovieComponent::setSpeed (const float newSpeed)
  199. {
  200. [theMovie setRate: newSpeed];
  201. }
  202. double QuickTimeMovieComponent::getMovieDuration() const
  203. {
  204. if (movie == 0)
  205. return 0.0;
  206. QTTime t = [theMovie duration];
  207. return t.timeValue / (double) t.timeScale;
  208. }
  209. void QuickTimeMovieComponent::setLooping (const bool shouldLoop)
  210. {
  211. looping = shouldLoop;
  212. [theMovie setAttribute: [NSNumber numberWithBool: shouldLoop]
  213. forKey: QTMovieLoopsAttribute];
  214. }
  215. bool QuickTimeMovieComponent::isLooping() const
  216. {
  217. return looping;
  218. }
  219. void QuickTimeMovieComponent::setMovieVolume (const float newVolume)
  220. {
  221. [theMovie setVolume: newVolume];
  222. }
  223. float QuickTimeMovieComponent::getMovieVolume() const
  224. {
  225. return movie != 0 ? [theMovie volume] : 0.0f;
  226. }
  227. void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const
  228. {
  229. width = 0;
  230. height = 0;
  231. if (movie != 0)
  232. {
  233. NSSize s = [[theMovie attributeForKey: QTMovieNaturalSizeAttribute] sizeValue];
  234. width = (int) s.width;
  235. height = (int) s.height;
  236. }
  237. }
  238. void QuickTimeMovieComponent::paint (Graphics& g)
  239. {
  240. if (movie == 0)
  241. g.fillAll (Colours::black);
  242. }
  243. bool QuickTimeMovieComponent::isControllerVisible() const
  244. {
  245. return controllerVisible;
  246. }
  247. //==============================================================================
  248. void QuickTimeMovieComponent::goToStart()
  249. {
  250. setPosition (0.0);
  251. }
  252. void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin,
  253. const RectanglePlacement& placement)
  254. {
  255. int normalWidth, normalHeight;
  256. getMovieNormalSize (normalWidth, normalHeight);
  257. const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight);
  258. if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty()))
  259. setBounds (placement.appliedTo (normalSize, spaceToFitWithin));
  260. else
  261. setBounds (spaceToFitWithin);
  262. }
  263. //==============================================================================
  264. #if ! (JUCE_MAC && JUCE_64BIT)
  265. bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, Handle& dataHandle)
  266. {
  267. if (movieStream == nullptr)
  268. return false;
  269. File file;
  270. QTMovie* movie = openMovieFromStream (movieStream, file);
  271. if (movie != nil)
  272. result = [movie quickTimeMovie];
  273. return movie != nil;
  274. }
  275. #endif
  276. #endif