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; }
/***************************************************************************** * OpenAudio: *****************************************************************************/ static int OpenAudio( decoder_t *p_dec ) { decoder_sys_t *p_sys; int i_error; char fcc[4]; unsigned long WantedBufferSize; unsigned long InputBufferSize = 0; unsigned long OutputBufferSize = 0; /* get lock, avoid segfault */ vlc_mutex_lock( &qt_mutex ); p_sys = calloc( 1, sizeof( decoder_sys_t ) ); p_dec->p_sys = p_sys; p_dec->pf_decode_audio = DecodeAudio; if( p_dec->fmt_in.i_original_fourcc ) memcpy( fcc, &p_dec->fmt_in.i_original_fourcc, 4 ); else memcpy( fcc, &p_dec->fmt_in.i_codec, 4 ); #ifdef __APPLE__ EnterMovies(); #endif if( QTAudioInit( p_dec ) ) { msg_Err( p_dec, "cannot initialize QT"); goto exit_error; } #ifndef __APPLE__ if( ( i_error = p_sys->InitializeQTML( 6 + 16 ) ) ) { msg_Dbg( p_dec, "error on InitializeQTML = %d", i_error ); goto exit_error; } #endif /* input format settings */ p_sys->InputFormatInfo.flags = 0; p_sys->InputFormatInfo.sampleCount = 0; p_sys->InputFormatInfo.buffer = NULL; p_sys->InputFormatInfo.reserved = 0; p_sys->InputFormatInfo.numChannels = p_dec->fmt_in.audio.i_channels; p_sys->InputFormatInfo.sampleSize = p_dec->fmt_in.audio.i_bitspersample; p_sys->InputFormatInfo.sampleRate = p_dec->fmt_in.audio.i_rate; p_sys->InputFormatInfo.format = FCC( fcc[0], fcc[1], fcc[2], fcc[3] ); /* output format settings */ p_sys->OutputFormatInfo.flags = 0; p_sys->OutputFormatInfo.sampleCount = 0; p_sys->OutputFormatInfo.buffer = NULL; p_sys->OutputFormatInfo.reserved = 0; p_sys->OutputFormatInfo.numChannels = p_dec->fmt_in.audio.i_channels; p_sys->OutputFormatInfo.sampleSize = 16; p_sys->OutputFormatInfo.sampleRate = p_dec->fmt_in.audio.i_rate; p_sys->OutputFormatInfo.format = FCC( 'N', 'O', 'N', 'E' ); i_error = p_sys->SoundConverterOpen( &p_sys->InputFormatInfo, &p_sys->OutputFormatInfo, &p_sys->myConverter ); if( i_error ) { msg_Err( p_dec, "error on SoundConverterOpen = %d", i_error ); goto exit_error; } #if 0 /* tell the sound converter we accept VBR formats */ i_error = SoundConverterSetInfo( p_dec->myConverter, siClientAcceptsVBR, (void *)true ); #endif if( p_dec->fmt_in.i_extra > 36 + 8 ) { i_error = p_sys->SoundConverterSetInfo( p_sys->myConverter, FCC( 'w', 'a', 'v', 'e' ), ((uint8_t*)p_dec->fmt_in.p_extra) + 36 + 8 ); msg_Dbg( p_dec, "error on SoundConverterSetInfo = %d", i_error ); } WantedBufferSize = p_sys->OutputFormatInfo.numChannels * p_sys->OutputFormatInfo.sampleRate * 2; p_sys->FramesToGet = 0; i_error = p_sys->SoundConverterGetBufferSizes( p_sys->myConverter, WantedBufferSize, &p_sys->FramesToGet, &InputBufferSize, &OutputBufferSize ); msg_Dbg( p_dec, "WantedBufferSize=%li InputBufferSize=%li " "OutputBufferSize=%li FramesToGet=%li", WantedBufferSize, InputBufferSize, OutputBufferSize, p_sys->FramesToGet ); p_sys->InFrameSize = (InputBufferSize + p_sys->FramesToGet - 1 ) / p_sys->FramesToGet; p_sys->OutFrameSize = OutputBufferSize / p_sys->FramesToGet; msg_Dbg( p_dec, "frame size %d -> %d", p_sys->InFrameSize, p_sys->OutFrameSize ); if( (i_error = p_sys->SoundConverterBeginConversion(p_sys->myConverter)) ) { msg_Err( p_dec, "error on SoundConverterBeginConversion = %d", i_error ); goto exit_error; } es_format_Init( &p_dec->fmt_out, AUDIO_ES, VLC_CODEC_S16N ); p_dec->fmt_out.audio.i_rate = p_sys->OutputFormatInfo.sampleRate; p_dec->fmt_out.audio.i_channels = p_sys->OutputFormatInfo.numChannels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_sys->OutputFormatInfo.numChannels]; date_Init( &p_sys->date, p_dec->fmt_out.audio.i_rate, 1 ); p_sys->i_buffer = 0; p_sys->i_buffer_size = 100*1000; p_sys->p_buffer = malloc( p_sys->i_buffer_size ); if( !p_sys->p_buffer ) goto exit_error; p_sys->i_out = 0; p_sys->i_out_frames = 0; vlc_mutex_unlock( &qt_mutex ); return VLC_SUCCESS; exit_error: #ifdef LOADER Restore_LDT_Keeper( p_sys->ldt_fs ); #endif vlc_mutex_unlock( &qt_mutex ); free( p_sys ); return VLC_EGENERIC; }
bool QTImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks, int *outNumTracks) { OSErr err = noErr; // // Determine the file format. // // GetMediaSampleDescription takes a SampleDescriptionHandle, but apparently // if the media is a sound (which presumably we know it is) then it will treat // it as a SoundDescriptionHandle (which in addition to the format of single // samples, also tells you sample rate, number of channels, etc.) // Pretty messed up interface, if you ask me. SoundDescriptionHandle soundDescription = (SoundDescriptionHandle)NewHandle(0); GetMediaSampleDescription(mMedia, 1, (SampleDescriptionHandle)soundDescription); // If this is a compressed format, it may have out-of-stream compression // parameters that need to be passed to the sound converter. We retrieve // these in the form of an audio atom. To do this, however we have to // get the data by way of a handle, then copy it manually from the handle to // the atom. These interfaces get worse all the time! Handle decompressionParamsHandle = NewHandle(0); AudioFormatAtomPtr decompressionParamsAtom = NULL; err = GetSoundDescriptionExtension(soundDescription, &decompressionParamsHandle, siDecompressionParams); if(err == noErr) { // this stream has decompression parameters. copy from the handle to the atom. int paramsSize = GetHandleSize(decompressionParamsHandle); HLock(decompressionParamsHandle); decompressionParamsAtom = (AudioFormatAtomPtr)NewPtr(paramsSize); //err = MemError(); BlockMoveData(*decompressionParamsHandle, decompressionParamsAtom, paramsSize); HUnlock(decompressionParamsHandle); } if(decompressionParamsHandle) DisposeHandle(decompressionParamsHandle); // // Now we set up a sound converter to decompress the data if it is compressed. // SoundComponentData inputFormat; SoundComponentData outputFormat; SoundConverter soundConverter = NULL; inputFormat.flags = outputFormat.flags = 0; inputFormat.sampleCount = outputFormat.sampleCount = 0; inputFormat.reserved = outputFormat.reserved = 0; inputFormat.buffer = outputFormat.buffer = NULL; inputFormat.numChannels = outputFormat.numChannels = (*soundDescription)->numChannels; inputFormat.sampleSize = outputFormat.sampleSize = (*soundDescription)->sampleSize; inputFormat.sampleRate = outputFormat.sampleRate = (*soundDescription)->sampleRate; inputFormat.format = (*soundDescription)->dataFormat; outputFormat.format = kSoundNotCompressed; err = SoundConverterOpen(&inputFormat, &outputFormat, &soundConverter); // // Create the Audacity WaveTracks to house the new data // *outNumTracks = outputFormat.numChannels; WaveTrack **channels = new WaveTrack *[*outNumTracks]; // determine sample format sampleFormat format; int bytesPerSample; // TODO: do we know for sure that 24 and 32 bit samples are the same kind // of 24 and 32 bit samples we expect? switch(outputFormat.sampleSize) { case 16: format = int16Sample; bytesPerSample = 2; break; case 24: format = int24Sample; bytesPerSample = 3; break; case 32: format = floatSample; bytesPerSample = 4; break; default: printf("I can't import a %d-bit file!\n", outputFormat.sampleSize); return false; } int c; for (c = 0; c < *outNumTracks; c++) { channels[c] = trackFactory->NewWaveTrack(format); channels[c]->SetRate(outputFormat.sampleRate / 65536.0); if(*outNumTracks == 2) { if(c == 0) { channels[c]->SetChannel(Track::LeftChannel); channels[c]->SetLinked(true); } else if(c == 1) { channels[c]->SetChannel(Track::RightChannel); } } } // // Give the converter the decompression atom. // // (judging from the sample code, it's OK if the atom is NULL, which // it will be if there was no decompression information) err = SoundConverterSetInfo(soundConverter, siDecompressionParams, decompressionParamsAtom); if(err == siUnknownInfoType) { // the decompressor didn't need the decompression atom, but that's ok. err = noErr; } // Tell the converter we're cool with VBR audio SoundConverterSetInfo(soundConverter, siClientAcceptsVBR, Ptr(true)); // // Determine buffer sizes and allocate output buffer // int inputBufferSize = 655360; int outputBufferSize = 524288; char *outputBuffer = new char[outputBufferSize]; // // Populate the structure of data that is passed to the callback // CallbackData cbData; memset(&cbData.compData, 0, sizeof(ExtendedSoundComponentData)); cbData.isSourceVBR = ((*soundDescription)->compressionID == variableCompression); cbData.sourceMedia = mMedia; cbData.getMediaAtThisTime = 0; cbData.sourceDuration = GetMediaDuration(mMedia); cbData.isThereMoreSource = true; cbData.maxBufferSize = inputBufferSize; // allocate source media buffer cbData.hSource = NewHandle((long)cbData.maxBufferSize); MoveHHi(cbData.hSource); HLock(cbData.hSource); cbData.compData.desc = inputFormat; cbData.compData.desc.buffer = (BytePtr)*cbData.hSource; cbData.compData.desc.flags = kExtendedSoundData; cbData.compData.extendedFlags = kExtendedSoundBufferSizeValid | kExtendedSoundSampleCountNotValid; if(cbData.isSourceVBR) cbData.compData.extendedFlags |= kExtendedSoundCommonFrameSizeValid; cbData.compData.bufferSize = 0; // filled in during callback // this doesn't make sense to me, but it is taken from sample code cbData.compData.recordSize = sizeof(ExtendedSoundComponentData); // // Begin the Conversion // err = SoundConverterBeginConversion(soundConverter); SoundConverterFillBufferDataUPP fillBufferUPP; fillBufferUPP = NewSoundConverterFillBufferDataUPP(SoundConverterFillBufferCallback); bool done = false; bool cancelled = false; sampleCount samplesSinceLastCallback = 0; UInt32 outputFrames; UInt32 outputBytes; UInt32 outputFlags; #define SAMPLES_PER_CALLBACK 10000 while(!done && !cancelled) { err = SoundConverterFillBuffer(soundConverter, // a sound converter fillBufferUPP, // the callback &cbData, // refCon passed to FillDataProc outputBuffer, // the buffer to decompress into outputBufferSize, // size of that buffer &outputBytes, // number of bytes actually output &outputFrames, // number of frames actually output &outputFlags); // fillbuffer retured advisor flags if (err) break; if((outputFlags & kSoundConverterHasLeftOverData) == false) done = true; for(c = 0; c < *outNumTracks; c++) channels[c]->Append(outputBuffer + (c*bytesPerSample), format, outputFrames, *outNumTracks); samplesSinceLastCallback += outputFrames; if( samplesSinceLastCallback > SAMPLES_PER_CALLBACK ) { if( mProgressCallback ) cancelled = mProgressCallback(mUserData, (float)cbData.getMediaAtThisTime / cbData.sourceDuration); samplesSinceLastCallback -= SAMPLES_PER_CALLBACK; } } HUnlock(cbData.hSource); // Flush any remaining data to the output buffer. // It appears that we have no way of telling this routine how big the output // buffer is! We had better hope that there isn't more data left than // the buffer is big. SoundConverterEndConversion(soundConverter, outputBuffer, &outputFrames, &outputBytes); for(c = 0; c < *outNumTracks; c++) { channels[c]->Append(outputBuffer + (c*bytesPerSample), format, outputFrames, *outNumTracks); channels[c]->Flush(); } delete[] outputBuffer; DisposeHandle(cbData.hSource); SoundConverterClose(soundConverter); DisposeMovie(mMovie); if (cancelled || err != noErr) { for (c = 0; c < *outNumTracks; c++) delete channels[c]; delete[] channels; return false; } else { *outTracks = new Track *[*outNumTracks]; for(c = 0; c < *outNumTracks; c++) (*outTracks)[c] = channels[c]; delete[] channels; return true; } }