Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
21 kB · 770 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771/*This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version.
Darling is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.
You should have received a copy of the GNU General Public Licensealong with Darling. If not, see <http://www.gnu.org/licenses/>.*/
#include "AudioConverterImpl.h"#include <CoreServices/MacErrors.h>#include <stdexcept>#include <cstring>#include <cassert>#include <iostream>#include <sstream>#include "stub.h"
extern "C" {#include <libavcodec/avcodec.h>#include <libavutil/opt.h>#include <libavutil/mem.h>}
static constexpr int ENCODER_FRAME_SAMPLES = 1024;
// http://blinkingblip.wordpress.com/
static void throwFFMPEGError(int errnum, const char* function){ char buf[256]; std::stringstream ss;
if (av_strerror(errnum, buf, sizeof(buf)) == 0) ss << function << ": " << buf; else ss << function << ": unknown error";
throw std::runtime_error(ss.str());}
AudioConverter::AudioConverter(const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat) : m_sourceFormat(*inSourceFormat), m_destinationFormat(*inDestinationFormat), m_decoder(nullptr), m_encoder(nullptr){ memset(&m_avpkt, 0, sizeof(m_avpkt)); memset(&m_avpktOut, 0, sizeof(m_avpktOut));}
void AudioConverter::flush(){ TRACE(); avcodec_flush_buffers(m_decoder); avcodec_flush_buffers(m_encoder); //avcodec_close(m_encoder);}
OSStatus AudioConverter::create(const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverter** out){ TRACE2(inSourceFormat, inDestinationFormat); // TODO: non-interleaved audio
const AVCodec *codecIn, *codecOut; AVCodecContext *cIn; AVCodecContext *cOut; enum AVCodecID idIn, idOut;
*out = nullptr; idIn = CACodecToAV(inSourceFormat); idOut = CACodecToAV(inDestinationFormat);
if (idIn == AV_CODEC_ID_NONE || idOut == AV_CODEC_ID_NONE) { // LOG << "AudioConverter::create(): Unsupported codec, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl; return paramErr; }
codecIn = avcodec_find_decoder(idIn); codecOut = avcodec_find_encoder(idOut);
if (!codecIn || !codecOut) { // LOG << "AudioConverter::create(): avcodec_find_*() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl; return paramErr; }
*out = new AudioConverter(inSourceFormat, inDestinationFormat);
(*out)->m_decoder = cIn = avcodec_alloc_context3(codecIn); if (inSourceFormat->mFormatID == kAudioFormatLinearPCM) { cIn->channels = inSourceFormat->mChannelsPerFrame; cIn->sample_rate = inSourceFormat->mSampleRate; std::cout << "Converting from PCM with " << cIn->channels << " channels at " << cIn->sample_rate << " Hz\n"; } if (avcodec_open2((*out)->m_decoder, codecIn, nullptr) < 0) { delete *out; std::cerr << "AudioConverter::create(): avcodec_open() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl;
return paramErr; }
// The encoder will be initialized after we process the first packet (*out)->m_encoder = cOut = avcodec_alloc_context3(codecOut); (*out)->m_codecIn = codecIn; (*out)->m_codecOut = codecOut;
return noErr;}
void AudioConverter::initEncoder(){ int err; if (m_encoderInitialized) throw std::logic_error("Encoder already initialized"); m_encoder->codec_type = AVMEDIA_TYPE_AUDIO; m_encoder->bit_rate = m_outBitRate; m_encoder->channels = m_destinationFormat.mChannelsPerFrame; m_encoder->sample_rate = m_destinationFormat.mSampleRate; m_encoder->channel_layout = CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame); m_encoder->sample_fmt = CACodecSampleFormat(&m_destinationFormat);
#ifdef DEBUG_AUDIOCONVERTER std::cout << "ENCODER FORMAT:\n"; std::cout << "\tSample rate: " << m_encoder->sample_rate << std::endl; std::cout << "\tChannels: " << m_destinationFormat.mChannelsPerFrame << std::endl; std::cout << "\tFormat: 0x" << std::hex << m_encoder->sample_fmt << std::dec << std::endl;#endif err = avcodec_open2(m_encoder, m_codecOut, 0); if (err < 0) throwFFMPEGError(err, "avcodec_open2() encoder"); allocateBuffers(); m_encoderInitialized = true;}
void AudioConverter::allocateBuffers(){#ifdef HAVE_AV_FRAME_ALLOC m_audioFrame = av_frame_alloc();#else m_audioFrame = avcodec_alloc_frame();#endif m_audioFrame->nb_samples = ENCODER_FRAME_SAMPLES; m_audioFrame->format = m_encoder->sample_fmt; m_audioFrame->channel_layout = m_encoder->channel_layout;
int audioSampleBuffer_size = av_samples_get_buffer_size(nullptr, m_encoder->channels, m_audioFrame->nb_samples, m_encoder->sample_fmt, 0); void* audioSampleBuffer = (uint8_t*) av_malloc(audioSampleBuffer_size);
if (!audioSampleBuffer) { std::cerr << "AudioConverter::allocateBuffers(): Failed to allocate sample buffer\n"; throw std::runtime_error("AudioConverter::allocateBuffers(): Failed to allocate sample buffer"); }
// Setup the data pointers in the AVFrame if (int err = avcodec_fill_audio_frame(m_audioFrame, m_encoder->channels, m_encoder->sample_fmt, (const uint8_t*) audioSampleBuffer, audioSampleBuffer_size, 0 ); err < 0) { std::cerr << "AudioConverter::allocateBuffers(): Could not set up audio frame\n"; throw std::runtime_error("AudioConverter::allocateBuffers(): Could not set up audio frame"); }}
AudioConverter::~AudioConverter(){ TRACE(); if (m_decoder) avcodec_close(m_decoder); if (m_encoder) avcodec_close(m_encoder); if (m_audioFrame) av_free(m_audioFrame); if (m_resampler) swr_free(&m_resampler);}
template <typename T> OSStatus setPropertyT(UInt32 inPropertyDataSize, T* localProperty, const void* propertySource){ const T* t = static_cast<const T*>(propertySource); if (inPropertyDataSize != sizeof(T)) return kAudioConverterErr_BadPropertySizeError; *localProperty = *t; return noErr;}
OSStatus AudioConverter::setProperty(AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData){ switch (inPropertyID) { case kAudioConverterEncodeBitRate: { return setPropertyT(inPropertyDataSize, &m_outBitRate, inPropertyData); } case kAudioConverterInputChannelLayout: { } case kAudioConverterOutputChannelLayout: { } case kAudioConverterCurrentOutputStreamDescription: { return kAudioConverterErr_PropertyNotSupported; //return setPropertyT(inPropertyDataSize, &m_sourceFormat, inPropertyData); } case kAudioConverterCurrentInputStreamDescription: { return kAudioConverterErr_PropertyNotSupported; //return setPropertyT(inPropertyDataSize, &m_destinationFormat, inPropertyData); } default: { STUB(); return kAudioConverterErr_PropertyNotSupported; } } return unimpErr;}
OSStatus AudioConverter::getPropertyInfo(AudioConverterPropertyID inPropertyID, UInt32 *outSize, Boolean *outWritable){ STUB(); return unimpErr;}
template <typename T> OSStatus getPropertyT(UInt32 *ioPropertyDataSize, const T* localProperty, void* propertyTarget){ T* t = static_cast<T*>(propertyTarget); if (*ioPropertyDataSize < sizeof(T)) return kAudioConverterErr_BadPropertySizeError; *ioPropertyDataSize = sizeof(T); *t = *localProperty; return noErr;}
OSStatus AudioConverter::getProperty(AudioConverterPropertyID inPropertyID, UInt32 *ioPropertyDataSize, void *outPropertyData){ switch (inPropertyID) { case kAudioConverterEncodeBitRate: { return getPropertyT(ioPropertyDataSize, &m_outBitRate, outPropertyData); } case kAudioConverterCurrentInputStreamDescription: { return getPropertyT(ioPropertyDataSize, &m_sourceFormat, outPropertyData); } case kAudioConverterCurrentOutputStreamDescription: { return getPropertyT(ioPropertyDataSize, &m_destinationFormat, outPropertyData); } default: { STUB(); return kAudioConverterErr_PropertyNotSupported; } }}
OSStatus AudioConverter::feedInput(AudioConverterComplexInputDataProc dataProc, void* opaque, UInt32& numDataPackets){ AudioBufferList bufferList; AudioStreamPacketDescription* aspd; OSStatus err;
numDataPackets = 4096; // TODO: increase this? bufferList.mNumberBuffers = 1; bufferList.mBuffers[0].mDataByteSize = 0; bufferList.mBuffers[0].mData = nullptr; err = dataProc(AudioConverterRef(this), &numDataPackets, &bufferList, &aspd, opaque); if (err != noErr) return err; m_avpkt.size = bufferList.mBuffers[0].mDataByteSize; m_avpkt.data = (uint8_t*) bufferList.mBuffers[0].mData; return noErr;}
void AudioConverter::setupResampler(const AVFrame* frame){ int err; if (m_resampler != nullptr) throw std::logic_error("Resampler already created"); m_resampler = swr_alloc(); m_targetFormat = CACodecSampleFormat(&m_destinationFormat); av_opt_set_int(m_resampler, "in_channel_layout", CAChannelCountToLayout(m_sourceFormat.mChannelsPerFrame), 0); av_opt_set_int(m_resampler, "out_channel_layout", CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame), 0); av_opt_set_int(m_resampler, "in_channels", m_sourceFormat.mChannelsPerFrame, 0); av_opt_set_int(m_resampler, "out_channels", m_destinationFormat.mChannelsPerFrame, 0); av_opt_set_int(m_resampler, "in_sample_rate", frame->sample_rate, 0); av_opt_set_int(m_resampler, "out_sample_rate", m_destinationFormat.mSampleRate, 0); av_opt_set_int(m_resampler, "in_sample_fmt", frame->format, 0); av_opt_set_int(m_resampler, "out_sample_fmt", m_targetFormat, 0);
#ifdef DEBUG_AUDIOCONVERTER std::cout << "RESAMPLER:\n"; std::cout << "\tInput rate: " << frame->sample_rate << std::endl; std::cout << "\tInput format: 0x" << std::hex << frame->format << std::dec <<std::endl; std::cout << "\tOutput rate: " << m_destinationFormat.mSampleRate << std::endl; std::cout << "\tOutput format: 0x" << std::hex << CACodecSampleFormat(&m_destinationFormat) << std::dec << std::endl;
m_resamplerInput.open("/tmp/resampler.in.raw", std::ios_base::binary | std::ios_base::out); m_resamplerOutput.open("/tmp/resampler.out.raw", std::ios_base::binary | std::ios_base::out); m_encoderOutput.open("/tmp/encoder.out.raw", std::ios_base::binary | std::ios_base::out);#endif err = swr_init(m_resampler); if (err < 0) throwFFMPEGError(err, "swr_init()");}
OSStatus AudioConverter::fillComplex(AudioConverterComplexInputDataProc dataProc, void* opaque, UInt32* ioOutputDataPacketSize, AudioBufferList *outOutputData, AudioStreamPacketDescription* outPacketDescription){ AVFrame* srcaudio;
#ifdef HAVE_AV_FRAME_ALLOC srcaudio = av_frame_alloc(); av_frame_unref(srcaudio);#else srcaudio = avcodec_alloc_frame(); avcodec_get_frame_defaults(srcaudio);#endif try { for (uint32_t i = 0; i < outOutputData->mNumberBuffers; i++) { UInt32 origSize = outOutputData->mBuffers[i].mDataByteSize; UInt32& newSize = outOutputData->mBuffers[i].mDataByteSize; newSize = 0; while (newSize < origSize) { if (m_avpktOutUsed < m_avpktOut.size) { // std::cout << "case 1 (used " << m_avpktOutUsed << " from " << m_avpktOut.size << ")\n"; // Feed output from previous conversion while (m_avpktOutUsed < m_avpktOut.size && newSize < origSize) { // Output data int tocopy = std::min<int>(m_avpktOut.size - m_avpktOutUsed, origSize - newSize); memcpy(((char*) outOutputData->mBuffers[i].mData) + newSize, m_avpktOut.data + m_avpktOutUsed, tocopy); newSize += tocopy; m_avpktOutUsed += tocopy; } if (m_avpktOutUsed >= m_avpktOut.size) { m_avpktOutUsed = 0; av_packet_unref(&m_avpktOut); } } else { while (!feedEncoder()) { if (!feedDecoder(dataProc, opaque, srcaudio)) goto end; } } } }end: #ifdef HAVE_AV_FRAME_ALLOC av_frame_free(&srcaudio);#else avcodec_free_frame(&srcaudio);#endif } catch (const std::exception& e) { std::cerr << "AudioConverter::fillComplex(): Exception: " << e.what();#ifdef HAVE_AV_FRAME_ALLOC av_frame_free(&srcaudio);#else avcodec_free_frame(&srcaudio);#endif return ioErr; } catch (OSStatus err) { std::cerr << "AudioConverter::fillComplex(): OSStatus error: " << err;#ifdef HAVE_AV_FRAME_ALLOC av_frame_free(&srcaudio);#else avcodec_free_frame(&srcaudio);#endif return err; } return noErr;}
bool AudioConverter::feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio){ int gotFrame, err; do { // Read input if (!m_avpkt.size) { UInt32 numDataPackets = 0; OSStatus err = feedInput(dataProc, opaque, numDataPackets);
// The documentation says that this may be a temporary condition if (err != noErr) return false;
if (!m_avpkt.size) // numDataPackets cannot be trusted return false; }
#if 0 err = avcodec_decode_audio4(m_decoder, srcaudio, &gotFrame, &m_avpkt); if (err < 0) throwFFMPEGError(err, "avcodec_decode_audio4()");
m_avpkt.size -= err; m_avpkt.data += err;#else #warning TODO: test this new avcodec decoder code err = avcodec_send_packet(m_decoder, &m_avpkt);
if (err < 0) { if (err == AVERROR(EAGAIN)) { // we need to consume frames before sending more packets err = 0; } if (err < 0) { throwFFMPEGError(err, "avcodec_send_packet()"); } } else { // on success, the data packet has been consumed entirely m_avpkt.data += m_avpkt.size; m_avpkt.size = 0; }
err = avcodec_receive_frame(m_decoder, srcaudio);
if (err < 0) { gotFrame = false; if (err == AVERROR(EAGAIN)) { // we need to send more packets before consuming a frame err = 0; } if (err < 0) { throwFFMPEGError(err, "avcodec_receive_frame()"); } } else { // on success, we have a valid frame gotFrame = true; }#endif
if (gotFrame) { if (!m_resampler) setupResampler(srcaudio);
#ifdef DEBUG_AUDIOCONVERTER m_resamplerInput.write((char*) srcaudio->data, srcaudio->nb_samples * 2 * m_sourceFormat.mChannelsPerFrame); m_resamplerInput.flush();#endif // Resample PCM err = swr_convert(m_resampler, nullptr, 0, (const uint8_t**)&srcaudio->data[0], srcaudio->nb_samples); if (err < 0) throwFFMPEGError(err, "swr_convert()"); } } while (!gotFrame);
return true;}
bool AudioConverter::feedEncoder(){ int gotFrame = 0, err; uint8_t *output; int out_linesize; int avail;
if (!m_resampler) return false;
if (!m_encoderInitialized) initEncoder(); assert(m_avpktOutUsed == m_avpktOut.size);
const size_t bytesPerSample = m_destinationFormat.mBitsPerChannel / 8; const size_t bytesPerFrame = m_destinationFormat.mChannelsPerFrame * bytesPerSample; const size_t requiredBytes = bytesPerFrame * ENCODER_FRAME_SAMPLES;
while (m_audioFramePrebuf.size() < requiredBytes && (avail = swr_get_out_samples(m_resampler, 0)) > 0) { av_samples_alloc(&output, &out_linesize, m_destinationFormat.mChannelsPerFrame, avail, m_encoder->sample_fmt, 0);
if ((avail = swr_convert(m_resampler, &output, avail, nullptr, 0)) < 0) { av_freep(&output); throwFFMPEGError(err, "swr_convert()"); }
#ifdef DEBUG_AUDIOCONVERTER m_resamplerOutput.write((char*) output, avail * bytesPerFrame); m_resamplerOutput.flush();#endif
m_audioFramePrebuf.push(output, avail * bytesPerFrame); av_freep(&output); }
av_init_packet(&m_avpktOut); m_avpktOut.data = 0; m_avpktOut.size = 0; m_avpktOutUsed = 0;
if (m_audioFramePrebuf.size() >= requiredBytes) { try { err = avcodec_fill_audio_frame(m_audioFrame, m_destinationFormat.mChannelsPerFrame, m_targetFormat, m_audioFramePrebuf.data(), requiredBytes, 0); if (err < 0) throwFFMPEGError(err, "avcodec_fill_audio_frame()");
#if 0 err = avcodec_encode_audio2(m_encoder, &m_avpktOut, m_audioFrame, &gotFrame); if (err < 0) throwFFMPEGError(err, "avcodec_encode_audio2()");#else #warning TODO: test this new avcodec encoder code err = avcodec_send_frame(m_encoder, m_audioFrame);
if (err < 0) { if (err == AVERROR(EAGAIN)) { // we need to consume more packets before sending // TODO: handle this case properly. // for now, we just proceed to throw an error to avoid dropping a frame } if (err < 0) { throwFFMPEGError(err, "avcodec_send_frame()"); } }
err = avcodec_receive_packet(m_encoder, &m_avpkt);
if (err < 0) { gotFrame = false; if (err == AVERROR(EAGAIN)) { // we need to send more frames before consuming a packet err = 0; } if (err < 0) { throwFFMPEGError(err, "avcodec_receive_packet()"); } } else { gotFrame = true; }#endif
m_audioFramePrebuf.consume(requiredBytes);
#ifdef DEBUG_AUDIOCONVERTER if (gotFrame) m_encoderOutput.write((char*) m_avpktOut.data, m_avpktOut.size);#endif } catch (...) { m_audioFramePrebuf.consume(requiredBytes); throw; }
return gotFrame; } return false;}
uint32_t AudioConverter::CAChannelCountToLayout(UInt32 numChannels){ // TODO: this is just wild guessing switch (numChannels) { case 1: return AV_CH_LAYOUT_MONO; case 2: return AV_CH_LAYOUT_STEREO; case 3: return AV_CH_LAYOUT_SURROUND; case 4: return AV_CH_LAYOUT_4POINT0; case 5: return AV_CH_LAYOUT_4POINT1; case 6: return AV_CH_LAYOUT_5POINT1; case 7: return AV_CH_LAYOUT_6POINT1; case 8: return AV_CH_LAYOUT_7POINT1; default: return AV_CH_LAYOUT_STEREO; }}
enum AVSampleFormat AudioConverter::CACodecSampleFormat(const AudioStreamBasicDescription* desc){ if (desc->mFormatFlags & kAudioFormatFlagIsFloat) { if (desc->mBitsPerChannel == 32) return AV_SAMPLE_FMT_FLT; else if (desc->mBitsPerChannel == 64) return AV_SAMPLE_FMT_DBL; else return AV_SAMPLE_FMT_NONE; } else { switch (desc->mBitsPerChannel) { case 8: return AV_SAMPLE_FMT_U8; case 16: return AV_SAMPLE_FMT_S16; case 24: return AV_SAMPLE_FMT_S32; // FIXME: 24-bits? case 32: return AV_SAMPLE_FMT_S32; default: return AV_SAMPLE_FMT_NONE; } }}
enum AVCodecID AudioConverter::CACodecToAV(const AudioStreamBasicDescription* desc){ switch (desc->mFormatID) { case kAudioFormatLinearPCM: { if (desc->mFormatFlags & kAudioFormatFlagIsFloat) { if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian) { if (desc->mBitsPerChannel == 32) return AV_CODEC_ID_PCM_F32BE; else if (desc->mBitsPerChannel == 64) return AV_CODEC_ID_PCM_F64BE; } else { if (desc->mBitsPerChannel == 32) return AV_CODEC_ID_PCM_F32LE; else if (desc->mBitsPerChannel == 64) return AV_CODEC_ID_PCM_F64LE; } } else if (desc->mFormatFlags & kAudioFormatFlagIsSignedInteger) { enum AVCodecID cid;
switch (desc->mBitsPerChannel) { case 8: cid = AV_CODEC_ID_PCM_S8; break; case 16: cid = AV_CODEC_ID_PCM_S16LE; break; case 24: cid = AV_CODEC_ID_PCM_S24LE; break; case 32: cid = AV_CODEC_ID_PCM_S32LE; break; default: return AV_CODEC_ID_NONE; }
if (desc->mBitsPerChannel != 8 && desc->mFormatFlags & kAudioFormatFlagIsBigEndian) cid = (enum AVCodecID)(int(cid)+1); return cid; } else { enum AVCodecID cid;
switch (desc->mBitsPerChannel) { case 8: cid = AV_CODEC_ID_PCM_U8; break; case 16: cid = AV_CODEC_ID_PCM_U16LE; break; case 24: cid = AV_CODEC_ID_PCM_U24LE; break; case 32: cid = AV_CODEC_ID_PCM_U32LE; break; default: return AV_CODEC_ID_NONE; }
if (desc->mBitsPerChannel != 8 && desc->mFormatFlags & kAudioFormatFlagIsBigEndian) cid = (enum AVCodecID)(int(cid)+1); return cid; } return AV_CODEC_ID_NONE; } case kAudioFormatULaw: return AV_CODEC_ID_PCM_MULAW; case kAudioFormatALaw: return AV_CODEC_ID_PCM_ALAW; case kAudioFormatMPEGLayer1: return AV_CODEC_ID_MP1; case kAudioFormatMPEGLayer2: return AV_CODEC_ID_MP2; case kAudioFormatMPEGLayer3: return AV_CODEC_ID_MP3; case kAudioFormatAC3: case kAudioFormat60958AC3: // TODO: is this correct? return AV_CODEC_ID_AC3; case kAudioFormatAppleIMA4: return AV_CODEC_ID_ADPCM_IMA_DK4; // TODO: is this correct? case kAudioFormatMPEG4AAC: case kAudioFormatMPEG4AAC_HE: case kAudioFormatMPEG4AAC_LD: case kAudioFormatMPEG4AAC_ELD: case kAudioFormatMPEG4AAC_ELD_SBR: case kAudioFormatMPEG4AAC_ELD_V2: case kAudioFormatMPEG4AAC_HE_V2: case kAudioFormatMPEG4AAC_Spatial: return AV_CODEC_ID_AAC; case kAudioFormatMPEG4CELP: return AV_CODEC_ID_QCELP; // TODO: is this correct? case kAudioFormatAMR: return AV_CODEC_ID_AMR_NB; case kAudioFormatiLBC: return AV_CODEC_ID_ILBC; case kAudioFormatAppleLossless: return AV_CODEC_ID_APE; case kAudioFormatMicrosoftGSM: return AV_CODEC_ID_GSM_MS; case kAudioFormatMACE3: return AV_CODEC_ID_MACE3; case kAudioFormatMACE6: return AV_CODEC_ID_MACE6; default: return AV_CODEC_ID_NONE; }}