summaryrefslogtreecommitdiffstats
path: root/chromium/media/base/android/media_decoder_job.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/base/android/media_decoder_job.h')
-rw-r--r--chromium/media/base/android/media_decoder_job.h245
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);
};