void QTVideo_CreateMyVideoTrack(Movie theMovie) { Track theTrack; Media theMedia; OSErr err = noErr; Rect trackFrame = {0,0,100,320}; theTrack = NewMovieTrack (theMovie, FixRatio(trackFrame.right,1), FixRatio(trackFrame.bottom,1), kNoVolume); CheckError( GetMoviesError(), "NewMovieTrack error" ); theMedia = NewTrackMedia (theTrack, VideoMediaType, kVideoTimeScale, /* Video Time Scale */ nil, 0); CheckError( GetMoviesError(), "NewTrackMedia error" ); err = BeginMediaEdits (theMedia); CheckError( err, "BeginMediaEdits error" ); QTVideo_AddVideoSamplesToMedia (theMedia, &trackFrame); err = EndMediaEdits (theMedia); CheckError( err, "EndMediaEdits error" ); err = InsertMediaIntoTrack (theTrack, kTrackStart,/* track start time */ kMediaStart, /* media start time */ GetMediaDuration (theMedia), fixed1); CheckError( err, "InsertMediaIntoTrack error" ); }
static void QT_CreateMyVideoTrack(int rectx, int recty, ReportList *reports) { OSErr err = noErr; Rect trackFrame; // MatrixRecord myMatrix; trackFrame.top = 0; trackFrame.left = 0; trackFrame.bottom = recty; trackFrame.right = rectx; qtexport->theTrack = NewMovieTrack (qtexport->theMovie, FixRatio(trackFrame.right,1), FixRatio(trackFrame.bottom,1), 0); CheckError( GetMoviesError(), "NewMovieTrack error", reports ); // SetIdentityMatrix(&myMatrix); // ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0); // TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom)); // SetMovieMatrix(qtexport->theMovie, &myMatrix); qtexport->theMedia = NewTrackMedia (qtexport->theTrack, VideoMediaType, qtdata->kVideoTimeScale, nil, 0); CheckError( GetMoviesError(), "NewTrackMedia error", reports ); err = BeginMediaEdits (qtexport->theMedia); CheckError( err, "BeginMediaEdits error", reports ); QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty, reports); }
/* Given a reference to the media that contains the sample data for a track, calculate the static frame rate. */ OSErr MediaGetStaticFrameRate(Media inMovieMedia, double *outFPS) { *outFPS = 0; /* get the number of samples in the media */ long sampleCount = GetMediaSampleCount(inMovieMedia); OSErr err = GetMoviesError(); if (sampleCount && err == noErr) { /* find the media duration */ //Quicktime 7.0 code //TimeValue64 duration = GetMediaDisplayDuration(inMovieMedia); TimeValue64 duration = GetMediaDuration(inMovieMedia); err = GetMoviesError(); if (err == noErr) { /* get the media time scale */ TimeValue64 timeScale = GetMediaTimeScale(inMovieMedia); err = GetMoviesError(); if (err == noErr) { /* calculate the frame rate: frame rate = (sample count * media time scale) / media duration */ *outFPS = (double)sampleCount * (double)timeScale / (double)duration; } } } return err; }
OSErr QTDR_CreateTrackInRAM (Movie theMovie) { Track myTrack = NULL; Media myMedia = NULL; Handle myDataRef = NULL; unsigned long myAtomHeader[2]; OSErr myErr = noErr; if (theMovie == NULL) return(paramErr); myDataRef = NewHandleClear(sizeof(Handle) + sizeof(char)); if (myDataRef == NULL) return(MemError()); myAtomHeader[0] = EndianU32_NtoB(sizeof(myAtomHeader)); myAtomHeader[1] = EndianU32_NtoB(kDataRefExtensionInitializationData); myErr = PtrAndHand(myAtomHeader, myDataRef, sizeof(myAtomHeader)); if (myErr != noErr) goto bail; // create the movie track and media myTrack = NewMovieTrack(theMovie, FixRatio(kVideoTrackWidth, 1), FixRatio(kVideoTrackHeight, 1), kNoVolume); myErr = GetMoviesError(); if (myErr != noErr) goto bail; myMedia = NewTrackMedia(myTrack, VideoMediaType, kVideoTimeScale, myDataRef, HandleDataHandlerSubType); myErr = GetMoviesError(); if (myErr != noErr) goto bail; // create the media samples myErr = BeginMediaEdits(myMedia); if (myErr != noErr) goto bail; myErr = QTDR_AddVideoSamplesToMedia(myMedia, kVideoTrackWidth, kVideoTrackHeight); if (myErr != noErr) goto bail; myErr = EndMediaEdits(myMedia); if (myErr != noErr) goto bail; // add the media to the track myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1); bail: if (myDataRef != NULL) DisposeHandle(myDataRef); return(myErr); }
static OSStatus setup_video(void) { //Add video track videoTrack = NewMovieTrack(movie, video_width << 16, video_height << 16, 0); OSStatus theError = GetMoviesError(); if (theError) { log_debug("quicktime_video: error creating movie track"); return theError; } //Create video track media videoMedia = NewTrackMedia(videoTrack, VideoMediaType, timeScale, 0, 0); theError = GetMoviesError(); if (theError) { log_debug("quicktime_video: error creating track media!"); return theError; } //Prepare media for editing theError = BeginMediaEdits(videoMedia); if (theError) { log_debug("quicktime_video: error beginning media edits!"); return theError; } // ----- Setup Codec ----- CodecType codec = (CodecType)video_codec; // Create compression session ICMEncodedFrameOutputRecord record = { FrameOutputCallback, NULL, NULL }; theError = ICMCompressionSessionCreate(kCFAllocatorDefault, video_width, video_height, codec, timeScale, NULL /*options*/, NULL, &record, &videoCompressionSession); if (theError) { log_debug("quicktime_video: error creating compression session!"); return theError; } // ----- PixelBuffer ----- theError = CVPixelBufferCreate(NULL, video_width, video_height, kCVPixelFormatType_24RGB, NULL, &pixelBuffer); if (theError) { log_debug("quicktime_video: error creating pixel buffer!"); return theError; } CVPixelBufferRetain(pixelBuffer); video_ready = 1; return noErr; }
void ofxQtAudioRecorder::closeMovie(){ short movieResId = movieInDataForkResID; AddMovieResource(movie, movieResRefNum, &movieResId, NULL); OSErr err = GetMoviesError(); if(err != noErr){ printf("error adding movie resource\n"); return; } if(movieResRefNum != 0) { CloseMovieFile(movieResRefNum); } if(movie != NULL) { DisposeMovie(movie); } if(soundDesc != NULL) { DisposeHandle((Handle)soundDesc); soundDesc = NULL; } movie = NULL; movieResRefNum = 0; audioMedia = NULL; audioTrack = NULL; printf("closed movie file\n"); }
/* returns the ImageDescriptionHandle for the track. If it's not a video track, return NULL */ static ImageDescriptionHandle track_image_description(VALUE obj) { OSErr osErr; /* restrict reporting to video track */ if (track_get_media_type(obj) != VideoMediaType) return NULL; SampleDescriptionHandle sample_description = NULL; sample_description = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); if (LMGetMemErr() != noErr) { rb_raise(eQuickTime, "Memory Error %d when determining image description", LMGetMemErr()); return NULL; } GetMediaSampleDescription(TRACK_MEDIA(obj), 1, sample_description); osErr = GetMoviesError(); if (osErr != noErr) { rb_raise(eQuickTime, "Movie Error %d when determining image description", osErr); DisposeHandle((Handle)sample_description); return NULL; } return (ImageDescriptionHandle)sample_description; }
void ofxQtAudioRecorder::prepareAudioRecording(int sampleRate, int numChannels_){ OSErr err = noErr; // create audio description and set format ID along with format flags, mBitsPerChannel and mBytesPerPacket AudioStreamBasicDescription asbd; numChannels = numChannels_; asbd.mSampleRate = sampleRate; asbd.mFormatID = kAudioFormatLinearPCM; asbd.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; // if multi-channel, the data format must be interleaved (non-interleaved is not allowed), // and you should set up the asbd accordingly asbd.mChannelsPerFrame = numChannels; // 2 (Stereo) // mBitsPerChannel = number of bits of sample data for each channel in a frame of data asbd.mBitsPerChannel = sizeof (Float32) * 8; // was 8 // 32-bit floating point PCM // mBytesPerFrame = number of bytes in a single sample frame of data // (bytes per channel) * (channels per frame) = 4 * 2 = 8 asbd.mBytesPerFrame = (asbd.mBitsPerChannel>>3) * asbd.mChannelsPerFrame; // // number of *bytes* per channel * channels per frame asbd.mFramesPerPacket = 1; // For PCM, frames per packet is always 1 // mBytesPerPacket = (bytes per frame) * (frames per packet) = 8 * 1 = 8 asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; //printf("bits per channel %i\n", asbd.mBitsPerChannel); //printf("bytes per frame %i - %i %i\n", asbd.mBytesPerFrame, (asbd.mBitsPerChannel>>3), asbd.mChannelsPerFrame); //printf("bytes per packet %i\n", asbd.mBytesPerPacket); err = QTSoundDescriptionCreate(&asbd, NULL, 0, NULL, 0, kQTSoundDescriptionKind_Movie_Version2, &soundDesc); checkErr(0x0200); audioTrack = NewMovieTrack(movie, Long2Fix(0), Long2Fix(0), kFullVolume); err = GetMoviesError(); checkErr(0x0201); audioMedia = NewTrackMedia(audioTrack, SoundMediaType, sampleRate, NULL, 0); err = GetMoviesError(); checkErr(0x0202); return; }
OSErr QTCode_GetStartPointOfFirstVideoSample(Movie theMovie, TimeValue *startPoint) { OSErr anErr = noErr; OSType media = VideoMediaType; *startPoint = -1; GetMovieNextInterestingTime(theMovie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0, fixed1, startPoint, NULL); anErr = GetMoviesError(); return anErr; }
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); }
TLevelWriter3gp::TLevelWriter3gp(const TFilePath &path, TPropertyGroup *winfo) : TLevelWriter(path, winfo), m_initDone(false), m_IOError(QTNoError), m_pixmap(0), m_compressedData(0), m_gworld(0), m_videoMedia(0), m_videoTrack(0), m_movie(0), m_cancelled(false), m_soundDataRef(0), m_hSoundMovieData(0) { m_frameRate = 12.; QDErr err; //FSSpec fspec; if (QuickTimeStuff::instance()->getStatus() != noErr) { m_IOError = QTNotInstalled; throw TImageException(m_path, buildQTErrorString(m_IOError)); } m_movie = NewMovie(0); if ((err = GetMoviesError() != noErr)) throw TImageException(getFilePath(), "can't create movie"); }
bool qtCanvas::Impl::setupMovie() { OSErr err; Handle dataRefH = nil; OSType dataRefType = 0; err = QTNewDataReferenceFromFullPathCFString( mPath, (UInt32)kQTNativeDefaultPathStyle, 0, &dataRefH, &dataRefType); CheckError(err, "QTNewDataReferenceFromFullPathCFString"); CreateMovieStorage(dataRefH, dataRefType, 'TVOD', smSystemScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile | newMovieActive, &mDataHandler, &mMovie); CheckMoviesError("CreateMovieStorage"); CheckError((OSErr)((nil != mMovie) ? noErr : -1), "CreateMovieStorage movie"); return (err == noErr) && (GetMoviesError() == noErr) && (nil != mMovie); }
//------------------------------------------------------ bool ofVideoGrabber::qtInitSeqGrabber(){ if (bSgInited != true){ OSErr err = noErr; ComponentDescription theDesc; Component sgCompID; // this crashes when we get to // SGNewChannel // we get -9405 as error code for the channel // ----------------------------------------- // gSeqGrabber = OpenDefaultComponent(SeqGrabComponentType, 0); // this seems to work instead (got it from hackTV) // ----------------------------------------- theDesc.componentType = SeqGrabComponentType; theDesc.componentSubType = NULL; theDesc.componentManufacturer = 'appl'; theDesc.componentFlags = NULL; theDesc.componentFlagsMask = NULL; sgCompID = FindNextComponent (NULL, &theDesc); // ----------------------------------------- if (sgCompID == NULL){ ofLog(OF_LOG_ERROR, "error:FindNextComponent did not return a valid component"); return false; } gSeqGrabber = OpenComponent(sgCompID); err = GetMoviesError(); if (gSeqGrabber == NULL || err) { ofLog(OF_LOG_ERROR, "error: can't get default sequence grabber component"); return false; } err = SGInitialize(gSeqGrabber); if (err != noErr) { ofLog(OF_LOG_ERROR, "error: can't initialize sequence grabber component"); return false; } err = SGSetDataRef(gSeqGrabber, 0, 0, seqGrabDontMakeMovie); if (err != noErr) { ofLog(OF_LOG_ERROR, "error: can't set the destination data reference"); return false; } // windows crashes w/ out gworld, make a dummy for now... // this took a long time to figure out. err = SGSetGWorld(gSeqGrabber, 0, 0); if (err != noErr) { ofLog(OF_LOG_ERROR, "error: setting up the gworld"); return false; } err = SGNewChannel(gSeqGrabber, VideoMediaType, &(gVideoChannel)); if (err != noErr) { ofLog(OF_LOG_ERROR, "error: creating a channel. Check if you have any qt capable cameras attached"); return false; } bSgInited = true; return true; } return false; }
void QTSound_CreateMySoundTrack (Movie theMovie) { Track theTrack; Media theMedia; Handle sndHandle = nil; SoundDescriptionHandle sndDesc = nil; long sndDataOffset; long sndDataSize; long numSamples; OSErr err = noErr; #if TARGET_OS_WIN32 char path[MAX_PATH+1]; short resID; FSSpec fsspec; fsspec.vRefNum = 0; fsspec.parID = 0; GetModuleFileName( NULL, path, MAX_PATH+1); NativePathNameToFSSpec((char *)&path, &fsspec, 0); /* open our application resource file so we can access the Macintosh 'snd ' resource */ resID = FSpOpenResFile(&fsspec, fsRdPerm); CheckError (ResError(), "FSpOpenResFile error" ); #endif sndHandle = GetResource ('snd ', kOurSoundResourceID); CheckError (ResError(), "GetResource error" ); if (sndHandle == nil) { return; } sndDesc = (SoundDescriptionHandle) NewHandle(4); CheckError (MemError(), "NewHandle error" ); QTSound_CreateSoundDescription (sndHandle, sndDesc, &sndDataOffset, &numSamples, &sndDataSize ); theTrack = NewMovieTrack (theMovie, 0, 0, kFullVolume); CheckError (GetMoviesError(), "NewMovieTrack error" ); theMedia = NewTrackMedia (theTrack, SoundMediaType, FixRound ((**sndDesc).sampleRate), nil, 0); CheckError (GetMoviesError(), "NewTrackMedia error" ); err = BeginMediaEdits (theMedia); CheckError( err, "BeginMediaEdits error" ); err = AddMediaSample(theMedia, sndHandle, sndDataOffset,/* offset in data */ sndDataSize, kSoundSampleDuration,/* duration of each sound sample */ (SampleDescriptionHandle) sndDesc, numSamples, kSyncSample,/* self-contained samples */ nil); CheckError( err, "AddMediaSample error" ); err = EndMediaEdits (theMedia); CheckError( err, "EndMediaEdits error" ); err = InsertMediaIntoTrack (theTrack, kTrackStart,/* track start time */ kMediaStart,/* media start time */ GetMediaDuration (theMedia), fixed1); CheckError( err, "InsertMediaIntoTrack error" ); if (sndDesc != nil) { DisposeHandle( (Handle)sndDesc); } }
int main( int argc, char **argv ) { Movie movie; Track track; Media media; short refNum; short resID = 0; Boolean wasChanged; OSErr err = noErr; FSSpec fsspec; AudioFormatAtomPtr outAudioAtom; CmpSoundHeader outSoundInfo; SoundComponentData theInputFormat, theOutputFormat; SoundConverter mySoundConverter = NULL; // SCFillBufferData scFillBufferData = { NULL }; Ptr pDecomBuffer0 = NULL, pDecomBuffer1 = NULL; long kMaxOutputBuffer = 64 * 1024; long noFrames = 0, niFrames = 0, noBytes = 0, noSamples = 0; #define MAX_BUFFER_SIZE 256 * 1024 * 1024 /** Initialise MovieToolbox */ EnterMovies(); /** Open the movie file from the first argument */ printf( "opening audio file: '%s'\n", argv[1] ); path2fss( &fsspec, argv[1] ); err = OpenMovieFile( &fsspec, &refNum, fsRdPerm ); if ( err != noErr ) { printf( "failed to open audio: %d\n", GetMoviesError() ); exit( -1 ); } /** Instantiate the movie */ err = NewMovieFromFile( &movie, refNum, &resID, NULL, newMovieActive, &wasChanged ); if ( err ) { printf( "failed to instantiate movie\n" ); exit( -1 ); } CloseMovieFile( refNum ); refNum = 0; /** Get the first sound track */ track = GetMovieIndTrackType( movie, 1, SoundMediaType, movieTrackMediaType ); if ( track == NULL ) { printf( "failed to get sound track\n" ); exit( -1 ); } /** Get the sound track media */ media = GetTrackMedia( track ); if ( media == NULL ) { printf( "failed to get media from audio track\n" ); exit( -1 ); } Size size; Handle extension; SoundDescriptionHandle sourceSoundDescription; sourceSoundDescription = (SoundDescriptionHandle)NewHandle(0); /** Get the description of the sample data */ GetMediaSampleDescription( media, 1, (SampleDescriptionHandle)sourceSoundDescription ); err = GetMoviesError(); if ( err ) { printf( "failed to get description of sample data\n" ); exit( -1 ); } extension = NewHandle( 0 ); // get the "magic" decompression atom // This extension to the SoundDescription information stores // data specific to a given audio decompressor. Some audio // decompression algorithms require a set of out-of-stream // values to configure the decompressor. err = GetSoundDescriptionExtension( (SoundDescriptionHandle)sourceSoundDescription, &extension, siDecompressionParams ); if ( noErr == err ) { size = GetHandleSize( extension ); printf( "transferring data to audio buffer: %d bytes\n", size ); HLock( extension ); outAudioAtom = (AudioFormatAtom*)NewPtr( size ); err = MemError(); // copy the atom data to our buffer... BlockMoveData( *extension, outAudioAtom, size ); HUnlock( extension ); } else { // if it doesn't have an atom, that's ok outAudioAtom = NULL; err = noErr; } /** Setup our sound header */ outSoundInfo.format = (*sourceSoundDescription)->dataFormat; outSoundInfo.numChannels = (*sourceSoundDescription)->numChannels; outSoundInfo.sampleSize = (*sourceSoundDescription)->sampleSize; outSoundInfo.sampleRate = (*sourceSoundDescription)->sampleRate; outSoundInfo.compressionID = (*sourceSoundDescription)->compressionID; float db = ((float)outSoundInfo.sampleRate)/(1<<16); printf( "sample: %d\tchannels: %d\tsample size: %d\tsample rate: %f\tcompressionID: %d\n", outSoundInfo.format, outSoundInfo.numChannels, outSoundInfo.sampleSize, db, outSoundInfo.compressionID ); DisposeHandle( extension ); DisposeHandle( (Handle)sourceSoundDescription ); /** * Now that we've figured out what the audio file is, allocate buffers * and so on for conversion and playback */ printf( "initialising input/output conversion buffers\n" ); /** setup input/output format for sound converter */ theInputFormat.flags = 0; theInputFormat.format = outSoundInfo.format; theInputFormat.numChannels = outSoundInfo.numChannels; theInputFormat.sampleSize = outSoundInfo.sampleSize; theInputFormat.sampleRate = outSoundInfo. sampleRate; theInputFormat.sampleCount = 0; theInputFormat.buffer = NULL; theInputFormat.reserved = 0; theOutputFormat.flags = 0; theOutputFormat.format = kSoundNotCompressed; theOutputFormat.numChannels = theInputFormat.numChannels; theOutputFormat.sampleSize = theInputFormat.sampleSize; theOutputFormat.sampleRate = theInputFormat.sampleRate; theOutputFormat.sampleCount = 0; theOutputFormat.buffer = NULL; theOutputFormat.reserved = 0; // variableCompression means we're going to use the commonFrameSize field and the kExtendedSoundCommonFrameSizeValid flag // scFillBufferData.isSourceVBR = (outSoundInfo.compressionID == variableCompression ); err = SoundConverterOpen( &theInputFormat, &theOutputFormat, &mySoundConverter ); if ( err != noErr ) { printf( "failed to open sound converter\n" ); exit( -1 ); } else { printf( "opened sound converter ok\n" ); } // this isn't crucial or even required for decompression only, but it does tell // the sound converter that we're cool with VBR audio Ptr tptr = NewPtr( 1 ); tptr[0] = 1; SoundConverterSetInfo( mySoundConverter, siClientAcceptsVBR, tptr ); free( tptr ); /** * Set up the sound converters decompresson 'environment' by passing * in the 'magic' decompression atom */ err = SoundConverterSetInfo( mySoundConverter, siDecompressionParams, outAudioAtom ); if ( err != noErr ) { printf( "failed to set sound converter info\n" ); exit( -1 ); } else { printf( "set sound converter info ok\n" ); } if ( outAudioAtom ) { DisposePtr( (Ptr)outAudioAtom ); } if ( siUnknownInfoType == err ) { // clear this error, the decompressor didn't // need the decompression atom and that's OK err = noErr; } else { // BailErr(err); } /** * The input buffer has to be large enough so GetMediaSample isn't * going to fail, your mileage may vary */ Handle inputBuffer = NewHandle( MAX_BUFFER_SIZE ); // HLock( inputBuffer ); /** Start the sound conversion */ err = SoundConverterBeginConversion(mySoundConverter); // BailErr(err); /** Extract compressed audio from media track */ TimeValue tperSample = 0; err = GetMediaSample( media, inputBuffer, 0, &noBytes, 0, NULL, &tperSample, NULL, NULL, 0, &noSamples, NULL ); if ( err != noErr ) { printf( "failed to fetch media sample data: %d\n", GetMoviesError() ); exit( -1 ); } else { printf( "media sample: %d (%d) bytes / %ld samples / %d per sample\n", noBytes, GetHandleSize( inputBuffer ), noSamples, tperSample ); } unsigned long niBytes = 0; SoundConverterGetBufferSizes( mySoundConverter, noBytes * noSamples, &niFrames, &niBytes, &noBytes ); printf( "buffer sizes: frames: %d\tibytes: %d\tobytes: %d\n", niFrames, niBytes, noBytes ); /** Convert into uncompressed audio */ Ptr outputBuffer = NewPtr( noBytes * 1.2 ); SoundConverterConvertBuffer( mySoundConverter, inputBuffer, noSamples /* niFrames */, outputBuffer, &noFrames, &noBytes ); printf( "converted: %d frames / %d bytes\n", noFrames, noBytes ); /** Shutdown the sound converter */ err = SoundConverterEndConversion( mySoundConverter, outputBuffer, &noFrames, &noBytes ); printf( "converted final: %d frames / %d bytes\n", noFrames, noBytes ); // HUnlock( inputBuffer ); /** We now should have decompressed audio for the input file */ /** * So, generate visuals using a sliding sample grid at the * given framerate */ /** Create a new movie clip with audio and video tracks */ /** PROJECTM CRAP HERE -- stuff frames into QuickTime */ /** Close movie file */ /** Shutdown MovieToolbox */ ExitMovies(); return 0; }
static bool CheckMoviesError(const char* name) { return CheckError(GetMoviesError(), name); }
void MolDisplayWin::WriteQTMovie(wxString & filepath) { //Create a QuickTime movie using the standard animation codecs with normal quality, and //temporal compression. The final file is flattened for cross platform compatability QTExport * QTOptions = new QTExport(this); //setup controls for the current data if (MainData->GetNumFrames() > 1) { //default to frame animation QTOptions->SetMovieChoice(0); } else { QTOptions->EnableFrameMovie(false); } if (MainData->cFrame->GetNumberNormalModes() <= 0) { QTOptions->EnableModeMovie(false); } if (QTOptions->ShowModal() != wxID_OK) { //user cancelled the operation QTOptions->Destroy(); return; } //retrieve the value of each option int MovieType = QTOptions->GetMovieChoice(); bool IncludeEPlot = QTOptions->AddEnergyPlot(); int compressorChoice = QTOptions->GetCompressorChoice(); int keyFrameRate = QTOptions->GetKeyFrameRate(); if (keyFrameRate < 0) keyFrameRate = 0; QTOptions->Destroy(); CodecType mCodec; switch (compressorChoice) { case 0: mCodec = kCinepakCodecType; break; case 1: mCodec = kGraphicsCodecType; break; case 2: mCodec = kAnimationCodecType; break; case 3: default: mCodec = kMPEG4VisualCodecType; } OSStatus s; OSErr myErr = myErr; FSSpec targetSpec; //ugh I need to get an FSSpec to hand to quicktime, but these calls only seem to work if //the file already exists... const char * t = filepath.mb_str(wxConvUTF8); FILE * temp = fopen(t, "wb"); fclose(temp); #ifdef __WXOSX_COCOA__ //This function is not found in the wxCocoa implementation, it is probably possible to work around it //Otherwise the code appears to link and run currently. However, it is probably better to redue the //code to use the Cocoa qtKit framework rather than the old Carbon QT library. //This path is not tested as the current Cocoa code does not properly support the extended save dialog. // void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) { OSStatus err = noErr; FSRef fsRef; wxMacPathToFSRef( filepath , &fsRef ); err = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL, NULL, &targetSpec, NULL); verify_noerr( err ); } #else wxMacFilename2FSSpec(filepath, &targetSpec); #endif Movie theMovie = NULL; FSSpec tempSpec = targetSpec; strcpy((char *) &(tempSpec.name[1]), "MacMolPlt8933tempMovie"); tempSpec.name[0] = 22; BeginOperation(); ProgressInd->ChangeText("Creating movie..."); myErr = EnterMovies(); //initialize the quicktime manager if (myErr != noErr) { FinishOperation(); MessageAlert("Error initializing QuickTime!"); return; } //Create the movie file and initialize file data //Use Quicktime creator code 'TVOD' instead of simpletext 'ttxt' short resRefNum = 0; short resId = 0; myErr = CreateMovieFile(&tempSpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile, &resRefNum, &theMovie); if (myErr != noErr) { MessageAlert("Error creating movie file!"); } else { bool KillEPlot = false; int width, height, savedEPlotWidth, savedEPlotHeight; glCanvas->GetClientSize(&width, &height); Rect lDisplayRect={0,0,0,0}; lDisplayRect.right = width; lDisplayRect.bottom = height; Rect gRect = lDisplayRect; Rect EPlotRect = lDisplayRect; //If we are including an energy plot add space for it here if (IncludeEPlot && (MovieType == 0)) { EPlotRect.left = EPlotRect.right; EPlotRect.right = EPlotRect.left + height; if (!energyPlotWindow) { energyPlotWindow = new EnergyPlotDialog(this); KillEPlot = true; } else { energyPlotWindow->GetSize(&savedEPlotWidth, &savedEPlotHeight); } gRect.right += height; width += height; energyPlotWindow->Show(false); energyPlotWindow->SetSize(height, height); energyPlotWindow->Update(); //This is needed to initialise the window if we just created it } LocalToGlobal ((Point *) &(gRect.top)); LocalToGlobal ((Point *) &(gRect.bottom)); WindowRef TempWindow; s = CreateNewWindow(kDocumentWindowClass, kWindowNoAttributes, &gRect, &TempWindow); if (s == noErr) { //Create the video track Track theTrack = NewMovieTrack (theMovie, FixRatio(width,1), FixRatio(height,1), kNoVolume); if ((noErr == GetMoviesError())&&theTrack) { Media theMedia = NewTrackMedia (theTrack, VideoMediaType, 60, // Video Time Scale NULL, 0); if ((noErr == GetMoviesError())&&theMedia) { myErr = BeginMediaEdits (theMedia); if (myErr == noErr) { //create the actual movie frames GWorldPtr lgWorld=NULL; if (! NewGWorld (&lgWorld, 0, &gRect, (CTabHandle) NULL, (GDHandle) NULL, (GWorldFlags) (pixPurge + useTempMem))) { long MaxCompressedSize; ImageSequence seqID; ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(4); PixMapHandle myPixMap = GetPortPixMap(lgWorld); LockPixels (myPixMap); myErr = CompressSequenceBegin(&seqID, myPixMap, NULL, &gRect, &gRect, 0, mCodec, bestCompressionCodec, codecNormalQuality, codecNormalQuality, keyFrameRate, NULL, codecFlagUpdatePreviousComp, imageDesc); GetMaxCompressionSize (myPixMap, &gRect, 0, codecNormalQuality, mCodec, (CompressorComponent) anyCodec, &MaxCompressedSize); Handle Buffer = TempNewHandle(MaxCompressedSize, &myErr); if (!Buffer) Buffer = NewHandle(MaxCompressedSize); if (Buffer) { qtData myqtData = {theMedia, imageDesc, seqID, lDisplayRect, gRect}; if (MovieType == 0) { CreateFrameMovie(lgWorld, Buffer, myqtData, IncludeEPlot); } else { CreateModeMovie(lgWorld, Buffer, myqtData); } DisposeHandle(Buffer); } myErr = CDSequenceEnd(seqID); if (lgWorld != NULL) DisposeGWorld (lgWorld); if (imageDesc) DisposeHandle((Handle) imageDesc); } myErr = EndMediaEdits (theMedia); } myErr = InsertMediaIntoTrack (theTrack, 0,/* track start time */ 0, /* media start time */ GetMediaDuration (theMedia), FixRatio(1,1)); } myErr = AddMovieResource (theMovie, resRefNum, &resId, NULL); } if (resRefNum) { //Create the actual file as a flat data fork so it can be placed on the www ProgressInd->ChangeText("Flattening movieÉ"); FlattenMovie(theMovie, flattenAddMovieToDataFork, &targetSpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile, &resId, NULL); CloseMovieFile (resRefNum); } DisposeWindow(TempWindow); } DisposeMovie (theMovie); DeleteMovieFile (&tempSpec); //delete the temp file after disposing of the movie if (energyPlotWindow) { if (KillEPlot) { delete energyPlotWindow; energyPlotWindow = NULL; } else { energyPlotWindow->SetSize(savedEPlotWidth, savedEPlotHeight); energyPlotWindow->FrameChanged(); energyPlotWindow->Show(true); } } } ExitMovies(); //Close out quicktime as we are done with it for now FinishOperation(); }
/* * PsychQTGetTextureFromMovie() -- Create an OpenGL texture map from a specific videoframe from given movie object. * * win = Window pointer of onscreen window for which a OpenGL texture should be created. * moviehandle = Handle to the movie object. * checkForImage = true == Just check if new image available, false == really retrieve the image, blocking if necessary. * timeindex = When not in playback mode, this allows specification of a requested frame by presentation time. * If set to -1, or if in realtime playback mode, this parameter is ignored and the next video frame is returned. * out_texture = Pointer to the Psychtoolbox texture-record where the new texture should be stored. * presentation_timestamp = A ptr to a double variable, where the presentation timestamp of the returned frame should be stored. * * Returns true (1) on success, false (0) if no new image available, -1 if no new image available and there won't be any in future. */ int PsychQTGetTextureFromMovie(PsychWindowRecordType *win, int moviehandle, int checkForImage, double timeindex, PsychWindowRecordType *out_texture, double *presentation_timestamp) { static TimeValue myNextTimeCached = -2; static TimeValue nextFramesTimeCached = -2; TimeValue myCurrTime; TimeValue myNextTime; TimeValue nextFramesTime=0; short myFlags; OSType myTypes[1]; OSErr error = noErr; Movie theMovie; CVOpenGLTextureRef newImage = NULL; QTVisualContextRef theMoviecontext; unsigned int failcount=0; float lowerLeft[2]; float lowerRight[2]; float upperRight[2]; float upperLeft[2]; GLuint texid; Rect rect; float rate; double targetdelta, realdelta, frames; PsychRectType outRect; if (!PsychIsOnscreenWindow(win)) { PsychErrorExitMsg(PsychError_user, "Need onscreen window ptr!!!"); } // Activate OpenGL context of target window: PsychSetGLContext(win); // Explicitely disable Apple's Client storage extensions. For now they are not really useful to us. glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); if (moviehandle < 0 || moviehandle >= PSYCH_MAX_MOVIES) { PsychErrorExitMsg(PsychError_user, "Invalid moviehandle provided."); } if ((timeindex!=-1) && (timeindex < 0 || timeindex >= 10000.0)) { PsychErrorExitMsg(PsychError_user, "Invalid timeindex provided."); } if (NULL == out_texture && !checkForImage) { PsychErrorExitMsg(PsychError_internal, "NULL-Ptr instead of out_texture ptr passed!!!"); } // Fetch references to objects we need: theMovie = movieRecordBANK[moviehandle].theMovie; theMoviecontext = movieRecordBANK[moviehandle].QTMovieContext; if (theMovie == NULL) { PsychErrorExitMsg(PsychError_user, "Invalid moviehandle provided. No movie associated with this handle."); } // Check if end of movie is reached. Rewind, if so... if (IsMovieDone(theMovie) && movieRecordBANK[moviehandle].loopflag > 0) { if (GetMovieRate(theMovie)>0) { GoToBeginningOfMovie(theMovie); } else { GoToEndOfMovie(theMovie); } } // Is movie actively playing (automatic async playback, possibly with synced sound)? // If so, then we ignore the 'timeindex' parameter, because the automatic playback // process determines which frames should be delivered to PTB when. This function will // simply wait or poll for arrival/presence of a new frame that hasn't been fetched // in previous calls. if (0 == GetMovieRate(theMovie)) { // Movie playback inactive. We are in "manual" mode: No automatic async playback, // no synced audio output. The user just wants to manually fetch movie frames into // textures for manual playback in a standard Matlab-loop. // First pass - checking for new image? if (checkForImage) { // Image for specific point in time requested? if (timeindex >= 0) { // Yes. We try to retrieve the next possible image for requested timeindex. myCurrTime = (TimeValue) ((timeindex * (double) GetMovieTimeScale(theMovie)) + 0.5f); } else { // No. We just retrieve the next frame, given the current movie time. myCurrTime = GetMovieTime(theMovie, NULL); } // Retrieve timeindex of the closest image sample after myCurrTime: myFlags = nextTimeStep + nextTimeEdgeOK; // We want the next frame in the movie's media. myTypes[0] = VisualMediaCharacteristic; // We want video samples. GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, myCurrTime, FloatToFixed(1), &myNextTime, &nextFramesTime); error = GetMoviesError(); if (error != noErr) { PsychErrorExitMsg(PsychError_internal, "Failed to fetch texture from movie for given timeindex!"); } // Found useful event? if (myNextTime == -1) { if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: Bogus timevalue in movie track for movie %i. Trying to keep going.\n", moviehandle); // No. Just push timestamp to current time plus a little bit in the hope // this will get us unstuck: myNextTime = myCurrTime + (TimeValue) 1; nextFramesTime = (TimeValue) 0; } if (myNextTime != myNextTimeCached) { // Set movies current time to myNextTime, so the next frame will be fetched from there: SetMovieTimeValue(theMovie, myNextTime); // nextFramesTime is the timeindex to which we need to advance for retrieval of next frame: (see code below) nextFramesTime=myNextTime + nextFramesTime; if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: Current timevalue in movie track for movie %i is %lf secs.\n", moviehandle, (double) myNextTime / (double) GetMovieTimeScale(theMovie)); if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: Next timevalue in movie track for movie %i is %lf secs.\n", moviehandle, (double) nextFramesTime / (double) GetMovieTimeScale(theMovie)); // Cache values for 2nd pass: myNextTimeCached = myNextTime; nextFramesTimeCached = nextFramesTime; } else { // Somehow got stuck? Do nothing... if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: Seem to be a bit stuck at timevalue [for movie %i] of %lf secs. Nudging a bit forward...\n", moviehandle, (double) myNextTime / (double) GetMovieTimeScale(theMovie)); // Nudge the timeindex a bit forware in the hope that this helps: SetMovieTimeValue(theMovie, GetMovieTime(theMovie, NULL) + 1); } } else { // This is the 2nd pass: Image fetching. Use cached values from first pass: // Caching in a static works because we're always called immediately for 2nd // pass after successfull return from 1st pass, and we're not multi-threaded, // i.e., don't need to be reentrant or thread-safe here: myNextTime = myNextTimeCached; nextFramesTime = nextFramesTimeCached; myNextTimeCached = -2; } } else { // myNextTime unavailable if in autoplayback-mode: myNextTime=-1; } // Presentation timestamp requested? if (presentation_timestamp) { // Already available? if (myNextTime==-1) { // Retrieve the exact presentation timestamp of the retrieved frame (in movietime): myFlags = nextTimeStep + nextTimeEdgeOK; // We want the next frame in the movie's media. myTypes[0] = VisualMediaCharacteristic; // We want video samples. // We search backward for the closest available image for the current time. Either we get the current time // if we happen to fetch a frame exactly when it becomes ready, or we get a bit earlier timestamp, which is // the optimal presentation timestamp for this frame: GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, GetMovieTime(theMovie, NULL), FloatToFixed(-1), &myNextTime, NULL); } // Convert pts (in Quicktime ticks) to pts in seconds since start of movie and return it: *presentation_timestamp = (double) myNextTime / (double) GetMovieTimeScale(theMovie); } // Allow quicktime visual context task to do its internal bookkeeping and cleanup work: if (theMoviecontext) QTVisualContextTask(theMoviecontext); // Perform decompress-operation: if (checkForImage) MoviesTask(theMovie, 0); // Should we just check for new image? If so, just return availability status: if (checkForImage) { if (PSYCH_USE_QT_GWORLDS) { // We use GWorlds. In this case we either suceed immediately due to the // synchronous nature of GWorld rendering, or we fail completely at end // of non-looping movie: if (IsMovieDone(theMovie) && movieRecordBANK[moviehandle].loopflag == 0) { // No new frame available and there won't be any in the future, because this is a non-looping // movie that has reached its end. return(-1); } // Is this the special case of a movie without video, but only sound? In that case, // we always return a 'false' because there ain't no image to return. if (movieRecordBANK[moviehandle].QTMovieGWorld == NULL) return(false); // Success! return(true); } // Code which uses QTVisualContextTasks... if (QTVisualContextIsNewImageAvailable(theMoviecontext, NULL)) { // New frame ready! return(true); } else if (IsMovieDone(theMovie) && movieRecordBANK[moviehandle].loopflag == 0) { // No new frame available and there won't be any in the future, because this is a non-looping // movie that has reached its end. return(-1); } else { // No new frame available yet: return(false); } } if (!PSYCH_USE_QT_GWORLDS) { // Blocking wait-code for non-GWorld mode: // Try up to 1000 iterations for arrival of requested image data in wait-mode: failcount=0; while ((failcount < 1000) && !QTVisualContextIsNewImageAvailable(theMoviecontext, NULL)) { PsychWaitIntervalSeconds(0.005); MoviesTask(theMovie, 0); failcount++; } // No new frame available and there won't be any in the future, because this is a non-looping // movie that has reached its end. if ((failcount>=1000) && IsMovieDone(theMovie) && (movieRecordBANK[moviehandle].loopflag == 0)) { return(-1); } // Fetch new OpenGL texture with the new movie image frame: error = QTVisualContextCopyImageForTime(theMoviecontext, kCFAllocatorDefault, NULL, &newImage); if ((error!=noErr) || newImage == NULL) { PsychErrorExitMsg(PsychError_internal, "OpenGL<->Quicktime texture fetch failed!!!"); } // Disable client storage, if it was enabled: glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); // Build a standard PTB texture record: CVOpenGLTextureGetCleanTexCoords (newImage, lowerLeft, lowerRight, upperRight, upperLeft); texid = CVOpenGLTextureGetName(newImage); // Assign texture rectangle: PsychMakeRect(outRect, upperLeft[0], upperLeft[1], lowerRight[0], lowerRight[1]); // Set texture orientation as if it were an inverted Offscreen window: Upside-down. out_texture->textureOrientation = (CVOpenGLTextureIsFlipped(newImage)) ? 3 : 4; // Assign OpenGL texture id: out_texture->textureNumber = texid; // Store special texture object as part of the PTB texture record: out_texture->targetSpecific.QuickTimeGLTexture = newImage; } else { // Synchronous texture fetch code for GWorld rendering mode: // At this point, the GWorld should contain the source image for creating a // standard OpenGL texture: // Disable client storage, if it was enabled: glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); // Build a standard PTB texture record: // Assign texture rectangle: GetMovieBox(theMovie, &rect); // Hack: Need to extend rect by 4 pixels, because GWorlds are 4 pixels-aligned via // image row padding: rect.right = rect.right + 4; PsychMakeRect(out_texture->rect, rect.left, rect.top, rect.right, rect.bottom); // Set NULL - special texture object as part of the PTB texture record: out_texture->targetSpecific.QuickTimeGLTexture = NULL; // Set texture orientation as if it were an inverted Offscreen window: Upside-down. out_texture->textureOrientation = 3; // Setup a pointer to our GWorld as texture data pointer: out_texture->textureMemorySizeBytes = 0; // Quicktime textures are aligned on 4 Byte boundaries: out_texture->textureByteAligned = 4; // Lock GWorld: if(!LockPixels(GetGWorldPixMap(movieRecordBANK[moviehandle].QTMovieGWorld))) { // Locking surface failed! We abort. PsychErrorExitMsg(PsychError_internal, "PsychQTGetTextureFromMovie(): Locking GWorld pixmap surface failed!!!"); } // This will retrieve an OpenGL compatible pointer to the GWorlds pixel data and assign it to our texmemptr: out_texture->textureMemory = (GLuint*) GetPixBaseAddr(GetGWorldPixMap(movieRecordBANK[moviehandle].QTMovieGWorld)); // Let PsychCreateTexture() do the rest of the job of creating, setting up and // filling an OpenGL texture with GWorlds content: PsychCreateTexture(out_texture); // Undo hack from above after texture creation: Now we need the real width of the // texture for proper texture coordinate assignments in drawing code et al. rect.right = rect.right - 4; PsychMakeRect(outRect, rect.left, rect.top, rect.right, rect.bottom); // Unlock GWorld surface. We do a glFinish() before, for safety reasons... //glFinish(); UnlockPixels(GetGWorldPixMap(movieRecordBANK[moviehandle].QTMovieGWorld)); // Ready to use the texture... We're done. } // Normalize texture rectangle and assign it: PsychNormalizeRect(outRect, out_texture->rect); rate = FixedToFloat(GetMovieRate(theMovie)); // Detection of dropped frames: This is a heuristic. We'll see how well it works out... if (rate && presentation_timestamp) { // Try to check for dropped frames in playback mode: // Expected delta between successive presentation timestamps: targetdelta = 1.0f / (movieRecordBANK[moviehandle].fps * rate); // Compute real delta, given rate and playback direction: if (rate>0) { realdelta = *presentation_timestamp - movieRecordBANK[moviehandle].last_pts; if (realdelta<0) realdelta = 0; } else { realdelta = -1.0 * (*presentation_timestamp - movieRecordBANK[moviehandle].last_pts); if (realdelta<0) realdelta = 0; } frames = realdelta / targetdelta; // Dropped frames? if (frames > 1 && movieRecordBANK[moviehandle].last_pts>=0) { movieRecordBANK[moviehandle].nr_droppedframes += (int) (frames - 1 + 0.5); } movieRecordBANK[moviehandle].last_pts = *presentation_timestamp; } // Manually advance movie time, if in fetch mode: if (0 == GetMovieRate(theMovie)) { // We are in manual fetch mode: Need to manually advance movie time to next // media sample: if (nextFramesTime == myNextTime) { // Invalid value? Try to hack something that gets us unstuck: myNextTime = GetMovieTime(theMovie, NULL); nextFramesTime = myNextTime + (TimeValue) 1; } SetMovieTimeValue(theMovie, nextFramesTime); } // Check if end of movie is reached. Rewind, if so... if (IsMovieDone(theMovie) && movieRecordBANK[moviehandle].loopflag > 0) { if (GetMovieRate(theMovie)>0) { GoToBeginningOfMovie(theMovie); } else { GoToEndOfMovie(theMovie); } } return(TRUE); }
OSErr QTDR_CreateMovieInRAM (void) { Movie myMovie = NULL; Track myTrack = NULL; Media myMedia = NULL; short myResRefNum = 0; short myResID = 0; Handle myDataRef = NULL; Handle myHandle = NULL; FSSpec myFSSpec; OSErr myErr = noErr; // create a new handle to hold the media data myHandle = NewHandleClear(0); if (myHandle == NULL) goto bail; // create a data reference to that handle myDataRef = QTDR_MakeHandleDataRef(myHandle); if (myDataRef == NULL) goto bail; myMovie = NewMovie(newMovieActive); if (myMovie == NULL) goto bail; myErr = SetMovieDefaultDataRef(myMovie, myDataRef, HandleDataHandlerSubType); if (myErr != noErr) goto bail; // create the movie track and media myTrack = NewMovieTrack(myMovie, FixRatio(kVideoTrackWidth, 1), FixRatio(kVideoTrackHeight, 1), kNoVolume); myErr = GetMoviesError(); if (myErr != noErr) goto bail; myMedia = NewTrackMedia(myTrack, VideoMediaType, kVideoTimeScale, NULL, 0); myErr = GetMoviesError(); if (myErr != noErr) goto bail; // create the media samples myErr = BeginMediaEdits(myMedia); if (myErr != noErr) goto bail; myErr = QTDR_AddVideoSamplesToMedia(myMedia, kVideoTrackWidth, kVideoTrackHeight); if (myErr != noErr) goto bail; myErr = EndMediaEdits(myMedia); if (myErr != noErr) goto bail; // add the media to the track myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1); if (myErr != noErr) goto bail; // add the movie atom to the movie file myErr = AddMovieResource(myMovie, myResRefNum, &myResID, NULL); myFSSpec.name[0] = (unsigned char)0; myFSSpec.parID = 0; myFSSpec.vRefNum = 0; QTFrame_OpenMovieInWindow(myMovie, &myFSSpec); bail: if (myDataRef != NULL) DisposeHandle(myDataRef); return(myErr); }
QuickTimeFileReader::QuickTimeFileReader(FileSource source, DecodeMode decodeMode, CacheMode mode, size_t targetRate, ProgressReporter *reporter) : CodedAudioFileReader(mode, targetRate), m_source(source), m_path(source.getLocalFilename()), m_d(new D), m_reporter(reporter), m_cancelled(false), m_completion(0), m_decodeThread(0) { m_channelCount = 0; m_fileRate = 0; Profiler profiler("QuickTimeFileReader::QuickTimeFileReader", true); SVDEBUG << "QuickTimeFileReader: path is \"" << m_path << "\"" << endl; long QTversion; #ifdef WIN32 InitializeQTML(0); // FIXME should check QT version #else m_d->err = Gestalt(gestaltQuickTime,&QTversion); if ((m_d->err != noErr) || (QTversion < 0x07000000)) { m_error = QString("Failed to find compatible version of QuickTime (version 7 or above required)"); return; } #endif EnterMovies(); Handle dataRef; OSType dataRefType; // CFStringRef URLString = CFStringCreateWithCString // (0, m_path.toLocal8Bit().data(), 0); QByteArray ba = m_path.toLocal8Bit(); CFURLRef url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, (const UInt8 *)ba.data(), (CFIndex)ba.length(), false); // m_d->err = QTNewDataReferenceFromURLCFString m_d->err = QTNewDataReferenceFromCFURL (url, 0, &dataRef, &dataRefType); if (m_d->err) { m_error = QString("Error creating data reference for QuickTime decoder: code %1").arg(m_d->err); return; } short fileID = movieInDataForkResID; short flags = 0; m_d->err = NewMovieFromDataRef (&m_d->movie, flags, &fileID, dataRef, dataRefType); DisposeHandle(dataRef); if (m_d->err) { m_error = QString("Error creating new movie for QuickTime decoder: code %1").arg(m_d->err); return; } Boolean isProtected = 0; Track aTrack = GetMovieIndTrackType (m_d->movie, 1, SoundMediaType, movieTrackMediaType | movieTrackEnabledOnly); if (aTrack) { Media aMedia = GetTrackMedia(aTrack); // get the track media if (aMedia) { MediaHandler mh = GetMediaHandler(aMedia); // get the media handler we can query if (mh) { m_d->err = QTGetComponentProperty(mh, kQTPropertyClass_DRM, kQTDRMPropertyID_IsProtected, sizeof(Boolean), &isProtected,nil); } else { m_d->err = 1; } } else { m_d->err = 1; } } else { m_d->err = 1; } if (m_d->err && m_d->err != kQTPropertyNotSupportedErr) { m_error = QString("Error checking for DRM in QuickTime decoder: code %1").arg(m_d->err); return; } else if (!m_d->err && isProtected) { m_error = QString("File is protected with DRM"); return; } else if (m_d->err == kQTPropertyNotSupportedErr && !isProtected) { std::cerr << "QuickTime: File is not protected with DRM" << std::endl; } if (m_d->movie) { SetMovieActive(m_d->movie, TRUE); m_d->err = GetMoviesError(); if (m_d->err) { m_error = QString("Error in QuickTime decoder activation: code %1").arg(m_d->err); return; } } else { m_error = QString("Error in QuickTime decoder: Movie object not valid"); return; } m_d->err = MovieAudioExtractionBegin (m_d->movie, 0, &m_d->extractionSessionRef); if (m_d->err) { m_error = QString("Error in QuickTime decoder extraction init: code %1").arg(m_d->err); return; } m_d->err = MovieAudioExtractionGetProperty (m_d->extractionSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof(m_d->asbd), &m_d->asbd, nil); if (m_d->err) { m_error = QString("Error in QuickTime decoder property get: code %1").arg(m_d->err); return; } m_channelCount = m_d->asbd.mChannelsPerFrame; m_fileRate = m_d->asbd.mSampleRate; std::cerr << "QuickTime: " << m_channelCount << " channels, " << m_fileRate << " kHz" << std::endl; m_d->asbd.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; m_d->asbd.mBitsPerChannel = sizeof(float) * 8; m_d->asbd.mBytesPerFrame = sizeof(float) * m_d->asbd.mChannelsPerFrame; m_d->asbd.mBytesPerPacket = m_d->asbd.mBytesPerFrame; m_d->err = MovieAudioExtractionSetProperty (m_d->extractionSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof(m_d->asbd), &m_d->asbd); if (m_d->err) { m_error = QString("Error in QuickTime decoder property set: code %1").arg(m_d->err); m_channelCount = 0; return; } m_d->buffer.mNumberBuffers = 1; m_d->buffer.mBuffers[0].mNumberChannels = m_channelCount; m_d->buffer.mBuffers[0].mDataByteSize = sizeof(float) * m_channelCount * m_d->blockSize; m_d->data = new float[m_channelCount * m_d->blockSize]; m_d->buffer.mBuffers[0].mData = m_d->data; initialiseDecodeCache(); if (decodeMode == DecodeAtOnce) { if (m_reporter) { connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); m_reporter->setMessage (tr("Decoding %1...").arg(QFileInfo(m_path).fileName())); } while (1) { UInt32 framesRead = m_d->blockSize; UInt32 extractionFlags = 0; m_d->err = MovieAudioExtractionFillBuffer (m_d->extractionSessionRef, &framesRead, &m_d->buffer, &extractionFlags); if (m_d->err) { m_error = QString("Error in QuickTime decoding: code %1") .arg(m_d->err); break; } //!!! progress? // std::cerr << "Read " << framesRead << " frames (block size " << m_d->blockSize << ")" << std::endl; // QuickTime buffers are interleaved unless specified otherwise addSamplesToDecodeCache(m_d->data, framesRead); if (framesRead < m_d->blockSize) break; } finishDecodeCache(); endSerialised(); m_d->err = MovieAudioExtractionEnd(m_d->extractionSessionRef); if (m_d->err) { m_error = QString("Error ending QuickTime extraction session: code %1").arg(m_d->err); } m_completion = 100; } else { if (m_reporter) m_reporter->setProgress(100); if (m_channelCount > 0) { m_decodeThread = new DecodeThread(this); m_decodeThread->start(); } } std::cerr << "QuickTimeFileReader::QuickTimeFileReader: frame count is now " << getFrameCount() << ", error is \"\"" << m_error << "\"" << std::endl; }
OSErr QTDR_CreateReferenceCopy (Movie theSrcMovie, FSSpecPtr theDstMovieFile, FSSpecPtr theDstMediaFile) { Track mySrcTrack = NULL; Media mySrcMedia = NULL; Movie myDstMovie = NULL; Track myDstTrack = NULL; Media myDstMedia = NULL; Handle myMediaRef = NULL; // data reference for the media file #if !USE_ADDEMPTYTRACKTOMOVIE Fixed myWidth, myHeight; OSType myType; #endif long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; short myResRefNum = 0; short myResID = movieInDataForkResID; OSErr myErr = paramErr; // get the first video track and media in the source movie mySrcTrack = GetMovieIndTrackType(theSrcMovie, 1, VideoMediaType, movieTrackMediaType); if (mySrcTrack == NULL) goto bail; mySrcMedia = GetTrackMedia(mySrcTrack); if (mySrcMedia == NULL) goto bail; // create a file data reference for the new media file myMediaRef = QTDR_MakeFileDataRef(theDstMediaFile); if (myMediaRef == NULL) goto bail; // create a file for the destination movie data myErr = FSpCreate(theDstMediaFile, sigMoviePlayer, MovieFileType, 0); if (myErr != noErr) goto bail; // create a file for the destination movie atom and create an empty movie myErr = CreateMovieFile(theDstMovieFile, sigMoviePlayer, smCurrentScript, myFlags, &myResRefNum, &myDstMovie); if (myErr != noErr) goto bail; // assign the default progress proc to the destination movie SetMovieProgressProc(myDstMovie, (MovieProgressUPP)-1, 0); #if USE_ADDEMPTYTRACKTOMOVIE myErr = AddEmptyTrackToMovie(mySrcTrack, myDstMovie, myMediaRef, rAliasType, &myDstTrack); if (myErr != noErr) goto bail; myDstMedia = GetTrackMedia(myDstTrack); myErr = GetMoviesError(); if (myErr != noErr) goto bail; #else // get some information about the source track and media GetTrackDimensions(mySrcTrack, &myWidth, &myHeight); GetMediaHandlerDescription(mySrcMedia, &myType, 0, 0); // create the destination movie track and media myDstTrack = NewMovieTrack(myDstMovie, myWidth, myHeight, kNoVolume); myErr = GetMoviesError(); if (myErr != noErr) goto bail; myDstMedia = NewTrackMedia(myDstTrack, myType, GetMediaTimeScale(mySrcMedia), myMediaRef, rAliasType); myErr = GetMoviesError(); if (myErr != noErr) goto bail; CopyTrackSettings(mySrcTrack, myDstTrack); #endif // copy the entire source track into the destination track; this copies the track's media // samples into the destination media file myErr = BeginMediaEdits(myDstMedia); if (myErr != noErr) goto bail; myErr = InsertTrackSegment(mySrcTrack, myDstTrack, 0, GetTrackDuration(mySrcTrack), 0); if (myErr != noErr) goto bail; myErr = EndMediaEdits(myDstMedia); if (myErr != noErr) goto bail; // add the movie atom to the data fork of the movie file myErr = AddMovieResource(myDstMovie, myResRefNum, &myResID, NULL); bail: return(myErr); }
quicktime_recorder* quicktime_recorder::create( const char *path2, int width, int height, float fps ) { OSErr err; OSType dataRefType; Handle dataRef = NULL; impl *m = new impl(width, height); std::string pathStd = path2; #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, kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType); CFRelease(cfPath); if (err != noErr) { delete m; return NULL; } err = CreateMovieStorage(dataRef, dataRefType, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &m->data_handler, &m->movie); DisposeHandle(dataRef); if (err != noErr) { delete m; return NULL; } m->track = NewMovieTrack(m->movie, FixRatio(m->width, 1), FixRatio(m->height, 1), kNoVolume); err &= GetMoviesError(); TimeScale timeScale = (TimeScale)(fps * 100.0f); m->media = NewTrackMedia(m->track, VideoMediaType, timeScale, nil, 0 ); err &= GetMoviesError(); if (err != noErr) { delete m; return NULL; } SetMovieTimeScale(m->movie, timeScale); m->buffer = new unsigned char[4 * m->width * m->height]; Rect rect; rect.left = rect.top = 0; rect.right = m->width; rect.bottom = m->height; err = QTNewGWorldFromPtr(&m->gworld, k32BGRAPixelFormat, &rect, NULL, NULL, 0, m->buffer, 4 * m->width); if (err != noErr) { delete m; return NULL; } m->pixmap = GetGWorldPixMap(m->gworld); if (!m->pixmap) { delete m; return NULL; } LockPixels(m->pixmap); long maxSize = 0; err = GetMaxCompressionSize(m->pixmap, &rect, 0, codecNormalQuality, kPNGCodecType, anyCodec, &maxSize); if (err != noErr) { delete m; return NULL; } m->handle = NewHandle(maxSize); if (!m->handle) { delete m; return NULL; } HLockHi(m->handle); m->ptr = *m->handle; m->image_desc = (ImageDescriptionHandle)NewHandle(4); if (!m->image_desc) { delete m; return NULL; } err = BeginMediaEdits( m->media ); if (err != noErr) { delete m; return NULL; } return new quicktime_recorder(m); }
void ofQtVideoSaver::setup( int width , int height, string movieName){ w = width; h = height; fileName = (ofToDataPath(movieName)); //pszFlatFilename = flatFileName; initializeQuicktime(); /* Load the FSSpec structure to describe the receiving file. For a description of this and related calls see http://developer.apple.com/quicktime/icefloe/dispatch004.html. ================================================================ */ #ifdef TARGET_WIN32 //FILE * pFile = NULL; //pFile = fopen (fileName.c_str(),"w"); //fclose (pFile); char fileNameStr[255]; sprintf(fileNameStr, "%s", fileName.c_str()); osErr = NativePathNameToFSSpec (fileNameStr, &fsSpec, 0); #endif #ifdef TARGET_OSX /// kill a file and make a new one if needed: FILE * pFile; pFile = fopen (fileName.c_str(),"w"); fclose (pFile); Boolean isdir; osErr = FSPathMakeRef((const UInt8*)fileName.c_str(), &fsref, &isdir); osErr = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL); #endif if (osErr && (osErr != fnfErr)) /* File-not-found error is ok */ { printf ("getting FSS spec failed %d\n", osErr); goto bail; } /* Step 1: Create a new, empty movie file and a movie that references that file (CreateMovieFile). ======================================================================== */ osErr = CreateMovieFile ( &fsSpec, /* FSSpec specifier */ FOUR_CHAR_CODE('TVOD'), /* file creator type, TVOD = QT player*/ smCurrentScript, /* movie script system to use */ createMovieFileDeleteCurFile /* movie file creation flags */ | createMovieFileDontCreateResFile, &sResRefNum, /* returned file ref num to data fork */ &movie /* returned handle to open empty movie*/ /* that references the created file */ ); if (osErr) { printf ("CreateMovieFile failed %d\n", osErr); goto bail; } /* Step 2: Add a new track to that movie (NewMovieTrack). ======================================================= */ track = NewMovieTrack ( movie, /* the movie to add track to */ ((long) w << 16), /* width of track in pixels (Fixed) */ FixRatio (h, 1), /* height of track in pixels (Fixed) */ kNoVolume /* default volume level */ ); osErr = GetMoviesError (); if (osErr) { printf ("NewMovieTrack failed %d\n", osErr); goto bail; } /* Step 3: Add a new media to that track (NewTrackMedia). ======================================================= */ media = NewTrackMedia ( track, /* the track to add the media to */ VideoMediaType, /* media type, e.g. SoundMediaType */ 600, /* num media time units that elapse/sec*/ NULL, /* ptr to file that holds media sampls*/ 0 /* type of ptr to media samples */ ); osErr = GetMoviesError (); if (osErr) { printf ("NewTrackMedia failed %d\n", osErr); goto bail; } /* Step 4: Add media samples to the media. ======================================== */ BeginMediaEdits (media); /* Inform the Movie Toolbox that we */ /* want to change the media samples */ /* referenced by a track's media. */ /* This opens the media container */ /* and makes it ready to receive */ /* and/or remove sample data. */ // Step 5: setup graphics port for qt movie and compression type --- /* Create a new offscreen graphics world that will hold the movie's drawing surface. draw_image() copies the image of IceFlow to this surface with varying amounts of transparency. ================================================================= */ MacSetRect (&rect, 0, 0, w, h); osErr = NewGWorld ( &pMovieGWorld, /* receives the new GWorld. */ 24, /* pixel depth in bits/pixel */ &rect, /* desired size of the GWorld. */ NULL, NULL, (GWorldFlags) 0 ); if (osErr != noErr) { printf ("NewGWorld 1 failed %d\n", osErr); goto bail; } /* Retrieve the pixel map associated with that graphics world and lock the pixel map in memory. GetMaxCompressionSize() and CompressImage() only operate on pixel maps, not graphics worlds. ===================================================================== */ pixMapHandle = GetGWorldPixMap (pMovieGWorld); if (pixMapHandle == NULL) { printf ("GetGWorldPixMap failed\n"); goto bail; } LockPixels (pixMapHandle); /* Get the maximum number of bytes required to hold an image having the specified characteristics compressed using the specified compressor. ==================================================================== */ osErr = GetMaxCompressionSize ( pixMapHandle, /* the pixel map to compress from. */ &rect, /* the image rectangle. */ 0, /* let ICM choose image bit depth. */ codecHighQuality, /* compression quality specifier. */ kRawCodecType, /* desired compression type */ // < set to RAW in case we set to a new compression type... (CompressorComponent) anyCodec, /* codec specifier. */ &lMaxCompressionSize /* receives max bytes needed for cmp. */ ); if (osErr != noErr) { printf ("GetMaxCompressionSize failed %d\n", osErr); goto bail; } /* Allocate a buffer to hold the compressed image data by creating a new handle. ===================================================================== */ hCompressedData = NewHandle (lMaxCompressionSize); if (hCompressedData == NULL) { printf ("NewHandle(%ld) failed\n", lMaxCompressionSize); goto bail; } /* Lock the handle and then dereference it to obtain a pointer to the data buffer because CompressImage() wants us to pass it a pointer, not a handle. ======================================================================= */ HLockHi (hCompressedData); pCompressedData = *hCompressedData; /* Create an image description object in memory of minimum size to pass to CompressImage(). CompressImage() will resize the memory as necessary so create it small here. ==================================================================== */ hImageDescription = (ImageDescriptionHandle) NewHandle (4); if (hImageDescription == NULL) { printf ("NewHandle(4) failed\n"); goto bail; } bSetupForRecordingMovie = true; return; bail: printf("got to bail somehows \n"); if (sResRefNum != 0) CloseMovieFile (sResRefNum); if (movie != NULL) DisposeMovie (movie); //ExitMovies (); /* Finalize Quicktime */ return; }
OSStatus MovieMaker::setupMovie() { OSStatus error = noErr; FSRef fileRef; FSSpec fileSpec; rowBytes = width * 4; bufferSize = height * rowBytes; buffer = (char*)malloc(bufferSize); invertedBuffer = (char*)malloc(bufferSize); rect.left = 0; rect.top = 0; rect.right = width; rect.bottom = height; error = NewGWorldFromPtr(&gworld, k32ARGBPixelFormat, &rect, 0, 0, 0, buffer, rowBytes); if (error == noErr) { LockPixels(GetGWorldPixMap(gworld)); } // MBW -- I think this needs to happen after all the dialogs, etc. // if (error == noErr) // { // Microseconds(&lastFrameTime); // error = grabFrame(); // } if (error == noErr) { error = EnterMovies(); } if (error == noErr) { ci = OpenDefaultComponent(StandardCompressionType,StandardCompressionSubType); if(ci == NULL) error = paramErr; } if (error == noErr) { long flags; SCGetInfo(ci,scPreferenceFlagsType,&flags); flags &= ~scShowBestDepth; flags |= scAllowZeroFrameRate; SCSetInfo(ci,scPreferenceFlagsType,&flags); } if (error == noErr) { send_agent_pause(); gViewerWindow->mWindow->beforeDialog(); error = SCRequestSequenceSettings(ci); gViewerWindow->mWindow->afterDialog(); send_agent_resume(); if (error == scUserCancelled) { // deal with user cancelling. EndCapture(); } } if (error == noErr) { // This is stoopid. I have to take the passed full path, create the file so I can get an FSRef, and Get Info to get the FSSpec for QuickTime. Could Apple make this any more difficult... FILE* file = LLFile::fopen(fname, "w"); /* Flawfinder: ignore */ if (file) { fclose(file); error = FSPathMakeRef((UInt8*)fname, &fileRef, NULL); if (error == noErr) error = FSGetCatalogInfo(&fileRef, 0, NULL, NULL, &fileSpec, NULL); } else { error = paramErr; } } if (error == noErr) { error = CreateMovieFile(&fileSpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &movieResRef, &movie); } if (error == noErr) { track = NewMovieTrack(movie, FixRatio(width, 1), FixRatio(height, 1), kNoVolume); error = GetMoviesError(); } if (error == noErr) { media = NewTrackMedia(track, VideoMediaType, 600, NULL, 0); error = GetMoviesError(); } if (error == noErr) { Microseconds(&lastFrameTime); error = grabFrame(); } if (error == noErr) { error = SCCompressSequenceBegin(ci,GetPortPixMap(gworld),nil,&idh); } if (error == noErr) { error = BeginMediaEdits(media); } if (error != noErr) { media = NULL; } return error; }
void TLevelWriter3gp::save(const TImageP &img, int frameIndex) { if (m_cancelled) return; TRasterImageP image(img); int lx = image->getRaster()->getLx(); int ly = image->getRaster()->getLy(); //void *buffer = image->getRaster()->getRawData(); int pixSize = image->getRaster()->getPixelSize(); if (pixSize != 4) throw TImageException(getFilePath(), "Unsupported pixel type"); QMutexLocker sl(&m_mutex); if (!m_properties) m_properties = new Tiio::MovWriterProperties(); Tiio::MovWriterProperties *prop = (Tiio::MovWriterProperties *)(m_properties); //CodecType compression = StandardCompressionType; prop->getCurrentCodec(); //CodecQ quality = StandardQualityType; prop->getCurrentQuality(); if (!m_initDone) { //FSSpec fspec; Rect frame; long max_compressed_size; QDErr err; m_videoTrack = NewMovieTrack(m_movie, FixRatio((short)lx, 1), FixRatio((short)ly, 1), kNoVolume); if ((err = GetMoviesError() != noErr)) throw TImageException(getFilePath(), "can't create video track"); m_dataRef = nil; m_hMovieData = NewHandle(0); // Construct the Handle data reference err = PtrToHand(&m_hMovieData, &m_dataRef, sizeof(Handle)); if ((err = GetMoviesError() != noErr)) throw TImageException(getFilePath(), "can't create Data Ref"); m_videoMedia = NewTrackMedia(m_videoTrack, VideoMediaType, (TINT32)m_frameRate, m_dataRef, HandleDataHandlerSubType); OpenADefaultComponent(MovieExportType, '3gpp', &m_myExporter); // err = (short)MovieExportDoUserDialog(m_myExporter, m_movie, 0, 0, 0, &m_cancelled); // if (m_cancelled) // throw TImageException(getFilePath(), "User abort of 3GP render"); if ((err = GetMoviesError() != noErr)) throw TImageException(getFilePath(), "can't create video media"); if ((err = BeginMediaEdits(m_videoMedia)) != noErr) throw TImageException(getFilePath(), "can't begin edit video media"); frame.left = 0; frame.top = 0; frame.right = lx; frame.bottom = ly; #if 0 if ((err = NewGWorld(&(m_gworld), pixSize * 8, &frame, 0, 0, 0))!=noErr) #else /* Mac OSX 10.7 later */ if ((err = QTNewGWorld(&(m_gworld), pixSize * 8, &frame, 0, 0, 0)) != noErr) #endif throw TImageException(getFilePath(), "can't create movie buffer"); #ifdef WIN32 LockPixels(m_gworld->portPixMap); if ((err = GetMaxCompressionSize(m_gworld->portPixMap, &frame, 0, quality, compression, anyCodec, &max_compressed_size)) != noErr) throw TImageException(getFilePath(), "can't get max compression size"); #else #if 0 PixMapHandle pixmapH = GetPortPixMap (m_gworld); LockPixels(pixmapH); #else PixMapHandle pixmapH = NULL; #endif max_compressed_size = lx * ly * 4 * 20; /*if ((err = GetMaxCompressionSize(pixmapH, &frame, 0, quality, compression,anyCodec, &max_compressed_size))!=noErr) throw TImageException(getFilePath(), "can't get max compression size");*/ #endif m_compressedData = NewHandle(max_compressed_size); if ((err = MemError()) != noErr) throw TImageException(getFilePath(), "can't allocate compressed data for movie"); MoveHHi(m_compressedData); HLock(m_compressedData); if ((err = MemError()) != noErr) throw TImageException(getFilePath(), "can't allocate img handle"); #if 0 m_pixmap = GetGWorldPixMap(m_gworld); if (!LockPixels(m_pixmap)) throw TImageException(getFilePath(), "can't lock pixels"); buf = (PixelXRGB*) GetPixBaseAddr(m_pixmap); #else m_pixmap = NULL; buf = NULL; #endif buf_lx = lx; buf_ly = ly; m_initDone = true; } unsigned short rowBytes = (unsigned short)(((short)(*(m_pixmap))->rowBytes & ~(3 << 14))); Rect frame; ImageDescriptionHandle img_descr; Ptr compressed_data_ptr; QDErr err; frame.left = 0; frame.top = 0; frame.right = lx; frame.bottom = ly; TRasterP ras = image->getRaster(); #ifdef WIN32 compressed_data_ptr = StripAddress(*(m_compressedData)); copy(ras, buf, buf_lx, buf_ly); #else compressed_data_ptr = *m_compressedData; copy(ras, buf, buf_lx, buf_ly, rowBytes); #endif img_descr = (ImageDescriptionHandle)NewHandle(4); #ifdef WIN32 if ((err = CompressImage(m_gworld->portPixMap, &frame, quality, compression, img_descr, compressed_data_ptr)) != noErr) throw TImageException(getFilePath(), "can't compress image"); #else #if 0 PixMapHandle pixmapH = GetPortPixMap (m_gworld); if ((err = CompressImage(pixmapH, &frame, codecNormalQuality, kJPEGCodecType, img_descr, compressed_data_ptr))!=noErr) { throw TImageException(getFilePath(), "can't compress image"); } #endif #endif if ((err = AddMediaSample(m_videoMedia, m_compressedData, 0, (*img_descr)->dataSize, 1, (SampleDescriptionHandle)img_descr, 1, 0, 0)) != noErr) throw TImageException(getFilePath(), "can't add image to movie media"); DisposeHandle((Handle)img_descr); }
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)); }
static int init_audio(int speed, int channels, soundmovie_buffer_t **buffer) { AudioStreamBasicDescription asbd = {0}; //see CoreAudioTypes.h asbd.mSampleRate = speed; asbd.mFormatID = kAudioFormatLinearPCM; asbd.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger; asbd.mChannelsPerFrame = channels; asbd.mBitsPerChannel = sizeof (SWORD) * 8; asbd.mBytesPerFrame = (asbd.mBitsPerChannel >> 3) // number of *bytes* per channel * asbd.mChannelsPerFrame; // channels per frame asbd.mFramesPerPacket = 1; // For PCM, frames per packet is always 1 asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; UInt32 layoutSize; layoutSize = offsetof(AudioChannelLayout, mChannelDescriptions[0]); AudioChannelLayout *layout = NULL; layout = calloc(layoutSize, 1); OSErr err = -1; if (layout != NULL) { if (channels == 1) { layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono; } else if (channels == 2) { layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; } else { log_debug("quicktime_audio: unsupported channels: %d", channels); return -1; } err = QTSoundDescriptionCreate( &asbd, // format description layout, layoutSize, // channel layout NULL, 0, // magic cookie (compression parameters) kQTSoundDescriptionKind_Movie_LowestPossibleVersion, &soundDescriptionHandle); // SoundDescriptionHandle returned here free(layout); } if (err != noErr) { log_debug("quicktime_audio: error creating sound description!"); return -1; } //Add audio track audioTrack = NewMovieTrack(movie, 0, 0, kFullVolume); OSStatus theError = GetMoviesError(); if (theError) { log_debug("quicktime_audio: error creating movie track"); return theError; } //Create audio track media audioMedia = NewTrackMedia(audioTrack, SoundMediaType, speed, 0, 0); theError = GetMoviesError(); if (theError) { log_debug("quicktime_audio: error creating track media!"); return theError; } //Prepare media for editing theError = BeginMediaEdits(audioMedia); if (theError) { log_debug("quicktime_audio: error beginning media edits!"); return theError; } *buffer = &audioBuffer; audioBuffer.size = speed * channels / 10; audioBuffer.buffer = malloc(sizeof(SWORD) * audioBuffer.size); audioBuffer.used = 0; audio_ready = 1; return 0; }
void TLevelWriter3gp::saveSoundTrack(TSoundTrack *st) { Track theTrack; OSErr myErr = noErr; SoundDescriptionV1Handle mySampleDesc; Media myMedia; Handle myDestHandle; SoundComponentData sourceInfo; SoundComponentData destInfo; SoundConverter converter; CompressionInfo compressionInfo; int err; if (!st) throw TException("null reference to soundtrack"); if (st->getBitPerSample() != 16) { throw TImageException(m_path, "Only 16 bits per sample is supported"); } theTrack = NewMovieTrack(m_movie, 0, 0, kFullVolume); myErr = GetMoviesError(); if (myErr != noErr) throw TImageException(m_path, "error creating audio track"); FailIf(myErr != noErr, CompressErr); myDestHandle = NewHandle(0); FailWithAction(myDestHandle == NULL, myErr = MemError(), NoDest); *myDestHandle = (char *)st->getRawData(); ////////// // // create a media for the track passed in // ////////// // set new track to be a sound track m_soundDataRef = nil; m_hSoundMovieData = NewHandle(0); // Construct the Handle data reference err = PtrToHand(&m_hSoundMovieData, &m_soundDataRef, sizeof(Handle)); if ((err = GetMoviesError() != noErr)) throw TImageException(getFilePath(), "can't create Data Ref"); myMedia = NewTrackMedia(theTrack, SoundMediaType, st->getSampleRate(), m_soundDataRef, HandleDataHandlerSubType); //track->rate >> 16 myErr = GetMoviesError(); if (myErr != noErr) throw TImageException(m_path, "error setting audio track"); FailIf(myErr != noErr, Exit); // start a media editing session myErr = BeginMediaEdits(myMedia); if (myErr != noErr) throw TImageException(m_path, "error beginning edit audio track"); FailIf(myErr != noErr, Exit); sourceInfo.flags = 0x0; sourceInfo.format = kSoundNotCompressed; sourceInfo.numChannels = st->getChannelCount(); sourceInfo.sampleSize = st->getBitPerSample(); sourceInfo.sampleRate = st->getSampleRate(); sourceInfo.sampleCount = st->getSampleCount(); sourceInfo.buffer = (unsigned char *)st->getRawData(); sourceInfo.reserved = 0x0; destInfo.flags = kNoSampleRateConversion | kNoSampleSizeConversion | kNoSampleFormatConversion | kNoChannelConversion | kNoDecompression | kNoVolumeConversion | kNoRealtimeProcessing; destInfo.format = k16BitNativeEndianFormat; destInfo.numChannels = st->getChannelCount(); destInfo.sampleSize = st->getBitPerSample(); destInfo.sampleRate = st->getSampleRate(); destInfo.sampleCount = st->getSampleCount(); destInfo.buffer = (unsigned char *)st->getRawData(); destInfo.reserved = 0x0; SoundConverterOpen(&sourceInfo, &destInfo, &converter); myErr = SoundConverterGetInfo(converter, siCompressionFactor, &compressionInfo); if (myErr != noErr) throw TImageException(m_path, "error getting audio converter info"); myErr = GetCompressionInfo(fixedCompression, sourceInfo.format, sourceInfo.numChannels, sourceInfo.sampleSize, &compressionInfo); if (myErr != noErr) throw TImageException(m_path, "error getting audio compression info"); FailIf(myErr != noErr, ConverterErr); compressionInfo.bytesPerFrame = compressionInfo.bytesPerPacket * destInfo.numChannels; ////////// // // create a sound sample description // ////////// // use the SoundDescription format 1 because it adds fields for data size information // and is required by AddSoundDescriptionExtension if an extension is required for the compression format mySampleDesc = (SoundDescriptionV1Handle)NewHandleClear(sizeof(SoundDescriptionV1)); FailWithAction(myErr != noErr, myErr = MemError(), Exit); (**mySampleDesc).desc.descSize = sizeof(SoundDescriptionV1); (**mySampleDesc).desc.dataFormat = destInfo.format; (**mySampleDesc).desc.resvd1 = 0; (**mySampleDesc).desc.resvd2 = 0; (**mySampleDesc).desc.dataRefIndex = 1; (**mySampleDesc).desc.version = 1; (**mySampleDesc).desc.revlevel = 0; (**mySampleDesc).desc.vendor = 0; (**mySampleDesc).desc.numChannels = destInfo.numChannels; (**mySampleDesc).desc.sampleSize = destInfo.sampleSize; (**mySampleDesc).desc.compressionID = 0; (**mySampleDesc).desc.packetSize = 0; (**mySampleDesc).desc.sampleRate = st->getSampleRate() << 16; (**mySampleDesc).samplesPerPacket = compressionInfo.samplesPerPacket; (**mySampleDesc).bytesPerPacket = compressionInfo.bytesPerPacket; (**mySampleDesc).bytesPerFrame = compressionInfo.bytesPerFrame; (**mySampleDesc).bytesPerSample = compressionInfo.bytesPerSample; ////////// // // add samples to the media // ////////// myErr = AddMediaSample(myMedia, myDestHandle, 0, destInfo.sampleCount * compressionInfo.bytesPerFrame, 1, (SampleDescriptionHandle)mySampleDesc, destInfo.sampleCount * compressionInfo.samplesPerPacket, 0, NULL); if (myErr != noErr) throw TImageException(m_path, "error adding audio samples"); FailIf(myErr != noErr, MediaErr); myErr = EndMediaEdits(myMedia); if (myErr != noErr) throw TImageException(m_path, "error ending audio edit"); FailIf(myErr != noErr, MediaErr); ////////// // // insert the media into the track // ////////// myErr = InsertMediaIntoTrack(theTrack, 0, 0, GetMediaDuration(myMedia), fixed1); if (myErr != noErr) throw TImageException(m_path, "error inserting audio track"); FailIf(myErr != noErr, MediaErr); goto Done; ConverterErr: NoDest: CompressErr: Exit: Done: MediaErr: if (mySampleDesc != NULL) DisposeHandle((Handle)mySampleDesc); if (converter) SoundConverterClose(converter); if (myErr != noErr) throw TImageException(m_path, "error saving audio track"); }
OSErr makeMovieFromVideoFramesFile(char *inDestMovieFile) { Handle dataRef = NULL; OSType dataRefType; ImageDescriptionHandle videoDescH = NULL; OSErr err; #if TARGET_OS_WIN32 err = InitializeQTML(0); if ((err = GetMoviesError()) != noErr) goto bail; #endif err = EnterMovies(); if ((err = GetMoviesError()) != noErr) goto bail; // create a data reference from the full path to the video frames file makeDataRefFromFullPath(inDestMovieFile, &dataRef, &dataRefType); if (dataRef == NULL) goto bail; Movie m = NewMovie(0); if ((err = GetMoviesError()) != noErr) goto bail; // create the video track for the movie Track videoT = NewMovieTrack( m, Long2Fix(kFrameWidth), Long2Fix(kFrameHeight), kNoVolume); if ((err = GetMoviesError()) != noErr) goto bail; // create the video track media Media videoM = NewTrackMedia( videoT, VideoMediaType, kMediaTimeScale, dataRef, dataRefType); if ((err = GetMoviesError()) != noErr) goto bail; videoDescH = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); if (videoDescH == NULL) goto bail; // create the ImageDescription that will describe our video track media samples videoDescH[0]->idSize = sizeof(ImageDescription); videoDescH[0]->cType = kCodecType; // the codec type for your data videoDescH[0]->temporalQuality = codecNormalQuality; videoDescH[0]->spatialQuality = codecNormalQuality; videoDescH[0]->width = kFrameWidth; videoDescH[0]->height = kFrameHeight; videoDescH[0]->hRes = 72L << 16; videoDescH[0]->vRes = 72L << 16; videoDescH[0]->depth = 32; videoDescH[0]->clutID = -1; SampleReference64Record videoRef; videoRef.dataOffset.hi = 0; videoRef.dataOffset.lo = 0; videoRef.dataSize = (kFrameWidth*kFrameHeight*4) * kNumberOfSamples; videoRef.durationPerSample = kDurationPerSample; videoRef.numberOfSamples = kNumberOfSamples; videoRef.sampleFlags = 0; // now add all of our media samples to the movie data file. err = AddMediaSampleReferences64(videoM, (SampleDescriptionHandle)videoDescH, 1, &videoRef, 0); if (err != noErr) goto bail; TimeValue mediaDuration = kNumberOfSamples * kDurationPerSample; // inserts a reference to our media samples into the track. err = InsertMediaIntoTrack(videoT, 0, 0, mediaDuration, fixed1); // media's rate (1.0 = media's natural playback rate). if (err != noErr) goto bail; DataHandler outDataHandler; // opens a data handler for our movie storage (the video frames file) err = OpenMovieStorage (dataRef, dataRefType, kDataHCanWrite, &outDataHandler ); if (err != noErr) goto bail; // add a movie to our movie storage container err = AddMovieToStorage (m, outDataHandler ); if (err != noErr) goto bail; err = CloseMovieStorage (outDataHandler); outDataHandler = NULL; bail: if (videoDescH) { DisposeHandle((Handle)videoDescH); } return err; }
void MacQTStartRecording(char *path) { OSStatus err; CFStringRef str; CFURLRef url; memset(&sqt, 0, sizeof(sqt)); // storage str = CFStringCreateWithCString(kCFAllocatorDefault, path, MAC_PATH_ENCODING); url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false); err = QTNewDataReferenceFromCFURL(url, 0, &(sqt.dataRef), &(sqt.dataRefType)); CheckError(err, 21); CFRelease(url); CFRelease(str); err = CreateMovieStorage(sqt.dataRef, sqt.dataRefType, 'TVOD', smSystemScript, createMovieFileDeleteCurFile | newMovieActive, &(sqt.dataHandler), &(sqt.movie)); CheckError(err, 22); // video MacQTOpenVideoComponent(&(sqt.vci)); SCTemporalSettings ts; err = SCGetInfo(sqt.vci, scTemporalSettingsType, &ts); ts.frameRate = FixRatio(Memory.ROMFramesPerSecond, 1); if (ts.keyFrameRate < 1) ts.keyFrameRate = Memory.ROMFramesPerSecond; sqt.keyFrame = sqt.keyFrameCount = ts.keyFrameRate; sqt.frameSkip = sqt.frameSkipCount = (macQTMovFlag & 0xFF00) >> 8; err = SCSetInfo(sqt.vci, scTemporalSettingsType, &ts); sqt.frame.top = 0; sqt.frame.left = 0; sqt.frame.right = ((macQTMovFlag & kMovDoubleSize) ? 2 : 1) * SNES_WIDTH; sqt.frame.bottom = ((macQTMovFlag & kMovDoubleSize) ? 2 : 1) * ((macQTMovFlag & kMovExtendedHeight) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT); sqt.pw = sqt.ph = 0; sqt.firstFrame = true; Rect rct; SetRect(&rct, 0, 0, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2 + 4); InitGWorld(&(sqt.bw), &rct, 16); sqt.vTrack = NewMovieTrack(sqt.movie, FixRatio(sqt.frame.right, 1), FixRatio(sqt.frame.bottom, 1), kNoVolume); CheckError(GetMoviesError(), 23); sqt.vMedia = NewTrackMedia(sqt.vTrack, VideoMediaType, Memory.ROMFramesPerSecond, nil, 0); CheckError(GetMoviesError(), 24); err = BeginMediaEdits(sqt.vMedia); CheckError(err, 25); // sound sqt.soundDesc = (SoundDescriptionHandle) NewHandleClear(sizeof(SoundDescription)); CheckError(MemError(), 26); (**sqt.soundDesc).descSize = sizeof(SoundDescription); #ifdef __BIG_ENDIAN__ (**sqt.soundDesc).dataFormat = Settings.SixteenBitSound ? k16BitBigEndianFormat : k8BitOffsetBinaryFormat; #else (**sqt.soundDesc).dataFormat = Settings.SixteenBitSound ? k16BitLittleEndianFormat : k8BitOffsetBinaryFormat; #endif (**sqt.soundDesc).numChannels = Settings.Stereo ? 2 : 1; (**sqt.soundDesc).sampleSize = Settings.SixteenBitSound ? 16 : 8; (**sqt.soundDesc).sampleRate = (UnsignedFixed) FixRatio(Settings.SoundPlaybackRate, 1); sqt.samplesPerSec = Settings.SoundPlaybackRate / Memory.ROMFramesPerSecond; sqt.soundBufferSize = sqt.samplesPerSec; if (Settings.SixteenBitSound) sqt.soundBufferSize <<= 1; if (Settings.Stereo) sqt.soundBufferSize <<= 1; sqt.soundBuffer = NewHandleClear(sqt.soundBufferSize); CheckError(MemError(), 27); HLock(sqt.soundBuffer); sqt.sTrack = NewMovieTrack(sqt.movie, 0, 0, kFullVolume); CheckError(GetMoviesError(), 28); sqt.sMedia = NewTrackMedia(sqt.sTrack, SoundMediaType, Settings.SoundPlaybackRate, nil, 0); CheckError(GetMoviesError(), 29); err = BeginMediaEdits(sqt.sMedia); CheckError(err, 30); }