| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ | 5 #ifndef MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ |
| 6 #define MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ | 6 #define MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ |
| 7 | 7 |
| 8 #include <deque> | 8 #include <deque> |
| 9 | 9 |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/weak_ptr.h" | |
| 12 #include "base/synchronization/condition_variable.h" | 11 #include "base/synchronization/condition_variable.h" |
| 13 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
| 14 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
| 15 #include "media/base/decryptor.h" | 14 #include "media/base/decryptor.h" |
| 16 #include "media/base/demuxer_stream.h" | 15 #include "media/base/demuxer_stream.h" |
| 17 #include "media/base/pipeline_status.h" | 16 #include "media/base/pipeline_status.h" |
| 18 #include "media/base/video_decoder.h" | 17 #include "media/base/video_decoder.h" |
| 19 #include "media/base/video_frame.h" | 18 #include "media/base/video_frame.h" |
| 20 #include "media/base/video_renderer.h" | 19 #include "media/base/video_renderer.h" |
| 21 | 20 |
| 22 namespace base { | 21 namespace base { |
| 23 class MessageLoopProxy; | 22 class MessageLoopProxy; |
| 24 } | 23 } |
| 25 | 24 |
| 26 namespace media { | 25 namespace media { |
| 27 | 26 |
| 28 class DecryptingDemuxerStream; | 27 class DecryptingDemuxerStream; |
| 29 class VideoDecoderSelector; | 28 class VideoDecoderSelector; |
| 30 | 29 |
| 31 // VideoRendererBase creates its own thread for the sole purpose of timing frame | 30 // VideoRendererBase creates its own thread for the sole purpose of timing frame |
| 32 // presentation. It handles reading from the decoder and stores the results in | 31 // presentation. It handles reading from the decoder and stores the results in |
| 33 // a queue of decoded frames and executing a callback when a frame is ready for | 32 // a queue of decoded frames and executing a callback when a frame is ready for |
| 34 // rendering. | 33 // rendering. |
| 35 class MEDIA_EXPORT VideoRendererBase | 34 class MEDIA_EXPORT VideoRendererBase |
| 36 : public VideoRenderer, | 35 : public VideoRenderer, |
| 37 public base::PlatformThread::Delegate { | 36 public base::PlatformThread::Delegate { |
| 38 public: | 37 public: |
| 39 typedef base::Callback<void(const scoped_refptr<VideoFrame>&)> PaintCB; | |
| 40 typedef base::Callback<void(bool)> SetOpaqueCB; | 38 typedef base::Callback<void(bool)> SetOpaqueCB; |
| 41 | 39 |
| 42 // Maximum duration of the last frame. | 40 // Maximum duration of the last frame. |
| 43 static base::TimeDelta kMaxLastFrameDuration(); | 41 static base::TimeDelta kMaxLastFrameDuration(); |
| 44 | 42 |
| 45 // |paint_cb| is executed on the video frame timing thread whenever a new | 43 // |paint_cb| is executed on the video frame timing thread whenever a new |
| 46 // frame is available for painting. | 44 // frame is available for painting via GetCurrentFrame(). |
| 47 // | 45 // |
| 48 // |set_opaque_cb| is executed when the renderer is initialized to inform | 46 // |set_opaque_cb| is executed when the renderer is initialized to inform |
| 49 // the player whether the decoder's output will be opaque or not. | 47 // the player whether the decoder's output will be opaque or not. |
| 50 // | 48 // |
| 51 // Implementors should avoid doing any sort of heavy work in this method and | 49 // Implementors should avoid doing any sort of heavy work in this method and |
| 52 // instead post a task to a common/worker thread to handle rendering. Slowing | 50 // instead post a task to a common/worker thread to handle rendering. Slowing |
| 53 // down the video thread may result in losing synchronization with audio. | 51 // down the video thread may result in losing synchronization with audio. |
| 54 // | 52 // |
| 55 // Setting |drop_frames_| to true causes the renderer to drop expired frames. | 53 // Setting |drop_frames_| to true causes the renderer to drop expired frames. |
| 56 // | 54 // |
| 57 // TODO(scherkus): pass the VideoFrame* to this callback and remove | 55 // TODO(scherkus): pass the VideoFrame* to this callback and remove |
| 58 // Get/PutCurrentFrame() http://crbug.com/108435 | 56 // Get/PutCurrentFrame() http://crbug.com/108435 |
| 59 VideoRendererBase(const scoped_refptr<base::MessageLoopProxy>& message_loop, | 57 VideoRendererBase(const scoped_refptr<base::MessageLoopProxy>& message_loop, |
| 60 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 58 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
| 61 const PaintCB& paint_cb, | 59 const base::Closure& paint_cb, |
| 62 const SetOpaqueCB& set_opaque_cb, | 60 const SetOpaqueCB& set_opaque_cb, |
| 63 bool drop_frames); | 61 bool drop_frames); |
| 64 virtual ~VideoRendererBase(); | |
| 65 | 62 |
| 66 // VideoRenderer implementation. | 63 // VideoRenderer implementation. |
| 67 virtual void Initialize(const scoped_refptr<DemuxerStream>& stream, | 64 virtual void Initialize(const scoped_refptr<DemuxerStream>& stream, |
| 68 const VideoDecoderList& decoders, | 65 const VideoDecoderList& decoders, |
| 69 const PipelineStatusCB& init_cb, | 66 const PipelineStatusCB& init_cb, |
| 70 const StatisticsCB& statistics_cb, | 67 const StatisticsCB& statistics_cb, |
| 71 const TimeCB& max_time_cb, | 68 const TimeCB& max_time_cb, |
| 72 const NaturalSizeChangedCB& size_changed_cb, | 69 const NaturalSizeChangedCB& size_changed_cb, |
| 73 const base::Closure& ended_cb, | 70 const base::Closure& ended_cb, |
| 74 const PipelineStatusCB& error_cb, | 71 const PipelineStatusCB& error_cb, |
| 75 const TimeDeltaCB& get_time_cb, | 72 const TimeDeltaCB& get_time_cb, |
| 76 const TimeDeltaCB& get_duration_cb) OVERRIDE; | 73 const TimeDeltaCB& get_duration_cb) OVERRIDE; |
| 77 virtual void Play(const base::Closure& callback) OVERRIDE; | 74 virtual void Play(const base::Closure& callback) OVERRIDE; |
| 78 virtual void Pause(const base::Closure& callback) OVERRIDE; | 75 virtual void Pause(const base::Closure& callback) OVERRIDE; |
| 79 virtual void Flush(const base::Closure& callback) OVERRIDE; | 76 virtual void Flush(const base::Closure& callback) OVERRIDE; |
| 80 virtual void Preroll(base::TimeDelta time, | 77 virtual void Preroll(base::TimeDelta time, |
| 81 const PipelineStatusCB& cb) OVERRIDE; | 78 const PipelineStatusCB& cb) OVERRIDE; |
| 82 virtual void Stop(const base::Closure& callback) OVERRIDE; | 79 virtual void Stop(const base::Closure& callback) OVERRIDE; |
| 83 virtual void SetPlaybackRate(float playback_rate) OVERRIDE; | 80 virtual void SetPlaybackRate(float playback_rate) OVERRIDE; |
| 84 | 81 |
| 85 // PlatformThread::Delegate implementation. | 82 // PlatformThread::Delegate implementation. |
| 86 virtual void ThreadMain() OVERRIDE; | 83 virtual void ThreadMain() OVERRIDE; |
| 87 | 84 |
| 85 // Clients of this class (painter/compositor) should use GetCurrentFrame() |
| 86 // obtain ownership of VideoFrame, it should always relinquish the ownership |
| 87 // by use PutCurrentFrame(). Current frame is not guaranteed to be non-NULL. |
| 88 // It expects clients to use color-fill the background if current frame |
| 89 // is NULL. This could happen before pipeline is pre-rolled or during |
| 90 // pause/flush/preroll. |
| 91 void GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out); |
| 92 void PutCurrentFrame(scoped_refptr<VideoFrame> frame); |
| 93 |
| 94 protected: |
| 95 virtual ~VideoRendererBase(); |
| 96 |
| 88 private: | 97 private: |
| 89 // Called when |decoder_selector_| selected the |selected_decoder|. | 98 // Called when |decoder_selector_| selected the |selected_decoder|. |
| 90 // |decrypting_demuxer_stream| was also populated if a DecryptingDemuxerStream | 99 // |decrypting_demuxer_stream| was also populated if a DecryptingDemuxerStream |
| 91 // created to help decrypt the encrypted stream. | 100 // created to help decrypt the encrypted stream. |
| 92 // Note: |decoder_selector| is passed here to keep the VideoDecoderSelector | 101 // Note: |decoder_selector| is passed here to keep the VideoDecoderSelector |
| 93 // alive until OnDecoderSelected() finishes. | 102 // alive until OnDecoderSelected() finishes. |
| 94 void OnDecoderSelected( | 103 void OnDecoderSelected( |
| 95 scoped_ptr<VideoDecoderSelector> decoder_selector, | 104 scoped_ptr<VideoDecoderSelector> decoder_selector, |
| 96 const scoped_refptr<VideoDecoder>& selected_decoder, | 105 const scoped_refptr<VideoDecoder>& selected_decoder, |
| 97 const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream); | 106 const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 108 // as there isn't a pending read and we have capacity. | 117 // as there isn't a pending read and we have capacity. |
| 109 void AttemptRead(); | 118 void AttemptRead(); |
| 110 void AttemptRead_Locked(); | 119 void AttemptRead_Locked(); |
| 111 | 120 |
| 112 // Called when VideoDecoder::Reset() completes. | 121 // Called when VideoDecoder::Reset() completes. |
| 113 void OnDecoderResetDone(); | 122 void OnDecoderResetDone(); |
| 114 | 123 |
| 115 // Attempts to complete flushing and transition into the flushed state. | 124 // Attempts to complete flushing and transition into the flushed state. |
| 116 void AttemptFlush_Locked(); | 125 void AttemptFlush_Locked(); |
| 117 | 126 |
| 118 // Calculates the duration to sleep for based on |last_timestamp_|, | 127 // Calculates the duration to sleep for based on |current_frame_|'s timestamp, |
| 119 // the next frame timestamp (may be NULL), and the provided playback rate. | 128 // the next frame timestamp (may be NULL), and the provided playback rate. |
| 120 // | 129 // |
| 121 // We don't use |playback_rate_| to avoid locking. | 130 // We don't use |playback_rate_| to avoid locking. |
| 122 base::TimeDelta CalculateSleepDuration( | 131 base::TimeDelta CalculateSleepDuration( |
| 123 const scoped_refptr<VideoFrame>& next_frame, | 132 const scoped_refptr<VideoFrame>& next_frame, |
| 124 float playback_rate); | 133 float playback_rate); |
| 125 | 134 |
| 126 // Helper function that flushes the buffers when a Stop() or error occurs. | 135 // Helper function that flushes the buffers when a Stop() or error occurs. |
| 127 void DoStopOrError_Locked(); | 136 void DoStopOrError_Locked(); |
| 128 | 137 |
| 129 // Return the number of frames currently held by this class. | 138 // Return the number of frames currently held by this class. |
| 130 int NumFrames_Locked() const; | 139 int NumFrames_Locked() const; |
| 131 | 140 |
| 132 // Runs |paint_cb_| with the next frame from |ready_frames_|, updating | 141 // Updates |current_frame_| to the next frame on |ready_frames_| and calls |
| 133 // |last_natural_size_| and running |size_changed_cb_| if the natural size | 142 // |size_changed_cb_| if the natural size changes. |
| 134 // changes. | 143 void SetCurrentFrameToNextReadyFrame(); |
| 135 // | |
| 136 // A read is scheduled to replace the frame. | |
| 137 void PaintNextReadyFrame_Locked(); | |
| 138 | |
| 139 // Drops the next frame from |ready_frames_| and runs |statistics_cb_|. | |
| 140 // | |
| 141 // A read is scheduled to replace the frame. | |
| 142 void DropNextReadyFrame_Locked(); | |
| 143 | 144 |
| 144 void ResetDecoder(); | 145 void ResetDecoder(); |
| 145 void StopDecoder(const base::Closure& callback); | 146 void StopDecoder(const base::Closure& callback); |
| 146 | 147 |
| 147 // Pops the front of |decoders|, assigns it to |decoder_| and then | 148 // Pops the front of |decoders|, assigns it to |decoder_| and then |
| 148 // calls initialize on the new decoder. | 149 // calls initialize on the new decoder. |
| 149 void InitializeNextDecoder(const scoped_refptr<DemuxerStream>& demuxer_stream, | 150 void InitializeNextDecoder(const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 150 scoped_ptr<VideoDecoderList> decoders); | 151 scoped_ptr<VideoDecoderList> decoders); |
| 151 | 152 |
| 152 // Called when |decoder_| initialization completes. | 153 // Called when |decoder_| initialization completes. |
| 153 // |demuxer_stream| & |decoders| are used if initialization failed and | 154 // |demuxer_stream| & |decoders| are used if initialization failed and |
| 154 // InitializeNextDecoder() needs to be called again. | 155 // InitializeNextDecoder() needs to be called again. |
| 155 void OnDecoderInitDone(const scoped_refptr<DemuxerStream>& demuxer_stream, | 156 void OnDecoderInitDone(const scoped_refptr<DemuxerStream>& demuxer_stream, |
| 156 scoped_ptr<VideoDecoderList> decoders, | 157 scoped_ptr<VideoDecoderList> decoders, |
| 157 PipelineStatus status); | 158 PipelineStatus status); |
| 158 | 159 |
| 159 scoped_refptr<base::MessageLoopProxy> message_loop_; | 160 scoped_refptr<base::MessageLoopProxy> message_loop_; |
| 160 base::WeakPtrFactory<VideoRendererBase> weak_factory_; | |
| 161 base::WeakPtr<VideoRendererBase> weak_this_; | |
| 162 | 161 |
| 163 // Used for accessing data members. | 162 // Used for accessing data members. |
| 164 base::Lock lock_; | 163 base::Lock lock_; |
| 165 | 164 |
| 166 SetDecryptorReadyCB set_decryptor_ready_cb_; | 165 SetDecryptorReadyCB set_decryptor_ready_cb_; |
| 167 | 166 |
| 168 // These two will be set by VideoDecoderSelector::SelectVideoDecoder(). | 167 // These two will be set by VideoDecoderSelector::SelectVideoDecoder(). |
| 169 scoped_refptr<VideoDecoder> decoder_; | 168 scoped_refptr<VideoDecoder> decoder_; |
| 170 scoped_refptr<DecryptingDemuxerStream> decrypting_demuxer_stream_; | 169 scoped_refptr<DecryptingDemuxerStream> decrypting_demuxer_stream_; |
| 171 | 170 |
| 172 // Queue of incoming frames yet to be painted. | 171 // Queue of incoming frames as well as the current frame since the last time |
| 172 // OnFrameAvailable() was called. |
| 173 typedef std::deque<scoped_refptr<VideoFrame> > VideoFrameQueue; | 173 typedef std::deque<scoped_refptr<VideoFrame> > VideoFrameQueue; |
| 174 VideoFrameQueue ready_frames_; | 174 VideoFrameQueue ready_frames_; |
| 175 | 175 |
| 176 // The current frame available to subclasses for rendering via |
| 177 // GetCurrentFrame(). |current_frame_| can only be altered when |
| 178 // |pending_paint_| is false. |
| 179 scoped_refptr<VideoFrame> current_frame_; |
| 180 |
| 181 // The previous |current_frame_| and is returned via GetCurrentFrame() in the |
| 182 // situation where all frames were deallocated (i.e., during a flush). |
| 183 // |
| 184 // TODO(scherkus): remove this after getting rid of Get/PutCurrentFrame() in |
| 185 // favour of passing ownership of the current frame to the renderer via |
| 186 // callback. |
| 187 scoped_refptr<VideoFrame> last_available_frame_; |
| 188 |
| 176 // Used to signal |thread_| as frames are added to |frames_|. Rule of thumb: | 189 // Used to signal |thread_| as frames are added to |frames_|. Rule of thumb: |
| 177 // always check |state_| to see if it was set to STOPPED after waking up! | 190 // always check |state_| to see if it was set to STOPPED after waking up! |
| 178 base::ConditionVariable frame_available_; | 191 base::ConditionVariable frame_available_; |
| 179 | 192 |
| 180 // State transition Diagram of this class: | 193 // State transition Diagram of this class: |
| 181 // [kUninitialized] -------> [kError] | 194 // [kUninitialized] -------> [kError] |
| 182 // | | 195 // | |
| 183 // | Initialize() | 196 // | Initialize() |
| 184 // V All frames returned | 197 // V All frames returned |
| 185 // +------[kFlushed]<-----[kFlushing]<--- OnDecoderResetDone() | 198 // +------[kFlushed]<-----[kFlushing]<--- OnDecoderResetDone() |
| (...skipping 26 matching lines...) Expand all Loading... |
| 212 kPlaying, | 225 kPlaying, |
| 213 kEnded, | 226 kEnded, |
| 214 kStopped, | 227 kStopped, |
| 215 kError, | 228 kError, |
| 216 }; | 229 }; |
| 217 State state_; | 230 State state_; |
| 218 | 231 |
| 219 // Video thread handle. | 232 // Video thread handle. |
| 220 base::PlatformThreadHandle thread_; | 233 base::PlatformThreadHandle thread_; |
| 221 | 234 |
| 222 // Keep track of outstanding reads on the video decoder. Flushing can only | 235 // Keep track of various pending operations: |
| 223 // complete once reads have completed. | 236 // - |pending_read_| is true when there's an active video decoding request. |
| 237 // - |pending_paint_| is true when |current_frame_| is currently being |
| 238 // accessed by the subclass. |
| 239 // - |pending_paint_with_last_available_| is true when |
| 240 // |last_available_frame_| is currently being accessed by the subclass. |
| 241 // |
| 242 // Flushing cannot complete until both |pending_read_| and |pending_paint_| |
| 243 // are false. |
| 224 bool pending_read_; | 244 bool pending_read_; |
| 245 bool pending_paint_; |
| 246 bool pending_paint_with_last_available_; |
| 225 | 247 |
| 226 bool drop_frames_; | 248 bool drop_frames_; |
| 227 | 249 |
| 228 float playback_rate_; | 250 float playback_rate_; |
| 229 | 251 |
| 230 // Playback operation callbacks. | 252 // Playback operation callbacks. |
| 231 base::Closure flush_cb_; | 253 base::Closure flush_cb_; |
| 232 PipelineStatusCB preroll_cb_; | 254 PipelineStatusCB preroll_cb_; |
| 233 | 255 |
| 234 // Event callbacks. | 256 // Event callbacks. |
| 235 PipelineStatusCB init_cb_; | 257 PipelineStatusCB init_cb_; |
| 236 StatisticsCB statistics_cb_; | 258 StatisticsCB statistics_cb_; |
| 237 TimeCB max_time_cb_; | 259 TimeCB max_time_cb_; |
| 238 NaturalSizeChangedCB size_changed_cb_; | 260 NaturalSizeChangedCB size_changed_cb_; |
| 239 base::Closure ended_cb_; | 261 base::Closure ended_cb_; |
| 240 PipelineStatusCB error_cb_; | 262 PipelineStatusCB error_cb_; |
| 241 TimeDeltaCB get_time_cb_; | 263 TimeDeltaCB get_time_cb_; |
| 242 TimeDeltaCB get_duration_cb_; | 264 TimeDeltaCB get_duration_cb_; |
| 243 | 265 |
| 244 base::TimeDelta preroll_timestamp_; | 266 base::TimeDelta preroll_timestamp_; |
| 245 | 267 |
| 246 // Delayed frame used during kPrerolling to determine whether | 268 // Delayed frame used during kPrerolling to determine whether |
| 247 // |preroll_timestamp_| is between this frame and the next one. | 269 // |preroll_timestamp_| is between this frame and the next one. |
| 248 scoped_refptr<VideoFrame> prerolling_delayed_frame_; | 270 scoped_refptr<VideoFrame> prerolling_delayed_frame_; |
| 249 | 271 |
| 250 // Embedder callback for notifying a new frame is available for painting. | 272 // Embedder callback for notifying a new frame is available for painting. |
| 251 PaintCB paint_cb_; | 273 base::Closure paint_cb_; |
| 252 | 274 |
| 253 // Callback to execute to inform the player if the video decoder's output is | 275 // Callback to execute to inform the player if the video decoder's output is |
| 254 // opaque. | 276 // opaque. |
| 255 SetOpaqueCB set_opaque_cb_; | 277 SetOpaqueCB set_opaque_cb_; |
| 256 | 278 |
| 257 // The last natural size |size_changed_cb_| was called with. | 279 // The last natural size |size_changed_cb_| was called with. |
| 258 // | |
| 259 // TODO(scherkus): WebMediaPlayerImpl should track this instead of plumbing | |
| 260 // this through Pipeline. The one tricky bit might be guaranteeing we deliver | |
| 261 // the size information before we reach HAVE_METADATA. | |
| 262 gfx::Size last_natural_size_; | 280 gfx::Size last_natural_size_; |
| 263 | 281 |
| 264 // The timestamp of the last frame removed from the |ready_frames_| queue, | |
| 265 // either for calling |paint_cb_| or for dropping. Set to kNoTimestamp() | |
| 266 // during flushing. | |
| 267 base::TimeDelta last_timestamp_; | |
| 268 | |
| 269 DISALLOW_COPY_AND_ASSIGN(VideoRendererBase); | 282 DISALLOW_COPY_AND_ASSIGN(VideoRendererBase); |
| 270 }; | 283 }; |
| 271 | 284 |
| 272 } // namespace media | 285 } // namespace media |
| 273 | 286 |
| 274 #endif // MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ | 287 #endif // MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ |
| OLD | NEW |