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

Unified 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 side-by-side diff with in-line comments
Download patch
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..35011afdbfd008dbe8c4e066ac3c9772a0d7bb9c 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"
@@ -30,70 +31,45 @@
// 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 +79,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 +97,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 +135,23 @@ 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);
+ // Start the timer immediately if |start| is true or stop it based on elapsed
+ // idle time if |start| is false.
+ // void ManageTimer(bool start);
// 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 +177,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

Powered by Google App Engine
This is Rietveld 408576698