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

Unified Diff: media/filters/android/media_codec_audio_decoder.h

Issue 1685483002: Add stub MediaCodecAudioDecoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments, one question Created 4 years, 10 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
« no previous file with comments | « media/BUILD.gn ('k') | media/filters/android/media_codec_audio_decoder.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
new file mode 100644
index 0000000000000000000000000000000000000000..a15fd800e491df08fa04142a56cb48448eb5890b
--- /dev/null
+++ b/media/filters/android/media_codec_audio_decoder.h
@@ -0,0 +1,217 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
+#define MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
+
+#include <deque>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "media/base/android/media_codec_bridge.h"
+#include "media/base/audio_decoder.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/media_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace media {
+
+// MediaCodecAudioDecoder is based on Android's MediaCodec API.
+// 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.
+//
+// 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
+// tries to send the front buffer from the input queue to the MediaCodec. In
+// the case of success the element is removed from the queue, the decode
+// callback is fired and the decoding process advances. The same timer tries to
+// dequeue an output buffer.
+//
+// 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]
+//
+// [Ready, WaitingForKey, Draining] -[Any state]-
+// | | |
+// (MediaCodec error) (Reset ok) (Reset fails)
+// | | |
+// [Error] [Ready] [Error]
+
+class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
+ public:
+ explicit MediaCodecAudioDecoder(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+ ~MediaCodecAudioDecoder() override;
+
+ // AudioDecoder implementation.
+ std::string GetDisplayName() const override;
+ void Initialize(const AudioDecoderConfig& config,
+ const SetCdmReadyCB& set_cdm_ready_cb,
+ const InitCB& init_cb,
+ const OutputCB& output_cb) override;
+ void Decode(const scoped_refptr<DecoderBuffer>& buffer,
+ const DecodeCB& decode_cb) override;
+ void Reset(const base::Closure& closure) override;
+
+ private:
+ // Possible states.
+ enum State {
+ STATE_UNINITIALIZED,
+ STATE_READY,
+ STATE_WAITING_FOR_KEY,
+ STATE_DRAINING,
+ STATE_DRAINED,
+ 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;
+ };
+
+ // Callback called when a new key is available after the codec received
+ // the status MEDIA_CODEC_NO_KEY.
+ void OnKeyAdded();
+
+ // Does the MediaCodec processing cycle: enqueues an input buffer, then
+ // dequeues output buffers.
+ void DoIOTask();
+
+ // Enqueues one pending input buffer into MediaCodec if MediaCodec has room.
+ // Returns true if any input was processed.
+ bool QueueInput();
+
+ // 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);
+
+ // The following helper methods ConfigureMediaCodec(), OnDecodedFrame(),
+ // 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).
+
+ // Configures MediaCodec with |config|. Returns valid MediaCodec pointer if
+ // succeeded or null if configuration failed.
+ scoped_ptr<MediaCodecBridge> ConfigureMediaCodec(
+ const AudioDecoderConfig& config);
+
+ // 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);
+
+ // Used to post tasks. This class is single threaded and every method should
+ // run on this task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ State state_;
+
+ // The queue of encoded (and maybe encrypted) buffers. The MediaCodec might
+ // not be able to accept the input at the time of Decode(), thus all
+ // DecoderBuffers first go to |input_queue_|.
+ using BufferCBPair = std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>;
+ using InputQueue = std::deque<BufferCBPair>;
+ InputQueue input_queue_;
+
+ // Cached decoder config.
+ AudioDecoderConfig config_;
+
+ // Callback that delivers output frames.
+ OutputCB output_cb_;
+
+ scoped_ptr<MediaCodecBridge> media_codec_;
+
+ // 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_;
+
+ // Weak pointer factory must be the last member variable.
+ base::WeakPtrFactory<MediaCodecAudioDecoder> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaCodecAudioDecoder);
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_ANDROID_MEDIA_CODEC_AUDIO_DECODER_H_
« no previous file with comments | « media/BUILD.gn ('k') | media/filters/android/media_codec_audio_decoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698