std::vector<AudioValueRange> AudioConverterX::getApplicableEncodeBitRates() { UInt32 size; Boolean writable; CHECKCA(AudioConverterGetPropertyInfo(m_converter.get(), kAudioConverterApplicableEncodeBitRates, &size, &writable)); std::vector<AudioValueRange> vec(size / sizeof(AudioValueRange)); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterApplicableEncodeBitRates, &size, vec.data())); return vec; }
std::vector<uint8_t> AudioConverterX::getCompressionMagicCookie() { UInt32 size; Boolean writable; CHECKCA(AudioConverterGetPropertyInfo(m_converter.get(), kAudioConverterCompressionMagicCookie, &size, &writable)); std::vector<uint8_t> vec(size / sizeof(uint8_t)); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterCompressionMagicCookie, &size, vec.data())); return vec; }
std::shared_ptr<AudioChannelLayout> AudioConverterX::getOutputChannelLayout() { UInt32 size; Boolean writable; CHECKCA(AudioConverterGetPropertyInfo(m_converter.get(), kAudioConverterOutputChannelLayout, &size, &writable)); std::shared_ptr<AudioChannelLayout> acl( static_cast<AudioChannelLayout*>(std::malloc(size)), std::free); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterOutputChannelLayout, &size, acl.get())); return acl; }
AudioConverterX::AudioConverterX(const AudioStreamBasicDescription &iasbd, const AudioStreamBasicDescription &oasbd) { AudioConverterRef converter; CHECKCA(AudioConverterNew(&iasbd, &oasbd, &converter)); attach(converter, true); }
uint32_t CoreAudioEncoder::encodeChunk(UInt32 npackets) { prepareOutputBuffer(npackets); AudioBufferList *abl = m_output_abl.get(); AudioStreamPacketDescription *aspd = &m_packet_desc[0]; CHECKCA(AudioConverterFillComplexBuffer(m_converter, staticInputDataProc, this, &npackets, abl, aspd)); if (samplesRead() == 0) return false; if (npackets == 0 && abl->mBuffers[0].mDataByteSize == 0) return 0; if (!m_requires_packet_desc) { writeSamples(abl->mBuffers[0].mData, abl->mBuffers[0].mDataByteSize, npackets); } else { for (uint32_t i = 0; i < npackets; ++i) { if (aspd[i].mVariableFramesInPacket) m_variable_packet_len = true; uint32_t nsamples = m_variable_packet_len ? aspd[i].mVariableFramesInPacket : m_output_desc.mFramesPerPacket; if (nsamples) { uint8_t *p = static_cast<uint8_t*>(abl->mBuffers[0].mData); writeSamples(p + aspd[i].mStartOffset, aspd[i].mDataByteSize, nsamples); } } } return npackets; }
UInt32 AudioConverterX::getSampleRateConverterComplexity() { UInt32 value; UInt32 size = sizeof value; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterSampleRateConverterComplexity, &size, &value)); return value; }
UInt32 AudioConverterX::getEncodeBitRate() { UInt32 value; UInt32 size = sizeof value; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterEncodeBitRate, &size, &value)); return value; }
UInt32 AudioConverterX::getCodecQuality() { UInt32 result; UInt32 size = sizeof result; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterCodecQuality, &size, &result)); return result; }
UInt32 AudioConverterX::getSoundQualityForVBR() { UInt32 result; UInt32 size = sizeof result; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioCodecPropertySoundQualityForVBR, &size, &result)); return result; }
AudioConverterPrimeInfo AudioConverterX::getPrimeInfo() { AudioConverterPrimeInfo result; UInt32 size = sizeof(AudioConverterPrimeInfo); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterPrimeInfo, &size, &result)); return result; }
UInt32 AudioConverterX::getBitRateControlMode() { UInt32 result; UInt32 size = sizeof result; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioCodecPropertyBitRateControlMode, &size, &result)); return result; }
UInt32 AudioConverterX::getMaximumOutputPacketSize() { UInt32 result; UInt32 size = sizeof result; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterPropertyMaximumOutputPacketSize, &size, &result)); return result; }
AudioStreamBasicDescription AudioConverterX::getOutputStreamDescription() { AudioStreamBasicDescription result; UInt32 size = sizeof(result); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterCurrentOutputStreamDescription, &size, &result)); return result; }
UInt32 AudioConverterX::getPrimeMethod() { UInt32 value; UInt32 size = sizeof value; CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterPrimeMethod, &size, &value)); return value; }
size_t ExtAFSource::readSamples(void *buffer, size_t nsamples) { UInt32 ns = nsamples; UInt32 nb = ns * m_asbd.mBytesPerFrame; AudioBufferList abl = { 0 }; abl.mNumberBuffers = 1; abl.mBuffers[0].mNumberChannels = m_asbd.mChannelsPerFrame; abl.mBuffers[0].mData = buffer; abl.mBuffers[0].mDataByteSize = nb; CHECKCA(ExtAudioFileRead(m_eaf, &ns, &abl)); return ns; }
size_t ALACSource::readSamples(void *buffer, size_t nsamples) { uint32_t bpf = m_asbd.mBytesPerFrame; if (!m_buffer.count()) { uint32_t size; MP4SampleId sid; try { sid = m_file.GetSampleIdFromTime(m_track_id, m_position); size = m_file.GetSampleSize(m_track_id, sid); } catch (mp4v2::impl::Exception *e) { delete e; return 0; } MP4Timestamp start; MP4Duration duration; std::vector<uint8_t> ivec(size); uint8_t *vp = &ivec[0]; try { m_file.ReadSample(m_track_id, sid, &vp, &size, &start, &duration); } catch (mp4v2::impl::Exception *e) { handle_mp4error(e); } BitBuffer bits; BitBufferInit(&bits, vp, size); m_buffer.resize(duration); uint32_t ncount; CHECKCA(m_decoder->Decode(&bits, m_buffer.write_ptr(), duration, m_asbd.mChannelsPerFrame, &ncount)); m_buffer.commit(ncount); m_buffer.advance(m_position - start); } uint32_t count = std::min(m_buffer.count(), static_cast<uint32_t>(nsamples)); size_t nbytes = count * bpf; util::unpack(m_buffer.read_ptr(), buffer, &nbytes, m_asbd.mBytesPerFrame / m_asbd.mChannelsPerFrame, m_oasbd.mBytesPerFrame / m_oasbd.mChannelsPerFrame); m_buffer.advance(count); m_position += count; return count; }
void ExtAFSource::seekTo(int64_t count) { int npreroll = 0; switch (m_iasbd.mFormatID) { case kAudioFormatMPEGLayer1: npreroll = 1; break; case kAudioFormatMPEGLayer2: npreroll = 1; break; case kAudioFormatMPEGLayer3: npreroll = 10; break; } int64_t off = std::max(0LL, count - m_iasbd.mFramesPerPacket * npreroll); CHECKCA(ExtAudioFileSeek(m_eaf, off)); int32_t distance = count - off; while (distance > 0) { size_t nbytes = distance * m_asbd.mBytesPerFrame; if (nbytes > m_buffer.size()) m_buffer.resize(nbytes); size_t n = readSamples(&m_buffer[0], distance); if (n <= 0) break; distance -= n; } }
ALACEncoderX::ALACEncoderX(const AudioStreamBasicDescription &desc) : m_encoder(new ALACEncoder()), m_iasbd(desc) { std::memcpy(&m_iafd, &desc, sizeof desc); m_iafd.mBytesPerFrame = ((desc.mBitsPerChannel + 7) & ~7) * desc.mChannelsPerFrame / 8; m_iafd.mBytesPerPacket = m_iafd.mBytesPerFrame * m_iafd.mFramesPerPacket; memset(&m_odesc, 0, sizeof m_odesc); AudioStreamBasicDescription & oasbd = m_odesc.asbd; oasbd.mFormatID = kALACFormatAppleLossless; if (desc.mFormatFlags & kAudioFormatFlagIsFloat) throw std::runtime_error("ALAC: Float PCM is not supported"); switch (desc.mBitsPerChannel) { case 16: oasbd.mFormatFlags = 1; break; case 20: oasbd.mFormatFlags = 2; break; case 24: oasbd.mFormatFlags = 3; break; case 32: oasbd.mFormatFlags = 4; break; default: throw std::runtime_error("ALAC: Not supported bit depth"); } if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian) throw std::runtime_error("ALAC: Big endian input is not supported"); oasbd.mChannelsPerFrame = desc.mChannelsPerFrame; oasbd.mSampleRate = desc.mSampleRate; oasbd.mFramesPerPacket = kALACDefaultFramesPerPacket; CHECKCA(m_encoder->InitializeEncoder(m_odesc.afd)); m_stat.setBasicDescription(oasbd); uint32_t pullbytes = desc.mBytesPerFrame * kALACDefaultFramesPerPacket; m_input_buffer.resize(pullbytes); m_output_buffer.resize(pullbytes * 2); }
CoreAudioEncoder::CoreAudioEncoder(AudioConverterX &converter) : m_converter(converter), m_variable_packet_len(false) { m_converter.getInputStreamDescription(&m_input_desc); m_converter.getOutputStreamDescription(&m_output_desc); m_stat.setBasicDescription(m_output_desc); { UInt32 res; UInt32 size = sizeof res; CHECKCA(AudioFormatGetProperty( kAudioFormatProperty_FormatIsExternallyFramed, sizeof m_output_desc, &m_output_desc, &size, &res)); m_requires_packet_desc = !!res; } { AudioBufferList *abl; size_t size = offsetof(AudioBufferList, mBuffers[1]); abl = static_cast<AudioBufferList*>(std::calloc(1, size)); abl->mBuffers[0].mNumberChannels = m_output_desc.mChannelsPerFrame; abl->mNumberBuffers = 1; m_output_abl = std::shared_ptr<AudioBufferList>(abl, std::free); } }
void AudioConverterX::setEncodeBitRate(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterEncodeBitRate, sizeof value, &value)); }
void AudioConverterX::setDecompressionMagicCookie(const std::vector<uint8_t> &v) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterDecompressionMagicCookie, v.size(), v.data())); }
void AudioConverterX::setOutputChannelLayout(const AudioChannelLayout &value) { UInt32 size = cautil::sizeofAudioChannelLayout(value); CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterOutputChannelLayout, size, &value)); }
void AudioConverterX::setPrimeInfo(const AudioConverterPrimeInfo &info) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterPrimeInfo, sizeof(info), &info)); }
void AudioConverterX::setBitRateControlMode(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertyBitRateControlMode, sizeof value, &value)); }
ALACSource::ALACSource(const std::shared_ptr<FILE> &fp) : m_position(0), m_fp(fp) { try { int fd = fileno(m_fp.get()); { util::FilePositionSaver _(fd); _lseeki64(fd, 0, SEEK_SET); char buf[8]; if (read(fd, buf, 8) != 8 || std::memcmp(&buf[4], "ftyp", 4)) throw std::runtime_error("Not an MP4 file"); } static MP4FDReadProvider provider; std::string name = strutil::format("%d", fd); m_file.Read(name.c_str(), &provider); m_track_id = m_file.FindTrackId(0, MP4_AUDIO_TRACK_TYPE); const char *type = m_file.GetTrackMediaDataName(m_track_id); if (std::strcmp(type, "alac")) throw std::runtime_error("Not an ALAC file"); const char *alacprop, *chanprop; const char *brand = m_file.GetStringProperty("ftyp.majorBrand"); if (!std::strcmp(brand, "qt ")) { // throw std::runtime_error("Not supported format"); alacprop = "mdia.minf.stbl.stsd.alac.wave.alac.decoderConfig"; chanprop = "mdia.minf.stbl.stsd.alac.wave.chan.data"; } else { alacprop = "mdia.minf.stbl.stsd.alac.alac.decoderConfig"; chanprop = "mdia.minf.stbl.stsd.alac.chan.data"; } std::vector<uint8_t> alac, chan; uint8_t *value; uint32_t size; m_file.GetTrackBytesProperty(m_track_id, alacprop, &value, &size); std::copy(value + 4, value + size, std::back_inserter(alac)); MP4Free(value); value = 0; try { m_file.GetTrackBytesProperty(m_track_id, chanprop, &value, &size); std::copy(value + 4, value + size, std::back_inserter(chan)); MP4Free(value); } catch (...) {} if (alac.size() != 24 || (chan.size() && chan.size() < 12)) throw std::runtime_error("ALACSource: invalid magic cookie"); uint32_t timeScale; std::memcpy(&timeScale, &alac[20], 4); timeScale = util::b2host32(timeScale); m_asbd = cautil::buildASBDForPCM(timeScale, alac[9], alac[5], kAudioFormatFlagIsSignedInteger, kAudioFormatFlagIsAlignedHigh); m_oasbd = cautil::buildASBDForPCM2(timeScale, alac[9], alac[5], 32, kAudioFormatFlagIsSignedInteger); m_buffer.units_per_packet = m_asbd.mBytesPerFrame; AudioChannelLayout acl = { 0 }; if (chan.size()) { util::fourcc tag(reinterpret_cast<const char*>(&chan[0])); util::fourcc bitmap(reinterpret_cast<const char*>(&chan[4])); acl.mChannelLayoutTag = tag; acl.mChannelBitmap = bitmap; chanmap::getChannels(&acl, &m_chanmap); } m_decoder = std::shared_ptr<ALACDecoder>(new ALACDecoder()); CHECKCA(m_decoder->Init(&alac[0], alac.size())); m_length = m_file.GetTrackDuration(m_track_id); mp4a::fetchTags(m_file, &m_tags); } catch (mp4v2::impl::Exception *e) { handle_mp4error(e); } }
void AudioConverterX::setPrimeMethod(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterPrimeMethod, sizeof value, &value)); }
void AudioConverterX::setSoundQualityForVBR(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertySoundQualityForVBR, sizeof value, &value)); }
void AudioConverterX::setSampleRateConverterQuality(UInt32 quality) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterSampleRateConverterQuality, sizeof quality, &quality)); }
void AudioConverterX::setSampleRateConverterComplexity(UInt32 complexity) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterSampleRateConverterComplexity, sizeof complexity, &complexity)); }
void AudioConverterX::setCodecQuality(UInt32 value) { CHECKCA(AudioConverterSetProperty(m_converter.get(), kAudioConverterCodecQuality, sizeof value, &value)); }