void ofVideoPlayer::createImgMemAndGWorld(){ Rect movieRect; movieRect.top = 0; movieRect.left = 0; movieRect.bottom = height; movieRect.right = width; offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; pixels = new unsigned char[width*height*3]; #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) QTNewGWorldFromPtr (&(offscreenGWorld), k32ARGBPixelFormat, &(movieRect), NULL, NULL, 0, (offscreenGWorldPixels), 4 * width); #else QTNewGWorldFromPtr (&(offscreenGWorld), k24RGBPixelFormat, &(movieRect), NULL, NULL, 0, (pixels), 3 * width); #endif LockPixels(GetGWorldPixMap(offscreenGWorld)); SetGWorld (offscreenGWorld, NULL); SetMovieGWorld (moviePtr, offscreenGWorld, nil); //------------------------------------ texture stuff: if (bUseTexture){ // create the texture, set the pixels to black and // upload them to the texture (so at least we see nothing black the callback) tex.allocate(width,height,GL_RGB); memset(pixels, 0, width*height*3); tex.loadData(pixels, width, height, GL_RGB); allocated = true; } }
void ofQuickTimePlayer::createImgMemAndGWorld() { Rect movieRect; movieRect.top = 0; movieRect.left = 0; movieRect.bottom = height; movieRect.right = width; offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; pixels.allocate(width,height,OF_IMAGE_COLOR); #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) QTNewGWorldFromPtr (&(offscreenGWorld), k32ARGBPixelFormat, &(movieRect), NULL, NULL, 0, (offscreenGWorldPixels), 4 * width); #else QTNewGWorldFromPtr (&(offscreenGWorld), k24RGBPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 3 * width); #endif LockPixels(GetGWorldPixMap(offscreenGWorld)); // from : https://github.com/openframeworks/openFrameworks/issues/244 // SetGWorld do not seems to be necessary for offscreen rendering of the movie // only SetMovieGWorld should be called // if both are called, the app will crash after a few ofVideoPlayer object have been deleted #ifndef TARGET_WIN32 SetGWorld (offscreenGWorld, NULL); #endif SetMovieGWorld (moviePtr, offscreenGWorld, nil); }
void ofQuickTimePlayer::createImgMemAndGWorld(){ Rect movieRect; movieRect.top = 0; movieRect.left = 0; movieRect.bottom = height; movieRect.right = width; if (pixelFormat == OF_PIXELS_RGBA) { pixels.allocate(width, height, OF_IMAGE_COLOR_ALPHA); } else { pixels.allocate(width, height, OF_IMAGE_COLOR); } #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; QTNewGWorldFromPtr (&(offscreenGWorld), k32ARGBPixelFormat, &(movieRect), NULL, NULL, 0, (offscreenGWorldPixels), 4 * width); #else if (pixelFormat == OF_PIXELS_RGBA) { QTNewGWorldFromPtr (&(offscreenGWorld), k32RGBAPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 4 * width); } else { QTNewGWorldFromPtr (&(offscreenGWorld), k24RGBPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 3 * width); } #endif LockPixels(GetGWorldPixMap(offscreenGWorld)); SetGWorld (offscreenGWorld, NULL); SetMovieGWorld (moviePtr, offscreenGWorld, nil); }
void ofxAlphaVideoPlayer::createImgMemAndGWorld(){ Rect movieRect; movieRect.top = 0; movieRect.left = 0; movieRect.bottom = height; movieRect.right = width; offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; pixels = new unsigned char[width*height*4]; // 4 =>rgba #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) //cout << "with Big Endian"<<endl; QTNewGWorldFromPtr (&(offscreenGWorld), k32ARGBPixelFormat, &(movieRect), NULL, NULL, 0, (offscreenGWorldPixels), 4 * width); #else //cout << "no Big Endian"<<endl; QTNewGWorldFromPtr (&(offscreenGWorld), k32RGBAPixelFormat, &(movieRect), NULL, NULL, 0, (pixels), 4 * width); #endif /** POSSIBLE PIXEL FORMATS k32BGRAPixelFormat = 'BGRA', // 32 bit bgra (Matrox) k32ABGRPixelFormat = 'ABGR', // 32 bit abgr k32RGBAPixelFormat = 'RGBA', // 32 bit rgba ***********/ LockPixels(GetGWorldPixMap(offscreenGWorld)); SetGWorld (offscreenGWorld, NULL); SetMovieGWorld (moviePtr, offscreenGWorld, nil); //------------------------------------ texture stuff: if (bUseTexture){ // create the texture, set the pixels to black and // upload them to the texture (so at least we see nothing black the callback) tex.allocate(width,height,GL_RGBA); memset(pixels, 0, width*height*4); tex.loadData(pixels, width, height, GL_RGBA); allocated = true; } }
OSErr QTDR_PlayMovieFromRAM (Movie theMovie) { WindowPtr myWindow = NULL; Rect myBounds = {50, 50, 100, 100}; Rect myRect; StringPtr myTitle = QTUtils_ConvertCToPascalString(kWindowTitle); OSErr myErr = memFullErr; myWindow = NewCWindow(NULL, &myBounds, myTitle, false, 0, (WindowPtr)-1, false, 0); if (myWindow == NULL) goto bail; myErr = noErr; MacSetPort((GrafPtr)GetWindowPort(myWindow)); GetMovieBox(theMovie, &myRect); MacOffsetRect(&myRect, -myRect.left, -myRect.top); SetMovieBox(theMovie, &myRect); if (!EmptyRect(&myRect)) SizeWindow(myWindow, myRect.right, myRect.bottom, false); else SizeWindow(myWindow, 200, 0, false); MacShowWindow(myWindow); SetMovieGWorld(theMovie, GetWindowPort(myWindow), NULL); GoToBeginningOfMovie(theMovie); MoviesTask(theMovie, 0); StartMovie(theMovie); myErr = GetMoviesError(); if (myErr != noErr) goto bail; while (!IsMovieDone(theMovie)) MoviesTask(theMovie, 0); bail: free(myTitle); if (theMovie != NULL) DisposeMovie(theMovie); if (myWindow != NULL) DisposeWindow(myWindow); return(myErr); }
OSErr DoPlayMovie(Boolean useOverlay) { Rect movieBounds; OSErr err; BailErr((err = GetAMovieFile(&mMovie))); GetMovieBox(mMovie, &movieBounds); mMovieController = NewMovieController(mMovie, &movieBounds, mcTopLeftMovie | mcNotVisible); NormalizeMovieRect(mMovie); GetMovieBox(mMovie, &movieBounds); BailErr((err = InitializeMungData(movieBounds, FrontWindow(), useOverlay, /* overlay */ true, /* clamp */ false /* draw with QT Effect */ ))); // This is key, as we need to draw all frames in our // offscreen gworld first. Once there, our custom // decompressor component can perform overlay drawing // or color clamping SetMovieGWorld(mMovie, GetMungDataOffscreen(), nil); // Our DrawCompleteProc calls BlitOneMungData which SetupMovieDrawCompleteProc(); // --------- SetMovieActive(mMovie, true); #ifndef __APPLE_CC__ // Due to a bug in Jaguar, some QT functions are missing from // /System/Library/CFMSupport/CarbonLib, so we must manually // grab the function pointers from the QuickTime.framework // for CFM Carbon applications. MachO Carbon applications do not // have the problem. GetMissingQTFunctionPointers(); #endif InstallMovieIdlingEventLoopTimer(&mMovieTimerState); // start the movie playing MCDoAction(mMovieController, mcActionPrerollAndPlay, (void*)Long2Fix(1)); bail: return err; }
quicktime_player* quicktime_player::open( const char *path ) { OSErr err; OSType dataRefType; Handle dataRef = NULL; short resID = 0; impl *m = new impl; std::string pathStd = path; #ifdef WIN32 for (std::string::iterator p = pathStd.begin(); p != pathStd.end(); ++p) if (*p == '/') *p = '\\'; #endif CFStringRef cfPath = CFStringCreateWithCString(NULL, pathStd.c_str(), kCFStringEncodingISOLatin1); err = QTNewDataReferenceFromFullPathCFString(cfPath, (QTPathStyle)kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType); CFRelease(cfPath); if (err != noErr) { delete m; return NULL; } err = NewMovieFromDataRef(&m->movie, newMovieActive, &resID, dataRef, dataRefType); DisposeHandle(dataRef); if (err != noErr) { delete m; return NULL; } m->track = GetMovieIndTrackType(m->movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic); m->media = GetTrackMedia(m->track); Rect bounds; GetMovieBox(m->movie, &bounds); m->width = bounds.right; m->height = bounds.bottom; m->buffer = (unsigned char*)malloc(4 * m->width * m->height); err = QTNewGWorldFromPtr(&m->gworld, k32BGRAPixelFormat, &bounds, NULL, NULL, 0, m->buffer, 4 * m->width); if (err != noErr) { delete m; return NULL; } SetMovieGWorld(m->movie, m->gworld, NULL); return new quicktime_player(m); }
//--------------------------------------------------------------------------- bool ofVideoPlayer::loadMovie(string name){ //-------------------------------------- #ifdef OF_VIDEO_PLAYER_QUICKTIME //-------------------------------------- initializeQuicktime(); // init quicktime closeMovie(); // if we have a movie open, close it bLoaded = false; // try to load now if( name.substr(0, 7) == "http://"){ if(! createMovieFromURL(name, moviePtr) ) return false; }else{ name = ofToDataPath(name); if( !createMovieFromPath((char *)name.c_str(), moviePtr) ) return false; } bool bDoWeAlreadyHaveAGworld = false; if (width != 0 && height != 0){ bDoWeAlreadyHaveAGworld = true; } Rect movieRect; GetMovieBox(moviePtr, &(movieRect)); if (bDoWeAlreadyHaveAGworld){ // is the gworld the same size, then lets *not* de-allocate and reallocate: if (width == movieRect.right && height == movieRect.bottom){ SetMovieGWorld (moviePtr, offscreenGWorld, nil); } else { width = movieRect.right; height = movieRect.bottom; delete(pixels); delete(offscreenGWorldPixels); if ((offscreenGWorld)) DisposeGWorld((offscreenGWorld)); createImgMemAndGWorld(); } } else { width = movieRect.right; height = movieRect.bottom; createImgMemAndGWorld(); } if (moviePtr == NULL){ return false; } //----------------- callback method MovieDrawingCompleteUPP myDrawCompleteProc; myDrawCompleteProc = NewMovieDrawingCompleteUPP (DrawCompleteProc); SetMovieDrawingCompleteProc (moviePtr, movieDrawingCallWhenChanged, myDrawCompleteProc, (long)this); // ------------- get some pixels in there ------ GoToBeginningOfMovie(moviePtr); SetMovieActiveSegment(moviePtr, -1,-1); MoviesTask(moviePtr,0); convertPixels(offscreenGWorldPixels, pixels, width, height); if (bUseTexture == true){ tex.loadData(pixels, width, height, GL_RGB); } bStarted = false; bLoaded = true; bPlaying = false; bHavePixelsChanged = false; speed = 1; return true; //-------------------------------------- #else //-------------------------------------- bLoaded = false; bPaused = false; speed = 1.0f; bHavePixelsChanged = false; name = ofToDataPath(name); fobsDecoder = new omnividea::fobs::Decoder(name.c_str()); omnividea::fobs::ReturnCode error = fobsDecoder->open(); width = fobsDecoder->getWidth(); height = fobsDecoder->getHeight(); pixels = new unsigned char[width*height*3]; if (!fobsDecoder->isVideoPresent()){ return false; } bLoaded = true; if (bUseTexture){ // create the texture, set the pixels to black and // upload them to the texture (so at least we see nothing black the callback) tex.allocate(width,height,GL_RGB); memset(pixels, 0, width*height*3); tex.loadData(pixels, width, height, GL_RGB); } error = fobsDecoder->setFrame(0); if(error == omnividea::fobs::NoFrameError) { error = omnividea::fobs::OkCode; printf("NoFrameError\n"); } if(omnividea::fobs::isOk(error)){ // get some pixels in: unsigned char *rgb = fobsDecoder->getRGB(); if(rgb == NULL) error = omnividea::fobs::GenericError; if(isOk(error)) { memcpy(pixels, rgb, width*height*3); tex.loadData(pixels, width, height, GL_RGB); } } iTotalFrames = (int)(fobsDecoder->getFrameRate()*fobsDecoder->getDurationSeconds()); positionPct = 0; timeLastIdle = ofGetElapsedTimef(); durationMillis = fobsDecoder->getDurationSeconds() * 1000.0f; return true; //-------------------------------------- #endif //-------------------------------------- }
/* * PsychQTCreateMovie() -- Create a movie object. * * This function tries to open a Quicktime-Moviefile and create an * associated movie object for it. * * win = Pointer to window record of associated onscreen window. * moviename = char* with the name of the moviefile. * preloadSecs = How many seconds of the movie should be preloaded/prefetched into RAM at movie open time? * moviehandle = handle to the new movie. */ void PsychQTCreateMovie(PsychWindowRecordType *win, const char* moviename, double preloadSecs, int* moviehandle) { Movie theMovie = NULL; QTVisualContextRef QTMovieContext = NULL; QTAudioContextRef QTAudioContext = NULL; int i, slotid; OSErr error; CFStringRef movieLocation; CFURLRef movieURLLocation; CFStringRef coreAudioDeviceUID; psych_bool trueValue = TRUE; QTNewMoviePropertyElement newMovieProperties[4] = {0}; int propcount = 0; char msgerr[10000]; char errdesc[1000]; Rect movierect; psych_bool printErrors; // Suppress output of error-messages if moviehandle == 1000. That means we // run in our own Posix-Thread, not in the Matlab-Thread. Printing via Matlabs // printing facilities would likely cause a terrible crash. printErrors = (*moviehandle == -1000) ? FALSE : TRUE; // Set movie handle to "failed" initially: *moviehandle = -1; // We startup the Quicktime subsystem only on first invocation. if (firsttime) { #if PSYCH_SYSTEM == PSYCH_WINDOWS // Initialize Quicktime for Windows compatibility layer: This will fail if // QT isn't installed on the Windows machine... error = InitializeQTML(0); if (error!=noErr) { if (printErrors) { PsychErrorExitMsg(PsychError_internal, "Quicktime Media Layer initialization failed: Quicktime not properly installed?!?"); } else return; } #endif // Initialize Quicktime-Subsystem: error = EnterMovies(); if (error!=noErr) { if (printErrors) PsychErrorExitMsg(PsychError_internal, "Quicktime EnterMovies() failed!!!"); else return; } firsttime = FALSE; } if (!PsychIsOnscreenWindow(win)) { if (printErrors) PsychErrorExitMsg(PsychError_user, "Provided windowPtr is not an onscreen window."); else return; } if (NULL==moviename) { if (printErrors) PsychErrorExitMsg(PsychError_internal, "NULL-Ptr instead of moviename passed!"); else return; } if (numMovieRecords >= PSYCH_MAX_MOVIES) { *moviehandle = -2; if (printErrors) PsychErrorExitMsg(PsychError_user, "Allowed maximum number of simultaneously open movies exceeded!"); else return; } // Search first free slot in movieRecordBANK: for (i=0; (i < PSYCH_MAX_MOVIES) && (movieRecordBANK[i].theMovie); i++); if (i>=PSYCH_MAX_MOVIES) { *moviehandle = -2; if (printErrors) PsychErrorExitMsg(PsychError_user, "Allowed maximum number of simultaneously open movies exceeded!"); else return; } // Slot slotid will contain the movie record for our new movie object: slotid=i; // Create name-string for moviename: movieLocation = CFStringCreateWithCString (kCFAllocatorDefault, moviename, kCFStringEncodingASCII); // Zero-out new record in moviebank: movieRecordBANK[slotid].theMovie=NULL; movieRecordBANK[slotid].QTMovieContext=NULL; movieRecordBANK[slotid].QTAudioContext=NULL; movieRecordBANK[slotid].QTMovieGWorld=NULL; if (!PSYCH_USE_QT_GWORLDS) { // Create QTGLTextureContext: #if PSYCH_SYSTEM != PSYCH_WINDOWS error = QTOpenGLTextureContextCreate (kCFAllocatorDefault, win->targetSpecific.contextObject, win->targetSpecific.pixelFormatObject, NULL, &QTMovieContext); #endif if (error!=noErr) { if (printErrors) PsychErrorExitMsg(PsychError_internal, "OpenGL Quicktime visual context creation failed!!!"); else return; } } // The Movie location newMovieProperties[propcount].propClass = kQTPropertyClass_DataLocation; if (strstr(moviename, "http:") || strstr(moviename, "ftp:")) { // Open movie from URL, e.g., http- or ftp- server: movieURLLocation = CFURLCreateWithString(kCFAllocatorDefault, movieLocation, NULL); newMovieProperties[propcount].propID = kQTDataLocationPropertyID_CFURL; newMovieProperties[propcount].propValueSize = sizeof(movieURLLocation); newMovieProperties[propcount++].propValueAddress = (void*) &movieURLLocation; } else { // Open movie file from filesystem: newMovieProperties[propcount].propID = kQTDataLocationPropertyID_CFStringPosixPath; newMovieProperties[propcount].propValueSize = sizeof(CFStringRef); newMovieProperties[propcount++].propValueAddress = &movieLocation; } if (!PSYCH_USE_QT_GWORLDS) { // The Movie visual context newMovieProperties[propcount].propClass = kQTPropertyClass_Context; newMovieProperties[propcount].propID = kQTContextPropertyID_VisualContext; newMovieProperties[propcount].propValueSize = sizeof(QTVisualContextRef); newMovieProperties[propcount++].propValueAddress = &QTMovieContext; } if (TRUE) { // Create QTAudioContext for default CoreAudio device: coreAudioDeviceUID = NULL; // Use default audio-output device. error =QTAudioContextCreateForAudioDevice (kCFAllocatorDefault, coreAudioDeviceUID, NULL, &QTAudioContext); if (error!=noErr) { if (printErrors) PsychErrorExitMsg(PsychError_internal, "Quicktime audio context creation failed!!!"); else return; } // The Movie audio context newMovieProperties[propcount].propClass = kQTPropertyClass_Context; newMovieProperties[propcount].propID = kQTContextPropertyID_AudioContext; newMovieProperties[propcount].propValueSize = sizeof(QTAudioContextRef); newMovieProperties[propcount++].propValueAddress = &QTAudioContext; } // The Movie active newMovieProperties[propcount].propClass = kQTPropertyClass_NewMovieProperty; newMovieProperties[propcount].propID = kQTNewMoviePropertyID_Active; newMovieProperties[propcount].propValueSize = sizeof(trueValue); newMovieProperties[propcount++].propValueAddress = &trueValue; // Instantiate the Movie error = NewMovieFromProperties(propcount, newMovieProperties, 0, NULL, &theMovie); if (error!=noErr) { QTVisualContextRelease(QTMovieContext); QTAudioContextRelease(QTAudioContext); switch(error) { case -2000: case -50: case -43: sprintf(errdesc, "File not found."); break; case -2048: sprintf(errdesc, "This is not a file that Quicktime understands."); break; case -2003: sprintf(errdesc, "Can't find media handler (codec) for this movie."); break; default: sprintf(errdesc, "Unknown: Check http://developer.apple.com/documentation/QuickTime/APIREF/ErrorCodes.htm#//apple_ref/doc/constant_group/Error_Codes"); } sprintf(msgerr, "Couldn't load movie %s! Quicktime error code %i [%s]", moviename, (int) error, errdesc); *moviehandle = (int) error; if (printErrors) PsychErrorExitMsg(PsychError_user, msgerr); else return; } CFRelease(movieLocation); if (PSYCH_USE_QT_GWORLDS) { // Determine size of images in movie: GetMovieBox(theMovie, &movierect); // Only create a GWorld if movie frames contain at least 1 pixel. This way we skip GWorld // setup on "movies" which only consist of sound tracks. if ((movierect.right - movierect.left != 0) && (movierect.bottom - movierect.top != 0)) { // Create GWorld for this movie object: // error = QTNewGWorld(&movieRecordBANK[slotid].QTMovieGWorld, k32ABGRPixelFormat, &movierect, NULL, NULL, 0); error = QTNewGWorld(&movieRecordBANK[slotid].QTMovieGWorld, 0, &movierect, NULL, NULL, 0); if (error!=noErr) { QTAudioContextRelease(QTAudioContext); DisposeMovie(movieRecordBANK[slotid].theMovie); movieRecordBANK[slotid].theMovie=NULL; if (printErrors) PsychErrorExitMsg(PsychError_internal, "Quicktime GWorld creation failed!!!"); else return; } // Attach this GWorld as rendering target for Quicktime: SetMovieGWorld(theMovie, movieRecordBANK[slotid].QTMovieGWorld, NULL); } } // Preload preloadSecs seconds of movie into system RAM for faster playback: if (preloadSecs > 0) LoadMovieIntoRam(theMovie, 0, ((long) preloadSecs + 0.5) * GetMovieTimeScale(theMovie), keepInRam); // Special setting - 1 means: Load whole movie into RAM: if (preloadSecs == -1) LoadMovieIntoRam(theMovie, 0, GetMovieDuration(theMovie), keepInRam); // We don't preroll: Didn't help for async playback, but leads to failure in // manual playback mode: PrerollMovie(theMovie, 0, FloatToFixed(1)); // MoviesTask() it to make sure start of plaback will be as stutter-free as possible: MoviesTask(theMovie, 10000); // Assign new record in moviebank: movieRecordBANK[slotid].theMovie=theMovie; movieRecordBANK[slotid].QTMovieContext=QTMovieContext; movieRecordBANK[slotid].QTAudioContext=QTAudioContext; movieRecordBANK[slotid].loopflag = 0; *moviehandle = slotid; // Increase counter: numMovieRecords++; // Compute basic movie properties - Duration and fps as well as image size: // Compute duration in seconds: movieRecordBANK[slotid].movieduration = (double) GetMovieDuration(theMovie) / (double) GetMovieTimeScale(theMovie); // Compute expected framerate, assuming a linear spacing between frames: It is derived as // reciprocal of the duration of the first video frame in the movie: movieRecordBANK[slotid].fps = PsychDetermineMovieFramecountAndFps(theMovie, NULL); // Determine size of images in movie: GetMovieBox(theMovie, &movierect); movieRecordBANK[slotid].width = movierect.right - movierect.left; movieRecordBANK[slotid].height = movierect.bottom - movierect.top; // We set nrframes == -1 to indicate that this value is not yet available. // Will do counting on first query for this parameter as it is very time-consuming: movieRecordBANK[slotid].nrframes = -1; return; }
//////////////////////////////////////////////////////////////////////////////// // virtual bool LLMediaImplQuickTime::sizeChanged() { if ( ! mMovieHandle ) return false; // sanitize size of movie Rect movie_rect; setMovieBoxEnhanced( &movie_rect ); // we need this later int width = ( movie_rect.right - movie_rect.left ); int height = ( movie_rect.bottom - movie_rect.top ); std::cout << "LLMEDIA> size changed to " << width << " x " << height << std::endl; setMediaSize( width, height ); // media depth won't change int depth_bits = getMediaDepth() * 8; GWorldPtr old_gworld_handle = mGWorldHandle; if (old_gworld_handle) { GWorldFlags result = UpdateGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, 0 ); if ( gwFlagErr == result ) { // TODO: unrecoverable?? throw exception? return something? return false; } } else { OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, keepLocal | pixelsLocked ); if ( noErr != result ) { // ATODO: unrecoverable?? throw exception? return something? return false; } // clear memory in GWorld to avoid random screen visual fuzz from uninitialized texture data if ( mGWorldHandle ) { PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); unsigned char* ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle ); memset( ptr, 0x00, height * QTGetPixMapHandleRowBytes( pix_map_handle ) ); } } // point movie at GWorld if it's new if ( mMovieHandle && ! old_gworld_handle ) { SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice ( mGWorldHandle ) ); } // update movie controller if ( mMovieController ) { MCSetControllerPort( mMovieController, mGWorldHandle ); MCPositionController( mMovieController, &movie_rect, &movie_rect, mcTopLeftMovie | mcPositionDontInvalidate ); MCMovieChanged( mMovieController, mMovieHandle ); } // Emit event with size change so the calling app knows about it too LLMediaEvent event( this ); mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); return true; }
void TLevelReader3gp::load(const TRasterP &rasP, int frameIndex, const TPoint &pos, int shrinkX, int shrinkY) { TRaster32P ras = rasP; { QMutexLocker sl(&m_mutex); ras->lock(); if (m_IOError != QTNoError) goto error; Rect rect; rect.right = pos.x + ras->getLx(); rect.left = pos.x; rect.bottom = pos.y + ras->getLy(); rect.top = pos.y; GWorldPtr offscreenGWorld; OSErr err; #if defined TNZ_MACHINE_CHANNEL_ORDER_BGRM OSType pixelFormat = k32BGRAPixelFormat; #elif defined TNZ_MACHINE_CHANNEL_ORDER_MRGB OSType pixelFormat = k32ARGBPixelFormat; #endif err = QTNewGWorldFromPtr( &offscreenGWorld, pixelFormat, &rect, 0, 0, 0, ras->getRawData(), ras->getWrap() * 4); if (err != noErr) { m_IOError = QTUnableToCreateResource; goto error; } SetMovieBox(m_movie, &rect); err = GetMoviesError(); if (err != noErr) { m_IOError = QTUnableToSetMovieBox; #if 0 DisposeGWorld(offscreenGWorld); #endif goto error; } #if 0 SetMovieGWorld(m_movie, offscreenGWorld, GetGWorldDevice(offscreenGWorld)); #endif err = GetMoviesError(); if (err != noErr) { m_IOError = QTUnableToSetMovieGWorld; #if 0 DisposeGWorld(offscreenGWorld); #endif goto error; } TimeValue currentTime = currentTimes[frameIndex]; SetMovieTimeValue(m_movie, currentTime); err = GetMoviesError(); if (err != noErr) { m_IOError = QTUnableToSetTimeValue; #if 0 DisposeGWorld(offscreenGWorld); #endif goto error; } err = UpdateMovie(m_movie); if (err != noErr) { m_IOError = QTUnableToUpdateMovie; #if 0 DisposeGWorld(offscreenGWorld); #endif goto error; } MoviesTask(m_movie, 0); err = GetMoviesError(); if (err != noErr) { m_IOError = QTUnableToDoMovieTask; #if 0 DisposeGWorld(offscreenGWorld); #endif goto error; } SetMovieGWorld(m_movie, 0, 0); #if 0 DisposeGWorld(offscreenGWorld); #endif ras->unlock(); } if (m_depth != 32) { setMatteAndYMirror(rasP); } else { rasP->yMirror(); } return; error: ras->unlock(); throw TImageException(m_path, buildQTErrorString(m_IOError)); }
void QTCode_SetMovieGWorld(Movie theMovie, GWorldPtr offscreen) { SetMovieGWorld(theMovie, offscreen, GetGWorldDevice(offscreen)); }
boolean playeropenmovieinwindow ( ptrfilespec f ) { // // 2006-06-23 creedon: FSRef-zed // // 7.0b4 PBS: open a movie in the QuickTime Player window and display it. If the window isn't already open, open it. // short movieresref; OSErr err; hdlwindowinfo hinfo; FSSpec fs; if (macgetfsspec (f, &fs) != noErr) return (false); if (!findplayerwindow (&hinfo)) playeropencommand (); // If the Player window doesn't exist, create a new one. getwindowinfo (playerwindow, &playerwindowinfo); playerdisposecurrentmovie (); // make sure the current movie has been disposed SetGWorld (GetWindowPort (playerwindow), nil); err = OpenMovieFile ( &fs, &movieresref, fsRdPerm); if (err != noErr) return (false); NewMovieFromFile (¤tmovie, movieresref, nil, nil, newMovieActive, nil); CloseMovieFile (movieresref); SetMovieGWorld (currentmovie, GetWindowPort (playerwindow), nil); GetMovieBox (currentmovie, ¤tmovierect); OffsetRect (¤tmovierect, -currentmovierect.left, -currentmovierect.top); SetMovieBox (currentmovie, ¤tmovierect); currentcontroller = NewMovieController (currentmovie, ¤tmovierect, mcTopLeftMovie); MCGetControllerBoundsRect (currentcontroller, ¤tmovierect); //MCSetActionFilterWithRefCon (currentcontroller, NewMCActionFilterWithRefConProc(playermoviecontrollereventfilter), (long) playerwindow); SizeWindow (playerwindow, currentmovierect.right, currentmovierect.bottom, false); (**playerwindowinfo).contentrect = currentmovierect; AlignWindow (playerwindow, false, nil, nil); // position for optimal playback //MCDoAction (currentcontroller, mcActionSetKeysEnabled, (void *) true); /*enable keyboard input*/ /*No!*/ MoviesTask (nil, 0); MCIdle (currentcontroller); return (true); } // playeropenmovieinwindow
//--------------------------------------------------------------------------- bool ofQuickTimePlayer::loadMovie(string name) { //-------------------------------------- #ifdef OF_VIDEO_PLAYER_QUICKTIME //-------------------------------------- initializeQuicktime(); // init quicktime closeMovie(); // if we have a movie open, close it bLoaded = false; // try to load now // from : https://github.com/openframeworks/openFrameworks/issues/244 // http://developer.apple.com/library/mac/#documentation/QuickTime/RM/QTforWindows/QTforWindows/C-Chapter/3BuildingQuickTimeCa.html // Apple's documentation *seems* to state that a Gworld should have been set prior to calling NewMovieFromFile // So I set a dummy Gworld (1x1 pixel) before calling createMovieFromPath // it avoids crash at the creation of objet ofVideoPlayer after a previous ofVideoPlayer have been deleted #ifdef TARGET_WIN32 if (width != 0 && height != 0) { pixels.clear(); delete [] offscreenGWorldPixels; } width = 1; height = 1; createImgMemAndGWorld(); #endif if( name.substr(0, 7) == "http://" || name.substr(0,7) == "rtsp://" ) { if(! createMovieFromURL(name, moviePtr) ) return false; } else { name = ofToDataPath(name); if( !createMovieFromPath((char *)name.c_str(), moviePtr) ) return false; } bool bDoWeAlreadyHaveAGworld = false; if (width != 0 && height != 0) { bDoWeAlreadyHaveAGworld = true; } Rect movieRect; GetMovieBox(moviePtr, &(movieRect)); if (bDoWeAlreadyHaveAGworld) { // is the gworld the same size, then lets *not* de-allocate and reallocate: if (width == movieRect.right && height == movieRect.bottom) { SetMovieGWorld (moviePtr, offscreenGWorld, nil); } else { width = movieRect.right; height = movieRect.bottom; pixels.clear(); delete [] offscreenGWorldPixels; if ((offscreenGWorld)) DisposeGWorld((offscreenGWorld)); createImgMemAndGWorld(); } } else { width = movieRect.right; height = movieRect.bottom; createImgMemAndGWorld(); } if (moviePtr == NULL) { return false; } //----------------- callback method myDrawCompleteProc = NewMovieDrawingCompleteUPP (DrawCompleteProc); SetMovieDrawingCompleteProc (moviePtr, movieDrawingCallWhenChanged, myDrawCompleteProc, (long)this); // ------------- get the total # of frames: nFrames = 0; TimeValue curMovieTime; curMovieTime = 0; TimeValue duration; //OSType whichMediaType = VIDEO_TYPE; // mingw chokes on this OSType whichMediaType = FOUR_CHAR_CODE('vide'); short flags = nextTimeMediaSample + nextTimeEdgeOK; while( curMovieTime >= 0 ) { nFrames++; GetMovieNextInterestingTime(moviePtr,flags,1,&whichMediaType,curMovieTime,0,&curMovieTime,&duration); flags = nextTimeMediaSample; } nFrames--; // there's an extra time step at the end of themovie // ------------- get some pixels in there ------ GoToBeginningOfMovie(moviePtr); SetMovieActiveSegment(moviePtr, -1,-1); MoviesTask(moviePtr,0); #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) convertPixels(offscreenGWorldPixels, pixels.getPixels(), width, height); #endif bStarted = false; bLoaded = true; bPlaying = false; bHavePixelsChanged = false; speed = 1; return true; //-------------------------------------- #endif //-------------------------------------- }
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { if (nlhs < 0) { mexErrMsgTxt("Too few output arguments."); return; } if (nlhs > 1) { mexErrMsgTxt("Too many output arguments."); return; } if (nrhs < 1) { mexErrMsgTxt("Too few input arguments."); return; } if (nrhs > 3) { mexErrMsgTxt("Too many input arguments."); return; } TimeValue duration; TimeRecord myTimeRecord; Rect bounds; OSErr result = 0; short resRefNum = -1; short actualResId = DoTheRightThing; FSSpec theFSSpec; GWorldPtr offWorld; Movie theMovie = nil; MovieController thePlayer = nil; MovieDrawingCompleteUPP myDrawCompleteProc; long frame_end; long myStep = 1; char location[PATH_BUFFER_SIZE]; long frame_count; mwSize cdims[2]; mxGetString(prhs[0], location, PATH_BUFFER_SIZE); if (nrhs > 2) { frame_start = rint(mxGetScalar(prhs[1])); frame_end = rint(mxGetScalar(prhs[2])); } else if (nrhs > 1) { frame_start = 1; frame_end = rint(mxGetScalar(prhs[1])); } else { frame_start = 1; frame_end = 0; } if (frame_start < 1) { mexErrMsgTxt("Error: the starting frame must be positive\n"); return; } if (frame_end < 0) { mexErrMsgTxt("Error: the ending frame must be positive\n"); return; } if (frame_end != 0 && frame_end < frame_start) { mexErrMsgTxt("Error: the ending frame must not be less than the starting frame\n"); return; } myDrawCompleteProc = NewMovieDrawingCompleteUPP(DrawCompleteProc); EnterMovies(); if (NativePathNameToFSSpec(location, &theFSSpec, 0) || OpenMovieFile(&theFSSpec, &resRefNum, 0) || NewMovieFromFile(&theMovie, resRefNum, &actualResId, 0, 0, 0)) { mexErrMsgTxt("Error: failed to open movie\n"); return; } if (resRefNum != -1) CloseMovieFile(resRefNum); GetMovieBox(theMovie, &bounds); QTNewGWorld(&offWorld, k32ARGBPixelFormat, &bounds, NULL, NULL, 0); LockPixels(GetGWorldPixMap(offWorld)); SetGWorld(offWorld, NULL); thePlayer = NewMovieController(theMovie, &bounds, mcTopLeftMovie | mcNotVisible); SetMovieGWorld(theMovie, offWorld, NULL); SetMovieActive(theMovie, true); SetMovieDrawingCompleteProc(theMovie, movieDrawingCallWhenChanged, myDrawCompleteProc, (long) offWorld); GetMovieTime(theMovie, &myTimeRecord); duration = GetMovieDuration(theMovie); // Compute the number of frames for allocation of output structure frame_count = 0; while ((frame_end == 0 || frame_count < frame_end) && GetMovieTime(theMovie, NULL) < duration) { frame_count++; MCDoAction(thePlayer, mcActionStep, (Ptr) myStep); } SetMovieTime(theMovie, &myTimeRecord); // Ignore frames greater than those in the file if (frame_end == 0 || frame_count < frame_end) frame_end = frame_count; cdims[0] = frame_end - frame_start + 1; // Indices are one-based cdims[1] = 1; plhs[0] = mxCreateCellArray(2, cdims); // Step through the movie and save the frame when in the chosen interval // Note: the step size seems to be handled as a short internally. // Using anything greater than 32758 will seek to an incorrect frame frame_num = 1; while (frame_num <= frame_end) { MCDoAction(thePlayer, mcActionStep, (Ptr) myStep); if (frame_num >= frame_start) { MCIdle(thePlayer); mxSetCell(plhs[0], frame_num - frame_start, framedata); } frame_num++; } UnlockPixels(GetGWorldPixMap (offWorld)); DisposeGWorld(offWorld); DisposeMovieController (thePlayer); DisposeMovie(theMovie); DisposeMovieDrawingCompleteUPP(myDrawCompleteProc); ExitMovies(); return; }
//--------------------------------------------------------------------------- bool ofQuickTimePlayer::loadMovie(string name){ //-------------------------------------- #ifdef OF_VIDEO_PLAYER_QUICKTIME //-------------------------------------- initializeQuicktime(); // init quicktime closeMovie(); // if we have a movie open, close it bLoaded = false; // try to load now if( name.substr(0, 7) == "http://" || name.substr(0,7) == "rtsp://" ){ if(! createMovieFromURL(name, moviePtr) ) return false; }else{ name = ofToDataPath(name); if( !createMovieFromPath((char *)name.c_str(), moviePtr) ) return false; } bool bDoWeAlreadyHaveAGworld = false; if (width != 0 && height != 0){ bDoWeAlreadyHaveAGworld = true; } Rect movieRect; GetMovieBox(moviePtr, &(movieRect)); if (bDoWeAlreadyHaveAGworld){ // is the gworld the same size, then lets *not* de-allocate and reallocate: if (width == movieRect.right && height == movieRect.bottom){ SetMovieGWorld (moviePtr, offscreenGWorld, nil); } else { width = movieRect.right; height = movieRect.bottom; pixels.clear(); delete(offscreenGWorldPixels); if ((offscreenGWorld)) DisposeGWorld((offscreenGWorld)); createImgMemAndGWorld(); } } else { width = movieRect.right; height = movieRect.bottom; createImgMemAndGWorld(); } if (moviePtr == NULL){ return false; } //----------------- callback method myDrawCompleteProc = NewMovieDrawingCompleteUPP (DrawCompleteProc); SetMovieDrawingCompleteProc (moviePtr, movieDrawingCallWhenChanged, myDrawCompleteProc, (long)this); // ------------- get the total # of frames: nFrames = 0; TimeValue curMovieTime; curMovieTime = 0; TimeValue duration; //OSType whichMediaType = VIDEO_TYPE; // mingw chokes on this OSType whichMediaType = FOUR_CHAR_CODE('vide'); short flags = nextTimeMediaSample + nextTimeEdgeOK; while( curMovieTime >= 0 ) { nFrames++; GetMovieNextInterestingTime(moviePtr,flags,1,&whichMediaType,curMovieTime,0,&curMovieTime,&duration); flags = nextTimeMediaSample; } nFrames--; // there's an extra time step at the end of themovie // ------------- get some pixels in there ------ GoToBeginningOfMovie(moviePtr); SetMovieActiveSegment(moviePtr, -1,-1); MoviesTask(moviePtr,0); #if defined(TARGET_OSX) && defined(__BIG_ENDIAN__) convertPixels(offscreenGWorldPixels, pixels.getPixels(), width, height); #endif bStarted = false; bLoaded = true; bPlaying = false; bHavePixelsChanged = false; speed = 1; return true; //-------------------------------------- #endif //-------------------------------------- }
void QTCmpr_CompressSequence (WindowObject theWindowObject) { ComponentInstance myComponent = NULL; GWorldPtr myImageWorld = NULL; // the graphics world we draw the images in PixMapHandle myPixMap = NULL; Movie mySrcMovie = NULL; Track mySrcTrack = NULL; Movie myDstMovie = NULL; Track myDstTrack = NULL; Media myDstMedia = NULL; Rect myRect; PicHandle myPicture = NULL; CGrafPtr mySavedPort = NULL; GDHandle mySavedDevice = NULL; SCTemporalSettings myTimeSettings; SCDataRateSettings myRateSettings; FSSpec myFile; Boolean myIsSelected = false; Boolean myIsReplacing = false; short myRefNum = -1; StringPtr myMoviePrompt = QTUtils_ConvertCToPascalString(kQTCSaveMoviePrompt); StringPtr myMovieFileName = QTUtils_ConvertCToPascalString(kQTCSaveMovieFileName); MatrixRecord myMatrix; ImageDescriptionHandle myImageDesc = NULL; TimeValue myCurMovieTime = 0L; TimeValue myOrigMovieTime = 0L; // current movie time, when compression is begun short myFrameNum; long myFlags = 0L; long myNumFrames = 0L; long mySrcMovieDuration = 0L; // duration of source movie OSErr myErr = noErr; #if USE_ASYNC_COMPRESSION ICMCompletionProcRecord myICMComplProcRec; ICMCompletionProcRecordPtr myICMComplProcPtr = NULL; OSErr myICMComplProcErr = noErr; myICMComplProcRec.completionProc = NULL; myICMComplProcRec.completionRefCon = 0L; #endif if (theWindowObject == NULL) goto bail; ////////// // // get the movie and the first video track in the movie // ////////// mySrcMovie = (**theWindowObject).fMovie; if (mySrcMovie == NULL) goto bail; mySrcTrack = GetMovieIndTrackType(mySrcMovie, 1, VideoMediaType, movieTrackMediaType); if (mySrcTrack == NULL) goto bail; // stop the movie; we don't want it to be playing while we're (re)compressing it SetMovieRate(mySrcMovie, (Fixed)0L); // get the current movie time, when compression is begun; we'll restore this later myOrigMovieTime = GetMovieTime(mySrcMovie, NULL); ////////// // // configure and display the Standard Image Compression dialog box // ////////// // open an instance of the Standard Image Compression dialog component myComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType); if (myComponent == NULL) goto bail; // turn off "best depth" option in the compression dialog, because all of our // buffering is done at 32-bits (regardless of the depth of the source data) // // a more ambitious approach would be to loop through each of the video sample // descriptions in each of the video tracks looking for the deepest depth, and // using that for the best depth; better yet, we could find out which compressors // were used and set one of those as the default in the compression dialog SCGetInfo(myComponent, scPreferenceFlagsType, &myFlags); myFlags &= ~scShowBestDepth; SCSetInfo(myComponent, scPreferenceFlagsType, &myFlags); // because we are recompressing a movie that may have a variable frame rate, // we want to allow the user to leave the frame rate text field blank (in which // case we can preserve the frame durations of the source movie); if the user // enters a number, we will resample the movie at a new frame rate; if we don't // clear this flag, the compression dialog will not allow zero in the frame rate field // // NOTE: we could have set this flag above when we cleared the scShowBestDepth flag; // it is done here for clarity. SCGetInfo(myComponent, scPreferenceFlagsType, &myFlags); myFlags |= scAllowZeroFrameRate; SCSetInfo(myComponent, scPreferenceFlagsType, &myFlags); // get the number of video frames in the movie myNumFrames = QTUtils_GetFrameCount(mySrcTrack); // get the bounding rectangle of the movie, create a 32-bit GWorld with those // dimensions, and draw the movie poster picture into it; this GWorld will be // used for the test image in the compression dialog box and for rendering movie // frames myPicture = GetMoviePosterPict(mySrcMovie); if (myPicture == NULL) goto bail; GetMovieBox(mySrcMovie, &myRect); myErr = NewGWorld(&myImageWorld, 32, &myRect, NULL, NULL, 0L); if (myErr != noErr) goto bail; // get the pixmap of the GWorld; we'll lock the pixmap, just to be safe myPixMap = GetGWorldPixMap(myImageWorld); if (!LockPixels(myPixMap)) goto bail; // draw the movie poster image into the GWorld GetGWorld(&mySavedPort, &mySavedDevice); SetGWorld(myImageWorld, NULL); EraseRect(&myRect); DrawPicture(myPicture, &myRect); KillPicture(myPicture); SetGWorld(mySavedPort, mySavedDevice); // set the picture to be displayed in the dialog box; passing NULL for the rect // means use the entire image; passing 0 for the flags means to use the default // system method of displaying the test image, which is currently a combination // of cropping and scaling; personally, I prefer scaling (your mileage may vary) SCSetTestImagePixMap(myComponent, myPixMap, NULL, scPreferScaling); // install the custom procs, if requested // we can install two kinds of custom procedures for use in connection with // the standard dialog box: (1) a modal-dialog filter function, and (2) a hook // function to handle the custom button in the dialog box if (gUseExtendedProcs) QTCmpr_InstallExtendedProcs(myComponent, (long)myPixMap); // set up some default settings for the compression dialog SCDefaultPixMapSettings(myComponent, myPixMap, true); // clear out the default frame rate chosen by Standard Compression (a frame rate // of 0 means to use the rate of the source movie) myErr = SCGetInfo(myComponent, scTemporalSettingsType, &myTimeSettings); if (myErr != noErr) goto bail; myTimeSettings.frameRate = 0; SCSetInfo(myComponent, scTemporalSettingsType, &myTimeSettings); // request image compression settings from the user; in other words, put up the dialog box myErr = SCRequestSequenceSettings(myComponent); if (myErr == scUserCancelled) goto bail; // get a copy of the temporal settings the user entered; we'll need them for some // of our calculations (in a simpler application, we'd never have to look at them) SCGetInfo(myComponent, scTemporalSettingsType, &myTimeSettings); ////////// // // adjust the data rate [to be supplied][relevant only for movies that have sound tracks] // ////////// ////////// // // adjust the sample count // // if the user wants to resample the frame rate of the movie (as indicated a non-zero // value in the frame rate field) calculate the number of frames and duration for the new movie // ////////// if (myTimeSettings.frameRate != 0) { long myDuration = GetMovieDuration(mySrcMovie); long myTimeScale = GetMovieTimeScale(mySrcMovie); float myFloat = (float)myDuration * myTimeSettings.frameRate; myNumFrames = myFloat / myTimeScale / 65536; if (myNumFrames == 0) myNumFrames = 1; } ////////// // // get the name and location of the new movie file // ////////// // prompt the user for a file to put the compressed image into; in theory, the name // should have a file extension appropriate to the type of compressed data selected by the user; // this is left as an exercise for the reader QTFrame_PutFile(myMoviePrompt, myMovieFileName, &myFile, &myIsSelected, &myIsReplacing); if (!myIsSelected) goto bail; // delete any existing file of that name if (myIsReplacing) { myErr = DeleteMovieFile(&myFile); if (myErr != noErr) goto bail; } ////////// // // create the target movie // ////////// myErr = CreateMovieFile(&myFile, sigMoviePlayer, smSystemScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &myRefNum, &myDstMovie); if (myErr != noErr) goto bail; // create a new video movie track with the same dimensions as the entire source movie myDstTrack = NewMovieTrack(myDstMovie, (long)(myRect.right - myRect.left) << 16, (long)(myRect.bottom - myRect.top) << 16, kNoVolume); if (myDstTrack == NULL) goto bail; // create a media for the new track with the same time scale as the source movie; // because the time scales are the same, we don't have to do any time scale conversions. myDstMedia = NewTrackMedia(myDstTrack, VIDEO_TYPE, GetMovieTimeScale(mySrcMovie), 0, 0); if (myDstMedia == NULL) goto bail; // copy the user data and settings from the source to the dest movie CopyMovieSettings(mySrcMovie, myDstMovie); // set movie matrix to identity and clear the movie clip region (because the conversion // process transforms and composites all video tracks into one untransformed video track) SetIdentityMatrix(&myMatrix); SetMovieMatrix(myDstMovie, &myMatrix); SetMovieClipRgn(myDstMovie, NULL); // set the movie to highest quality imaging SetMoviePlayHints(mySrcMovie, hintsHighQuality, hintsHighQuality); myImageDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); if (myImageDesc == NULL) goto bail; // prepare for adding frames to the movie myErr = BeginMediaEdits(myDstMedia); if (myErr != noErr) goto bail; ////////// // // compress the image sequence // // we are going to step through the source movie, compress each frame, and then add // the compressed frame to the destination movie // ////////// myErr = SCCompressSequenceBegin(myComponent, myPixMap, NULL, &myImageDesc); if (myErr != noErr) goto bail; #if USE_ASYNC_COMPRESSION myFlags = codecFlagUpdatePrevious + codecFlagUpdatePreviousComp + codecFlagLiveGrab; SCSetInfo(myComponent, scCodecFlagsType, &myFlags); #endif // clear out our image GWorld and set movie to draw into it SetGWorld(myImageWorld, NULL); EraseRect(&myRect); SetMovieGWorld(mySrcMovie, myImageWorld, GetGWorldDevice(myImageWorld)); // set current time value to beginning of the source movie myCurMovieTime = 0; // get a value we'll need inside the loop mySrcMovieDuration = GetMovieDuration(mySrcMovie); // loop through all of the interesting times we counted above for (myFrameNum = 0; myFrameNum < myNumFrames; myFrameNum++) { short mySyncFlag; TimeValue myDuration; long myDataSize; Handle myCompressedData; ////////// // // get the next frame of the source movie // ////////// // if we are resampling the movie, step to the next frame if (myTimeSettings.frameRate) { myCurMovieTime = myFrameNum * mySrcMovieDuration / (myNumFrames - 1); myDuration = mySrcMovieDuration / myNumFrames; } else { OSType myMediaType = VIDEO_TYPE; myFlags = nextTimeMediaSample; // if this is the first frame, include the frame we are currently on if (myFrameNum == 0) myFlags |= nextTimeEdgeOK; // if we are maintaining the frame durations of the source movie, // skip to the next interesting time and get the duration for that frame GetMovieNextInterestingTime(mySrcMovie, myFlags, 1, &myMediaType, myCurMovieTime, 0, &myCurMovieTime, &myDuration); } SetMovieTimeValue(mySrcMovie, myCurMovieTime); MoviesTask(mySrcMovie, 0); MoviesTask(mySrcMovie, 0); MoviesTask(mySrcMovie, 0); // if data rate constraining is being done, tell Standard Compression the // duration of the current frame in milliseconds; we only need to do this // if the frames have variable durations if (!SCGetInfo(myComponent, scDataRateSettingsType, &myRateSettings)) { myRateSettings.frameDuration = myDuration * 1000 / GetMovieTimeScale(mySrcMovie); SCSetInfo(myComponent, scDataRateSettingsType, &myRateSettings); } ////////// // // compress the current frame of the source movie and add it to the destination movie // ////////// // if SCCompressSequenceFrame completes successfully, myCompressedData will hold // a handle to the newly-compressed image data and myDataSize will be the size of // the compressed data (which will usually be different from the size of the handle); // also mySyncFlag will be a value that that indicates whether or not the frame is a // key frame (and which we pass directly to AddMediaSample); note that we do not need // to dispose of myCompressedData, since SCCompressSequenceEnd will do that for us #if !USE_ASYNC_COMPRESSION myErr = SCCompressSequenceFrame(myComponent, myPixMap, &myRect, &myCompressedData, &myDataSize, &mySyncFlag); if (myErr != noErr) goto bail; #else if (myICMComplProcPtr == NULL) { myICMComplProcRec.completionProc = NewICMCompletionProc(QTCmpr_CompletionProc); myICMComplProcRec.completionRefCon = (long)&myICMComplProcErr; myICMComplProcPtr = &myICMComplProcRec; } myICMComplProcErr = kAsyncDefaultValue; myErr = SCCompressSequenceFrameAsync(myComponent, myPixMap, &myRect, &myCompressedData, &myDataSize, &mySyncFlag, myICMComplProcPtr); if (myErr != noErr) goto bail; // spin our wheels while we're waiting for the compress call to complete while (myICMComplProcErr == kAsyncDefaultValue) { EventRecord myEvent; WaitNextEvent(0, &myEvent, 60, NULL); SCAsyncIdle(myComponent); } myErr = myICMComplProcErr; #endif myErr = AddMediaSample(myDstMedia, myCompressedData, 0, myDataSize, myDuration, (SampleDescriptionHandle)myImageDesc, 1, mySyncFlag, NULL); if (myErr != noErr) goto bail; } // close the compression sequence; this will dispose of the image description // and compressed data handles allocated by SCCompressSequenceBegin SCCompressSequenceEnd(myComponent); ////////// // // add the media data to the destination movie // ////////// myErr = EndMediaEdits(myDstMedia); if (myErr != noErr) goto bail; InsertMediaIntoTrack(myDstTrack, 0, 0, GetMediaDuration(myDstMedia), fixed1); // add the movie resource to the dst movie file. myErr = AddMovieResource(myDstMovie, myRefNum, NULL, NULL); if (myErr != noErr) goto bail; // flatten the movie data [to be supplied] // close the movie file CloseMovieFile(myRefNum); bail: // close the Standard Compression component if (myComponent != NULL) CloseComponent(myComponent); if (mySrcMovie != NULL) { // restore the source movie's original graphics port and device SetMovieGWorld(mySrcMovie, mySavedPort, mySavedDevice); // restore the source movie's original movie time SetMovieTimeValue(mySrcMovie, myOrigMovieTime); } // restore the original graphics port and device SetGWorld(mySavedPort, mySavedDevice); // delete the GWorld we were drawing frames into if (myImageWorld != NULL) DisposeGWorld(myImageWorld); #if USE_ASYNC_COMPRESSION if (myICMComplProcRec.completionProc != NULL) DisposeICMCompletionUPP(myICMComplProcRec.completionProc); #endif free(myMoviePrompt); free(myMovieFileName); }