diff options
Diffstat (limited to 'chromium/media/base/android/media_decoder_job.h')
-rw-r--r-- | chromium/media/base/android/media_decoder_job.h | 245 |
1 files changed, 193 insertions, 52 deletions
diff --git a/chromium/media/base/android/media_decoder_job.h b/chromium/media/base/android/media_decoder_job.h index 6ee086dea03..433e0359529 100644 --- a/chromium/media/base/android/media_decoder_job.h +++ b/chromium/media/base/android/media_decoder_job.h @@ -10,15 +10,21 @@ #include "base/time/time.h" #include "media/base/android/demuxer_stream_player_params.h" #include "media/base/android/media_codec_bridge.h" +#include "ui/gl/android/scoped_java_surface.h" namespace base { -class MessageLoopProxy; +class SingleThreadTaskRunner; } namespace media { +class MediaDrmBridge; + // Class for managing all the decoding tasks. Each decoding task will be posted // onto the same thread. The thread will be stopped once Stop() is called. +// Data is stored in 2 chunks. When new data arrives, it is always stored in +// an inactive chunk. And when the current active chunk becomes empty, a new +// data request will be sent to the renderer. class MediaDecoderJob { public: struct Deleter { @@ -26,15 +32,18 @@ class MediaDecoderJob { }; // Callback when a decoder job finishes its work. Args: whether decode - // finished successfully, presentation time, audio output bytes. - // If the presentation time is equal to kNoTimestamp(), the decoder job - // skipped rendering of the decoded output and the callback target should - // update its clock to avoid introducing extra delays to the next frame. - typedef base::Callback<void(MediaCodecStatus, const base::TimeDelta&, - size_t)> DecoderCallback; + // finished successfully, current presentation time, max presentation time. + // If the current presentation time is equal to kNoTimestamp(), the decoder + // job skipped rendering of the decoded output and the callback target should + // ignore the timestamps provided. + typedef base::Callback<void(MediaCodecStatus, base::TimeDelta, + base::TimeDelta)> DecoderCallback; // Callback when a decoder job finishes releasing the output buffer. - // Args: audio output bytes, must be 0 for video. - typedef base::Callback<void(size_t)> ReleaseOutputCompletionCallback; + // Args: current presentation time, max presentation time. + // If the current presentation time is equal to kNoTimestamp(), the callback + // target should ignore the timestamps provided. + typedef base::Callback<void(base::TimeDelta, base::TimeDelta)> + ReleaseOutputCompletionCallback; virtual ~MediaDecoderJob(); @@ -50,10 +59,10 @@ class MediaDecoderJob { // // Returns true if the next decode was started and |callback| will be // called when the decode operation is complete. - // Returns false if a config change is needed. |callback| is ignored - // and will not be called. - bool Decode(const base::TimeTicks& start_time_ticks, - const base::TimeDelta& start_presentation_timestamp, + // Returns false if |media_codec_bridge_| cannot be created; |callback| is + // ignored and will not be called. + bool Decode(base::TimeTicks start_time_ticks, + base::TimeDelta start_presentation_timestamp, const DecoderCallback& callback); // Called to stop the last Decode() early. @@ -66,20 +75,42 @@ class MediaDecoderJob { // reflects whether data was actually decoded or the decode terminated early. void StopDecode(); - // Flush the decoder. - void Flush(); + // Flushes the decoder and abandons all the data that is being decoded. + virtual void Flush(); + + // Enters prerolling state. The job must not currently be decoding. + void BeginPrerolling(base::TimeDelta preroll_timestamp); + + // Releases all the decoder resources as the current tab is going background. + virtual void ReleaseDecoderResources(); + + // Sets the demuxer configs. Returns true if configs has changed, or false + // otherwise. + bool SetDemuxerConfigs(const DemuxerConfigs& configs); + + // Returns whether the decoder has finished decoding all the data. + bool OutputEOSReached() const; - // Enter prerolling state. The job must not currently be decoding. - void BeginPrerolling(const base::TimeDelta& preroll_timestamp); + // Returns true if the audio/video stream is available, implemented by child + // classes. + virtual bool HasStream() const = 0; - bool prerolling() const { return prerolling_; } + void SetDrmBridge(MediaDrmBridge* drm_bridge); bool is_decoding() const { return !decode_cb_.is_null(); } + bool is_content_encrypted() const { return is_content_encrypted_; } + protected: - MediaDecoderJob(const scoped_refptr<base::MessageLoopProxy>& decoder_loop, - MediaCodecBridge* media_codec_bridge, - const base::Closure& request_data_cb); + // Creates a new MediaDecoderJob instance. + // |decoder_task_runner| - Thread on which the decoder task will run. + // |request_data_cb| - Callback to request more data for the decoder. + // |config_changed_cb| - Callback to inform the caller that + // demuxer config has changed. + MediaDecoderJob( + const scoped_refptr<base::SingleThreadTaskRunner>& decoder_task_runner, + const base::Closure& request_data_cb, + const base::Closure& config_changed_cb); // Release the output buffer at index |output_buffer_index| and render it if // |render_output| is true. Upon completion, |callback| will be called. @@ -87,16 +118,36 @@ class MediaDecoderJob { int output_buffer_index, size_t size, bool render_output, + base::TimeDelta current_presentation_timestamp, const ReleaseOutputCompletionCallback& callback) = 0; // Returns true if the "time to render" needs to be computed for frames in // this decoder job. virtual bool ComputeTimeToRender() const = 0; + // Gets MediaCrypto object from |drm_bridge_|. + base::android::ScopedJavaLocalRef<jobject> GetMediaCrypto(); + + // Releases the |media_codec_bridge_|. + void ReleaseMediaCodecBridge(); + + MediaDrmBridge* drm_bridge() { return drm_bridge_; } + + void set_is_content_encrypted(bool is_content_encrypted) { + is_content_encrypted_ = is_content_encrypted; + } + + bool need_to_reconfig_decoder_job_; + + scoped_ptr<MediaCodecBridge> media_codec_bridge_; + private: + friend class MediaSourcePlayerTest; + // Causes this instance to be deleted on the thread it is bound to. void Release(); + // Queues an access unit into |media_codec_bridge_|'s input buffer. MediaCodecStatus QueueInputBuffer(const AccessUnit& unit); // Returns true if this object has data to decode. @@ -106,20 +157,25 @@ class MediaDecoderJob { // |done_cb| is called when more data is available in |received_data_|. void RequestData(const base::Closure& done_cb); - // Posts a task to start decoding the next access unit in |received_data_|. - void DecodeNextAccessUnit( - const base::TimeTicks& start_time_ticks, - const base::TimeDelta& start_presentation_timestamp); - - // Helper function to decoder data on |thread_|. |unit| contains all the data - // to be decoded. |start_time_ticks| and |start_presentation_timestamp| - // represent the system time and the presentation timestamp when the first - // frame is rendered. We use these information to estimate when the current - // frame should be rendered. If |needs_flush| is true, codec needs to be - // flushed at the beginning of this call. + // Posts a task to start decoding the current access unit in |received_data_|. + void DecodeCurrentAccessUnit( + base::TimeTicks start_time_ticks, + base::TimeDelta start_presentation_timestamp); + + // Helper function to decode data on |decoder_task_runner_|. |unit| contains + // the data to be decoded. |start_time_ticks| and + // |start_presentation_timestamp| represent the system time and the + // presentation timestamp when the first frame is rendered. We use these + // information to estimate when the current frame should be rendered. + // If |needs_flush| is true, codec needs to be flushed at the beginning of + // this call. + // It is possible that |stop_decode_pending_| or |release_resources_pending_| + // becomes true while DecodeInternal() is called. However, they should have + // no impact on DecodeInternal(). They will be handled after DecoderInternal() + // finishes and OnDecodeCompleted() is posted on the UI thread. void DecodeInternal(const AccessUnit& unit, - const base::TimeTicks& start_time_ticks, - const base::TimeDelta& start_presentation_timestamp, + base::TimeTicks start_time_ticks, + base::TimeDelta start_presentation_timestamp, bool needs_flush, const DecoderCallback& callback); @@ -127,18 +183,69 @@ class MediaDecoderJob { // Completes any pending job destruction or any pending decode stop. If // destruction was not pending, passes its arguments to |decode_cb_|. void OnDecodeCompleted(MediaCodecStatus status, - const base::TimeDelta& presentation_timestamp, - size_t audio_output_bytes); + base::TimeDelta current_presentation_timestamp, + base::TimeDelta max_presentation_timestamp); - // The UI message loop where callbacks should be dispatched. - scoped_refptr<base::MessageLoopProxy> ui_loop_; + // Helper function to get the current access unit that is being decoded. + const AccessUnit& CurrentAccessUnit() const; + + // Helper function to get the current data chunk index that is being decoded. + size_t CurrentReceivedDataChunkIndex() const; + + // Check whether a chunk has no remaining access units to decode. If + // |is_active_chunk| is true, this function returns whether decoder has + // consumed all data in |received_data_[current_demuxer_data_index_]|. + // Otherwise, it returns whether decoder has consumed all data in the inactive + // chunk. + bool NoAccessUnitsRemainingInChunk(bool is_active_chunk) const; + + // Requests new data for the current chunk if it runs out of data. + void RequestCurrentChunkIfEmpty(); + + // Initializes |received_data_| and |access_unit_index_|. + void InitializeReceivedData(); + + // Called when the decoder is completely drained and is ready to be released. + void OnDecoderDrained(); + + // Creates |media_codec_bridge_| for decoding purpose. Returns true if it is + // created, or false otherwise. + bool CreateMediaCodecBridge(); - // The message loop that decoder job runs on. - scoped_refptr<base::MessageLoopProxy> decoder_loop_; + // Called when an access unit is consumed by the decoder. |is_config_change| + // indicates whether the current access unit is a config change. If it is + // true, the next access unit is guarateed to be an I-frame. + virtual void CurrentDataConsumed(bool is_config_change) {} - // The media codec bridge used for decoding. Owned by derived class. - // NOTE: This MUST NOT be accessed in the destructor. - MediaCodecBridge* media_codec_bridge_; + // Called when |media_codec_bridge_| is released + virtual void OnMediaCodecBridgeReleased() {} + + // Implemented by the child class to create |media_codec_bridge_| for a + // particular stream. Returns true if it is created, or false otherwise. + virtual bool CreateMediaCodecBridgeInternal() = 0; + + // Returns true if the |configs| doesn't match the current demuxer configs + // the decoder job has. + virtual bool AreDemuxerConfigsChanged( + const DemuxerConfigs& configs) const = 0; + + // Updates the demuxer configs. + virtual void UpdateDemuxerConfigs(const DemuxerConfigs& configs) = 0; + + // Returns true if |media_codec_bridge_| needs to be reconfigured for the + // new DemuxerConfigs, or false otherwise. + virtual bool IsCodecReconfigureNeeded(const DemuxerConfigs& configs) const; + + // Return the index to |received_data_| that is not currently being decoded. + size_t inactive_demuxer_data_index() const { + return 1 - current_demuxer_data_index_; + } + + // The UI message loop where callbacks should be dispatched. + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; + + // The task runner that decoder job runs on. + scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner_; // Whether the decoder needs to be flushed. bool needs_flush_; @@ -169,29 +276,41 @@ class MediaDecoderJob { // is not very accurate. bool prerolling_; - // Weak pointer passed to media decoder jobs for callbacks. It is bounded to - // the decoder thread. - base::WeakPtrFactory<MediaDecoderJob> weak_this_; - // Callback used to request more data. base::Closure request_data_cb_; + // Callback to notify the caller config has changed. + base::Closure config_changed_cb_; + // Callback to run when new data has been received. - base::Closure on_data_received_cb_; + base::Closure data_received_cb_; // Callback to run when the current Decode() operation completes. DecoderCallback decode_cb_; - // The current access unit being processed. - size_t access_unit_index_; - // Data received over IPC from last RequestData() operation. - DemuxerData received_data_; + // We keep 2 chunks at the same time to reduce the IPC latency between chunks. + // If data inside the current chunk are all decoded, we will request a new + // chunk from the demuxer and swap the current chunk with the other one. + // New data will always be stored in the other chunk since the current + // one may be still in use. + DemuxerData received_data_[2]; + + // Index to the current data chunk that is being decoded. + size_t current_demuxer_data_index_; + + // Index to the access unit inside each data chunk that is being decoded. + size_t access_unit_index_[2]; // The index of input buffer that can be used by QueueInputBuffer(). // If the index is uninitialized or invalid, it must be -1. int input_buf_index_; + // Indicates whether content is encrypted. + bool is_content_encrypted_; + + // Indicates the decoder job should stop after decoding the current access + // unit. bool stop_decode_pending_; // Indicates that this object should be destroyed once the current @@ -199,6 +318,28 @@ class MediaDecoderJob { // while there is a decode in progress. bool destroy_pending_; + // Indicates whether the decoder is in the middle of requesting new data. + bool is_requesting_demuxer_data_; + + // Indicates whether the incoming data should be ignored. + bool is_incoming_data_invalid_; + + // Indicates that |media_codec_bridge_| should be released once the current + // Decode() has completed. This gets set when ReleaseDecoderResources() gets + // called while there is a decode in progress. + bool release_resources_pending_; + + // Pointer to a DRM object that will be used for encrypted streams. + MediaDrmBridge* drm_bridge_; + + // Indicates whether |media_codec_bridge_| is in the middle of being drained + // due to a config change. + bool drain_decoder_; + + // This access unit is passed to the decoder during config changes to drain + // the decoder. + AccessUnit eos_unit_; + DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDecoderJob); }; |