Bug 1858921 - Part 6: Remove unused default template arguments r=sfink
[gecko.git] / dom / media / platforms / PlatformDecoderModule.h
blob0430b5745f7546421c3cb4feabc89c575f15ca59
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/. */
7 #if !defined(PlatformDecoderModule_h_)
8 # define PlatformDecoderModule_h_
10 # include <queue>
12 # include "DecoderDoctorLogger.h"
13 # include "GMPCrashHelper.h"
14 # include "MediaCodecsSupport.h"
15 # include "MediaEventSource.h"
16 # include "MediaInfo.h"
17 # include "MediaResult.h"
18 # include "mozilla/EnumSet.h"
19 # include "mozilla/EnumTypeTraits.h"
20 # include "mozilla/MozPromise.h"
21 # include "mozilla/RefPtr.h"
22 # include "mozilla/TaskQueue.h"
23 # include "mozilla/layers/KnowsCompositor.h"
24 # include "mozilla/layers/LayersTypes.h"
25 # include "mozilla/ipc/UtilityAudioDecoder.h"
26 # include "nsTArray.h"
27 # include "PerformanceRecorder.h"
29 namespace mozilla {
30 class TrackInfo;
31 class AudioInfo;
32 class VideoInfo;
33 class MediaRawData;
34 class DecoderDoctorDiagnostics;
36 namespace layers {
37 class ImageContainer;
38 } // namespace layers
40 class MediaDataDecoder;
41 class RemoteDecoderModule;
42 class CDMProxy;
44 static LazyLogModule sPDMLog("PlatformDecoderModule");
46 namespace media {
48 enum class Option {
49 Default,
50 LowLatency,
51 HardwareDecoderNotAllowed,
52 FullH264Parsing,
53 ErrorIfNoInitializationData, // By default frames delivered before
54 // initialization data are dropped. Pass this
55 // option to raise an error if frames are
56 // delivered before initialization data.
57 DefaultPlaybackDeviceMono, // Currently only used by Opus on RDD to avoid
58 // initialization of audio backends on RDD
60 SENTINEL // one past the last valid value
62 using OptionSet = EnumSet<Option>;
64 struct UseNullDecoder {
65 UseNullDecoder() = default;
66 explicit UseNullDecoder(bool aUseNullDecoder) : mUse(aUseNullDecoder) {}
67 bool mUse = false;
70 // Do not wrap H264 decoder in a H264Converter.
71 struct NoWrapper {
72 NoWrapper() = default;
73 explicit NoWrapper(bool aDontUseWrapper) : mDontUseWrapper(aDontUseWrapper) {}
74 bool mDontUseWrapper = false;
77 struct VideoFrameRate {
78 VideoFrameRate() = default;
79 explicit VideoFrameRate(float aFramerate) : mValue(aFramerate) {}
80 float mValue = 0.0f;
83 } // namespace media
85 struct CreateDecoderParams;
86 struct CreateDecoderParamsForAsync {
87 using Option = media::Option;
88 using OptionSet = media::OptionSet;
89 explicit CreateDecoderParamsForAsync(const CreateDecoderParams& aParams);
90 CreateDecoderParamsForAsync(CreateDecoderParamsForAsync&& aParams);
92 const VideoInfo& VideoConfig() const {
93 MOZ_ASSERT(mConfig->IsVideo());
94 return *mConfig->GetAsVideoInfo();
97 const AudioInfo& AudioConfig() const {
98 MOZ_ASSERT(mConfig->IsAudio());
99 return *mConfig->GetAsAudioInfo();
102 UniquePtr<TrackInfo> mConfig;
103 const RefPtr<layers::ImageContainer> mImageContainer;
104 const RefPtr<layers::KnowsCompositor> mKnowsCompositor;
105 const RefPtr<GMPCrashHelper> mCrashHelper;
106 const media::UseNullDecoder mUseNullDecoder;
107 const media::NoWrapper mNoWrapper;
108 const TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
109 std::function<MediaEventProducer<TrackInfo::TrackType>*()>
110 mOnWaitingForKeyEvent;
111 const OptionSet mOptions = OptionSet(Option::Default);
112 const media::VideoFrameRate mRate;
113 const Maybe<uint64_t> mMediaEngineId;
114 const Maybe<TrackingId> mTrackingId;
117 struct MOZ_STACK_CLASS CreateDecoderParams final {
118 using Option = media::Option;
119 using OptionSet = media::OptionSet;
120 using UseNullDecoder = media::UseNullDecoder;
121 using NoWrapper = media::NoWrapper;
122 using VideoFrameRate = media::VideoFrameRate;
124 explicit CreateDecoderParams(const TrackInfo& aConfig) : mConfig(aConfig) {}
125 CreateDecoderParams(const CreateDecoderParams& aParams) = default;
127 MOZ_IMPLICIT CreateDecoderParams(const CreateDecoderParamsForAsync& aParams)
128 : mConfig(*aParams.mConfig.get()),
129 mImageContainer(aParams.mImageContainer),
130 mKnowsCompositor(aParams.mKnowsCompositor),
131 mCrashHelper(aParams.mCrashHelper),
132 mUseNullDecoder(aParams.mUseNullDecoder),
133 mNoWrapper(aParams.mNoWrapper),
134 mType(aParams.mType),
135 mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent),
136 mOptions(aParams.mOptions),
137 mRate(aParams.mRate),
138 mMediaEngineId(aParams.mMediaEngineId),
139 mTrackingId(aParams.mTrackingId) {}
141 template <typename T1, typename... Ts>
142 CreateDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args)
143 : mConfig(aConfig) {
144 Set(std::forward<T1>(a1), std::forward<Ts>(args)...);
147 template <typename T1, typename... Ts>
148 CreateDecoderParams(const CreateDecoderParams& aParams, T1&& a1, Ts&&... args)
149 : CreateDecoderParams(aParams) {
150 Set(std::forward<T1>(a1), std::forward<Ts>(args)...);
153 const VideoInfo& VideoConfig() const {
154 MOZ_ASSERT(mConfig.IsVideo());
155 return *mConfig.GetAsVideoInfo();
158 const AudioInfo& AudioConfig() const {
159 MOZ_ASSERT(mConfig.IsAudio());
160 return *mConfig.GetAsAudioInfo();
163 layers::LayersBackend GetLayersBackend() const {
164 if (mKnowsCompositor) {
165 return mKnowsCompositor->GetCompositorBackendType();
167 return layers::LayersBackend::LAYERS_NONE;
170 // CreateDecoderParams is a MOZ_STACK_CLASS, it is only used to
171 // simplify the passing of arguments to Create*Decoder.
172 // It is safe to use references and raw pointers.
173 const TrackInfo& mConfig;
174 layers::ImageContainer* mImageContainer = nullptr;
175 MediaResult* mError = nullptr;
176 layers::KnowsCompositor* mKnowsCompositor = nullptr;
177 GMPCrashHelper* mCrashHelper = nullptr;
178 media::UseNullDecoder mUseNullDecoder;
179 media::NoWrapper mNoWrapper;
180 TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
181 std::function<MediaEventProducer<TrackInfo::TrackType>*()>
182 mOnWaitingForKeyEvent;
183 OptionSet mOptions = OptionSet(Option::Default);
184 media::VideoFrameRate mRate;
185 // Used on Windows when the MF media engine playback is enabled.
186 Maybe<uint64_t> mMediaEngineId;
187 Maybe<TrackingId> mTrackingId;
189 private:
190 void Set(layers::ImageContainer* aImageContainer) {
191 mImageContainer = aImageContainer;
193 void Set(MediaResult* aError) { mError = aError; }
194 void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
195 void Set(UseNullDecoder aUseNullDecoder) {
196 mUseNullDecoder = aUseNullDecoder;
198 void Set(NoWrapper aNoWrapper) { mNoWrapper = aNoWrapper; }
199 void Set(OptionSet aOptions) { mOptions = aOptions; }
200 void Set(VideoFrameRate aRate) { mRate = aRate; }
201 void Set(layers::KnowsCompositor* aKnowsCompositor) {
202 if (aKnowsCompositor) {
203 mKnowsCompositor = aKnowsCompositor;
204 MOZ_ASSERT(aKnowsCompositor->IsThreadSafe());
207 void Set(TrackInfo::TrackType aType) { mType = aType; }
208 void Set(std::function<MediaEventProducer<TrackInfo::TrackType>*()>&&
209 aOnWaitingForKey) {
210 mOnWaitingForKeyEvent = std::move(aOnWaitingForKey);
212 void Set(const std::function<MediaEventProducer<TrackInfo::TrackType>*()>&
213 aOnWaitingForKey) {
214 mOnWaitingForKeyEvent = aOnWaitingForKey;
216 void Set(const Maybe<uint64_t>& aMediaEngineId) {
217 mMediaEngineId = aMediaEngineId;
219 void Set(const Maybe<TrackingId>& aTrackingId) { mTrackingId = aTrackingId; }
220 void Set(const CreateDecoderParams& aParams) {
221 // Set all but mTrackInfo;
222 mImageContainer = aParams.mImageContainer;
223 mError = aParams.mError;
224 mKnowsCompositor = aParams.mKnowsCompositor;
225 mCrashHelper = aParams.mCrashHelper;
226 mUseNullDecoder = aParams.mUseNullDecoder;
227 mNoWrapper = aParams.mNoWrapper;
228 mType = aParams.mType;
229 mOnWaitingForKeyEvent = aParams.mOnWaitingForKeyEvent;
230 mOptions = aParams.mOptions;
231 mRate = aParams.mRate;
232 mMediaEngineId = aParams.mMediaEngineId;
233 mTrackingId = aParams.mTrackingId;
235 template <typename T1, typename T2, typename... Ts>
236 void Set(T1&& a1, T2&& a2, Ts&&... args) {
237 Set(std::forward<T1>(a1));
238 Set(std::forward<T2>(a2), std::forward<Ts>(args)...);
242 struct MOZ_STACK_CLASS SupportDecoderParams final {
243 using Option = media::Option;
244 using OptionSet = media::OptionSet;
245 using UseNullDecoder = media::UseNullDecoder;
246 using NoWrapper = media::NoWrapper;
247 using VideoFrameRate = media::VideoFrameRate;
249 explicit SupportDecoderParams(const TrackInfo& aConfig) : mConfig(aConfig) {}
251 explicit SupportDecoderParams(const CreateDecoderParams& aParams)
252 : mConfig(aParams.mConfig),
253 mError(aParams.mError),
254 mKnowsCompositor(aParams.mKnowsCompositor),
255 mUseNullDecoder(aParams.mUseNullDecoder),
256 mNoWrapper(aParams.mNoWrapper),
257 mOptions(aParams.mOptions),
258 mRate(aParams.mRate),
259 mMediaEngineId(aParams.mMediaEngineId) {}
261 template <typename T1, typename... Ts>
262 SupportDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args)
263 : mConfig(aConfig) {
264 Set(std::forward<T1>(a1), std::forward<Ts>(args)...);
267 const nsCString& MimeType() const { return mConfig.mMimeType; }
269 const TrackInfo& mConfig;
270 DecoderDoctorDiagnostics* mDiagnostics = nullptr;
271 MediaResult* mError = nullptr;
272 RefPtr<layers::KnowsCompositor> mKnowsCompositor;
273 UseNullDecoder mUseNullDecoder;
274 NoWrapper mNoWrapper;
275 OptionSet mOptions = OptionSet(Option::Default);
276 VideoFrameRate mRate;
277 Maybe<uint64_t> mMediaEngineId;
279 private:
280 void Set(DecoderDoctorDiagnostics* aDiagnostics) {
281 mDiagnostics = aDiagnostics;
283 void Set(MediaResult* aError) { mError = aError; }
284 void Set(media::UseNullDecoder aUseNullDecoder) {
285 mUseNullDecoder = aUseNullDecoder;
287 void Set(media::NoWrapper aNoWrapper) { mNoWrapper = aNoWrapper; }
288 void Set(media::OptionSet aOptions) { mOptions = aOptions; }
289 void Set(media::VideoFrameRate aRate) { mRate = aRate; }
290 void Set(layers::KnowsCompositor* aKnowsCompositor) {
291 if (aKnowsCompositor) {
292 mKnowsCompositor = aKnowsCompositor;
293 MOZ_ASSERT(aKnowsCompositor->IsThreadSafe());
296 void Set(const Maybe<uint64_t>& aMediaEngineId) {
297 mMediaEngineId = aMediaEngineId;
300 template <typename T1, typename T2, typename... Ts>
301 void Set(T1&& a1, T2&& a2, Ts&&... args) {
302 Set(std::forward<T1>(a1));
303 Set(std::forward<T2>(a2), std::forward<Ts>(args)...);
307 // Used for IPDL serialization.
308 // The 'value' have to be the biggest enum from CreateDecoderParams::Option.
309 template <>
310 struct MaxEnumValue<::mozilla::CreateDecoderParams::Option> {
311 static constexpr unsigned int value =
312 static_cast<unsigned int>(CreateDecoderParams::Option::SENTINEL);
315 // The PlatformDecoderModule interface is used by the MediaFormatReader to
316 // abstract access to decoders provided by various
317 // platforms.
318 // Each platform (Windows, MacOSX, Linux, B2G etc) must implement a
319 // PlatformDecoderModule to provide access to its decoders in order to get
320 // decompressed H.264/AAC from the MediaFormatReader.
322 // Decoding is asynchronous, and should be performed on the task queue
323 // provided if the underlying platform isn't already exposing an async API.
325 // A cross-platform decoder module that discards input and produces "blank"
326 // output samples exists for testing, and is created when the pref
327 // "media.use-blank-decoder" is true.
329 class PlatformDecoderModule {
330 public:
331 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule)
333 // Perform any per-instance initialization.
334 // This is called on the decode task queue.
335 virtual nsresult Startup() { return NS_OK; }
337 // Indicates if the PlatformDecoderModule supports decoding of aMimeType,
338 // and whether or not hardware-accelerated decoding is supported.
339 // The answer to both SupportsMimeType and Supports doesn't guarantee that
340 // creation of a decoder will actually succeed.
341 virtual media::DecodeSupportSet SupportsMimeType(
342 const nsACString& aMimeType,
343 DecoderDoctorDiagnostics* aDiagnostics) const = 0;
345 virtual media::DecodeSupportSet Supports(
346 const SupportDecoderParams& aParams,
347 DecoderDoctorDiagnostics* aDiagnostics) const {
348 const TrackInfo& trackInfo = aParams.mConfig;
349 const media::DecodeSupportSet support =
350 SupportsMimeType(trackInfo.mMimeType, aDiagnostics);
352 // Bail early if we don't support this format at all
353 if (support.isEmpty()) {
354 return support;
357 const auto* videoInfo = trackInfo.GetAsVideoInfo();
359 if (!videoInfo) {
360 // No video stream = software decode only
361 return media::DecodeSupport::SoftwareDecode;
364 // Check whether we support the desired color depth
365 if (!SupportsColorDepth(videoInfo->mColorDepth, aDiagnostics)) {
366 return media::DecodeSupportSet{};
368 return support;
371 using CreateDecoderPromise = MozPromise<RefPtr<MediaDataDecoder>, MediaResult,
372 /* IsExclusive = */ true>;
374 protected:
375 PlatformDecoderModule() = default;
376 virtual ~PlatformDecoderModule() = default;
378 friend class MediaChangeMonitor;
379 friend class PDMFactory;
380 friend class EMEDecoderModule;
381 friend class RemoteDecoderModule;
383 // Indicates if the PlatformDecoderModule supports decoding of aColorDepth.
384 // Should override this method when the platform can support color depth != 8.
385 virtual bool SupportsColorDepth(
386 gfx::ColorDepth aColorDepth,
387 DecoderDoctorDiagnostics* aDiagnostics) const {
388 return aColorDepth == gfx::ColorDepth::COLOR_8;
391 // Creates a Video decoder. The layers backend is passed in so that
392 // decoders can determine whether hardware accelerated decoding can be used.
393 // On Windows the task queue's threads in have MSCOM initialized with
394 // COINIT_MULTITHREADED.
395 // Returns nullptr if the decoder can't be created.
396 // It is not safe to store a reference to aParams or aParams.mConfig as the
397 // object isn't guaranteed to live after the call.
398 // CreateVideoDecoder may need to make additional checks if the
399 // CreateDecoderParams argument is actually supported and return nullptr if
400 // not to allow for fallback PDMs to be tried.
401 virtual already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
402 const CreateDecoderParams& aParams) = 0;
404 // Creates an Audio decoder with the specified properties.
405 // Returns nullptr if the decoder can't be created.
406 // On Windows the task queue's threads in have MSCOM initialized with
407 // COINIT_MULTITHREADED.
408 // It is not safe to store a reference to aParams or aParams.mConfig as the
409 // object isn't guaranteed to live after the call.
410 // CreateAudioDecoder may need to make additional checks if the
411 // CreateDecoderParams argument is actually supported and return nullptr if
412 // not to allow for fallback PDMs to be tried.
413 virtual already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
414 const CreateDecoderParams& aParams) = 0;
416 // Asychronously create a decoder.
417 virtual RefPtr<CreateDecoderPromise> AsyncCreateDecoder(
418 const CreateDecoderParams& aParams);
421 DDLoggedTypeDeclName(MediaDataDecoder);
423 // MediaDataDecoder is the interface exposed by decoders created by the
424 // PlatformDecoderModule's Create*Decoder() functions. The type of
425 // media data that the decoder accepts as valid input and produces as
426 // output is determined when the MediaDataDecoder is created.
428 // Unless otherwise noted, all functions are only called on the decode task
429 // queue. An exception is the MediaDataDecoder in
430 // MediaFormatReader::IsVideoAccelerated() for which all calls (Init(),
431 // IsHardwareAccelerated(), and Shutdown()) are from the main thread.
433 // Don't block inside these functions, unless it's explicitly noted that you
434 // should (like in Flush()).
436 // Decoding is done asynchronously.
437 class MediaDataDecoder : public DecoderDoctorLifeLogger<MediaDataDecoder> {
438 protected:
439 virtual ~MediaDataDecoder() = default;
441 public:
442 typedef TrackInfo::TrackType TrackType;
443 typedef nsTArray<RefPtr<MediaData>> DecodedData;
444 typedef MozPromise<TrackType, MediaResult, /* IsExclusive = */ true>
445 InitPromise;
446 typedef MozPromise<DecodedData, MediaResult, /* IsExclusive = */ true>
447 DecodePromise;
448 typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> FlushPromise;
450 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
452 // Initialize the decoder. The decoder should be ready to decode once
453 // the promise resolves. The decoder should do any initialization here, rather
454 // than in its constructor or PlatformDecoderModule::Create*Decoder(),
455 // so that if the MediaFormatReader needs to shutdown during initialization,
456 // it can call Shutdown() to cancel this operation. Any initialization
457 // that requires blocking the calling thread in this function *must*
458 // be done here so that it can be canceled by calling Shutdown()!
459 // Methods Decode, DecodeBatch, Drain, Flush, Shutdown are guaranteed to be
460 // called on the thread where Init() first ran.
461 virtual RefPtr<InitPromise> Init() = 0;
463 // Inserts a sample into the decoder's decode pipeline. The DecodePromise will
464 // be resolved with the decoded MediaData. In case the decoder needs more
465 // input, the DecodePromise may be resolved with an empty array of samples to
466 // indicate that Decode should be called again before a MediaData is returned.
467 virtual RefPtr<DecodePromise> Decode(MediaRawData* aSample) = 0;
469 // This could probably be implemented as a wrapper that takes a
470 // generic MediaDataDecoder and manages batching as needed. For now
471 // only AudioTrimmer with RemoteMediaDataDecoder supports batch
472 // decoding.
473 // Inserts an array of samples into the decoder's decode pipeline. The
474 // DecodePromise will be resolved with the decoded MediaData. In case
475 // the decoder needs more input, the DecodePromise may be resolved
476 // with an empty array of samples to indicate that Decode should be
477 // called again before a MediaData is returned.
478 virtual bool CanDecodeBatch() const { return false; }
479 virtual RefPtr<DecodePromise> DecodeBatch(
480 nsTArray<RefPtr<MediaRawData>>&& aSamples) {
481 MOZ_CRASH("DecodeBatch not implemented yet");
482 return MediaDataDecoder::DecodePromise::CreateAndReject(
483 NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__);
486 // Causes all complete samples in the pipeline that can be decoded to be
487 // output. If the decoder can't produce samples from the current output,
488 // it drops the input samples. The decoder may be holding onto samples
489 // that are required to decode samples that it expects to get in future.
490 // This is called when the demuxer reaches end of stream.
491 // This function is asynchronous.
492 // The MediaDataDecoder shall resolve the pending DecodePromise with drained
493 // samples. Drain will be called multiple times until the resolved
494 // DecodePromise is empty which indicates that there are no more samples to
495 // drain.
496 virtual RefPtr<DecodePromise> Drain() = 0;
498 // Causes all samples in the decoding pipeline to be discarded. When this
499 // promise resolves, the decoder must be ready to accept new data for
500 // decoding. This function is called when the demuxer seeks, before decoding
501 // resumes after the seek. The current DecodePromise if any shall be rejected
502 // with NS_ERROR_DOM_MEDIA_CANCELED
503 virtual RefPtr<FlushPromise> Flush() = 0;
505 // Cancels all init/decode/drain operations, and shuts down the decoder. The
506 // platform decoder should clean up any resources it's using and release
507 // memory etc. The shutdown promise will be resolved once the decoder has
508 // completed shutdown. The reader calls Flush() before calling Shutdown(). The
509 // reader will delete the decoder once the promise is resolved.
510 // The ShutdownPromise must only ever be resolved.
511 // Shutdown() may not be called if init hasn't been called first. It is
512 // possible under some circumstances for the decoder to be deleted without
513 // Init having been called first.
514 virtual RefPtr<ShutdownPromise> Shutdown() = 0;
516 // Called from the state machine task queue or main thread. Decoder needs to
517 // decide whether or not hardware acceleration is supported after creating.
518 // It doesn't need to call Init() before calling this function.
519 virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const {
520 return false;
523 // Return the name of the MediaDataDecoder, only used for decoding.
524 // May be accessed in a non thread-safe fashion.
525 virtual nsCString GetDescriptionName() const = 0;
527 virtual nsCString GetProcessName() const {
528 nsCString rv = nsCString(XRE_GetProcessTypeString());
529 if (XRE_IsUtilityProcess()) {
530 rv += "+"_ns + mozilla::ipc::GetChildAudioActorName();
532 return rv;
534 virtual nsCString GetCodecName() const = 0;
536 // Set a hint of seek target time to decoder. Decoder will drop any decoded
537 // data which pts is smaller than this value. This threshold needs to be clear
538 // after reset decoder. To clear it explicitly, call this method with
539 // TimeUnit::Invalid().
540 // Decoder may not honor this value. However, it'd be better that
541 // video decoder implements this API to improve seek performance.
542 // Note: it should be called before Input() or after Flush().
543 virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
545 // When playing adaptive playback, recreating an Android video decoder will
546 // cause the transition not smooth during resolution change.
547 // Reuse the decoder if the decoder support recycling.
548 // Currently, only Android video decoder will return true.
549 virtual bool SupportDecoderRecycling() const { return false; }
551 enum class ConversionRequired {
552 kNeedNone = 0,
553 kNeedAVCC = 1,
554 kNeedAnnexB = 2,
557 // Indicates that the decoder requires a specific format.
558 // The demuxed data will be converted accordingly before feeding it to
559 // Decode().
560 virtual ConversionRequired NeedsConversion() const {
561 return ConversionRequired::kNeedNone;
565 } // namespace mozilla
567 #endif