summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/wrappers/MediaChangeMonitor.h
blob: ff4f6921f68e84ed587407d9b968f5215583a1f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_H264Converter_h
#define mozilla_H264Converter_h

#include "PDMFactory.h"
#include "PlatformDecoderModule.h"
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"

namespace mozilla {

DDLoggedTypeDeclNameAndBase(MediaChangeMonitor, MediaDataDecoder);

// MediaChangeMonitor is a MediaDataDecoder wrapper used to ensure that
// only one type of content is fed to the underlying MediaDataDecoder.
// The MediaChangeMonitor allows playback of content where some out of band
// extra data (such as SPS NAL for H264 content) may not be provided in the
// init segment (e.g. AVC3 or Annex B) MediaChangeMonitor will monitor the
// input data, and will delay creation of the MediaDataDecoder until such out
// of band have been extracted should the underlying decoder required it.

class MediaChangeMonitor final
    : public MediaDataDecoder,
      public DecoderDoctorLifeLogger<MediaChangeMonitor> {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaChangeMonitor, final);

  static RefPtr<PlatformDecoderModule::CreateDecoderPromise> Create(
      PDMFactory* aPDMFactory, const CreateDecoderParams& aParams);

  RefPtr<InitPromise> Init() override;
  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
  RefPtr<DecodePromise> Drain() override;
  RefPtr<FlushPromise> Flush() override;
  RefPtr<ShutdownPromise> Shutdown() override;
  bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
  nsCString GetDescriptionName() const override {
    if (RefPtr<MediaDataDecoder> decoder = GetDecoderOnNonOwnerThread()) {
      return decoder->GetDescriptionName();
    }
    return "MediaChangeMonitor decoder (pending)"_ns;
  }
  nsCString GetProcessName() const override {
    if (RefPtr<MediaDataDecoder> decoder = GetDecoderOnNonOwnerThread()) {
      return decoder->GetProcessName();
    }
    return "MediaChangeMonitor"_ns;
  }
  nsCString GetCodecName() const override {
    if (RefPtr<MediaDataDecoder> decoder = GetDecoderOnNonOwnerThread()) {
      return decoder->GetCodecName();
    }
    return "MediaChangeMonitor"_ns;
  }
  void SetSeekThreshold(const media::TimeUnit& aTime) override;
  bool SupportDecoderRecycling() const override {
    if (RefPtr<MediaDataDecoder> decoder = GetDecoderOnNonOwnerThread()) {
      return decoder->SupportDecoderRecycling();
    }
    return false;
  }

  ConversionRequired NeedsConversion() const override {
    if (RefPtr<MediaDataDecoder> decoder = GetDecoderOnNonOwnerThread()) {
      return decoder->NeedsConversion();
    }
    // Default so no conversion is performed.
    return ConversionRequired::kNeedNone;
  }

  class CodecChangeMonitor {
   public:
    virtual bool CanBeInstantiated() const = 0;
    virtual MediaResult CheckForChange(MediaRawData* aSample) = 0;
    virtual const TrackInfo& Config() const = 0;
    virtual MediaResult PrepareSample(
        MediaDataDecoder::ConversionRequired aConversion, MediaRawData* aSample,
        bool aNeedKeyFrame) = 0;
    virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const {
      return false;
    }
    virtual ~CodecChangeMonitor() = default;
  };

 private:
  MediaChangeMonitor(PDMFactory* aPDMFactory,
                     UniquePtr<CodecChangeMonitor>&& aCodecChangeMonitor,
                     MediaDataDecoder* aDecoder,
                     const CreateDecoderParams& aParams);
  virtual ~MediaChangeMonitor();

  void AssertOnThread() const {
    // mThread may not be set if Init hasn't been called first.
    MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
  }

  // This is used for getting decoder debug info on other threads. Thread-safe.
  MediaDataDecoder* GetDecoderOnNonOwnerThread() const;

  bool CanRecycleDecoder() const;

  typedef MozPromise<bool, MediaResult, true /* exclusive */>
      CreateDecoderPromise;
  // Will create the required MediaDataDecoder if need AVCC and we have a SPS
  // NAL. Returns NS_ERROR_FAILURE if error is permanent and can't be recovered
  // and will set mError accordingly.
  RefPtr<CreateDecoderPromise> CreateDecoder();
  MediaResult CreateDecoderAndInit(MediaRawData* aSample);
  MediaResult CheckForChange(MediaRawData* aSample);

  void DecodeFirstSample(MediaRawData* aSample);
  void DrainThenFlushDecoder(MediaRawData* aPendingSample);
  void FlushThenShutdownDecoder(MediaRawData* aPendingSample);
  RefPtr<ShutdownPromise> ShutdownDecoder();

  UniquePtr<CodecChangeMonitor> mChangeMonitor;
  RefPtr<PDMFactory> mPDMFactory;
  VideoInfo mCurrentConfig;
  nsCOMPtr<nsISerialEventTarget> mThread;
  RefPtr<MediaDataDecoder> mDecoder;
  MozPromiseRequestHolder<CreateDecoderPromise> mDecoderRequest;
  MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
  MozPromiseHolder<InitPromise> mInitPromise;
  MozPromiseRequestHolder<DecodePromise> mDecodePromiseRequest;
  MozPromiseHolder<DecodePromise> mDecodePromise;
  MozPromiseRequestHolder<FlushPromise> mFlushRequest;
  MediaDataDecoder::DecodedData mPendingFrames;
  MozPromiseRequestHolder<DecodePromise> mDrainRequest;
  MozPromiseRequestHolder<ShutdownPromise> mShutdownRequest;
  RefPtr<ShutdownPromise> mShutdownPromise;
  MozPromiseHolder<FlushPromise> mFlushPromise;

  bool mNeedKeyframe = true;
  Maybe<bool> mCanRecycleDecoder;
  Maybe<MediaDataDecoder::ConversionRequired> mConversionRequired;
  bool mDecoderInitialized = false;
  const CreateDecoderParamsForAsync mParams;
  // Keep any seek threshold set for after decoder creation and initialization.
  Maybe<media::TimeUnit> mPendingSeekThreshold;

  // This lock is used for mDecoder specifically, but it doens't need to be used
  // for every places accessing mDecoder which is mostly on the owner thread.
  // However, when requesting decoder debug info, it can happen on other
  // threads, so we need this mutex to avoid the data race of
  // creating/destroying decoder and accessing decoder's debug info.
  mutable Mutex MOZ_ANNOTATED mMutex{"MediaChangeMonitor"};
};

}  // namespace mozilla

#endif  // mozilla_H264Converter_h