Home | History | Annotate | Download | only in filters
      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
      3 // found in the LICENSE file.
      4 
      5 #ifndef MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_
      6 #define MEDIA_FILTERS_VIDEO_RENDERER_BASE_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 
     24 namespace base {
     25 class MessageLoopProxy;
     26 }
     27 
     28 namespace media {
     29 
     30 // VideoRendererBase 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.
     34 class MEDIA_EXPORT VideoRendererBase
     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   VideoRendererBase(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 ~VideoRendererBase();
     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   scoped_refptr<base::MessageLoopProxy> message_loop_;
    133   base::WeakPtrFactory<VideoRendererBase> weak_factory_;
    134   base::WeakPtr<VideoRendererBase> weak_this_;
    135 
    136   // Used for accessing data members.
    137   base::Lock lock_;
    138 
    139   // Provides video frames to VideoRendererBase.
    140   VideoFrameStream video_frame_stream_;
    141 
    142   // Queue of incoming frames yet to be painted.
    143   typedef std::deque<scoped_refptr<VideoFrame> > VideoFrameQueue;
    144   VideoFrameQueue ready_frames_;
    145 
    146   // Keeps track of whether we received the end of stream buffer.
    147   bool received_end_of_stream_;
    148 
    149   // Used to signal |thread_| as frames are added to |frames_|.  Rule of thumb:
    150   // always check |state_| to see if it was set to STOPPED after waking up!
    151   base::ConditionVariable frame_available_;
    152 
    153   // State transition Diagram of this class:
    154   //       [kUninitialized] -------> [kError]
    155   //              |
    156   //              | Initialize()
    157   //        [kInitializing]
    158   //              |
    159   //              V
    160   //   +------[kFlushed]<---------------OnVideoFrameStreamResetDone()
    161   //   |          | Preroll() or upon               ^
    162   //   |          V got first frame            [kFlushing]
    163   //   |      [kPrerolling]                         ^
    164   //   |          |                                 | Flush()
    165   //   |          V Got enough frames               |
    166   //   |      [kPrerolled]---------------------->[kPaused]
    167   //   |          |                Pause()          ^
    168   //   |          V Play()                          |
    169   //   |       [kPlaying]---------------------------|
    170   //   |          |                Pause()          ^
    171   //   |          V Receive EOF frame.              | Pause()
    172   //   |       [kEnded]-----------------------------+
    173   //   |                                            ^
    174   //   |                                            |
    175   //   +-----> [kStopped]                 [Any state other than]
    176   //                                      [kUninitialized/kError]
    177 
    178   // Simple state tracking variable.
    179   enum State {
    180     kUninitialized,
    181     kInitializing,
    182     kPrerolled,
    183     kPaused,
    184     kFlushing,
    185     kFlushed,
    186     kPrerolling,
    187     kPlaying,
    188     kEnded,
    189     kStopped,
    190     kError,
    191   };
    192   State state_;
    193 
    194   // Video thread handle.
    195   base::PlatformThreadHandle thread_;
    196 
    197   // Keep track of the outstanding read on the VideoFrameStream. Flushing can
    198   // only complete once the read has completed.
    199   bool pending_read_;
    200 
    201   bool drop_frames_;
    202 
    203   float playback_rate_;
    204 
    205   // Playback operation callbacks.
    206   base::Closure flush_cb_;
    207   PipelineStatusCB preroll_cb_;
    208 
    209   // Event callbacks.
    210   PipelineStatusCB init_cb_;
    211   StatisticsCB statistics_cb_;
    212   TimeCB max_time_cb_;
    213   NaturalSizeChangedCB size_changed_cb_;
    214   base::Closure ended_cb_;
    215   PipelineStatusCB error_cb_;
    216   TimeDeltaCB get_time_cb_;
    217   TimeDeltaCB get_duration_cb_;
    218 
    219   base::TimeDelta preroll_timestamp_;
    220 
    221   // Embedder callback for notifying a new frame is available for painting.
    222   PaintCB paint_cb_;
    223 
    224   // Callback to execute to inform the player if the decoded output is opaque.
    225   SetOpaqueCB set_opaque_cb_;
    226 
    227   // The last natural size |size_changed_cb_| was called with.
    228   //
    229   // TODO(scherkus): WebMediaPlayerImpl should track this instead of plumbing
    230   // this through Pipeline. The one tricky bit might be guaranteeing we deliver
    231   // the size information before we reach HAVE_METADATA.
    232   gfx::Size last_natural_size_;
    233 
    234   // The timestamp of the last frame removed from the |ready_frames_| queue,
    235   // either for calling |paint_cb_| or for dropping. Set to kNoTimestamp()
    236   // during flushing.
    237   base::TimeDelta last_timestamp_;
    238 
    239   DISALLOW_COPY_AND_ASSIGN(VideoRendererBase);
    240 };
    241 
    242 }  // namespace media
    243 
    244 #endif  // MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_
    245