OLD | NEW |
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_ |
OLD | NEW |