this repo has no description
1/*
2This file is part of Darling.
3
4Copyright (C) 2020 Lubos Dolezel
5
6Darling is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11Darling is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with Darling. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "AudioConverterImpl.h"
21#include <CarbonCore/MacErrors.h>
22#include <stdexcept>
23#include <cstring>
24#include <cassert>
25#include <iostream>
26#include <sstream>
27#include "stub.h"
28
29extern "C" {
30#include <libavcodec/avcodec.h>
31#include <libavutil/opt.h>
32#include <libavutil/mem.h>
33}
34
35static constexpr int ENCODER_FRAME_SAMPLES = 1024;
36
37// http://blinkingblip.wordpress.com/
38
39static void throwFFMPEGError(int errnum, const char* function)
40{
41 char buf[256];
42 std::stringstream ss;
43
44 if (av_strerror(errnum, buf, sizeof(buf)) == 0)
45 ss << function << ": " << buf;
46 else
47 ss << function << ": unknown error";
48
49 throw std::runtime_error(ss.str());
50}
51
52AudioConverter::AudioConverter(const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat)
53 : m_sourceFormat(*inSourceFormat), m_destinationFormat(*inDestinationFormat), m_decoder(nullptr), m_encoder(nullptr)
54{
55 memset(&m_avpkt, 0, sizeof(m_avpkt));
56 memset(&m_avpktOut, 0, sizeof(m_avpktOut));
57}
58
59void AudioConverter::flush()
60{
61 TRACE();
62 avcodec_flush_buffers(m_decoder);
63 avcodec_flush_buffers(m_encoder);
64 //avcodec_close(m_encoder);
65}
66
67OSStatus AudioConverter::create(const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverter** out)
68{
69 TRACE2(inSourceFormat, inDestinationFormat);
70
71 // TODO: non-interleaved audio
72
73 const AVCodec *codecIn, *codecOut;
74 AVCodecContext *cIn;
75 AVCodecContext *cOut;
76 enum AVCodecID idIn, idOut;
77
78 *out = nullptr;
79 idIn = CACodecToAV(inSourceFormat);
80 idOut = CACodecToAV(inDestinationFormat);
81
82 if (idIn == AV_CODEC_ID_NONE || idOut == AV_CODEC_ID_NONE)
83 {
84 // LOG << "AudioConverter::create(): Unsupported codec, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl;
85 return paramErr;
86 }
87
88 codecIn = avcodec_find_decoder(idIn);
89 codecOut = avcodec_find_encoder(idOut);
90
91 if (!codecIn || !codecOut)
92 {
93 // LOG << "AudioConverter::create(): avcodec_find_*() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl;
94 return paramErr;
95 }
96
97 *out = new AudioConverter(inSourceFormat, inDestinationFormat);
98
99 (*out)->m_decoder = cIn = avcodec_alloc_context3(codecIn);
100
101 if (inSourceFormat->mFormatID == kAudioFormatLinearPCM)
102 {
103#warning "TODO: Remove deprecated 'channels' once we no longer support older distros"
104#if LIBAVCODEC_VERSION_MAJOR >= 61
105 cIn->ch_layout.nb_channels = inSourceFormat->mChannelsPerFrame;
106#else
107 cIn->channels = inSourceFormat->mChannelsPerFrame;
108#endif
109 cIn->sample_rate = inSourceFormat->mSampleRate;
110
111#if LIBAVCODEC_VERSION_MAJOR >= 61
112 std::cout << "Converting from PCM with " << cIn->ch_layout.nb_channels << " channels at " << cIn->sample_rate << " Hz\n";
113#else
114 std::cout << "Converting from PCM with " << cIn->channels << " channels at " << cIn->sample_rate << " Hz\n";
115#endif
116 }
117
118 if (avcodec_open2((*out)->m_decoder, codecIn, nullptr) < 0)
119 {
120 delete *out;
121 std::cerr << "AudioConverter::create(): avcodec_open() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl;
122
123 return paramErr;
124 }
125
126 // The encoder will be initialized after we process the first packet
127 (*out)->m_encoder = cOut = avcodec_alloc_context3(codecOut);
128 (*out)->m_codecIn = codecIn;
129 (*out)->m_codecOut = codecOut;
130
131 return noErr;
132}
133
134void AudioConverter::initEncoder()
135{
136 int err;
137
138 if (m_encoderInitialized)
139 throw std::logic_error("Encoder already initialized");
140
141 m_encoder->codec_type = AVMEDIA_TYPE_AUDIO;
142 m_encoder->bit_rate = m_outBitRate;
143#warning "TODO: Remove deprecated 'channels' once we no longer support older distros"
144#if LIBAVCODEC_VERSION_MAJOR >= 61
145 m_encoder->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
146 m_encoder->ch_layout.nb_channels = m_destinationFormat.mChannelsPerFrame;
147#else
148 m_encoder->channels = m_destinationFormat.mChannelsPerFrame;
149 m_encoder->channel_layout = CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame);
150#endif
151 m_encoder->sample_rate = m_destinationFormat.mSampleRate;
152 m_encoder->sample_fmt = CACodecSampleFormat(&m_destinationFormat);
153
154#ifdef DEBUG_AUDIOCONVERTER
155 std::cout << "ENCODER FORMAT:\n";
156 std::cout << "\tSample rate: " << m_encoder->sample_rate << std::endl;
157 std::cout << "\tChannels: " << m_destinationFormat.mChannelsPerFrame << std::endl;
158 std::cout << "\tFormat: 0x" << std::hex << m_encoder->sample_fmt << std::dec << std::endl;
159#endif
160
161 err = avcodec_open2(m_encoder, m_codecOut, 0);
162 if (err < 0)
163 throwFFMPEGError(err, "avcodec_open2() encoder");
164
165 allocateBuffers();
166 m_encoderInitialized = true;
167}
168
169void AudioConverter::allocateBuffers()
170{
171#ifdef HAVE_AV_FRAME_ALLOC
172 m_audioFrame = av_frame_alloc();
173#else
174 m_audioFrame = avcodec_alloc_frame();
175#endif
176
177 m_audioFrame->nb_samples = ENCODER_FRAME_SAMPLES;
178 m_audioFrame->format = m_encoder->sample_fmt;
179
180#warning "TODO: Remove deprecated 'channels' once we no longer support older distros"
181#if LIBAVCODEC_VERSION_MAJOR >= 61
182 m_audioFrame->ch_layout.order = m_encoder->ch_layout.order;
183 m_audioFrame->ch_layout.nb_channels = m_encoder->ch_layout.nb_channels;
184 int audioSampleBuffer_size = av_samples_get_buffer_size(nullptr, m_encoder->ch_layout.nb_channels, m_audioFrame->nb_samples, m_encoder->sample_fmt, 0);
185#else
186 m_audioFrame->channel_layout = m_encoder->channel_layout;
187 int audioSampleBuffer_size = av_samples_get_buffer_size(nullptr, m_encoder->channels, m_audioFrame->nb_samples, m_encoder->sample_fmt, 0);
188#endif
189 void* audioSampleBuffer = (uint8_t*) av_malloc(audioSampleBuffer_size);
190
191 if (!audioSampleBuffer)
192 {
193 std::cerr << "AudioConverter::allocateBuffers(): Failed to allocate sample buffer\n";
194 throw std::runtime_error("AudioConverter::allocateBuffers(): Failed to allocate sample buffer");
195 }
196
197 // Setup the data pointers in the AVFrame
198#if LIBAVCODEC_VERSION_MAJOR >= 61
199 if (int err = avcodec_fill_audio_frame(m_audioFrame, m_encoder->ch_layout.nb_channels, m_encoder->sample_fmt,
200 (const uint8_t*) audioSampleBuffer, audioSampleBuffer_size, 0 ); err < 0)
201#else
202 if (int err = avcodec_fill_audio_frame(m_audioFrame, m_encoder->channels, m_encoder->sample_fmt,
203 (const uint8_t*) audioSampleBuffer, audioSampleBuffer_size, 0 ); err < 0)
204#endif
205 {
206 std::cerr << "AudioConverter::allocateBuffers(): Could not set up audio frame\n";
207 throw std::runtime_error("AudioConverter::allocateBuffers(): Could not set up audio frame");
208 }
209}
210
211AudioConverter::~AudioConverter()
212{
213 TRACE();
214 if (m_decoder)
215 avcodec_free_context(&m_decoder);
216 if (m_encoder)
217 avcodec_free_context(&m_encoder);
218 if (m_audioFrame)
219 av_free(m_audioFrame);
220 if (m_resampler)
221 swr_free(&m_resampler);
222}
223
224template <typename T> OSStatus setPropertyT(UInt32 inPropertyDataSize, T* localProperty, const void* propertySource)
225{
226 const T* t = static_cast<const T*>(propertySource);
227
228 if (inPropertyDataSize != sizeof(T))
229 return kAudioConverterErr_BadPropertySizeError;
230
231 *localProperty = *t;
232 return noErr;
233}
234
235OSStatus AudioConverter::setProperty(AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData)
236{
237 switch (inPropertyID)
238 {
239 case kAudioConverterEncodeBitRate:
240 {
241 return setPropertyT(inPropertyDataSize, &m_outBitRate, inPropertyData);
242 }
243 case kAudioConverterInputChannelLayout:
244 {
245 }
246 case kAudioConverterOutputChannelLayout:
247 {
248 }
249 case kAudioConverterCurrentOutputStreamDescription:
250 {
251 return kAudioConverterErr_PropertyNotSupported;
252 //return setPropertyT(inPropertyDataSize, &m_sourceFormat, inPropertyData);
253 }
254 case kAudioConverterCurrentInputStreamDescription:
255 {
256 return kAudioConverterErr_PropertyNotSupported;
257 //return setPropertyT(inPropertyDataSize, &m_destinationFormat, inPropertyData);
258 }
259 default:
260 {
261 STUB();
262 return kAudioConverterErr_PropertyNotSupported;
263 }
264 }
265
266 return unimpErr;
267}
268
269OSStatus AudioConverter::getPropertyInfo(AudioConverterPropertyID inPropertyID, UInt32 *outSize, Boolean *outWritable)
270{
271 STUB();
272 return unimpErr;
273}
274
275template <typename T> OSStatus getPropertyT(UInt32 *ioPropertyDataSize, const T* localProperty, void* propertyTarget)
276{
277 T* t = static_cast<T*>(propertyTarget);
278
279 if (*ioPropertyDataSize < sizeof(T))
280 return kAudioConverterErr_BadPropertySizeError;
281 *ioPropertyDataSize = sizeof(T);
282
283 *t = *localProperty;
284 return noErr;
285}
286
287OSStatus AudioConverter::getProperty(AudioConverterPropertyID inPropertyID, UInt32 *ioPropertyDataSize, void *outPropertyData)
288{
289 switch (inPropertyID)
290 {
291 case kAudioConverterEncodeBitRate:
292 {
293 return getPropertyT(ioPropertyDataSize, &m_outBitRate, outPropertyData);
294 }
295 case kAudioConverterCurrentInputStreamDescription:
296 {
297 return getPropertyT(ioPropertyDataSize, &m_sourceFormat, outPropertyData);
298 }
299 case kAudioConverterCurrentOutputStreamDescription:
300 {
301 return getPropertyT(ioPropertyDataSize, &m_destinationFormat, outPropertyData);
302 }
303 default:
304 {
305 STUB();
306 return kAudioConverterErr_PropertyNotSupported;
307 }
308 }
309}
310
311OSStatus AudioConverter::feedInput(AudioConverterComplexInputDataProc dataProc, void* opaque, UInt32& numDataPackets)
312{
313 AudioBufferList bufferList;
314 AudioStreamPacketDescription* aspd;
315 OSStatus err;
316
317 numDataPackets = 4096; // TODO: increase this?
318 bufferList.mNumberBuffers = 1;
319 bufferList.mBuffers[0].mDataByteSize = 0;
320 bufferList.mBuffers[0].mData = nullptr;
321
322 err = dataProc(AudioConverterRef(this), &numDataPackets, &bufferList, &aspd, opaque);
323
324 if (err != noErr)
325 return err;
326
327 m_avpkt.size = bufferList.mBuffers[0].mDataByteSize;
328 m_avpkt.data = (uint8_t*) bufferList.mBuffers[0].mData;
329
330 return noErr;
331}
332
333void AudioConverter::setupResampler(const AVFrame* frame)
334{
335 int err;
336
337 if (m_resampler != nullptr)
338 throw std::logic_error("Resampler already created");
339
340 m_resampler = swr_alloc();
341 m_targetFormat = CACodecSampleFormat(&m_destinationFormat);
342
343 av_opt_set_int(m_resampler, "in_channel_layout", CAChannelCountToLayout(m_sourceFormat.mChannelsPerFrame), 0);
344 av_opt_set_int(m_resampler, "out_channel_layout", CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame), 0);
345 av_opt_set_int(m_resampler, "in_channels", m_sourceFormat.mChannelsPerFrame, 0);
346 av_opt_set_int(m_resampler, "out_channels", m_destinationFormat.mChannelsPerFrame, 0);
347 av_opt_set_int(m_resampler, "in_sample_rate", frame->sample_rate, 0);
348 av_opt_set_int(m_resampler, "out_sample_rate", m_destinationFormat.mSampleRate, 0);
349 av_opt_set_int(m_resampler, "in_sample_fmt", frame->format, 0);
350 av_opt_set_int(m_resampler, "out_sample_fmt", m_targetFormat, 0);
351
352#ifdef DEBUG_AUDIOCONVERTER
353 std::cout << "RESAMPLER:\n";
354 std::cout << "\tInput rate: " << frame->sample_rate << std::endl;
355 std::cout << "\tInput format: 0x" << std::hex << frame->format << std::dec <<std::endl;
356 std::cout << "\tOutput rate: " << m_destinationFormat.mSampleRate << std::endl;
357 std::cout << "\tOutput format: 0x" << std::hex << CACodecSampleFormat(&m_destinationFormat) << std::dec << std::endl;
358
359 m_resamplerInput.open("/tmp/resampler.in.raw", std::ios_base::binary | std::ios_base::out);
360 m_resamplerOutput.open("/tmp/resampler.out.raw", std::ios_base::binary | std::ios_base::out);
361 m_encoderOutput.open("/tmp/encoder.out.raw", std::ios_base::binary | std::ios_base::out);
362#endif
363
364 err = swr_init(m_resampler);
365 if (err < 0)
366 throwFFMPEGError(err, "swr_init()");
367}
368
369OSStatus AudioConverter::fillComplex(AudioConverterComplexInputDataProc dataProc, void* opaque,
370 UInt32* ioOutputDataPacketSize, AudioBufferList *outOutputData, AudioStreamPacketDescription* outPacketDescription)
371{
372 AVFrame* srcaudio;
373
374#ifdef HAVE_AV_FRAME_ALLOC
375 srcaudio = av_frame_alloc();
376 av_frame_unref(srcaudio);
377#else
378 srcaudio = avcodec_alloc_frame();
379 avcodec_get_frame_defaults(srcaudio);
380#endif
381
382 try
383 {
384 for (uint32_t i = 0; i < outOutputData->mNumberBuffers; i++)
385 {
386 UInt32 origSize = outOutputData->mBuffers[i].mDataByteSize;
387 UInt32& newSize = outOutputData->mBuffers[i].mDataByteSize;
388
389 newSize = 0;
390
391 while (newSize < origSize)
392 {
393 if (m_avpktOutUsed < m_avpktOut.size)
394 {
395 // std::cout << "case 1 (used " << m_avpktOutUsed << " from " << m_avpktOut.size << ")\n";
396 // Feed output from previous conversion
397 while (m_avpktOutUsed < m_avpktOut.size && newSize < origSize)
398 {
399 // Output data
400 int tocopy = std::min<int>(m_avpktOut.size - m_avpktOutUsed, origSize - newSize);
401 memcpy(((char*) outOutputData->mBuffers[i].mData) + newSize, m_avpktOut.data + m_avpktOutUsed, tocopy);
402 newSize += tocopy;
403 m_avpktOutUsed += tocopy;
404 }
405
406 if (m_avpktOutUsed >= m_avpktOut.size)
407 {
408 m_avpktOutUsed = 0;
409 av_packet_unref(&m_avpktOut);
410 }
411 }
412 else
413 {
414 while (!feedEncoder())
415 {
416 if (!feedDecoder(dataProc, opaque, srcaudio))
417 goto end;
418 }
419 }
420 }
421 }
422end:
423
424#ifdef HAVE_AV_FRAME_ALLOC
425 av_frame_free(&srcaudio);
426#else
427 avcodec_free_frame(&srcaudio);
428#endif
429 }
430 catch (const std::exception& e)
431 {
432 std::cerr << "AudioConverter::fillComplex(): Exception: " << e.what();
433#ifdef HAVE_AV_FRAME_ALLOC
434 av_frame_free(&srcaudio);
435#else
436 avcodec_free_frame(&srcaudio);
437#endif
438 return ioErr;
439 }
440 catch (OSStatus err)
441 {
442 std::cerr << "AudioConverter::fillComplex(): OSStatus error: " << err;
443#ifdef HAVE_AV_FRAME_ALLOC
444 av_frame_free(&srcaudio);
445#else
446 avcodec_free_frame(&srcaudio);
447#endif
448 return err;
449 }
450
451 return noErr;
452}
453
454bool AudioConverter::feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio)
455{
456 int gotFrame, err;
457
458 do
459 {
460 // Read input
461 if (!m_avpkt.size)
462 {
463 UInt32 numDataPackets = 0;
464 OSStatus err = feedInput(dataProc, opaque, numDataPackets);
465
466 // The documentation says that this may be a temporary condition
467 if (err != noErr)
468 return false;
469
470 if (!m_avpkt.size) // numDataPackets cannot be trusted
471 return false;
472 }
473
474#if 0
475 err = avcodec_decode_audio4(m_decoder, srcaudio, &gotFrame, &m_avpkt);
476 if (err < 0)
477 throwFFMPEGError(err, "avcodec_decode_audio4()");
478
479 m_avpkt.size -= err;
480 m_avpkt.data += err;
481#else
482 #warning TODO: test this new avcodec decoder code
483 err = avcodec_send_packet(m_decoder, &m_avpkt);
484
485 if (err < 0) {
486 if (err == AVERROR(EAGAIN)) {
487 // we need to consume frames before sending more packets
488 err = 0;
489 }
490 if (err < 0) {
491 throwFFMPEGError(err, "avcodec_send_packet()");
492 }
493 } else {
494 // on success, the data packet has been consumed entirely
495 m_avpkt.data += m_avpkt.size;
496 m_avpkt.size = 0;
497 }
498
499 err = avcodec_receive_frame(m_decoder, srcaudio);
500
501 if (err < 0) {
502 gotFrame = false;
503 if (err == AVERROR(EAGAIN)) {
504 // we need to send more packets before consuming a frame
505 err = 0;
506 }
507 if (err < 0) {
508 throwFFMPEGError(err, "avcodec_receive_frame()");
509 }
510 } else {
511 // on success, we have a valid frame
512 gotFrame = true;
513 }
514#endif
515
516 if (gotFrame)
517 {
518 if (!m_resampler)
519 setupResampler(srcaudio);
520
521#ifdef DEBUG_AUDIOCONVERTER
522 m_resamplerInput.write((char*) srcaudio->data, srcaudio->nb_samples * 2 * m_sourceFormat.mChannelsPerFrame);
523 m_resamplerInput.flush();
524#endif
525
526 // Resample PCM
527 err = swr_convert(m_resampler, nullptr, 0, (const uint8_t**)&srcaudio->data[0], srcaudio->nb_samples);
528 if (err < 0)
529 throwFFMPEGError(err, "swr_convert()");
530 }
531 }
532 while (!gotFrame);
533
534 return true;
535}
536
537bool AudioConverter::feedEncoder()
538{
539 int gotFrame = 0, err;
540 uint8_t *output;
541 int out_linesize;
542 int avail;
543
544 if (!m_resampler)
545 return false;
546
547 if (!m_encoderInitialized)
548 initEncoder();
549
550 assert(m_avpktOutUsed == m_avpktOut.size);
551
552 const size_t bytesPerSample = m_destinationFormat.mBitsPerChannel / 8;
553 const size_t bytesPerFrame = m_destinationFormat.mChannelsPerFrame * bytesPerSample;
554 const size_t requiredBytes = bytesPerFrame * ENCODER_FRAME_SAMPLES;
555
556 while (m_audioFramePrebuf.size() < requiredBytes && (avail = swr_get_out_samples(m_resampler, 0)) > 0)
557 {
558 av_samples_alloc(&output, &out_linesize, m_destinationFormat.mChannelsPerFrame,
559 avail, m_encoder->sample_fmt, 0);
560
561 if ((avail = swr_convert(m_resampler, &output, avail, nullptr, 0)) < 0)
562 {
563 av_freep(&output);
564 throwFFMPEGError(err, "swr_convert()");
565 }
566
567#ifdef DEBUG_AUDIOCONVERTER
568 m_resamplerOutput.write((char*) output, avail * bytesPerFrame);
569 m_resamplerOutput.flush();
570#endif
571
572 m_audioFramePrebuf.push(output, avail * bytesPerFrame);
573 av_freep(&output);
574 }
575
576 av_init_packet(&m_avpktOut);
577 m_avpktOut.data = 0;
578 m_avpktOut.size = 0;
579 m_avpktOutUsed = 0;
580
581 if (m_audioFramePrebuf.size() >= requiredBytes)
582 {
583 try
584 {
585 err = avcodec_fill_audio_frame(m_audioFrame, m_destinationFormat.mChannelsPerFrame,
586 m_targetFormat, m_audioFramePrebuf.data(), requiredBytes, 0);
587
588 if (err < 0)
589 throwFFMPEGError(err, "avcodec_fill_audio_frame()");
590
591#if 0
592 err = avcodec_encode_audio2(m_encoder, &m_avpktOut, m_audioFrame, &gotFrame);
593 if (err < 0)
594 throwFFMPEGError(err, "avcodec_encode_audio2()");
595#else
596 #warning TODO: test this new avcodec encoder code
597 err = avcodec_send_frame(m_encoder, m_audioFrame);
598
599 if (err < 0) {
600 if (err == AVERROR(EAGAIN)) {
601 // we need to consume more packets before sending
602 // TODO: handle this case properly.
603 // for now, we just proceed to throw an error to avoid dropping a frame
604 }
605 if (err < 0) {
606 throwFFMPEGError(err, "avcodec_send_frame()");
607 }
608 }
609
610 err = avcodec_receive_packet(m_encoder, &m_avpkt);
611
612 if (err < 0) {
613 gotFrame = false;
614 if (err == AVERROR(EAGAIN)) {
615 // we need to send more frames before consuming a packet
616 err = 0;
617 }
618 if (err < 0) {
619 throwFFMPEGError(err, "avcodec_receive_packet()");
620 }
621 } else {
622 gotFrame = true;
623 }
624#endif
625
626 m_audioFramePrebuf.consume(requiredBytes);
627
628#ifdef DEBUG_AUDIOCONVERTER
629 if (gotFrame)
630 m_encoderOutput.write((char*) m_avpktOut.data, m_avpktOut.size);
631#endif
632 }
633 catch (...)
634 {
635 m_audioFramePrebuf.consume(requiredBytes);
636 throw;
637 }
638
639 return gotFrame;
640 }
641 return false;
642}
643
644uint32_t AudioConverter::CAChannelCountToLayout(UInt32 numChannels)
645{
646 // TODO: this is just wild guessing
647 switch (numChannels)
648 {
649 case 1:
650 return AV_CH_LAYOUT_MONO;
651 case 2:
652 return AV_CH_LAYOUT_STEREO;
653 case 3:
654 return AV_CH_LAYOUT_SURROUND;
655 case 4:
656 return AV_CH_LAYOUT_4POINT0;
657 case 5:
658 return AV_CH_LAYOUT_4POINT1;
659 case 6:
660 return AV_CH_LAYOUT_5POINT1;
661 case 7:
662 return AV_CH_LAYOUT_6POINT1;
663 case 8:
664 return AV_CH_LAYOUT_7POINT1;
665 default:
666 return AV_CH_LAYOUT_STEREO;
667 }
668}
669
670enum AVSampleFormat AudioConverter::CACodecSampleFormat(const AudioStreamBasicDescription* desc)
671{
672 if (desc->mFormatFlags & kAudioFormatFlagIsFloat)
673 {
674 if (desc->mBitsPerChannel == 32)
675 return AV_SAMPLE_FMT_FLT;
676 else if (desc->mBitsPerChannel == 64)
677 return AV_SAMPLE_FMT_DBL;
678 else
679 return AV_SAMPLE_FMT_NONE;
680 }
681 else
682 {
683
684 switch (desc->mBitsPerChannel)
685 {
686 case 8: return AV_SAMPLE_FMT_U8;
687 case 16: return AV_SAMPLE_FMT_S16;
688 case 24: return AV_SAMPLE_FMT_S32; // FIXME: 24-bits?
689 case 32: return AV_SAMPLE_FMT_S32;
690 default: return AV_SAMPLE_FMT_NONE;
691 }
692 }
693}
694
695enum AVCodecID AudioConverter::CACodecToAV(const AudioStreamBasicDescription* desc)
696{
697 switch (desc->mFormatID)
698 {
699 case kAudioFormatLinearPCM:
700 {
701 if (desc->mFormatFlags & kAudioFormatFlagIsFloat)
702 {
703 if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
704 {
705 if (desc->mBitsPerChannel == 32)
706 return AV_CODEC_ID_PCM_F32BE;
707 else if (desc->mBitsPerChannel == 64)
708 return AV_CODEC_ID_PCM_F64BE;
709 }
710 else
711 {
712 if (desc->mBitsPerChannel == 32)
713 return AV_CODEC_ID_PCM_F32LE;
714 else if (desc->mBitsPerChannel == 64)
715 return AV_CODEC_ID_PCM_F64LE;
716 }
717 }
718 else if (desc->mFormatFlags & kAudioFormatFlagIsSignedInteger)
719 {
720 enum AVCodecID cid;
721
722 switch (desc->mBitsPerChannel)
723 {
724 case 8: cid = AV_CODEC_ID_PCM_S8; break;
725 case 16: cid = AV_CODEC_ID_PCM_S16LE; break;
726 case 24: cid = AV_CODEC_ID_PCM_S24LE; break;
727 case 32: cid = AV_CODEC_ID_PCM_S32LE; break;
728 default: return AV_CODEC_ID_NONE;
729 }
730
731 if (desc->mBitsPerChannel != 8 && desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
732 cid = (enum AVCodecID)(int(cid)+1);
733 return cid;
734 }
735 else
736 {
737 enum AVCodecID cid;
738
739 switch (desc->mBitsPerChannel)
740 {
741 case 8: cid = AV_CODEC_ID_PCM_U8; break;
742 case 16: cid = AV_CODEC_ID_PCM_U16LE; break;
743 case 24: cid = AV_CODEC_ID_PCM_U24LE; break;
744 case 32: cid = AV_CODEC_ID_PCM_U32LE; break;
745 default: return AV_CODEC_ID_NONE;
746 }
747
748 if (desc->mBitsPerChannel != 8 && desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
749 cid = (enum AVCodecID)(int(cid)+1);
750 return cid;
751 }
752 return AV_CODEC_ID_NONE;
753 }
754 case kAudioFormatULaw:
755 return AV_CODEC_ID_PCM_MULAW;
756 case kAudioFormatALaw:
757 return AV_CODEC_ID_PCM_ALAW;
758 case kAudioFormatMPEGLayer1:
759 return AV_CODEC_ID_MP1;
760 case kAudioFormatMPEGLayer2:
761 return AV_CODEC_ID_MP2;
762 case kAudioFormatMPEGLayer3:
763 return AV_CODEC_ID_MP3;
764 case kAudioFormatAC3:
765 case kAudioFormat60958AC3: // TODO: is this correct?
766 return AV_CODEC_ID_AC3;
767 case kAudioFormatAppleIMA4:
768 return AV_CODEC_ID_ADPCM_IMA_DK4; // TODO: is this correct?
769 case kAudioFormatMPEG4AAC:
770 case kAudioFormatMPEG4AAC_HE:
771 case kAudioFormatMPEG4AAC_LD:
772 case kAudioFormatMPEG4AAC_ELD:
773 case kAudioFormatMPEG4AAC_ELD_SBR:
774 case kAudioFormatMPEG4AAC_ELD_V2:
775 case kAudioFormatMPEG4AAC_HE_V2:
776 case kAudioFormatMPEG4AAC_Spatial:
777 return AV_CODEC_ID_AAC;
778 case kAudioFormatMPEG4CELP:
779 return AV_CODEC_ID_QCELP; // TODO: is this correct?
780 case kAudioFormatAMR:
781 return AV_CODEC_ID_AMR_NB;
782 case kAudioFormatiLBC:
783 return AV_CODEC_ID_ILBC;
784 case kAudioFormatAppleLossless:
785 return AV_CODEC_ID_APE;
786 case kAudioFormatMicrosoftGSM:
787 return AV_CODEC_ID_GSM_MS;
788 case kAudioFormatMACE3:
789 return AV_CODEC_ID_MACE3;
790 case kAudioFormatMACE6:
791 return AV_CODEC_ID_MACE6;
792 default:
793 return AV_CODEC_ID_NONE;
794 }
795}
796