Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/platforms/ffmpeg/FFmpegDataDecoder.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
8
#include <string.h>
9
#ifdef __GNUC__
10
#include <unistd.h>
11
#endif
12
13
#include "FFmpegLog.h"
14
#include "FFmpegDataDecoder.h"
15
#include "mozilla/TaskQueue.h"
16
#include "prsystem.h"
17
18
namespace mozilla {
19
20
StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
21
22
FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FFmpegLibWrapper* aLib,
23
                                                TaskQueue* aTaskQueue,
24
                                                AVCodecID aCodecID)
25
  : mLib(aLib)
26
  , mCodecContext(nullptr)
27
  , mCodecParser(nullptr)
28
  , mFrame(NULL)
29
  , mExtraData(nullptr)
30
  , mCodecID(aCodecID)
31
  , mTaskQueue(aTaskQueue)
32
  , mLastInputDts(media::TimeUnit::FromMicroseconds(INT64_MIN))
33
0
{
34
0
  MOZ_ASSERT(aLib);
35
0
  MOZ_COUNT_CTOR(FFmpegDataDecoder);
36
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, CodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::FFmpegDataDecoder(mozilla::FFmpegLibWrapper*, mozilla::TaskQueue*, AVCodecID)
37
38
FFmpegDataDecoder<LIBAV_VER>::~FFmpegDataDecoder()
39
0
{
40
0
  MOZ_COUNT_DTOR(FFmpegDataDecoder);
41
0
  if (mCodecParser) {
42
0
    mLib->av_parser_close(mCodecParser);
43
0
    mCodecParser = nullptr;
44
0
  }
45
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::~FFmpegDataDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::~FFmpegDataDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::~FFmpegDataDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::~FFmpegDataDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::~FFmpegDataDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::~FFmpegDataDecoder()
46
47
MediaResult
48
FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
49
0
{
50
0
  FFMPEG_LOG("Initialising FFmpeg decoder.");
51
0
52
0
  AVCodec* codec = FindAVCodec(mLib, mCodecID);
53
0
  if (!codec) {
54
0
    return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
55
0
                       RESULT_DETAIL("Couldn't find ffmpeg decoder"));
56
0
  }
57
0
58
0
  StaticMutexAutoLock mon(sMonitor);
59
0
60
0
  if (!(mCodecContext = mLib->avcodec_alloc_context3(codec))) {
61
0
    return MediaResult(NS_ERROR_OUT_OF_MEMORY,
62
0
                       RESULT_DETAIL("Couldn't init ffmpeg context"));
63
0
  }
64
0
65
0
  if (NeedParser()) {
66
0
    MOZ_ASSERT(mCodecParser == nullptr);
67
0
    mCodecParser = mLib->av_parser_init(mCodecID);
68
0
    if (mCodecParser) {
69
0
      mCodecParser->flags |= ParserFlags();
70
0
    }
71
0
  }
72
0
  mCodecContext->opaque = this;
73
0
74
0
  InitCodecContext();
75
0
76
0
  if (mExtraData) {
77
0
    mCodecContext->extradata_size = mExtraData->Length();
78
0
    // FFmpeg may use SIMD instructions to access the data which reads the
79
0
    // data in 32 bytes block. Must ensure we have enough data to read.
80
0
    uint32_t padding_size =
81
#if LIBAVCODEC_VERSION_MAJOR >= 58
82
0
      AV_INPUT_BUFFER_PADDING_SIZE;
83
#else
84
0
      FF_INPUT_BUFFER_PADDING_SIZE;
85
#endif
86
    mCodecContext->extradata = static_cast<uint8_t*>(
87
0
      mLib->av_malloc(mExtraData->Length() + padding_size));
88
0
    if (!mCodecContext->extradata) {
89
0
      return MediaResult(NS_ERROR_OUT_OF_MEMORY,
90
0
                        RESULT_DETAIL("Couldn't init ffmpeg extradata"));
91
0
    }
92
0
    memcpy(mCodecContext->extradata,
93
0
           mExtraData->Elements(),
94
0
           mExtraData->Length());
95
0
  } else {
96
0
    mCodecContext->extradata_size = 0;
97
0
  }
98
0
99
#if LIBAVCODEC_VERSION_MAJOR < 57
100
0
  if (codec->capabilities & CODEC_CAP_DR1) {
101
0
    mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
102
0
  }
103
#endif
104
105
0
  if (mLib->avcodec_open2(mCodecContext, codec, nullptr) < 0) {
106
0
    mLib->avcodec_close(mCodecContext);
107
0
    mLib->av_freep(&mCodecContext);
108
0
    return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
109
0
                       RESULT_DETAIL("Couldn't initialise ffmpeg decoder"));
110
0
  }
111
0
112
0
  FFMPEG_LOG("FFmpeg init successful.");
113
0
  return NS_OK;
114
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::InitDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::InitDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::InitDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::InitDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::InitDecoder()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::InitDecoder()
115
116
RefPtr<ShutdownPromise>
117
FFmpegDataDecoder<LIBAV_VER>::Shutdown()
118
0
{
119
0
  if (mTaskQueue) {
120
0
    RefPtr<FFmpegDataDecoder<LIBAV_VER>> self = this;
121
0
    return InvokeAsync(mTaskQueue, __func__, [self]() {
122
0
      self->ProcessShutdown();
123
0
      return ShutdownPromise::CreateAndResolve(true, __func__);
124
0
    });
Unexecuted instantiation: Unified_cpp_ffmpeg_ffvpx0.cpp:mozilla::FFmpegDataDecoder<46465650>::Shutdown()::$_0::operator()() const
Unexecuted instantiation: Unified_cpp_ffmpeg_libav530.cpp:mozilla::FFmpegDataDecoder<53>::Shutdown()::$_0::operator()() const
Unexecuted instantiation: Unified_cpp_ffmpeg_libav540.cpp:mozilla::FFmpegDataDecoder<54>::Shutdown()::$_0::operator()() const
Unexecuted instantiation: Unified_cpp_ffmpeg_libav550.cpp:mozilla::FFmpegDataDecoder<55>::Shutdown()::$_0::operator()() const
Unexecuted instantiation: Unified_cpp_ffmpeg_ffmpeg570.cpp:mozilla::FFmpegDataDecoder<57>::Shutdown()::$_0::operator()() const
Unexecuted instantiation: Unified_cpp_ffmpeg_ffmpeg580.cpp:mozilla::FFmpegDataDecoder<58>::Shutdown()::$_0::operator()() const
125
0
  }
126
0
  ProcessShutdown();
127
0
  return ShutdownPromise::CreateAndResolve(true, __func__);
128
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::Shutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::Shutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::Shutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::Shutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::Shutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::Shutdown()
129
130
RefPtr<MediaDataDecoder::DecodePromise>
131
FFmpegDataDecoder<LIBAV_VER>::Decode(MediaRawData* aSample)
132
0
{
133
0
  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
134
0
                                    &FFmpegDataDecoder::ProcessDecode, aSample);
135
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::Decode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::Decode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::Decode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::Decode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::Decode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::Decode(mozilla::MediaRawData*)
136
137
RefPtr<MediaDataDecoder::DecodePromise>
138
FFmpegDataDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
139
0
{
140
0
  bool gotFrame = false;
141
0
  DecodedData results;
142
0
  MediaResult rv = DoDecode(aSample, &gotFrame, results);
143
0
  if (NS_FAILED(rv)) {
144
0
    return DecodePromise::CreateAndReject(rv, __func__);
145
0
  }
146
0
  return DecodePromise::CreateAndResolve(std::move(results), __func__);
147
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::ProcessDecode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::ProcessDecode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::ProcessDecode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::ProcessDecode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::ProcessDecode(mozilla::MediaRawData*)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::ProcessDecode(mozilla::MediaRawData*)
148
149
MediaResult
150
FFmpegDataDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, bool* aGotFrame,
151
                                       MediaDataDecoder::DecodedData& aResults)
152
0
{
153
0
  uint8_t* inputData = const_cast<uint8_t*>(aSample->Data());
154
0
  size_t inputSize = aSample->Size();
155
0
156
0
  mLastInputDts = aSample->mTimecode;
157
0
158
0
  if (inputData && mCodecParser) { // inputData is null when draining.
159
0
    if (aGotFrame) {
160
0
      *aGotFrame = false;
161
0
    }
162
0
    while (inputSize) {
163
0
      uint8_t* data = inputData;
164
0
      int size = inputSize;
165
0
      int len = mLib->av_parser_parse2(
166
0
        mCodecParser, mCodecContext, &data, &size, inputData, inputSize,
167
0
        aSample->mTime.ToMicroseconds(), aSample->mTimecode.ToMicroseconds(),
168
0
        aSample->mOffset);
169
0
      if (size_t(len) > inputSize) {
170
0
        return NS_ERROR_DOM_MEDIA_DECODE_ERR;
171
0
      }
172
0
      if (size) {
173
0
        bool gotFrame = false;
174
0
        MediaResult rv = DoDecode(aSample, data, size, &gotFrame, aResults);
175
0
        if (NS_FAILED(rv)) {
176
0
          return rv;
177
0
        }
178
0
        if (gotFrame && aGotFrame) {
179
0
          *aGotFrame = true;
180
0
        }
181
0
      }
182
0
      inputData += len;
183
0
      inputSize -= len;
184
0
    }
185
0
    return NS_OK;
186
0
  }
187
0
  return DoDecode(aSample, inputData, inputSize, aGotFrame, aResults);
188
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::DoDecode(mozilla::MediaRawData*, bool*, nsTArray<RefPtr<mozilla::MediaData> >&)
189
190
RefPtr<MediaDataDecoder::FlushPromise>
191
FFmpegDataDecoder<LIBAV_VER>::Flush()
192
0
{
193
0
  return InvokeAsync(mTaskQueue, this, __func__,
194
0
                     &FFmpegDataDecoder<LIBAV_VER>::ProcessFlush);
195
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::Flush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::Flush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::Flush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::Flush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::Flush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::Flush()
196
197
RefPtr<MediaDataDecoder::DecodePromise>
198
FFmpegDataDecoder<LIBAV_VER>::Drain()
199
0
{
200
0
  return InvokeAsync(mTaskQueue, this, __func__,
201
0
                     &FFmpegDataDecoder<LIBAV_VER>::ProcessDrain);
202
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::Drain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::Drain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::Drain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::Drain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::Drain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::Drain()
203
204
RefPtr<MediaDataDecoder::DecodePromise>
205
FFmpegDataDecoder<LIBAV_VER>::ProcessDrain()
206
0
{
207
0
  RefPtr<MediaRawData> empty(new MediaRawData());
208
0
  empty->mTimecode = mLastInputDts;
209
0
  bool gotFrame = false;
210
0
  DecodedData results;
211
0
  while (NS_SUCCEEDED(DoDecode(empty, &gotFrame, results)) &&
212
0
         gotFrame) {
213
0
  }
214
0
  return DecodePromise::CreateAndResolve(std::move(results), __func__);
215
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::ProcessDrain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::ProcessDrain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::ProcessDrain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::ProcessDrain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::ProcessDrain()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::ProcessDrain()
216
217
RefPtr<MediaDataDecoder::FlushPromise>
218
FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
219
0
{
220
0
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
221
0
  if (mCodecContext) {
222
0
    mLib->avcodec_flush_buffers(mCodecContext);
223
0
  }
224
0
  if (mCodecParser) {
225
0
    mLib->av_parser_close(mCodecParser);
226
0
    mCodecParser = mLib->av_parser_init(mCodecID);
227
0
  }
228
0
  return FlushPromise::CreateAndResolve(true, __func__);
229
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::ProcessFlush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::ProcessFlush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::ProcessFlush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::ProcessFlush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::ProcessFlush()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::ProcessFlush()
230
231
void
232
FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
233
0
{
234
0
  StaticMutexAutoLock mon(sMonitor);
235
0
236
0
  if (mCodecContext) {
237
0
    if (mCodecContext->extradata) {
238
0
      mLib->av_freep(&mCodecContext->extradata);
239
0
    }
240
0
    mLib->avcodec_close(mCodecContext);
241
0
    mLib->av_freep(&mCodecContext);
242
#if LIBAVCODEC_VERSION_MAJOR >= 55
243
    mLib->av_frame_free(&mFrame);
244
#elif LIBAVCODEC_VERSION_MAJOR == 54
245
    mLib->avcodec_free_frame(&mFrame);
246
#else
247
    mLib->av_freep(&mFrame);
248
#endif
249
  }
250
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::ProcessShutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::ProcessShutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::ProcessShutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::ProcessShutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::ProcessShutdown()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::ProcessShutdown()
251
252
AVFrame*
253
FFmpegDataDecoder<LIBAV_VER>::PrepareFrame()
254
0
{
255
0
  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
256
#if LIBAVCODEC_VERSION_MAJOR >= 55
257
0
  if (mFrame) {
258
0
    mLib->av_frame_unref(mFrame);
259
0
  } else {
260
0
    mFrame = mLib->av_frame_alloc();
261
0
  }
262
#elif LIBAVCODEC_VERSION_MAJOR == 54
263
0
  if (mFrame) {
264
0
    mLib->avcodec_get_frame_defaults(mFrame);
265
0
  } else {
266
0
    mFrame = mLib->avcodec_alloc_frame();
267
0
  }
268
#else
269
  mLib->av_freep(&mFrame);
270
  mFrame = mLib->avcodec_alloc_frame();
271
#endif
272
  return mFrame;
273
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::PrepareFrame()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::PrepareFrame()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::PrepareFrame()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::PrepareFrame()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::PrepareFrame()
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::PrepareFrame()
274
275
/* static */ AVCodec*
276
FFmpegDataDecoder<LIBAV_VER>::FindAVCodec(FFmpegLibWrapper* aLib,
277
                                          AVCodecID aCodec)
278
0
{
279
0
  return aLib->avcodec_find_decoder(aCodec);
280
0
}
Unexecuted instantiation: mozilla::FFmpegDataDecoder<46465650>::FindAVCodec(mozilla::FFmpegLibWrapper*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<53>::FindAVCodec(mozilla::FFmpegLibWrapper*, CodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<54>::FindAVCodec(mozilla::FFmpegLibWrapper*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<55>::FindAVCodec(mozilla::FFmpegLibWrapper*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<57>::FindAVCodec(mozilla::FFmpegLibWrapper*, AVCodecID)
Unexecuted instantiation: mozilla::FFmpegDataDecoder<58>::FindAVCodec(mozilla::FFmpegLibWrapper*, AVCodecID)
281
282
} // namespace mozilla