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