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; }
static DWORD WINAPI QTSplitter_thread(LPVOID data) { QTSplitter *This = (QTSplitter *)data; HRESULT hr = S_OK; TimeValue next_time; CVPixelBufferRef pixelBuffer = NULL; OSStatus err; TimeRecord tr; WaitForSingleObject(This->runEvent, -1); EnterCriticalSection(&This->csReceive); if (!This->pQTMovie) { LeaveCriticalSection(&This->csReceive); return 0; } This->state = State_Running; /* Prime the pump: Needed for MPEG streams */ GetMovieNextInterestingTime(This->pQTMovie, nextTimeEdgeOK | nextTimeStep, 0, NULL, This->movie_time, 1, &next_time, NULL); GetMovieTime(This->pQTMovie, &tr); if (This->pAudio_Pin) QT_Create_Extract_Session(This); LeaveCriticalSection(&This->csReceive); do { LONGLONG tStart=0, tStop=0; LONGLONG mStart=0, mStop=0; float time; EnterCriticalSection(&This->csReceive); if (!This->pQTMovie) { LeaveCriticalSection(&This->csReceive); return 0; } GetMovieNextInterestingTime(This->pQTMovie, nextTimeStep, 0, NULL, This->movie_time, 1, &next_time, NULL); if (next_time == -1) { TRACE("No next time\n"); LeaveCriticalSection(&This->csReceive); break; } tr.value = SInt64ToWide(next_time); SetMovieTime(This->pQTMovie, &tr); MoviesTask(This->pQTMovie,0); QTVisualContextTask(This->vContext); TRACE("In loop at time %ld\n",This->movie_time); TRACE("In Next time %ld\n",next_time); mStart = This->movie_time; mStop = next_time; time = (float)(This->movie_time - This->movie_start) / This->movie_scale; tStart = time * 10000000; time = (float)(next_time - This->movie_start) / This->movie_scale; tStop = time * 10000000; /* Deliver Audio */ if (This->pAudio_Pin && This->pAudio_Pin->pin.pin.pConnectedTo && This->aSession) { int data_size=0; BYTE* ptr; IMediaSample *sample = NULL; AudioBufferList aData; UInt32 flags; UInt32 frames; WAVEFORMATEX* pvi; float duration; pvi = (WAVEFORMATEX*)This->pAudio_Pin->pmt->pbFormat; hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->pAudio_Pin->pin, &sample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Audio: Unable to get delivery buffer (%x)\n", hr); goto audio_error; } hr = IMediaSample_GetPointer(sample, &ptr); if (FAILED(hr)) { ERR("Audio: Unable to get pointer to buffer (%x)\n", hr); goto audio_error; } duration = (float)next_time / This->movie_scale; time = (float)This->movie_time / This->movie_scale; duration -= time; frames = pvi->nSamplesPerSec * duration; TRACE("Need audio for %f seconds (%li frames)\n",duration,frames); data_size = IMediaSample_GetSize(sample); if (data_size < frames * pvi->nBlockAlign) FIXME("Audio buffer is too small\n"); aData.mNumberBuffers = 1; aData.mBuffers[0].mNumberChannels = pvi->nChannels; aData.mBuffers[0].mDataByteSize = data_size; aData.mBuffers[0].mData = ptr; err = MovieAudioExtractionFillBuffer(This->aSession, &frames, &aData, &flags); if (frames == 0) { TimeRecord etr; /* Ran out of frames, Restart the extraction session */ TRACE("Restarting extraction session\n"); MovieAudioExtractionEnd(This->aSession); This->aSession = NULL; QT_Create_Extract_Session(This); etr = tr; etr.value = SInt64ToWide(This->movie_time); MovieAudioExtractionSetProperty(This->aSession, kQTPropertyClass_MovieAudioExtraction_Movie, kQTMovieAudioExtractionMoviePropertyID_CurrentTime, sizeof(TimeRecord), &etr ); frames = pvi->nSamplesPerSec * duration; aData.mNumberBuffers = 1; aData.mBuffers[0].mNumberChannels = pvi->nChannels; aData.mBuffers[0].mDataByteSize = data_size; aData.mBuffers[0].mData = ptr; MovieAudioExtractionFillBuffer(This->aSession, &frames, &aData, &flags); } TRACE("Got %i frames\n",(int)frames); IMediaSample_SetActualDataLength(sample, frames * pvi->nBlockAlign); IMediaSample_SetMediaTime(sample, &mStart, &mStop); IMediaSample_SetTime(sample, &tStart, &tStop); hr = OutputQueue_Receive(This->pAudio_Pin->queue, sample); TRACE("Audio Delivered (%x)\n",hr); audio_error: if (sample) IMediaSample_Release(sample); } else TRACE("Audio Pin not connected or no Audio\n"); /* Deliver Video */ if (This->pVideo_Pin && QTVisualContextIsNewImageAvailable(This->vContext,0)) { err = QTVisualContextCopyImageForTime(This->vContext, NULL, NULL, &pixelBuffer); if (err == noErr) { int data_size=0; BYTE* ptr; IMediaSample *sample = NULL; hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->pVideo_Pin->pin, &sample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Video: Unable to get delivery buffer (%x)\n", hr); goto video_error; } data_size = IMediaSample_GetSize(sample); if (data_size < This->outputSize) { ERR("Sample size is too small %d < %d\n", data_size, This->outputSize) ; hr = E_FAIL; goto video_error; } hr = IMediaSample_GetPointer(sample, &ptr); if (FAILED(hr)) { ERR("Video: Unable to get pointer to buffer (%x)\n", hr); goto video_error; } hr = AccessPixelBufferPixels( pixelBuffer, ptr); if (FAILED(hr)) { ERR("Failed to access Pixels\n"); goto video_error; } IMediaSample_SetActualDataLength(sample, This->outputSize); IMediaSample_SetMediaTime(sample, &mStart, &mStop); IMediaSample_SetTime(sample, &tStart, &tStop); hr = OutputQueue_Receive(This->pVideo_Pin->queue, sample); TRACE("Video Delivered (%x)\n",hr); video_error: if (sample) IMediaSample_Release(sample); if (pixelBuffer) CVPixelBufferRelease(pixelBuffer); } } else TRACE("No video to deliver\n"); This->movie_time = next_time; LeaveCriticalSection(&This->csReceive); } while (hr == S_OK); This->state = State_Stopped; if (This->pAudio_Pin) OutputQueue_EOS(This->pAudio_Pin->queue); if (This->pVideo_Pin) OutputQueue_EOS(This->pVideo_Pin->queue); return hr; }
void PlaySound_QuickTime(const char *cSoundFilename) { int err; Str255 pSoundFilename; /* file pathname in Pascal-string format */ FSSpec fsSoundFile; /* movie file location descriptor */ short resRefNum; /* open movie file reference */ if (!fQTInitialised) { pthread_mutex_init(&mutexQTAccess, NULL); ListCreate(&movielist); fQTInitialised = TRUE; } /* QuickTime is NOT reentrant in Mac OS (it is in MS Windows!) */ pthread_mutex_lock(&mutexQTAccess); EnterMovies(); /* can be called multiple times */ err = NativePathNameToFSSpec(cSoundFilename, &fsSoundFile, 0); if (err != 0) { outputf(_("PlaySound_QuickTime: error #%d, can't find %s.\n"), err, cSoundFilename); } else { /* open movie (WAV or whatever) file */ err = OpenMovieFile(&fsSoundFile, &resRefNum, fsRdPerm); if (err != 0) { outputf(_("PlaySound_QuickTime: error #%d opening %s.\n"), err, cSoundFilename); } else { /* create movie from movie file */ Movie *movie = (Movie *) malloc(sizeof(Movie)); err = NewMovieFromFile(movie, resRefNum, NULL, NULL, 0, NULL); CloseMovieFile(resRefNum); if (err != 0) { outputf(_("PlaySound_QuickTime: error #%d reading %s.\n"), err, cSoundFilename); } else { /* reset movie timebase */ TimeRecord t = { 0 }; t.base = GetMovieTimeBase(*movie); SetMovieTime(*movie, &t); /* add movie to list of running movies */ ListInsert(&movielist, movie); /* run movie */ StartMovie(*movie); } } } pthread_mutex_unlock(&mutexQTAccess); if (!fQTPlaying) { /* launch playing thread if necessary */ int err; pthread_t qtthread; fQTPlaying = TRUE; err = pthread_create(&qtthread, 0L, Thread_PlaySound_QuickTime, NULL); if (err == 0) pthread_detach(qtthread); else fQTPlaying = FALSE; } }