Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "FFmpegLibWrapper.h"
6
#include "FFmpegLog.h"
7
#include "mozilla/PodOperations.h"
8
#ifdef MOZ_FFMPEG
9
#include "mozilla/StaticPrefs.h"
10
#endif
11
#include "mozilla/Types.h"
12
#include "PlatformDecoderModule.h"
13
#include "prlink.h"
14
15
0
#define AV_LOG_DEBUG    48
16
0
#define AV_LOG_INFO     32
17
18
namespace mozilla
19
{
20
21
FFmpegLibWrapper::LinkResult
22
FFmpegLibWrapper::Link()
23
0
{
24
0
  if (!mAVCodecLib || !mAVUtilLib) {
25
0
    Unlink();
26
0
    return LinkResult::NoProvidedLib;
27
0
  }
28
0
29
0
  avcodec_version =
30
0
    (decltype(avcodec_version))PR_FindSymbol(mAVCodecLib, "avcodec_version");
31
0
  if (!avcodec_version) {
32
0
    Unlink();
33
0
    return LinkResult::NoAVCodecVersion;
34
0
  }
35
0
  uint32_t version = avcodec_version();
36
0
  uint32_t macro = (version >> 16) & 0xFFu;
37
0
  mVersion = static_cast<int>(macro);
38
0
  uint32_t micro = version & 0xFFu;
39
0
  // A micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV).
40
0
  bool isFFMpeg = micro >= 100;
41
0
  if (!isFFMpeg) {
42
0
    if (macro == 57) {
43
0
      // Due to current AVCodecContext binary incompatibility we can only
44
0
      // support FFmpeg 57 at this stage.
45
0
      Unlink();
46
0
      return LinkResult::CannotUseLibAV57;
47
0
    }
48
0
#ifdef MOZ_FFMPEG
49
0
    if (version < (54u << 16 | 35u << 8 | 1u) &&
50
0
        !StaticPrefs::MediaLibavcodecAllowObsolete()) {
51
0
      // Refuse any libavcodec version prior to 54.35.1.
52
0
      // (Unless media.libavcodec.allow-obsolete==true)
53
0
      Unlink();
54
0
      return LinkResult::BlockedOldLibAVVersion;
55
0
    }
56
0
#endif
57
0
  }
58
0
59
0
  enum {
60
0
    AV_FUNC_AVUTIL_MASK = 1 << 8,
61
0
    AV_FUNC_53 = 1 << 0,
62
0
    AV_FUNC_54 = 1 << 1,
63
0
    AV_FUNC_55 = 1 << 2,
64
0
    AV_FUNC_56 = 1 << 3,
65
0
    AV_FUNC_57 = 1 << 4,
66
0
    AV_FUNC_58 = 1 << 5,
67
0
    AV_FUNC_AVUTIL_53 = AV_FUNC_53 | AV_FUNC_AVUTIL_MASK,
68
0
    AV_FUNC_AVUTIL_54 = AV_FUNC_54 | AV_FUNC_AVUTIL_MASK,
69
0
    AV_FUNC_AVUTIL_55 = AV_FUNC_55 | AV_FUNC_AVUTIL_MASK,
70
0
    AV_FUNC_AVUTIL_56 = AV_FUNC_56 | AV_FUNC_AVUTIL_MASK,
71
0
    AV_FUNC_AVUTIL_57 = AV_FUNC_57 | AV_FUNC_AVUTIL_MASK,
72
0
    AV_FUNC_AVUTIL_58 = AV_FUNC_58 | AV_FUNC_AVUTIL_MASK,
73
0
    AV_FUNC_AVCODEC_ALL = AV_FUNC_53 | AV_FUNC_54 | AV_FUNC_55 | AV_FUNC_56 | AV_FUNC_57 | AV_FUNC_58,
74
0
    AV_FUNC_AVUTIL_ALL = AV_FUNC_AVCODEC_ALL | AV_FUNC_AVUTIL_MASK
75
0
  };
76
0
77
0
  switch (macro) {
78
0
    case 53:
79
0
      version = AV_FUNC_53;
80
0
      break;
81
0
    case 54:
82
0
      version = AV_FUNC_54;
83
0
      break;
84
0
    case 55:
85
0
      version = AV_FUNC_55;
86
0
      break;
87
0
    case 56:
88
0
      version = AV_FUNC_56;
89
0
      break;
90
0
    case 57:
91
0
      version = AV_FUNC_57;
92
0
      break;
93
0
    case 58:
94
0
      version = AV_FUNC_58;
95
0
      break;
96
0
    default:
97
0
      FFMPEG_LOG("Unknown avcodec version");
98
0
      Unlink();
99
0
      return isFFMpeg
100
0
             ? ((macro > 57)
101
0
                ? LinkResult::UnknownFutureFFMpegVersion
102
0
                : LinkResult::UnknownOlderFFMpegVersion)
103
0
             // All LibAV versions<54.35.1 are blocked, therefore we must be
104
0
             // dealing with a later one.
105
0
             : LinkResult::UnknownFutureLibAVVersion;
106
0
  }
107
0
108
0
#define AV_FUNC_OPTION(func, ver)                                              \
109
0
  if ((ver) & version) {                                                       \
110
0
    if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? mAVUtilLib : mAVCodecLib, #func))) { \
111
0
      FFMPEG_LOG("Couldn't load function " # func);                            \
112
0
    }                                                                          \
113
0
  } else {                                                                     \
114
0
    func = (decltype(func))nullptr;                                            \
115
0
  }
116
0
117
0
#define AV_FUNC(func, ver)                                                     \
118
0
  AV_FUNC_OPTION(func, ver)                                                    \
119
0
  if ((ver) & version && !func) {                                              \
120
0
    Unlink();                                                                  \
121
0
    return isFFMpeg ? LinkResult::MissingFFMpegFunction                        \
122
0
                    : LinkResult::MissingLibAVFunction;                        \
123
0
  }
124
0
125
0
  AV_FUNC(av_lockmgr_register, AV_FUNC_AVCODEC_ALL)
126
0
  AV_FUNC(avcodec_alloc_context3, AV_FUNC_AVCODEC_ALL)
127
0
  AV_FUNC(avcodec_close, AV_FUNC_AVCODEC_ALL)
128
0
  AV_FUNC(avcodec_decode_audio4, AV_FUNC_AVCODEC_ALL)
129
0
  AV_FUNC(avcodec_decode_video2, AV_FUNC_AVCODEC_ALL)
130
0
  AV_FUNC(avcodec_find_decoder, AV_FUNC_AVCODEC_ALL)
131
0
  AV_FUNC(avcodec_flush_buffers, AV_FUNC_AVCODEC_ALL)
132
0
  AV_FUNC(avcodec_open2, AV_FUNC_AVCODEC_ALL)
133
0
  AV_FUNC(avcodec_register_all, AV_FUNC_AVCODEC_ALL)
134
0
  AV_FUNC(av_init_packet, AV_FUNC_AVCODEC_ALL)
135
0
  AV_FUNC(av_parser_init, AV_FUNC_AVCODEC_ALL)
136
0
  AV_FUNC(av_parser_close, AV_FUNC_AVCODEC_ALL)
137
0
  AV_FUNC(av_parser_parse2, AV_FUNC_AVCODEC_ALL)
138
0
  AV_FUNC(avcodec_alloc_frame, (AV_FUNC_53 | AV_FUNC_54))
139
0
  AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54))
140
0
  AV_FUNC(avcodec_free_frame, AV_FUNC_54)
141
0
  AV_FUNC_OPTION(av_rdft_init, AV_FUNC_AVCODEC_ALL)
142
0
  AV_FUNC_OPTION(av_rdft_calc, AV_FUNC_AVCODEC_ALL)
143
0
  AV_FUNC_OPTION(av_rdft_end, AV_FUNC_AVCODEC_ALL)
144
0
  AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL)
145
0
  AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL)
146
0
  AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL)
147
0
  AV_FUNC(av_frame_alloc, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58))
148
0
  AV_FUNC(av_frame_free, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58))
149
0
  AV_FUNC(av_frame_unref, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58))
150
0
  AV_FUNC_OPTION(av_frame_get_colorspace, AV_FUNC_AVUTIL_ALL)
151
0
#undef AV_FUNC
152
0
#undef AV_FUNC_OPTION
153
0
154
0
  avcodec_register_all();
155
0
  if (MOZ_LOG_TEST(sPDMLog, LogLevel::Debug)) {
156
0
    av_log_set_level(AV_LOG_DEBUG);
157
0
  } else if (MOZ_LOG_TEST(sPDMLog, LogLevel::Info)) {
158
0
    av_log_set_level(AV_LOG_INFO);
159
0
  } else {
160
0
    av_log_set_level(0);
161
0
  }
162
0
  return LinkResult::Success;
163
0
}
164
165
void
166
FFmpegLibWrapper::Unlink()
167
0
{
168
0
  if (av_lockmgr_register) {
169
0
    // Registering a null lockmgr cause the destruction of libav* global mutexes
170
0
    // as the default lockmgr that allocated them will be deregistered.
171
0
    // This prevents ASAN and valgrind to report sizeof(pthread_mutex_t) leaks.
172
0
    av_lockmgr_register(nullptr);
173
0
  }
174
0
  if (mAVUtilLib && mAVUtilLib != mAVCodecLib) {
175
0
    PR_UnloadLibrary(mAVUtilLib);
176
0
  }
177
0
  if (mAVCodecLib) {
178
0
    PR_UnloadLibrary(mAVCodecLib);
179
0
  }
180
0
  PodZero(this);
181
0
}
182
183
} // namespace mozilla