Commit 2e583073 authored by servolk's avatar servolk Committed by Commit bot

Chromecast: Play audio streams not supported by CMA via default renderer

For Chromecast we want to choose which media renderer to use based on
the types of input content streams. We will use CMA media renderer for
media types that are supported by our hardware (H264, AAC, etc) and
will use the default media renderer for audio streams other than AAC
or Vorbis. This will allow us support software decoding of FLAC and
Opus via the default Chrome audio path.

BUG=457959

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

Cr-Commit-Position: refs/heads/master@{#318941}
parent 365c5588
...@@ -496,8 +496,8 @@ ...@@ -496,8 +496,8 @@
'common/media/shared_memory_chunk.h', 'common/media/shared_memory_chunk.h',
'renderer/media/audio_pipeline_proxy.cc', 'renderer/media/audio_pipeline_proxy.cc',
'renderer/media/audio_pipeline_proxy.h', 'renderer/media/audio_pipeline_proxy.h',
'renderer/media/cma_media_renderer_factory.cc', 'renderer/media/chromecast_media_renderer_factory.cc',
'renderer/media/cma_media_renderer_factory.h', 'renderer/media/chromecast_media_renderer_factory.h',
'renderer/media/cma_message_filter_proxy.cc', 'renderer/media/cma_message_filter_proxy.cc',
'renderer/media/cma_message_filter_proxy.h', 'renderer/media/cma_message_filter_proxy.h',
'renderer/media/media_channel_proxy.cc', 'renderer/media/media_channel_proxy.cc',
......
// Copyright 2015 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 "chromecast/media/base/switching_media_renderer.h"
#include "base/logging.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/demuxer_stream.h"
#include "media/base/demuxer_stream_provider.h"
namespace chromecast {
namespace media {
SwitchingMediaRenderer::SwitchingMediaRenderer(
scoped_ptr<::media::Renderer> default_renderer,
scoped_ptr<::media::Renderer> cma_renderer)
: default_renderer_(default_renderer.Pass()),
cma_renderer_(cma_renderer.Pass()) {
DCHECK(default_renderer_);
DCHECK(cma_renderer_);
}
SwitchingMediaRenderer::~SwitchingMediaRenderer() {
}
void SwitchingMediaRenderer::Initialize(
::media::DemuxerStreamProvider* demuxer_stream_provider,
const base::Closure& init_cb,
const ::media::StatisticsCB& statistics_cb,
const ::media::BufferingStateCB& buffering_state_cb,
const ::media::Renderer::PaintCB& paint_cb,
const base::Closure& ended_cb,
const ::media::PipelineStatusCB& error_cb) {
// At this point the DemuxerStreamProvider should be fully initialized, so we
// have enough information to decide which renderer to use.
demuxer_stream_provider_ = demuxer_stream_provider;
DCHECK(demuxer_stream_provider_);
::media::DemuxerStream* audio_stream =
demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
::media::DemuxerStream* video_stream =
demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
if (audio_stream && !video_stream &&
audio_stream->audio_decoder_config().codec() != ::media::kCodecAAC &&
audio_stream->audio_decoder_config().codec() != ::media::kCodecVorbis) {
// We'll use the default Chrome media renderer with software audio decoding
cma_renderer_.reset();
} else {
// We'll use the CMA-based rendering with hardware decoding
default_renderer_.reset();
}
return GetRenderer()->Initialize(demuxer_stream_provider,
init_cb, statistics_cb, buffering_state_cb,
paint_cb, ended_cb, error_cb);
}
::media::Renderer* SwitchingMediaRenderer::GetRenderer() const {
DCHECK(default_renderer_ || cma_renderer_);
if (cma_renderer_)
return cma_renderer_.get();
DCHECK(default_renderer_);
return default_renderer_.get();
}
void SwitchingMediaRenderer::SetCdm(
::media::CdmContext* cdm_context,
const ::media::CdmAttachedCB& cdm_attached_cb) {
GetRenderer()->SetCdm(cdm_context, cdm_attached_cb);
}
void SwitchingMediaRenderer::Flush(const base::Closure& flush_cb) {
GetRenderer()->Flush(flush_cb);
}
void SwitchingMediaRenderer::StartPlayingFrom(base::TimeDelta time) {
GetRenderer()->StartPlayingFrom(time);
}
void SwitchingMediaRenderer::SetPlaybackRate(float playback_rate) {
GetRenderer()->SetPlaybackRate(playback_rate);
}
void SwitchingMediaRenderer::SetVolume(float volume) {
GetRenderer()->SetVolume(volume);
}
base::TimeDelta SwitchingMediaRenderer::GetMediaTime() {
return GetRenderer()->GetMediaTime();
}
bool SwitchingMediaRenderer::HasAudio() {
return GetRenderer()->HasAudio();
}
bool SwitchingMediaRenderer::HasVideo() {
return GetRenderer()->HasVideo();
}
} // namespace media
} // namespace chromecast
// Copyright 2015 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 CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_
#define CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/renderer.h"
namespace media {
class DemuxerStreamProvider;
}
namespace chromecast {
namespace media {
// Chromecast's custom media renderer which is capable of selecting an
// appropriate media renderer at runtime depending on the content.
// We'll look at media types of media streams present in DemuxerStreamProvider
// and will use either CMA-based renderer (for media types that are supported by
// our hardware decoder - H264 and VP8 video, AAC and Vorbis audio) or the
// default Chrome media renderer (this will allow us to support audio codecs
// like FLAC and Opus, which are decoded in software).
class SwitchingMediaRenderer : public ::media::Renderer {
public:
SwitchingMediaRenderer(
scoped_ptr<::media::Renderer> default_renderer,
scoped_ptr<::media::Renderer> cma_renderer);
~SwitchingMediaRenderer() override;
// ::media::Renderer implementation:
void Initialize(
::media::DemuxerStreamProvider* demuxer_stream_provider,
const base::Closure& init_cb,
const ::media::StatisticsCB& statistics_cb,
const ::media::BufferingStateCB& buffering_state_cb,
const ::media::Renderer::PaintCB& paint_cb,
const base::Closure& ended_cb,
const ::media::PipelineStatusCB& error_cb) override;
void SetCdm(::media::CdmContext* cdm_context,
const ::media::CdmAttachedCB& cdm_attached_cb) override;
void Flush(const base::Closure& flush_cb) override;
void StartPlayingFrom(base::TimeDelta time) override;
void SetPlaybackRate(float playback_rate) override;
void SetVolume(float volume) override;
base::TimeDelta GetMediaTime() override;
bool HasAudio() override;
bool HasVideo() override;
private:
// Returns the pointer to the actual renderer being used
::media::Renderer* GetRenderer() const;
::media::DemuxerStreamProvider* demuxer_stream_provider_;
scoped_ptr<::media::Renderer> default_renderer_;
scoped_ptr<::media::Renderer> cma_renderer_;
DISALLOW_COPY_AND_ASSIGN(SwitchingMediaRenderer);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_BASE_SWITCHING_MEDIA_RENDERER_H_
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
'base/decrypt_context_clearkey.h', 'base/decrypt_context_clearkey.h',
'base/key_systems_common.cc', 'base/key_systems_common.cc',
'base/key_systems_common.h', 'base/key_systems_common.h',
'base/switching_media_renderer.cc',
'base/switching_media_renderer.h',
], ],
'conditions': [ 'conditions': [
['chromecast_branding=="Chrome"', { ['chromecast_branding=="Chrome"', {
......
...@@ -6,6 +6,7 @@ include_rules = [ ...@@ -6,6 +6,7 @@ include_rules = [
"+components/network_hints/renderer", "+components/network_hints/renderer",
"+content/public/renderer", "+content/public/renderer",
"+media/base", "+media/base",
"+media/renderers",
"+third_party/WebKit/public/platform", "+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web", "+third_party/WebKit/public/web",
] ]
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "chromecast/renderer/cast_media_load_deferrer.h" #include "chromecast/renderer/cast_media_load_deferrer.h"
#include "chromecast/renderer/cast_render_process_observer.h" #include "chromecast/renderer/cast_render_process_observer.h"
#include "chromecast/renderer/key_systems_cast.h" #include "chromecast/renderer/key_systems_cast.h"
#include "chromecast/renderer/media/cma_media_renderer_factory.h" #include "chromecast/renderer/media/chromecast_media_renderer_factory.h"
#include "components/network_hints/renderer/prescient_networking_dispatcher.h" #include "components/network_hints/renderer/prescient_networking_dispatcher.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame.h"
...@@ -160,8 +160,8 @@ CastContentRendererClient::CreateMediaRendererFactory( ...@@ -160,8 +160,8 @@ CastContentRendererClient::CreateMediaRendererFactory(
return nullptr; return nullptr;
return scoped_ptr<::media::RendererFactory>( return scoped_ptr<::media::RendererFactory>(
new chromecast::media::CmaMediaRendererFactory( new chromecast::media::ChromecastMediaRendererFactory(
render_frame->GetRoutingID())); media_log, render_frame->GetRoutingID()));
} }
#endif #endif
......
// Copyright 2015 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 "chromecast/renderer/media/chromecast_media_renderer_factory.h"
#include "base/command_line.h"
#include "chromecast/media/base/switching_media_renderer.h"
#include "chromecast/media/cma/filters/cma_renderer.h"
#include "chromecast/renderer/media/media_pipeline_proxy.h"
#include "content/public/renderer/render_thread.h"
#include "media/base/audio_hardware_config.h"
#include "media/base/media_log.h"
#include "media/renderers/default_renderer_factory.h"
namespace chromecast {
namespace media {
ChromecastMediaRendererFactory::ChromecastMediaRendererFactory(
const scoped_refptr<::media::MediaLog>& media_log,
int render_frame_id)
: render_frame_id_(render_frame_id),
media_log_(media_log) {
}
ChromecastMediaRendererFactory::~ChromecastMediaRendererFactory() {
}
scoped_ptr<::media::Renderer> ChromecastMediaRendererFactory::CreateRenderer(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
::media::AudioRendererSink* audio_renderer_sink) {
if (!default_render_factory_) {
// Chromecast doesn't have input audio devices, so leave this uninitialized
::media::AudioParameters input_audio_params;
// TODO(servolk): Audio parameters are hardcoded for now, but in the future
// either we need to obtain AudioHardwareConfig from RenderThreadImpl,
// or media renderer needs to figure out optimal audio parameters itself.
const int kDefaultSamplingRate = 48000;
const int kDefaultBitsPerSample = 16;
// About 20ms of stereo (2 channels) 16bit (2 byte) audio
int buffer_size = kDefaultSamplingRate * 20 * 2 * 2 / 1000;
::media::AudioParameters output_audio_params(
::media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
::media::CHANNEL_LAYOUT_STEREO,
kDefaultSamplingRate, kDefaultBitsPerSample,
buffer_size, ::media::AudioParameters::NO_EFFECTS);
::media::AudioHardwareConfig audio_config(input_audio_params,
output_audio_params);
default_render_factory_.reset(new ::media::DefaultRendererFactory(
media_log_, /*gpu_factories*/ nullptr, audio_config));
}
DCHECK(default_render_factory_);
// TODO(erickung): crbug.com/443956. Need to provide right LoadType.
LoadType cma_load_type = kLoadTypeMediaSource;
scoped_ptr<MediaPipeline> cma_media_pipeline(
new MediaPipelineProxy(
render_frame_id_,
content::RenderThread::Get()->GetIOMessageLoopProxy(),
cma_load_type));
scoped_ptr<CmaRenderer> cma_renderer(
new CmaRenderer(cma_media_pipeline.Pass()));
scoped_ptr<::media::Renderer> default_media_render(
default_render_factory_->CreateRenderer(media_task_runner,
audio_renderer_sink));
scoped_ptr<SwitchingMediaRenderer> media_renderer(new SwitchingMediaRenderer(
default_media_render.Pass(), cma_renderer.Pass()));
return media_renderer.Pass();
}
} // namespace media
} // namespace chromecast
// Copyright 2014 The Chromium Authors. All rights reserved. // Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ #ifndef CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_
#define CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ #define CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "media/base/renderer_factory.h" #include "media/base/renderer_factory.h"
namespace media {
class MediaLog;
class DefaultRendererFactory;
}
namespace chromecast { namespace chromecast {
namespace media { namespace media {
class CmaMediaRendererFactory : public ::media::RendererFactory { class ChromecastMediaRendererFactory : public ::media::RendererFactory {
public: public:
explicit CmaMediaRendererFactory(int render_frame_id); ChromecastMediaRendererFactory(
~CmaMediaRendererFactory() final; const scoped_refptr<::media::MediaLog>& media_log,
int render_frame_id);
~ChromecastMediaRendererFactory() final;
// ::media::RendererFactory implementation. // ::media::RendererFactory implementation.
scoped_ptr< ::media::Renderer> CreateRenderer( scoped_ptr<::media::Renderer> CreateRenderer(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
::media::AudioRendererSink* audio_renderer_sink) final; ::media::AudioRendererSink* audio_renderer_sink) final;
private: private:
int render_frame_id_; int render_frame_id_;
DISALLOW_COPY_AND_ASSIGN(CmaMediaRendererFactory); scoped_refptr<::media::MediaLog> media_log_;
scoped_ptr<::media::DefaultRendererFactory> default_render_factory_;
DISALLOW_COPY_AND_ASSIGN(ChromecastMediaRendererFactory);
}; };
} // namespace media } // namespace media
} // namespace chromecast } // namespace chromecast
#endif // CHROMECAST_RENDERER_MEDIA_CMA_MEDIA_RENDERER_FACTORY_H_ #endif // CHROMECAST_RENDERER_MEDIA_CHROMECAST_MEDIA_RENDERER_FACTORY_H_
\ No newline at end of file
// 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 "chromecast/renderer/media/cma_media_renderer_factory.h"
#include "base/command_line.h"
#include "chromecast/media/cma/filters/cma_renderer.h"
#include "chromecast/renderer/media/media_pipeline_proxy.h"
#include "content/public/renderer/render_thread.h"
namespace chromecast {
namespace media {
CmaMediaRendererFactory::CmaMediaRendererFactory(int render_frame_id)
: render_frame_id_(render_frame_id) {
}
CmaMediaRendererFactory::~CmaMediaRendererFactory() {
}
scoped_ptr< ::media::Renderer> CmaMediaRendererFactory::CreateRenderer(
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
::media::AudioRendererSink* audio_renderer_sink) {
// TODO(erickung): crbug.com/443956. Need to provide right LoadType.
LoadType cma_load_type = kLoadTypeMediaSource;
scoped_ptr<MediaPipeline> cma_media_pipeline(
new MediaPipelineProxy(
render_frame_id_,
content::RenderThread::Get()->GetIOMessageLoopProxy(),
cma_load_type));
return scoped_ptr< ::media::Renderer>(
new CmaRenderer(cma_media_pipeline.Pass()));
}
} // namespace media
} // namespace chromecast
\ No newline at end of file
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