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
media / renderers / win / media_foundation_stream_wrapper.h [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_STREAM_WRAPPER_H_
#define MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_STREAM_WRAPPER_H_
#include <mfapi.h>
#include <mfidl.h>
#include <wrl.h>
#include <memory>
#include <optional>
#include <queue>
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
namespace media {
namespace {
struct PendingInputBuffer {
PendingInputBuffer(DemuxerStream::Status status,
scoped_refptr<media::DecoderBuffer> buffer);
explicit PendingInputBuffer(DemuxerStream::Status status);
PendingInputBuffer(const PendingInputBuffer& other);
~PendingInputBuffer();
DemuxerStream::Status status;
scoped_refptr<media::DecoderBuffer> buffer;
};
} // namespace
// IMFMediaStream implementation
// (https://msdn.microsoft.com/en-us/windows/desktop/ms697561) based on the
// given |demuxer_stream|.
//
class MediaFoundationStreamWrapper
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<
Microsoft::WRL::RuntimeClassType::ClassicCom>,
IMFMediaStream> {
public:
MediaFoundationStreamWrapper();
~MediaFoundationStreamWrapper() override;
static HRESULT Create(int stream_id,
IMFMediaSource* parent_source,
DemuxerStream* demuxer_stream,
std::unique_ptr<MediaLog> media_log,
scoped_refptr<base::SequencedTaskRunner> task_runner,
MediaFoundationStreamWrapper** stream_out);
HRESULT RuntimeClassInitialize(int stream_id,
IMFMediaSource* parent_source,
DemuxerStream* demuxer_stream,
std::unique_ptr<MediaLog> media_log);
void SetTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner);
void DetachParent();
void DetachDemuxerStream();
bool HasEnded() const;
// The following methods can be invoked by media stack thread or MF threadpool
// thread via MediaFoundationSourceWrapper::Start().
void SetSelected(bool selected);
bool IsSelected();
bool IsEnabled();
void SetEnabled(bool enabled);
void SetFlushed(bool flushed);
// TODO: revisting inheritance and potentially replacing it with composition.
// The stream is encrypted or not.
virtual bool IsEncrypted() const = 0;
// Let derived class to adjust the IMFSample if necessary.
virtual HRESULT TransformSample(Microsoft::WRL::ComPtr<IMFSample>& sample);
// Allow derived class to tell us if we can send MEStreamFormatChanged to MF.
virtual bool AreFormatChangesEnabled();
HRESULT QueueStartedEvent(const PROPVARIANT* start_position);
HRESULT QueueSeekedEvent(const PROPVARIANT* start_position);
HRESULT QueueStoppedEvent();
HRESULT QueuePausedEvent();
HRESULT QueueFormatChangedEvent();
DemuxerStream::Type StreamType() const;
void ProcessRequestsIfPossible();
void OnDemuxerStreamRead(DemuxerStream::Status status,
scoped_refptr<DecoderBuffer> buffer);
// Receive the data from MojoDemuxerStreamAdapter.
void OnDemuxerStreamReadBuffers(DemuxerStream::Status status,
DemuxerStream::DecoderBufferVector buffers);
// IMFMediaStream implementation - it is in general running in MF threadpool
// thread.
IFACEMETHODIMP GetMediaSource(IMFMediaSource** media_source_out) override;
IFACEMETHODIMP GetStreamDescriptor(
IMFStreamDescriptor** stream_descriptor_out) override;
IFACEMETHODIMP RequestSample(IUnknown* token) override;
// IMFMediaEventGenerator implementation - IMFMediaStream derives from
// IMFMediaEventGenerator.
IFACEMETHODIMP GetEvent(DWORD flags, IMFMediaEvent** event_out) override;
IFACEMETHODIMP BeginGetEvent(IMFAsyncCallback* callback,
IUnknown* state) override;
IFACEMETHODIMP EndGetEvent(IMFAsyncResult* result,
IMFMediaEvent** event_out) override;
IFACEMETHODIMP QueueEvent(MediaEventType type,
REFGUID extended_type,
HRESULT status,
const PROPVARIANT* value) override;
GUID GetLastKeyId() const;
protected:
HRESULT GenerateStreamDescriptor();
HRESULT ServiceSampleRequest(IUnknown* token, DecoderBuffer* buffer)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
// Returns true when a sample request has been serviced.
bool ServicePostFlushSampleRequest();
virtual HRESULT GetMediaType(IMFMediaType** media_type_out) = 0;
void ReportEncryptionType(const scoped_refptr<DecoderBuffer>& buffer);
void SetLastStartPosition(const PROPVARIANT* start_position);
scoped_refptr<base::SequencedTaskRunner> task_runner_;
enum class State {
kInitialized,
kStarted,
kStopped,
kPaused
} state_ = State::kInitialized;
raw_ptr<DemuxerStream> demuxer_stream_ = nullptr;
DemuxerStream::Type stream_type_ = DemuxerStream::Type::UNKNOWN;
std::unique_ptr<MediaLog> media_log_;
// Need exclusive access to some members between calls from MF threadpool
// thread and calling thread from Chromium media stack.
base::Lock lock_;
// Indicates whether the stream is selected in the MF pipeline.
bool selected_ GUARDED_BY(lock_) = false;
// Indicates whether the stream is enabled in the Chromium media pipeline.
bool enabled_ GUARDED_BY(lock_) = true;
// Indicates whether the Chromium pipeline has flushed the renderer
// (prior to a seek).
// Since SetFlushed() can be invoked by media stack thread or MF threadpool
// thread, |flushed_| and |post_flush_buffers_| are protected by lock.
bool flushed_ GUARDED_BY(lock_) = false;
int stream_id_;
bool has_clear_lead_ = false;
bool switched_clear_to_encrypted_ = false;
// |mf_media_event_queue_| is safe to be called on any thread.
Microsoft::WRL::ComPtr<IMFMediaEventQueue> mf_media_event_queue_;
Microsoft::WRL::ComPtr<IMFStreamDescriptor> mf_stream_descriptor_;
// The IMFMediaSource that contains this stream.
Microsoft::WRL::ComPtr<IMFMediaSource> parent_source_ GUARDED_BY(lock_);
// If non-zero, there are pending sample request from MF.
std::queue<Microsoft::WRL::ComPtr<IUnknown>> pending_sample_request_tokens_
GUARDED_BY(lock_);
// If true, there is a pending a read completion from Chromium media stack.
bool pending_stream_read_ = false;
// Maintain the buffer obtained by batch read. We push buffer into
// |buffer_queue_| by OnDemuxerStreamReadBuffers(), pop buffer by
// ProcessRequestsIfPossible(), these two operations are both on media stack
// thread. SetFlush() can be invoked by media stack thread or MF threadpool
// thread, it clears the buffer in |buffer_queue_|. So |buffer_queue_| needs
// to be guardedby the lock.
std::deque<PendingInputBuffer> buffer_queue_ GUARDED_BY(lock_);
// |batch_read_count_| represents how many buffers we try to get by a IPC
// call. The actual returned buffer count could be less according to
// DemuxerStream::Read() API.
uint32_t batch_read_count_ = 1;
bool stream_ended_ = false;
GUID last_key_id_ = GUID_NULL;
static constexpr MFTIME kInvalidTime = -1;
// The starting position in 100-nanosecond units, relative to the start of
// the presentation. Set from MediaFoundationSourceWrapper::Start, and used
// to send Stream ticks in ServicePostFlushSampleRequest.
MFTIME last_start_time_ GUARDED_BY(lock_) = kInvalidTime;
// Save media::DecoderBuffer from OnDemuxerStreamRead call when we are in
// progress of a flush operation.
std::queue<scoped_refptr<DecoderBuffer>> post_flush_buffers_
GUARDED_BY(lock_);
bool encryption_type_reported_ = false;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<MediaFoundationStreamWrapper> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_STREAM_WRAPPER_H_