diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/llmedia/llmediaimplquicktime.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2 meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz |
Second Life viewer sources 1.19.1.0
Diffstat (limited to 'linden/indra/llmedia/llmediaimplquicktime.cpp')
-rw-r--r-- | linden/indra/llmedia/llmediaimplquicktime.cpp | 1191 |
1 files changed, 456 insertions, 735 deletions
diff --git a/linden/indra/llmedia/llmediaimplquicktime.cpp b/linden/indra/llmedia/llmediaimplquicktime.cpp index 8fcd7bf..f9a3b05 100644 --- a/linden/indra/llmedia/llmediaimplquicktime.cpp +++ b/linden/indra/llmedia/llmediaimplquicktime.cpp | |||
@@ -1,10 +1,10 @@ | |||
1 | /** | 1 | /** |
2 | * @file llmediaimplquicktime.cpp | 2 | * @file llmediaimplquicktime.cpp |
3 | * @brief implementation that supports Apple QuickTime media. | 3 | * @brief QuickTime media impl concrete class |
4 | * | 4 | * |
5 | * $LicenseInfo:firstyear=2005&license=viewergpl$ | 5 | * $LicenseInfo:firstyear=2007&license=viewergpl$ |
6 | * | 6 | * |
7 | * Copyright (c) 2005-2008, Linden Research, Inc. | 7 | * Copyright (c) 2007-2008, Linden Research, Inc. |
8 | * | 8 | * |
9 | * Second Life Viewer Source Code | 9 | * Second Life Viewer Source Code |
10 | * The source code in this file ("Source Code") is provided by Linden Lab | 10 | * The source code in this file ("Source Code") is provided by Linden Lab |
@@ -29,382 +29,269 @@ | |||
29 | * $/LicenseInfo$ | 29 | * $/LicenseInfo$ |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include "linden_common.h" | 32 | #include "llmediaimplquicktime.h" |
33 | 33 | ||
34 | #if LL_QUICKTIME_ENABLED | 34 | #if LL_QUICKTIME_ENABLED |
35 | 35 | ||
36 | #include <iostream> | 36 | #include "llmediamanager.h" |
37 | #include "llmediaimplregister.h" | ||
37 | 38 | ||
38 | #include "llmediaimplquicktime.h" | 39 | #if LL_WINDOWS |
40 | #include <windows.h> | ||
41 | #endif | ||
42 | |||
43 | #include <iostream> | ||
44 | #include <sstream> | ||
39 | 45 | ||
40 | #include "llgl.h" | 46 | // register this impl with media manager factory |
41 | #include "llglheaders.h" // For gl texture modes | 47 | static LLMediaImplRegister sLLMediaImplQuickTimeReg( "LLMediaImplQuickTime", new LLMediaImplQuickTimeMaker() ); |
42 | 48 | ||
43 | /////////////////////////////////////////////////////////////////////////////// | 49 | /////////////////////////////////////////////////////////////////////////////// |
44 | // | 50 | // |
45 | LLMediaImplQuickTime:: | 51 | LLMediaImplQuickTimeMaker::LLMediaImplQuickTimeMaker() |
46 | LLMediaImplQuickTime () : | ||
47 | theController ( NULL ), | ||
48 | currentMode ( ModeIdle ), | ||
49 | theGWorld ( 0 ), | ||
50 | theMovie ( 0 ), | ||
51 | mediaData ( 0 ), | ||
52 | loopsLeft ( 0 ), | ||
53 | ownBuffer ( TRUE ), | ||
54 | curVolume ( 0 ), | ||
55 | sizeChangeInProgress ( FALSE ), | ||
56 | initialStartDone ( FALSE ), | ||
57 | autoScaled ( FALSE ) | ||
58 | { | 52 | { |
59 | // These should probably be in the initializer list above, but that seemed uglier... | 53 | // Register to handle the scheme |
60 | #if LL_DARWIN | 54 | mSchema.push_back( "rtsp" ); |
61 | // Mac OS -- gworld will be xRGB (4 byte pixels, like ARGB, but QuickDraw doesn't actually do alpha...) | ||
62 | mMediaDepthBytes = 4; | ||
63 | mTextureDepth = 4; | ||
64 | mTextureFormatInternal = GL_RGB8; | ||
65 | mTextureFormatPrimary = GL_BGRA; | ||
66 | #ifdef LL_BIG_ENDIAN | ||
67 | mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; | ||
68 | #else | ||
69 | mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8; | ||
70 | #endif | ||
71 | 55 | ||
72 | #else | 56 | // Register to handle the category |
73 | // Windows -- GWorld will be RGB (3 byte pixels) | 57 | mMimeTypeCategories.push_back( "video" ); |
74 | mMediaDepthBytes = 3; | 58 | mMimeTypeCategories.push_back( "audio" ); |
75 | mTextureDepth = 3; | 59 | mMimeTypeCategories.push_back( "image" ); |
76 | mTextureFormatInternal = GL_RGB8; | 60 | } |
77 | mTextureFormatPrimary = GL_RGB; | ||
78 | mTextureFormatType = GL_UNSIGNED_BYTE; | ||
79 | #endif | ||
80 | }; | ||
81 | 61 | ||
82 | /////////////////////////////////////////////////////////////////////////////// | 62 | /////////////////////////////////////////////////////////////////////////////// |
83 | // | 63 | // |
84 | LLMediaImplQuickTime:: | 64 | LLMediaImplQuickTime::LLMediaImplQuickTime() : |
85 | ~LLMediaImplQuickTime () | 65 | mMovieHandle( 0 ), |
66 | mGWorldHandle( 0 ), | ||
67 | mMovieController( 0 ), | ||
68 | mMinWidth( 32 ), | ||
69 | mMaxWidth( 2048 ), | ||
70 | mMinHeight( 32 ), | ||
71 | mMaxHeight( 2048 ), | ||
72 | mCurVolume( 0 ) | ||
86 | { | 73 | { |
87 | unload(); | ||
88 | } | 74 | } |
89 | 75 | ||
90 | /////////////////////////////////////////////////////////////////////////////// | 76 | /////////////////////////////////////////////////////////////////////////////// |
91 | // | 77 | // |
92 | BOOL | 78 | LLMediaImplQuickTime::~LLMediaImplQuickTime() |
93 | LLMediaImplQuickTime:: | ||
94 | setBuffer ( U8* bufferIn ) | ||
95 | { | 79 | { |
96 | OSErr err = noErr; | 80 | unload(); |
97 | 81 | } | |
98 | // If we're waiting for a size change, we just got one. | ||
99 | sizeChangeInProgress = FALSE; | ||
100 | |||
101 | // Since we've pointed QuickTime at the old media data buffer directly, we need to be somewhat careful deleting it... | ||
102 | U8* oldMediaData = mediaData; | ||
103 | BOOL ownedMediaData = ownBuffer; | ||
104 | #if LL_DARWIN | ||
105 | GWorldPtr oldGWorld = theGWorld; | ||
106 | #endif | ||
107 | |||
108 | if(bufferIn == NULL) | ||
109 | { | ||
110 | // Passing NULL to this function requests that the object allocate its own buffer. | ||
111 | mediaData = new unsigned char [ mMediaHeight * mMediaRowbytes ]; | ||
112 | ownBuffer = TRUE; | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | // Use the supplied buffer. | ||
117 | mediaData = bufferIn; | ||
118 | ownBuffer = FALSE; | ||
119 | } | ||
120 | |||
121 | if(mediaData == NULL) | ||
122 | { | ||
123 | // This is bad. | ||
124 | llerrs << "LLMediaImplQuickTime::setBuffer: mediaData is NULL" << llendl; | ||
125 | // NOTE: This case doesn't clean up properly. This assert is fatal, so this isn't a huge problem, | ||
126 | // but if this assert is ever removed the code should be fixed to clean up correctly. | ||
127 | return FALSE; | ||
128 | } | ||
129 | |||
130 | err = NewGWorldFromPtr ( &theGWorld, mMediaDepthBytes * 8, &movieRect, NULL, NULL, 0, (Ptr)mediaData, mMediaRowbytes); | ||
131 | if(err == noErr) | ||
132 | { | ||
133 | if(theMovie) | ||
134 | { | ||
135 | // tell the movie about it | ||
136 | SetMovieGWorld ( theMovie, theGWorld, GetGWorldDevice ( theGWorld ) ); | ||
137 | } | ||
138 | |||
139 | if(theController) | ||
140 | { | ||
141 | // and tell the movie controller about it. | ||
142 | MCSetControllerPort(theController, theGWorld); | ||
143 | } | ||
144 | 82 | ||
145 | #if LL_DARWIN | 83 | //////////////////////////////////////////////////////////////////////////////// |
146 | // NOTE: (CP) This call ultimately leads to a crash in NewGWorldFromPtr on Windows (only) | 84 | // (static) super-initialization - called once at application startup |
147 | // Not calling DisposeGWorld doesn't appear to leak anything significant and stops the crash occuring. | 85 | bool LLMediaImplQuickTime::startup( LLMediaManagerData* init_data ) |
148 | // This will eventually be fixed but for now, leaking slightly is better than crashing. | 86 | { |
149 | if ( oldGWorld != NULL ) | 87 | #ifdef WIN32 |
150 | { | 88 | if ( InitializeQTML( 0L ) != noErr ) |
151 | // Delete the old GWorld | ||
152 | DisposeGWorld ( oldGWorld ); | ||
153 | oldGWorld = NULL; | ||
154 | } | ||
155 | #endif | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | // Hmm... this may be bad. Assert here? | ||
160 | llerrs << "LLMediaImplQuickTime::setBuffer: NewGWorldFromPtr failed" << llendl; | ||
161 | theGWorld = NULL; | ||
162 | return FALSE; | ||
163 | } | ||
164 | |||
165 | // Delete the old media data buffer iff we owned it. | ||
166 | if ( ownedMediaData ) | ||
167 | { | 89 | { |
168 | if ( oldMediaData ) | 90 | return false; |
169 | { | 91 | }; |
170 | delete [] oldMediaData; | 92 | #endif |
171 | } | 93 | |
172 | } | 94 | EnterMovies(); |
173 | 95 | ||
174 | // build event and emit it | 96 | return true; |
175 | |||
176 | return TRUE; | ||
177 | } | 97 | } |
178 | 98 | ||
179 | /////////////////////////////////////////////////////////////////////////////// | 99 | //////////////////////////////////////////////////////////////////////////////// |
180 | // | 100 | // (static) super-uninitialization - called once at application closedown |
181 | BOOL | 101 | bool LLMediaImplQuickTime::closedown() |
182 | LLMediaImplQuickTime:: | ||
183 | init () | ||
184 | { | 102 | { |
185 | // movied to main application initialization for now because it's non-trivial and only needs to be done once | 103 | ExitMovies(); |
186 | // (even though it goes against the media framework design) | 104 | |
187 | //if ( InitializeQTML ( 0L ) != 0 ) | 105 | #ifdef WIN32 |
188 | //{ | 106 | TerminateQTML(); |
189 | // return FALSE; | 107 | #endif |
190 | //}; | 108 | |
191 | 109 | return true; | |
192 | //if ( EnterMovies () != 0 ) | ||
193 | //{ | ||
194 | // return FALSE; | ||
195 | //}; | ||
196 | |||
197 | return LLMediaMovieBase::init(); | ||
198 | } | 110 | } |
199 | 111 | ||
200 | /////////////////////////////////////////////////////////////////////////////// | 112 | //////////////////////////////////////////////////////////////////////////////// |
201 | // | 113 | // private |
202 | void | 114 | bool LLMediaImplQuickTime::load( const std::string url ) |
203 | LLMediaImplQuickTime:: | ||
204 | updateMediaSize() | ||
205 | { | 115 | { |
206 | if((theController == NULL) && (!isQTLoaded())) | 116 | if ( url.empty() ) |
207 | { | 117 | return false; |
208 | // The movie's not loaded enough to get info about it yet. | ||
209 | // Set up a dummy buffer. | ||
210 | movieRect.left = movieRect.top = 0; | ||
211 | movieRect.right = movieRect.bottom = 64; | ||
212 | mMediaRowbytes = mMediaDepthBytes * 64; | ||
213 | mMediaWidth = 64; | ||
214 | mMediaHeight = 64; | ||
215 | mTextureWidth = 64; | ||
216 | mTextureHeight = 64; | ||
217 | |||
218 | return; | ||
219 | } | ||
220 | |||
221 | // pick up the size of the movie | ||
222 | GetMovieBox ( theMovie, &movieRect ); | ||
223 | |||
224 | // save the size of the media so consumer of media class can use it | ||
225 | mMediaWidth = movieRect.right - movieRect.left; | ||
226 | mMediaHeight = movieRect.bottom - movieRect.top; | ||
227 | |||
228 | // Giant media could make us try to use textures bigger than the opengl implementation can handle. | ||
229 | // Pin the maximum X or Y dimension to 1024. | ||
230 | // NOTE: 1024x1024 may still hurt a lot, but it shouldn't cause opengl to flame out. | ||
231 | if(mMediaWidth > 1024) | ||
232 | { | ||
233 | mMediaWidth = 1024; | ||
234 | } | ||
235 | if(mMediaHeight > 1024) | ||
236 | { | ||
237 | mMediaHeight = 1024; | ||
238 | } | ||
239 | |||
240 | // calculate the texture size required to hold media of this size (next power of 2 bigger) | ||
241 | for ( mTextureWidth = 1; mTextureWidth < mMediaWidth; mTextureWidth <<= 1 ) | ||
242 | { | ||
243 | }; | ||
244 | 118 | ||
245 | for ( mTextureHeight = 1; mTextureHeight < mMediaHeight; mTextureHeight <<= 1 ) | 119 | Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); |
246 | { | 120 | if ( NULL == handle ) |
247 | }; | 121 | return false; |
248 | 122 | ||
249 | // llinfos << "Media texture size will be " << mTextureWidth << " x " << mTextureHeight << llendl; | 123 | BlockMove( url.c_str(), *handle, ( Size )( url.length() + 1 ) ); |
250 | |||
251 | // if autoscale is on we simply make the media & texture sizes the same and quicktime does all the hard work | ||
252 | if ( autoScaled ) | ||
253 | { | ||
254 | // Stretch the movie to fill the texture. | ||
255 | mMediaWidth = mTextureWidth; | ||
256 | mMediaHeight = mTextureHeight; | ||
257 | |||
258 | // scale movie using high quality but slow algorithm. | ||
259 | // NOTE: this results in close to same quality as texture scaling option but with (perhaps) significant | ||
260 | // loss of performance (e.g. my machine, release build, frame rate goes from 92 -> 82 fps | ||
261 | // To revert to original behaviour, just remove the line below. | ||
262 | |||
263 | // MBW -- There seems to be serious drop in performance above a particular size, on both low and high end machines. | ||
264 | // 512x256 is fine, while 512x512 is unusable. I theorize that this is due to CPU cache getting broken around that size. | ||
265 | if((mTextureWidth * mTextureHeight) <= (512 * 256)) | ||
266 | { | ||
267 | // llinfos << "Setting high-quality hint." << llendl; | ||
268 | SetMoviePlayHints ( theMovie, hintsHighQuality, hintsHighQuality ); | ||
269 | } | ||
270 | }; | ||
271 | |||
272 | // always flip movie using quicktime (little performance impact and no loss in quality) | ||
273 | if ( TRUE ) | ||
274 | { | ||
275 | // Invert the movie in the Y directon to match the expected orientation of GL textures. | ||
276 | MatrixRecord transform; | ||
277 | GetMovieMatrix ( theMovie, &transform ); | ||
278 | |||
279 | double centerX = mMediaWidth / 2.0; | ||
280 | double centerY = mMediaHeight / 2.0; | ||
281 | ScaleMatrix ( &transform, X2Fix ( 1.0 ), X2Fix ( -1.0 ), X2Fix ( centerX ), X2Fix ( centerY ) ); | ||
282 | |||
283 | SetMovieMatrix ( theMovie, &transform ); | ||
284 | }; | ||
285 | 124 | ||
286 | movieRect.left = 0; | 125 | //std::cout << "LLMediaImplQuickTime::load( " << url << " )" << std::endl; |
287 | movieRect.top = 0; | ||
288 | movieRect.right = mMediaWidth; | ||
289 | movieRect.bottom = mMediaHeight; | ||
290 | 126 | ||
291 | // Calculate the rowbytes of the texture | 127 | // TODO: supposed to use NewMovieFromDataParams now |
292 | mMediaRowbytes = mMediaWidth * mMediaDepthBytes; | 128 | OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); |
293 | 129 | DisposeHandle( handle ); | |
294 | SetMovieBox(theMovie, &movieRect); | 130 | if ( noErr != err ) |
131 | return false; | ||
295 | 132 | ||
296 | if(theController == NULL) | 133 | // do pre-roll actions (typically fired for streaming movies but not always) |
297 | { | 134 | PrePrerollMovie( mMovieHandle, 0, GetMoviePreferredRate( mMovieHandle ), moviePrePrerollCompleteCallback, ( void * )this ); |
298 | SetGWorld(theGWorld, NULL); | 135 | |
299 | 136 | // get movie rect (and check for min/max) | |
300 | // Create a movie controller for the movie | 137 | Rect movie_rect; |
301 | theController = NewMovieController(theMovie, &movieRect, mcNotVisible|mcTopLeftMovie); | 138 | setMovieBoxEnhanced( &movie_rect ); |
302 | 139 | ||
303 | MCSetActionFilterWithRefCon(theController, myMCActionFilterProc, (long)this); | 140 | // make a new movie controller |
304 | 141 | mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); | |
305 | // Allow the movie to dynamically resize (may be necessary for streaming movies to work right...) | 142 | |
306 | SetMoviePlayHints(theMovie, hintsAllowDynamicResize, hintsAllowDynamicResize); | 143 | #if defined(__APPLE__) || defined(MACOSX) |
307 | } | 144 | setMediaDepth( 4 ); |
308 | else | 145 | #else |
309 | { | 146 | setMediaDepth( 3 ); |
310 | MCPositionController(theController, &movieRect, &movieRect, mcTopLeftMovie|mcPositionDontInvalidate); | 147 | #endif |
311 | } | 148 | |
149 | // tell manager about the media size | ||
150 | setMediaSize( movie_rect.right - movie_rect.left, movie_rect.bottom - movie_rect.top); | ||
151 | |||
152 | // movie controller | ||
153 | MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); | ||
154 | |||
155 | SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); | ||
156 | |||
157 | // function that gets called when a frame is drawn | ||
158 | SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); | ||
159 | |||
160 | // emit an event to say that a media source was loaded | ||
161 | LLMediaEvent event( this ); | ||
162 | mEventEmitter.update( &LLMediaObserver::onMediaLoaded, event ); | ||
163 | |||
164 | // set up inital state | ||
165 | sizeChanged(); | ||
166 | |||
167 | return true; | ||
312 | } | 168 | } |
313 | 169 | ||
314 | /////////////////////////////////////////////////////////////////////////////// | 170 | //////////////////////////////////////////////////////////////////////////////// |
315 | // | 171 | // virtual |
316 | void | 172 | std::string LLMediaImplQuickTime::getVersion() |
317 | LLMediaImplQuickTime:: | ||
318 | setupDummyBuffer() | ||
319 | { | 173 | { |
320 | // Used when the movie can't be drawn for some reason. This sets up a buffer that keeps callers from getting annoyed. | 174 | long version; |
321 | movieRect.left = movieRect.top = 0; | 175 | Gestalt( gestaltQuickTimeVersion, &version ); |
322 | movieRect.right = movieRect.bottom = 64; | 176 | |
323 | mMediaRowbytes = mMediaDepthBytes * 64; | 177 | std::ostringstream codec( "" ); |
324 | mMediaWidth = 64; | 178 | codec << "["; |
325 | mMediaHeight = 64; | 179 | codec << sLLMediaImplQuickTimeReg.getImplName(); |
326 | mTextureWidth = 64; | 180 | codec << "] - "; |
327 | mTextureHeight = 64; | 181 | codec << "QuickTime: " << std::hex << version; |
328 | 182 | ||
329 | setBuffer ( NULL ); | 183 | return codec.str(); |
330 | |||
331 | memset(mediaData, 0, mMediaRowbytes * mMediaHeight ); | ||
332 | } | 184 | } |
333 | 185 | ||
334 | /////////////////////////////////////////////////////////////////////////////// | 186 | //////////////////////////////////////////////////////////////////////////////// |
335 | // | 187 | // virtual |
336 | BOOL | 188 | bool LLMediaImplQuickTime::navigateTo( const std::string url ) |
337 | LLMediaImplQuickTime:: | ||
338 | load ( const LLString& urlIn ) | ||
339 | { | 189 | { |
340 | // The movie may do things to the current port when it's created. Make sure we have a valid port set. | 190 | // tell engine what we're doing |
341 | setupDummyBuffer(); | 191 | setStatus( LLMediaBase::STATUS_NAVIGATING ); |
342 | SetGWorld(theGWorld, NULL); | ||
343 | |||
344 | Size mySize = ( Size ) urlIn.length () + 1; | ||
345 | if ( mySize == 0 ) | ||
346 | return FALSE; | ||
347 | |||
348 | Handle myHandle = NewHandleClear ( mySize ); | ||
349 | if ( myHandle == NULL ) | ||
350 | return FALSE; | ||
351 | |||
352 | BlockMove ( urlIn.c_str (), *myHandle, mySize ); | ||
353 | |||
354 | // Might be able to make this asynchronous with (newMovieActive|newMovieAsyncOK|newMovieIdleImportOK)? | ||
355 | OSErr err = NewMovieFromDataRef ( &theMovie, newMovieActive|newMovieDontInteractWithUser|newMovieAsyncOK|newMovieIdleImportOK, NULL, myHandle, URLDataHandlerSubType ); | ||
356 | |||
357 | if ( err != noErr ) | ||
358 | return false; | ||
359 | 192 | ||
360 | // function that gets called when a frame is drawn | 193 | // remove the movie we were looking at |
361 | SetMovieDrawingCompleteProc ( theMovie, movieDrawingCallWhenChanged, myFrameDrawnCallback, ( long ) this ); | 194 | unload(); |
362 | 195 | ||
363 | if(isQTLoaded()) | 196 | // load the new one (no real 'go to this url' function in QT) |
364 | { | 197 | load( url ); |
365 | updateMediaSize(); | 198 | |
366 | setBuffer(NULL); | 199 | return true; |
367 | } | ||
368 | |||
369 | // Tell the controller to play the movie. This also deals with the movie still loading. | ||
370 | //play(); | ||
371 | |||
372 | return LLMediaMovieBase::load(urlIn); | ||
373 | } | 200 | } |
374 | 201 | ||
375 | /////////////////////////////////////////////////////////////////////////////// | 202 | //////////////////////////////////////////////////////////////////////////////// |
376 | // | 203 | // virtual |
377 | OSErr | 204 | bool LLMediaImplQuickTime::sizeChanged() |
378 | LLMediaImplQuickTime:: | ||
379 | myFrameDrawnCallback ( Movie callbackMovie, long refCon ) | ||
380 | { | 205 | { |
381 | LLMediaImplQuickTime* myQtRenderer = ( LLMediaImplQuickTime* ) refCon; | 206 | if ( ! mMovieHandle ) |
382 | 207 | return false; | |
383 | // The gworld quicktime is playing back into is now wrapped around myQtRenderer->mediaData, | ||
384 | // so there's no need to copy any data here. | ||
385 | #if 0 | ||
386 | Ptr pixels = GetPixBaseAddr ( myQtRenderer->pixmapHandle ); | ||
387 | 208 | ||
388 | LockPixels ( myQtRenderer->pixmapHandle ); | 209 | // sanitize size of movie |
210 | Rect movie_rect; | ||
211 | setMovieBoxEnhanced( &movie_rect ); | ||
389 | 212 | ||
390 | memcpy ( ( U8* ) myQtRenderer->mediaData, pixels, myQtRenderer->getMediaBufferSize () ); /* Flawfinder: ignore */ | 213 | // we need this later |
214 | int width = ( movie_rect.right - movie_rect.left ); | ||
215 | int height = ( movie_rect.bottom - movie_rect.top ); | ||
391 | 216 | ||
392 | UnlockPixels ( myQtRenderer->pixmapHandle ); | 217 | std::cout << "LLMEDIA> size changed to " << width << " x " << height << std::endl; |
393 | #endif | 218 | |
219 | setMediaSize( width, height ); | ||
220 | |||
221 | // media depth won't change | ||
222 | int depth_bits = getMediaDepth() * 8; | ||
394 | 223 | ||
395 | myQtRenderer->bufferChanged(); | 224 | GWorldPtr old_gworld_handle = mGWorldHandle; |
396 | 225 | ||
397 | return 0; | 226 | if (old_gworld_handle) |
227 | { | ||
228 | GWorldFlags result = UpdateGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, 0 ); | ||
229 | if ( gwFlagErr == result ) | ||
230 | { | ||
231 | // TODO: unrecoverable?? throw exception? return something? | ||
232 | return false; | ||
233 | } | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, keepLocal | pixelsLocked ); | ||
238 | if ( noErr != result ) | ||
239 | { | ||
240 | // ATODO: unrecoverable?? throw exception? return something? | ||
241 | return false; | ||
242 | } | ||
243 | |||
244 | // clear memory in GWorld to avoid random screen visual fuzz from uninitialized texture data | ||
245 | if ( mGWorldHandle ) | ||
246 | { | ||
247 | PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); | ||
248 | unsigned char* ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle ); | ||
249 | memset( ptr, 0x00, height * QTGetPixMapHandleRowBytes( pix_map_handle ) ); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | // point movie at GWorld if it's new | ||
254 | if ( mMovieHandle && ! old_gworld_handle ) | ||
255 | { | ||
256 | SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice ( mGWorldHandle ) ); | ||
257 | } | ||
258 | |||
259 | // flip movie to match the way the client expects textures (sigh!) | ||
260 | MatrixRecord transform; | ||
261 | SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix | ||
262 | double scaleX = 1.0 / (double)LLMediaManager::textureWidthFromMediaWidth( width ); | ||
263 | double scaleY = -1.0 / (double)LLMediaManager::textureHeightFromMediaHeight( height ); | ||
264 | double centerX = width / 2.0; | ||
265 | double centerY = height / 2.0; | ||
266 | ScaleMatrix( &transform, X2Fix ( scaleX ), X2Fix ( scaleY ), X2Fix ( centerX ), X2Fix ( centerY ) ); | ||
267 | SetMovieMatrix( mMovieHandle, &transform ); | ||
268 | std::cout << "LLMEDIA> Flipping stream to match expected OpenGL orientation size=" << width << " x " << height << std::endl; | ||
269 | |||
270 | // update movie controller | ||
271 | if ( mMovieController ) | ||
272 | { | ||
273 | MCSetControllerPort( mMovieController, mGWorldHandle ); | ||
274 | MCPositionController( mMovieController, &movie_rect, &movie_rect, | ||
275 | mcTopLeftMovie | mcPositionDontInvalidate ); | ||
276 | MCMovieChanged( mMovieController, mMovieHandle ); | ||
277 | } | ||
278 | |||
279 | // Emit event with size change so the calling app knows about it too | ||
280 | LLMediaEvent event( this ); | ||
281 | mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); | ||
282 | |||
283 | return true; | ||
398 | } | 284 | } |
399 | 285 | ||
400 | /////////////////////////////////////////////////////////////////////////////// | 286 | //////////////////////////////////////////////////////////////////////////////// |
401 | Boolean | 287 | // static |
402 | LLMediaImplQuickTime::myMCActionFilterProc (MovieController theMC, short theAction, void *theParams, long theRefCon) | 288 | Boolean LLMediaImplQuickTime::mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) |
403 | { | 289 | { |
404 | Boolean result = false; | 290 | Boolean result = false; |
405 | LLMediaImplQuickTime *self = (LLMediaImplQuickTime*)theRefCon; | ||
406 | 291 | ||
407 | switch ( theAction ) | 292 | LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; |
293 | |||
294 | switch( action ) | ||
408 | { | 295 | { |
409 | // handle window resizing | 296 | // handle window resizing |
410 | case mcActionControllerSizeChanged: | 297 | case mcActionControllerSizeChanged: |
@@ -423,502 +310,336 @@ LLMediaImplQuickTime::myMCActionFilterProc (MovieController theMC, short theActi | |||
423 | break; | 310 | break; |
424 | }; | 311 | }; |
425 | 312 | ||
426 | return ( result ); | 313 | return result; |
427 | } | 314 | } |
428 | 315 | ||
429 | /////////////////////////////////////////////////////////////////////////////// | 316 | //////////////////////////////////////////////////////////////////////////////// |
430 | // | 317 | // private |
431 | void | 318 | bool LLMediaImplQuickTime::unload() |
432 | LLMediaImplQuickTime::rewind() | ||
433 | { | 319 | { |
434 | // MBW -- XXX -- I don't see an easy way to do this via the movie controller. | 320 | if ( mMovieHandle ) |
435 | GoToBeginningOfMovie ( theMovie ); | 321 | { |
436 | 322 | StopMovie( mMovieHandle ); | |
437 | // Call this afterwards so the movie controller can sync itself with the movie. | 323 | if ( mMovieController ) |
438 | MCMovieChanged(theController, theMovie); | 324 | { |
439 | 325 | MCMovieChanged( mMovieController, mMovieHandle ); | |
440 | #if 0 | 326 | }; |
441 | // Maybe something like this? | 327 | }; |
442 | TimeRecord when; | 328 | |
443 | when.value.hi = 0; | 329 | if ( mMovieController ) |
444 | when.value.lo = 0; | 330 | { |
445 | when.scale = GetMovieTimeScale(theMovie); | 331 | MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); |
446 | 332 | DisposeMovieController( mMovieController ); | |
447 | // This seems like the obvious thing, but a tech note (http://developer.apple.com/technotes/qt/qt_510.html) says otherwise... | 333 | mMovieController = NULL; |
448 | // when.base = GetMovieTimeBase(theMovie); | 334 | }; |
449 | when.base = 0; | 335 | |
450 | 336 | if ( mMovieHandle ) | |
451 | MCDoAction(theController, mcActionGoToTime, &when); | 337 | { |
452 | #endif | 338 | SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); |
339 | DisposeMovie ( mMovieHandle ); | ||
340 | mMovieHandle = NULL; | ||
341 | }; | ||
342 | |||
343 | if ( mGWorldHandle ) | ||
344 | { | ||
345 | DisposeGWorld( mGWorldHandle ); | ||
346 | mGWorldHandle = NULL; | ||
347 | }; | ||
348 | |||
349 | return true; | ||
453 | } | 350 | } |
454 | 351 | ||
455 | /////////////////////////////////////////////////////////////////////////////// | 352 | //////////////////////////////////////////////////////////////////////////////// |
456 | // | 353 | // static |
457 | void | 354 | OSErr LLMediaImplQuickTime::movieDrawingCompleteCallback( Movie call_back_movie, long ref ) |
458 | LLMediaImplQuickTime::sizeChanged() | ||
459 | { | 355 | { |
460 | // Set the movie to render (well, actually NOT render) to an internal buffer until the size change can be handled. | 356 | LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; |
461 | setupDummyBuffer(); | 357 | |
462 | 358 | // IMPORTANT: typically, a consumer who is observing this event will set a flag | |
463 | // Make the next call to updateMedia request a size change. | 359 | // when this event is fired then render later. Be aware that the media stream |
464 | sizeChangeInProgress = true; | 360 | // can change during this period - dimensions, depth, format etc. |
465 | 361 | LLMediaEvent event( self ); | |
466 | // Recalculate the values that depend on the movie rect. | 362 | self->mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); |
467 | updateMediaSize(); | 363 | |
364 | return noErr; | ||
468 | } | 365 | } |
469 | 366 | ||
470 | /////////////////////////////////////////////////////////////////////////////// | 367 | //////////////////////////////////////////////////////////////////////////////// |
471 | // | 368 | // static |
472 | BOOL | 369 | void LLMediaImplQuickTime::moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) |
473 | LLMediaImplQuickTime:: | ||
474 | isQTLoaded() | ||
475 | { | 370 | { |
476 | BOOL result = false; | 371 | LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; |
477 | 372 | ||
478 | if(theMovie) | 373 | LLMediaEvent event( self ); |
479 | { | 374 | self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); |
480 | if(GetMovieLoadState(theMovie) >= kMovieLoadStateLoaded) | ||
481 | { | ||
482 | result = true; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | return result; | ||
487 | } | 375 | } |
488 | 376 | ||
489 | /////////////////////////////////////////////////////////////////////////////// | 377 | /////////////////////////////////////////////////////////////////////////////// |
490 | // | 378 | // used for stop / loop |
491 | BOOL | 379 | void LLMediaImplQuickTime::rewind() |
492 | LLMediaImplQuickTime:: | ||
493 | isQTPlaythroughOK() | ||
494 | { | 380 | { |
495 | BOOL result = false; | 381 | GoToBeginningOfMovie ( mMovieHandle ); |
496 | 382 | ||
497 | if(theMovie) | 383 | MCMovieChanged( mMovieController, mMovieHandle ); |
498 | { | ||
499 | if(GetMovieLoadState(theMovie) >= kMovieLoadStatePlaythroughOK) | ||
500 | { | ||
501 | result = true; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | return result; | ||
506 | } | 384 | } |
507 | 385 | ||
508 | /////////////////////////////////////////////////////////////////////////////// | 386 | //////////////////////////////////////////////////////////////////////////////// |
509 | // | 387 | // |
510 | BOOL | 388 | bool LLMediaImplQuickTime::processState() |
511 | LLMediaImplQuickTime:: | ||
512 | unload () | ||
513 | { | 389 | { |
514 | 390 | // start stream | |
515 | if( theController ) | 391 | if ( nextCommand() == LLMediaBase::COMMAND_START ) |
516 | { | 392 | { |
517 | // Slight paranoia... | 393 | // valid when we are in these states |
518 | MCSetActionFilterWithRefCon(theController, NULL, (long)this); | 394 | if ( getStatus() == LLMediaBase::STATUS_NAVIGATING|| getStatus() == LLMediaBase::STATUS_STOPPED || getStatus() == LLMediaBase::STATUS_PAUSED ) |
395 | { | ||
396 | // it appears that the movie must be in a loaded state before we do this command | ||
397 | if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) | ||
398 | { | ||
399 | MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) ); | ||
519 | 400 | ||
520 | DisposeMovieController( theController ); | 401 | MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); |
521 | theController = NULL; | ||
522 | }; | ||
523 | |||
524 | if ( theMovie ) | ||
525 | { | ||
526 | // Slight paranoia... | ||
527 | SetMovieDrawingCompleteProc ( theMovie, movieDrawingCallWhenChanged, nil, ( long ) this ); | ||
528 | 402 | ||
529 | DisposeMovie ( theMovie ); | 403 | setStatus( LLMediaBase::STATUS_STARTED ); |
530 | theMovie = NULL; | ||
531 | }; | ||
532 | 404 | ||
533 | if ( theGWorld ) | 405 | clearCommand(); |
534 | { | 406 | } |
535 | DisposeGWorld ( theGWorld ); | 407 | } |
536 | theGWorld = NULL; | 408 | } |
537 | }; | 409 | else |
538 | 410 | if ( nextCommand() == LLMediaBase::COMMAND_STOP ) | |
539 | if ( mediaData ) | ||
540 | { | 411 | { |
541 | if ( ownBuffer ) | 412 | // valid when we are in these states |
413 | if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_PAUSED ) | ||
542 | { | 414 | { |
543 | delete mediaData; | 415 | // it appears that the movie must be in a loaded state before we do this command |
544 | mediaData = NULL; | 416 | if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) |
545 | }; | 417 | { |
546 | }; | 418 | // stop playing |
419 | Fixed rate = X2Fix( 0.0 ); | ||
420 | MCDoAction( mMovieController, mcActionPlay, (void*)rate ); | ||
547 | 421 | ||
548 | return TRUE; | 422 | // go back to start |
549 | } | 423 | rewind(); |
550 | 424 | ||
551 | /////////////////////////////////////////////////////////////////////////////// | 425 | setStatus( LLMediaBase::STATUS_STOPPED ); |
552 | // | 426 | clearCommand(); |
553 | S32 | 427 | }; |
554 | LLMediaImplQuickTime:: | 428 | }; |
555 | updateMedia () | ||
556 | { | ||
557 | if(!theController) | ||
558 | { | ||
559 | if(isQTLoaded()) | ||
560 | { | ||
561 | // Movie has finished loading. Request a size change to update buffers, etc. | ||
562 | // We MUST update the media size here, so it will be correct before the size change request. | ||
563 | updateMediaSize(); | ||
564 | return updateMediaNeedsSizeChange; | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | // Movie is still loading. | ||
569 | MoviesTask ( theMovie, 0 ); | ||
570 | } | ||
571 | } | 429 | } |
572 | 430 | else | |
573 | if(theController) | 431 | if ( nextCommand() == LLMediaBase::COMMAND_PAUSE ) |
574 | { | 432 | { |
575 | switch(currentMode) | 433 | // valid when we are in these states |
434 | if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_STOPPED ) | ||
576 | { | 435 | { |
577 | case ModePlaying: | 436 | // it appears that the movie must be in a loaded state before we do this command |
578 | case ModeLooping: | 437 | if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) |
579 | if(!initialStartDone) | ||
580 | { | 438 | { |
581 | if(isQTPlaythroughOK()) | 439 | // stop playing |
582 | { | 440 | Fixed rate = X2Fix( 0.0 ); |
583 | // The movie is loaded enough to start playing. Start it now. | 441 | MCDoAction( mMovieController, mcActionPlay, (void*)rate ); |
584 | MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie)); | ||
585 | 442 | ||
586 | MCDoAction(theController, mcActionSetVolume, (void*)curVolume ); | 443 | setStatus( LLMediaBase::STATUS_PAUSED ); |
444 | clearCommand(); | ||
445 | }; | ||
446 | }; | ||
447 | }; | ||
587 | 448 | ||
588 | initialStartDone = TRUE; | 449 | return true; |
589 | } | 450 | } |
590 | } | 451 | |
591 | break; | 452 | //////////////////////////////////////////////////////////////////////////////// |
592 | } | 453 | // virtual |
454 | bool LLMediaImplQuickTime::setMovieBoxEnhanced( Rect* rect ) | ||
455 | { | ||
456 | // get movie rect | ||
457 | GetMovieBox( mMovieHandle, rect ); | ||
458 | int width = ( rect->right - rect->left ); | ||
459 | int height = ( rect->bottom - rect->top ); | ||
593 | 460 | ||
594 | // // This function may copy decompressed movie frames into our media data pointer. JC | 461 | // if the user has requested a specific size, use it: |
595 | // if (!mediaData) | 462 | if ((mMediaRequestedWidth != 0) && (mMediaRequestedHeight != 0)) |
596 | // { | 463 | { |
597 | // llwarns << "LLMediaImplQuickTime::updateMedia() about to update with null media pointer" << llendl; | 464 | width = mMediaRequestedWidth; |
598 | // } | 465 | height = mMediaRequestedHeight; |
599 | // else | ||
600 | // { | ||
601 | // // try writing to the pointer to see if it's valid | ||
602 | // *mediaData = 0; | ||
603 | // } | ||
604 | |||
605 | MCIdle(theController); | ||
606 | } | 466 | } |
607 | 467 | ||
608 | // If we need a size change, that takes precedence. | 468 | // if the user has requested, resize media to exactly fit texture |
609 | if(sizeChangeInProgress) | 469 | if (mAutoScaled) |
610 | { | 470 | { |
611 | return updateMediaNeedsSizeChange; | 471 | width = LLMediaManager::textureWidthFromMediaWidth( width ); |
472 | height = LLMediaManager::textureHeightFromMediaHeight( height ); | ||
612 | } | 473 | } |
613 | 474 | ||
614 | BOOL updated = getBufferChanged(); | 475 | // make sure it falls in valid range |
476 | if ( width < mMinWidth ) | ||
477 | width = mMinWidth; | ||
615 | 478 | ||
616 | resetBufferChanged(); | 479 | if ( width > mMaxWidth ) |
617 | 480 | width = mMaxWidth; | |
618 | if(updated) | ||
619 | return updateMediaNeedsUpdate; | ||
620 | 481 | ||
621 | // don't use movie controller for looping - appears to be broken on PCs (volume issue) | 482 | if ( height < mMinHeight ) |
622 | if ( currentMode == ModeLooping ) | 483 | height = mMinHeight; |
623 | if ( IsMovieDone ( theMovie ) ) | ||
624 | loop ( 0 ); | ||
625 | 484 | ||
626 | return updateMediaNoChanges; | 485 | if ( height > mMaxHeight ) |
627 | } | 486 | height = mMaxHeight; |
628 | 487 | ||
629 | /////////////////////////////////////////////////////////////////////////////// | 488 | // tell quicktime about new size |
630 | // | 489 | rect->right = width; |
631 | void | 490 | rect->bottom = height; |
632 | LLMediaImplQuickTime:: | 491 | rect->left = 0; |
633 | setAutoScaled ( BOOL autoScaledIn ) | 492 | rect->top = 0; |
634 | { | 493 | SetMovieBox( mMovieHandle, rect ); |
635 | autoScaled = autoScaledIn; | 494 | |
495 | return true; | ||
636 | } | 496 | } |
637 | 497 | ||
638 | /////////////////////////////////////////////////////////////////////////////// | 498 | //////////////////////////////////////////////////////////////////////////////// |
639 | // | 499 | // virtual |
640 | BOOL | 500 | bool LLMediaImplQuickTime::updateMedia() |
641 | LLMediaImplQuickTime:: | ||
642 | stop () | ||
643 | { | 501 | { |
644 | currentMode = ModeStopped; | 502 | if ( ! mMovieHandle ) |
503 | return false; | ||
645 | 504 | ||
646 | if(theController) | 505 | if ( ! mMovieController ) |
647 | { | 506 | return false; |
648 | Fixed rate = X2Fix(0.0); | ||
649 | MCDoAction(theController, mcActionPlay, (void*)rate); | ||
650 | |||
651 | rewind(); | ||
652 | } | ||
653 | |||
654 | return LLMediaMovieBase::stop(); | ||
655 | }; | ||
656 | 507 | ||
657 | /////////////////////////////////////////////////////////////////////////////// | 508 | if ( ! mGWorldHandle ) |
658 | // | 509 | return false; |
659 | BOOL | ||
660 | LLMediaImplQuickTime:: | ||
661 | play () | ||
662 | { | ||
663 | currentMode = ModePlaying; | ||
664 | |||
665 | if(theController) | ||
666 | { | ||
667 | if ( IsMovieDone ( theMovie ) ) | ||
668 | { | ||
669 | rewind(); | ||
670 | }; | ||
671 | 510 | ||
672 | MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie)); | 511 | // service QuickTime |
512 | MoviesTask( mMovieHandle, 0 ); | ||
513 | MCIdle( mMovieController ); | ||
673 | 514 | ||
674 | MCDoAction(theController, mcActionSetVolume, (void*)curVolume ); | 515 | // update state machine (deals with transport controls for example) |
675 | } | 516 | processState(); |
676 | |||
677 | return LLMediaMovieBase::play(); | ||
678 | }; | ||
679 | 517 | ||
680 | /////////////////////////////////////////////////////////////////////////////// | 518 | // special code for looping - need to rewind at the end of the movie |
681 | // | ||
682 | BOOL | ||
683 | LLMediaImplQuickTime:: | ||
684 | loop ( S32 howMany ) | ||
685 | { | ||
686 | currentMode = ModeLooping; | ||
687 | |||
688 | // MBW -- XXX -- This may be harder to do with a movie controller... | ||
689 | // loopsLeft = howMany; | ||
690 | 519 | ||
691 | if ( theController ) | 520 | if ( isLooping() ) |
692 | { | 521 | { |
693 | // Movie is loaded and set up. | 522 | // QT call to see if we are at the end - can't do with controller |
694 | if ( IsMovieDone ( theMovie ) ) | 523 | if ( IsMovieDone( mMovieHandle ) ) |
695 | { | 524 | { |
525 | // go back to start | ||
696 | rewind(); | 526 | rewind(); |
697 | }; | ||
698 | |||
699 | MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie)); | ||
700 | |||
701 | MCDoAction(theController, mcActionSetVolume, (void*)curVolume ); | ||
702 | } | ||
703 | |||
704 | return LLMediaMovieBase::loop(howMany); | ||
705 | }; | ||
706 | |||
707 | /////////////////////////////////////////////////////////////////////////////// | ||
708 | // | ||
709 | BOOL | ||
710 | LLMediaImplQuickTime:: | ||
711 | pause () | ||
712 | { | ||
713 | currentMode = ModePaused; | ||
714 | |||
715 | if(theController) | ||
716 | { | ||
717 | // Movie is loaded and set up. | ||
718 | Fixed rate = X2Fix(0.0); | ||
719 | MCDoAction(theController, mcActionPlay, (void*)rate); | ||
720 | } | ||
721 | 527 | ||
722 | return LLMediaMovieBase::pause(); | 528 | // kick off new play |
723 | }; | 529 | MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) ); |
724 | 530 | ||
725 | /////////////////////////////////////////////////////////////////////////////// | 531 | // set the volume |
726 | // | 532 | MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); |
727 | BOOL | 533 | } |
728 | LLMediaImplQuickTime:: | ||
729 | setVolume ( F32 volumeIn ) | ||
730 | { | ||
731 | // Fixed point signed short, 8.8 | ||
732 | curVolume = (short)(volumeIn * ( F32 ) 0x100); | ||
733 | |||
734 | if(theController != NULL) | ||
735 | { | ||
736 | MCDoAction(theController, mcActionSetVolume, (void*)curVolume); | ||
737 | } | 534 | } |
738 | |||
739 | return TRUE; | ||
740 | } | ||
741 | 535 | ||
742 | /////////////////////////////////////////////////////////////////////////////// | 536 | return true; |
743 | // | ||
744 | F32 | ||
745 | LLMediaImplQuickTime:: | ||
746 | getVolume () | ||
747 | { | ||
748 | return ( ( F32 ) curVolume ) / ( F32 ) 0x100; | ||
749 | } | 537 | } |
750 | 538 | ||
751 | /////////////////////////////////////////////////////////////////////////////// | 539 | //////////////////////////////////////////////////////////////////////////////// |
752 | // | 540 | // virtual |
753 | BOOL | 541 | unsigned char* LLMediaImplQuickTime::getMediaData() |
754 | LLMediaImplQuickTime:: | ||
755 | isIdle () const | ||
756 | { | 542 | { |
757 | return ( currentMode == ModeIdle ); | 543 | unsigned char* ptr = NULL; |
758 | }; | ||
759 | 544 | ||
760 | /////////////////////////////////////////////////////////////////////////////// | 545 | if ( mGWorldHandle ) |
761 | // | 546 | { |
762 | BOOL | 547 | PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); |
763 | LLMediaImplQuickTime:: | ||
764 | isError () const | ||
765 | { | ||
766 | return ( currentMode == ModeError ); | ||
767 | }; | ||
768 | 548 | ||
769 | /////////////////////////////////////////////////////////////////////////////// | 549 | ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle ); |
770 | // | 550 | }; |
771 | BOOL | ||
772 | LLMediaImplQuickTime:: | ||
773 | isBuffering () const | ||
774 | { | ||
775 | return ( currentMode == ModeBuffering ); | ||
776 | }; | ||
777 | 551 | ||
778 | /////////////////////////////////////////////////////////////////////////////// | 552 | return ptr; |
779 | // | 553 | } |
780 | BOOL | ||
781 | LLMediaImplQuickTime:: | ||
782 | isLoaded () const | ||
783 | { | ||
784 | // Only tell the caller the movie is loaded if we've had a chance to set up the movie controller. | ||
785 | |||
786 | return (theController != NULL); | ||
787 | }; | ||
788 | 554 | ||
789 | /////////////////////////////////////////////////////////////////////////////// | 555 | //////////////////////////////////////////////////////////////////////////////// |
790 | // | 556 | // virtual |
791 | BOOL | 557 | int LLMediaImplQuickTime::getMediaDataWidth() const |
792 | LLMediaImplQuickTime:: | ||
793 | isPlaying () const | ||
794 | { | 558 | { |
795 | return ( currentMode == ModePlaying ); | 559 | if ( mGWorldHandle ) |
796 | }; | 560 | { |
561 | int depth = getMediaDepth(); | ||
797 | 562 | ||
798 | /////////////////////////////////////////////////////////////////////////////// | 563 | if (depth < 1) |
799 | // | 564 | depth = 1; |
800 | BOOL | ||
801 | LLMediaImplQuickTime:: | ||
802 | isLooping () const | ||
803 | { | ||
804 | return ( currentMode == ModeLooping ); | ||
805 | }; | ||
806 | 565 | ||
807 | /////////////////////////////////////////////////////////////////////////////// | 566 | // ALWAYS use the row bytes from the PixMap if we have a GWorld because |
808 | // | 567 | // sometimes it's not the same as mMediaDepth * mMediaWidth ! |
809 | BOOL | 568 | PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); |
810 | LLMediaImplQuickTime:: | 569 | return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; |
811 | isPaused () const | 570 | } |
812 | { | 571 | else |
813 | return ( currentMode == ModePaused ); | 572 | { |
814 | }; | 573 | return LLMediaImplCommon::getMediaDataWidth(); |
574 | } | ||
575 | } | ||
815 | 576 | ||
816 | /////////////////////////////////////////////////////////////////////////////// | 577 | //////////////////////////////////////////////////////////////////////////////// |
817 | // | 578 | // virtual |
818 | BOOL | 579 | int LLMediaImplQuickTime::getTextureFormatPrimary() const |
819 | LLMediaImplQuickTime:: | ||
820 | isStopped () const | ||
821 | { | 580 | { |
822 | return ( currentMode == ModeStopped ); | 581 | #if defined(__APPLE__) || defined(MACOSX) |
823 | }; | 582 | return LL_MEDIA_BGRA; |
583 | #else | ||
584 | return LL_MEDIA_RGB; | ||
585 | #endif | ||
586 | } | ||
824 | 587 | ||
825 | /////////////////////////////////////////////////////////////////////////////// | 588 | //////////////////////////////////////////////////////////////////////////////// |
826 | // | 589 | // virtual |
827 | U8* | 590 | int LLMediaImplQuickTime::getTextureFormatType() const |
828 | LLMediaImplQuickTime:: | ||
829 | getMediaData () | ||
830 | { | 591 | { |
831 | return mediaData; | 592 | #if defined(__APPLE__) || defined(MACOSX) |
593 | #ifdef __BIG_ENDIAN__ | ||
594 | return LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; | ||
595 | #else | ||
596 | return LL_MEDIA_UNSIGNED_INT_8_8_8_8; | ||
597 | #endif | ||
598 | #else | ||
599 | return LL_MEDIA_UNSIGNED_BYTE; | ||
600 | #endif | ||
832 | } | 601 | } |
833 | 602 | ||
834 | /////////////////////////////////////////////////////////////////////////////// | 603 | //////////////////////////////////////////////////////////////////////////////// |
835 | // | 604 | // virtual |
836 | BOOL | 605 | bool LLMediaImplQuickTime::seek( double time ) |
837 | LLMediaImplQuickTime:: | ||
838 | seek ( F64 time ) | ||
839 | { | 606 | { |
840 | // MBW -- XXX -- This should stash the time if theController is NULL, and seek to there when the movie's loaded. | 607 | if ( mMovieController ) |
841 | // Do this later. | ||
842 | if(theController != NULL) | ||
843 | { | 608 | { |
844 | TimeRecord when; | 609 | TimeRecord when; |
845 | when.scale = GetMovieTimeScale(theMovie); | 610 | when.scale = GetMovieTimeScale( mMovieHandle ); |
846 | when.base = 0; | 611 | when.base = 0; |
847 | 612 | ||
848 | // 'time' is in (floating point) seconds. The timebase time will be in 'units', where | 613 | // 'time' is in (floating point) seconds. The timebase time will be in 'units', where |
849 | // there are 'scale' units per second. | 614 | // there are 'scale' units per second. |
850 | S64 rawTime = (S64)(time * (F64)(when.scale)); | 615 | SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); |
851 | |||
852 | when.value.hi = ( SInt32 ) ( rawTime >> 32 ); | ||
853 | when.value.lo = ( SInt32 ) ( ( rawTime & 0x00000000FFFFFFFF ) ); | ||
854 | |||
855 | MCDoAction(theController, mcActionGoToTime, &when); | ||
856 | } | ||
857 | |||
858 | return TRUE; | ||
859 | } | ||
860 | 616 | ||
861 | /////////////////////////////////////////////////////////////////////////////// | 617 | when.value.hi = ( SInt32 )( raw_time >> 32 ); |
862 | // | 618 | when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); |
863 | F64 | ||
864 | LLMediaImplQuickTime:: | ||
865 | getTime () const | ||
866 | { | ||
867 | F64 result = 0; | ||
868 | |||
869 | if(theController != NULL) | ||
870 | { | ||
871 | TimeValue time; | ||
872 | TimeScale scale = 0; | ||
873 | 619 | ||
874 | time = MCGetCurrentTime(theController, &scale); | 620 | MCDoAction( mMovieController, mcActionGoToTime, &when ); |
875 | if(scale != 0) | 621 | |
876 | { | 622 | return true; |
877 | result = ((F64)time) / ((F64)scale); | ||
878 | } | ||
879 | } | 623 | } |
880 | 624 | ||
881 | return result; | 625 | return false; |
882 | } | 626 | } |
883 | 627 | ||
884 | /////////////////////////////////////////////////////////////////////////////// | 628 | //////////////////////////////////////////////////////////////////////////////// |
885 | // | 629 | // virtual |
886 | F64 | 630 | bool LLMediaImplQuickTime::setVolume( float volume ) |
887 | LLMediaImplQuickTime:: | ||
888 | getMediaDuration () const | ||
889 | { | 631 | { |
890 | F64 result = 0; | 632 | mCurVolume = (short)(volume * ( double ) 0x100 ); |
891 | TimeScale scale = GetMovieTimeScale(theMovie); | 633 | |
892 | TimeValue duration = GetMovieDuration(theMovie); | 634 | if ( mMovieController ) |
893 | |||
894 | if(duration == kQTSUnknownDuration) | ||
895 | { | ||
896 | // Hmph. | ||
897 | // Return 0 in this case. | ||
898 | } | ||
899 | else if(duration == kQTSInfiniteDuration) | ||
900 | { | ||
901 | // This is the magic number for "indefinite duration", i.e. a live stream. | ||
902 | // Note that the docs claim this value is 0x7FFFFFF, while the symbolic constant is 0x7FFFFFFF. Go figure. | ||
903 | // Return 0 in this case. | ||
904 | } | ||
905 | else if(scale != 0) | ||
906 | { | 635 | { |
907 | // Timescale is a useful number. Convert to seconds. | 636 | MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); |
908 | result = (F64)duration; | ||
909 | result /= (F64)scale; | ||
910 | } | ||
911 | |||
912 | return result; | ||
913 | } | ||
914 | 637 | ||
915 | // static since we need this before an impl is created by media manager | 638 | return true; |
916 | S32 LLMediaImplQuickTime::getVersion() | 639 | } |
917 | { | ||
918 | S32 version; | ||
919 | Gestalt( gestaltQuickTimeVersion, (long*)&version ); | ||
920 | 640 | ||
921 | return version; | 641 | return false; |
922 | } | 642 | } |
923 | 643 | ||
924 | #endif | 644 | #endif // _3DNOW_InstructionExtensions/ LL_QUICKTIME_ENABLED |
645 | |||