Commit f1dc7cd8 authored by dalecurtis's avatar dalecurtis Committed by Commit bot

Add support for external video renderers in mojo.

- Extends RendererConfig to handle VideoDecoders.
- Extends the MOJO interfaces for DemuxerStreams with VIDEO.
- Adds the VideoFrame type plus converters to media types.
- Extends DemuxerStreamProviderShim to handle multiple streams.

BUG=410451
TEST=YouTube videos play with MOJO renderer!

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

Cr-Commit-Position: refs/heads/master@{#302728}
parent fcd1ac7e
......@@ -1038,9 +1038,11 @@
],
'export_dependent_settings': [
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../mojo/services/public/mojo_services_public.gyp:mojo_geometry_bindings',
],
'dependencies': [
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../mojo/services/public/mojo_services_public.gyp:mojo_geometry_bindings',
],
},
{
......@@ -1053,9 +1055,12 @@
'media',
'media_mojo_bindings',
'../base/base.gyp:base',
'../mojo/mojo_geometry_converters.gyp:mojo_geometry_lib',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_base',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/gfx/gfx.gyp:gfx_geometry',
'<(mojo_system_for_component)',
],
'export_dependent_settings': [
......@@ -1084,6 +1089,8 @@
'shared_memory_support',
],
'sources': [
'mojo/services/demuxer_stream_provider_shim.cc',
'mojo/services/demuxer_stream_provider_shim.h',
'mojo/services/mojo_demuxer_stream_adapter.cc',
'mojo/services/mojo_demuxer_stream_adapter.h',
'mojo/services/mojo_renderer_service.cc',
......
include_rules = [
"+mojo/application",
"+mojo/converters",
"+mojo/public",
]
......@@ -11,4 +11,8 @@ mojom("interfaces") {
"media_renderer.mojom",
"demuxer_stream.mojom",
]
deps = [
"//mojo/services/public/interfaces/geometry",
]
}
......@@ -15,7 +15,8 @@ interface DemuxerStream {
enum Type {
UNKNOWN,
AUDIO,
LAST_TYPE = AUDIO
VIDEO,
LAST_TYPE = VIDEO,
};
// See media::DemuxerStream for descriptions.
......@@ -49,4 +50,9 @@ interface DemuxerStreamClient {
// whenever a DemuxerStream::STATUS_CONFIG_CHANGED is observed (either
// in a Read() callback or over the DataPipe).
OnAudioDecoderConfigChanged(AudioDecoderConfig config);
// A new VideoDecoderConfig is available. Will be sent by the DemuxerStream
// whenever a DemuxerStream::STATUS_CONFIG_CHANGED is observed (either
// in a Read() callback or over the DataPipe).
OnVideoDecoderConfigChanged(VideoDecoderConfig config);
};
......@@ -9,10 +9,11 @@ import "media/mojo/interfaces/media_types.mojom";
[Client=MediaRendererClient]
interface MediaRenderer {
// Initializes the Renderer with |stream|, calling back upon completion.
// Initializes the Renderer with one or both of an audio and video stream,
// calling back upon completion.
// NOTE: If an error occurs, MediaRendererClient::OnError() will be called
// before the callback is executed.
Initialize(DemuxerStream stream) => ();
Initialize(DemuxerStream? audio, DemuxerStream? video) => ();
// Discards any buffered data, executing callback when completed.
// NOTE: If an error occurs, MediaRendererClient::OnError() can be called
......
......@@ -4,6 +4,8 @@
module mojo;
import "mojo/services/public/interfaces/geometry/geometry.mojom";
// See media/base/buffering_state.h for descriptions.
// Kept in sync with media::BufferingState via COMPILE_ASSERTs.
enum BufferingState {
......@@ -68,7 +70,7 @@ enum ChannelLayout {
k_OCTAGONAL = 28,
k_DISCRETE = 29,
k_STEREO_AND_KEYBOARD_MIC = 30,
k_MAX = k_STEREO_AND_KEYBOARD_MIC
k_MAX = k_STEREO_AND_KEYBOARD_MIC,
};
// See media/base/sample_format.h for descriptions.
......@@ -84,6 +86,63 @@ enum SampleFormat {
Max = PlanarF32,
};
// See media/base/video_frame.h for descriptions.
// Kept in sync with media::VideoFrame::Format via COMPILE_ASSERTs.
enum VideoFormat {
UNKNOWN = 0,
YV12,
YV16,
I420,
YV12A,
HOLE,
NATIVE_TEXTURE,
YV12J,
NV12,
YV24,
FORMAT_MAX = YV24,
};
// See media/base/video_decoder_config.h for descriptions.
// Kept in sync with media::VideoCodec via COMPILE_ASSERTs.
enum VideoCodec {
UNKNOWN = 0,
H264,
VC1,
MPEG2,
MPEG4,
Theora,
VP8,
VP9,
Max = VP9,
};
// See media/base/video_decoder_config.h for descriptions.
// Kept in sync with media::VideoCodecProfile via COMPILE_ASSERTs.
enum VideoCodecProfile {
VIDEO_CODEC_PROFILE_UNKNOWN = -1,
VIDEO_CODEC_PROFILE_MIN = VIDEO_CODEC_PROFILE_UNKNOWN,
H264PROFILE_MIN = 0,
H264PROFILE_BASELINE = H264PROFILE_MIN,
H264PROFILE_MAIN = 1,
H264PROFILE_EXTENDED = 2,
H264PROFILE_HIGH = 3,
H264PROFILE_HIGH10PROFILE = 4,
H264PROFILE_HIGH422PROFILE = 5,
H264PROFILE_HIGH444PREDICTIVEPROFILE = 6,
H264PROFILE_SCALABLEBASELINE = 7,
H264PROFILE_SCALABLEHIGH = 8,
H264PROFILE_STEREOHIGH = 9,
H264PROFILE_MULTIVIEWHIGH = 10,
H264PROFILE_MAX = H264PROFILE_MULTIVIEWHIGH,
VP8PROFILE_MIN = 11,
VP8PROFILE_ANY = VP8PROFILE_MIN,
VP8PROFILE_MAX = VP8PROFILE_ANY,
VP9PROFILE_MIN = 12,
VP9PROFILE_ANY = VP9PROFILE_MIN,
VP9PROFILE_MAX = VP9PROFILE_ANY,
VIDEO_CODEC_PROFILE_MAX = VP9PROFILE_MAX,
};
// This defines a mojo transport format for media::AudioDecoderConfig.
// See media/base/audio_decoder_config.h for descriptions.
struct AudioDecoderConfig {
......@@ -96,6 +155,19 @@ struct AudioDecoderConfig {
int32 codec_delay;
};
// This defines a mojo transport format for media::VideoDecoderConfig.
// See media/base/video_decoder_config.h for descriptions.
struct VideoDecoderConfig {
VideoCodec codec;
VideoCodecProfile profile;
VideoFormat format;
Size coded_size;
Rect visible_rect;
Size natural_size;
array<uint8>? extra_data;
bool is_encrypted;
};
// This defines a mojo transport format for media::DecoderBuffer.
struct MediaDecoderBuffer {
// See media/base/buffers.h for details.
......
......@@ -10,8 +10,11 @@ source_set("lib") {
"//media",
"//media/mojo/interfaces",
"//mojo/common",
"//mojo/converters/geometry",
"//mojo/environment:chromium",
"//mojo/public/c/system:for_component",
"//mojo/services/public/interfaces/geometry",
"//skia",
]
sources = [
......@@ -61,6 +64,8 @@ shared_library("renderer_app") {
]
sources = [
"demuxer_stream_provider_shim.cc",
"demuxer_stream_provider_shim.h",
"mojo_renderer_service.cc",
"mojo_renderer_service.h",
"renderer_config.cc",
......
// Copyright 2014 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/mojo/services/demuxer_stream_provider_shim.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
namespace media {
DemuxerStreamProviderShim::DemuxerStreamProviderShim(
mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const base::Closure& demuxer_ready_cb)
: demuxer_ready_cb_(demuxer_ready_cb),
streams_ready_(0),
weak_factory_(this) {
DCHECK(audio || video);
DCHECK(!demuxer_ready_cb_.is_null());
if (audio) {
streams_.push_back(new MojoDemuxerStreamAdapter(
audio.Pass(),
base::Bind(&DemuxerStreamProviderShim::OnStreamReady,
weak_factory_.GetWeakPtr())));
}
if (video) {
streams_.push_back(new MojoDemuxerStreamAdapter(
video.Pass(),
base::Bind(&DemuxerStreamProviderShim::OnStreamReady,
weak_factory_.GetWeakPtr())));
}
}
DemuxerStreamProviderShim::~DemuxerStreamProviderShim() {
}
DemuxerStream* DemuxerStreamProviderShim::GetStream(DemuxerStream::Type type) {
DCHECK(demuxer_ready_cb_.is_null());
for (auto* stream : streams_) {
if (stream->type() == type)
return stream;
}
return nullptr;
}
DemuxerStreamProvider::Liveness DemuxerStreamProviderShim::GetLiveness() const {
// TODO(dalecurtis): This should be removed once liveness lives elsewhere, see
// http://crbug.com/420025
return DemuxerStreamProvider::LIVENESS_UNKNOWN;
}
void DemuxerStreamProviderShim::OnStreamReady() {
if (++streams_ready_ == streams_.size())
base::ResetAndReturn(&demuxer_ready_cb_).Run();
}
} // namespace media
// Copyright 2014 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_MOJO_SERVICES_DEMUXER_STREAM_PROVIDER_SHIM_H_
#define MEDIA_MOJO_SERVICES_DEMUXER_STREAM_PROVIDER_SHIM_H_
#include "base/callback.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "media/base/demuxer_stream_provider.h"
#include "media/mojo/services/mojo_demuxer_stream_adapter.h"
namespace media {
// DemuxerStreamProvider shim for mojo::DemuxerStreams.
class DemuxerStreamProviderShim : public DemuxerStreamProvider {
public:
// Constructs the shim; at least a single audio or video stream must be
// provided. |demuxer_ready_cb| will be called once the streams have been
// initialized. Calling any method before then is an error.
DemuxerStreamProviderShim(mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const base::Closure& demuxer_ready_cb);
~DemuxerStreamProviderShim() override;
// DemuxerStreamProvider interface.
DemuxerStream* GetStream(DemuxerStream::Type type) override;
Liveness GetLiveness() const override;
private:
// Called as each mojo::DemuxerStream becomes ready. Once all streams are
// ready it will fire the |demuxer_ready_cb_| provided during construction.
void OnStreamReady();
// Stored copy the ready callback provided during construction; cleared once
// all streams are ready.
base::Closure demuxer_ready_cb_;
// Scoped container for demuxer stream adapters which interface with the
// mojo level demuxer streams. |streams_ready_| tracks how many streams are
// ready and is used by OnStreamReady() to know when |demuxer_ready_cb_|
// should be fired.
ScopedVector<MojoDemuxerStreamAdapter> streams_;
size_t streams_ready_;
// WeakPtrFactorys must always be the last member variable.
base::WeakPtrFactory<DemuxerStreamProviderShim> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DemuxerStreamProviderShim);
};
} // namespace media
#endif // MEDIA_MOJO_SERVICES_DEMUXER_STREAM_PROVIDER_SHIM_H_
......@@ -10,6 +10,7 @@
namespace media {
class AudioDecoderConfig;
class VideoDecoderConfig;
class DecoderBuffer;
}
......@@ -37,6 +38,15 @@ struct TypeConverter<media::AudioDecoderConfig, AudioDecoderConfigPtr> {
static media::AudioDecoderConfig Convert(const AudioDecoderConfigPtr& input);
};
template <>
struct TypeConverter<VideoDecoderConfigPtr, media::VideoDecoderConfig> {
static VideoDecoderConfigPtr Convert(const media::VideoDecoderConfig& input);
};
template <>
struct TypeConverter<media::VideoDecoderConfig, VideoDecoderConfigPtr> {
static media::VideoDecoderConfig Convert(const VideoDecoderConfigPtr& input);
};
} // namespace mojo
#endif // MEDIA_MOJO_SERVICES_MEDIA_TYPE_CONVERTERS_H_
......@@ -16,6 +16,7 @@ MojoDemuxerStreamAdapter::MojoDemuxerStreamAdapter(
const base::Closure& stream_ready_cb)
: demuxer_stream_(demuxer_stream.Pass()),
stream_ready_cb_(stream_ready_cb),
type_(DemuxerStream::UNKNOWN),
weak_factory_(this) {
DVLOG(1) << __FUNCTION__;
demuxer_stream_.set_client(this);
......@@ -35,21 +36,23 @@ void MojoDemuxerStreamAdapter::Read(const DemuxerStream::ReadCB& read_cb) {
}
AudioDecoderConfig MojoDemuxerStreamAdapter::audio_decoder_config() {
DCHECK(!config_queue_.empty());
return config_queue_.front();
DCHECK_EQ(type_, DemuxerStream::AUDIO);
DCHECK(!audio_config_queue_.empty());
return audio_config_queue_.front();
}
VideoDecoderConfig MojoDemuxerStreamAdapter::video_decoder_config() {
NOTREACHED();
return VideoDecoderConfig();
DCHECK_EQ(type_, DemuxerStream::VIDEO);
DCHECK(!video_config_queue_.empty());
return video_config_queue_.front();
}
media::DemuxerStream::Type MojoDemuxerStreamAdapter::type() {
return media::DemuxerStream::AUDIO;
DemuxerStream::Type MojoDemuxerStreamAdapter::type() {
return type_;
}
void MojoDemuxerStreamAdapter::EnableBitstreamConverter() {
NOTREACHED();
NOTIMPLEMENTED();
}
bool MojoDemuxerStreamAdapter::SupportsConfigChanges() {
......@@ -66,16 +69,34 @@ void MojoDemuxerStreamAdapter::OnStreamReady(
DVLOG(1) << __FUNCTION__;
// TODO(tim): We don't support pipe streaming yet.
DCHECK(!pipe.is_valid());
DCHECK(!config_queue_.empty());
DCHECK_NE(type_, DemuxerStream::UNKNOWN);
stream_ready_cb_.Run();
}
void MojoDemuxerStreamAdapter::OnAudioDecoderConfigChanged(
mojo::AudioDecoderConfigPtr config) {
config_queue_.push(config.To<media::AudioDecoderConfig>());
DCHECK(type_ == DemuxerStream::UNKNOWN || type_ == DemuxerStream::AUDIO)
<< type_;
type_ = DemuxerStream::AUDIO;
audio_config_queue_.push(config.To<AudioDecoderConfig>());
if (!read_cb_.is_null()) {
read_cb_.Run(media::DemuxerStream::Status::kConfigChanged, NULL);
read_cb_.Run(DemuxerStream::Status::kConfigChanged, NULL);
read_cb_.Reset();
}
}
void MojoDemuxerStreamAdapter::OnVideoDecoderConfigChanged(
mojo::VideoDecoderConfigPtr config) {
DCHECK(type_ == DemuxerStream::UNKNOWN || type_ == DemuxerStream::VIDEO)
<< type_;
type_ = DemuxerStream::VIDEO;
video_config_queue_.push(config.To<VideoDecoderConfig>());
if (!read_cb_.is_null()) {
read_cb_.Run(DemuxerStream::Status::kConfigChanged, NULL);
read_cb_.Reset();
}
}
......@@ -85,22 +106,30 @@ void MojoDemuxerStreamAdapter::OnBufferReady(
mojo::MediaDecoderBufferPtr buffer) {
DVLOG(3) << __FUNCTION__;
DCHECK(!read_cb_.is_null());
DCHECK(!config_queue_.empty());
DCHECK_NE(type_, DemuxerStream::UNKNOWN);
media::DemuxerStream::Status media_status(
static_cast<media::DemuxerStream::Status>(status));
scoped_refptr<media::DecoderBuffer> media_buffer(
buffer.To<scoped_refptr<media::DecoderBuffer> >());
DemuxerStream::Status media_status(
static_cast<DemuxerStream::Status>(status));
scoped_refptr<DecoderBuffer> media_buffer(
buffer.To<scoped_refptr<DecoderBuffer>>());
if (status == mojo::DemuxerStream::STATUS_CONFIG_CHANGED) {
DCHECK(!media_buffer.get());
config_queue_.pop();
// If the |config_queue_| is empty we need to wait for
// OnAudioDecoderConfigChanged before invoking |read_cb|.
if (config_queue_.empty())
// If the configuration queue is empty we need to wait for a config change
// event before invoking |read_cb_|.
if (type_ == DemuxerStream::AUDIO) {
audio_config_queue_.pop();
if (audio_config_queue_.empty())
return;
} else if (type_ == DemuxerStream::VIDEO) {
video_config_queue_.pop();
if (video_config_queue_.empty())
return;
}
}
read_cb_.Run(media_status, media_buffer);
read_cb_.Reset();
}
......
......@@ -15,11 +15,11 @@
namespace media {
// This class acts as a MojoRendererService-side stub for a real
// media::DemuxerStream that is part of a media::Pipeline in a remote
// application. Roughly speaking, it takes a mojo::DemuxerStreamPtr and exposes
// it as a media::DemuxerStream for use by media components.
class MojoDemuxerStreamAdapter : public media::DemuxerStream,
// This class acts as a MojoRendererService-side stub for a real DemuxerStream
// that is part of a Pipeline in a remote application. Roughly speaking, it
// takes a mojo::DemuxerStreamPtr and exposes it as a DemuxerStream for use by
// media components.
class MojoDemuxerStreamAdapter : public DemuxerStream,
public mojo::DemuxerStreamClient {
public:
// |demuxer_stream| is connected to the mojo::DemuxerStream that |this| will
......@@ -31,7 +31,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
const base::Closure& stream_ready_cb);
~MojoDemuxerStreamAdapter() override;
// media::DemuxerStream implementation.
// DemuxerStream implementation.
void Read(const ReadCB& read_cb) override;
AudioDecoderConfig audio_decoder_config() override;
VideoDecoderConfig video_decoder_config() override;
......@@ -43,6 +43,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
// mojo::DemuxerStreamClient implementation.
void OnStreamReady(mojo::ScopedDataPipeConsumerHandle pipe) override;
void OnAudioDecoderConfigChanged(mojo::AudioDecoderConfigPtr config) override;
void OnVideoDecoderConfigChanged(mojo::VideoDecoderConfigPtr config) override;
private:
// The callback from |demuxer_stream_| that a read operation has completed.
......@@ -63,7 +64,10 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
// The front of the queue is the current config. We pop when we observe
// DemuxerStatus::CONFIG_CHANGED.
std::queue<media::AudioDecoderConfig> config_queue_;
std::queue<AudioDecoderConfig> audio_config_queue_;
std::queue<VideoDecoderConfig> video_config_queue_;
DemuxerStream::Type type_;
base::WeakPtrFactory<MojoDemuxerStreamAdapter> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MojoDemuxerStreamAdapter);
......
......@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/video_decoder_config.h"
#include "media/mojo/interfaces/demuxer_stream.mojom.h"
#include "media/mojo/services/media_type_converters.h"
#include "mojo/public/cpp/bindings/interface_impl.h"
......@@ -35,8 +36,13 @@ void MojoDemuxerStreamImpl::OnBufferReady(
if (status == media::DemuxerStream::kConfigChanged) {
// Send the config change so our client can read it once it parses the
// Status obtained via Run() below.
if (stream_->type() == media::DemuxerStream::AUDIO) {
client()->OnAudioDecoderConfigChanged(
mojo::AudioDecoderConfig::From(stream_->audio_decoder_config()));
} else if (stream_->type() == media::DemuxerStream::VIDEO) {
client()->OnVideoDecoderConfigChanged(
mojo::VideoDecoderConfig::From(stream_->video_decoder_config()));
}
}
// TODO(tim): Once using DataPipe, fill via the producer handle and then
......@@ -49,8 +55,13 @@ void MojoDemuxerStreamImpl::OnConnectionEstablished() {
// This is called when our DemuxerStreamClient has connected itself and is
// ready to receive messages. Send an initial config and notify it that
// we are now ready for business.
if (stream_->type() == media::DemuxerStream::AUDIO) {
client()->OnAudioDecoderConfigChanged(
mojo::AudioDecoderConfig::From(stream_->audio_decoder_config()));
} else if (stream_->type() == media::DemuxerStream::VIDEO) {
client()->OnVideoDecoderConfigChanged(
mojo::VideoDecoderConfig::From(stream_->video_decoder_config()));
}
// TODO(tim): Create a DataPipe, hold the producer handle, and pass the
// consumer handle here.
......
......@@ -53,14 +53,24 @@ void MojoRendererImpl::Initialize(
error_cb_ = error_cb;
buffering_state_cb_ = buffering_state_cb;
// Create a mojo::DemuxerStream and bind its lifetime to the pipe.
mojo::DemuxerStreamPtr demuxer_stream;
mojo::BindToProxy(
new MojoDemuxerStreamImpl(
demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)),
&demuxer_stream);
// Create audio and video mojo::DemuxerStream and bind its lifetime to the
// pipe.
DemuxerStream* const audio =
demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
DemuxerStream* const video =
demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
mojo::DemuxerStreamPtr audio_stream;
if (audio)
mojo::BindToProxy(new MojoDemuxerStreamImpl(audio), &audio_stream);
mojo::DemuxerStreamPtr video_stream;
if (video)
mojo::BindToProxy(new MojoDemuxerStreamImpl(video), &video_stream);
remote_audio_renderer_->Initialize(
demuxer_stream.Pass(),
audio_stream.Pass(),
video_stream.Pass(),
BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized,
weak_factory_.GetWeakPtr())));
}
......@@ -105,13 +115,13 @@ bool MojoRendererImpl::HasAudio() {
DVLOG(1) << __FUNCTION__;
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(remote_audio_renderer_.get()); // We always bind the renderer.
return true;
return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
}
bool MojoRendererImpl::HasVideo() {
DVLOG(1) << __FUNCTION__;
DCHECK(task_runner_->BelongsToCurrentThread());
return false;
return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
}
void MojoRendererImpl::SetCdm(MediaKeys* cdm) {
......
......@@ -15,6 +15,8 @@
#include "media/base/video_renderer.h"
#include "media/filters/audio_renderer_impl.h"
#include "media/filters/renderer_impl.h"
#include "media/filters/video_renderer_impl.h"
#include "media/mojo/services/demuxer_stream_provider_shim.h"
#include "media/mojo/services/mojo_demuxer_stream_adapter.h"
#include "media/mojo/services/renderer_config.h"
#include "mojo/application/application_runner_chromium.h"
......@@ -33,29 +35,8 @@ static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log,
media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
}
// Shim DemuxerStreamProvider wrapper for a single DemuxerStream.
// TODO(dalecurtis): Once we support more than one DemuxerStream we'll need a
// more complicated shim which can handle a mojo::Array<DemuxerStream>.
class DemuxerStreamProviderShim : public DemuxerStreamProvider {
public:
DemuxerStreamProviderShim(scoped_ptr<MojoDemuxerStreamAdapter> stream)
: stream_(stream.Pass()) {}
~DemuxerStreamProviderShim() override {}
DemuxerStream* GetStream(DemuxerStream::Type type) override {
return type != stream_->type() ? nullptr : stream_.get();
};
Liveness GetLiveness() const override {
return DemuxerStreamProvider::LIVENESS_UNKNOWN;
}
private:
scoped_ptr<MojoDemuxerStreamAdapter> stream_;
DISALLOW_COPY_AND_ASSIGN(DemuxerStreamProviderShim);
};
static void PaintNothing(const scoped_refptr<VideoFrame>& frame) {
}
class MojoRendererApplication
: public mojo::ApplicationDelegate,
......@@ -102,7 +83,16 @@ MojoRendererService::MojoRendererService(
SetDecryptorReadyCB(),
renderer_config->GetAudioHardwareConfig(),
media_log));
scoped_ptr<VideoRenderer> video_renderer(nullptr);
scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl(
task_runner,
renderer_config->GetVideoDecoders(
task_runner,
base::Bind(&LogMediaSourceError, media_log)).Pass(),
SetDecryptorReadyCB(),
base::Bind(&PaintNothing),
true,
media_log));
// Create renderer.
renderer_.reset(new RendererImpl(
......@@ -112,7 +102,8 @@ MojoRendererService::MojoRendererService(
MojoRendererService::~MojoRendererService() {
}
void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream,
void MojoRendererService::Initialize(mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const mojo::Closure& callback) {
DVLOG(1) << __FUNCTION__;
DCHECK_EQ(state_, STATE_UNINITIALIZED);
......@@ -120,11 +111,9 @@ void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream,
state_ = STATE_INITIALIZING;
stream_provider_.reset(new DemuxerStreamProviderShim(
make_scoped_ptr(new MojoDemuxerStreamAdapter(
stream.Pass(),
base::Bind(&MojoRendererService::OnStreamReady,
weak_this_,
callback))).Pass()));
audio.Pass(),
video.Pass(),
base::Bind(&MojoRendererService::OnStreamReady, weak_this_, callback)));
}
void MojoRendererService::Flush(const mojo::Closure& callback) {
......
......@@ -39,7 +39,8 @@ class MojoRendererService : public mojo::InterfaceImpl<mojo::MediaRenderer> {
~MojoRendererService() override;
// mojo::MediaRenderer implementation.
void Initialize(mojo::DemuxerStreamPtr streams,
void Initialize(mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const mojo::Closure& callback) override;
void Flush(const mojo::Closure& callback) override;
void StartPlayingFrom(int64_t time_delta_usec) override;
......
......@@ -24,6 +24,12 @@ ScopedVector<AudioDecoder> RendererConfig::GetAudioDecoders(
return renderer_config_->GetAudioDecoders(media_task_runner, media_log_cb);
}
ScopedVector<VideoDecoder> RendererConfig::GetVideoDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb) {
return renderer_config_->GetVideoDecoders(media_task_runner, media_log_cb);
}
scoped_refptr<AudioRendererSink> RendererConfig::GetAudioRendererSink() {
return renderer_config_->GetAudioRendererSink();
}
......
......@@ -12,6 +12,7 @@
#include "media/base/audio_hardware_config.h"
#include "media/base/audio_renderer_sink.h"
#include "media/base/media_log.h"
#include "media/base/video_decoder.h"
namespace media {
......@@ -21,13 +22,17 @@ class PlatformRendererConfig {
public:
virtual ~PlatformRendererConfig() {};
// The list of audio decoders for use with the AudioRenderer. Ownership of
// the decoders is passed to the caller. The methods on each decoder will
// only be called on |media_task_runner|. |media_log_cb| should be used to
// log errors or important status information.
// The list of audio or video decoders for use with the AudioRenderer or
// VideoRenderer respectively. Ownership of the decoders is passed to the
// caller. The methods on each decoder will only be called on
// |media_task_runner|. |media_log_cb| should be used to log errors or
// important status information.
virtual ScopedVector<AudioDecoder> GetAudioDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb) = 0;
virtual ScopedVector<VideoDecoder> GetVideoDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb) = 0;
// The audio output sink used for rendering audio.
virtual scoped_refptr<AudioRendererSink> GetAudioRendererSink() = 0;
......@@ -36,7 +41,6 @@ class PlatformRendererConfig {
// constant for the lifetime of the PlatformRendererConfig.
virtual const AudioHardwareConfig& GetAudioHardwareConfig() = 0;
// TODO(dalecurtis): Expose methods for retrieving the video decoders.
};
class RendererConfig {
......@@ -49,6 +53,9 @@ class RendererConfig {
ScopedVector<AudioDecoder> GetAudioDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb);
ScopedVector<VideoDecoder> GetVideoDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb);
scoped_refptr<AudioRendererSink> GetAudioRendererSink();
const AudioHardwareConfig& GetAudioHardwareConfig();
......
......@@ -10,9 +10,17 @@
#include "media/audio/audio_output_stream_sink.h"
#include "media/audio/fake_audio_log_factory.h"
#include "media/base/media.h"
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/opus_audio_decoder.h"
#if !defined(OS_ANDROID)
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/ffmpeg_video_decoder.h"
#endif
#if !defined(MEDIA_DISABLE_LIBVPX)
#include "media/filters/vpx_video_decoder.h"
#endif
namespace media {
namespace internal {
......@@ -56,6 +64,25 @@ class DefaultRendererConfig : public PlatformRendererConfig {
return audio_decoders.Pass();
}
ScopedVector<VideoDecoder> GetVideoDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb) override {
ScopedVector<VideoDecoder> video_decoders;
// TODO(dalecurtis): If we ever need GPU video decoders, we'll need to
// figure out how to retrieve the GpuVideoAcceleratorFactories...
#if !defined(MEDIA_DISABLE_LIBVPX)
video_decoders.push_back(new VpxVideoDecoder(media_task_runner));
#endif // !defined(MEDIA_DISABLE_LIBVPX)
#if !defined(OS_ANDROID)
video_decoders.push_back(new FFmpegVideoDecoder(media_task_runner));
#endif
return video_decoders.Pass();
}
scoped_refptr<AudioRendererSink> GetAudioRendererSink() override {
return new AudioOutputStreamSink();
}
......
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