Line data Source code
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 "mozilla/TaskQueue.h"
8 :
9 : #include "FFmpegAudioDecoder.h"
10 : #include "TimeUnits.h"
11 :
12 : #define MAX_CHANNELS 16
13 :
14 : namespace mozilla {
15 :
16 0 : FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
17 0 : TaskQueue* aTaskQueue, const AudioInfo& aConfig)
18 0 : : FFmpegDataDecoder(aLib, aTaskQueue, GetCodecId(aConfig.mMimeType))
19 : {
20 0 : MOZ_COUNT_CTOR(FFmpegAudioDecoder);
21 : // Use a new MediaByteBuffer as the object will be modified during
22 : // initialization.
23 0 : if (aConfig.mCodecSpecificConfig && aConfig.mCodecSpecificConfig->Length()) {
24 0 : mExtraData = new MediaByteBuffer;
25 0 : mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
26 : }
27 0 : }
28 :
29 : RefPtr<MediaDataDecoder::InitPromise>
30 0 : FFmpegAudioDecoder<LIBAV_VER>::Init()
31 : {
32 0 : nsresult rv = InitDecoder();
33 :
34 : return rv == NS_OK
35 : ? InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__)
36 : : InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
37 0 : __func__);
38 : }
39 :
40 : void
41 0 : FFmpegAudioDecoder<LIBAV_VER>::InitCodecContext()
42 : {
43 0 : MOZ_ASSERT(mCodecContext);
44 : // We do not want to set this value to 0 as FFmpeg by default will
45 : // use the number of cores, which with our mozlibavutil get_cpu_count
46 : // isn't implemented.
47 0 : mCodecContext->thread_count = 1;
48 : // FFmpeg takes this as a suggestion for what format to use for audio samples.
49 : // LibAV 0.8 produces rubbish float interleaved samples, request 16 bits
50 : // audio.
51 0 : mCodecContext->request_sample_fmt =
52 0 : (mLib->mVersion == 53) ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT;
53 0 : }
54 :
55 : static AlignedAudioBuffer
56 0 : CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
57 : {
58 0 : MOZ_ASSERT(aNumChannels <= MAX_CHANNELS);
59 :
60 0 : AlignedAudioBuffer audio(aNumChannels * aNumAFrames);
61 0 : if (!audio) {
62 0 : return audio;
63 : }
64 :
65 0 : if (aFrame->format == AV_SAMPLE_FMT_FLT) {
66 : // Audio data already packed. No need to do anything other than copy it
67 : // into a buffer we own.
68 0 : memcpy(audio.get(), aFrame->data[0],
69 0 : aNumChannels * aNumAFrames * sizeof(AudioDataValue));
70 0 : } else if (aFrame->format == AV_SAMPLE_FMT_FLTP) {
71 : // Planar audio data. Pack it into something we can understand.
72 0 : AudioDataValue* tmp = audio.get();
73 0 : AudioDataValue** data = reinterpret_cast<AudioDataValue**>(aFrame->data);
74 0 : for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
75 0 : for (uint32_t channel = 0; channel < aNumChannels; channel++) {
76 0 : *tmp++ = data[channel][frame];
77 : }
78 : }
79 0 : } else if (aFrame->format == AV_SAMPLE_FMT_S16) {
80 : // Audio data already packed. Need to convert from S16 to 32 bits Float
81 0 : AudioDataValue* tmp = audio.get();
82 0 : int16_t* data = reinterpret_cast<int16_t**>(aFrame->data)[0];
83 0 : for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
84 0 : for (uint32_t channel = 0; channel < aNumChannels; channel++) {
85 0 : *tmp++ = AudioSampleToFloat(*data++);
86 : }
87 : }
88 0 : } else if (aFrame->format == AV_SAMPLE_FMT_S16P) {
89 : // Planar audio data. Convert it from S16 to 32 bits float
90 : // and pack it into something we can understand.
91 0 : AudioDataValue* tmp = audio.get();
92 0 : int16_t** data = reinterpret_cast<int16_t**>(aFrame->data);
93 0 : for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
94 0 : for (uint32_t channel = 0; channel < aNumChannels; channel++) {
95 0 : *tmp++ = AudioSampleToFloat(data[channel][frame]);
96 : }
97 : }
98 0 : } else if (aFrame->format == AV_SAMPLE_FMT_S32) {
99 : // Audio data already packed. Need to convert from S16 to 32 bits Float
100 0 : AudioDataValue* tmp = audio.get();
101 0 : int32_t* data = reinterpret_cast<int32_t**>(aFrame->data)[0];
102 0 : for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
103 0 : for (uint32_t channel = 0; channel < aNumChannels; channel++) {
104 0 : *tmp++ = AudioSampleToFloat(*data++);
105 : }
106 : }
107 0 : } else if (aFrame->format == AV_SAMPLE_FMT_S32P) {
108 : // Planar audio data. Convert it from S32 to 32 bits float
109 : // and pack it into something we can understand.
110 0 : AudioDataValue* tmp = audio.get();
111 0 : int32_t** data = reinterpret_cast<int32_t**>(aFrame->data);
112 0 : for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
113 0 : for (uint32_t channel = 0; channel < aNumChannels; channel++) {
114 0 : *tmp++ = AudioSampleToFloat(data[channel][frame]);
115 : }
116 : }
117 : }
118 :
119 0 : return audio;
120 : }
121 :
122 : RefPtr<MediaDataDecoder::DecodePromise>
123 0 : FFmpegAudioDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
124 : {
125 : AVPacket packet;
126 0 : mLib->av_init_packet(&packet);
127 :
128 0 : packet.data = const_cast<uint8_t*>(aSample->Data());
129 0 : packet.size = aSample->Size();
130 :
131 0 : if (!PrepareFrame()) {
132 : return DecodePromise::CreateAndReject(
133 0 : MediaResult(
134 : NS_ERROR_OUT_OF_MEMORY,
135 0 : RESULT_DETAIL("FFmpeg audio decoder failed to allocate frame")),
136 0 : __func__);
137 : }
138 :
139 0 : int64_t samplePosition = aSample->mOffset;
140 0 : media::TimeUnit pts = aSample->mTime;
141 :
142 0 : DecodedData results;
143 0 : while (packet.size > 0) {
144 : int decoded;
145 : int bytesConsumed =
146 0 : mLib->avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet);
147 :
148 0 : if (bytesConsumed < 0) {
149 0 : NS_WARNING("FFmpeg audio decoder error.");
150 : return DecodePromise::CreateAndReject(
151 0 : MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
152 0 : RESULT_DETAIL("FFmpeg audio error:%d", bytesConsumed)),
153 0 : __func__);
154 : }
155 :
156 0 : if (decoded) {
157 0 : if (mFrame->format != AV_SAMPLE_FMT_FLT &&
158 0 : mFrame->format != AV_SAMPLE_FMT_FLTP &&
159 0 : mFrame->format != AV_SAMPLE_FMT_S16 &&
160 0 : mFrame->format != AV_SAMPLE_FMT_S16P &&
161 0 : mFrame->format != AV_SAMPLE_FMT_S32 &&
162 0 : mFrame->format != AV_SAMPLE_FMT_S32P) {
163 : return DecodePromise::CreateAndReject(
164 0 : MediaResult(
165 : NS_ERROR_DOM_MEDIA_DECODE_ERR,
166 0 : RESULT_DETAIL(
167 : "FFmpeg audio decoder outputs unsupported audio format")),
168 0 : __func__);
169 : }
170 0 : uint32_t numChannels = mCodecContext->channels;
171 0 : AudioConfig::ChannelLayout layout(numChannels);
172 0 : if (!layout.IsValid()) {
173 : return DecodePromise::CreateAndReject(
174 0 : MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
175 0 : RESULT_DETAIL("Unsupported channel layout:%u", numChannels)),
176 0 : __func__);
177 : }
178 :
179 0 : uint32_t samplingRate = mCodecContext->sample_rate;
180 :
181 : AlignedAudioBuffer audio =
182 0 : CopyAndPackAudio(mFrame, numChannels, mFrame->nb_samples);
183 0 : if (!audio) {
184 : return DecodePromise::CreateAndReject(
185 0 : MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
186 : }
187 :
188 : media::TimeUnit duration =
189 0 : FramesToTimeUnit(mFrame->nb_samples, samplingRate);
190 0 : if (!duration.IsValid()) {
191 : return DecodePromise::CreateAndReject(
192 0 : MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
193 0 : RESULT_DETAIL("Invalid sample duration")),
194 0 : __func__);
195 : }
196 :
197 0 : media::TimeUnit newpts = pts + duration;
198 0 : if (!newpts.IsValid()) {
199 : return DecodePromise::CreateAndReject(
200 0 : MediaResult(
201 : NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
202 0 : RESULT_DETAIL("Invalid count of accumulated audio samples")),
203 0 : __func__);
204 : }
205 :
206 0 : results.AppendElement(new AudioData(
207 : samplePosition, pts, duration,
208 0 : mFrame->nb_samples, Move(audio), numChannels, samplingRate));
209 :
210 0 : pts = newpts;
211 : }
212 0 : packet.data += bytesConsumed;
213 0 : packet.size -= bytesConsumed;
214 0 : samplePosition += bytesConsumed;
215 : }
216 0 : return DecodePromise::CreateAndResolve(Move(results), __func__);
217 : }
218 :
219 : RefPtr<MediaDataDecoder::DecodePromise>
220 0 : FFmpegAudioDecoder<LIBAV_VER>::ProcessDrain()
221 : {
222 0 : ProcessFlush();
223 0 : return DecodePromise::CreateAndResolve(DecodedData(), __func__);
224 : }
225 :
226 : AVCodecID
227 0 : FFmpegAudioDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
228 : {
229 0 : if (aMimeType.EqualsLiteral("audio/mpeg")) {
230 0 : return AV_CODEC_ID_MP3;
231 0 : } else if (aMimeType.EqualsLiteral("audio/flac")) {
232 0 : return AV_CODEC_ID_FLAC;
233 0 : } else if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
234 0 : return AV_CODEC_ID_AAC;
235 : }
236 :
237 0 : return AV_CODEC_ID_NONE;
238 : }
239 :
240 0 : FFmpegAudioDecoder<LIBAV_VER>::~FFmpegAudioDecoder()
241 : {
242 0 : MOZ_COUNT_DTOR(FFmpegAudioDecoder);
243 0 : }
244 :
245 : } // namespace mozilla
|