OSStatus GetMovieAudioExtractionASBD(MovieAudioExtractionRef inSessionRef, QTPropertyValuePtr *outASBDPtr) { QTPropertyValueType outPropType; ByteCount outPropValueSize; UInt32 outPropertyFlags; OSStatus status = noErr; *outASBDPtr = nil; // first get the size of the property so we know how // much memory to allocate for our property buffer status = MovieAudioExtractionGetPropertyInfo( inSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, &outPropType, &outPropValueSize, &outPropertyFlags); assert(noErr == status); // allocate a buffer for the property using the size value just obtained *outASBDPtr = malloc(outPropValueSize); assert(*outASBDPtr != nil); // now get the actual property and put it into our buffer ByteCount outPropValueSizeUsed; status = MovieAudioExtractionGetProperty( inSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, outPropValueSize, *outASBDPtr, &outPropValueSizeUsed); return status; }
// Get the default extraction layout for this movie, expanded into individual channel descriptions. // The channel layout returned by this routine must be deallocated by the client. // If 'asbd' is non-NULL, fill it with the default extraction asbd, which contains the // highest sample rate among the sound tracks that will be contributing. // 'outLayoutSize' and 'asbd' may be nil. OSStatus GetDefaultExtractionLayout(Movie movie, UInt32* outLayoutSize, AudioChannelLayout** outLayout, AudioStreamBasicDescription *asbd) { OSStatus err = noErr; AudioChannelLayout *layout = NULL; UInt32 size = 0; MovieAudioExtractionRef extractionSessionRef = nil; if (!outLayout) { err = paramErr; goto bail; } // Initiate a dummy audio extraction here, in order to get the resulting default channel layout. err = MovieAudioExtractionBegin(movie, 0, &extractionSessionRef); require(err == noErr, bail); // Get the size of the extraction output layout err = MovieAudioExtractionGetPropertyInfo(extractionSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, NULL, &size, NULL); require(err == noErr, bail); // Allocate memory for the layout layout = (AudioChannelLayout *) calloc(1, size); if (layout == nil) { err = memFullErr; goto bail; } // Get the layout for the current extraction configuration. // This will have already been expanded into channel descriptions. err = MovieAudioExtractionGetProperty(extractionSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, size, layout, nil); require(err == noErr, bail); // Return the layout and size, if requested *outLayout = layout; if (outLayoutSize) *outLayoutSize = size; // If the ASBD was requested, get that also. if (asbd != nil) { // Get the layout for the current extraction configuration. // This will have already been expanded into channel descriptions. size = sizeof (*asbd); err = MovieAudioExtractionGetProperty(extractionSessionRef, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, size, asbd, nil); require(err == noErr, bail); } bail: if (err != noErr) { if (layout) free(layout); if (outLayoutSize) *outLayoutSize = 0; } // Throw away the temporary audio extraction session if (extractionSessionRef) { MovieAudioExtractionEnd(extractionSessionRef); } return err; }
QTAudioReader (InputStream* const input_, const int trackNum_) : AudioFormatReader (input_, TRANS (quickTimeFormatName)), ok (false), movie (0), trackNum (trackNum_), lastSampleRead (0), lastThreadId (0), extractor (0), dataHandle (0) { JUCE_AUTORELEASEPOOL bufferList.calloc (256, 1); #if JUCE_WINDOWS if (InitializeQTML (0) != noErr) return; #endif if (EnterMovies() != noErr) return; bool opened = juce_OpenQuickTimeMovieFromStream (input_, movie, dataHandle); if (! opened) return; { const int numTracks = GetMovieTrackCount (movie); int trackCount = 0; for (int i = 1; i <= numTracks; ++i) { track = GetMovieIndTrack (movie, i); media = GetTrackMedia (track); OSType mediaType; GetMediaHandlerDescription (media, &mediaType, 0, 0); if (mediaType == SoundMediaType && trackCount++ == trackNum_) { ok = true; break; } } } if (! ok) return; ok = false; lengthInSamples = GetMediaDecodeDuration (media); usesFloatingPointData = false; samplesPerFrame = (int) (GetMediaDecodeDuration (media) / GetMediaSampleCount (media)); trackUnitsPerFrame = GetMovieTimeScale (movie) * samplesPerFrame / GetMediaTimeScale (media); OSStatus err = MovieAudioExtractionBegin (movie, 0, &extractor); unsigned long output_layout_size; err = MovieAudioExtractionGetPropertyInfo (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, 0, &output_layout_size, 0); if (err != noErr) return; HeapBlock <AudioChannelLayout> qt_audio_channel_layout; qt_audio_channel_layout.calloc (output_layout_size, 1); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout, 0); qt_audio_channel_layout[0].mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof (inputStreamDesc), &inputStreamDesc, 0); if (err != noErr) return; inputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; inputStreamDesc.mBitsPerChannel = sizeof (SInt16) * 8; inputStreamDesc.mChannelsPerFrame = jmin ((UInt32) 2, inputStreamDesc.mChannelsPerFrame); inputStreamDesc.mBytesPerFrame = sizeof (SInt16) * inputStreamDesc.mChannelsPerFrame; inputStreamDesc.mBytesPerPacket = inputStreamDesc.mBytesPerFrame; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof (inputStreamDesc), &inputStreamDesc); if (err != noErr) return; Boolean allChannelsDiscrete = false; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Movie, kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, sizeof (allChannelsDiscrete), &allChannelsDiscrete); if (err != noErr) return; bufferList->mNumberBuffers = 1; bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame; bufferList->mBuffers[0].mDataByteSize = jmax ((UInt32) 4096, (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16); dataBuffer.malloc (bufferList->mBuffers[0].mDataByteSize); bufferList->mBuffers[0].mData = dataBuffer; sampleRate = inputStreamDesc.mSampleRate; bitsPerSample = 16; numChannels = inputStreamDesc.mChannelsPerFrame; detachThread(); ok = true; }