1 // Copyright 2013 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.
5 #ifndef MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
6 #define MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
8 #include "base/callback.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/time/time.h"
11 #include "media/base/android/demuxer_stream_player_params.h"
12 #include "media/base/android/media_codec_bridge.h"
13 #include "ui/gl/android/scoped_java_surface.h"
16 class SingleThreadTaskRunner
;
23 // Class for managing all the decoding tasks. Each decoding task will be posted
24 // onto the same thread. The thread will be stopped once Stop() is called.
25 // Data is stored in 2 chunks. When new data arrives, it is always stored in
26 // an inactive chunk. And when the current active chunk becomes empty, a new
27 // data request will be sent to the renderer.
28 class MediaDecoderJob
{
30 // Return value when Decode() is called.
31 enum MediaDecoderJobStatus
{
33 STATUS_KEY_FRAME_REQUIRED
,
38 inline void operator()(MediaDecoderJob
* ptr
) const { ptr
->Release(); }
41 // Callback when a decoder job finishes its work. Args: whether decode
42 // finished successfully, current presentation time, max presentation time.
43 // If the current presentation time is equal to kNoTimestamp(), the decoder
44 // job skipped rendering of the decoded output and the callback target should
45 // ignore the timestamps provided.
46 typedef base::Callback
<void(MediaCodecStatus
, base::TimeDelta
,
47 base::TimeDelta
)> DecoderCallback
;
48 // Callback when a decoder job finishes releasing the output buffer.
49 // Args: current presentation time, max presentation time.
50 // If the current presentation time is equal to kNoTimestamp(), the callback
51 // target should ignore the timestamps provided.
52 typedef base::Callback
<void(base::TimeDelta
, base::TimeDelta
)>
53 ReleaseOutputCompletionCallback
;
55 virtual ~MediaDecoderJob();
57 // Called by MediaSourcePlayer when more data for this object has arrived.
58 void OnDataReceived(const DemuxerData
& data
);
60 // Prefetch so we know the decoder job has data when we call Decode().
61 // |prefetch_cb| - Run when prefetching has completed.
62 void Prefetch(const base::Closure
& prefetch_cb
);
64 // Called by MediaSourcePlayer to decode some data.
65 // |callback| - Run when decode operation has completed.
67 // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
68 // STATUS_KEY_FRAME_REQUIRED if a browser seek is required. |callback| is
69 // ignored and will not be called for the latter 2 cases.
70 MediaDecoderJobStatus
Decode(base::TimeTicks start_time_ticks
,
71 base::TimeDelta start_presentation_timestamp
,
72 const DecoderCallback
& callback
);
74 // Called to stop the last Decode() early.
75 // If the decoder is in the process of decoding the next frame, then
76 // this method will just allow the decode to complete as normal. If
77 // this object is waiting for a data request to complete, then this method
78 // will wait for the data to arrive and then call the |callback|
79 // passed to Decode() with a status of MEDIA_CODEC_ABORT. This ensures that
80 // the |callback| passed to Decode() is always called and the status
81 // reflects whether data was actually decoded or the decode terminated early.
84 // Flushes the decoder and abandons all the data that is being decoded.
87 // Enters prerolling state. The job must not currently be decoding.
88 void BeginPrerolling(base::TimeDelta preroll_timestamp
);
90 // Releases all the decoder resources as the current tab is going background.
91 virtual void ReleaseDecoderResources();
93 // Sets the demuxer configs.
94 virtual void SetDemuxerConfigs(const DemuxerConfigs
& configs
) = 0;
96 // Returns whether the decoder has finished decoding all the data.
97 bool OutputEOSReached() const;
99 // Returns true if the audio/video stream is available, implemented by child
101 virtual bool HasStream() const = 0;
103 void SetDrmBridge(MediaDrmBridge
* drm_bridge
);
105 bool is_decoding() const { return !decode_cb_
.is_null(); }
107 bool is_content_encrypted() const { return is_content_encrypted_
; }
109 bool prerolling() const { return prerolling_
; }
112 // Creates a new MediaDecoderJob instance.
113 // |decoder_task_runner| - Thread on which the decoder task will run.
114 // |request_data_cb| - Callback to request more data for the decoder.
115 // |config_changed_cb| - Callback to inform the caller that
116 // demuxer config has changed.
118 const scoped_refptr
<base::SingleThreadTaskRunner
>& decoder_task_runner
,
119 const base::Closure
& request_data_cb
,
120 const base::Closure
& config_changed_cb
);
122 // Release the output buffer at index |output_buffer_index| and render it if
123 // |render_output| is true. Upon completion, |callback| will be called.
124 virtual void ReleaseOutputBuffer(
125 int output_buffer_index
,
129 base::TimeDelta current_presentation_timestamp
,
130 const ReleaseOutputCompletionCallback
& callback
) = 0;
132 // Returns true if the "time to render" needs to be computed for frames in
134 virtual bool ComputeTimeToRender() const = 0;
136 // Gets MediaCrypto object from |drm_bridge_|.
137 base::android::ScopedJavaLocalRef
<jobject
> GetMediaCrypto();
139 // Releases the |media_codec_bridge_|.
140 void ReleaseMediaCodecBridge();
142 // Sets the current frame to a previously cached key frame. Returns true if
143 // a key frame is found, or false otherwise.
144 // TODO(qinmin): add UMA to study the cache hit ratio for key frames.
145 bool SetCurrentFrameToPreviouslyCachedKeyFrame();
147 MediaDrmBridge
* drm_bridge() { return drm_bridge_
; }
149 void set_is_content_encrypted(bool is_content_encrypted
) {
150 is_content_encrypted_
= is_content_encrypted
;
153 bool need_to_reconfig_decoder_job_
;
155 scoped_ptr
<MediaCodecBridge
> media_codec_bridge_
;
158 friend class MediaSourcePlayerTest
;
160 // Causes this instance to be deleted on the thread it is bound to.
163 // Queues an access unit into |media_codec_bridge_|'s input buffer.
164 MediaCodecStatus
QueueInputBuffer(const AccessUnit
& unit
);
166 // Returns true if this object has data to decode.
167 bool HasData() const;
169 // Initiates a request for more data.
170 // |done_cb| is called when more data is available in |received_data_|.
171 void RequestData(const base::Closure
& done_cb
);
173 // Posts a task to start decoding the current access unit in |received_data_|.
174 void DecodeCurrentAccessUnit(
175 base::TimeTicks start_time_ticks
,
176 base::TimeDelta start_presentation_timestamp
);
178 // Helper function to decode data on |decoder_task_runner_|. |unit| contains
179 // the data to be decoded. |start_time_ticks| and
180 // |start_presentation_timestamp| represent the system time and the
181 // presentation timestamp when the first frame is rendered. We use these
182 // information to estimate when the current frame should be rendered.
183 // If |needs_flush| is true, codec needs to be flushed at the beginning of
185 // It is possible that |stop_decode_pending_| or |release_resources_pending_|
186 // becomes true while DecodeInternal() is called. However, they should have
187 // no impact on DecodeInternal(). They will be handled after DecoderInternal()
188 // finishes and OnDecodeCompleted() is posted on the UI thread.
189 void DecodeInternal(const AccessUnit
& unit
,
190 base::TimeTicks start_time_ticks
,
191 base::TimeDelta start_presentation_timestamp
,
193 const DecoderCallback
& callback
);
195 // Called on the UI thread to indicate that one decode cycle has completed.
196 // Completes any pending job destruction or any pending decode stop. If
197 // destruction was not pending, passes its arguments to |decode_cb_|.
198 void OnDecodeCompleted(MediaCodecStatus status
,
199 base::TimeDelta current_presentation_timestamp
,
200 base::TimeDelta max_presentation_timestamp
);
202 // Helper function to get the current access unit that is being decoded.
203 const AccessUnit
& CurrentAccessUnit() const;
205 // Helper function to get the current data chunk index that is being decoded.
206 size_t CurrentReceivedDataChunkIndex() const;
208 // Check whether a chunk has no remaining access units to decode. If
209 // |is_active_chunk| is true, this function returns whether decoder has
210 // consumed all data in |received_data_[current_demuxer_data_index_]|.
211 // Otherwise, it returns whether decoder has consumed all data in the inactive
213 bool NoAccessUnitsRemainingInChunk(bool is_active_chunk
) const;
215 // Requests new data for the current chunk if it runs out of data.
216 void RequestCurrentChunkIfEmpty();
218 // Initializes |received_data_| and |access_unit_index_|.
219 void InitializeReceivedData();
221 // Called when the decoder is completely drained and is ready to be released.
222 void OnDecoderDrained();
224 // Creates |media_codec_bridge_| for decoding purpose.
225 // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
226 // STATUS_KEY_FRAME_REQUIRED if a browser seek is required.
227 MediaDecoderJobStatus
CreateMediaCodecBridge();
229 // Implemented by the child class to create |media_codec_bridge_| for a
230 // particular stream.
231 // Returns STATUS_SUCCESS on success, or STATUS_FAILURE on failure, or
232 // STATUS_KEY_FRAME_REQUIRED if a browser seek is required.
233 virtual MediaDecoderJobStatus
CreateMediaCodecBridgeInternal() = 0;
235 // Returns true if the |configs| doesn't match the current demuxer configs
236 // the decoder job has.
237 virtual bool AreDemuxerConfigsChanged(
238 const DemuxerConfigs
& configs
) const = 0;
240 // Returns true if |media_codec_bridge_| needs to be reconfigured for the
241 // new DemuxerConfigs, or false otherwise.
242 virtual bool IsCodecReconfigureNeeded(const DemuxerConfigs
& configs
) const;
244 // Signals to decoder job that decoder has updated output format. Decoder job
245 // may need to do internal reconfiguration in order to correctly interpret
247 virtual void OnOutputFormatChanged();
249 // Update the output format from the decoder, returns true if the output
250 // format changes, or false otherwise.
251 virtual bool UpdateOutputFormat();
253 // Return the index to |received_data_| that is not currently being decoded.
254 size_t inactive_demuxer_data_index() const {
255 return 1 - current_demuxer_data_index_
;
258 // The UI message loop where callbacks should be dispatched.
259 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
261 // The task runner that decoder job runs on.
262 scoped_refptr
<base::SingleThreadTaskRunner
> decoder_task_runner_
;
264 // Whether the decoder needs to be flushed.
267 // Whether input EOS is encountered.
268 // TODO(wolenetz/qinmin): Protect with a lock. See http://crbug.com/320043.
269 bool input_eos_encountered_
;
271 // Whether output EOS is encountered.
272 bool output_eos_encountered_
;
274 // Tracks whether DecodeInternal() should skip decoding if the first access
275 // unit is EOS or empty, and report |MEDIA_CODEC_OUTPUT_END_OF_STREAM|. This
276 // is to work around some decoders that could crash otherwise. See
277 // http://b/11696552.
278 bool skip_eos_enqueue_
;
280 // The timestamp the decoder needs to preroll to. If an access unit's
281 // timestamp is smaller than |preroll_timestamp_|, don't render it.
282 // TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
283 // is not very accurate.
284 base::TimeDelta preroll_timestamp_
;
286 // Indicates prerolling state. If true, this job has not yet decoded output
287 // that it will render, since the most recent of job construction or
288 // BeginPrerolling(). If false, |preroll_timestamp_| has been reached.
289 // TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
290 // is not very accurate.
293 // Callback used to request more data.
294 base::Closure request_data_cb_
;
296 // Callback to notify the caller config has changed.
297 base::Closure config_changed_cb_
;
299 // Callback to run when new data has been received.
300 base::Closure data_received_cb_
;
302 // Callback to run when the current Decode() operation completes.
303 DecoderCallback decode_cb_
;
305 // Data received over IPC from last RequestData() operation.
306 // We keep 2 chunks at the same time to reduce the IPC latency between chunks.
307 // If data inside the current chunk are all decoded, we will request a new
308 // chunk from the demuxer and swap the current chunk with the other one.
309 // New data will always be stored in the other chunk since the current
310 // one may be still in use.
311 DemuxerData received_data_
[2];
313 // Index to the current data chunk that is being decoded.
314 size_t current_demuxer_data_index_
;
316 // Index to the access unit inside each data chunk that is being decoded.
317 size_t access_unit_index_
[2];
319 // The index of input buffer that can be used by QueueInputBuffer().
320 // If the index is uninitialized or invalid, it must be -1.
321 int input_buf_index_
;
323 // Indicates whether content is encrypted.
324 bool is_content_encrypted_
;
326 // Indicates the decoder job should stop after decoding the current access
328 bool stop_decode_pending_
;
330 // Indicates that this object should be destroyed once the current
331 // Decode() has completed. This gets set when Release() gets called
332 // while there is a decode in progress.
333 bool destroy_pending_
;
335 // Indicates whether the decoder is in the middle of requesting new data.
336 bool is_requesting_demuxer_data_
;
338 // Indicates whether the incoming data should be ignored.
339 bool is_incoming_data_invalid_
;
341 // Indicates that |media_codec_bridge_| should be released once the current
342 // Decode() has completed. This gets set when ReleaseDecoderResources() gets
343 // called while there is a decode in progress.
344 bool release_resources_pending_
;
346 // Pointer to a DRM object that will be used for encrypted streams.
347 MediaDrmBridge
* drm_bridge_
;
349 // Indicates whether |media_codec_bridge_| is in the middle of being drained
350 // due to a config change.
353 // This access unit is passed to the decoder during config changes to drain
355 AccessUnit eos_unit_
;
357 DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDecoderJob
);
362 #endif // MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_