aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmedia/llmediaimplquicktime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llmedia/llmediaimplquicktime.cpp')
-rw-r--r--linden/indra/llmedia/llmediaimplquicktime.cpp657
1 files changed, 0 insertions, 657 deletions
diff --git a/linden/indra/llmedia/llmediaimplquicktime.cpp b/linden/indra/llmedia/llmediaimplquicktime.cpp
deleted file mode 100644
index 76cacee..0000000
--- a/linden/indra/llmedia/llmediaimplquicktime.cpp
+++ /dev/null
@@ -1,657 +0,0 @@
1/**
2 * @file llmediaimplquicktime.cpp
3 * @brief QuickTime media impl concrete class
4 *
5 * $LicenseInfo:firstyear=2007&license=viewergpl$
6 *
7 * Copyright (c) 2007-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llmediaimplquicktime.h"
34
35#if LL_QUICKTIME_ENABLED
36
37#include "llmediamanager.h"
38#include "llmediaimplregister.h"
39
40#if LL_WINDOWS
41#include <windows.h>
42#endif
43
44#include <iostream>
45#include <sstream>
46
47// register this impl with media manager factory
48static LLMediaImplRegister sLLMediaImplQuickTimeReg( "LLMediaImplQuickTime", new LLMediaImplQuickTimeMaker() );
49
50///////////////////////////////////////////////////////////////////////////////
51//
52LLMediaImplQuickTimeMaker::LLMediaImplQuickTimeMaker()
53{
54 // Register to handle the scheme
55 mSchema.push_back( "rtsp" );
56
57 // Register to handle the category
58 mMimeTypeCategories.push_back( "video" );
59 mMimeTypeCategories.push_back( "audio" );
60 mMimeTypeCategories.push_back( "image" );
61}
62
63///////////////////////////////////////////////////////////////////////////////
64//
65LLMediaImplQuickTime::LLMediaImplQuickTime() :
66 mMovieHandle( 0 ),
67 mGWorldHandle( 0 ),
68 mMovieController( 0 ),
69 mMinWidth( 32 ),
70 mMaxWidth( 2048 ),
71 mMinHeight( 32 ),
72 mMaxHeight( 2048 ),
73 mCurVolume( 0 )
74{
75}
76
77///////////////////////////////////////////////////////////////////////////////
78//
79LLMediaImplQuickTime::~LLMediaImplQuickTime()
80{
81 unload();
82}
83
84////////////////////////////////////////////////////////////////////////////////
85// (static) super-initialization - called once at application startup
86bool LLMediaImplQuickTime::startup( LLMediaManagerData* init_data )
87{
88#ifdef WIN32
89 if ( InitializeQTML( 0L ) != noErr )
90 {
91 return false;
92 };
93#endif
94
95 EnterMovies();
96
97 return true;
98}
99
100////////////////////////////////////////////////////////////////////////////////
101// (static) super-uninitialization - called once at application closedown
102bool LLMediaImplQuickTime::closedown()
103{
104 ExitMovies();
105
106#ifdef WIN32
107 TerminateQTML();
108#endif
109
110 return true;
111}
112
113////////////////////////////////////////////////////////////////////////////////
114// private
115bool LLMediaImplQuickTime::load( const std::string url )
116{
117 if ( url.empty() )
118 return false;
119
120 //In case std::string::c_str() makes a copy of the url data,
121 //make sure there is memory to hold it before allocating memory for handle.
122 //if fails, NewHandleClear(...) should return NULL.
123 const char* url_string = url.c_str() ;
124 Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
125 if ( NULL == handle )
126 return false;
127 if(noErr != MemError() || NULL == *handle)
128 {
129 return false ;
130 }
131
132 BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) );
133
134 //std::cout << "LLMediaImplQuickTime::load( " << url << " )" << std::endl;
135
136 // TODO: supposed to use NewMovieFromDataParams now
137 OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
138 DisposeHandle( handle );
139 if ( noErr != err )
140 return false;
141
142 // do pre-roll actions (typically fired for streaming movies but not always)
143 PrePrerollMovie( mMovieHandle, 0, GetMoviePreferredRate( mMovieHandle ), moviePrePrerollCompleteCallback, ( void * )this );
144
145 // get movie rect (and check for min/max)
146 Rect movie_rect;
147 setMovieBoxEnhanced( &movie_rect );
148
149 // make a new movie controller
150 mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
151
152#if defined(__APPLE__) || defined(MACOSX)
153 setMediaDepth( 4 );
154#else
155 setMediaDepth( 3 );
156#endif
157
158 // tell manager about the media size
159 setMediaSize( movie_rect.right - movie_rect.left, movie_rect.bottom - movie_rect.top);
160
161 // movie controller
162 MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
163
164 SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
165
166 // function that gets called when a frame is drawn
167 SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
168
169 // emit an event to say that a media source was loaded
170 LLMediaEvent event( this );
171 mEventEmitter.update( &LLMediaObserver::onMediaLoaded, event );
172
173 // set up inital state
174 sizeChanged();
175
176 return true;
177}
178
179////////////////////////////////////////////////////////////////////////////////
180// virtual
181std::string LLMediaImplQuickTime::getVersion()
182{
183 long version;
184 Gestalt( gestaltQuickTimeVersion, &version );
185
186 std::ostringstream codec( "" );
187 codec << "[";
188 codec << sLLMediaImplQuickTimeReg.getImplName();
189 codec << "] - ";
190 codec << "QuickTime: " << std::hex << version;
191
192 return codec.str();
193}
194
195////////////////////////////////////////////////////////////////////////////////
196// virtual
197bool LLMediaImplQuickTime::navigateTo( const std::string url )
198{
199 // tell engine what we're doing
200 setStatus( LLMediaBase::STATUS_NAVIGATING );
201
202 // remove the movie we were looking at
203 unload();
204
205 // load the new one (no real 'go to this url' function in QT)
206 load( url );
207
208 return true;
209}
210
211////////////////////////////////////////////////////////////////////////////////
212// virtual
213bool LLMediaImplQuickTime::sizeChanged()
214{
215 if ( ! mMovieHandle )
216 return false;
217
218 // sanitize size of movie
219 Rect movie_rect;
220 setMovieBoxEnhanced( &movie_rect );
221
222 // we need this later
223 int width = ( movie_rect.right - movie_rect.left );
224 int height = ( movie_rect.bottom - movie_rect.top );
225
226 std::cout << "LLMEDIA> size changed to " << width << " x " << height << std::endl;
227
228 setMediaSize( width, height );
229
230 // media depth won't change
231 int depth_bits = getMediaDepth() * 8;
232
233 GWorldPtr old_gworld_handle = mGWorldHandle;
234
235 if (old_gworld_handle)
236 {
237 GWorldFlags result = UpdateGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, 0 );
238 if ( gwFlagErr == result )
239 {
240 // TODO: unrecoverable?? throw exception? return something?
241 return false;
242 }
243 }
244 else
245 {
246 OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, keepLocal | pixelsLocked );
247 if ( noErr != result )
248 {
249 // ATODO: unrecoverable?? throw exception? return something?
250 return false;
251 }
252
253 // clear memory in GWorld to avoid random screen visual fuzz from uninitialized texture data
254 if ( mGWorldHandle )
255 {
256 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
257 unsigned char* ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle );
258 memset( ptr, 0x00, height * QTGetPixMapHandleRowBytes( pix_map_handle ) );
259 }
260 }
261
262 // point movie at GWorld if it's new
263 if ( mMovieHandle && ! old_gworld_handle )
264 {
265 SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice ( mGWorldHandle ) );
266 }
267
268 // update movie controller
269 if ( mMovieController )
270 {
271 MCSetControllerPort( mMovieController, mGWorldHandle );
272 MCPositionController( mMovieController, &movie_rect, &movie_rect,
273 mcTopLeftMovie | mcPositionDontInvalidate );
274 MCMovieChanged( mMovieController, mMovieHandle );
275 }
276
277 // Emit event with size change so the calling app knows about it too
278 LLMediaEvent event( this );
279 mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
280
281 return true;
282}
283
284////////////////////////////////////////////////////////////////////////////////
285// static
286Boolean LLMediaImplQuickTime::mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
287{
288 Boolean result = false;
289
290 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
291
292 switch( action )
293 {
294 // handle window resizing
295 case mcActionControllerSizeChanged:
296 self->sizeChanged();
297 break;
298
299 // Block any movie controller actions that open URLs.
300 case mcActionLinkToURL:
301 case mcActionGetNextURL:
302 case mcActionLinkToURLExtended:
303 // Prevent the movie controller from handling the message
304 result = true;
305 break;
306
307 default:
308 break;
309 };
310
311 return result;
312}
313
314////////////////////////////////////////////////////////////////////////////////
315// private
316bool LLMediaImplQuickTime::unload()
317{
318 if ( mMovieHandle )
319 {
320 StopMovie( mMovieHandle );
321 if ( mMovieController )
322 {
323 MCMovieChanged( mMovieController, mMovieHandle );
324 };
325 };
326
327 if ( mMovieController )
328 {
329 MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
330 DisposeMovieController( mMovieController );
331 mMovieController = NULL;
332 };
333
334 if ( mMovieHandle )
335 {
336 SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
337 DisposeMovie ( mMovieHandle );
338 mMovieHandle = NULL;
339 };
340
341 if ( mGWorldHandle )
342 {
343 DisposeGWorld( mGWorldHandle );
344 mGWorldHandle = NULL;
345 };
346
347 return true;
348}
349
350////////////////////////////////////////////////////////////////////////////////
351// static
352OSErr LLMediaImplQuickTime::movieDrawingCompleteCallback( Movie call_back_movie, long ref )
353{
354 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
355
356 // IMPORTANT: typically, a consumer who is observing this event will set a flag
357 // when this event is fired then render later. Be aware that the media stream
358 // can change during this period - dimensions, depth, format etc.
359 LLMediaEvent event( self );
360 self->mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event );
361
362 return noErr;
363}
364
365////////////////////////////////////////////////////////////////////////////////
366// static
367void LLMediaImplQuickTime::moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
368{
369 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
370
371 LLMediaEvent event( self );
372 self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
373}
374
375///////////////////////////////////////////////////////////////////////////////
376// used for stop / loop
377void LLMediaImplQuickTime::rewind()
378{
379 GoToBeginningOfMovie ( mMovieHandle );
380
381 MCMovieChanged( mMovieController, mMovieHandle );
382}
383
384////////////////////////////////////////////////////////////////////////////////
385//
386bool LLMediaImplQuickTime::processState()
387{
388 // start stream
389 if ( nextCommand() == LLMediaBase::COMMAND_START )
390 {
391 // valid when we are in these states
392 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING|| getStatus() == LLMediaBase::STATUS_STOPPED || getStatus() == LLMediaBase::STATUS_PAUSED )
393 {
394 // it appears that the movie must be in a loaded state before we do this command
395 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
396 {
397 MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) );
398
399 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
400
401 setStatus( LLMediaBase::STATUS_STARTED );
402
403 clearCommand();
404 }
405 }
406 }
407 else
408 if ( nextCommand() == LLMediaBase::COMMAND_STOP )
409 {
410 // valid when we are in these states
411 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_PAUSED )
412 {
413 // it appears that the movie must be in a loaded state before we do this command
414 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
415 {
416 // stop playing
417 Fixed rate = X2Fix( 0.0 );
418 MCDoAction( mMovieController, mcActionPlay, (void*)rate );
419
420 // go back to start
421 rewind();
422
423 setStatus( LLMediaBase::STATUS_STOPPED );
424 clearCommand();
425 };
426 };
427 }
428 else
429 if ( nextCommand() == LLMediaBase::COMMAND_PAUSE )
430 {
431 // valid when we are in these states
432 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_STOPPED )
433 {
434 // it appears that the movie must be in a loaded state before we do this command
435 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
436 {
437 // stop playing
438 Fixed rate = X2Fix( 0.0 );
439 MCDoAction( mMovieController, mcActionPlay, (void*)rate );
440
441 setStatus( LLMediaBase::STATUS_PAUSED );
442 clearCommand();
443 };
444 };
445 };
446
447 return true;
448}
449
450////////////////////////////////////////////////////////////////////////////////
451// virtual
452bool LLMediaImplQuickTime::setMovieBoxEnhanced( Rect* rect )
453{
454 // get movie rect
455 GetMovieNaturalBoundsRect( mMovieHandle, rect );
456
457 int natural_width = ( rect->right - rect->left );
458 int natural_height = ( rect->bottom - rect->top );
459
460 int width = natural_width;
461 int height = natural_height;
462
463 // if the user has requested a specific size, use it:
464 if ((mMediaRequestedWidth != 0) && (mMediaRequestedHeight != 0))
465 {
466 width = mMediaRequestedWidth;
467 height = mMediaRequestedHeight;
468 }
469
470 // if the user has requested, resize media to exactly fit texture
471 if (mAutoScaled)
472 {
473 width = LLMediaManager::textureWidthFromMediaWidth( width );
474 height = LLMediaManager::textureHeightFromMediaHeight( height );
475 }
476
477 // make sure it falls in valid range
478 if ( width < mMinWidth )
479 width = mMinWidth;
480
481 if ( width > mMaxWidth )
482 width = mMaxWidth;
483
484 if ( height < mMinHeight )
485 height = mMinHeight;
486
487 if ( height > mMaxHeight )
488 height = mMaxHeight;
489
490
491 // scale movie to fit rect and invert vertically to match opengl image format
492 MatrixRecord transform;
493 SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix
494 double scaleX = (double) width / natural_width;
495 double scaleY = -1.0 * (double) height / natural_height;
496 double centerX = width / 2.0;
497 double centerY = height / 2.0;
498 ScaleMatrix( &transform, X2Fix ( scaleX ), X2Fix ( scaleY ), X2Fix ( centerX ), X2Fix ( centerY ) );
499 SetMovieMatrix( mMovieHandle, &transform );
500
501 // return the new rect
502 rect->right = width;
503 rect->bottom = height;
504 rect->left = 0;
505 rect->top = 0;
506
507 return true;
508}
509
510////////////////////////////////////////////////////////////////////////////////
511// virtual
512bool LLMediaImplQuickTime::updateMedia()
513{
514 if ( ! mMovieHandle )
515 return false;
516
517 if ( ! mMovieController )
518 return false;
519
520 if ( ! mGWorldHandle )
521 return false;
522
523 // service QuickTime
524 MoviesTask( mMovieHandle, 0 );
525 MCIdle( mMovieController );
526
527 // update state machine (deals with transport controls for example)
528 processState();
529
530 // special code for looping - need to rewind at the end of the movie
531
532 if ( isLooping() )
533 {
534 // QT call to see if we are at the end - can't do with controller
535 if ( IsMovieDone( mMovieHandle ) )
536 {
537 // go back to start
538 rewind();
539
540 // kick off new play
541 MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) );
542
543 // set the volume
544 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
545 }
546 }
547
548 return true;
549}
550
551////////////////////////////////////////////////////////////////////////////////
552// virtual
553unsigned char* LLMediaImplQuickTime::getMediaData()
554{
555 unsigned char* ptr = NULL;
556
557 if ( mGWorldHandle )
558 {
559 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
560
561 ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle );
562 };
563
564 return ptr;
565}
566
567////////////////////////////////////////////////////////////////////////////////
568// virtual
569int LLMediaImplQuickTime::getMediaDataWidth() const
570{
571 if ( mGWorldHandle )
572 {
573 int depth = getMediaDepth();
574
575 if (depth < 1)
576 depth = 1;
577
578 // ALWAYS use the row bytes from the PixMap if we have a GWorld because
579 // sometimes it's not the same as mMediaDepth * mMediaWidth !
580 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
581 return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
582 }
583 else
584 {
585 return LLMediaImplCommon::getMediaDataWidth();
586 }
587}
588
589////////////////////////////////////////////////////////////////////////////////
590// virtual
591int LLMediaImplQuickTime::getTextureFormatPrimary() const
592{
593#if defined(__APPLE__) || defined(MACOSX)
594 return LL_MEDIA_BGRA;
595#else
596 return LL_MEDIA_RGB;
597#endif
598}
599
600////////////////////////////////////////////////////////////////////////////////
601// virtual
602int LLMediaImplQuickTime::getTextureFormatType() const
603{
604#if defined(__APPLE__) || defined(MACOSX)
605 #ifdef __BIG_ENDIAN__
606 return LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV;
607 #else
608 return LL_MEDIA_UNSIGNED_INT_8_8_8_8;
609 #endif
610#else
611 return LL_MEDIA_UNSIGNED_BYTE;
612#endif
613}
614
615////////////////////////////////////////////////////////////////////////////////
616// virtual
617bool LLMediaImplQuickTime::seek( double time )
618{
619 if ( mMovieController )
620 {
621 TimeRecord when;
622 when.scale = GetMovieTimeScale( mMovieHandle );
623 when.base = 0;
624
625 // 'time' is in (floating point) seconds. The timebase time will be in 'units', where
626 // there are 'scale' units per second.
627 SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
628
629 when.value.hi = ( SInt32 )( raw_time >> 32 );
630 when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
631
632 MCDoAction( mMovieController, mcActionGoToTime, &when );
633
634 return true;
635 }
636
637 return false;
638}
639
640////////////////////////////////////////////////////////////////////////////////
641// virtual
642bool LLMediaImplQuickTime::setVolume( float volume )
643{
644 mCurVolume = (short)(volume * ( double ) 0x100 );
645
646 if ( mMovieController )
647 {
648 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
649
650 return true;
651 }
652
653 return false;
654}
655
656#endif // _3DNOW_InstructionExtensions/ LL_QUICKTIME_ENABLED
657