Coverage Report

Created: 2018-09-25 14:53

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