summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/wmf/MFMediaEngineStream.h
blob: aa3bf7e65d618d9004c5c3390c69c15338d84c32 (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* 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 DOM_MEDIA_PLATFORM_WMF_MFMEDIAENGINESTREAM_H
#define DOM_MEDIA_PLATFORM_WMF_MFMEDIAENGINESTREAM_H

#include <mfidl.h>
#include <wrl.h>

#include <queue>

#include "BlankDecoderModule.h"
#include "MediaQueue.h"
#include "PlatformDecoderModule.h"
#include "mozilla/Atomics.h"
#include "mozilla/Mutex.h"
#include "mozilla/SPSCQueue.h"

namespace mozilla {

class MFMediaEngineVideoStream;
class MFMediaSource;

/**
 * MFMediaEngineStream represents a track which would be responsible to provide
 * encoded data into the media engine. The media engine can access this stream
 * by the presentation descriptor which was acquired from the custom media
 * source.
 */
class MFMediaEngineStream
    : public Microsoft::WRL::RuntimeClass<
          Microsoft::WRL::RuntimeClassFlags<
              Microsoft::WRL::RuntimeClassType::ClassicCom>,
          IMFMediaStream> {
 public:
  MFMediaEngineStream();
  ~MFMediaEngineStream();

  virtual nsCString GetDescriptionName() const = 0;

  virtual nsCString GetCodecName() const = 0;

  HRESULT RuntimeClassInitialize(uint64_t aStreamId, const TrackInfo& aInfo,
                                 MFMediaSource* aParentSource);

  // Called by MFMediaSource.
  HRESULT Start(const PROPVARIANT* aPosition);
  HRESULT Seek(const PROPVARIANT* aPosition);
  HRESULT Stop();
  HRESULT Pause();
  void Shutdown();

  void SetSelected(bool aSelected);
  bool IsSelected() const { return mIsSelected; }
  DWORD DescriptorId() const { return mStreamDescriptorId; }

  // Methods for IMFMediaStream
  IFACEMETHODIMP GetMediaSource(IMFMediaSource** aMediaSource) override;
  IFACEMETHODIMP GetStreamDescriptor(
      IMFStreamDescriptor** aStreamDescriptor) override;
  IFACEMETHODIMP RequestSample(IUnknown* aToken) override;

  // Methods for IMFMediaEventGenerator, IMFMediaStream derives from
  // IMFMediaEventGenerator.
  IFACEMETHODIMP GetEvent(DWORD aFlags, IMFMediaEvent** aEvent) override;
  IFACEMETHODIMP BeginGetEvent(IMFAsyncCallback* aCallback,
                               IUnknown* aState) override;
  IFACEMETHODIMP EndGetEvent(IMFAsyncResult* aResult,
                             IMFMediaEvent** aEvent) override;
  IFACEMETHODIMP QueueEvent(MediaEventType aType, REFGUID aExtendedType,
                            HRESULT aStatus,
                            const PROPVARIANT* aValue) override;

  TaskQueue* GetTaskQueue() { return mTaskQueue; }

  void NotifyEndOfStream() {
    Microsoft::WRL::ComPtr<MFMediaEngineStream> self = this;
    Unused << mTaskQueue->Dispatch(NS_NewRunnableFunction(
        "MFMediaEngineStream::NotifyEndOfStream",
        [self]() { self->NotifyEndOfStreamInternal(); }));
  }

  // Return the type of the track, the result should be either audio or video.
  virtual TrackInfo::TrackType TrackType() = 0;

  RefPtr<MediaDataDecoder::FlushPromise> Flush();

  MediaEventProducer<TrackInfo::TrackType>& EndedEvent() { return mEndedEvent; }

  // True if the stream has been shutdown, it's a thread safe method.
  bool IsShutdown() const { return mIsShutdown; }

  virtual MFMediaEngineVideoStream* AsVideoStream() { return nullptr; }

  RefPtr<MediaDataDecoder::DecodePromise> OutputData(
      RefPtr<MediaRawData> aSample);

  virtual RefPtr<MediaDataDecoder::DecodePromise> Drain();

  virtual MediaDataDecoder::ConversionRequired NeedsConversion() const {
    return MediaDataDecoder::ConversionRequired::kNeedNone;
  }

  virtual bool IsEncrypted() const = 0;

 protected:
  HRESULT GenerateStreamDescriptor(
      Microsoft::WRL::ComPtr<IMFMediaType>& aMediaType);

  // Create a IMFMediaType which includes the details about the stream.
  // https://docs.microsoft.com/en-us/windows/win32/medfound/media-type-attributes
  virtual HRESULT CreateMediaType(const TrackInfo& aInfo,
                                  IMFMediaType** aMediaType) = 0;

  // True if the stream already has enough raw data.
  virtual bool HasEnoughRawData() const = 0;

  HRESULT CreateInputSample(IMFSample** aSample);
  void ReplySampleRequestIfPossible();
  bool ShouldServeSamples() const;

  void NotifyNewData(MediaRawData* aSample);
  void NotifyEndOfStreamInternal();

  virtual bool IsEnded() const;

  // Overwrite this method if inherited class needs to perform clean up on the
  // task queue when the stream gets shutdowned.
  virtual void ShutdownCleanUpOnTaskQueue(){};

  // Inherited class must implement this method to return decoded data. it
  // should uses `mRawDataQueueForGeneratingOutput` to generate output.
  virtual already_AddRefed<MediaData> OutputDataInternal() = 0;

  void SendRequestSampleEvent(bool aIsEnough);

  HRESULT AddEncryptAttributes(IMFSample* aSample,
                               const CryptoSample& aCryptoConfig);

  void AssertOnTaskQueue() const;
  void AssertOnMFThreadPool() const;

  // IMFMediaEventQueue is thread-safe.
  Microsoft::WRL::ComPtr<IMFMediaEventQueue> mMediaEventQueue;
  Microsoft::WRL::ComPtr<IMFStreamDescriptor> mStreamDescriptor;
  Microsoft::WRL::ComPtr<MFMediaSource> mParentSource;

  // This an unique ID retrieved from the IMFStreamDescriptor.
  DWORD mStreamDescriptorId = 0;

  // A unique ID assigned by MFMediaSource, which won't be changed after first
  // assignment.
  uint64_t mStreamId = 0;

  RefPtr<TaskQueue> mTaskQueue;

  // This class would be run on three threads, MF thread pool, the source's
  // task queue and MediaPDecoder (wrapper thread). Following members would be
  // used across both threads so they need to be thread-safe.

  // Modify on the MF thread pool, access from any threads.
  Atomic<bool> mIsShutdown;

  // True if the stream is selected by the media source.
  // Modify on MF thread pool, access from any threads.
  Atomic<bool> mIsSelected;

  // A thread-safe queue storing input samples, which provides samples to the
  // media engine.
  MediaQueue<MediaRawData> mRawDataQueueForFeedingEngine;

  // A thread-safe queue storing input samples, which would be used to generate
  // decoded data.
  MediaQueue<MediaRawData> mRawDataQueueForGeneratingOutput;

  // Thread-safe members END

  // Store sample request token, one token should be related with one output
  // data. It's used on the task queue only.
  std::queue<Microsoft::WRL::ComPtr<IUnknown>> mSampleRequestTokens;

  // Notify when playback reachs the end for this track.
  MediaEventProducer<TrackInfo::TrackType> mEndedEvent;

  // True if the stream has received the last data, but it could be reset if the
  // stream starts delivering more data. Used on the task queue only.
  bool mReceivedEOS;
};

/**
 * This wrapper helps to dispatch task onto the stream's task queue. Its methods
 * are not thread-safe and would only be called on the IPC decoder manager
 * thread.
 */
class MFMediaEngineStreamWrapper final : public MediaDataDecoder {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MFMediaEngineStreamWrapper, final);

  MFMediaEngineStreamWrapper(MFMediaEngineStream* aStream,
                             TaskQueue* aTaskQueue,
                             const CreateDecoderParams& aParams)
      : mStream(aStream), mTaskQueue(aTaskQueue) {
    MOZ_ASSERT(mStream);
    MOZ_ASSERT(mTaskQueue);
  }

  // Methods for MediaDataDecoder, they are all called on the remote
  // decoder manager thread.
  RefPtr<InitPromise> Init() override;
  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
  RefPtr<DecodePromise> Drain() override;
  RefPtr<FlushPromise> Flush() override;
  RefPtr<ShutdownPromise> Shutdown() override;
  nsCString GetDescriptionName() const override;
  nsCString GetCodecName() const override;
  ConversionRequired NeedsConversion() const override;

 private:
  ~MFMediaEngineStreamWrapper() = default;

  Microsoft::WRL::ComPtr<MFMediaEngineStream> mStream;
  RefPtr<TaskQueue> mTaskQueue;
};

}  // namespace mozilla

#endif  // DOM_MEDIA_PLATFORM_WMF_MFMEDIAENGINESTREAM_H