Commit b052c43a authored by timav's avatar timav Committed by Commit bot

Add stub MediaCdecAudioDecoder

MediaCodecAudioDecoder is an audio decoder that uses Android
MediaCodec API and implements the AudioDecoder interface, i.e.
it can be attached to the DecoderStream and used in the Spitzer
pipeline directly.

This CL only defines its interface and have notes about
possible implementation.

BUG=542910

Review URL: https://codereview.chromium.org/1685483002

Cr-Commit-Position: refs/heads/master@{#374734}
parent a87bd2fc
...@@ -394,6 +394,8 @@ component("media") { ...@@ -394,6 +394,8 @@ component("media") {
"capture/video/android/video_capture_device_android.h", "capture/video/android/video_capture_device_android.h",
"capture/video/android/video_capture_device_factory_android.cc", "capture/video/android/video_capture_device_factory_android.cc",
"capture/video/android/video_capture_device_factory_android.h", "capture/video/android/video_capture_device_factory_android.h",
"filters/android/media_codec_audio_decoder.cc",
"filters/android/media_codec_audio_decoder.h",
] ]
sources -= [ sources -= [
"filters/decrypting_audio_decoder.cc", "filters/decrypting_audio_decoder.cc",
......
// 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.
#include "media/filters/android/media_codec_audio_decoder.h"
#include "base/logging.h"
#include "base/thread_task_runner_handle.h"
namespace media {
MediaCodecAudioDecoder::MediaCodecAudioDecoder(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
: task_runner_(task_runner),
state_(STATE_UNINITIALIZED),
pending_input_buf_index_(-1),
weak_factory_(this) {
DVLOG(1) << __FUNCTION__;
}
MediaCodecAudioDecoder::~MediaCodecAudioDecoder() {
DVLOG(1) << __FUNCTION__;
NOTIMPLEMENTED();
}
std::string MediaCodecAudioDecoder::GetDisplayName() const {
return "MediaCodecAudioDecoder";
}
void MediaCodecAudioDecoder::Initialize(const AudioDecoderConfig& config,
const SetCdmReadyCB& set_cdm_ready_cb,
const InitCB& init_cb,
const OutputCB& output_cb) {
DVLOG(1) << __FUNCTION__ << ": " << config.AsHumanReadableString();
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
const DecodeCB& decode_cb) {
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::Reset(const base::Closure& closure) {
DVLOG(1) << __FUNCTION__;
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::OnKeyAdded() {
DVLOG(1) << __FUNCTION__;
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::DoIOTask() {
NOTIMPLEMENTED();
}
bool MediaCodecAudioDecoder::QueueInput() {
DVLOG(2) << __FUNCTION__;
NOTIMPLEMENTED();
return true;
}
bool MediaCodecAudioDecoder::DequeueOutput() {
DVLOG(2) << __FUNCTION__;
NOTIMPLEMENTED();
return true;
}
void MediaCodecAudioDecoder::ManageTimer(bool start) {
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::SetState(State new_state) {
DVLOG(1) << __FUNCTION__ << ": " << AsString(state_) << "->"
<< AsString(new_state);
state_ = new_state;
}
scoped_ptr<MediaCodecBridge> MediaCodecAudioDecoder::ConfigureMediaCodec(
const AudioDecoderConfig& config) {
NOTIMPLEMENTED();
return nullptr;
}
void MediaCodecAudioDecoder::OnDecodedFrame(const OutputBufferInfo& out) {
DVLOG(2) << __FUNCTION__ << " pts:" << out.pts;
NOTIMPLEMENTED();
}
void MediaCodecAudioDecoder::OnOutputFormatChanged() {
DVLOG(2) << __FUNCTION__;
NOTIMPLEMENTED();
}
#undef RETURN_STRING
#define RETURN_STRING(x) \
case x: \
return #x;
// static
const char* MediaCodecAudioDecoder::AsString(State state) {
switch (state) {
RETURN_STRING(STATE_UNINITIALIZED);
RETURN_STRING(STATE_READY);
RETURN_STRING(STATE_WAITING_FOR_KEY);
RETURN_STRING(STATE_DRAINING);
RETURN_STRING(STATE_DRAINED);
RETURN_STRING(STATE_ERROR);
}
NOTREACHED() << "Unknown state " << state;
return nullptr;
}
#undef RETURN_STRING
} // namespace media
// 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_
...@@ -764,6 +764,10 @@ ...@@ -764,6 +764,10 @@
'filters/ffmpeg_video_decoder.cc', 'filters/ffmpeg_video_decoder.cc',
'filters/ffmpeg_video_decoder.h', 'filters/ffmpeg_video_decoder.h',
], ],
'sources': [
'filters/android/media_codec_audio_decoder.cc',
'filters/android/media_codec_audio_decoder.h',
],
'defines': [ 'defines': [
'DISABLE_USER_INPUT_MONITOR', 'DISABLE_USER_INPUT_MONITOR',
], ],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment