| Index: media/filters/android/media_codec_audio_decoder.h
|
| diff --git a/media/filters/android/media_codec_audio_decoder.h b/media/filters/android/media_codec_audio_decoder.h
|
| index 57d4b86991f30b45bd78c0a0970c1638d608da24..d19fdf5614599044dacf97d0bc33a9c083ca8e49 100644
|
| --- a/media/filters/android/media_codec_audio_decoder.h
|
| +++ b/media/filters/android/media_codec_audio_decoder.h
|
| @@ -15,6 +15,7 @@
|
| #include "base/time/time.h"
|
| #include "base/timer/timer.h"
|
| #include "media/base/android/media_codec_bridge.h"
|
| +#include "media/base/android/media_codec_loop.h"
|
| #include "media/base/android/media_drm_bridge_cdm_context.h"
|
| #include "media/base/audio_decoder.h"
|
| #include "media/base/audio_decoder_config.h"
|
| @@ -24,76 +25,47 @@
|
| // The MediaCodec API is required to play encrypted (as in EME) content on
|
| // Android. It is also a way to employ hardware-accelerated decoding.
|
|
|
| -// TODO(timav): This class has the logic to manipulate the MediaCodec that is
|
| -// the common for audio and video stream and can and should be refactored out
|
| -// (http://crbug.com/583082).
|
| -
|
| // Implementation notes.
|
| //
|
| -// The MediaCodec
|
| -// (http://developer.android.com/reference/android/media/MediaCodec.html) works
|
| -// by exchanging buffers between the client and the codec itself. On the input
|
| -// side an "empty" buffer has to be dequeued from the codec, filled with data
|
| -// and queued back. On the output side a "full" buffer with data should be
|
| -// dequeued, the data is to be used somehow (copied out, or rendered to a pre-
|
| -// defined texture for video) and the buffer has to be returned back (released).
|
| -// Neither input nor output dequeue operations are guaranteed to succeed: the
|
| -// codec might not have available input buffers yet, or not every encoded buffer
|
| -// has arrived to complete an output frame. In such case the client should try
|
| -// to dequeue a buffer again at a later time.
|
| -//
|
| -// There is also a special situation related to an encrypted stream, where the
|
| -// enqueuing of a filled input buffer might fail due to lack of the relevant key
|
| -// in the CDM module.
|
| +// This class provides audio decoding via MediaCodec. It allocates the
|
| +// MediaCodecBridge instance, and hands ownership to MediaCodecLoop to drive I/O
|
| +// with the codec. For encrypted streams, we also talk to the DRM bridge.
|
| //
|
| // Because both dequeuing and enqueuing of an input buffer can fail, the
|
| // implementation puts the input |DecoderBuffer|s and the corresponding decode
|
| // callbacks into an input queue. The decoder has a timer that periodically
|
| // fires the decoding cycle that has two steps. The first step tries to send the
|
| -// front buffer from the input queue to the MediaCodec. In the case of success
|
| +// front buffer from the input queue to MediaCodecLoop. In the case of success
|
| // the element is removed from the queue, the decode callback is fired and the
|
| // decoding process advances. The second step tries to dequeue an output buffer,
|
| // and uses it in the case of success.
|
| //
|
| +// An EOS buffer is handled differently. Success is not signalled to the decode
|
| +// callback until the EOS is received at the output. So, for EOS, the decode
|
| +// callback indicates that all previous decodes have completed.
|
| +//
|
| // The failures in both steps are normal and they happen periodically since
|
| // both input and output buffers become available at unpredictable moments. The
|
| // timer is here to repeat the dequeueing attempts.
|
| //
|
| -// Although one can specify a delay in the MediaCodec's dequeue operations,
|
| -// this implementation follows the simple logic which is similar to
|
| -// AndroidVideoDecodeAccelerator: no delay for either input or output buffers,
|
| -// the processing is initated by the timer with short period (10 ms). Using no
|
| -// delay for enqueue operations has an extra benefit of not blocking the current
|
| -// thread.
|
| -//
|
| -// This implementation detects the MediaCodec idle run (no input or output
|
| -// buffer processing) and after being idle for a predefined time the timer
|
| -// stops. Every Decode() wakes the timer up.
|
| -//
|
| -// The current implementation is single threaded. Every method is supposed to
|
| -// run on the same thread.
|
| -//
|
| // State diagram.
|
| //
|
| -// [Uninitialized] <-> (init failed) [Ready]
|
| -// | |
|
| -// (init succeeded) (MEDIA_CODEC_NO_KEY)
|
| -// | |
|
| -// [Ready] [WaitingForKey]
|
| -// | |
|
| -// (EOS enqueued) (OnKeyAdded)
|
| -// | |
|
| -// [Draining] [Ready]
|
| -// |
|
| -// (EOS dequeued on output)
|
| -// |
|
| -// [Drained]
|
| +// [Uninitialized] <-> (init failed)
|
| +// | |
|
| +// (no enc.) (encrypted)
|
| +// | |
|
| +// | [WaitingForMediaCrypto] -- (OMCR failure) --> [Uninitialized]
|
| +// | | (OnMediaCryptoReady success)
|
| +// v v
|
| +// (Create Codec and MediaCodecLoop)
|
| +// |
|
| +// \--> [Ready] -(any error)-> [Error]
|
| //
|
| -// [Ready, WaitingForKey, Draining] -[Any state]-
|
| -// | | |
|
| -// (MediaCodec error) (Reset ok) (Reset fails)
|
| -// | | |
|
| -// [Error] [Ready] [Error]
|
| +// -[Any state]-
|
| +// | |
|
| +// (Reset ok) (Reset fails)
|
| +// | |
|
| +// [Ready] [Error]
|
|
|
| namespace base {
|
| class SingleThreadTaskRunner;
|
| @@ -103,7 +75,8 @@ namespace media {
|
|
|
| class AudioTimestampHelper;
|
|
|
| -class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
|
| +class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder,
|
| + public MediaCodecLoop::Client {
|
| public:
|
| explicit MediaCodecAudioDecoder(
|
| scoped_refptr<base::SingleThreadTaskRunner> task_runner);
|
| @@ -120,36 +93,36 @@ class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
|
| void Reset(const base::Closure& closure) override;
|
| bool NeedsBitstreamConversion() const override;
|
|
|
| + // MediaCodecLoop::Client implementation
|
| + bool IsAnyInputPending() const override;
|
| + MediaCodecLoop::InputData ProvideInputData() override;
|
| + void OnDecodedEos(const MediaCodecLoop::OutputBuffer& out) override;
|
| + bool OnDecodedFrame(const MediaCodecLoop::OutputBuffer& out) override;
|
| + bool OnOutputFormatChanged() override;
|
| + void OnCodecLoopError() override;
|
| +
|
| private:
|
| // Possible states.
|
| enum State {
|
| + // A successful call to Initialize() is required.
|
| STATE_UNINITIALIZED,
|
| +
|
| + // Codec is initialized, but a call to SetCdm() is required.
|
| STATE_WAITING_FOR_MEDIA_CRYPTO,
|
| +
|
| + // Normal state. May decode, etc.
|
| STATE_READY,
|
| - STATE_WAITING_FOR_KEY,
|
| - STATE_DRAINING,
|
| - STATE_DRAINED,
|
| - STATE_ERROR,
|
| - };
|
|
|
| - // Information about dequeued input buffer.
|
| - struct InputBufferInfo {
|
| - int buf_index; // The codec input buffers are referred to by this index.
|
| - bool is_pending; // True if we tried to enqueue this buffer before.
|
| - InputBufferInfo(int i, bool p) : buf_index(i), is_pending(p) {}
|
| + // Codec must be reset.
|
| + STATE_ERROR,
|
| };
|
|
|
| - // Information about the MediaCodec's output buffer.
|
| - struct OutputBufferInfo {
|
| - int buf_index; // The codec output buffers are referred to by this index.
|
| - size_t offset; // Position in the buffer where data starts.
|
| - size_t size; // The size of the buffer (includes offset).
|
| - base::TimeDelta pts; // Presentation timestamp.
|
| - bool is_eos; // true if this buffer is the end of stream.
|
| - bool is_key_frame;
|
| - };
|
| + // Allocate a new MediaCodec and MediaCodecLoop, and replace |codec_loop_|.
|
| + // Returns true on success.
|
| + bool CreateMediaCodecLoop();
|
|
|
| - // A helper method to start CDM initialization.
|
| + // A helper method to start CDM initialization. This must be called if and
|
| + // only if we were constructed with |is_encrypted| set to true.
|
| void SetCdm(CdmContext* cdm_context, const InitCB& init_cb);
|
|
|
| // This callback is called after CDM obtained a MediaCrypto object.
|
| @@ -158,67 +131,19 @@ class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
|
| media::MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto,
|
| bool needs_protected_surface);
|
|
|
| - // Callback called when a new key is available after the codec received
|
| - // the status MEDIA_CODEC_NO_KEY.
|
| + // Callback called when a new key is available.
|
| void OnKeyAdded();
|
|
|
| - // Does the MediaCodec processing cycle: enqueues an input buffer, then
|
| - // dequeues output buffers.
|
| - void DoIOTask();
|
| -
|
| - // Enqueues pending input buffers into MediaCodec as long as it can happen
|
| - // without delay in dequeuing and enqueueing input buffers.
|
| - // Returns true if any input was processed.
|
| - bool QueueInput();
|
| -
|
| - // Enqueues one pending input buffer into MediaCodec if MediaCodec has room.
|
| - // Returns true if any input was processed.
|
| - bool QueueOneInputBuffer();
|
| -
|
| - // A helper method for QueueInput(). Dequeues an empty input buffer from the
|
| - // codec and returns the information about it. OutputBufferInfo.buf_index is
|
| - // the index of the dequeued buffer or -1 if the codec is busy or an error
|
| - // occured. OutputBufferInfo.is_pending is set to true if we tried to enqueue
|
| - // this buffer before. In this case the buffer is already filled with data.
|
| - // In the case of an error sets STATE_ERROR.
|
| - InputBufferInfo DequeueInputBuffer();
|
| -
|
| - // A helper method for QueueInput(). Fills an input buffer referred to by
|
| - // |input_info| with data and enqueues it to the codec. Returns true if
|
| - // succeeded or false if an error occurs or there is no good CDM key.
|
| - // May set STATE_DRAINING, STATE_WAITING_FOR_KEY or STATE_ERROR.
|
| - bool EnqueueInputBuffer(const InputBufferInfo& input_info);
|
| -
|
| // Calls DecodeCB with |decode_status| for every frame in |input_queue| and
|
| // then clears it.
|
| void ClearInputQueue(DecodeStatus decode_status);
|
|
|
| - // Dequeues all output buffers from MediaCodec that are immediately available.
|
| - // Returns true if any output buffer was received from MediaCodec.
|
| - bool DequeueOutput();
|
| -
|
| - // Start the timer immediately if |start| is true or stop it based on elapsed
|
| - // idle time if |start| is false.
|
| - void ManageTimer(bool start);
|
| -
|
| // Helper method to change the state.
|
| void SetState(State new_state);
|
|
|
| - // Helper method for DequeueOutput(), processes end of stream.
|
| - void OnDecodedEos(const OutputBufferInfo& out);
|
| -
|
| - // The following helper methods OnDecodedFrame() and OnOutputFormatChanged()
|
| - // are specific to the stream (audio/video), but others seem to apply to any
|
| - // MediaCodec decoder.
|
| // TODO(timav): refactor the common part out and use it here and in AVDA
|
| // (http://crbug.com/583082).
|
|
|
| - // Processes the output buffer after it comes from MediaCodec.
|
| - void OnDecodedFrame(const OutputBufferInfo& out);
|
| -
|
| - // Processes the output format change.
|
| - void OnOutputFormatChanged();
|
| -
|
| // A helper function for logging.
|
| static const char* AsString(State state);
|
|
|
| @@ -244,21 +169,10 @@ class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
|
| // Callback that delivers output frames.
|
| OutputCB output_cb_;
|
|
|
| - std::unique_ptr<MediaCodecBridge> media_codec_;
|
| + std::unique_ptr<MediaCodecLoop> codec_loop_;
|
|
|
| std::unique_ptr<AudioTimestampHelper> timestamp_helper_;
|
|
|
| - // Repeating timer that kicks MediaCodec operation.
|
| - base::RepeatingTimer io_timer_;
|
| -
|
| - // Time at which we last did useful work on |io_timer_|.
|
| - base::TimeTicks idle_time_begin_;
|
| -
|
| - // Index of the dequeued and filled buffer that we keep trying to enqueue.
|
| - // Such buffer appears in MEDIA_CODEC_NO_KEY processing. The -1 value means
|
| - // there is no such buffer.
|
| - int pending_input_buf_index_;
|
| -
|
| // CDM related stuff.
|
|
|
| // CDM context that knowns about MediaCrypto. Owned by CDM which is external
|
|
|