1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/fmp4/ffmpeg/FFmpegAACDecoder.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,130 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "MediaTaskQueue.h" 1.11 +#include "FFmpegRuntimeLinker.h" 1.12 + 1.13 +#include "FFmpegAACDecoder.h" 1.14 + 1.15 +#define MAX_CHANNELS 16 1.16 + 1.17 +typedef mp4_demuxer::MP4Sample MP4Sample; 1.18 + 1.19 +namespace mozilla 1.20 +{ 1.21 + 1.22 +FFmpegAACDecoder::FFmpegAACDecoder( 1.23 + MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, 1.24 + const mp4_demuxer::AudioDecoderConfig &aConfig) 1.25 + : FFmpegDataDecoder(aTaskQueue, AV_CODEC_ID_AAC) 1.26 + , mCallback(aCallback) 1.27 + , mConfig(aConfig) 1.28 +{ 1.29 + MOZ_COUNT_CTOR(FFmpegAACDecoder); 1.30 +} 1.31 + 1.32 +nsresult 1.33 +FFmpegAACDecoder::Init() 1.34 +{ 1.35 + nsresult rv = FFmpegDataDecoder::Init(); 1.36 + NS_ENSURE_SUCCESS(rv, rv); 1.37 + 1.38 + return NS_OK; 1.39 +} 1.40 + 1.41 +static AudioDataValue* 1.42 +CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumSamples) 1.43 +{ 1.44 + // These are the only two valid AAC packet sizes. 1.45 + NS_ASSERTION(aNumSamples == 960 || aNumSamples == 1024, 1.46 + "Should have exactly one AAC audio packet."); 1.47 + MOZ_ASSERT(aNumChannels <= MAX_CHANNELS); 1.48 + 1.49 + nsAutoArrayPtr<AudioDataValue> audio( 1.50 + new AudioDataValue[aNumChannels * aNumSamples]); 1.51 + 1.52 + AudioDataValue** data = reinterpret_cast<AudioDataValue**>(aFrame->data); 1.53 + 1.54 + if (aFrame->format == AV_SAMPLE_FMT_FLT) { 1.55 + // Audio data already packed. No need to do anything other than copy it 1.56 + // into a buffer we own. 1.57 + memcpy(audio, data[0], aNumChannels * aNumSamples * sizeof(AudioDataValue)); 1.58 + } else if (aFrame->format == AV_SAMPLE_FMT_FLTP) { 1.59 + // Planar audio data. Pack it into something we can understand. 1.60 + for (uint32_t channel = 0; channel < aNumChannels; channel++) { 1.61 + for (uint32_t sample = 0; sample < aNumSamples; sample++) { 1.62 + audio[sample * aNumChannels + channel] = data[channel][sample]; 1.63 + } 1.64 + } 1.65 + } 1.66 + 1.67 + return audio.forget(); 1.68 +} 1.69 + 1.70 +void 1.71 +FFmpegAACDecoder::DecodePacket(MP4Sample* aSample) 1.72 +{ 1.73 + nsAutoPtr<AVFrame> frame(avcodec_alloc_frame()); 1.74 + avcodec_get_frame_defaults(frame); 1.75 + 1.76 + AVPacket packet; 1.77 + av_init_packet(&packet); 1.78 + 1.79 + packet.data = &(*aSample->data)[0]; 1.80 + packet.size = aSample->data->size(); 1.81 + packet.pos = aSample->byte_offset; 1.82 + packet.dts = aSample->decode_timestamp; 1.83 + 1.84 + int decoded; 1.85 + int bytesConsumed = 1.86 + avcodec_decode_audio4(&mCodecContext, frame.get(), &decoded, &packet); 1.87 + 1.88 + if (bytesConsumed < 0 || !decoded) { 1.89 + NS_WARNING("FFmpeg audio decoder error."); 1.90 + mCallback->Error(); 1.91 + return; 1.92 + } 1.93 + 1.94 + NS_ASSERTION(bytesConsumed == (int)aSample->data->size(), 1.95 + "Only one audio packet should be received at a time."); 1.96 + 1.97 + uint32_t numChannels = mCodecContext.channels; 1.98 + 1.99 + nsAutoArrayPtr<AudioDataValue> audio( 1.100 + CopyAndPackAudio(frame.get(), numChannels, frame->nb_samples)); 1.101 + 1.102 + nsAutoPtr<AudioData> data(new AudioData(packet.pos, aSample->decode_timestamp, 1.103 + aSample->duration, frame->nb_samples, 1.104 + audio.forget(), numChannels)); 1.105 + 1.106 + mCallback->Output(data.forget()); 1.107 + 1.108 + if (mTaskQueue->IsEmpty()) { 1.109 + mCallback->InputExhausted(); 1.110 + } 1.111 +} 1.112 + 1.113 +nsresult 1.114 +FFmpegAACDecoder::Input(MP4Sample* aSample) 1.115 +{ 1.116 + mTaskQueue->Dispatch(NS_NewRunnableMethodWithArg<nsAutoPtr<MP4Sample> >( 1.117 + this, &FFmpegAACDecoder::DecodePacket, nsAutoPtr<MP4Sample>(aSample))); 1.118 + 1.119 + return NS_OK; 1.120 +} 1.121 + 1.122 +nsresult 1.123 +FFmpegAACDecoder::Drain() 1.124 +{ 1.125 + // AAC is never delayed; nothing to do here. 1.126 + return NS_OK; 1.127 +} 1.128 + 1.129 +FFmpegAACDecoder::~FFmpegAACDecoder() { 1.130 + MOZ_COUNT_DTOR(FFmpegAACDecoder); 1.131 +} 1.132 + 1.133 +} // namespace mozilla