Commit e69b9325 authored by damienv's avatar damienv Committed by Commit bot

Add the frame provider base class used in cast media.

Also add an adapter from the Chrome media DemuxerStream
to the CodedFrameProvider.

BUG=408189

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

Cr-Commit-Position: refs/heads/master@{#293624}
parent ce69e2ad
// 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/media/cma/base/coded_frame_provider.h"
namespace chromecast {
namespace media {
CodedFrameProvider::CodedFrameProvider() {
}
CodedFrameProvider::~CodedFrameProvider() {
}
} // namespace media
} // namespace chromecast
// 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 CHROMECAST_MEDIA_CMA_BASE_CODED_FRAME_PROVIDER_H_
#define CHROMECAST_MEDIA_CMA_BASE_CODED_FRAME_PROVIDER_H_
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace media {
class AudioDecoderConfig;
class VideoDecoderConfig;
}
namespace chromecast {
namespace media {
class DecoderBufferBase;
class CodedFrameProvider {
public:
typedef base::Callback<void(const scoped_refptr<DecoderBufferBase>&,
const ::media::AudioDecoderConfig&,
const ::media::VideoDecoderConfig&)> ReadCB;
CodedFrameProvider();
virtual ~CodedFrameProvider();
// Request a coded frame which is provided asynchronously through callback
// |read_cb|.
// If the frame is associated with a new video/audio configuration,
// these configurations are returned as part of the |read_cb| callback.
// Invoking the |read_cb| callback with invalid audio/video configurations
// means the configurations have not changed.
virtual void Read(const ReadCB& read_cb) = 0;
// Flush the coded frames held by the frame provider.
// Invoke callback |flush_cb| when completed.
// Note: any pending read is cancelled, meaning that any pending |read_cb|
// callback will not be invoked.
virtual void Flush(const base::Closure& flush_cb) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CodedFrameProvider);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_BASE_CODED_FRAME_PROVIDER_H_
// 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/media/cma/filters/demuxer_stream_adapter.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/single_thread_task_runner.h"
#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
#include "chromecast/media/cma/base/cma_logging.h"
#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
#include "chromecast/media/cma/base/media_task_runner.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/buffers.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
namespace chromecast {
namespace media {
namespace {
class DummyMediaTaskRunner : public MediaTaskRunner {
public:
DummyMediaTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
// MediaTaskRunner implementation.
virtual bool PostMediaTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta timestamp) OVERRIDE;
private:
virtual ~DummyMediaTaskRunner();
scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
DISALLOW_COPY_AND_ASSIGN(DummyMediaTaskRunner);
};
DummyMediaTaskRunner::DummyMediaTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
: task_runner_(task_runner) {
}
DummyMediaTaskRunner::~DummyMediaTaskRunner() {
}
bool DummyMediaTaskRunner::PostMediaTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta timestamp) {
return task_runner_->PostTask(from_here, task);
}
} // namespace
DemuxerStreamAdapter::DemuxerStreamAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const scoped_refptr<BalancedMediaTaskRunnerFactory>&
media_task_runner_factory,
::media::DemuxerStream* demuxer_stream)
: task_runner_(task_runner),
media_task_runner_factory_(media_task_runner_factory),
media_task_runner_(new DummyMediaTaskRunner(task_runner)),
demuxer_stream_(demuxer_stream),
is_pending_read_(false),
weak_factory_(new base::WeakPtrFactory<DemuxerStreamAdapter>(this)) {
ResetMediaTaskRunner();
weak_this_ = weak_factory_->GetWeakPtr();
thread_checker_.DetachFromThread();
}
DemuxerStreamAdapter::~DemuxerStreamAdapter() {
// Needed since we use weak pointers:
// weak pointers must be invalidated on the same thread.
DCHECK(thread_checker_.CalledOnValidThread());
}
void DemuxerStreamAdapter::Read(const ReadCB& read_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
// Support only one read at a time.
DCHECK(!is_pending_read_);
is_pending_read_ = true;
bool may_run_in_future = media_task_runner_->PostMediaTask(
FROM_HERE,
base::Bind(&DemuxerStreamAdapter::RequestBuffer, weak_this_, read_cb),
max_pts_);
DCHECK(may_run_in_future);
}
void DemuxerStreamAdapter::Flush(const base::Closure& flush_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
CMALOG(kLogControl) << __FUNCTION__;
// Invalidate all the weak pointers so that we don't receive anymore buffers
// from |demuxer_stream_| that are associated with the current media
// timeline.
is_pending_read_ = false;
weak_factory_->InvalidateWeakPtrs();
weak_factory_.reset(new base::WeakPtrFactory<DemuxerStreamAdapter>(this));
weak_this_ = weak_factory_->GetWeakPtr();
// Reset the decoder configurations.
audio_config_ = ::media::AudioDecoderConfig();
video_config_ = ::media::VideoDecoderConfig();
// Create a new media task runner for the upcoming media playback.
ResetMediaTaskRunner();
CMALOG(kLogControl) << "Flush done";
flush_cb.Run();
}
void DemuxerStreamAdapter::ResetMediaTaskRunner() {
DCHECK(thread_checker_.CalledOnValidThread());
max_pts_ = ::media::kNoTimestamp();
if (media_task_runner_factory_.get()) {
media_task_runner_ =
media_task_runner_factory_->CreateMediaTaskRunner(task_runner_);
}
}
void DemuxerStreamAdapter::RequestBuffer(const ReadCB& read_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
demuxer_stream_->Read(::media::BindToCurrentLoop(
base::Bind(&DemuxerStreamAdapter::OnNewBuffer, weak_this_, read_cb)));
}
void DemuxerStreamAdapter::OnNewBuffer(
const ReadCB& read_cb,
::media::DemuxerStream::Status status,
const scoped_refptr< ::media::DecoderBuffer>& input) {
DCHECK(thread_checker_.CalledOnValidThread());
is_pending_read_ = false;
if (status == ::media::DemuxerStream::kAborted) {
DCHECK(input.get() == NULL);
return;
}
if (status == ::media::DemuxerStream::kConfigChanged) {
DCHECK(input.get() == NULL);
if (demuxer_stream_->type() == ::media::DemuxerStream::VIDEO)
video_config_ = demuxer_stream_->video_decoder_config();
if (demuxer_stream_->type() == ::media::DemuxerStream::AUDIO)
audio_config_ = demuxer_stream_->audio_decoder_config();
// Got a new config, but we still need to get a frame.
Read(read_cb);
return;
}
DCHECK_EQ(status, ::media::DemuxerStream::kOk);
// Updates the timestamp used for task scheduling.
if (!input->end_of_stream() &&
input->timestamp() != ::media::kNoTimestamp() &&
(max_pts_ == ::media::kNoTimestamp() || input->timestamp() > max_pts_)) {
max_pts_ = input->timestamp();
}
// Provides the buffer as well as possibly valid audio and video configs.
scoped_refptr<DecoderBufferBase> buffer(new DecoderBufferAdapter(input));
read_cb.Run(buffer, audio_config_, video_config_);
// Back to the default audio/video config:
// an invalid audio/video config means there is no config update.
if (audio_config_.IsValidConfig())
audio_config_ = ::media::AudioDecoderConfig();
if (video_config_.IsValidConfig())
video_config_ = ::media::VideoDecoderConfig();
}
} // namespace media
} // namespace chromecast
// 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 CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
#define CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "chromecast/media/cma/base/coded_frame_provider.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder_config.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace media {
class DemuxerStream;
}
namespace chromecast {
namespace media {
class BalancedMediaTaskRunnerFactory;
class MediaTaskRunner;
// DemuxerStreamAdapter wraps a DemuxerStream into a CodedFrameProvider.
class DemuxerStreamAdapter : public CodedFrameProvider {
public:
DemuxerStreamAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const scoped_refptr<BalancedMediaTaskRunnerFactory>&
media_task_runner_factory,
::media::DemuxerStream* demuxer_stream);
virtual ~DemuxerStreamAdapter();
// CodedFrameProvider implementation.
virtual void Read(const ReadCB& read_cb) OVERRIDE;
virtual void Flush(const base::Closure& flush_cb) OVERRIDE;
private:
void ResetMediaTaskRunner();
void RequestBuffer(const ReadCB& read_cb);
// Callback invoked from the demuxer stream to signal a buffer is ready.
void OnNewBuffer(const ReadCB& read_cb,
::media::DemuxerStream::Status status,
const scoped_refptr< ::media::DecoderBuffer>& input);
base::ThreadChecker thread_checker_;
// Task runner DemuxerStreamAdapter is running on.
scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
// Media task runner to pace requests to the DemuxerStream.
scoped_refptr<BalancedMediaTaskRunnerFactory> const
media_task_runner_factory_;
scoped_refptr<MediaTaskRunner> media_task_runner_;
base::TimeDelta max_pts_;
// Frames are provided by |demuxer_stream_|.
::media::DemuxerStream* const demuxer_stream_;
// Indicate if there is a pending read on the demuxer.
bool is_pending_read_;
// Audio/video configuration that applies to the next frame.
::media::AudioDecoderConfig audio_config_;
::media::VideoDecoderConfig video_config_;
scoped_ptr<base::WeakPtrFactory<DemuxerStreamAdapter> > weak_factory_;
base::WeakPtr<DemuxerStreamAdapter> weak_this_;
DISALLOW_COPY_AND_ASSIGN(DemuxerStreamAdapter);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
......@@ -22,6 +22,8 @@
'cma/base/buffering_state.cc',
'cma/base/buffering_state.h',
'cma/base/cma_logging.h',
'cma/base/coded_frame_provider.cc',
'cma/base/coded_frame_provider.h',
'cma/base/decoder_buffer_adapter.cc',
'cma/base/decoder_buffer_adapter.h',
'cma/base/decoder_buffer_base.cc',
......@@ -45,11 +47,25 @@
'cma/ipc/media_message_fifo.h',
],
},
{
'target_name': 'cma_filters',
'type': '<(component)',
'dependencies': [
'../../base/base.gyp:base',
'../../media/media.gyp:media',
'cma_base',
],
'sources': [
'cma/filters/demuxer_stream_adapter.cc',
'cma/filters/demuxer_stream_adapter.h',
],
},
{
'target_name': 'cast_media',
'type': 'none',
'dependencies': [
'cma_base',
'cma_filters',
'cma_ipc',
],
},
......@@ -69,6 +85,7 @@
'cma/base/balanced_media_task_runner_unittest.cc',
'cma/base/buffering_controller_unittest.cc',
'cma/base/run_all_unittests.cc',
'cma/filters/demuxer_stream_adapter_unittest.cc',
'cma/ipc/media_message_fifo_unittest.cc',
'cma/ipc/media_message_unittest.cc',
],
......
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