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_