Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Side by Side Diff: media/cast/sender/audio_encoder.cc

Issue 601413003: [cast] AAC encoder for OS X and iOS based on AudioConverter and AudioFile (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@audio-remove-constants
Patch Set: Modernize to C++11 per the rules at http://chromium-cpp.appspot.com/ Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cast/sender/audio_encoder.h" 5 #include "media/cast/sender/audio_encoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/sys_byteorder.h" 13 #include "base/sys_byteorder.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "media/base/audio_bus.h" 15 #include "media/base/audio_bus.h"
16 #include "media/cast/cast_defines.h" 16 #include "media/cast/cast_defines.h"
17 #include "media/cast/cast_environment.h" 17 #include "media/cast/cast_environment.h"
18
19 #if !defined(OS_IOS)
18 #include "third_party/opus/src/include/opus.h" 20 #include "third_party/opus/src/include/opus.h"
21 #endif
22
23 #if defined(OS_MACOSX)
24 #include <AudioToolbox/AudioToolbox.h>
25 #endif
19 26
20 namespace media { 27 namespace media {
21 namespace cast { 28 namespace cast {
22 29
23 30
24 // Base class that handles the common problem of feeding one or more AudioBus' 31 // Base class that handles the common problem of feeding one or more AudioBus'
25 // data into a buffer and then, once the buffer is full, encoding the signal and 32 // data into a buffer and then, once the buffer is full, encoding the signal and
26 // emitting an EncodedFrame via the FrameEncodedCallback. 33 // emitting an EncodedFrame via the FrameEncodedCallback.
27 // 34 //
28 // Subclasses complete the implementation by handling the actual encoding 35 // Subclasses complete the implementation by handling the actual encoding
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 // the RTP timestamps. 199 // the RTP timestamps.
193 base::TimeTicks frame_capture_time_; 200 base::TimeTicks frame_capture_time_;
194 201
195 // Set to non-zero to indicate the next output frame skipped over audio 202 // Set to non-zero to indicate the next output frame skipped over audio
196 // samples in order to recover from an input underrun. 203 // samples in order to recover from an input underrun.
197 int samples_dropped_from_buffer_; 204 int samples_dropped_from_buffer_;
198 205
199 DISALLOW_COPY_AND_ASSIGN(ImplBase); 206 DISALLOW_COPY_AND_ASSIGN(ImplBase);
200 }; 207 };
201 208
209 #if !defined(OS_IOS)
202 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { 210 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
203 public: 211 public:
204 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, 212 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment,
205 int num_channels, 213 int num_channels,
206 int sampling_rate, 214 int sampling_rate,
207 int bitrate, 215 int bitrate,
208 const FrameEncodedCallback& callback) 216 const FrameEncodedCallback& callback)
209 : ImplBase(cast_environment, 217 : ImplBase(cast_environment,
210 CODEC_AUDIO_OPUS, 218 CODEC_AUDIO_OPUS,
211 num_channels, 219 num_channels,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 // This is the recommended value, according to documentation in 291 // This is the recommended value, according to documentation in
284 // third_party/opus/src/include/opus.h, so that the Opus encoder does not 292 // third_party/opus/src/include/opus.h, so that the Opus encoder does not
285 // degrade the audio due to memory constraints. 293 // degrade the audio due to memory constraints.
286 // 294 //
287 // Note: Whereas other RTP implementations do not, the cast library is 295 // Note: Whereas other RTP implementations do not, the cast library is
288 // perfectly capable of transporting larger than MTU-sized audio frames. 296 // perfectly capable of transporting larger than MTU-sized audio frames.
289 static const int kOpusMaxPayloadSize = 4000; 297 static const int kOpusMaxPayloadSize = 4000;
290 298
291 DISALLOW_COPY_AND_ASSIGN(OpusImpl); 299 DISALLOW_COPY_AND_ASSIGN(OpusImpl);
292 }; 300 };
301 #endif
302
303 #if defined(OS_MACOSX)
304 class AudioEncoder::AacAudioConverterImpl : public AudioEncoder::ImplBase {
305 public:
306 AacAudioConverterImpl(const scoped_refptr<CastEnvironment>& cast_environment,
307 int num_channels,
308 int sampling_rate,
309 int bitrate,
310 const FrameEncodedCallback& callback)
311 : ImplBase(cast_environment,
312 CODEC_AUDIO_AAC,
313 num_channels,
314 sampling_rate,
315 1024, /* AudioConverter produces 1024 samples blocks */
miu 2014/09/29 19:54:47 s/AudioConverter/AacImpl/
316 callback),
317 input_buffer_(AudioBus::Create(num_channels, 1024)),
318 output_buffer_(nullptr),
319 converter_(nullptr),
320 file_(nullptr),
321 num_encoded_packets_(0),
322 max_packet_size_(0),
323 can_resume_(true) {
324 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) {
325 return;
326 }
327 if (!Initialize(sampling_rate, bitrate)) {
328 ImplBase::cast_initialization_status_ =
329 STATUS_INVALID_AUDIO_CONFIGURATION;
330 return;
331 }
332 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED;
333 }
334
335 private:
336 // The |AudioConverterFillComplexBuffer| input callback function. Returns the
337 // data that has been copied into the encoder's |buffer_| by the
338 // |TransferSamplesIntoBuffer| method.
miu 2014/09/29 19:54:47 Just a sanity-check: This callback is called synch
jfroy 2014/10/14 01:06:34 Yep. I'll add the comment.
339 static OSStatus ConverterFillDataCallback(
miu 2014/09/29 19:54:47 style nit: static methods need to be declared/defi
340 AudioConverterRef in_converter,
341 UInt32* io_num_packets,
342 AudioBufferList* io_data,
343 AudioStreamPacketDescription** out_packet_desc,
344 void* in_encoder) {
345 DCHECK(io_data);
346 DCHECK(in_encoder);
347 auto encoder = reinterpret_cast<const AacAudioConverterImpl*>(in_encoder);
348
349 // Provide the entire content of the input buffer.
350 const int num_frames = encoder->input_buffer_->frames();
351 *io_num_packets = num_frames;
352
353 DCHECK_EQ(io_data->mNumberBuffers,
354 static_cast<unsigned>(encoder->input_buffer_->channels()));
355 for (int i_buf = 0, end = io_data->mNumberBuffers; i_buf < end; ++i_buf) {
356 io_data->mBuffers[i_buf].mNumberChannels = 1;
357 io_data->mBuffers[i_buf].mDataByteSize = sizeof(float) * num_frames;
358 io_data->mBuffers[i_buf].mData = encoder->input_buffer_->channel(i_buf);
359 }
360 return noErr;
361 }
362
363 // The AudioFile write callback function. Appends the data to the encoder's
364 // current output buffer.
365 static OSStatus FileWriteCallback(void* in_encoder,
366 SInt64 in_position,
367 UInt32 in_size,
368 const void* in_buffer,
369 UInt32* out_size) {
370 DCHECK(in_encoder);
371 auto encoder = reinterpret_cast<const AacAudioConverterImpl*>(in_encoder);
372 DCHECK(in_buffer);
373 auto buffer = reinterpret_cast<const std::string::value_type*>(in_buffer);
374
375 std::string* const output_buffer = encoder->output_buffer_;
376 DCHECK(output_buffer);
377
378 output_buffer->append(buffer, in_size);
379 *out_size = in_size;
380 return noErr;
381 }
382
383 virtual ~AacAudioConverterImpl() { Teardown(); }
384
385 // Destroys the existing audio converter and file, if any.
386 void Teardown() {
387 if (converter_) {
388 AudioConverterDispose(converter_);
389 converter_ = nullptr;
390 }
391 if (file_) {
392 AudioFileClose(file_);
393 file_ = nullptr;
394 }
395 }
396
397 // Initializes the audio converter and file. Calls Teardown to destroy any
398 // existing state. This is so that Initialize() may be called to setup another
399 // converter after a non-resumable interruption.
400 bool Initialize(int sampling_rate, int bitrate) {
401 // Teardown previous audio converter and file.
402 Teardown();
403
404 // Input data comes from AudioBus objects, which carry deinterleaved packed
405 // native-endian float samples.
406 AudioStreamBasicDescription in_asbd;
407 in_asbd.mSampleRate = sampling_rate;
408 in_asbd.mFormatID = kAudioFormatLinearPCM;
409 in_asbd.mFormatFlags =
410 kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
411 in_asbd.mChannelsPerFrame = num_channels_;
412 in_asbd.mBitsPerChannel = sizeof(float) * 8;
413 in_asbd.mFramesPerPacket = 1;
414 in_asbd.mBytesPerPacket = in_asbd.mBytesPerFrame = sizeof(float);
miu 2014/09/29 19:54:47 Somehow, this doesn't seem right. Only 4 bytes pe
jfroy 2014/10/14 01:06:34 In Core Audio, a frame of audio is one sample acro
415 in_asbd.mReserved = 0;
416
417 // Request AAC-LC encoding, with no downmixing or downsampling.
418 AudioStreamBasicDescription out_asbd;
419 memset(&out_asbd, 0, sizeof(AudioStreamBasicDescription));
420 out_asbd.mSampleRate = sampling_rate;
421 out_asbd.mFormatID = kAudioFormatMPEG4AAC;
422 out_asbd.mChannelsPerFrame = num_channels_;
423 UInt32 prop_size = sizeof(out_asbd);
424 if (AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
425 0,
426 nullptr,
427 &prop_size,
428 &out_asbd) != noErr) {
429 return false;
430 }
431
432 if (AudioConverterNew(&in_asbd, &out_asbd, &converter_) != noErr) {
433 return false;
434 }
435
436 // The converter is allowed to modify (really fill-in) the output format.
437 // After creation, we can query the final output format.
438 prop_size = sizeof(out_asbd);
439 if (AudioConverterGetProperty(converter_,
440 kAudioConverterCurrentOutputStreamDescription,
441 &prop_size,
442 &out_asbd) != noErr) {
443 return false;
444 }
445
446 // If bitrate is <= 0, allow the encoder to pick a suitable value.
447 // Otherwise, set the bitrate (which can fail if the value is not suitable
448 // or compatible with the output sampling rate or channels).
449 if (bitrate > 0) {
450 prop_size = sizeof(int);
451 if (AudioConverterSetProperty(
452 converter_, kAudioConverterEncodeBitRate, prop_size, &bitrate) !=
453 noErr) {
454 return false;
455 }
456 }
457
458 // See the comment next to |can_resume_| for details on resumption. Some
459 // converters can return kAudioConverterErr_PropertyNotSupported, in which
460 // case resumption is implicitly supported.
461 uint32_t can_resume;
462 prop_size = sizeof(can_resume);
463 OSStatus oserr = AudioConverterGetProperty(
464 converter_,
465 kAudioConverterPropertyCanResumeFromInterruption,
466 &prop_size,
467 &can_resume);
468 if (oserr == noErr) {
469 const_cast<bool&>(can_resume_) = can_resume != 0;
470 }
471
472 // mBytesPerPacket will be 0 for variable packet size configurations, in
473 // which case we must query the maximum possible packet size.
474 const_cast<uint32_t&>(max_packet_size_) = out_asbd.mBytesPerPacket;
475 if (max_packet_size_ == 0) {
476 prop_size = sizeof(max_packet_size_);
477 if (AudioConverterGetProperty(
478 converter_,
479 kAudioConverterPropertyMaximumOutputPacketSize,
480 &prop_size,
481 const_cast<uint32_t*>(&max_packet_size_)) != noErr) {
482 return false;
483 }
484 }
485
486 // This is the only location where we modify the packet buffer.
487 const_cast<scoped_ptr<uint8[]>&>(packet_buffer_)
488 .reset(new uint8[max_packet_size_]);
489
490 // The "magic cookie" is an encoder state vector required for decoding and
491 // packing. We query it from the converter and set it on the file below.
492 UInt32 cookie_size;
493 if (AudioConverterGetPropertyInfo(converter_,
494 kAudioConverterCompressionMagicCookie,
495 &cookie_size,
496 nullptr) != noErr) {
497 return false;
498 }
499 scoped_ptr<int8[]> cookie_data(new int8[cookie_size]);
miu 2014/09/29 19:54:47 Sanity-check: Did you mean uint8 here, or is int8
jfroy 2014/10/14 01:06:34 Their API use void*, which doesn't play well in C+
500 if (AudioConverterGetProperty(converter_,
501 kAudioConverterCompressionMagicCookie,
502 &cookie_size,
503 cookie_data.get()) != noErr) {
504 return false;
505 }
506
507 if (AudioFileInitializeWithCallbacks(this,
508 nullptr,
509 &FileWriteCallback,
510 nullptr,
511 nullptr,
512 kAudioFileAAC_ADTSType,
513 &out_asbd,
514 0,
515 &file_) != noErr) {
516 return false;
517 }
518
519 if (AudioFileSetProperty(file_,
520 kAudioFilePropertyMagicCookieData,
521 cookie_size,
522 cookie_data.get()) != noErr) {
523 return false;
524 }
525
526 return true;
527 }
528
529 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
530 int source_offset,
531 int buffer_fill_offset,
532 int num_samples) override {
533 audio_bus->CopyPartialFramesTo(
534 source_offset, num_samples, buffer_fill_offset, input_buffer_.get());
535 }
536
537 virtual bool EncodeFromFilledBuffer(std::string* out) override {
538 AudioBufferList out_abl;
miu 2014/09/29 19:54:47 nit: Can out_abl be initialized once in Initialize
jfroy 2014/10/14 01:06:34 Good idea.
539 out_abl.mNumberBuffers = 1;
540 out_abl.mBuffers[0].mNumberChannels = num_channels_;
541 out_abl.mBuffers[0].mDataByteSize = max_packet_size_;
542 out_abl.mBuffers[0].mData = packet_buffer_.get();
543
544 UInt32 io_num_packets = 1;
545 AudioStreamPacketDescription packet_description;
546 if (AudioConverterFillComplexBuffer(converter_,
547 &ConverterFillDataCallback,
548 this,
549 &io_num_packets,
550 &out_abl,
551 &packet_description) != noErr ||
552 io_num_packets == 0) {
553 return false;
554 }
555
556 // Reserve enough space to write the packet and a basic ADTS header.
557 out->reserve(packet_description.mDataByteSize + 7);
miu 2014/09/29 19:54:47 Where does 7 come from? Can you specify this as s
jfroy 2014/10/14 01:06:34 It's the ADTS header size. I've switched to a cons
558
559 output_buffer_ = out;
560 OSStatus oserr = AudioFileWritePackets(file_,
561 false,
562 out_abl.mBuffers[0].mDataByteSize,
563 &packet_description,
564 num_encoded_packets_,
565 &io_num_packets,
566 out_abl.mBuffers[0].mData);
567 output_buffer_ = nullptr;
568 if (oserr != noErr || io_num_packets == 0) {
569 return false;
570 }
571 num_encoded_packets_ += io_num_packets;
572 return true;
573 }
574
575 // A buffer that holds one encoded packet worth of audio frames. Initialized
576 // during construction.
577 const scoped_ptr<AudioBus> input_buffer_;
578
579 // A buffer that holds one encoded packet. Initialized in |Initialize| once
580 // the maximum packet size is known.
581 const scoped_ptr<uint8[]> packet_buffer_;
582
583 // A temporary pointer to the current output buffer. Only non-null when
584 // writing a packet for use by the AudioFile write callback.
585 std::string* output_buffer_;
586
587 // The AudioConverter is responsible for encoding LPCM frames to AAC packets.
588 AudioConverterRef converter_;
589
590 // The AudioFile is responsible for wrapping AAC packets into ADTS packets.
591 AudioFileID file_;
592
593 // The number of encoded packets emitted so far by the encoder.
594 uint64_t num_encoded_packets_;
595
596 // The maximum packet size that the encoder can emit.
597 const uint32_t max_packet_size_;
598
599 // On iOS, AudioConverter can be interrupted by other services (such as an
600 // audio alert or phone call). Depending on the underlying hardware and
601 // configuration, the converter may have to be thrown away and re-initialized
602 // after such an interruption. This flag tracks if we can resume or not.
603 const bool can_resume_;
miu 2014/09/29 19:54:47 Is this used anywhere?
jfroy 2014/10/14 01:06:34 Not yet but I'll be filing a bug to add support fo
604
605 DISALLOW_COPY_AND_ASSIGN(AacAudioConverterImpl);
606 };
607 #endif // defined(OS_MACOSX)
293 608
294 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { 609 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase {
295 public: 610 public:
296 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, 611 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment,
297 int num_channels, 612 int num_channels,
298 int sampling_rate, 613 int sampling_rate,
299 const FrameEncodedCallback& callback) 614 const FrameEncodedCallback& callback)
300 : ImplBase(cast_environment, 615 : ImplBase(cast_environment,
301 CODEC_AUDIO_PCM16, 616 CODEC_AUDIO_PCM16,
302 num_channels, 617 num_channels,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 int num_channels, 660 int num_channels,
346 int sampling_rate, 661 int sampling_rate,
347 int bitrate, 662 int bitrate,
348 Codec codec, 663 Codec codec,
349 const FrameEncodedCallback& frame_encoded_callback) 664 const FrameEncodedCallback& frame_encoded_callback)
350 : cast_environment_(cast_environment) { 665 : cast_environment_(cast_environment) {
351 // Note: It doesn't matter which thread constructs AudioEncoder, just so long 666 // Note: It doesn't matter which thread constructs AudioEncoder, just so long
352 // as all calls to InsertAudio() are by the same thread. 667 // as all calls to InsertAudio() are by the same thread.
353 insert_thread_checker_.DetachFromThread(); 668 insert_thread_checker_.DetachFromThread();
354 switch (codec) { 669 switch (codec) {
670 #if !defined(OS_IOS)
355 case CODEC_AUDIO_OPUS: 671 case CODEC_AUDIO_OPUS:
356 impl_ = new OpusImpl(cast_environment, 672 impl_ = new OpusImpl(cast_environment,
357 num_channels, 673 num_channels,
358 sampling_rate, 674 sampling_rate,
359 bitrate, 675 bitrate,
360 frame_encoded_callback); 676 frame_encoded_callback);
361 break; 677 break;
678 #endif
679 #if defined(OS_MACOSX)
680 case CODEC_AUDIO_AAC:
681 impl_ = new AacAudioConverterImpl(cast_environment,
682 num_channels,
683 sampling_rate,
684 bitrate,
685 frame_encoded_callback);
686 break;
687 #endif // defined(OS_MACOSX)
362 case CODEC_AUDIO_PCM16: 688 case CODEC_AUDIO_PCM16:
363 impl_ = new Pcm16Impl(cast_environment, 689 impl_ = new Pcm16Impl(cast_environment,
364 num_channels, 690 num_channels,
365 sampling_rate, 691 sampling_rate,
366 frame_encoded_callback); 692 frame_encoded_callback);
367 break; 693 break;
368 default: 694 default:
369 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; 695 NOTREACHED() << "Unsupported or unspecified codec for audio encoder";
370 break; 696 break;
371 } 697 }
(...skipping 29 matching lines...) Expand all
401 cast_environment_->PostTask(CastEnvironment::AUDIO, 727 cast_environment_->PostTask(CastEnvironment::AUDIO,
402 FROM_HERE, 728 FROM_HERE,
403 base::Bind(&AudioEncoder::ImplBase::EncodeAudio, 729 base::Bind(&AudioEncoder::ImplBase::EncodeAudio,
404 impl_, 730 impl_,
405 base::Passed(&audio_bus), 731 base::Passed(&audio_bus),
406 recorded_time)); 732 recorded_time));
407 } 733 }
408 734
409 } // namespace cast 735 } // namespace cast
410 } // namespace media 736 } // namespace media
OLDNEW
« media/cast/sender/audio_encoder.h ('K') | « media/cast/sender/audio_encoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698