void AACEncode::setBitrate(int bitrate) { if(m_bitrate != bitrate) { m_converterMutex.lock(); UInt32 br = bitrate; AudioConverterDispose(m_audioConverter); const OSType subtype = kAudioFormatMPEG4AAC; AudioClassDescription requestedCodecs[2] = { { kAudioEncoderComponentType, subtype, kAppleSoftwareAudioCodecManufacturer }, { kAudioEncoderComponentType, subtype, kAppleHardwareAudioCodecManufacturer } }; AudioConverterNewSpecific(&m_in, &m_out, 2,requestedCodecs, &m_audioConverter); OSStatus result = AudioConverterSetProperty(m_audioConverter, kAudioConverterEncodeBitRate, sizeof(br), &br); UInt32 propSize = sizeof(br); if(result == noErr) { AudioConverterGetProperty(m_audioConverter, kAudioConverterEncodeBitRate, &propSize, &br); m_bitrate = br; } m_converterMutex.unlock(); } }
void Audio_Stream::setCookiesForStream(AudioFileStreamID inAudioFileStream) { OSStatus err; // get the cookie size UInt32 cookieSize; Boolean writable; err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable); if (err) { return; } // get the cookie data void* cookieData = calloc(1, cookieSize); err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData); if (err) { free(cookieData); return; } // set the cookie on the queue. if (m_audioConverter) { err = AudioConverterSetProperty(m_audioConverter, kAudioConverterDecompressionMagicCookie, cookieSize, cookieData); } free(cookieData); }
static int ffat_update_ctx(AVCodecContext *avctx) { ATDecodeContext *at = avctx->priv_data; AudioStreamBasicDescription format; UInt32 size = sizeof(format); if (!AudioConverterGetProperty(at->converter, kAudioConverterCurrentInputStreamDescription, &size, &format)) { if (format.mSampleRate) avctx->sample_rate = format.mSampleRate; avctx->channels = format.mChannelsPerFrame; avctx->channel_layout = av_get_default_channel_layout(avctx->channels); avctx->frame_size = format.mFramesPerPacket; } if (!AudioConverterGetProperty(at->converter, kAudioConverterCurrentOutputStreamDescription, &size, &format)) { format.mSampleRate = avctx->sample_rate; format.mChannelsPerFrame = avctx->channels; AudioConverterSetProperty(at->converter, kAudioConverterCurrentOutputStreamDescription, size, &format); } if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterOutputChannelLayout, &size, NULL) && size) { AudioChannelLayout *layout = av_malloc(size); uint64_t layout_mask = 0; int i; if (!layout) return AVERROR(ENOMEM); AudioConverterGetProperty(at->converter, kAudioConverterOutputChannelLayout, &size, layout); if (!(layout = ffat_convert_layout(layout, &size))) return AVERROR(ENOMEM); for (i = 0; i < layout->mNumberChannelDescriptions; i++) { int id = ffat_get_channel_id(layout->mChannelDescriptions[i].mChannelLabel); if (id < 0) goto done; if (layout_mask & (1 << id)) goto done; layout_mask |= 1 << id; layout->mChannelDescriptions[i].mChannelFlags = i; // Abusing flags as index } avctx->channel_layout = layout_mask; qsort(layout->mChannelDescriptions, layout->mNumberChannelDescriptions, sizeof(AudioChannelDescription), &ffat_compare_channel_descriptions); for (i = 0; i < layout->mNumberChannelDescriptions; i++) at->channel_map[i] = layout->mChannelDescriptions[i].mChannelFlags; done: av_free(layout); } if (!avctx->frame_size) avctx->frame_size = 2048; return 0; }
static void ca_start_w(CAData *d){ OSStatus err= noErr; if (d->write_started==FALSE){ AudioStreamBasicDescription inASBD; int i; i = ca_open_w(d); if (i<0) return; inASBD = d->caOutASBD; inASBD.mSampleRate = d->rate; inASBD.mFormatID = kAudioFormatLinearPCM; inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; if (htonl(0x1234) == 0x1234) inASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; inASBD.mChannelsPerFrame = d->stereo ? 2 : 1; inASBD.mBytesPerPacket = (d->bits / 8) * inASBD.mChannelsPerFrame; inASBD.mBytesPerFrame = (d->bits / 8) * inASBD.mChannelsPerFrame; inASBD.mFramesPerPacket = 1; inASBD.mBitsPerChannel = d->bits; err = AudioConverterNew( &inASBD, &d->caOutASBD, &d->caOutConverter); if(err != noErr) ms_error("AudioConverterNew %x %d", err, inASBD.mBytesPerFrame); else CAShow(d->caOutConverter); if (inASBD.mChannelsPerFrame == 1 && d->caOutASBD.mChannelsPerFrame == 2) { if (d->caOutConverter) { // This should be as large as the number of output channels, // each element specifies which input channel's data is routed to that output channel SInt32 channelMap[] = { 0, 0 }; err = AudioConverterSetProperty(d->caOutConverter, kAudioConverterChannelMap, 2*sizeof(SInt32), channelMap); } } memset((char*)&d->caOutRenderCallback, 0, sizeof(AURenderCallbackStruct)); d->caOutRenderCallback.inputProc = writeRenderProc; d->caOutRenderCallback.inputProcRefCon = d; err = AudioUnitSetProperty (d->caOutAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &d->caOutRenderCallback, sizeof(AURenderCallbackStruct)); if(err != noErr) ms_error("AudioUnitSetProperty %x", err); if(err == noErr) { if(AudioOutputUnitStart(d->caOutAudioUnit) == noErr) d->write_started=TRUE; } } }
// _______________________________________________________________________________________ // void CAAudioFile::SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout) { LOG_FUNCTION("CAAudioFile::SetConverterChannelLayout", "%p", this); OSStatus err; if (layout.IsValid()) { #if VERBOSE_CHANNELMAP printf("Setting converter's %s channel layout: %s\n", output ? "output" : "input", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); #endif if (output) { err = AudioConverterSetProperty(mConverter, kAudioConverterOutputChannelLayout, layout.Size(), &layout.Layout()); XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's output channel layout"); } else { err = AudioConverterSetProperty(mConverter, kAudioConverterInputChannelLayout, layout.Size(), &layout.Layout()); XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's input channel layout"); } if (mMode == kPreparingToWrite) FileFormatChanged(); } }
// _______________________________________________________________________________________ // OSStatus CAAudioFile::SetConverterProperty( AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData, bool inCanFail) { OSStatus err = noErr; //LOG_FUNCTION("ExtAudioFile::SetConverterProperty", "%p %-4.4s", this, (char *)&inPropertyID); if (inPropertyID == kAudioConverterPropertySettings && *(CFPropertyListRef *)inPropertyData == NULL) ; else { err = AudioConverterSetProperty(mConverter, inPropertyID, inPropertyDataSize, inPropertyData); if (!inCanFail) { XThrowIfError(err, "set audio converter property"); } } UpdateClientMaxPacketSize(); if (mMode == kPreparingToWrite) FileFormatChanged(); return err; }
static int ffat_set_extradata(AVCodecContext *avctx) { ATDecodeContext *at = avctx->priv_data; if (ffat_usable_extradata(avctx)) { OSStatus status; UInt32 cookie_size; uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size); if (!cookie) return AVERROR(ENOMEM); status = AudioConverterSetProperty(at->converter, kAudioConverterDecompressionMagicCookie, cookie_size, cookie); if (status != 0) av_log(avctx, AV_LOG_WARNING, "AudioToolbox cookie error: %i\n", (int)status); if (cookie != at->extradata) av_free(cookie); } return 0; }
// Some audio formats have a magic cookie associated with them which is required to decompress audio data // When converting audio data you must check to see if the format of the data has a magic cookie // If the audio data format has a magic cookie associated with it, you must add this information to anAudio Converter // using AudioConverterSetProperty and kAudioConverterDecompressionMagicCookie to appropriately decompress the data // http://developer.apple.com/mac/library/qa/qa2001/qa1318.html static void ReadCookie(AudioFileID sourceFileID, AudioConverterRef converter) { // grab the cookie from the source file and set it on the converter UInt32 cookieSize = 0; OSStatus error = AudioFileGetPropertyInfo(sourceFileID, kAudioFilePropertyMagicCookieData, &cookieSize, NULL); // if there is an error here, then the format doesn't have a cookie - this is perfectly fine as some formats do not if (noErr == error && 0 != cookieSize) { char* cookie = new char [cookieSize]; error = AudioFileGetProperty(sourceFileID, kAudioFilePropertyMagicCookieData, &cookieSize, cookie); if (noErr == error) { error = AudioConverterSetProperty(converter, kAudioConverterDecompressionMagicCookie, cookieSize, cookie); if (error) printf("Could not Set kAudioConverterDecompressionMagicCookie on the Audio Converter!\n"); } else { printf("Could not Get kAudioFilePropertyMagicCookieData from source file!\n"); } delete [] cookie; } }
const OSStatus AudioFile::setClientFormat(const AudioStreamBasicDescription clientASBD) { checkError(AudioConverterNew(&mInputFormat, &clientASBD, &mAudioConverterRef), "AudioConverterNew"); mClientFormat = clientASBD; UInt32 size = sizeof(UInt32); UInt32 maxPacketSize; checkError(AudioFileGetProperty(mAudioFileID, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize), "AudioFileGetProperty"); if (mIsVBR) { mPacketDescs = (AudioStreamPacketDescription*)calloc(mNumPacketsToRead, sizeof(AudioStreamPacketDescription)); } // set magic cookie to the AudioConverter { UInt32 cookieSize; OSStatus err = AudioFileGetPropertyInfo(mAudioFileID, kAudioFilePropertyMagicCookieData, &cookieSize, NULL); if (err == noErr && cookieSize > 0){ char *magicCookie = (char*)malloc(sizeof(UInt8) * cookieSize); UInt32 magicCookieSize = cookieSize; AudioFileGetProperty(mAudioFileID, kAudioFilePropertyMagicCookieData, &magicCookieSize, magicCookie); AudioConverterSetProperty(mAudioConverterRef, kAudioConverterDecompressionMagicCookie, magicCookieSize, magicCookie); free(magicCookie); } } return noErr; }
void AudioConverterX::setSoundQualityForVBR(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertySoundQualityForVBR, sizeof value, &value)); }
void AudioConverterX::setBitRateControlMode(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertyBitRateControlMode, sizeof value, &value)); }
void AudioConverterX::setOutputChannelLayout(const AudioChannelLayout &value) { UInt32 size = cautil::sizeofAudioChannelLayout(value); CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterOutputChannelLayout, size, &value)); }
void AudioConverterX::setEncodeBitRate(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterEncodeBitRate, sizeof value, &value)); }
int AudioDecoderCoreAudio::open() { //Open the audio file. OSStatus err; /** This code blocks works with OS X 10.5+ only. DO NOT DELETE IT for now. */ /*CFStringRef urlStr = CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>( //qurlStr.unicode()), qurlStr.size()); m_filename.data()), m_filename.size()); */ CFStringRef urlStr = CFStringCreateWithCString(kCFAllocatorDefault, m_filename.c_str(), kCFStringEncodingUTF8); //CFStringGetSystemEncoding()); CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, urlStr, kCFURLPOSIXPathStyle, false); err = ExtAudioFileOpenURL(urlRef, &m_audioFile); CFRelease(urlStr); CFRelease(urlRef); /** TODO: Use FSRef for compatibility with 10.4 Tiger. Note that ExtAudioFileOpen() is deprecated above Tiger, so we must maintain both code paths if someone finishes this part of the code. FSRef fsRef; CFURLGetFSRef(reinterpret_cast<CFURLRef>(url.get()), &fsRef); err = ExtAudioFileOpen(&fsRef, &m_audioFile); */ if (err != noErr) { std::cerr << "AudioDecoderCoreAudio: Error opening file." << std::endl; return AUDIODECODER_ERROR; } // get the input file format CAStreamBasicDescription inputFormat; UInt32 size = sizeof(inputFormat); err = ExtAudioFileGetProperty(m_audioFile, kExtAudioFileProperty_FileDataFormat, &size, &inputFormat); if (err != noErr) { std::cerr << "AudioDecoderCoreAudio: Error getting file format." << std::endl; return AUDIODECODER_ERROR; } m_inputFormat = inputFormat; // create the output format CAStreamBasicDescription outputFormat; bzero(&outputFormat, sizeof(AudioStreamBasicDescription)); outputFormat.mFormatID = kAudioFormatLinearPCM; outputFormat.mSampleRate = inputFormat.mSampleRate; outputFormat.mChannelsPerFrame = 2; outputFormat.mFormatFlags = kAudioFormatFlagsCanonical; //kAudioFormatFlagsCanonical means Native endian, float, packed on Mac OS X, //but signed int for iOS instead. //Note iPhone/iOS only supports signed integers supposedly: outputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger; //Debugging: //printf ("Source File format: "); inputFormat.Print(); //printf ("Dest File format: "); outputFormat.Print(); /* switch(inputFormat.mBitsPerChannel) { case 16: outputFormat.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData; break; case 20: outputFormat.mFormatFlags = kAppleLosslessFormatFlag_20BitSourceData; break; case 24: outputFormat.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData; break; case 32: outputFormat.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData; break; }*/ // get and set the client format - it should be lpcm CAStreamBasicDescription clientFormat = outputFormat; //We're always telling the OS to do the conversion to floats for us now clientFormat.mChannelsPerFrame = 2; clientFormat.mBytesPerFrame = sizeof(SAMPLE)*clientFormat.mChannelsPerFrame; clientFormat.mBitsPerChannel = sizeof(SAMPLE)*8; //16 for signed int, 32 for float; clientFormat.mFramesPerPacket = 1; clientFormat.mBytesPerPacket = clientFormat.mBytesPerFrame*clientFormat.mFramesPerPacket; clientFormat.mReserved = 0; m_clientFormat = clientFormat; size = sizeof(clientFormat); err = ExtAudioFileSetProperty(m_audioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); if (err != noErr) { //qDebug() << "SSCA: Error setting file property"; std::cerr << "AudioDecoderCoreAudio: Error setting file property." << std::endl; return AUDIODECODER_ERROR; } //Set m_iChannels and m_iNumSamples; m_iChannels = clientFormat.NumberChannels(); //get the total length in frames of the audio file - copypasta: http://discussions.apple.com/thread.jspa?threadID=2364583&tstart=47 UInt32 dataSize; SInt64 totalFrameCount; dataSize = sizeof(totalFrameCount); //XXX: This looks sketchy to me - Albert err = ExtAudioFileGetProperty(m_audioFile, kExtAudioFileProperty_FileLengthFrames, &dataSize, &totalFrameCount); if (err != noErr) { std::cerr << "AudioDecoderCoreAudio: Error getting number of frames." << std::endl; return AUDIODECODER_ERROR; } // // WORKAROUND for bug in ExtFileAudio // AudioConverterRef acRef; UInt32 acrsize=sizeof(AudioConverterRef); err = ExtAudioFileGetProperty(m_audioFile, kExtAudioFileProperty_AudioConverter, &acrsize, &acRef); //_ThrowExceptionIfErr(@"kExtAudioFileProperty_AudioConverter", err); AudioConverterPrimeInfo primeInfo; UInt32 piSize=sizeof(AudioConverterPrimeInfo); memset(&primeInfo, 0, piSize); err = AudioConverterGetProperty(acRef, kAudioConverterPrimeInfo, &piSize, &primeInfo); if(err != kAudioConverterErr_PropertyNotSupported) // Only if decompressing { //_ThrowExceptionIfErr(@"kAudioConverterPrimeInfo", err); m_headerFrames=primeInfo.leadingFrames; } m_iNumSamples = (totalFrameCount/*-m_headerFrames*/)*m_iChannels; m_iSampleRate = inputFormat.mSampleRate; m_fDuration = m_iNumSamples / static_cast<float>(m_iSampleRate * m_iChannels); //Convert mono files into stereo if (inputFormat.NumberChannels() == 1) { SInt32 channelMap[2] = {0, 0}; // array size should match the number of output channels AudioConverterSetProperty(acRef, kAudioConverterChannelMap, sizeof(channelMap), channelMap); } //Seek to position 0, which forces us to skip over all the header frames. //This makes sure we're ready to just let the Analyser rip and it'll //get the number of samples it expects (ie. no header frames). seek(0); return AUDIODECODER_OK; }
void AudioConverterX::setPrimeInfo(const AudioConverterPrimeInfo &info) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterPrimeInfo, sizeof(info), &info)); }
void AudioConverterX::setSampleRateConverterQuality(UInt32 quality) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterSampleRateConverterQuality, sizeof quality, &quality)); }
OSStatus DoConvertFile(CFURLRef sourceURL, CFURLRef destinationURL, OSType outputFormat, Float64 outputSampleRate, UInt32 outputBitRate) { AudioFileID sourceFileID = 0; AudioFileID destinationFileID = 0; AudioConverterRef converter = NULL; Boolean canResumeFromInterruption = true; // we can continue unless told otherwise CAStreamBasicDescription srcFormat, dstFormat; AudioFileIO afio = {}; char *outputBuffer = NULL; AudioStreamPacketDescription *outputPacketDescriptions = NULL; OSStatus error = noErr; // in this sample we should never be on the main thread here assert(![NSThread isMainThread]); // transition thread state to kStateRunning before continuing printf("\nDoConvertFile\n"); try { // get the source file XThrowIfError(AudioFileOpenURL(sourceURL, kAudioFileReadPermission, 0, &sourceFileID), "AudioFileOpenURL failed"); // get the source data format UInt32 size = sizeof(srcFormat); XThrowIfError(AudioFileGetProperty(sourceFileID, kAudioFilePropertyDataFormat, &size, &srcFormat), "couldn't get source data format"); // setup the output file format dstFormat.mSampleRate = (outputSampleRate == 0 ? srcFormat.mSampleRate : outputSampleRate); // set sample rate if (outputFormat == kAudioFormatLinearPCM) { // if the output format is PC create a 16-bit int PCM file format description as an example dstFormat.mFormatID = outputFormat; dstFormat.mChannelsPerFrame = srcFormat.NumberChannels(); dstFormat.mBitsPerChannel = 16; dstFormat.mBytesPerPacket = dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame; dstFormat.mFramesPerPacket = 1; dstFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; // little-endian } else { // compressed format - need to set at least format, sample rate and channel fields for kAudioFormatProperty_FormatInfo dstFormat.mFormatID = outputFormat; dstFormat.mChannelsPerFrame = (outputFormat == kAudioFormatiLBC ? 1 : srcFormat.NumberChannels()); // for iLBC num channels must be 1 // use AudioFormat API to fill out the rest of the description size = sizeof(dstFormat); XThrowIfError(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &dstFormat), "couldn't create destination data format"); } printf("Source File format: "); srcFormat.Print(); printf("Destination format: "); dstFormat.Print(); // create the AudioConverter XThrowIfError(AudioConverterNew(&srcFormat, &dstFormat, &converter), "AudioConverterNew failed!"); // if the source has a cookie, get it and set it on the Audio Converter ReadCookie(sourceFileID, converter); // get the actual formats back from the Audio Converter size = sizeof(srcFormat); XThrowIfError(AudioConverterGetProperty(converter, kAudioConverterCurrentInputStreamDescription, &size, &srcFormat), "AudioConverterGetProperty kAudioConverterCurrentInputStreamDescription failed!"); size = sizeof(dstFormat); XThrowIfError(AudioConverterGetProperty(converter, kAudioConverterCurrentOutputStreamDescription, &size, &dstFormat), "AudioConverterGetProperty kAudioConverterCurrentOutputStreamDescription failed!"); printf("Formats returned from AudioConverter:\n"); printf(" Source format: "); srcFormat.Print(); printf(" Destination File format: "); dstFormat.Print(); // if encoding to AAC set the bitrate // kAudioConverterEncodeBitRate is a UInt32 value containing the number of bits per second to aim for when encoding data // when you explicitly set the bit rate and the sample rate, this tells the encoder to stick with both bit rate and sample rate // but there are combinations (also depending on the number of channels) which will not be allowed // if you do not explicitly set a bit rate the encoder will pick the correct value for you depending on samplerate and number of channels // bit rate also scales with the number of channels, therefore one bit rate per sample rate can be used for mono cases // and if you have stereo or more, you can multiply that number by the number of channels. if (outputBitRate == 0) { outputBitRate = 192000; // 192kbs } if (dstFormat.mFormatID == kAudioFormatMPEG4AAC) { UInt32 propSize = sizeof(outputBitRate); // set the bit rate depending on the samplerate chosen XThrowIfError(AudioConverterSetProperty(converter, kAudioConverterEncodeBitRate, propSize, &outputBitRate), "AudioConverterSetProperty kAudioConverterEncodeBitRate failed!"); // get it back and print it out AudioConverterGetProperty(converter, kAudioConverterEncodeBitRate, &propSize, &outputBitRate); printf ("AAC Encode Bitrate: %u\n", (unsigned int)outputBitRate); } // can the Audio Converter resume conversion after an interruption? // this property may be queried at any time after construction of the Audio Converter after setting its output format // there's no clear reason to prefer construction time, interruption time, or potential resumption time but we prefer // construction time since it means less code to execute during or after interruption time UInt32 canResume = 0; size = sizeof(canResume); error = AudioConverterGetProperty(converter, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume); if (noErr == error) { // we recieved a valid return value from the GetProperty call // if the property's value is 1, then the codec CAN resume work following an interruption // if the property's value is 0, then interruptions destroy the codec's state and we're done if (0 == canResume) canResumeFromInterruption = false; printf("Audio Converter %s continue after interruption!\n", (canResumeFromInterruption == 0 ? "CANNOT" : "CAN")); } else { // if the property is unimplemented (kAudioConverterErr_PropertyNotSupported, or paramErr returned in the case of PCM), // then the codec being used is not a hardware codec so we're not concerned about codec state // we are always going to be able to resume conversion after an interruption if (kAudioConverterErr_PropertyNotSupported == error) { printf("kAudioConverterPropertyCanResumeFromInterruption property not supported - see comments in source for more info.\n"); } else { printf("AudioConverterGetProperty kAudioConverterPropertyCanResumeFromInterruption result %ld, paramErr is OK if PCM\n", error); } error = noErr; } // create the destination file XThrowIfError(AudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, kAudioFileFlags_EraseFile, &destinationFileID), "AudioFileCreateWithURL failed!"); // set up source buffers and data proc info struct afio.srcFileID = sourceFileID; afio.srcBufferSize = 32768; afio.srcBuffer = new char [afio.srcBufferSize]; afio.srcFilePos = 0; afio.srcFormat = srcFormat; if (srcFormat.mBytesPerPacket == 0) { // if the source format is VBR, we need to get the maximum packet size // use kAudioFilePropertyPacketSizeUpperBound which returns the theoretical maximum packet size // in the file (without actually scanning the whole file to find the largest packet, // as may happen with kAudioFilePropertyMaximumPacketSize) size = sizeof(afio.srcSizePerPacket); XThrowIfError(AudioFileGetProperty(sourceFileID, kAudioFilePropertyPacketSizeUpperBound, &size, &afio.srcSizePerPacket), "AudioFileGetProperty kAudioFilePropertyPacketSizeUpperBound failed!"); // how many packets can we read for our buffer size? afio.numPacketsPerRead = afio.srcBufferSize / afio.srcSizePerPacket; // allocate memory for the PacketDescription structures describing the layout of each packet afio.packetDescriptions = new AudioStreamPacketDescription [afio.numPacketsPerRead]; } else { // CBR source format afio.srcSizePerPacket = srcFormat.mBytesPerPacket; afio.numPacketsPerRead = afio.srcBufferSize / afio.srcSizePerPacket; afio.packetDescriptions = NULL; } // set up output buffers UInt32 outputSizePerPacket = dstFormat.mBytesPerPacket; // this will be non-zero if the format is CBR UInt32 theOutputBufSize = 32768; outputBuffer = new char[theOutputBufSize]; if (outputSizePerPacket == 0) { // if the destination format is VBR, we need to get max size per packet from the converter size = sizeof(outputSizePerPacket); XThrowIfError(AudioConverterGetProperty(converter, kAudioConverterPropertyMaximumOutputPacketSize, &size, &outputSizePerPacket), "AudioConverterGetProperty kAudioConverterPropertyMaximumOutputPacketSize failed!"); // allocate memory for the PacketDescription structures describing the layout of each packet outputPacketDescriptions = new AudioStreamPacketDescription [theOutputBufSize / outputSizePerPacket]; } UInt32 numOutputPackets = theOutputBufSize / outputSizePerPacket; // if the destination format has a cookie, get it and set it on the output file WriteCookie(converter, destinationFileID); // write destination channel layout if (srcFormat.mChannelsPerFrame > 2) { WriteDestinationChannelLayout(converter, sourceFileID, destinationFileID); } UInt64 totalOutputFrames = 0; // used for debgging printf SInt64 outputFilePos = 0; // loop to convert data printf("Converting...\n"); while (1) { // set up output buffer list AudioBufferList fillBufList; fillBufList.mNumberBuffers = 1; fillBufList.mBuffers[0].mNumberChannels = dstFormat.mChannelsPerFrame; fillBufList.mBuffers[0].mDataByteSize = theOutputBufSize; fillBufList.mBuffers[0].mData = outputBuffer; // this will block if we're interrupted Boolean wasInterrupted = NO; if ((error || wasInterrupted) && (false == canResumeFromInterruption)) { // this is our interruption termination condition // an interruption has occured but the Audio Converter cannot continue error = kMyAudioConverterErr_CannotResumeFromInterruptionError; break; } // convert data UInt32 ioOutputDataPackets = numOutputPackets; printf("AudioConverterFillComplexBuffer...\n"); error = AudioConverterFillComplexBuffer(converter, EncoderDataProc, &afio, &ioOutputDataPackets, &fillBufList, outputPacketDescriptions); // if interrupted in the process of the conversion call, we must handle the error appropriately if (error) { if (kAudioConverterErr_HardwareInUse == error) { printf("Audio Converter returned kAudioConverterErr_HardwareInUse!\n"); } else { XThrowIfError(error, "AudioConverterFillComplexBuffer error!"); } } else { if (ioOutputDataPackets == 0) { // this is the EOF conditon error = noErr; break; } } if (noErr == error) { // write to output file UInt32 inNumBytes = fillBufList.mBuffers[0].mDataByteSize; XThrowIfError(AudioFileWritePackets(destinationFileID, false, inNumBytes, outputPacketDescriptions, outputFilePos, &ioOutputDataPackets, outputBuffer), "AudioFileWritePackets failed!"); printf("Convert Output: Write %lu packets at position %lld, size: %ld\n", ioOutputDataPackets, outputFilePos, inNumBytes); // advance output file packet position outputFilePos += ioOutputDataPackets; if (dstFormat.mFramesPerPacket) { // the format has constant frames per packet totalOutputFrames += (ioOutputDataPackets * dstFormat.mFramesPerPacket); } else if (outputPacketDescriptions != NULL) { // variable frames per packet require doing this for each packet (adding up the number of sample frames of data in each packet) for (UInt32 i = 0; i < ioOutputDataPackets; ++i) totalOutputFrames += outputPacketDescriptions[i].mVariableFramesInPacket; } } } // while if (noErr == error) { // write out any of the leading and trailing frames for compressed formats only if (dstFormat.mBitsPerChannel == 0) { // our output frame count should jive with printf("Total number of output frames counted: %lld\n", totalOutputFrames); WritePacketTableInfo(converter, destinationFileID); } // write the cookie again - sometimes codecs will update cookies at the end of a conversion WriteCookie(converter, destinationFileID); } } catch (CAXException e) { char buf[256]; fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); error = e.mError; } // cleanup if (converter) AudioConverterDispose(converter); if (destinationFileID) AudioFileClose(destinationFileID); if (sourceFileID) AudioFileClose(sourceFileID); if (afio.srcBuffer) delete [] afio.srcBuffer; if (afio.packetDescriptions) delete [] afio.packetDescriptions; if (outputBuffer) delete [] outputBuffer; if (outputPacketDescriptions) delete [] outputPacketDescriptions; return error; }
int ConvertFile (CFURLRef inputFileURL, CAStreamBasicDescription &inputFormat, CFURLRef outputFileURL, AudioFileTypeID outputFileType, CAStreamBasicDescription &outputFormat, UInt32 outputBitRate) { ExtAudioFileRef infile, outfile; // first open the input file OSStatus err = ExtAudioFileOpenURL (inputFileURL, &infile); XThrowIfError (err, "ExtAudioFileOpen"); // if outputBitRate is specified, this can change the sample rate of the output file // so we let this "take care of itself" if (outputBitRate) outputFormat.mSampleRate = 0.; // create the output file (this will erase an exsiting file) err = ExtAudioFileCreateWithURL (outputFileURL, outputFileType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outfile); XThrowIfError (err, "ExtAudioFileCreateNew"); // get and set the client format - it should be lpcm CAStreamBasicDescription clientFormat = (inputFormat.mFormatID == kAudioFormatLinearPCM ? inputFormat : outputFormat); UInt32 size = sizeof(clientFormat); err = ExtAudioFileSetProperty(infile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); XThrowIfError (err, "ExtAudioFileSetProperty inFile, kExtAudioFileProperty_ClientDataFormat"); size = sizeof(clientFormat); err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); XThrowIfError (err, "ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ClientDataFormat"); if( outputBitRate > 0 ) { printf ("Dest bit rate: %d\n", (int)outputBitRate); AudioConverterRef outConverter; size = sizeof(outConverter); err = ExtAudioFileGetProperty(outfile, kExtAudioFileProperty_AudioConverter, &size, &outConverter); XThrowIfError (err, "ExtAudioFileGetProperty outFile, kExtAudioFileProperty_AudioConverter"); err = AudioConverterSetProperty(outConverter, kAudioConverterEncodeBitRate, sizeof(outputBitRate), &outputBitRate); XThrowIfError (err, "AudioConverterSetProperty, kAudioConverterEncodeBitRate"); // we have changed the converter, so we should do this in case // setting a converter property changes the converter used by ExtAF in some manner CFArrayRef config = NULL; err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ConverterConfig, sizeof(config), &config); XThrowIfError (err, "ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ConverterConfig"); } // set up buffers char srcBuffer[kSrcBufSize]; // do the read and write - the conversion is done on and by the write call while (1) { AudioBufferList fillBufList; fillBufList.mNumberBuffers = 1; fillBufList.mBuffers[0].mNumberChannels = inputFormat.mChannelsPerFrame; fillBufList.mBuffers[0].mDataByteSize = kSrcBufSize; fillBufList.mBuffers[0].mData = srcBuffer; // client format is always linear PCM - so here we determine how many frames of lpcm // we can read/write given our buffer size UInt32 numFrames = (kSrcBufSize / clientFormat.mBytesPerFrame); // printf("test %d\n", numFrames); err = ExtAudioFileRead (infile, &numFrames, &fillBufList); XThrowIfError (err, "ExtAudioFileRead"); if (!numFrames) { // this is our termination condition break; } err = ExtAudioFileWrite(outfile, numFrames, &fillBufList); XThrowIfError (err, "ExtAudioFileWrite"); } // close ExtAudioFileDispose(outfile); ExtAudioFileDispose(infile); return 0; }
static GVBool gviHardwareInitPlayback(GVIDevice * device) { GVIHardwareData * data = (GVIHardwareData *)device->m_data; UInt32 size; OSStatus result; UInt32 primeMethod; SInt32 channelMap[100]; int i; // create the array of sources data->m_playbackSources = gviNewSourceList(); if(!data->m_playbackSources) return GVFalse; // get the playback format size = sizeof(AudioStreamBasicDescription); result = AudioDeviceGetProperty(device->m_deviceID, 0, false, kAudioDevicePropertyStreamFormat, &size, &data->m_playbackStreamDescriptor); if(result != noErr) { gviFreeSourceList(data->m_playbackSources); return GVFalse; } // create a converter from the GV format to the playback format result = AudioConverterNew(&GVIVoiceFormat, &data->m_playbackStreamDescriptor, &data->m_playbackConverter); if(result != noErr) { gviFreeSourceList(data->m_playbackSources); return GVFalse; } // set it to do no priming primeMethod = kConverterPrimeMethod_None; result = AudioConverterSetProperty(data->m_playbackConverter, kAudioConverterPrimeMethod, sizeof(UInt32), &primeMethod); if(result != noErr) { AudioConverterDispose(data->m_playbackConverter); gviFreeSourceList(data->m_playbackSources); return GVFalse; } // setup the converter to map the input channel to all output channels result = AudioConverterGetPropertyInfo(data->m_playbackConverter, kAudioConverterChannelMap, &size, NULL); if(result == noErr) { result = AudioConverterGetProperty(data->m_playbackConverter, kAudioConverterChannelMap, &size, channelMap); if(result == noErr) { for(i = 0 ; i < (size / sizeof(SInt32)) ; i++) channelMap[i] = 0; AudioConverterSetProperty(data->m_playbackConverter, kAudioConverterChannelMap, size, channelMap); } } // allocate the playback buffer data->m_playbackBuffer = (GVSample *)gsimalloc(GVIBytesPerFrame); if(!data->m_playbackBuffer) { AudioConverterDispose(data->m_playbackConverter); gviFreeSourceList(data->m_playbackSources); return GVFalse; } // add property listener AudioDeviceAddPropertyListener(device->m_deviceID, 0, false, kAudioDevicePropertyDeviceIsAlive, gviPropertyListener, device); #if GVI_VOLUME_IN_SOFTWARE // init volume data->m_playbackVolume = (GVScalar)1.0; #endif return GVTrue; }
/*********************************************************************** * hb_work_encCoreAudio_init *********************************************************************** * **********************************************************************/ int encCoreAudioInit(hb_work_object_t *w, hb_job_t *job, enum AAC_MODE mode) { hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); hb_audio_t *audio = w->audio; AudioStreamBasicDescription input, output; UInt32 tmp, tmpsiz = sizeof(tmp); OSStatus err; w->private_data = pv; pv->job = job; // pass the number of channels used into the private work data pv->nchannels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); bzero(&input, sizeof(AudioStreamBasicDescription)); input.mSampleRate = (Float64)audio->config.out.samplerate; input.mFormatID = kAudioFormatLinearPCM; input.mFormatFlags = (kLinearPCMFormatFlagIsFloat|kAudioFormatFlagsNativeEndian); input.mBytesPerPacket = 4 * pv->nchannels; input.mFramesPerPacket = 1; input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket; input.mChannelsPerFrame = pv->nchannels; input.mBitsPerChannel = 32; bzero(&output, sizeof(AudioStreamBasicDescription)); switch (mode) { case AAC_MODE_HE: output.mFormatID = kAudioFormatMPEG4AAC_HE; break; case AAC_MODE_LC: default: output.mFormatID = kAudioFormatMPEG4AAC; break; } output.mSampleRate = (Float64)audio->config.out.samplerate; output.mChannelsPerFrame = pv->nchannels; // let CoreAudio decide the rest // initialise encoder err = AudioConverterNew(&input, &output, &pv->converter); if (err != noErr) { // Retry without the samplerate bzero(&output, sizeof(AudioStreamBasicDescription)); switch (mode) { case AAC_MODE_HE: output.mFormatID = kAudioFormatMPEG4AAC_HE; break; case AAC_MODE_LC: default: output.mFormatID = kAudioFormatMPEG4AAC; break; } output.mChannelsPerFrame = pv->nchannels; err = AudioConverterNew(&input, &output, &pv->converter); if (err != noErr) { hb_log("Error creating an AudioConverter err=%"PRId64" output.mBytesPerFrame=%"PRIu64"", (int64_t)err, (uint64_t)output.mBytesPerFrame); *job->done_error = HB_ERROR_UNKNOWN; *job->die = 1; return -1; } } // set encoder quality to maximum tmp = kAudioConverterQuality_Max; AudioConverterSetProperty(pv->converter, kAudioConverterCodecQuality, sizeof(tmp), &tmp); if (audio->config.out.bitrate > 0) { // set encoder bitrate control mode to constrained variable tmp = kAudioCodecBitRateControlMode_VariableConstrained; AudioConverterSetProperty(pv->converter, kAudioCodecPropertyBitRateControlMode, sizeof(tmp), &tmp); // get available bitrates AudioValueRange *bitrates; ssize_t bitrateCounts; err = AudioConverterGetPropertyInfo(pv->converter, kAudioConverterApplicableEncodeBitRates, &tmpsiz, NULL); bitrates = malloc(tmpsiz); err = AudioConverterGetProperty(pv->converter, kAudioConverterApplicableEncodeBitRates, &tmpsiz, bitrates); bitrateCounts = tmpsiz / sizeof(AudioValueRange); // set bitrate tmp = audio->config.out.bitrate * 1000; if (tmp < bitrates[0].mMinimum) tmp = bitrates[0].mMinimum; if (tmp > bitrates[bitrateCounts-1].mMinimum) tmp = bitrates[bitrateCounts-1].mMinimum; free(bitrates); if (tmp != audio->config.out.bitrate * 1000) { hb_log("encCoreAudioInit: sanitizing track %d audio bitrate %d to %"PRIu32"", audio->config.out.track, audio->config.out.bitrate, tmp / 1000); } AudioConverterSetProperty(pv->converter, kAudioConverterEncodeBitRate, sizeof(tmp), &tmp); } else if (audio->config.out.quality >= 0) { if (mode != AAC_MODE_LC) { hb_error("encCoreAudioInit: internal error, VBR set but not applicable"); return 1; } // set encoder bitrate control mode to variable tmp = kAudioCodecBitRateControlMode_Variable; AudioConverterSetProperty(pv->converter, kAudioCodecPropertyBitRateControlMode, sizeof(tmp), &tmp); // set quality tmp = audio->config.out.quality; AudioConverterSetProperty(pv->converter, kAudioCodecPropertySoundQualityForVBR, sizeof(tmp), &tmp); } else { hb_error("encCoreAudioInit: internal error, bitrate/quality not set"); return 1; } // get real input tmpsiz = sizeof(input); AudioConverterGetProperty(pv->converter, kAudioConverterCurrentInputStreamDescription, &tmpsiz, &input); // get real output tmpsiz = sizeof(output); AudioConverterGetProperty(pv->converter, kAudioConverterCurrentOutputStreamDescription, &tmpsiz, &output); // set sizes pv->isamplesiz = input.mBytesPerPacket; pv->isamples = output.mFramesPerPacket; pv->osamplerate = output.mSampleRate; audio->config.out.samples_per_frame = pv->isamples; // channel remapping pv->remap = hb_audio_remap_init(AV_SAMPLE_FMT_FLT, &hb_aac_chan_map, audio->config.in.channel_map); if (pv->remap == NULL) { hb_error("encCoreAudioInit: hb_audio_remap_init() failed"); } uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); hb_audio_remap_set_channel_layout(pv->remap, layout); // get maximum output size AudioConverterGetProperty(pv->converter, kAudioConverterPropertyMaximumOutputPacketSize, &tmpsiz, &tmp); pv->omaxpacket = tmp; // get magic cookie (elementary stream descriptor) tmp = HB_CONFIG_MAX_SIZE; AudioConverterGetProperty(pv->converter, kAudioConverterCompressionMagicCookie, &tmp, w->config->extradata.bytes); // CoreAudio returns a complete ESDS, but we only need // the DecoderSpecific info. UInt8* buffer = NULL; ReadESDSDescExt(w->config->extradata.bytes, &buffer, &tmpsiz, 0); w->config->extradata.length = tmpsiz; memmove(w->config->extradata.bytes, buffer, w->config->extradata.length); free(buffer); pv->list = hb_list_init(); pv->buf = NULL; return 0; }
/*********************************************************************** * hb_work_encCoreAudio_init *********************************************************************** * **********************************************************************/ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job, enum AAC_MODE mode ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); hb_audio_t * audio = w->audio; AudioStreamBasicDescription input, output; UInt32 tmp, tmpsiz = sizeof( tmp ); OSStatus err; w->private_data = pv; pv->job = job; // pass the number of channels used into the private work data pv->nchannels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( audio->config.out.mixdown ); bzero( &input, sizeof( AudioStreamBasicDescription ) ); input.mSampleRate = ( Float64 ) audio->config.out.samplerate; input.mFormatID = kAudioFormatLinearPCM; input.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian; input.mBytesPerPacket = 4 * pv->nchannels; input.mFramesPerPacket = 1; input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket; input.mChannelsPerFrame = pv->nchannels; input.mBitsPerChannel = 32; bzero( &output, sizeof( AudioStreamBasicDescription ) ); switch ( mode ) { case AAC_MODE_HE: output.mFormatID = kAudioFormatMPEG4AAC_HE; break; case AAC_MODE_LC: default: output.mFormatID = kAudioFormatMPEG4AAC; break; } output.mSampleRate = ( Float64 ) audio->config.out.samplerate; output.mChannelsPerFrame = pv->nchannels; // let CoreAudio decide the rest... // initialise encoder err = AudioConverterNew( &input, &output, &pv->converter ); if( err != noErr) { // Retry without the samplerate bzero( &output, sizeof( AudioStreamBasicDescription ) ); switch ( mode ) { case AAC_MODE_HE: output.mFormatID = kAudioFormatMPEG4AAC_HE; break; case AAC_MODE_LC: default: output.mFormatID = kAudioFormatMPEG4AAC; break; } output.mChannelsPerFrame = pv->nchannels; err = AudioConverterNew( &input, &output, &pv->converter ); if( err != noErr) { hb_log( "Error creating an AudioConverter err=%"PRId64" %"PRIu64, (int64_t)err, (uint64_t)output.mBytesPerFrame ); *job->die = 1; return 0; } } if( ( audio->config.out.mixdown == HB_AMIXDOWN_6CH ) && ( audio->config.in.codec == HB_ACODEC_AC3) ) { SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 }; AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap, sizeof( channelMap ), channelMap ); } // set encoder quality to maximum tmp = kAudioConverterQuality_Max; AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality, sizeof( tmp ), &tmp ); // set encoder bitrate control mode to constrained variable tmp = kAudioCodecBitRateControlMode_VariableConstrained; AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode, sizeof( tmp ), &tmp ); // get available bitrates AudioValueRange *bitrates; ssize_t bitrateCounts; err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates, &tmpsiz, NULL); bitrates = malloc( tmpsiz ); err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates, &tmpsiz, bitrates); bitrateCounts = tmpsiz / sizeof( AudioValueRange ); // set bitrate tmp = audio->config.out.bitrate * 1000; if( tmp < bitrates[0].mMinimum ) tmp = bitrates[0].mMinimum; if( tmp > bitrates[bitrateCounts-1].mMinimum ) tmp = bitrates[bitrateCounts-1].mMinimum; free( bitrates ); if( tmp != audio->config.out.bitrate * 1000 ) hb_log( "encca_aac: sanitizing track %d audio bitrate %d to %"PRIu32"", audio->config.out.track, audio->config.out.bitrate, tmp/1000 ); AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate, sizeof( tmp ), &tmp ); // get real input tmpsiz = sizeof( input ); AudioConverterGetProperty( pv->converter, kAudioConverterCurrentInputStreamDescription, &tmpsiz, &input ); // get real output tmpsiz = sizeof( output ); AudioConverterGetProperty( pv->converter, kAudioConverterCurrentOutputStreamDescription, &tmpsiz, &output ); // set sizes pv->isamplesiz = input.mBytesPerPacket; pv->isamples = output.mFramesPerPacket; pv->osamplerate = output.mSampleRate; // get maximum output size AudioConverterGetProperty( pv->converter, kAudioConverterPropertyMaximumOutputPacketSize, &tmpsiz, &tmp ); pv->omaxpacket = tmp; // get magic cookie (elementary stream descriptor) tmp = HB_CONFIG_MAX_SIZE; AudioConverterGetProperty( pv->converter, kAudioConverterCompressionMagicCookie, &tmp, w->config->aac.bytes ); // CoreAudio returns a complete ESDS, but we only need // the DecoderSpecific info. UInt8* buffer = NULL; ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0); w->config->aac.length = tmpsiz; memmove( w->config->aac.bytes, buffer, w->config->aac.length ); pv->list = hb_list_init(); pv->buf = NULL; return 0; }
// _______________________________________________________________________________________ // void CAAudioFile::SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout) { LOG_FUNCTION("CAAudioFile::SetClientFormat", "%p", this); XThrowIf(!dataFormat.IsPCM(), kExtAudioFileError_NonPCMClientFormat, "non-PCM client format on audio file"); bool dataFormatChanging = (mClientDataFormat.mFormatID == 0 || mClientDataFormat != dataFormat); if (dataFormatChanging) { CloseConverter(); if (mWriteBufferList) { delete mWriteBufferList; mWriteBufferList = NULL; } mClientDataFormat = dataFormat; } if (layout && layout->IsValid()) { XThrowIf(layout->NumberChannels() != mClientDataFormat.NumberChannels(), kExtAudioFileError_InvalidChannelMap, "inappropriate channel map"); mClientChannelLayout = *layout; } bool differentLayouts; if (mClientChannelLayout.IsValid()) { if (mFileChannelLayout.IsValid()) { differentLayouts = mClientChannelLayout.Tag() != mFileChannelLayout.Tag(); #if VERBOSE_CHANNELMAP printf("two valid layouts, %s\n", differentLayouts ? "different" : "same"); #endif } else { differentLayouts = false; #if VERBOSE_CHANNELMAP printf("valid client layout, unknown file layout\n"); #endif } } else { differentLayouts = false; #if VERBOSE_CHANNELMAP if (mFileChannelLayout.IsValid()) printf("valid file layout, unknown client layout\n"); else printf("two invalid layouts\n"); #endif } if (mClientDataFormat != mFileDataFormat || differentLayouts) { // We need an AudioConverter. if (mMode == kReading) { // file -> client (decode) //mFileDataFormat.PrintFormat( stdout, "", "File: "); //mClientDataFormat.PrintFormat(stdout, "", "Client: "); if (mConverter == NULL) XThrowIfError(AudioConverterNew(&mFileDataFormat, &mClientDataFormat, &mConverter), "create audio converter"); #if VERBOSE_CONVERTER printf("CAAudioFile %p -- created converter\n", this); CAShow(mConverter); #endif // set the magic cookie, if any (for decode) if (mMagicCookie) SetConverterProperty(kAudioConverterDecompressionMagicCookie, mMagicCookieSize, mMagicCookie, mFileDataFormat.IsPCM()); // we get cookies from some AIFF's but the converter barfs on them, // so we set canFail to true for PCM SetConverterChannelLayout(false, mFileChannelLayout); SetConverterChannelLayout(true, mClientChannelLayout); // propagate leading/trailing frame counts if (mFileDataFormat.mBitsPerChannel == 0) { UInt32 propertySize; OSStatus err; AudioFilePacketTableInfo pti; propertySize = sizeof(pti); err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti); if (err == noErr && (pti.mPrimingFrames > 0 || pti.mRemainderFrames > 0)) { AudioConverterPrimeInfo primeInfo; primeInfo.leadingFrames = pti.mPrimingFrames; primeInfo.trailingFrames = pti.mRemainderFrames; /* ignore any error. better to play it at all than not. */ /*err = */AudioConverterSetProperty(mConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo); //XThrowIfError(err, "couldn't set prime info on converter"); } } } else if (mMode == kPreparingToCreate || mMode == kPreparingToWrite) { // client -> file (encode) if (mConverter == NULL) XThrowIfError(AudioConverterNew(&mClientDataFormat, &mFileDataFormat, &mConverter), "create audio converter"); mWriteBufferList = CABufferList::New("", mClientDataFormat); SetConverterChannelLayout(false, mClientChannelLayout); SetConverterChannelLayout(true, mFileChannelLayout); if (mMode == kPreparingToWrite) FileFormatChanged(); } else XThrowIfError(kExtAudioFileError_InvalidOperationOrder, "audio file format not yet known"); } UpdateClientMaxPacketSize(); }
void AudioConverterX::setCodecQuality(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterCodecQuality, sizeof value, &value)); }
JNIEXPORT jint JNICALL Java_com_apple_audio_toolbox_AudioConverter_AudioConverterSetProperty (JNIEnv *, jclass, jint inAudioConverter, jint inPropertyID, jint inPropertyDataSize, jint inPropertyData) { return (jint)AudioConverterSetProperty((AudioConverterRef)inAudioConverter, (AudioConverterPropertyID)inPropertyID, (UInt32)inPropertyDataSize, (void *)inPropertyData); }
void AudioConverterX::setSampleRateConverterComplexity(UInt32 complexity) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterSampleRateConverterComplexity, sizeof complexity, &complexity)); }
std::shared_ptr<Buffer> AudioMixer::resample(const uint8_t* const buffer, size_t size, AudioBufferMetadata& metadata) { const auto inFrequncyInHz = metadata.getData<kAudioMetadataFrequencyInHz>(); const auto inBitsPerChannel = metadata.getData<kAudioMetadataBitsPerChannel>(); const auto inChannelCount = metadata.getData<kAudioMetadataChannelCount>(); const auto inFlags = metadata.getData<kAudioMetadataFlags>(); const auto inBytesPerFrame = metadata.getData<kAudioMetadataBytesPerFrame>(); const auto inNumberFrames = metadata.getData<kAudioMetadataNumberFrames>(); const auto inUsesOSStruct = metadata.getData<kAudioMetadataUsesOSStruct>(); if(m_outFrequencyInHz == inFrequncyInHz && m_outBitsPerChannel == inBitsPerChannel && m_outChannelCount == inChannelCount && !(inFlags & kAudioFormatFlagIsNonInterleaved) && !(inFlags & kAudioFormatFlagIsFloat)) { // No resampling necessary return std::make_shared<Buffer>(); } uint64_t hash = uint64_t(inBytesPerFrame&0xFF) << 56 | uint64_t(inFlags&0xFF) << 48 | uint64_t(inChannelCount&0xFF) << 40 | uint64_t(inBitsPerChannel&0xFF) << 32 | inFrequncyInHz; auto it = m_converters.find(hash) ; ConverterInst converter = {0}; if(it == m_converters.end()) { AudioStreamBasicDescription in = {0}; AudioStreamBasicDescription out = {0}; in.mFormatID = kAudioFormatLinearPCM; in.mFormatFlags = inFlags; in.mChannelsPerFrame = inChannelCount; in.mSampleRate = inFrequncyInHz; in.mBitsPerChannel = inBitsPerChannel; in.mBytesPerFrame = inBytesPerFrame; in.mFramesPerPacket = 1; in.mBytesPerPacket = in.mBytesPerFrame * in.mFramesPerPacket; out.mFormatID = kAudioFormatLinearPCM; out.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; out.mChannelsPerFrame = m_outChannelCount; out.mSampleRate = m_outFrequencyInHz; out.mBitsPerChannel = m_outBitsPerChannel; out.mBytesPerFrame = (out.mBitsPerChannel * out.mChannelsPerFrame) / 8; out.mFramesPerPacket = 1; out.mBytesPerPacket = out.mBytesPerFrame * out.mFramesPerPacket; converter.asbdIn = in; converter.asbdOut = out; OSStatus ret = AudioConverterNew(&in, &out, &converter.converter); AudioConverterSetProperty(converter.converter, kAudioConverterSampleRateConverterComplexity, sizeof(s_samplingRateConverterComplexity), &s_samplingRateConverterComplexity); AudioConverterSetProperty(converter.converter, kAudioConverterSampleRateConverterQuality, sizeof(s_samplingRateConverterQuality), &s_samplingRateConverterQuality); auto prime = kConverterPrimeMethod_None; AudioConverterSetProperty(converter.converter, kAudioConverterPrimeMethod, sizeof(prime), &prime); m_converters[hash] = converter; if(ret != noErr) { DLog("ret = %d (%x)", (int)ret, (unsigned)ret); } } else { converter = it->second; } auto & in = converter.asbdIn; auto & out = converter.asbdOut; const double inSampleCount = inNumberFrames; const double ratio = static_cast<double>(inFrequncyInHz) / static_cast<double>(m_outFrequencyInHz); const double outBufferSampleCount = std::round(double(inSampleCount) / ratio); const size_t outBufferSize = out.mBytesPerPacket * outBufferSampleCount; const auto outBuffer = std::make_shared<Buffer>(outBufferSize); std::unique_ptr<UserData> ud(new UserData()); ud->size = static_cast<int>(size); ud->data = const_cast<uint8_t*>(buffer); ud->p = inUsesOSStruct ? 0 : ud->data; ud->packetSize = in.mBytesPerPacket; ud->numberPackets = inSampleCount; ud->numChannels = inChannelCount; ud->isInterleaved = !(inFlags & kAudioFormatFlagIsNonInterleaved); ud->usesOSStruct = inUsesOSStruct; AudioBufferList outBufferList; outBufferList.mNumberBuffers = 1; outBufferList.mBuffers[0].mDataByteSize = static_cast<UInt32>(outBufferSize); outBufferList.mBuffers[0].mNumberChannels = m_outChannelCount; outBufferList.mBuffers[0].mData = (*outBuffer)(); UInt32 sampleCount = outBufferSampleCount; OSStatus ret = AudioConverterFillComplexBuffer(converter.converter, /* AudioConverterRef inAudioConverter */ AudioMixer::ioProc, /* AudioConverterComplexInputDataProc inInputDataProc */ ud.get(), /* void *inInputDataProcUserData */ &sampleCount, /* UInt32 *ioOutputDataPacketSize */ &outBufferList, /* AudioBufferList *outOutputData */ NULL /* AudioStreamPacketDescription *outPacketDescription */ ); if(ret != noErr) { DLog("ret = %d (%x)", (int)ret, (unsigned)ret); } outBuffer->setSize(outBufferList.mBuffers[0].mDataByteSize); return outBuffer; }
void AudioConverterX::setPrimeMethod(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterPrimeMethod, sizeof value, &value)); }
AACEncode::AACEncode(int frequencyInHz, int channelCount, int bitrate) : m_sentConfig(false), m_bitrate(bitrate) { OSStatus result = 0; AudioStreamBasicDescription in = {0}, out = {0}; // passing anything except 48000, 44100, and 22050 for mSampleRate results in "!dat" // OSStatus when querying for kAudioConverterPropertyMaximumOutputPacketSize property // below in.mSampleRate = frequencyInHz; // passing anything except 2 for mChannelsPerFrame results in "!dat" OSStatus when // querying for kAudioConverterPropertyMaximumOutputPacketSize property below in.mChannelsPerFrame = channelCount; in.mBitsPerChannel = 16; in.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; in.mFormatID = kAudioFormatLinearPCM; in.mFramesPerPacket = 1; in.mBytesPerFrame = in.mBitsPerChannel * in.mChannelsPerFrame / 8; in.mBytesPerPacket = in.mFramesPerPacket*in.mBytesPerFrame; m_in = in; out.mFormatID = kAudioFormatMPEG4AAC; out.mFormatFlags = 0; out.mFramesPerPacket = kSamplesPerFrame; out.mSampleRate = frequencyInHz; out.mChannelsPerFrame = channelCount; m_out = out; UInt32 outputBitrate = bitrate; UInt32 propSize = sizeof(outputBitrate); UInt32 outputPacketSize = 0; const OSType subtype = kAudioFormatMPEG4AAC; AudioClassDescription requestedCodecs[2] = { { kAudioEncoderComponentType, subtype, kAppleSoftwareAudioCodecManufacturer }, { kAudioEncoderComponentType, subtype, kAppleHardwareAudioCodecManufacturer } }; result = AudioConverterNewSpecific(&in, &out, 2, requestedCodecs, &m_audioConverter); if(result == noErr) { result = AudioConverterSetProperty(m_audioConverter, kAudioConverterEncodeBitRate, propSize, &outputBitrate); } if(result == noErr) { result = AudioConverterGetProperty(m_audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, &propSize, &outputPacketSize); } if(result == noErr) { m_outputPacketMaxSize = outputPacketSize; m_bytesPerSample = 2 * channelCount; uint8_t sampleRateIndex = 0; switch(frequencyInHz) { case 96000: sampleRateIndex = 0; break; case 88200: sampleRateIndex = 1; break; case 64000: sampleRateIndex = 2; break; case 48000: sampleRateIndex = 3; break; case 44100: sampleRateIndex = 4; break; case 32000: sampleRateIndex = 5; break; case 24000: sampleRateIndex = 6; break; case 22050: sampleRateIndex = 7; break; case 16000: sampleRateIndex = 8; break; case 12000: sampleRateIndex = 9; break; case 11025: sampleRateIndex = 10; break; case 8000: sampleRateIndex = 11; break; case 7350: sampleRateIndex = 12; break; default: sampleRateIndex = 15; } makeAsc(sampleRateIndex, uint8_t(channelCount)); } else { DLog("Error setting up audio encoder %x", (int)result); } }
void AudioConverterX::setDecompressionMagicCookie(const std::vector<uint8_t> &v) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterDecompressionMagicCookie, v.size(), v.data())); }
static av_cold int ffat_init_encoder(AVCodecContext *avctx) { ATDecodeContext *at = avctx->priv_data; OSStatus status; AudioStreamBasicDescription in_format = { .mSampleRate = avctx->sample_rate, .mFormatID = kAudioFormatLinearPCM, .mFormatFlags = ((avctx->sample_fmt == AV_SAMPLE_FMT_FLT || avctx->sample_fmt == AV_SAMPLE_FMT_DBL) ? kAudioFormatFlagIsFloat : avctx->sample_fmt == AV_SAMPLE_FMT_U8 ? 0 : kAudioFormatFlagIsSignedInteger) | kAudioFormatFlagIsPacked, .mBytesPerPacket = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels, .mFramesPerPacket = 1, .mBytesPerFrame = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels, .mChannelsPerFrame = avctx->channels, .mBitsPerChannel = av_get_bytes_per_sample(avctx->sample_fmt) * 8, }; AudioStreamBasicDescription out_format = { .mSampleRate = avctx->sample_rate, .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile), .mChannelsPerFrame = in_format.mChannelsPerFrame, }; UInt32 layout_size = sizeof(AudioChannelLayout) + sizeof(AudioChannelDescription) * avctx->channels; AudioChannelLayout *channel_layout = av_malloc(layout_size); if (!channel_layout) return AVERROR(ENOMEM); if (avctx->codec_id == AV_CODEC_ID_ILBC) { int mode = get_ilbc_mode(avctx); out_format.mFramesPerPacket = 8000 * mode / 1000; out_format.mBytesPerPacket = (mode == 20 ? 38 : 50); } status = AudioConverterNew(&in_format, &out_format, &at->converter); if (status != 0) { av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status); av_free(channel_layout); return AVERROR_UNKNOWN; } if (!avctx->channel_layout) avctx->channel_layout = av_get_default_channel_layout(avctx->channels); if ((status = remap_layout(channel_layout, avctx->channel_layout, avctx->channels)) < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid channel layout\n"); av_free(channel_layout); return status; } if (AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout, layout_size, channel_layout)) { av_log(avctx, AV_LOG_ERROR, "Unsupported input channel layout\n"); av_free(channel_layout); return AVERROR(EINVAL); } if (avctx->codec_id == AV_CODEC_ID_AAC) { int tag = get_aac_tag(avctx->channel_layout); if (tag) { channel_layout->mChannelLayoutTag = tag; channel_layout->mNumberChannelDescriptions = 0; } } if (AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout, layout_size, channel_layout)) { av_log(avctx, AV_LOG_ERROR, "Unsupported output channel layout\n"); av_free(channel_layout); return AVERROR(EINVAL); } av_free(channel_layout); if (avctx->bits_per_raw_sample) AudioConverterSetProperty(at->converter, kAudioConverterPropertyBitDepthHint, sizeof(avctx->bits_per_raw_sample), &avctx->bits_per_raw_sample); #if !TARGET_OS_IPHONE if (at->mode == -1) at->mode = (avctx->flags & AV_CODEC_FLAG_QSCALE) ? kAudioCodecBitRateControlMode_Variable : kAudioCodecBitRateControlMode_Constant; AudioConverterSetProperty(at->converter, kAudioCodecPropertyBitRateControlMode, sizeof(at->mode), &at->mode); if (at->mode == kAudioCodecBitRateControlMode_Variable) { int q = avctx->global_quality / FF_QP2LAMBDA; if (q < 0 || q > 14) { av_log(avctx, AV_LOG_WARNING, "VBR quality %d out of range, should be 0-14\n", q); q = av_clip(q, 0, 14); } q = 127 - q * 9; AudioConverterSetProperty(at->converter, kAudioCodecPropertySoundQualityForVBR, sizeof(q), &q); } else #endif if (avctx->bit_rate > 0) { UInt32 rate = avctx->bit_rate; UInt32 size; status = AudioConverterGetPropertyInfo(at->converter, kAudioConverterApplicableEncodeBitRates, &size, NULL); if (!status && size) { UInt32 new_rate = rate; int count; int i; AudioValueRange *ranges = av_malloc(size); if (!ranges) return AVERROR(ENOMEM); AudioConverterGetProperty(at->converter, kAudioConverterApplicableEncodeBitRates, &size, ranges); count = size / sizeof(AudioValueRange); for (i = 0; i < count; i++) { AudioValueRange *range = &ranges[i]; if (rate >= range->mMinimum && rate <= range->mMaximum) { new_rate = rate; break; } else if (rate > range->mMaximum) { new_rate = range->mMaximum; } else { new_rate = range->mMinimum; break; } } if (new_rate != rate) { av_log(avctx, AV_LOG_WARNING, "Bitrate %u not allowed; changing to %u\n", rate, new_rate); rate = new_rate; } av_free(ranges); } AudioConverterSetProperty(at->converter, kAudioConverterEncodeBitRate, sizeof(rate), &rate); } at->quality = 96 - at->quality * 32; AudioConverterSetProperty(at->converter, kAudioConverterCodecQuality, sizeof(at->quality), &at->quality); if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterCompressionMagicCookie, &avctx->extradata_size, NULL) && avctx->extradata_size) { int extradata_size = avctx->extradata_size; uint8_t *extradata; if (!(avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE))) return AVERROR(ENOMEM); if (avctx->codec_id == AV_CODEC_ID_ALAC) { avctx->extradata_size = 0x24; AV_WB32(avctx->extradata, 0x24); AV_WB32(avctx->extradata + 4, MKBETAG('a','l','a','c')); extradata = avctx->extradata + 12; avctx->extradata_size = 0x24; } else { extradata = avctx->extradata; } status = AudioConverterGetProperty(at->converter, kAudioConverterCompressionMagicCookie, &extradata_size, extradata); if (status != 0) { av_log(avctx, AV_LOG_ERROR, "AudioToolbox cookie error: %i\n", (int)status); return AVERROR_UNKNOWN; } else if (avctx->codec_id == AV_CODEC_ID_AAC) { GetByteContext gb; int tag, len; bytestream2_init(&gb, extradata, extradata_size); do { len = read_descr(&gb, &tag); if (tag == MP4DecConfigDescrTag) { bytestream2_skip(&gb, 13); len = read_descr(&gb, &tag); if (tag == MP4DecSpecificDescrTag) { len = FFMIN(gb.buffer_end - gb.buffer, len); memmove(extradata, gb.buffer, len); avctx->extradata_size = len; break; } } else if (tag == MP4ESDescrTag) { int flags; bytestream2_skip(&gb, 2); flags = bytestream2_get_byte(&gb); if (flags & 0x80) //streamDependenceFlag bytestream2_skip(&gb, 2); if (flags & 0x40) //URL_Flag bytestream2_skip(&gb, bytestream2_get_byte(&gb)); if (flags & 0x20) //OCRstreamFlag bytestream2_skip(&gb, 2); } } while (bytestream2_get_bytes_left(&gb)); } else if (avctx->codec_id != AV_CODEC_ID_ALAC) { avctx->extradata_size = extradata_size; } } ffat_update_ctx(avctx); #if !TARGET_OS_IPHONE && defined(__MAC_10_9) if (at->mode == kAudioCodecBitRateControlMode_Variable && avctx->rc_max_rate) { UInt32 max_size = avctx->rc_max_rate * avctx->frame_size / avctx->sample_rate; if (max_size) AudioConverterSetProperty(at->converter, kAudioCodecPropertyPacketSizeLimitForVBR, sizeof(max_size), &max_size); } #endif ff_af_queue_init(avctx, &at->afq); return 0; } static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_packets, AudioBufferList *data, AudioStreamPacketDescription **packets, void *inctx) { AVCodecContext *avctx = inctx; ATDecodeContext *at = avctx->priv_data; AVFrame *frame; if (!at->frame_queue.available) { if (at->eof) { *nb_packets = 0; return 0; } else { *nb_packets = 0; return 1; } } frame = ff_bufqueue_get(&at->frame_queue); data->mNumberBuffers = 1; data->mBuffers[0].mNumberChannels = avctx->channels; data->mBuffers[0].mDataByteSize = frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels; data->mBuffers[0].mData = frame->data[0]; if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; ff_bufqueue_add(avctx, &at->used_frame_queue, frame); return 0; } static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { ATDecodeContext *at = avctx->priv_data; OSStatus ret; AudioBufferList out_buffers = { .mNumberBuffers = 1, .mBuffers = { { .mNumberChannels = avctx->channels, .mDataByteSize = at->pkt_size, } } };