|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "MediaTaskQueue.h" |
|
8 #include "FFmpegRuntimeLinker.h" |
|
9 |
|
10 #include "FFmpegAACDecoder.h" |
|
11 |
|
12 #define MAX_CHANNELS 16 |
|
13 |
|
14 typedef mp4_demuxer::MP4Sample MP4Sample; |
|
15 |
|
16 namespace mozilla |
|
17 { |
|
18 |
|
19 FFmpegAACDecoder::FFmpegAACDecoder( |
|
20 MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, |
|
21 const mp4_demuxer::AudioDecoderConfig &aConfig) |
|
22 : FFmpegDataDecoder(aTaskQueue, AV_CODEC_ID_AAC) |
|
23 , mCallback(aCallback) |
|
24 , mConfig(aConfig) |
|
25 { |
|
26 MOZ_COUNT_CTOR(FFmpegAACDecoder); |
|
27 } |
|
28 |
|
29 nsresult |
|
30 FFmpegAACDecoder::Init() |
|
31 { |
|
32 nsresult rv = FFmpegDataDecoder::Init(); |
|
33 NS_ENSURE_SUCCESS(rv, rv); |
|
34 |
|
35 return NS_OK; |
|
36 } |
|
37 |
|
38 static AudioDataValue* |
|
39 CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumSamples) |
|
40 { |
|
41 // These are the only two valid AAC packet sizes. |
|
42 NS_ASSERTION(aNumSamples == 960 || aNumSamples == 1024, |
|
43 "Should have exactly one AAC audio packet."); |
|
44 MOZ_ASSERT(aNumChannels <= MAX_CHANNELS); |
|
45 |
|
46 nsAutoArrayPtr<AudioDataValue> audio( |
|
47 new AudioDataValue[aNumChannels * aNumSamples]); |
|
48 |
|
49 AudioDataValue** data = reinterpret_cast<AudioDataValue**>(aFrame->data); |
|
50 |
|
51 if (aFrame->format == AV_SAMPLE_FMT_FLT) { |
|
52 // Audio data already packed. No need to do anything other than copy it |
|
53 // into a buffer we own. |
|
54 memcpy(audio, data[0], aNumChannels * aNumSamples * sizeof(AudioDataValue)); |
|
55 } else if (aFrame->format == AV_SAMPLE_FMT_FLTP) { |
|
56 // Planar audio data. Pack it into something we can understand. |
|
57 for (uint32_t channel = 0; channel < aNumChannels; channel++) { |
|
58 for (uint32_t sample = 0; sample < aNumSamples; sample++) { |
|
59 audio[sample * aNumChannels + channel] = data[channel][sample]; |
|
60 } |
|
61 } |
|
62 } |
|
63 |
|
64 return audio.forget(); |
|
65 } |
|
66 |
|
67 void |
|
68 FFmpegAACDecoder::DecodePacket(MP4Sample* aSample) |
|
69 { |
|
70 nsAutoPtr<AVFrame> frame(avcodec_alloc_frame()); |
|
71 avcodec_get_frame_defaults(frame); |
|
72 |
|
73 AVPacket packet; |
|
74 av_init_packet(&packet); |
|
75 |
|
76 packet.data = &(*aSample->data)[0]; |
|
77 packet.size = aSample->data->size(); |
|
78 packet.pos = aSample->byte_offset; |
|
79 packet.dts = aSample->decode_timestamp; |
|
80 |
|
81 int decoded; |
|
82 int bytesConsumed = |
|
83 avcodec_decode_audio4(&mCodecContext, frame.get(), &decoded, &packet); |
|
84 |
|
85 if (bytesConsumed < 0 || !decoded) { |
|
86 NS_WARNING("FFmpeg audio decoder error."); |
|
87 mCallback->Error(); |
|
88 return; |
|
89 } |
|
90 |
|
91 NS_ASSERTION(bytesConsumed == (int)aSample->data->size(), |
|
92 "Only one audio packet should be received at a time."); |
|
93 |
|
94 uint32_t numChannels = mCodecContext.channels; |
|
95 |
|
96 nsAutoArrayPtr<AudioDataValue> audio( |
|
97 CopyAndPackAudio(frame.get(), numChannels, frame->nb_samples)); |
|
98 |
|
99 nsAutoPtr<AudioData> data(new AudioData(packet.pos, aSample->decode_timestamp, |
|
100 aSample->duration, frame->nb_samples, |
|
101 audio.forget(), numChannels)); |
|
102 |
|
103 mCallback->Output(data.forget()); |
|
104 |
|
105 if (mTaskQueue->IsEmpty()) { |
|
106 mCallback->InputExhausted(); |
|
107 } |
|
108 } |
|
109 |
|
110 nsresult |
|
111 FFmpegAACDecoder::Input(MP4Sample* aSample) |
|
112 { |
|
113 mTaskQueue->Dispatch(NS_NewRunnableMethodWithArg<nsAutoPtr<MP4Sample> >( |
|
114 this, &FFmpegAACDecoder::DecodePacket, nsAutoPtr<MP4Sample>(aSample))); |
|
115 |
|
116 return NS_OK; |
|
117 } |
|
118 |
|
119 nsresult |
|
120 FFmpegAACDecoder::Drain() |
|
121 { |
|
122 // AAC is never delayed; nothing to do here. |
|
123 return NS_OK; |
|
124 } |
|
125 |
|
126 FFmpegAACDecoder::~FFmpegAACDecoder() { |
|
127 MOZ_COUNT_DTOR(FFmpegAACDecoder); |
|
128 } |
|
129 |
|
130 } // namespace mozilla |