void ofQtVideoSaver::addAudioTrack(string audioPath) { if(audioPath == "") return; OSErr err; Handle dataRef = NULL; FSSpec fileSpec; short audioMovieRefNum = 0; short audioMovieResId = 0; Movie audioMovie = NULL; Track audioCopyTrack = NULL; Media audioCopyMedia = NULL; Track destTrack = NULL; Media destMedia = NULL; destTrack = NewMovieTrack (movie, 0, 0, kFullVolume); destMedia = NewTrackMedia (destTrack, SoundMediaType, 30. * 100, /* Video Time Scale */ nil, 0); err = BeginMediaEdits (destMedia); char * p = new char[audioPath.length()+1]; strcpy(p, audioPath.c_str()); NativePathNameToFSSpec(p, &fileSpec, 0L); err = OpenMovieFile(&fileSpec, &audioMovieRefNum, fsRdPerm); err = NewMovieFromFile(&audioMovie, audioMovieRefNum, &audioMovieResId, NULL, newMovieActive, NULL); err = CloseMovieFile(audioMovieRefNum); SetMovieTimeScale(audioMovie, 30.*100); audioCopyTrack = GetMovieTrack(audioMovie, 1); audioCopyMedia = GetTrackMedia(audioCopyTrack); long duration = GetMovieDuration(audioMovie); err = AddEmptyTrackToMovie (audioCopyTrack, movie, nil, nil, &destTrack); err = InsertTrackSegment(audioCopyTrack, destTrack, 0, duration, 0); err = EndMediaEdits(destMedia); }
int get_qtcodec_settings(RenderData *rd, ReportList *reports) { OSErr err = noErr; /* erase any existing codecsetting */ if (qtdata) { if (qtdata->theComponent) CloseComponent(qtdata->theComponent); free_qtcomponentdata(); } /* allocate new */ qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData"); qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType); /* get previous selected codecsetting, from qtatom or detailed settings */ if (rd->qtcodecdata && rd->qtcodecdata->cdParms) { QT_GetCodecSettingsFromScene(rd, reports); } else { SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting); SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings); SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings); qtdata->gSpatialSettings.codecType = rd->qtcodecsettings.codecType; qtdata->gSpatialSettings.codec = (CodecComponent)rd->qtcodecsettings.codec; qtdata->gSpatialSettings.spatialQuality = (rd->qtcodecsettings.codecSpatialQuality * codecLosslessQuality) / 100; qtdata->gTemporalSettings.temporalQuality = (rd->qtcodecsettings.codecTemporalQuality * codecLosslessQuality) / 100; qtdata->gTemporalSettings.keyFrameRate = rd->qtcodecsettings.keyFrameRate; qtdata->aDataRateSetting.dataRate = rd->qtcodecsettings.bitRate; qtdata->gSpatialSettings.depth = rd->qtcodecsettings.colorDepth; qtdata->aDataRateSetting.minSpatialQuality = (rd->qtcodecsettings.minSpatialQuality * codecLosslessQuality) / 100; qtdata->aDataRateSetting.minTemporalQuality = (rd->qtcodecsettings.minTemporalQuality * codecLosslessQuality) / 100; qtdata->aDataRateSetting.frameDuration = rd->frs_sec; SetMovieTimeScale(qtexport->theMovie, rd->frs_sec_base * 1000); err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings); CheckError(err, "SCSetInfo1 error", reports); err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings); CheckError(err, "SCSetInfo2 error", reports); err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting); CheckError(err, "SCSetInfo3 error", reports); } check_renderbutton_framerate(rd, reports); return err; }
void ofxQtVideoSaver::addAudioTrack(string audioPath) { OSErr err; Handle dataRef = NULL; FSSpec fileSpec; short audioMovieRefNum = 0; short audioMovieResId = 0; Movie audioMovie = NULL; Track audioCopyTrack = NULL; Media audioCopyMedia = NULL; Track destTrack = NULL; Media destMedia = NULL; destTrack = NewMovieTrack (movie, 0, 0, kFullVolume); destMedia = NewTrackMedia (destTrack, SoundMediaType, (TimeScale) (30.f * 100), /* Video Time Scale */ nil, 0); err = BeginMediaEdits (destMedia); char * p = new char[audioPath.length()+1]; strcpy(p, audioPath.c_str()); #ifdef TARGET_WIN32 NativePathNameToFSSpec(p, &fileSpec, 0L); #endif #ifdef TARGET_OSX Boolean isdir; FSPathMakeRef((const UInt8*)p, &fsref, &isdir); FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fileSpec, NULL); #endif err = OpenMovieFile(&fileSpec, &audioMovieRefNum, fsRdPerm); err = NewMovieFromFile(&audioMovie, audioMovieRefNum, &audioMovieResId, NULL, newMovieActive, NULL); err = CloseMovieFile(audioMovieRefNum); SetMovieTimeScale(audioMovie, (TimeScale) (30.*100)); audioCopyTrack = GetMovieTrack(audioMovie, 1); audioCopyMedia = GetTrackMedia(audioCopyTrack); long duration = GetMovieDuration(audioMovie); err = AddEmptyTrackToMovie (audioCopyTrack, movie, 0, 0, &destTrack); err = InsertTrackSegment(audioCopyTrack, destTrack, 0, duration, 0); err = EndMediaEdits(destMedia); }
int convertToMP4PathThrough(CFStringRef inFile, CFStringRef outFile) { OSStatus error; MovieExportComponent movieExporter = NULL; Handle inDataRef=0, outDataRef=0; OSType inDataRefType, outDataRefType; short inResID = 0; Movie theMovie=0; int ret = -1; error = OpenADefaultComponent(MovieExportType, kQTFileTypeMP4, &movieExporter); if(error) { fprintf(stderr,"OpenADefaultComponent error: cannot find the QuickTime conponent\n"); goto last; } error = QTNewDataReferenceFromFullPathCFString(inFile, kQTNativeDefaultPathStyle, 0, &inDataRef, &inDataRefType); if(error) { fprintf(stderr,"QTNewDataReferenceFromFullPathCFString error: input file path is invalid\n"); goto last; } error = QTNewDataReferenceFromFullPathCFString(outFile, kQTNativeDefaultPathStyle, 0, &outDataRef, &outDataRefType); if(error) { fprintf(stderr,"QTNewDataReferenceFromFullPathCFString error: output file path is invalid\n"); goto last; } error = NewMovieFromDataRef(&theMovie, newMovieActive, &inResID, inDataRef, inDataRefType); if(error) { fprintf(stderr,"NewMovieFromDataRef error: cannot open the input file\n"); goto last; } Track theTrack = getSoundTrack(theMovie); Media theMedia = GetTrackMedia(theTrack); DeleteTrackSegment(theTrack, 0, GetTrackDuration(theTrack)); SetMovieTimeScale(theMovie, GetMediaTimeScale(theMedia)); InsertMediaIntoTrack(theTrack, 0, 0, GetMediaDuration(theMedia), fixed1); Boolean useHighResolutionAudio = true; QTSetComponentProperty( movieExporter, kQTPropertyClass_MovieExporter, kQTMovieExporterPropertyID_EnableHighResolutionAudioFeatures, sizeof(Boolean), &useHighResolutionAudio ); UInt32 ftyp = 'mp42'; QTSetComponentProperty( movieExporter, kQTPropertyClass_MovieExporter, 'ftyp', 4, &ftyp ); QTAtomContainer ac; MovieExportGetSettingsAsAtomContainer(movieExporter, &ac); QTAtom ensoAtom = QTFindChildByID(ac, kParentAtomIsContainer, kQTSettingsMovieExportEnableSound, 1, NULL); if(ensoAtom) { long size, *data; QTGetAtomDataPtr(ac,ensoAtom,&size,(Ptr *)&data); data[0] = EndianS32_NtoB('past'); QTSetAtomData(ac, ensoAtom, size, data); MovieExportSetSettingsFromAtomContainer(movieExporter, ac); } DisposeHandle(ac); /*Boolean cancelled; error = MovieExportDoUserDialog(movieExporter, theMovie, NULL, 0, GetMovieDuration(theMovie), &cancelled); if(cancelled) goto last; if(error) { printf("MovieExportDoUserDialog error\n"); goto last; }*/ error = ConvertMovieToDataRef(theMovie, 0, outDataRef, outDataRefType, kQTFileTypeMP4, FOUR_CHAR_CODE('TVOD'), createMovieFileDeleteCurFile|createMovieFileDontCreateResFile, movieExporter); if(error) { fprintf(stderr,"ConvertMovieToDataRef error: cannot translate .mov into .m4a (%d)\n",error); goto last; } ret = 0; last: if(movieExporter) CloseComponent(movieExporter); if(theMovie) DisposeMovie(theMovie); if(inDataRef) DisposeHandle(inDataRef); if(outDataRef) DisposeHandle(outDataRef); return ret; }
void QTEffects_RespondToDialogSelection (OSErr theErr) { Boolean myDialogWasCancelled = false; short myResID = movieInDataForkResID; UInt16 myMovieIter; short mySrcMovieRefNum = 0; Movie myPrevSrcMovie = NULL; Track myPrevSrcTrack = NULL; Movie myNextSrcMovie = NULL; Track myNextSrcTrack = NULL; short myDestMovieRefNum = 0; FSSpec myFile; Boolean myIsSelected = false; Boolean myIsReplacing = false; StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsSaveMovieFileName); Movie myDestMovie = NULL; Fixed myDestMovieWidth, myDestMovieHeight; ImageDescriptionHandle myDesc = NULL; Track videoTrackFX, videoTrackA, videoTrackB; Media videoMediaFX, videoMediaA, videoMediaB; TimeValue myCurrentDuration = 0; TimeValue myReturnedDuration; Boolean isFirstTransition = true; TimeValue myMediaTransitionDuration; TimeValue myMediaFXStartTime, myMediaFXDuration; OSType myEffectCode; long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; long myLong; OSErr myErr = noErr; // standard parameter box has been dismissed, so remember that fact gEffectsDialog = 0L; myDialogWasCancelled = (theErr == userCanceledErr); // we're finished with the effect list and movie posters QTDisposeAtomContainer(gEffectList); if (gPosterA != NULL) KillPicture(gPosterA); if (gPosterB != NULL) KillPicture(gPosterB); // when the sign says stop, then stop if (myDialogWasCancelled) goto bail; // add atoms naming the sources to gEffectSample myLong = EndianU32_NtoB(kSourceOneName); QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myLong), &myLong, NULL); myLong = EndianU32_NtoB(kSourceTwoName); QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myLong), &myLong, NULL); // extract the 'what' atom to find out what kind of effect it is { QTAtom myEffectAtom; QTAtomID myEffectAtomID; long myEffectCodeSize; Ptr myEffectCodePtr; myEffectAtom = QTFindChildByIndex(gEffectSample, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, &myEffectAtomID); myErr = QTLockContainer(gEffectSample); BailError(myErr); myErr = QTGetAtomDataPtr(gEffectSample, myEffectAtom, &myEffectCodeSize, &myEffectCodePtr); BailError(myErr); if (myEffectCodeSize != sizeof(OSType)) { myErr = paramErr; goto bail; } myEffectCode = *(OSType *)myEffectCodePtr; // "tsk" myEffectCode = EndianU32_BtoN(myEffectCode); // because the data is read from an atom container myErr = QTUnlockContainer(gEffectSample); BailError(myErr); } // ask the user for the name of the new movie file QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing); if (!myIsSelected) goto bail; // deal with user cancelling // create a movie file for the destination movie myErr = CreateMovieFile(&myFile, FOUR_CHAR_CODE('TVOD'), 0, myFlags, &myDestMovieRefNum, &myDestMovie); BailError(myErr); // open the first file as a movie; call the first movie myPrevSrcMovie myErr = OpenMovieFile(&gSpecList[0], &mySrcMovieRefNum, fsRdPerm); BailError(myErr); myErr = NewMovieFromFile(&myPrevSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL); BailError(myErr); myErr = CloseMovieFile(mySrcMovieRefNum); BailError(myErr); // if the movie is shorter than kMinimumDuration, scale it to that length SetMovieTimeScale(myPrevSrcMovie, kTimeScale); myErr = QTEffects_GetFirstVideoTrackInMovie(myPrevSrcMovie, &myPrevSrcTrack); BailNil(myPrevSrcTrack); if (GetTrackDuration(myPrevSrcTrack) < kMinimumDuration) { myErr = ScaleTrackSegment(myPrevSrcTrack, 0, GetTrackDuration(myPrevSrcTrack), kMinimumDuration); BailError(myErr); } // find out how big the first movie is; we'll use it as the size of all our tracks GetTrackDimensions(myPrevSrcTrack, &myDestMovieWidth, &myDestMovieHeight); #if USES_MAKE_IMAGE_DESC_FOR_EFFECT // create a new sample description for the effect, // which is just an image description specifying the effect and its dimensions myErr = MakeImageDescriptionForEffect(myEffectCode, &myDesc); if (myErr != noErr) BailError(myErr); #else // create a new sample description for the effect, // which is just an image description specifying the effect and its dimensions myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); BailNil(myDesc); (**myDesc).idSize = sizeof(ImageDescription); (**myDesc).cType = myEffectCode; (**myDesc).hRes = 72L << 16; (**myDesc).vRes = 72L << 16; (**myDesc).dataSize = 0L; (**myDesc).frameCount = 1; (**myDesc).depth = 0; (**myDesc).clutID = -1; #endif // fill in the fields of the sample description (**myDesc).vendor = kAppleManufacturer; (**myDesc).temporalQuality = codecNormalQuality; (**myDesc).spatialQuality = codecNormalQuality; (**myDesc).width = FixRound(myDestMovieWidth); (**myDesc).height = FixRound(myDestMovieHeight); // add three video tracks to the destination movie: // - videoTrackFX is where the effects and stills live; it's user-visible. // - videoTrackA is where the "source A"s for effects live; it's hidden by the input map // - videoTrackB is where the "source B"s for effects live; it's hidden by the input map videoTrackFX = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); BailNil(videoTrackFX); videoMediaFX = NewTrackMedia(videoTrackFX, VideoMediaType, kTimeScale, NULL, 0); BailNil(videoMediaFX); myErr = BeginMediaEdits(videoMediaFX); BailError(myErr); videoTrackA = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); BailNil(videoTrackA); videoMediaA = NewTrackMedia(videoTrackA, VideoMediaType, kTimeScale, NULL, 0); BailNil(videoMediaA); videoTrackB = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); BailNil(videoTrackB); videoMediaB = NewTrackMedia(videoTrackB, VideoMediaType, kTimeScale, NULL, 0); BailNil(videoMediaB); // create the input map { long myRefIndex1, myRefIndex2; QTAtomContainer myInputMap; QTAtom myInputAtom; OSType myInputType; QTNewAtomContainer(&myInputMap); // first input if (videoTrackA) { AddTrackReference(videoTrackFX, videoTrackA, kTrackModifierReference, &myRefIndex1); QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex1, 0, 0, NULL, &myInputAtom); myInputType = EndianU32_NtoB(kTrackModifierTypeImage); QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL); myLong = EndianU32_NtoB(kSourceOneName); QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL); } // second input if (videoTrackB) { AddTrackReference(videoTrackFX, videoTrackB, kTrackModifierReference, &myRefIndex2); QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex2, 0, 0, NULL, &myInputAtom); myInputType = EndianU32_NtoB(kTrackModifierTypeImage); QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL); myLong = EndianU32_NtoB(kSourceTwoName); QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL); } // set that map SetMediaInputMap(GetTrackMedia(videoTrackFX), myInputMap); QTDisposeAtomContainer(myInputMap); } myCurrentDuration = 0; #if MAKE_STILL_SECTIONS // copy the first sample of the first video track of the first movie to videoTrackFX, with duration kStillDuration. myErr = CopyPortionOfTrackToTrack(myPrevSrcTrack, eStartPortion + eMiddlePortion, videoTrackFX, myCurrentDuration, &myReturnedDuration); BailError(myErr); myCurrentDuration += myReturnedDuration; #endif // now process any remaining files myMovieIter = 1; while (myMovieIter < gSpecCount) { // open the next file as a movie; call it nextSourceMovie myErr = OpenMovieFile(&gSpecList[myMovieIter], &mySrcMovieRefNum, fsRdPerm); BailError(myErr); myErr = NewMovieFromFile(&myNextSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL); BailError(myErr); // we're done with the movie file, so close it myErr = CloseMovieFile(mySrcMovieRefNum); BailError(myErr); // if the movie is shorter than kMinimumDuration, scale it to that length SetMovieTimeScale(myNextSrcMovie, kTimeScale); myErr = QTEffects_GetFirstVideoTrackInMovie(myNextSrcMovie, &myNextSrcTrack); BailNil(myNextSrcTrack); if (GetTrackDuration(myNextSrcTrack) < kMinimumDuration) { myErr = ScaleTrackSegment(myNextSrcTrack, 0, GetTrackDuration(myNextSrcTrack), kMinimumDuration); BailError(myErr); } // create a transition effect from the previous source movie's first video sample to the next source movie's first video sample // (the effect should have duration kEffectDuration); // this involves adding one sample to each of the three video tracks: // sample from previous source movie -> videoTrackA myErr = QTEffects_CopyPortionOfTrackToTrack(myPrevSrcTrack, eFinishPortion, videoTrackA, myCurrentDuration, &myReturnedDuration); BailError(myErr); // sample from next source movie -> videoTrackB myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eStartPortion, videoTrackB, myCurrentDuration, &myReturnedDuration); BailError(myErr); // effect sample -> videoTrackFX if (isFirstTransition) { myMediaTransitionDuration = myReturnedDuration; myMediaFXStartTime = GetMediaDuration(videoMediaFX); myErr = AddMediaSample(videoMediaFX, gEffectSample, 0, GetHandleSize(gEffectSample), myMediaTransitionDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL); BailError(myErr); myMediaFXDuration = GetMediaDuration(videoMediaFX) - myMediaFXStartTime; isFirstTransition = false; } myErr = InsertMediaIntoTrack(videoTrackFX, myCurrentDuration, myMediaFXStartTime, myMediaFXDuration, FixRatio(myReturnedDuration, myMediaTransitionDuration)); BailError(myErr); myCurrentDuration += myReturnedDuration; #if MAKE_STILL_SECTIONS // copy the first video sample of myNextSrcMovie to videoTrackFX, with duration kStillDuration. myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eMiddlePortion + (myMovieIter + 1 == theSpecCount) ? eFinishPortion : 0, videoTrackFX, myCurrentDuration, &myReturnedDuration); BailError(myErr); myCurrentDuration += myReturnedDuration; #endif // MAKE_STILL_SECTIONS // dispose of previous source movie. DisposeMovie(myPrevSrcMovie); myPrevSrcMovie = myNextSrcMovie; myPrevSrcTrack = myNextSrcTrack; myNextSrcMovie = NULL; myNextSrcTrack = NULL; myMovieIter++; } // while myErr = EndMediaEdits(videoMediaFX); BailError(myErr); myErr = AddMovieResource(myDestMovie, myDestMovieRefNum, &myResID, "\pMovie 1"); BailError(myErr); CloseMovieFile(myDestMovieRefNum); if (myPrevSrcMovie != NULL) DisposeMovie(myPrevSrcMovie); DisposeMovie(myDestMovie); bail: free(myPrompt); free(myFileName); QTDisposeAtomContainer(gEffectSample); DisposeHandle((Handle)myDesc); return; }
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); }