| 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 |