ComponentResult initVorbisComponent(WebMExportGlobalsPtr globals, GenericStreamPtr as) { dbg_printf("[WebM] enter initVorbisComponent\n"); ComponentResult err = noErr; if (globals->audioSettingsAtom == NULL) getDefaultVorbisAtom(globals); //This chunk initializes the Component instance that will be used for decompression : TODO put this in its own function err = OpenADefaultComponent(StandardCompressionType, StandardCompressionSubTypeAudio, &as->aud.vorbisComponentInstance); if (err) goto bail; AudioStreamBasicDescription *inFormat = NULL; inFormat = calloc(1, sizeof(AudioStreamBasicDescription)); if (inFormat == NULL) goto bail; err = getInputBasicDescription(as, inFormat); if (err) goto bail; getInputBasicDescription(as, inFormat); err = SCSetSettingsFromAtomContainer(as->aud.vorbisComponentInstance, globals->audioSettingsAtom); if (err) goto bail; err = QTGetComponentProperty(as->aud.vorbisComponentInstance, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_BasicDescription, sizeof(AudioStreamBasicDescription), &as->aud.asbd, NULL); if (err) goto bail; err = QTSetComponentProperty(as->aud.vorbisComponentInstance, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_InputBasicDescription, sizeof(AudioStreamBasicDescription), inFormat); bail: if (inFormat != NULL) free(inFormat); dbg_printf("[WebM]initVorbisComponent return %d\n", err); return err; }
static void _initAudioBufferList(GenericStreamPtr as, AudioBufferList **audioBufferList, UInt32 ioPackets) { int i; UInt32 maxBytesPerPacket = 4096; ComponentResult err = noErr; err = QTGetComponentProperty(as->aud.vorbisComponentInstance, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_MaximumOutputPacketSize, sizeof(maxBytesPerPacket), &maxBytesPerPacket, NULL); if (err) { dbg_printf("[Webm] Error getting max Bytes per packet\n"); maxBytesPerPacket = 255 *255; //this should be roughly valid for ogg Vorbis err = noErr; } UInt32 bufferListSize = offsetof(AudioBufferList, mBuffers[ioPackets]); dbg_printf("[WebM]Calling InitAudioBufferList size %ld, each buffer being %lu\n", bufferListSize, maxBytesPerPacket); *audioBufferList = (AudioBufferList *) malloc(bufferListSize); (*audioBufferList)->mNumberBuffers = ioPackets; UInt32 wantedSize = maxBytesPerPacket * ioPackets; if (as->aud.buf.data == NULL || as->aud.buf.size != wantedSize) { as->aud.buf.data = realloc(as->aud.buf.data, wantedSize); as->aud.buf.size = wantedSize; as->aud.buf.offset = 0; } for (i = 0; i < ioPackets; i++) { (*audioBufferList)->mBuffers[i].mNumberChannels = as->aud.asbd.mChannelsPerFrame; (*audioBufferList)->mBuffers[i].mDataByteSize = maxBytesPerPacket; (*audioBufferList)->mBuffers[i].mData = (void *)((unsigned char *)as->aud.buf.data + maxBytesPerPacket * i); } }
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; }
ComponentResult write_vorbisPrivateData(GenericStreamPtr as, UInt8 **buf, UInt32 *bufSize) { ComponentResult err = noErr; void *magicCookie = NULL; UInt32 cookieSize = 0; dbg_printf("[WebM] Get Vorbis Private Data\n"); err = QTGetComponentPropertyInfo(as->aud.vorbisComponentInstance, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_MagicCookie, NULL, &cookieSize, NULL); if (err) return err; dbg_printf("[WebM] Cookie Size %d\n", cookieSize); magicCookie = calloc(1, cookieSize); err = QTGetComponentProperty(as->aud.vorbisComponentInstance, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_MagicCookie, cookieSize, magicCookie, NULL); if (err) goto bail; UInt8 *ptrheader = (UInt8 *) magicCookie; UInt8 *cend = ptrheader + cookieSize; CookieAtomHeader *aheader = (CookieAtomHeader *) ptrheader; WebMBuffer header, header_vc, header_cb; header.size = header_vc.size = header_cb.size = 0; while (ptrheader < cend) { aheader = (CookieAtomHeader *) ptrheader; ptrheader += EndianU32_BtoN(aheader->size); if (ptrheader > cend || EndianU32_BtoN(aheader->size) <= 0) break; switch (EndianS32_BtoN(aheader->type)) { case kCookieTypeVorbisHeader: header.size = EndianS32_BtoN(aheader->size) - 2 * sizeof(long); header.data = aheader->data; break; case kCookieTypeVorbisComments: header_vc.size = EndianS32_BtoN(aheader->size) - 2 * sizeof(long); header_vc.data = aheader->data; break; case kCookieTypeVorbisCodebooks: header_cb.size = EndianS32_BtoN(aheader->size) - 2 * sizeof(long); header_cb.data = aheader->data; break; default: break; } } if (header.size == 0 || header_vc.size == 0 || header_cb.size == 0) { err = paramErr; goto bail; } //1 + header1 /255 + header2 /255 + idheader.len + *bufSize = 1; //the first byte which is always 0x02 *bufSize += (header.size - 1) / 255 + 1; //the header size lacing *bufSize += (header_vc.size - 1) / 255 + 1; //the comment size lacing *bufSize += header.size + header_vc.size + header_cb.size; //the packets dbg_printf("[WebM]Packet headers %d %d %d -- total buffer %d\n", header.size, header_vc.size , header_cb.size, *bufSize); *buf = malloc(*bufSize); UInt8 *ptr = *buf; *ptr = 0x02; ptr ++; //using ogg lacing write out the size of the first two packets _oggLacing(&ptr, header.size); _oggLacing(&ptr, header_vc.size); _dbg_printVorbisHeader(header.data); memcpy(ptr, header.data, header.size); ptr += header.size; memcpy(ptr, header_vc.data, header_vc.size); ptr += header_vc.size; memcpy(ptr, header_cb.data, header_cb.size); bail: if (magicCookie != NULL) { free(magicCookie); magicCookie = NULL; } return err; }