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 @@ ...@@ -1038,9 +1038,11 @@
], ],
'export_dependent_settings': [ 'export_dependent_settings': [
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings', '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../mojo/services/public/mojo_services_public.gyp:mojo_geometry_bindings',
], ],
'dependencies': [ 'dependencies': [
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings', '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../mojo/services/public/mojo_services_public.gyp:mojo_geometry_bindings',
], ],
}, },
{ {
...@@ -1053,9 +1055,12 @@ ...@@ -1053,9 +1055,12 @@
'media', 'media',
'media_mojo_bindings', 'media_mojo_bindings',
'../base/base.gyp:base', '../base/base.gyp:base',
'../mojo/mojo_geometry_converters.gyp:mojo_geometry_lib',
'../mojo/mojo_base.gyp:mojo_environment_chromium', '../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_base', '../mojo/public/mojo_public.gyp:mojo_application_base',
'../mojo/public/mojo_public.gyp:mojo_application_bindings', '../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/gfx/gfx.gyp:gfx_geometry',
'<(mojo_system_for_component)', '<(mojo_system_for_component)',
], ],
'export_dependent_settings': [ 'export_dependent_settings': [
...@@ -1084,6 +1089,8 @@ ...@@ -1084,6 +1089,8 @@
'shared_memory_support', 'shared_memory_support',
], ],
'sources': [ '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.cc',
'mojo/services/mojo_demuxer_stream_adapter.h', 'mojo/services/mojo_demuxer_stream_adapter.h',
'mojo/services/mojo_renderer_service.cc', 'mojo/services/mojo_renderer_service.cc',
......
include_rules = [ include_rules = [
"+mojo/application", "+mojo/application",
"+mojo/converters",
"+mojo/public", "+mojo/public",
] ]
...@@ -11,4 +11,8 @@ mojom("interfaces") { ...@@ -11,4 +11,8 @@ mojom("interfaces") {
"media_renderer.mojom", "media_renderer.mojom",
"demuxer_stream.mojom", "demuxer_stream.mojom",
] ]
deps = [
"//mojo/services/public/interfaces/geometry",
]
} }
...@@ -15,7 +15,8 @@ interface DemuxerStream { ...@@ -15,7 +15,8 @@ interface DemuxerStream {
enum Type { enum Type {
UNKNOWN, UNKNOWN,
AUDIO, AUDIO,
LAST_TYPE = AUDIO VIDEO,
LAST_TYPE = VIDEO,
}; };
// See media::DemuxerStream for descriptions. // See media::DemuxerStream for descriptions.
...@@ -49,4 +50,9 @@ interface DemuxerStreamClient { ...@@ -49,4 +50,9 @@ interface DemuxerStreamClient {
// whenever a DemuxerStream::STATUS_CONFIG_CHANGED is observed (either // whenever a DemuxerStream::STATUS_CONFIG_CHANGED is observed (either
// in a Read() callback or over the DataPipe). // in a Read() callback or over the DataPipe).
OnAudioDecoderConfigChanged(AudioDecoderConfig config); 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"; ...@@ -9,10 +9,11 @@ import "media/mojo/interfaces/media_types.mojom";
[Client=MediaRendererClient] [Client=MediaRendererClient]
interface MediaRenderer { 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 // NOTE: If an error occurs, MediaRendererClient::OnError() will be called
// before the callback is executed. // before the callback is executed.
Initialize(DemuxerStream stream) => (); Initialize(DemuxerStream? audio, DemuxerStream? video) => ();
// Discards any buffered data, executing callback when completed. // Discards any buffered data, executing callback when completed.
// NOTE: If an error occurs, MediaRendererClient::OnError() can be called // NOTE: If an error occurs, MediaRendererClient::OnError() can be called
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
module mojo; module mojo;
import "mojo/services/public/interfaces/geometry/geometry.mojom";
// See media/base/buffering_state.h for descriptions. // See media/base/buffering_state.h for descriptions.
// Kept in sync with media::BufferingState via COMPILE_ASSERTs. // Kept in sync with media::BufferingState via COMPILE_ASSERTs.
enum BufferingState { enum BufferingState {
...@@ -68,7 +70,7 @@ enum ChannelLayout { ...@@ -68,7 +70,7 @@ enum ChannelLayout {
k_OCTAGONAL = 28, k_OCTAGONAL = 28,
k_DISCRETE = 29, k_DISCRETE = 29,
k_STEREO_AND_KEYBOARD_MIC = 30, 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. // See media/base/sample_format.h for descriptions.
...@@ -84,6 +86,63 @@ enum SampleFormat { ...@@ -84,6 +86,63 @@ enum SampleFormat {
Max = PlanarF32, 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. // This defines a mojo transport format for media::AudioDecoderConfig.
// See media/base/audio_decoder_config.h for descriptions. // See media/base/audio_decoder_config.h for descriptions.
struct AudioDecoderConfig { struct AudioDecoderConfig {
...@@ -96,6 +155,19 @@ struct AudioDecoderConfig { ...@@ -96,6 +155,19 @@ struct AudioDecoderConfig {
int32 codec_delay; 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. // This defines a mojo transport format for media::DecoderBuffer.
struct MediaDecoderBuffer { struct MediaDecoderBuffer {
// See media/base/buffers.h for details. // See media/base/buffers.h for details.
......
...@@ -10,8 +10,11 @@ source_set("lib") { ...@@ -10,8 +10,11 @@ source_set("lib") {
"//media", "//media",
"//media/mojo/interfaces", "//media/mojo/interfaces",
"//mojo/common", "//mojo/common",
"//mojo/converters/geometry",
"//mojo/environment:chromium", "//mojo/environment:chromium",
"//mojo/public/c/system:for_component", "//mojo/public/c/system:for_component",
"//mojo/services/public/interfaces/geometry",
"//skia",
] ]
sources = [ sources = [
...@@ -61,6 +64,8 @@ shared_library("renderer_app") { ...@@ -61,6 +64,8 @@ shared_library("renderer_app") {
] ]
sources = [ sources = [
"demuxer_stream_provider_shim.cc",
"demuxer_stream_provider_shim.h",
"mojo_renderer_service.cc", "mojo_renderer_service.cc",
"mojo_renderer_service.h", "mojo_renderer_service.h",
"renderer_config.cc", "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 @@ ...@@ -10,6 +10,7 @@
namespace media { namespace media {
class AudioDecoderConfig; class AudioDecoderConfig;
class VideoDecoderConfig;
class DecoderBuffer; class DecoderBuffer;
} }
...@@ -37,6 +38,15 @@ struct TypeConverter<media::AudioDecoderConfig, AudioDecoderConfigPtr> { ...@@ -37,6 +38,15 @@ struct TypeConverter<media::AudioDecoderConfig, AudioDecoderConfigPtr> {
static media::AudioDecoderConfig Convert(const AudioDecoderConfigPtr& input); 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 } // namespace mojo
#endif // MEDIA_MOJO_SERVICES_MEDIA_TYPE_CONVERTERS_H_ #endif // MEDIA_MOJO_SERVICES_MEDIA_TYPE_CONVERTERS_H_
...@@ -16,6 +16,7 @@ MojoDemuxerStreamAdapter::MojoDemuxerStreamAdapter( ...@@ -16,6 +16,7 @@ MojoDemuxerStreamAdapter::MojoDemuxerStreamAdapter(
const base::Closure& stream_ready_cb) const base::Closure& stream_ready_cb)
: demuxer_stream_(demuxer_stream.Pass()), : demuxer_stream_(demuxer_stream.Pass()),
stream_ready_cb_(stream_ready_cb), stream_ready_cb_(stream_ready_cb),
type_(DemuxerStream::UNKNOWN),
weak_factory_(this) { weak_factory_(this) {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
demuxer_stream_.set_client(this); demuxer_stream_.set_client(this);
...@@ -35,21 +36,23 @@ void MojoDemuxerStreamAdapter::Read(const DemuxerStream::ReadCB& read_cb) { ...@@ -35,21 +36,23 @@ void MojoDemuxerStreamAdapter::Read(const DemuxerStream::ReadCB& read_cb) {
} }
AudioDecoderConfig MojoDemuxerStreamAdapter::audio_decoder_config() { AudioDecoderConfig MojoDemuxerStreamAdapter::audio_decoder_config() {
DCHECK(!config_queue_.empty()); DCHECK_EQ(type_, DemuxerStream::AUDIO);
return config_queue_.front(); DCHECK(!audio_config_queue_.empty());
return audio_config_queue_.front();
} }
VideoDecoderConfig MojoDemuxerStreamAdapter::video_decoder_config() { VideoDecoderConfig MojoDemuxerStreamAdapter::video_decoder_config() {
NOTREACHED(); DCHECK_EQ(type_, DemuxerStream::VIDEO);
return VideoDecoderConfig(); DCHECK(!video_config_queue_.empty());
return video_config_queue_.front();
} }
media::DemuxerStream::Type MojoDemuxerStreamAdapter::type() { DemuxerStream::Type MojoDemuxerStreamAdapter::type() {
return media::DemuxerStream::AUDIO; return type_;
} }
void MojoDemuxerStreamAdapter::EnableBitstreamConverter() { void MojoDemuxerStreamAdapter::EnableBitstreamConverter() {
NOTREACHED(); NOTIMPLEMENTED();
} }
bool MojoDemuxerStreamAdapter::SupportsConfigChanges() { bool MojoDemuxerStreamAdapter::SupportsConfigChanges() {
...@@ -66,16 +69,34 @@ void MojoDemuxerStreamAdapter::OnStreamReady( ...@@ -66,16 +69,34 @@ void MojoDemuxerStreamAdapter::OnStreamReady(
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
// TODO(tim): We don't support pipe streaming yet. // TODO(tim): We don't support pipe streaming yet.
DCHECK(!pipe.is_valid()); DCHECK(!pipe.is_valid());
DCHECK(!config_queue_.empty()); DCHECK_NE(type_, DemuxerStream::UNKNOWN);
stream_ready_cb_.Run(); stream_ready_cb_.Run();
} }
void MojoDemuxerStreamAdapter::OnAudioDecoderConfigChanged( void MojoDemuxerStreamAdapter::OnAudioDecoderConfigChanged(
mojo::AudioDecoderConfigPtr config) { 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(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()) { if (!read_cb_.is_null()) {
read_cb_.Run(media::DemuxerStream::Status::kConfigChanged, NULL); read_cb_.Run(DemuxerStream::Status::kConfigChanged, NULL);
read_cb_.Reset(); read_cb_.Reset();
} }
} }
...@@ -85,22 +106,30 @@ void MojoDemuxerStreamAdapter::OnBufferReady( ...@@ -85,22 +106,30 @@ void MojoDemuxerStreamAdapter::OnBufferReady(
mojo::MediaDecoderBufferPtr buffer) { mojo::MediaDecoderBufferPtr buffer) {
DVLOG(3) << __FUNCTION__; DVLOG(3) << __FUNCTION__;
DCHECK(!read_cb_.is_null()); DCHECK(!read_cb_.is_null());
DCHECK(!config_queue_.empty()); DCHECK_NE(type_, DemuxerStream::UNKNOWN);
media::DemuxerStream::Status media_status( DemuxerStream::Status media_status(
static_cast<media::DemuxerStream::Status>(status)); static_cast<DemuxerStream::Status>(status));
scoped_refptr<media::DecoderBuffer> media_buffer( scoped_refptr<DecoderBuffer> media_buffer(
buffer.To<scoped_refptr<media::DecoderBuffer> >()); buffer.To<scoped_refptr<DecoderBuffer>>());
if (status == mojo::DemuxerStream::STATUS_CONFIG_CHANGED) { if (status == mojo::DemuxerStream::STATUS_CONFIG_CHANGED) {
DCHECK(!media_buffer.get()); DCHECK(!media_buffer.get());
config_queue_.pop();
// If the |config_queue_| is empty we need to wait for // If the configuration queue is empty we need to wait for a config change
// OnAudioDecoderConfigChanged before invoking |read_cb|. // event before invoking |read_cb_|.
if (config_queue_.empty())
return; 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_.Run(media_status, media_buffer);
read_cb_.Reset(); read_cb_.Reset();
} }
......
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
namespace media { namespace media {
// This class acts as a MojoRendererService-side stub for a real // This class acts as a MojoRendererService-side stub for a real DemuxerStream
// media::DemuxerStream that is part of a media::Pipeline in a remote // that is part of a Pipeline in a remote application. Roughly speaking, it
// application. Roughly speaking, it takes a mojo::DemuxerStreamPtr and exposes // takes a mojo::DemuxerStreamPtr and exposes it as a DemuxerStream for use by
// it as a media::DemuxerStream for use by media components. // media components.
class MojoDemuxerStreamAdapter : public media::DemuxerStream, class MojoDemuxerStreamAdapter : public DemuxerStream,
public mojo::DemuxerStreamClient { public mojo::DemuxerStreamClient {
public: public:
// |demuxer_stream| is connected to the mojo::DemuxerStream that |this| will // |demuxer_stream| is connected to the mojo::DemuxerStream that |this| will
...@@ -31,7 +31,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream, ...@@ -31,7 +31,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
const base::Closure& stream_ready_cb); const base::Closure& stream_ready_cb);
~MojoDemuxerStreamAdapter() override; ~MojoDemuxerStreamAdapter() override;
// media::DemuxerStream implementation. // DemuxerStream implementation.
void Read(const ReadCB& read_cb) override; void Read(const ReadCB& read_cb) override;
AudioDecoderConfig audio_decoder_config() override; AudioDecoderConfig audio_decoder_config() override;
VideoDecoderConfig video_decoder_config() override; VideoDecoderConfig video_decoder_config() override;
...@@ -43,6 +43,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream, ...@@ -43,6 +43,7 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
// mojo::DemuxerStreamClient implementation. // mojo::DemuxerStreamClient implementation.
void OnStreamReady(mojo::ScopedDataPipeConsumerHandle pipe) override; void OnStreamReady(mojo::ScopedDataPipeConsumerHandle pipe) override;
void OnAudioDecoderConfigChanged(mojo::AudioDecoderConfigPtr config) override; void OnAudioDecoderConfigChanged(mojo::AudioDecoderConfigPtr config) override;
void OnVideoDecoderConfigChanged(mojo::VideoDecoderConfigPtr config) override;
private: private:
// The callback from |demuxer_stream_| that a read operation has completed. // The callback from |demuxer_stream_| that a read operation has completed.
...@@ -63,7 +64,10 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream, ...@@ -63,7 +64,10 @@ class MojoDemuxerStreamAdapter : public media::DemuxerStream,
// The front of the queue is the current config. We pop when we observe // The front of the queue is the current config. We pop when we observe
// DemuxerStatus::CONFIG_CHANGED. // 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_; base::WeakPtrFactory<MojoDemuxerStreamAdapter> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MojoDemuxerStreamAdapter); DISALLOW_COPY_AND_ASSIGN(MojoDemuxerStreamAdapter);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/macros.h" #include "base/macros.h"
#include "media/base/audio_decoder_config.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/interfaces/demuxer_stream.mojom.h"
#include "media/mojo/services/media_type_converters.h" #include "media/mojo/services/media_type_converters.h"
#include "mojo/public/cpp/bindings/interface_impl.h" #include "mojo/public/cpp/bindings/interface_impl.h"
...@@ -35,8 +36,13 @@ void MojoDemuxerStreamImpl::OnBufferReady( ...@@ -35,8 +36,13 @@ void MojoDemuxerStreamImpl::OnBufferReady(
if (status == media::DemuxerStream::kConfigChanged) { if (status == media::DemuxerStream::kConfigChanged) {
// Send the config change so our client can read it once it parses the // Send the config change so our client can read it once it parses the
// Status obtained via Run() below. // Status obtained via Run() below.
client()->OnAudioDecoderConfigChanged( if (stream_->type() == media::DemuxerStream::AUDIO) {
mojo::AudioDecoderConfig::From(stream_->audio_decoder_config())); 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 // TODO(tim): Once using DataPipe, fill via the producer handle and then
...@@ -49,8 +55,13 @@ void MojoDemuxerStreamImpl::OnConnectionEstablished() { ...@@ -49,8 +55,13 @@ void MojoDemuxerStreamImpl::OnConnectionEstablished() {
// This is called when our DemuxerStreamClient has connected itself and is // This is called when our DemuxerStreamClient has connected itself and is
// ready to receive messages. Send an initial config and notify it that // ready to receive messages. Send an initial config and notify it that
// we are now ready for business. // we are now ready for business.
client()->OnAudioDecoderConfigChanged( if (stream_->type() == media::DemuxerStream::AUDIO) {
mojo::AudioDecoderConfig::From(stream_->audio_decoder_config())); 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 // TODO(tim): Create a DataPipe, hold the producer handle, and pass the
// consumer handle here. // consumer handle here.
......
...@@ -53,14 +53,24 @@ void MojoRendererImpl::Initialize( ...@@ -53,14 +53,24 @@ void MojoRendererImpl::Initialize(
error_cb_ = error_cb; error_cb_ = error_cb;
buffering_state_cb_ = buffering_state_cb; buffering_state_cb_ = buffering_state_cb;
// Create a mojo::DemuxerStream and bind its lifetime to the pipe. // Create audio and video mojo::DemuxerStream and bind its lifetime to the
mojo::DemuxerStreamPtr demuxer_stream; // pipe.
mojo::BindToProxy( DemuxerStream* const audio =
new MojoDemuxerStreamImpl( demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)), DemuxerStream* const video =
&demuxer_stream); 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( remote_audio_renderer_->Initialize(
demuxer_stream.Pass(), audio_stream.Pass(),
video_stream.Pass(),
BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized, BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized,
weak_factory_.GetWeakPtr()))); weak_factory_.GetWeakPtr())));
} }
...@@ -105,13 +115,13 @@ bool MojoRendererImpl::HasAudio() { ...@@ -105,13 +115,13 @@ bool MojoRendererImpl::HasAudio() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(remote_audio_renderer_.get()); // We always bind the renderer. DCHECK(remote_audio_renderer_.get()); // We always bind the renderer.
return true; return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
} }
bool MojoRendererImpl::HasVideo() { bool MojoRendererImpl::HasVideo() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
return false; return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
} }
void MojoRendererImpl::SetCdm(MediaKeys* cdm) { void MojoRendererImpl::SetCdm(MediaKeys* cdm) {
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "media/base/video_renderer.h" #include "media/base/video_renderer.h"
#include "media/filters/audio_renderer_impl.h" #include "media/filters/audio_renderer_impl.h"
#include "media/filters/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/mojo_demuxer_stream_adapter.h"
#include "media/mojo/services/renderer_config.h" #include "media/mojo/services/renderer_config.h"
#include "mojo/application/application_runner_chromium.h" #include "mojo/application/application_runner_chromium.h"
...@@ -33,29 +35,8 @@ static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log, ...@@ -33,29 +35,8 @@ static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log,
media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
} }
// Shim DemuxerStreamProvider wrapper for a single DemuxerStream. static void PaintNothing(const scoped_refptr<VideoFrame>& frame) {
// 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);
};
class MojoRendererApplication class MojoRendererApplication
: public mojo::ApplicationDelegate, : public mojo::ApplicationDelegate,
...@@ -102,7 +83,16 @@ MojoRendererService::MojoRendererService( ...@@ -102,7 +83,16 @@ MojoRendererService::MojoRendererService(
SetDecryptorReadyCB(), SetDecryptorReadyCB(),
renderer_config->GetAudioHardwareConfig(), renderer_config->GetAudioHardwareConfig(),
media_log)); 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. // Create renderer.
renderer_.reset(new RendererImpl( renderer_.reset(new RendererImpl(
...@@ -112,7 +102,8 @@ MojoRendererService::MojoRendererService( ...@@ -112,7 +102,8 @@ MojoRendererService::MojoRendererService(
MojoRendererService::~MojoRendererService() { MojoRendererService::~MojoRendererService() {
} }
void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream, void MojoRendererService::Initialize(mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const mojo::Closure& callback) { const mojo::Closure& callback) {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK_EQ(state_, STATE_UNINITIALIZED); DCHECK_EQ(state_, STATE_UNINITIALIZED);
...@@ -120,11 +111,9 @@ void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream, ...@@ -120,11 +111,9 @@ void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream,
state_ = STATE_INITIALIZING; state_ = STATE_INITIALIZING;
stream_provider_.reset(new DemuxerStreamProviderShim( stream_provider_.reset(new DemuxerStreamProviderShim(
make_scoped_ptr(new MojoDemuxerStreamAdapter( audio.Pass(),
stream.Pass(), video.Pass(),
base::Bind(&MojoRendererService::OnStreamReady, base::Bind(&MojoRendererService::OnStreamReady, weak_this_, callback)));
weak_this_,
callback))).Pass()));
} }
void MojoRendererService::Flush(const mojo::Closure& callback) { void MojoRendererService::Flush(const mojo::Closure& callback) {
......
...@@ -39,7 +39,8 @@ class MojoRendererService : public mojo::InterfaceImpl<mojo::MediaRenderer> { ...@@ -39,7 +39,8 @@ class MojoRendererService : public mojo::InterfaceImpl<mojo::MediaRenderer> {
~MojoRendererService() override; ~MojoRendererService() override;
// mojo::MediaRenderer implementation. // mojo::MediaRenderer implementation.
void Initialize(mojo::DemuxerStreamPtr streams, void Initialize(mojo::DemuxerStreamPtr audio,
mojo::DemuxerStreamPtr video,
const mojo::Closure& callback) override; const mojo::Closure& callback) override;
void Flush(const mojo::Closure& callback) override; void Flush(const mojo::Closure& callback) override;
void StartPlayingFrom(int64_t time_delta_usec) override; void StartPlayingFrom(int64_t time_delta_usec) override;
......
...@@ -24,6 +24,12 @@ ScopedVector<AudioDecoder> RendererConfig::GetAudioDecoders( ...@@ -24,6 +24,12 @@ ScopedVector<AudioDecoder> RendererConfig::GetAudioDecoders(
return renderer_config_->GetAudioDecoders(media_task_runner, media_log_cb); 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() { scoped_refptr<AudioRendererSink> RendererConfig::GetAudioRendererSink() {
return renderer_config_->GetAudioRendererSink(); return renderer_config_->GetAudioRendererSink();
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "media/base/audio_hardware_config.h" #include "media/base/audio_hardware_config.h"
#include "media/base/audio_renderer_sink.h" #include "media/base/audio_renderer_sink.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/video_decoder.h"
namespace media { namespace media {
...@@ -21,13 +22,17 @@ class PlatformRendererConfig { ...@@ -21,13 +22,17 @@ class PlatformRendererConfig {
public: public:
virtual ~PlatformRendererConfig() {}; virtual ~PlatformRendererConfig() {};
// The list of audio decoders for use with the AudioRenderer. Ownership of // The list of audio or video decoders for use with the AudioRenderer or
// the decoders is passed to the caller. The methods on each decoder will // VideoRenderer respectively. Ownership of the decoders is passed to the
// only be called on |media_task_runner|. |media_log_cb| should be used to // caller. The methods on each decoder will only be called on
// log errors or important status information. // |media_task_runner|. |media_log_cb| should be used to log errors or
// important status information.
virtual ScopedVector<AudioDecoder> GetAudioDecoders( virtual ScopedVector<AudioDecoder> GetAudioDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb) = 0; 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. // The audio output sink used for rendering audio.
virtual scoped_refptr<AudioRendererSink> GetAudioRendererSink() = 0; virtual scoped_refptr<AudioRendererSink> GetAudioRendererSink() = 0;
...@@ -36,7 +41,6 @@ class PlatformRendererConfig { ...@@ -36,7 +41,6 @@ class PlatformRendererConfig {
// constant for the lifetime of the PlatformRendererConfig. // constant for the lifetime of the PlatformRendererConfig.
virtual const AudioHardwareConfig& GetAudioHardwareConfig() = 0; virtual const AudioHardwareConfig& GetAudioHardwareConfig() = 0;
// TODO(dalecurtis): Expose methods for retrieving the video decoders.
}; };
class RendererConfig { class RendererConfig {
...@@ -49,6 +53,9 @@ class RendererConfig { ...@@ -49,6 +53,9 @@ class RendererConfig {
ScopedVector<AudioDecoder> GetAudioDecoders( ScopedVector<AudioDecoder> GetAudioDecoders(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
const LogCB& media_log_cb); 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(); scoped_refptr<AudioRendererSink> GetAudioRendererSink();
const AudioHardwareConfig& GetAudioHardwareConfig(); const AudioHardwareConfig& GetAudioHardwareConfig();
......
...@@ -10,9 +10,17 @@ ...@@ -10,9 +10,17 @@
#include "media/audio/audio_output_stream_sink.h" #include "media/audio/audio_output_stream_sink.h"
#include "media/audio/fake_audio_log_factory.h" #include "media/audio/fake_audio_log_factory.h"
#include "media/base/media.h" #include "media/base/media.h"
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/opus_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 media {
namespace internal { namespace internal {
...@@ -56,6 +64,25 @@ class DefaultRendererConfig : public PlatformRendererConfig { ...@@ -56,6 +64,25 @@ class DefaultRendererConfig : public PlatformRendererConfig {
return audio_decoders.Pass(); 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 { scoped_refptr<AudioRendererSink> GetAudioRendererSink() override {
return new AudioOutputStreamSink(); 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