1/* 2 * MovieUtils.c -- 3 * 4 * Non-Tk Utility functions, part of QuickTimeTcl. 5 * 6 * Copyright (c) 2000-2003 Mats Bengtsson 7 * 8 * $Id: MovieUtils.c,v 1.2 2005/04/02 13:41:26 matben Exp $ 9 */ 10 11#include "MoviePlayer.h" 12 13 14/* 15 *---------------------------------------------------------------------- 16 * 17 * GetFirstVideoTrackInMovie -- 18 * 19 * Return, through the theTrack parameter, the first video track in 20 * the specified movie. Actually, we look for the first track that 21 * has the kCharacteristicCanSendVideo characteristic, so we can 22 * apply effects to MPEG or QD3D tracks as well. 23 * 24 * Results: 25 * OSErr: noErr if found track, returned in '*theTrack', 26 * or 'invalidTrack' if none. 27 * 28 * Side effects: 29 * None. 30 * 31 *---------------------------------------------------------------------- 32 */ 33 34OSErr 35GetFirstVideoTrackInMovie( Movie theMovie, Track *theTrack ) 36{ 37 *theTrack = GetMovieIndTrackType( theMovie, 1, kCharacteristicCanSendVideo, 38 movieTrackCharacteristic | movieTrackEnabledOnly ); 39 40 if (*theTrack == NULL) { 41 return(invalidTrack); 42 } 43 return(noErr); 44} 45 46/* 47 *---------------------------------------------------------------------- 48 * 49 * ShowControllerButton, HideControllerButton -- 50 * 51 * Shows or hides controller buttons. 52 * 53 * Results: 54 * None. 55 * 56 * Side effects: 57 * None. 58 * 59 *---------------------------------------------------------------------- 60 */ 61 62void 63ShowControllerButton( MovieController theMC, long theButton ) 64{ 65 long flags; 66 67 /* Handle the custom button separately. */ 68 if (theButton == mcFlagsUseCustomButton) { 69 MCDoAction( theMC, mcActionGetFlags, &flags ); 70 MCDoAction( theMC, mcActionSetFlags, 71 (void *)((flags | theButton))); 72 } else { 73 74 /* 75 * Get the current explicit flags and set the explicit flag for the 76 * specified button. 77 */ 78 79 flags = mcFlagQTVRExplicitFlagSet; 80 MCDoAction(theMC, mcActionGetFlags, &flags); 81 MCDoAction(theMC, mcActionSetFlags, 82 (void *)((flags | theButton) | mcFlagQTVRExplicitFlagSet)); 83 84 /* 85 * Get the current control flags and clear the suppress flag for the 86 * specified button. 87 */ 88 89 flags = 0; 90 MCDoAction(theMC, mcActionGetFlags, &flags); 91 MCDoAction(theMC, mcActionSetFlags, 92 (void *)(flags & ~theButton & ~mcFlagQTVRExplicitFlagSet)); 93 } 94} 95 96void 97HideControllerButton( MovieController theMC, long theButton ) 98{ 99 long flags; 100 101 /* Handle the custom button separately. */ 102 if (theButton == mcFlagsUseCustomButton) { 103 MCDoAction(theMC, mcActionGetFlags, &flags); 104 MCDoAction(theMC, mcActionSetFlags, (void *)(flags & ~theButton)); 105 } else { 106 flags = mcFlagQTVRExplicitFlagSet; 107 MCDoAction(theMC, mcActionGetFlags, &flags); 108 MCDoAction(theMC, mcActionSetFlags, 109 (void *)((flags | theButton) | mcFlagQTVRExplicitFlagSet)); 110 111 flags = 0; 112 MCDoAction(theMC, mcActionGetFlags, &flags); 113 MCDoAction(theMC, mcActionSetFlags, 114 (void *)((flags | theButton) & ~mcFlagQTVRExplicitFlagSet)); 115 } 116} 117 118/* 119 *---------------------------------------------------------------------- 120 * 121 * SetLoopingState -- 122 * 123 * Sets the movies looping state via its controller. 124 * 125 * Results: 126 * None. 127 * 128 * Side effects: 129 * None. 130 * 131 *---------------------------------------------------------------------- 132 */ 133 134void 135SetLoopingState( MovieController theMC, UInt8 theLoopState ) 136{ 137 138 switch (theLoopState) { 139 140 case kQTTclNormalLooping: 141 MCDoAction( theMC, mcActionSetLooping, (void *) true ); 142 MCDoAction( theMC, mcActionSetLoopIsPalindrome, (void *) false ); 143 break; 144 145 case kQTTclPalindromeLooping: 146 MCDoAction( theMC, mcActionSetLooping, (void *) true ); 147 MCDoAction( theMC, mcActionSetLoopIsPalindrome, (void *) true ); 148 break; 149 150 case kQTTclNoLooping: 151 MCDoAction( theMC, mcActionSetLooping, (void *) false ); 152 MCDoAction( theMC, mcActionSetLoopIsPalindrome, (void *) false ); 153 154 default: 155 break; 156 } 157} 158 159/* 160 *---------------------------------------------------------------------- 161 * 162 * SetMovieLoopState -- 163 * 164 * Sets the movies looping state if it doesn't have a controller. 165 * 166 * Results: 167 * None. 168 * 169 * Side effects: 170 * None. 171 * 172 *---------------------------------------------------------------------- 173 */ 174 175void 176SetMovieLoopState( Movie theMovie, UInt8 theLoopState ) 177{ 178 TimeBase myTimeBase; 179 long myFlags = 0L; 180 181 if (theMovie == NULL) 182 return; 183 184 myTimeBase = GetMovieTimeBase( theMovie ); 185 myFlags = GetTimeBaseFlags( myTimeBase ); 186 187 switch (theLoopState) { 188 189 case kQTTclNormalLooping: 190 SetMoviePlayHints( theMovie, hintsLoop, hintsLoop ); 191 SetMoviePlayHints( theMovie, 0L, hintsPalindrome ); 192 myFlags |= loopTimeBase; 193 myFlags &= ~palindromeLoopTimeBase; 194 break; 195 196 case kQTTclPalindromeLooping: 197 SetMoviePlayHints( theMovie, hintsLoop, hintsLoop ); 198 SetMoviePlayHints( theMovie, hintsPalindrome, hintsPalindrome ); 199 myFlags |= loopTimeBase; 200 myFlags |= palindromeLoopTimeBase; 201 break; 202 203 case kQTTclNoLooping: 204 myFlags &= ~loopTimeBase; 205 myFlags &= ~palindromeLoopTimeBase; 206 SetMoviePlayHints( theMovie, 0L, hintsLoop | hintsPalindrome ); 207 break; 208 } 209 SetTimeBaseFlags( myTimeBase, myFlags ); 210} 211 212/* 213 *---------------------------------------------------------------------- 214 * 215 * IsMovieLooping -- 216 * 217 * Returns a boolean of 'true' if the movie is in a looping state, 218 * and 'false' else. 219 * 220 * Results: 221 * Boolean. 222 * 223 * Side effects: 224 * None. 225 * 226 *---------------------------------------------------------------------- 227 */ 228 229Boolean 230IsMovieLooping( Movie theMovie ) 231{ 232 TimeBase myTimeBase; 233 long myFlags = 0L; 234 235 if (theMovie == NULL) 236 return(false); 237 238 myTimeBase = GetMovieTimeBase( theMovie ); 239 myFlags = GetTimeBaseFlags( myTimeBase ); 240 return((Boolean) (myFlags & loopTimeBase)); 241} 242/* 243 *---------------------------------------------------------------------- 244 * 245 * MoviePrePrerollCompleteProc -- 246 * 247 * . 248 * 249 * Results: 250 * None. 251 * 252 * Side effects: 253 * None. 254 * 255 *---------------------------------------------------------------------- 256 */ 257 258void 259MoviePrePrerollCompleteProc( Movie theMovie, OSErr err, void *refConst ) 260{ 261 TimeValue myTimeValue; 262 Fixed myPlayRate; 263 264 if (theMovie == NULL) { 265 return; 266 } 267 // Preroll the movie so that it's ready to play. 268 myTimeValue = GetMovieTime( theMovie, NULL ); 269 myPlayRate = GetMoviePreferredRate( theMovie ); 270} 271 272/* 273 *---------------------------------------------------------------------- 274 * 275 * GetControllerType -- 276 * 277 * Gets a movie's type of controller by examining the movie's user data. 278 * 279 * Results: 280 * Returns the movie's controller type which is a four-character code. 281 * 282 * Side effects: 283 * None. 284 * 285 *---------------------------------------------------------------------- 286 */ 287 288OSType 289GetControllerType( Movie theMovie ) 290{ 291 UserData theUserData; 292 OSType theType = kUnknownType; 293 OSErr err = noErr; 294 295 if (theMovie == NULL) { 296 return(theType); 297 } 298 theUserData = GetMovieUserData( theMovie ); 299 if (theUserData != NULL) { 300 err = GetUserDataItem( theUserData, &theType, sizeof(theType), 301 kUserDataMovieControllerType, 0 ); 302 if (err == noErr) { 303 theType = EndianU32_BtoN( theType ); 304 } 305 } 306 return(theType); 307} 308 309/* 310 *---------------------------------------------------------------------- 311 * 312 * IsQTVRMovie -- 313 * 314 * Returns a Boolean value of 'true' if we have got a VR panoramic movie, 315 * and 'false' otherwise. 316 * 317 * Results: 318 * Returns a Boolean value of 'true' if we have got a VR panoramic movie, 319 * and 'false' otherwise. 320 * 321 * Side effects: 322 * None. 323 * 324 *---------------------------------------------------------------------- 325 */ 326 327Boolean 328IsQTVRMovie( Movie theMovie ) 329{ 330 Boolean isQTVRMovie = false; 331 OSType theType = kUnknownType; 332 333 /* 334 * QTVR panos have a special piece of user data identifying the movie 335 * controller type. 336 */ 337 338 theType = GetControllerType( theMovie ); 339 if ((theType == kQTVRQTVRType) || (theType == kQTVROldPanoType) || 340 (theType == kQTVROldObjectType)) { 341 isQTVRMovie = true; 342 } 343 return(isQTVRMovie); 344} 345 346/* 347 *---------------------------------------------------------------------- 348 * 349 * GetControllerBarHeight -- 350 * 351 * Return the height of the controller bar displayed by the movie controller. 352 * Note that MCGetControllerBoundsRect returns rectangle of bar and movie, 353 * if attached, so we need to unattach the controller bar first. 354 * 355 * Results: 356 * the height 357 * 358 * Side effects: 359 * None. 360 * 361 *---------------------------------------------------------------------- 362 */ 363 364short GetControllerBarHeight( MovieController mc ) 365{ 366 Boolean wasAttached = false; 367 Rect myRect; 368 short myHeight = 0; 369 370 /* If the controller bar is attached, detach it (and remember we did so) */ 371 if (MCIsControllerAttached(mc) == 1) { 372 wasAttached = true; 373 MCSetControllerAttached( mc, false ); 374 } 375 376 /* Get the rectangle of the controller */ 377 MCGetControllerBoundsRect( mc, &myRect ); 378 myHeight = myRect.bottom - myRect.top; 379 380 /* Now reattach the controller bar, if it was originally attached */ 381 if (wasAttached) { 382 MCSetControllerAttached( mc, true ); 383 } 384 return(myHeight); 385} 386 387/* 388 *---------------------------------------------------------------------- 389 * 390 * GetQTVRInstanceFromController -- 391 * 392 * Returns either the QTVR instance or NULL for non QTVR movies. 393 * 394 * Results: 395 * QTVR instance or NULL. 396 * 397 * Side effects: 398 * None. 399 * 400 *---------------------------------------------------------------------- 401 */ 402 403QTVRInstance 404GetQTVRInstanceFromController( MovieController mc ) 405{ 406 Track track = NULL; 407 QTVRInstance qtvrInstance = NULL; 408 Movie aMovie = NULL; 409 410 aMovie = MCGetMovie( mc ); 411 if (aMovie != NULL) { 412 track = QTVRGetQTVRTrack( aMovie, 1 ); 413 if (track != NULL) { 414 QTVRGetQTVRInstance( &qtvrInstance, track, mc ); 415 416 /* Set units to degrees */ 417 if (qtvrInstance != NULL) { 418 QTVRSetAngularUnits( qtvrInstance, kQTVRDegrees ); 419 } 420 } 421 } 422 return qtvrInstance; 423} 424 425/* 426 *---------------------------------------------------------------------- 427 * 428 * TranslateTclListToMatrixRecord -- 429 * 430 * Takes a tcl list, and fills in the matrix record. 431 * 432 * Results: 433 * The return value is a standard Tcl result. If TCL_ERROR is 434 * returned, then the interp's result contains an error message. 435 * 436 * Side effects: 437 * None. 438 * 439 *---------------------------------------------------------------------- 440 */ 441 442int 443TranslateTclListToMatrixRecord( Tcl_Interp *interp, 444 Tcl_Obj *listObjPtr, 445 MatrixRecord *mr ) 446{ 447 int i; 448 int j; 449 int len; 450 double doubleElement; 451 Tcl_Obj *subListObjPtr; 452 Tcl_Obj *objPtr; 453 454 if (Tcl_ListObjLength( interp, listObjPtr, &len ) != TCL_OK) { 455 Tcl_AddErrorInfo( interp, 456 "\n (processing matrix object)" ); 457 return TCL_ERROR; 458 } 459 if (len != 3) { 460 Tcl_SetObjResult( interp, Tcl_NewStringObj( 461 "Wrong number of items in matrix list", -1 ) ); 462 return TCL_ERROR; 463 } 464 for (i = 0; i < 3; i++) { 465 if (Tcl_ListObjIndex( interp, listObjPtr, i, &subListObjPtr ) != TCL_OK) { 466 Tcl_AddErrorInfo( interp, 467 "\n (processing matrix object)" ); 468 return TCL_ERROR; 469 } 470 if (Tcl_ListObjLength( interp, subListObjPtr, &len ) != TCL_OK) { 471 Tcl_AddErrorInfo( interp, 472 "\n (processing matrix object)" ); 473 return TCL_ERROR; 474 } 475 if (len != 3) { 476 Tcl_SetObjResult( interp, Tcl_NewStringObj( 477 "Wrong number of items in matrix list", -1 ) ); 478 return TCL_ERROR; 479 } 480 481 /* 482 * Loop over all columns for this row. 483 */ 484 485 for (j = 0; j < 2; j++) { 486 if (Tcl_ListObjIndex( interp, subListObjPtr, j, &objPtr ) 487 != TCL_OK) { 488 Tcl_AddErrorInfo( interp, 489 "\n (processing matrix object)" ); 490 return TCL_ERROR; 491 } 492 if (Tcl_GetDoubleFromObj( interp, objPtr, &doubleElement ) 493 != TCL_OK) { 494 Tcl_AddErrorInfo( interp, 495 "\n (processing matrix object)" ); 496 return TCL_ERROR; 497 } 498 mr->matrix[i][j] = X2Fix( doubleElement ); 499 } 500 } 501 502 mr->matrix[0][2] = X2Frac(0.0); 503 mr->matrix[1][2] = X2Frac(0.0); 504 mr->matrix[2][2] = X2Frac(1.0); 505 506 return TCL_OK; 507} 508 509/* 510 *---------------------------------------------------------------------- 511 * 512 * TranslateMatrixRecordToTclList -- 513 * 514 * Takes a matrix record and fills in the tcl object as a 3x3 tcl 515 * list-sublist. 516 * 517 * Results: 518 * The return value is a standard Tcl result. 519 * 3x3 matrix of Tcl_Obj* put in listObjPtrPtr. 520 * 521 * Side effects: 522 * None. 523 * 524 *---------------------------------------------------------------------- 525 */ 526 527int 528TranslateMatrixRecordToTclList( Tcl_Interp *interp, 529 Tcl_Obj **listObjPtrPtr, 530 MatrixRecord *mr ) 531{ 532 int i; 533 int j; 534 double doubleElement; 535 Tcl_Obj *rowObj; 536 537 *listObjPtrPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 538 539 for (i = 0; i < 3; i++) { 540 rowObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 541 for (j = 0; j < 3; j++) { 542 if (j == 2) { 543 doubleElement = Frac2X( mr->matrix[i][j] ); 544 } else { 545 doubleElement = Fix2X( mr->matrix[i][j] ); 546 } 547 Tcl_ListObjAppendElement( interp, rowObj, 548 Tcl_NewDoubleObj(doubleElement) ); 549 } 550 Tcl_ListObjAppendElement( interp, *listObjPtrPtr, rowObj ); 551 } 552 return TCL_OK; 553} 554 555int 556DoesCodecSupport( CodecType cType, long what, int value ) 557{ 558 int answer = 0; 559 CodecInfo cInfo; 560 OSErr err = noErr; 561 562 err = GetCodecInfo( &cInfo, cType, 0 ); 563 564 switch (what) { 565 566 case kDoesCodecPixmapDepth: { 567 long compressFlags = cInfo.compressFlags; 568 569 switch (value) { 570 case 1: { 571 answer = compressFlags | codecInfoDoes1; 572 break; 573 } 574 case 2: { 575 answer = compressFlags | codecInfoDoes2; 576 break; 577 } 578 case 4: { 579 answer = compressFlags | codecInfoDoes4; 580 break; 581 } 582 case 8: { 583 answer = compressFlags | codecInfoDoes8; 584 break; 585 } 586 case 16: { 587 answer = compressFlags | codecInfoDoes16; 588 break; 589 } 590 case 32: { 591 answer = compressFlags | codecInfoDoes32; 592 break; 593 } 594 default: { 595 596 } 597 } 598 break; 599 } 600 case kDoesCodecCompressDepth: { 601 long formatFlags = cInfo.formatFlags; 602 603 switch (value) { 604 case 1: { 605 answer = formatFlags | codecInfoDepth1; 606 break; 607 } 608 case 2: { 609 answer = formatFlags | codecInfoDepth2; 610 break; 611 } 612 case 4: { 613 answer = formatFlags | codecInfoDepth4; 614 break; 615 } 616 case 8: { 617 answer = formatFlags | codecInfoDepth8; 618 break; 619 } 620 case 16: { 621 answer = formatFlags | codecInfoDepth16; 622 break; 623 } 624 case 32: { 625 answer = formatFlags | codecInfoDepth32; 626 break; 627 } 628 case 24: { 629 answer = formatFlags | codecInfoDepth24; 630 break; 631 } 632 case 33: { 633 answer = formatFlags | codecInfoDepth33; 634 break; 635 } 636 case 34: { 637 answer = formatFlags | codecInfoDepth34; 638 break; 639 } 640 case 36: { 641 answer = formatFlags | codecInfoDepth36; 642 break; 643 } 644 case 40: { 645 answer = formatFlags | codecInfoDepth40; 646 break; 647 } 648 default: { 649 650 } 651 } 652 } 653 } 654 return answer; 655} 656 657/* 658 *---------------------------------------------------------------------- 659 * 660 * IsTrackForEyes -- 661 * 662 * Returns false if sound track, and true if text or video track. 663 * 664 * Results: 665 * Boolean. 666 * 667 * Side effects: 668 * None. 669 * 670 *---------------------------------------------------------------------- 671 */ 672 673int 674IsTrackForEyes( Track myTrack ) 675{ 676 int isForEyes = true; 677 Media myMedia = NULL; 678 OSType mediaType; 679 680 myMedia = GetTrackMedia( myTrack ); 681 if (myMedia != NULL) { 682 GetMediaHandlerDescription( myMedia, &mediaType, NULL, NULL ); 683 if (mediaType == SoundMediaType) { 684 isForEyes = false; 685 } 686 } 687 return isForEyes; 688} 689 690/*----------------------------------------------------------------------*/ 691