Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: media/filters/android/media_codec_audio_decoder.h

Issue 2016213003: Separate MediaCodecLoop from MediaCodecAudioDecoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl feedback. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_ 5 #ifndef MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
6 #define MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_ 6 #define MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
7 7
8 #include <deque> 8 #include <deque>
9 #include <memory> 9 #include <memory>
10 #include <utility> 10 #include <utility>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "base/timer/timer.h" 16 #include "base/timer/timer.h"
17 #include "media/base/android/media_codec_bridge.h" 17 #include "media/base/android/media_codec_bridge.h"
18 #include "media/base/android/media_codec_loop.h"
18 #include "media/base/android/media_drm_bridge_cdm_context.h" 19 #include "media/base/android/media_drm_bridge_cdm_context.h"
19 #include "media/base/audio_decoder.h" 20 #include "media/base/audio_decoder.h"
20 #include "media/base/audio_decoder_config.h" 21 #include "media/base/audio_decoder_config.h"
21 #include "media/base/media_export.h" 22 #include "media/base/media_export.h"
22 23
23 // MediaCodecAudioDecoder is based on Android's MediaCodec API. 24 // MediaCodecAudioDecoder is based on Android's MediaCodec API.
24 // The MediaCodec API is required to play encrypted (as in EME) content on 25 // The MediaCodec API is required to play encrypted (as in EME) content on
25 // Android. It is also a way to employ hardware-accelerated decoding. 26 // Android. It is also a way to employ hardware-accelerated decoding.
26 27
27 // TODO(timav): This class has the logic to manipulate the MediaCodec that is 28 // TODO(timav): This class has the logic to manipulate the MediaCodec that is
28 // the common for audio and video stream and can and should be refactored out 29 // the common for audio and video stream and can and should be refactored out
29 // (http://crbug.com/583082). 30 // (http://crbug.com/583082).
30 31
31 // Implementation notes. 32 // Implementation notes.
32 // 33 //
33 // The MediaCodec 34 // This class provides audio decoding via MediaCodec. It allocates the
34 // (http://developer.android.com/reference/android/media/MediaCodec.html) works 35 // MediaCodecBridge instance, and hands ownership to MediaCodecLoop to drive I/O
35 // by exchanging buffers between the client and the codec itself. On the input 36 // with the codec. For encrypted streams, we also talk to the DRM bridge.
36 // side an "empty" buffer has to be dequeued from the codec, filled with data
37 // and queued back. On the output side a "full" buffer with data should be
38 // dequeued, the data is to be used somehow (copied out, or rendered to a pre-
39 // defined texture for video) and the buffer has to be returned back (released).
40 // Neither input nor output dequeue operations are guaranteed to succeed: the
41 // codec might not have available input buffers yet, or not every encoded buffer
42 // has arrived to complete an output frame. In such case the client should try
43 // to dequeue a buffer again at a later time.
44 //
45 // There is also a special situation related to an encrypted stream, where the
46 // enqueuing of a filled input buffer might fail due to lack of the relevant key
47 // in the CDM module.
48 // 37 //
49 // Because both dequeuing and enqueuing of an input buffer can fail, the 38 // Because both dequeuing and enqueuing of an input buffer can fail, the
50 // implementation puts the input |DecoderBuffer|s and the corresponding decode 39 // implementation puts the input |DecoderBuffer|s and the corresponding decode
51 // callbacks into an input queue. The decoder has a timer that periodically 40 // callbacks into an input queue. The decoder has a timer that periodically
52 // fires the decoding cycle that has two steps. The first step tries to send the 41 // fires the decoding cycle that has two steps. The first step tries to send the
53 // front buffer from the input queue to the MediaCodec. In the case of success 42 // front buffer from the input queue to MediaCodecLoop. In the case of success
54 // the element is removed from the queue, the decode callback is fired and the 43 // the element is removed from the queue, the decode callback is fired and the
55 // decoding process advances. The second step tries to dequeue an output buffer, 44 // decoding process advances. The second step tries to dequeue an output buffer,
56 // and uses it in the case of success. 45 // and uses it in the case of success.
57 // 46 //
47 // An EOS buffer is handled differently. Success is not signalled to the decode
48 // callback until the EOS is received at the output. So, for EOS, the decode
49 // callback indicates that all previous decodes have completed.
50 //
58 // The failures in both steps are normal and they happen periodically since 51 // The failures in both steps are normal and they happen periodically since
59 // both input and output buffers become available at unpredictable moments. The 52 // both input and output buffers become available at unpredictable moments. The
60 // timer is here to repeat the dequeueing attempts. 53 // timer is here to repeat the dequeueing attempts.
61 // 54 //
62 // Although one can specify a delay in the MediaCodec's dequeue operations,
63 // this implementation follows the simple logic which is similar to
64 // AndroidVideoDecodeAccelerator: no delay for either input or output buffers,
65 // the processing is initated by the timer with short period (10 ms). Using no
66 // delay for enqueue operations has an extra benefit of not blocking the current
67 // thread.
68 //
69 // This implementation detects the MediaCodec idle run (no input or output
70 // buffer processing) and after being idle for a predefined time the timer
71 // stops. Every Decode() wakes the timer up.
72 //
73 // The current implementation is single threaded. Every method is supposed to
74 // run on the same thread.
75 //
76 // State diagram. 55 // State diagram.
77 // 56 //
78 // [Uninitialized] <-> (init failed) [Ready] 57 // [Uninitialized] <-> (init failed)
79 // | | 58 // | |
80 // (init succeeded) (MEDIA_CODEC_NO_KEY) 59 // (no enc.) (encrypted)
81 // | | 60 // | |
82 // [Ready] [WaitingForKey] 61 // | [WaitingForMediaCrypto] -- (OMCR failure) --> [Uninitialized]
83 // | | 62 // | | (OnMediaCryptoReady success)
84 // (EOS enqueued) (OnKeyAdded) 63 // v v
85 // | | 64 // (Create Codec and MediaCodecLoop)
86 // [Draining] [Ready] 65 // |
87 // | 66 // \--> [Ready] -(any error)-> [Error]
88 // (EOS dequeued on output)
89 // |
90 // [Drained]
91 // 67 //
92 // [Ready, WaitingForKey, Draining] -[Any state]- 68 // -[Any state]-
93 // | | | 69 // | |
94 // (MediaCodec error) (Reset ok) (Reset fails) 70 // (Reset ok) (Reset fails)
95 // | | | 71 // | |
96 // [Error] [Ready] [Error] 72 // [Ready] [Error]
97 73
98 namespace base { 74 namespace base {
99 class SingleThreadTaskRunner; 75 class SingleThreadTaskRunner;
100 } 76 }
101 77
102 namespace media { 78 namespace media {
103 79
104 class AudioTimestampHelper; 80 class AudioTimestampHelper;
105 81
106 class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder { 82 class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder,
83 public MediaCodecLoop::Client {
107 public: 84 public:
108 explicit MediaCodecAudioDecoder( 85 explicit MediaCodecAudioDecoder(
109 scoped_refptr<base::SingleThreadTaskRunner> task_runner); 86 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
110 ~MediaCodecAudioDecoder() override; 87 ~MediaCodecAudioDecoder() override;
111 88
112 // AudioDecoder implementation. 89 // AudioDecoder implementation.
113 std::string GetDisplayName() const override; 90 std::string GetDisplayName() const override;
114 void Initialize(const AudioDecoderConfig& config, 91 void Initialize(const AudioDecoderConfig& config,
115 CdmContext* cdm_context, 92 CdmContext* cdm_context,
116 const InitCB& init_cb, 93 const InitCB& init_cb,
117 const OutputCB& output_cb) override; 94 const OutputCB& output_cb) override;
118 void Decode(const scoped_refptr<DecoderBuffer>& buffer, 95 void Decode(const scoped_refptr<DecoderBuffer>& buffer,
119 const DecodeCB& decode_cb) override; 96 const DecodeCB& decode_cb) override;
120 void Reset(const base::Closure& closure) override; 97 void Reset(const base::Closure& closure) override;
121 bool NeedsBitstreamConversion() const override; 98 bool NeedsBitstreamConversion() const override;
122 99
100 // MediaCodecLoop::Client implementation
101 bool IsAnyInputPending() const override;
102 MediaCodecLoop::InputData ProvideInputData() override;
103 void OnDecodedEos(const MediaCodecLoop::OutputBuffer& out) override;
104 bool OnDecodedFrame(const MediaCodecLoop::OutputBuffer& out) override;
105 bool OnOutputFormatChanged() override;
106 void OnCodecLoopError() override;
107
123 private: 108 private:
124 // Possible states. 109 // Possible states.
125 enum State { 110 enum State {
111 // A successful call to Initialize() is required.
126 STATE_UNINITIALIZED, 112 STATE_UNINITIALIZED,
113
114 // Codec is initialized, but a call to SetCdm() is required.
127 STATE_WAITING_FOR_MEDIA_CRYPTO, 115 STATE_WAITING_FOR_MEDIA_CRYPTO,
116
117 // Normal state. May decode, etc.
128 STATE_READY, 118 STATE_READY,
129 STATE_WAITING_FOR_KEY, 119
130 STATE_DRAINING, 120 // Codec must be reset.
131 STATE_DRAINED,
132 STATE_ERROR, 121 STATE_ERROR,
133 }; 122 };
134 123
135 // Information about dequeued input buffer. 124 // Allocate a new MediaCodec and MediaCodecLoop, and replace |codec_loop_|.
136 struct InputBufferInfo { 125 // Returns true on success.
137 int buf_index; // The codec input buffers are referred to by this index. 126 bool CreateMediaCodecLoop();
138 bool is_pending; // True if we tried to enqueue this buffer before.
139 InputBufferInfo(int i, bool p) : buf_index(i), is_pending(p) {}
140 };
141 127
142 // Information about the MediaCodec's output buffer. 128 // A helper method to start CDM initialization. This must be called if and
143 struct OutputBufferInfo { 129 // only if we were constructed with |is_encrypted| set to true.
144 int buf_index; // The codec output buffers are referred to by this index.
145 size_t offset; // Position in the buffer where data starts.
146 size_t size; // The size of the buffer (includes offset).
147 base::TimeDelta pts; // Presentation timestamp.
148 bool is_eos; // true if this buffer is the end of stream.
149 bool is_key_frame;
150 };
151
152 // A helper method to start CDM initialization.
153 void SetCdm(CdmContext* cdm_context, const InitCB& init_cb); 130 void SetCdm(CdmContext* cdm_context, const InitCB& init_cb);
154 131
155 // This callback is called after CDM obtained a MediaCrypto object. 132 // This callback is called after CDM obtained a MediaCrypto object.
156 void OnMediaCryptoReady( 133 void OnMediaCryptoReady(
157 const InitCB& init_cb, 134 const InitCB& init_cb,
158 media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto, 135 media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto,
159 bool needs_protected_surface); 136 bool needs_protected_surface);
160 137
161 // Callback called when a new key is available after the codec received 138 // Callback called when a new key is available.
162 // the status MEDIA_CODEC_NO_KEY.
163 void OnKeyAdded(); 139 void OnKeyAdded();
164 140
165 // Does the MediaCodec processing cycle: enqueues an input buffer, then 141 // Start the timer immediately if |start| is true or stop it based on elapsed
166 // dequeues output buffers. 142 // idle time if |start| is false.
167 void DoIOTask(); 143 // void ManageTimer(bool start);
168
169 // Enqueues pending input buffers into MediaCodec as long as it can happen
170 // without delay in dequeuing and enqueueing input buffers.
171 // Returns true if any input was processed.
172 bool QueueInput();
173
174 // Enqueues one pending input buffer into MediaCodec if MediaCodec has room.
175 // Returns true if any input was processed.
176 bool QueueOneInputBuffer();
177
178 // A helper method for QueueInput(). Dequeues an empty input buffer from the
179 // codec and returns the information about it. OutputBufferInfo.buf_index is
180 // the index of the dequeued buffer or -1 if the codec is busy or an error
181 // occured. OutputBufferInfo.is_pending is set to true if we tried to enqueue
182 // this buffer before. In this case the buffer is already filled with data.
183 // In the case of an error sets STATE_ERROR.
184 InputBufferInfo DequeueInputBuffer();
185
186 // A helper method for QueueInput(). Fills an input buffer referred to by
187 // |input_info| with data and enqueues it to the codec. Returns true if
188 // succeeded or false if an error occurs or there is no good CDM key.
189 // May set STATE_DRAINING, STATE_WAITING_FOR_KEY or STATE_ERROR.
190 bool EnqueueInputBuffer(const InputBufferInfo& input_info);
191 144
192 // Calls DecodeCB with |decode_status| for every frame in |input_queue| and 145 // Calls DecodeCB with |decode_status| for every frame in |input_queue| and
193 // then clears it. 146 // then clears it.
194 void ClearInputQueue(DecodeStatus decode_status); 147 void ClearInputQueue(DecodeStatus decode_status);
195 148
196 // Dequeues all output buffers from MediaCodec that are immediately available.
197 // Returns true if any output buffer was received from MediaCodec.
198 bool DequeueOutput();
199
200 // Start the timer immediately if |start| is true or stop it based on elapsed
201 // idle time if |start| is false.
202 void ManageTimer(bool start);
203
204 // Helper method to change the state. 149 // Helper method to change the state.
205 void SetState(State new_state); 150 void SetState(State new_state);
206 151
207 // Helper method for DequeueOutput(), processes end of stream.
208 void OnDecodedEos(const OutputBufferInfo& out);
209
210 // The following helper methods OnDecodedFrame() and OnOutputFormatChanged()
211 // are specific to the stream (audio/video), but others seem to apply to any
212 // MediaCodec decoder.
213 // TODO(timav): refactor the common part out and use it here and in AVDA 152 // TODO(timav): refactor the common part out and use it here and in AVDA
214 // (http://crbug.com/583082). 153 // (http://crbug.com/583082).
215 154
216 // Processes the output buffer after it comes from MediaCodec.
217 void OnDecodedFrame(const OutputBufferInfo& out);
218
219 // Processes the output format change.
220 void OnOutputFormatChanged();
221
222 // A helper function for logging. 155 // A helper function for logging.
223 static const char* AsString(State state); 156 static const char* AsString(State state);
224 157
225 // Used to post tasks. This class is single threaded and every method should 158 // Used to post tasks. This class is single threaded and every method should
226 // run on this task runner. 159 // run on this task runner.
227 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 160 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
228 161
229 State state_; 162 State state_;
230 163
231 // The queue of encoded (and maybe encrypted) buffers. The MediaCodec might 164 // The queue of encoded (and maybe encrypted) buffers. The MediaCodec might
232 // not be able to accept the input at the time of Decode(), thus all 165 // not be able to accept the input at the time of Decode(), thus all
233 // DecoderBuffers first go to |input_queue_|. 166 // DecoderBuffers first go to |input_queue_|.
234 using BufferCBPair = std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>; 167 using BufferCBPair = std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>;
235 using InputQueue = std::deque<BufferCBPair>; 168 using InputQueue = std::deque<BufferCBPair>;
236 InputQueue input_queue_; 169 InputQueue input_queue_;
237 170
238 // Cached decoder config. 171 // Cached decoder config.
239 AudioDecoderConfig config_; 172 AudioDecoderConfig config_;
240 173
241 // Actual channel count that comes from decoder may be different than config. 174 // Actual channel count that comes from decoder may be different than config.
242 int channel_count_; 175 int channel_count_;
243 176
244 // Callback that delivers output frames. 177 // Callback that delivers output frames.
245 OutputCB output_cb_; 178 OutputCB output_cb_;
246 179
247 std::unique_ptr<MediaCodecBridge> media_codec_; 180 std::unique_ptr<MediaCodecLoop> codec_loop_;
248 181
249 std::unique_ptr<AudioTimestampHelper> timestamp_helper_; 182 std::unique_ptr<AudioTimestampHelper> timestamp_helper_;
250 183
251 // Repeating timer that kicks MediaCodec operation.
252 base::RepeatingTimer io_timer_;
253
254 // Time at which we last did useful work on |io_timer_|.
255 base::TimeTicks idle_time_begin_;
256
257 // Index of the dequeued and filled buffer that we keep trying to enqueue.
258 // Such buffer appears in MEDIA_CODEC_NO_KEY processing. The -1 value means
259 // there is no such buffer.
260 int pending_input_buf_index_;
261
262 // CDM related stuff. 184 // CDM related stuff.
263 185
264 // CDM context that knowns about MediaCrypto. Owned by CDM which is external 186 // CDM context that knowns about MediaCrypto. Owned by CDM which is external
265 // to this decoder. 187 // to this decoder.
266 MediaDrmBridgeCdmContext* media_drm_bridge_cdm_context_; 188 MediaDrmBridgeCdmContext* media_drm_bridge_cdm_context_;
267 189
268 // MediaDrmBridge requires registration/unregistration of the player, this 190 // MediaDrmBridge requires registration/unregistration of the player, this
269 // registration id is used for this. 191 // registration id is used for this.
270 int cdm_registration_id_; 192 int cdm_registration_id_;
271 193
272 // The MediaCrypto object is used in the MediaCodec.configure() in case of 194 // The MediaCrypto object is used in the MediaCodec.configure() in case of
273 // an encrypted stream. 195 // an encrypted stream.
274 media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto_; 196 media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto_;
275 197
276 base::WeakPtrFactory<MediaCodecAudioDecoder> weak_factory_; 198 base::WeakPtrFactory<MediaCodecAudioDecoder> weak_factory_;
277 199
278 DISALLOW_COPY_AND_ASSIGN(MediaCodecAudioDecoder); 200 DISALLOW_COPY_AND_ASSIGN(MediaCodecAudioDecoder);
279 }; 201 };
280 202
281 } // namespace media 203 } // namespace media
282 204
283 #endif // MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_ 205 #endif // MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698