1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef MEDIA_FILTERS_VIDEO_RENDERER_IMPL_H_
6#define MEDIA_FILTERS_VIDEO_RENDERER_IMPL_H_
7
8#include <deque>
9
10#include "base/memory/ref_counted.h"
11#include "base/memory/scoped_vector.h"
12#include "base/memory/weak_ptr.h"
13#include "base/synchronization/condition_variable.h"
14#include "base/synchronization/lock.h"
15#include "base/threading/platform_thread.h"
16#include "media/base/decryptor.h"
17#include "media/base/demuxer_stream.h"
18#include "media/base/pipeline_status.h"
19#include "media/base/video_decoder.h"
20#include "media/base/video_frame.h"
21#include "media/base/video_renderer.h"
22#include "media/filters/video_frame_stream.h"
23
24namespace base {
25class MessageLoopProxy;
26}
27
28namespace media {
29
30// VideoRendererImpl creates its own thread for the sole purpose of timing frame
31// presentation.  It handles reading from the VideoFrameStream and stores the
32// results in a queue of decoded frames and executing a callback when a frame is
33// ready for rendering.
34class MEDIA_EXPORT VideoRendererImpl
35    : public VideoRenderer,
36      public base::PlatformThread::Delegate {
37 public:
38  typedef base::Callback<void(const scoped_refptr<VideoFrame>&)> PaintCB;
39  typedef base::Callback<void(bool)> SetOpaqueCB;
40
41  // Maximum duration of the last frame.
42  static base::TimeDelta kMaxLastFrameDuration();
43
44  // |decoders| contains the VideoDecoders to use when initializing.
45  //
46  // |paint_cb| is executed on the video frame timing thread whenever a new
47  // frame is available for painting.
48  //
49  // |set_opaque_cb| is executed when the renderer is initialized to inform
50  // the player whether the decoded output will be opaque or not.
51  //
52  // Implementors should avoid doing any sort of heavy work in this method and
53  // instead post a task to a common/worker thread to handle rendering.  Slowing
54  // down the video thread may result in losing synchronization with audio.
55  //
56  // Setting |drop_frames_| to true causes the renderer to drop expired frames.
57  VideoRendererImpl(const scoped_refptr<base::MessageLoopProxy>& message_loop,
58                    ScopedVector<VideoDecoder> decoders,
59                    const SetDecryptorReadyCB& set_decryptor_ready_cb,
60                    const PaintCB& paint_cb,
61                    const SetOpaqueCB& set_opaque_cb,
62                    bool drop_frames);
63  virtual ~VideoRendererImpl();
64
65  // VideoRenderer implementation.
66  virtual void Initialize(DemuxerStream* stream,
67                          const PipelineStatusCB& init_cb,
68                          const StatisticsCB& statistics_cb,
69                          const TimeCB& max_time_cb,
70                          const NaturalSizeChangedCB& size_changed_cb,
71                          const base::Closure& ended_cb,
72                          const PipelineStatusCB& error_cb,
73                          const TimeDeltaCB& get_time_cb,
74                          const TimeDeltaCB& get_duration_cb) OVERRIDE;
75  virtual void Play(const base::Closure& callback) OVERRIDE;
76  virtual void Pause(const base::Closure& callback) OVERRIDE;
77  virtual void Flush(const base::Closure& callback) OVERRIDE;
78  virtual void Preroll(base::TimeDelta time,
79                       const PipelineStatusCB& cb) OVERRIDE;
80  virtual void Stop(const base::Closure& callback) OVERRIDE;
81  virtual void SetPlaybackRate(float playback_rate) OVERRIDE;
82
83  // PlatformThread::Delegate implementation.
84  virtual void ThreadMain() OVERRIDE;
85
86 private:
87  // Callback for |video_frame_stream_| initialization.
88  void OnVideoFrameStreamInitialized(bool success, bool has_alpha);
89
90  // Callback for |video_frame_stream_| to deliver decoded video frames and
91  // report video decoding status.
92  void FrameReady(VideoFrameStream::Status status,
93                  const scoped_refptr<VideoFrame>& frame);
94
95  // Helper method for adding a frame to |ready_frames_|.
96  void AddReadyFrame_Locked(const scoped_refptr<VideoFrame>& frame);
97
98  // Helper method that schedules an asynchronous read from the
99  // |video_frame_stream_| as long as there isn't a pending read and we have
100  // capacity.
101  void AttemptRead();
102  void AttemptRead_Locked();
103
104  // Called when VideoFrameStream::Reset() completes.
105  void OnVideoFrameStreamResetDone();
106
107  // Calculates the duration to sleep for based on |last_timestamp_|,
108  // the next frame timestamp (may be NULL), and the provided playback rate.
109  //
110  // We don't use |playback_rate_| to avoid locking.
111  base::TimeDelta CalculateSleepDuration(
112      const scoped_refptr<VideoFrame>& next_frame,
113      float playback_rate);
114
115  // Helper function that flushes the buffers when a Stop() or error occurs.
116  void DoStopOrError_Locked();
117
118  // Runs |paint_cb_| with the next frame from |ready_frames_|, updating
119  // |last_natural_size_| and running |size_changed_cb_| if the natural size
120  // changes.
121  //
122  // A read is scheduled to replace the frame.
123  void PaintNextReadyFrame_Locked();
124
125  // Drops the next frame from |ready_frames_| and runs |statistics_cb_|.
126  //
127  // A read is scheduled to replace the frame.
128  void DropNextReadyFrame_Locked();
129
130  void TransitionToPrerolled_Locked();
131
132  // Returns true of all conditions have been met to transition from
133  // kPrerolling to kPrerolled.
134  bool ShouldTransitionToPrerolled_Locked();
135
136  // Runs |statistics_cb_| with |frames_decoded_| and |frames_dropped_|, resets
137  // them to 0, and then waits on |frame_available_| for up to the
138  // |wait_duration|.
139  void UpdateStatsAndWait_Locked(base::TimeDelta wait_duration);
140
141  scoped_refptr<base::MessageLoopProxy> message_loop_;
142  base::WeakPtrFactory<VideoRendererImpl> weak_factory_;
143  base::WeakPtr<VideoRendererImpl> weak_this_;
144
145  // Used for accessing data members.
146  base::Lock lock_;
147
148  // Provides video frames to VideoRendererImpl.
149  VideoFrameStream video_frame_stream_;
150
151  // Queue of incoming frames yet to be painted.
152  typedef std::deque<scoped_refptr<VideoFrame> > VideoFrameQueue;
153  VideoFrameQueue ready_frames_;
154
155  // Keeps track of whether we received the end of stream buffer.
156  bool received_end_of_stream_;
157
158  // Used to signal |thread_| as frames are added to |frames_|.  Rule of thumb:
159  // always check |state_| to see if it was set to STOPPED after waking up!
160  base::ConditionVariable frame_available_;
161
162  // State transition Diagram of this class:
163  //       [kUninitialized] -------> [kError]
164  //              |
165  //              | Initialize()
166  //        [kInitializing]
167  //              |
168  //              V
169  //   +------[kFlushed]<---------------OnVideoFrameStreamResetDone()
170  //   |          | Preroll() or upon               ^
171  //   |          V got first frame            [kFlushing]
172  //   |      [kPrerolling]                         ^
173  //   |          |                                 | Flush()
174  //   |          V Got enough frames               |
175  //   |      [kPrerolled]---------------------->[kPaused]
176  //   |          |                Pause()          ^
177  //   |          V Play()                          |
178  //   |       [kPlaying]---------------------------|
179  //   |          |                Pause()          ^
180  //   |          V Receive EOF frame.              | Pause()
181  //   |       [kEnded]-----------------------------+
182  //   |                                            ^
183  //   |                                            |
184  //   +-----> [kStopped]                 [Any state other than]
185  //                                      [kUninitialized/kError]
186
187  // Simple state tracking variable.
188  enum State {
189    kUninitialized,
190    kInitializing,
191    kPrerolled,
192    kPaused,
193    kFlushing,
194    kFlushed,
195    kPrerolling,
196    kPlaying,
197    kEnded,
198    kStopped,
199    kError,
200  };
201  State state_;
202
203  // Video thread handle.
204  base::PlatformThreadHandle thread_;
205
206  // Keep track of the outstanding read on the VideoFrameStream. Flushing can
207  // only complete once the read has completed.
208  bool pending_read_;
209
210  bool drop_frames_;
211
212  float playback_rate_;
213
214  // Playback operation callbacks.
215  base::Closure flush_cb_;
216  PipelineStatusCB preroll_cb_;
217
218  // Event callbacks.
219  PipelineStatusCB init_cb_;
220  StatisticsCB statistics_cb_;
221  TimeCB max_time_cb_;
222  NaturalSizeChangedCB size_changed_cb_;
223  base::Closure ended_cb_;
224  PipelineStatusCB error_cb_;
225  TimeDeltaCB get_time_cb_;
226  TimeDeltaCB get_duration_cb_;
227
228  base::TimeDelta preroll_timestamp_;
229
230  // Embedder callback for notifying a new frame is available for painting.
231  PaintCB paint_cb_;
232
233  // Callback to execute to inform the player if the decoded output is opaque.
234  SetOpaqueCB set_opaque_cb_;
235
236  // The last natural size |size_changed_cb_| was called with.
237  //
238  // TODO(scherkus): WebMediaPlayerImpl should track this instead of plumbing
239  // this through Pipeline. The one tricky bit might be guaranteeing we deliver
240  // the size information before we reach HAVE_METADATA.
241  gfx::Size last_natural_size_;
242
243  // The timestamp of the last frame removed from the |ready_frames_| queue,
244  // either for calling |paint_cb_| or for dropping. Set to kNoTimestamp()
245  // during flushing.
246  base::TimeDelta last_timestamp_;
247
248  // Keeps track of the number of frames decoded and dropped since the
249  // last call to |statistics_cb_|. These must be accessed under lock.
250  int frames_decoded_;
251  int frames_dropped_;
252
253  DISALLOW_COPY_AND_ASSIGN(VideoRendererImpl);
254};
255
256}  // namespace media
257
258#endif  // MEDIA_FILTERS_VIDEO_RENDERER_IMPL_H_
259