summaryrefslogtreecommitdiffstats
path: root/dom/media/mediasink/VideoSink.h
blob: 7f2528d87019340b606835cbf782367ad1289d2a (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 VideoSink_h_
#define VideoSink_h_

#include "FrameStatistics.h"
#include "ImageContainer.h"
#include "MediaEventSource.h"
#include "MediaSink.h"
#include "MediaTimer.h"
#include "VideoFrameContainer.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"

namespace mozilla {

class VideoFrameContainer;
template <class T>
class MediaQueue;

class VideoSink : public MediaSink {
  typedef mozilla::layers::ImageContainer::ProducerID ProducerID;

 public:
  VideoSink(AbstractThread* aThread, MediaSink* aAudioSink,
            MediaQueue<VideoData>& aVideoQueue, VideoFrameContainer* aContainer,
            FrameStatistics& aFrameStats, uint32_t aVQueueSentToCompositerSize);

  RefPtr<EndedPromise> OnEnded(TrackType aType) override;

  media::TimeUnit GetEndTime(TrackType aType) const override;

  media::TimeUnit GetPosition(TimeStamp* aTimeStamp = nullptr) override;

  bool HasUnplayedFrames(TrackType aType) const override;
  media::TimeUnit UnplayedDuration(TrackType aType) const override;

  void SetPlaybackRate(double aPlaybackRate) override;

  void SetVolume(double aVolume) override;

  void SetStreamName(const nsAString& aStreamName) override;

  void SetPreservesPitch(bool aPreservesPitch) override;

  void SetPlaying(bool aPlaying) override;

  double PlaybackRate() const override;

  void Redraw(const VideoInfo& aInfo) override;

  nsresult Start(const media::TimeUnit& aStartTime,
                 const MediaInfo& aInfo) override;

  void Stop() override;

  bool IsStarted() const override;

  bool IsPlaying() const override;

  const AudioDeviceInfo* AudioDevice() const override;

  void Shutdown() override;

  void SetSecondaryVideoContainer(VideoFrameContainer* aSecondary) override;

  void GetDebugInfo(dom::MediaSinkDebugInfo& aInfo) override;

  void EnableTreatAudioUnderrunAsSilence(bool aEnabled) override;

 private:
  virtual ~VideoSink();

  // VideoQueue listener related.
  void OnVideoQueuePushed(RefPtr<VideoData>&& aSample);
  void OnVideoQueueFinished();
  void ConnectListener();
  void DisconnectListener();

  void EnsureHighResTimersOnOnlyIfPlaying();

  // Sets VideoQueue images into the VideoFrameContainer. Called on the shared
  // state machine thread. The first aMaxFrames (at most) are set.
  // aClockTime and aClockTimeStamp are used as the baseline for deriving
  // timestamps for the frames; when omitted, aMaxFrames must be 1 and
  // a null timestamp is passed to the VideoFrameContainer.
  // If the VideoQueue is empty, this does nothing.
  void RenderVideoFrames(int32_t aMaxFrames, int64_t aClockTime = 0,
                         const TimeStamp& aClickTimeStamp = TimeStamp());

  // Triggered while videosink is started, videosink becomes "playing" status,
  // or VideoQueue event arrived.
  void TryUpdateRenderedVideoFrames();

  // If we have video, display a video frame if it's time for display has
  // arrived, otherwise sleep until it's time for the next frame. Update the
  // current frame time as appropriate, and trigger ready state update.
  // Called on the shared state machine thread.
  void UpdateRenderedVideoFrames();
  void UpdateRenderedVideoFramesByTimer();

  void MaybeResolveEndPromise();

  void AssertOwnerThread() const {
    MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
  }

  MediaQueue<VideoData>& VideoQueue() const { return mVideoQueue; }

  const RefPtr<AbstractThread> mOwnerThread;
  const RefPtr<MediaSink> mAudioSink;
  MediaQueue<VideoData>& mVideoQueue;
  VideoFrameContainer* mContainer;
  RefPtr<VideoFrameContainer> mSecondaryContainer;

  // Producer ID to help ImageContainer distinguish different streams of
  // FrameIDs. A unique and immutable value per VideoSink.
  const ProducerID mProducerID;

  // Used to notify MediaDecoder's frame statistics
  FrameStatistics& mFrameStats;

  RefPtr<EndedPromise> mEndPromise;
  MozPromiseHolder<EndedPromise> mEndPromiseHolder;
  MozPromiseRequestHolder<EndedPromise> mVideoSinkEndRequest;

  // The presentation end time of the last video frame which has been displayed.
  media::TimeUnit mVideoFrameEndTime;

  uint32_t mOldCompositorDroppedCount;
  uint32_t mPendingDroppedCount;

  // Event listeners for VideoQueue
  MediaEventListener mPushListener;
  MediaEventListener mFinishListener;

  // True if this sink is going to handle video track.
  bool mHasVideo;

  // Used to trigger another update of rendered frames in next round.
  DelayedScheduler mUpdateScheduler;

  // Max frame number sent to compositor at a time.
  // Based on the pref value obtained in MDSM.
  const uint32_t mVideoQueueSendToCompositorSize;

  // Talos tests for the compositor require at least one frame in the
  // video queue so that the compositor has something to composit during
  // the talos test when the decode is stressed. We have a minimum size
  // on the video queue in order to facilitate this talos test.
  // Note: Normal playback should not have a queue size of more than 0,
  // otherwise A/V sync will be ruined! *Only* make this non-zero for
  // testing purposes.
  const uint32_t mMinVideoQueueSize;

#ifdef XP_WIN
  // Whether we've called timeBeginPeriod(1) to request high resolution
  // timers. We request high resolution timers when playback starts, and
  // turn them off when playback is paused. Enabling high resolution
  // timers can cause higher CPU usage and battery drain on Windows 7,
  // but reduces our frame drop rate.
  bool mHiResTimersRequested;
#endif

  RefPtr<layers::Image> mBlankImage;
  bool InitializeBlankImage();
};

}  // namespace mozilla

#endif