// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this // source code is governed by a BSD-style license that can be found in the // LICENSE file. // VideoRendererBase creates its own thread for the sole purpose of timing frame // presentation. It handles reading from the decoder and stores the results in // a queue of decoded frames, calling OnFrameAvailable() on subclasses to notify // when a frame is ready to display. // // The media filter methods Initialize(), Stop(), SetPlaybackRate() and Seek() // should be serialized, which they commonly are the pipeline thread. // As long as VideoRendererBase is initialized, GetCurrentFrame() is safe to // call from any thread, at any time, including inside of OnFrameAvailable(). #ifndef MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ #define MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_ #include #include "base/condition_variable.h" #include "base/lock.h" #include "media/base/filters.h" namespace media { // TODO(scherkus): to avoid subclasses, consider using a peer/delegate interface // and pass in a reference to the constructor. class VideoRendererBase : public VideoRenderer, public PlatformThread::Delegate { public: VideoRendererBase(); virtual ~VideoRendererBase(); // Helper method for subclasses to parse out video-related information from // a MediaFormat. Returns true if |width_out| and |height_out| were assigned. static bool ParseMediaFormat(const MediaFormat& media_format, int* width_out, int* height_out); // MediaFilter implementation. virtual void Play(FilterCallback* callback); virtual void Pause(FilterCallback* callback); virtual void Stop(); virtual void SetPlaybackRate(float playback_rate); virtual void Seek(base::TimeDelta time, FilterCallback* callback); // VideoRenderer implementation. virtual void Initialize(VideoDecoder* decoder, FilterCallback* callback); virtual bool HasEnded(); // PlatformThread::Delegate implementation. virtual void ThreadMain(); // Assigns the current frame, which will never be NULL as long as this filter // is initialized. void GetCurrentFrame(scoped_refptr* frame_out); protected: // Subclass interface. Called before any other initialization in the base // class takes place. // // Implementors typically use the media format of |decoder| to create their // output surfaces. Implementors should NOT call InitializationComplete(). virtual bool OnInitialize(VideoDecoder* decoder) = 0; // Subclass interface. Called before any other stopping actions takes place. // // Implementors should perform any necessary cleanup before returning. virtual void OnStop() = 0; // Subclass interface. Called when a new frame is ready for display, which // can be accessed via GetCurrentFrame(). // // Implementors should avoid doing any sort of heavy work in this method and // instead post a task to a common/worker thread to handle rendering. Slowing // down the video thread may result in losing synchronization with audio. virtual void OnFrameAvailable() = 0; private: // Read complete callback from video decoder and decrements |pending_reads_|. void OnReadComplete(VideoFrame* frame); // Helper method that schedules an asynchronous read from the decoder and // increments |pending_reads_|. // // Safe to call from any thread. void ScheduleRead_Locked(); // Calculates the duration to sleep for based on |current_frame_|'s timestamp, // the next frame timestamp (may be NULL), and the provided playback rate. // // We don't use |playback_rate_| to avoid locking. base::TimeDelta CalculateSleepDuration(VideoFrame* next_frame, float playback_rate); // Used for accessing data members. Lock lock_; scoped_refptr decoder_; // Video dimensions parsed from the decoder's media format. int width_; int height_; // Queue of incoming frames as well as the current frame since the last time // OnFrameAvailable() was called. typedef std::deque< scoped_refptr > VideoFrameQueue; VideoFrameQueue frames_; scoped_refptr current_frame_; // Used to signal |thread_| as frames are added to |frames_|. Rule of thumb: // always check |state_| to see if it was set to STOPPED after waking up! ConditionVariable frame_available_; // Simple state tracking variable. enum State { kUninitialized, kPaused, kSeeking, kPlaying, kEnded, kStopped, kError, }; State state_; // Video thread handle. PlatformThreadHandle thread_; // Previous time returned from the pipeline. base::TimeDelta previous_time_; // Keeps track of our pending reads. We *must* have no pending reads before // executing the pause callback, otherwise we breach the contract that all // filters are idling. // // We use size_t since we compare against std::deque::size(). size_t pending_reads_; float playback_rate_; // Filter callbacks. scoped_ptr pause_callback_; scoped_ptr seek_callback_; DISALLOW_COPY_AND_ASSIGN(VideoRendererBase); }; } // namespace media #endif // MEDIA_FILTERS_VIDEO_RENDERER_BASE_H_