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"
15 class SingleThreadTaskRunner
;
20 // Class for managing all the decoding tasks. Each decoding task will be posted
21 // onto the same thread. The thread will be stopped once Stop() is called.
22 // Data is stored in 2 chunks. When new data arrives, it is always stored in
23 // an inactive chunk. And when the current active chunk becomes empty, a new
24 // data request will be sent to the renderer.
25 class MediaDecoderJob
{
28 inline void operator()(MediaDecoderJob
* ptr
) const { ptr
->Release(); }
31 // Callback when a decoder job finishes its work. Args: whether decode
32 // finished successfully, current presentation time, max presentation time.
33 // If the current presentation time is equal to kNoTimestamp(), the decoder
34 // job skipped rendering of the decoded output and the callback target should
35 // ignore the timestamps provided.
36 typedef base::Callback
<void(MediaCodecStatus
, base::TimeDelta
,
37 base::TimeDelta
)> DecoderCallback
;
38 // Callback when a decoder job finishes releasing the output buffer.
39 // Args: current presentation time, max presentation time.
40 // If the current presentation time is equal to kNoTimestamp(), the callback
41 // target should ignore the timestamps provided.
42 typedef base::Callback
<void(base::TimeDelta
, base::TimeDelta
)>
43 ReleaseOutputCompletionCallback
;
45 virtual ~MediaDecoderJob();
47 // Called by MediaSourcePlayer when more data for this object has arrived.
48 void OnDataReceived(const DemuxerData
& data
);
50 // Prefetch so we know the decoder job has data when we call Decode().
51 // |prefetch_cb| - Run when prefetching has completed.
52 void Prefetch(const base::Closure
& prefetch_cb
);
54 // Called by MediaSourcePlayer to decode some data.
55 // |callback| - Run when decode operation has completed.
57 // Returns true if the next decode was started and |callback| will be
58 // called when the decode operation is complete.
59 // Returns false if a config change is needed. |callback| is ignored
60 // and will not be called.
61 bool Decode(base::TimeTicks start_time_ticks
,
62 base::TimeDelta start_presentation_timestamp
,
63 const DecoderCallback
& callback
);
65 // Called to stop the last Decode() early.
66 // If the decoder is in the process of decoding the next frame, then
67 // this method will just allow the decode to complete as normal. If
68 // this object is waiting for a data request to complete, then this method
69 // will wait for the data to arrive and then call the |callback|
70 // passed to Decode() with a status of MEDIA_CODEC_STOPPED. This ensures that
71 // the |callback| passed to Decode() is always called and the status
72 // reflects whether data was actually decoded or the decode terminated early.
78 // Enter prerolling state. The job must not currently be decoding.
79 void BeginPrerolling(base::TimeDelta preroll_timestamp
);
81 bool prerolling() const { return prerolling_
; }
83 bool is_decoding() const { return !decode_cb_
.is_null(); }
85 bool is_requesting_demuxer_data() const {
86 return is_requesting_demuxer_data_
;
91 const scoped_refptr
<base::SingleThreadTaskRunner
>& decoder_task_runner
,
92 MediaCodecBridge
* media_codec_bridge
,
93 const base::Closure
& request_data_cb
);
95 // Release the output buffer at index |output_buffer_index| and render it if
96 // |render_output| is true. Upon completion, |callback| will be called.
97 virtual void ReleaseOutputBuffer(
98 int output_buffer_index
,
101 base::TimeDelta current_presentation_timestamp
,
102 const ReleaseOutputCompletionCallback
& callback
) = 0;
104 // Returns true if the "time to render" needs to be computed for frames in
106 virtual bool ComputeTimeToRender() const = 0;
109 friend class MediaSourcePlayerTest
;
111 // Causes this instance to be deleted on the thread it is bound to.
114 MediaCodecStatus
QueueInputBuffer(const AccessUnit
& unit
);
116 // Returns true if this object has data to decode.
117 bool HasData() const;
119 // Initiates a request for more data.
120 // |done_cb| is called when more data is available in |received_data_|.
121 void RequestData(const base::Closure
& done_cb
);
123 // Posts a task to start decoding the current access unit in |received_data_|.
124 void DecodeCurrentAccessUnit(
125 base::TimeTicks start_time_ticks
,
126 base::TimeDelta start_presentation_timestamp
);
128 // Helper function to decoder data on |thread_|. |unit| contains all the data
129 // to be decoded. |start_time_ticks| and |start_presentation_timestamp|
130 // represent the system time and the presentation timestamp when the first
131 // frame is rendered. We use these information to estimate when the current
132 // frame should be rendered. If |needs_flush| is true, codec needs to be
133 // flushed at the beginning of this call.
134 void DecodeInternal(const AccessUnit
& unit
,
135 base::TimeTicks start_time_ticks
,
136 base::TimeDelta start_presentation_timestamp
,
138 const DecoderCallback
& callback
);
140 // Called on the UI thread to indicate that one decode cycle has completed.
141 // Completes any pending job destruction or any pending decode stop. If
142 // destruction was not pending, passes its arguments to |decode_cb_|.
143 void OnDecodeCompleted(MediaCodecStatus status
,
144 base::TimeDelta current_presentation_timestamp
,
145 base::TimeDelta max_presentation_timestamp
);
147 // Helper function to get the current access unit that is being decoded.
148 const AccessUnit
& CurrentAccessUnit() const;
150 // Check whether a chunk has no remaining access units to decode. If
151 // |is_active_chunk| is true, this function returns whether decoder has
152 // consumed all data in |received_data_[current_demuxer_data_index_]|.
153 // Otherwise, it returns whether decoder has consumed all data in the inactive
155 bool NoAccessUnitsRemainingInChunk(bool is_active_chunk
) const;
157 // Clearn all the received data.
160 // Request new data for the current chunk if it runs out of data.
161 void RequestCurrentChunkIfEmpty();
163 // Initialize |received_data_| and |access_unit_index_|.
164 void InitializeReceivedData();
166 // Return the index to |received_data_| that is not currently being decoded.
167 size_t inactive_demuxer_data_index() const {
168 return 1 - current_demuxer_data_index_
;
171 // The UI message loop where callbacks should be dispatched.
172 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
174 // The task runner that decoder job runs on.
175 scoped_refptr
<base::SingleThreadTaskRunner
> decoder_task_runner_
;
177 // The media codec bridge used for decoding. Owned by derived class.
178 // NOTE: This MUST NOT be accessed in the destructor.
179 MediaCodecBridge
* media_codec_bridge_
;
181 // Whether the decoder needs to be flushed.
184 // Whether input EOS is encountered.
185 // TODO(wolenetz/qinmin): Protect with a lock. See http://crbug.com/320043.
186 bool input_eos_encountered_
;
188 // Whether output EOS is encountered.
189 bool output_eos_encountered_
;
191 // Tracks whether DecodeInternal() should skip decoding if the first access
192 // unit is EOS or empty, and report |MEDIA_CODEC_OUTPUT_END_OF_STREAM|. This
193 // is to work around some decoders that could crash otherwise. See
194 // http://b/11696552.
195 bool skip_eos_enqueue_
;
197 // The timestamp the decoder needs to preroll to. If an access unit's
198 // timestamp is smaller than |preroll_timestamp_|, don't render it.
199 // TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
200 // is not very accurate.
201 base::TimeDelta preroll_timestamp_
;
203 // Indicates prerolling state. If true, this job has not yet decoded output
204 // that it will render, since the most recent of job construction or
205 // BeginPrerolling(). If false, |preroll_timestamp_| has been reached.
206 // TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
207 // is not very accurate.
210 // Callback used to request more data.
211 base::Closure request_data_cb_
;
213 // Callback to run when new data has been received.
214 base::Closure on_data_received_cb_
;
216 // Callback to run when the current Decode() operation completes.
217 DecoderCallback decode_cb_
;
219 // Data received over IPC from last RequestData() operation.
220 // We keep 2 chunks at the same time to reduce the IPC latency between chunks.
221 // If data inside the current chunk are all decoded, we will request a new
222 // chunk from the demuxer and swap the current chunk with the other one.
223 // New data will always be stored in the other chunk since the current
224 // one may be still in use.
225 DemuxerData received_data_
[2];
227 // Index to the current data chunk that is being decoded.
228 size_t current_demuxer_data_index_
;
230 // Index to the access unit inside each data chunk that is being decoded.
231 size_t access_unit_index_
[2];
233 // The index of input buffer that can be used by QueueInputBuffer().
234 // If the index is uninitialized or invalid, it must be -1.
235 int input_buf_index_
;
237 bool stop_decode_pending_
;
239 // Indicates that this object should be destroyed once the current
240 // Decode() has completed. This gets set when Release() gets called
241 // while there is a decode in progress.
242 bool destroy_pending_
;
244 // Indicates whether the decoder is in the middle of requesting new data.
245 bool is_requesting_demuxer_data_
;
247 // Indicates whether the incoming data should be ignored.
248 bool is_incoming_data_invalid_
;
250 // Weak pointer passed to media decoder jobs for callbacks. It is bounded to
251 // the decoder thread.
252 // NOTE: Weak pointers must be invalidated before all other member variables.
253 base::WeakPtrFactory
<MediaDecoderJob
> weak_factory_
;
255 DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDecoderJob
);
260 #endif // MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_