#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_number_conversions.h"
#include "content/renderer/media/android/renderer_demuxer_android.h"
-#include "content/renderer/media/webmediaplayer_util.h"
-#include "content/renderer/media/webmediasource_impl.h"
#include "media/base/android/demuxer_stream_player_params.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
+#include "media/blink/webmediaplayer_util.h"
+#include "media/blink/webmediasource_impl.h"
#include "media/filters/chunk_demuxer.h"
#include "media/filters/decrypting_demuxer_stream.h"
#include "third_party/WebKit/public/platform/WebString.h"
MediaSourceDelegate::MediaSourceDelegate(
RendererDemuxerAndroid* demuxer_client,
int demuxer_client_id,
- const scoped_refptr<base::MessageLoopProxy>& media_loop,
- media::MediaLog* media_log)
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const scoped_refptr<media::MediaLog> media_log)
: demuxer_client_(demuxer_client),
demuxer_client_id_(demuxer_client_id),
media_log_(media_log),
browser_seek_time_(media::kNoTimestamp()),
expecting_regular_seek_(false),
access_unit_size_(0),
- main_loop_(base::MessageLoopProxy::current()),
- media_loop_(media_loop),
+ main_task_runner_(base::MessageLoopProxy::current()),
+ media_task_runner_(media_task_runner),
main_weak_factory_(this),
media_weak_factory_(this),
main_weak_this_(main_weak_factory_.GetWeakPtr()) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
}
MediaSourceDelegate::~MediaSourceDelegate() {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!chunk_demuxer_);
DCHECK(!demuxer_client_);
DCHECK(!video_stream_);
}
-void MediaSourceDelegate::Destroy() {
- DCHECK(main_loop_->BelongsToCurrentThread());
+void MediaSourceDelegate::Stop(const base::Closure& stop_cb) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (!chunk_demuxer_) {
DCHECK(!demuxer_client_);
- delete this;
return;
}
chunk_demuxer_->Shutdown();
- // |this| will be transferred to the callback StopDemuxer() and
- // OnDemuxerStopDone(). They own |this| and OnDemuxerStopDone() will delete
- // it when called, hence using base::Unretained(this) is safe here.
- media_loop_->PostTask(FROM_HERE,
- base::Bind(&MediaSourceDelegate::StopDemuxer,
- base::Unretained(this)));
+ // Continue to stop objects on the media thread.
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &MediaSourceDelegate::StopDemuxer, base::Unretained(this), stop_cb));
}
bool MediaSourceDelegate::IsVideoEncrypted() {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
base::AutoLock auto_lock(is_video_encrypted_lock_);
return is_video_encrypted_;
}
-void MediaSourceDelegate::StopDemuxer() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+base::Time MediaSourceDelegate::GetTimelineOffset() const {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (!chunk_demuxer_)
+ return base::Time();
+
+ return chunk_demuxer_->GetTimelineOffset();
+}
+
+void MediaSourceDelegate::StopDemuxer(const base::Closure& stop_cb) {
+ DVLOG(2) << __FUNCTION__;
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DCHECK(chunk_demuxer_);
demuxer_client_->RemoveDelegate(demuxer_client_id_);
media_weak_factory_.InvalidateWeakPtrs();
DCHECK(!media_weak_factory_.HasWeakPtrs());
- // The callback OnDemuxerStopDone() owns |this| and will delete it when
- // called. Hence using base::Unretained(this) is safe here.
- chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone,
- base::Unretained(this)));
+ chunk_demuxer_->Stop();
+ chunk_demuxer_.reset();
+
+ // |this| may be destroyed at this point in time as a result of running
+ // |stop_cb|.
+ stop_cb.Run();
}
void MediaSourceDelegate::InitializeMediaSource(
const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
const DurationChangeCB& duration_change_cb) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(!media_source_opened_cb.is_null());
media_source_opened_cb_ = media_source_opened_cb;
need_key_cb_ = need_key_cb;
// |this| will be retained until StopDemuxer() is posted, so Unretained() is
// safe here.
- media_loop_->PostTask(FROM_HERE,
+ media_task_runner_->PostTask(FROM_HERE,
base::Bind(&MediaSourceDelegate::InitializeDemuxer,
base::Unretained(this)));
}
void MediaSourceDelegate::InitializeDemuxer() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
demuxer_client_->AddDelegate(demuxer_client_id_, this);
chunk_demuxer_->Initialize(this,
base::Bind(&MediaSourceDelegate::OnDemuxerInitDone,
false);
}
-const blink::WebTimeRanges& MediaSourceDelegate::Buffered() {
- buffered_web_time_ranges_ =
- ConvertToWebTimeRanges(buffered_time_ranges_);
- return buffered_web_time_ranges_;
+blink::WebTimeRanges MediaSourceDelegate::Buffered() const {
+ return media::ConvertToWebTimeRanges(buffered_time_ranges_);
}
size_t MediaSourceDelegate::DecodedFrameCount() const {
}
void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
<< demuxer_client_id_;
void MediaSourceDelegate::StartWaitingForSeek(
const base::TimeDelta& seek_time) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
<< demuxer_client_id_;
void MediaSourceDelegate::Seek(
const base::TimeDelta& seek_time, bool is_browser_seek) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", "
<< (is_browser_seek ? "browser seek" : "regular seek") << ") : "
<< demuxer_client_id_;
}
void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DCHECK(IsSeeking());
chunk_demuxer_->Seek(seek_time, base::Bind(
&MediaSourceDelegate::OnDemuxerSeekDone,
media_weak_factory_.GetWeakPtr()));
}
-void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
- NOTIMPLEMENTED();
-}
-
-void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) {
- NOTIMPLEMENTED();
-}
-
void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
base::TimeDelta end) {
buffered_time_ranges_.Add(start, end);
}
void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : "
<< demuxer_client_id_;
// Force duration change notification to be async to avoid reentrancy into
// ChunkDemxuer.
- main_loop_->PostTask(FROM_HERE, base::Bind(
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(
&MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration));
}
void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
if (demuxer_client_)
demuxer_client_->DurationChanged(demuxer_client_id_, duration);
if (!duration_change_cb_.is_null())
}
void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_;
if (IsSeeking())
return; // Drop the request during seeking.
void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type,
scoped_ptr<DemuxerData> data,
size_t index) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
// DemuxerStream::Read() always returns the read callback asynchronously.
DemuxerStream* stream =
(type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_;
size_t index,
DemuxerStream::Status status,
const scoped_refptr<media::DecoderBuffer>& buffer) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", "
- << ((!buffer || buffer->end_of_stream()) ?
- -1 : buffer->timestamp().InMilliseconds())
+ << ((!buffer.get() || buffer->end_of_stream())
+ ? -1
+ : buffer->timestamp().InMilliseconds())
<< ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
break;
case DemuxerStream::kConfigChanged:
- // In case of kConfigChanged, need to read decoder_config once
- // for the next reads.
- // TODO(kjyoun): Investigate if we need to use this new config. See
- // http://crbug.com/255783
- if (is_audio) {
- audio_stream_->audio_decoder_config();
- } else {
- gfx::Size size = video_stream_->video_decoder_config().coded_size();
+ CHECK((is_audio && audio_stream_) || (!is_audio && video_stream_));
+ data->demuxer_configs.resize(1);
+ CHECK(GetDemuxerConfigFromStream(&data->demuxer_configs[0], is_audio));
+ if (!is_audio) {
+ gfx::Size size = data->demuxer_configs[0].video_size;
DVLOG(1) << "Video config is changed: " << size.width() << "x"
<< size.height();
}
}
void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
// Notify demuxer ready when both streams are not encrypted.
is_demuxer_ready_ = true;
- if (CanNotifyDemuxerReady())
- NotifyDemuxerReady();
+ NotifyDemuxerReady();
}
void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!set_decryptor_ready_cb_.is_null());
audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
- media_loop_, set_decryptor_ready_cb_));
+ media_task_runner_, set_decryptor_ready_cb_));
audio_decrypting_demuxer_stream_->Initialize(
audio_stream_,
base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
}
void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!set_decryptor_ready_cb_.is_null());
video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
- media_loop_, set_decryptor_ready_cb_));
+ media_task_runner_, set_decryptor_ready_cb_));
video_decrypting_demuxer_stream_->Initialize(
video_stream_,
base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
media::PipelineStatus status) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
// Try to notify demuxer ready when audio DDS initialization finished and
// video is not encrypted.
is_demuxer_ready_ = true;
- if (CanNotifyDemuxerReady())
- NotifyDemuxerReady();
+ NotifyDemuxerReady();
}
void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
media::PipelineStatus status) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
// Try to notify demuxer ready when video DDS initialization finished.
is_demuxer_ready_ = true;
- if (CanNotifyDemuxerReady())
- NotifyDemuxerReady();
+ NotifyDemuxerReady();
}
void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(IsSeeking());
}
void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (audio_decrypting_demuxer_stream_) {
audio_decrypting_demuxer_stream_->Reset(
}
void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (video_decrypting_demuxer_stream_) {
video_decrypting_demuxer_stream_->Reset(base::Bind(
}
void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
base::AutoLock auto_lock(seeking_lock_);
demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
}
-void MediaSourceDelegate::OnDemuxerStopDone() {
- DCHECK(media_loop_->BelongsToCurrentThread());
- DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
- main_loop_->PostTask(
- FROM_HERE,
- base::Bind(&MediaSourceDelegate::DeleteSelf, base::Unretained(this)));
-}
-
-void MediaSourceDelegate::DeleteSelf() {
- DCHECK(main_loop_->BelongsToCurrentThread());
- DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
- chunk_demuxer_.reset();
- delete this;
-}
-
-void MediaSourceDelegate::OnMediaConfigRequest() {
- DCHECK(media_loop_->BelongsToCurrentThread());
- DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
- if (CanNotifyDemuxerReady())
- NotifyDemuxerReady();
-}
-
-bool MediaSourceDelegate::CanNotifyDemuxerReady() {
- DCHECK(media_loop_->BelongsToCurrentThread());
- return is_demuxer_ready_;
-}
-
void MediaSourceDelegate::NotifyDemuxerReady() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
- DCHECK(CanNotifyDemuxerReady());
+ DCHECK(is_demuxer_ready_);
scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs());
- if (audio_stream_) {
- media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
- configs->audio_codec = config.codec();
- configs->audio_channels =
- media::ChannelLayoutToChannelCount(config.channel_layout());
- configs->audio_sampling_rate = config.samples_per_second();
- configs->is_audio_encrypted = config.is_encrypted();
- configs->audio_extra_data = std::vector<uint8>(
- config.extra_data(), config.extra_data() + config.extra_data_size());
- }
- if (video_stream_) {
- media::VideoDecoderConfig config = video_stream_->video_decoder_config();
- configs->video_codec = config.codec();
- configs->video_size = config.natural_size();
- configs->is_video_encrypted = config.is_encrypted();
- configs->video_extra_data = std::vector<uint8>(
- config.extra_data(), config.extra_data() + config.extra_data_size());
- }
- configs->duration_ms = GetDurationMs();
+ GetDemuxerConfigFromStream(configs.get(), true);
+ GetDemuxerConfigFromStream(configs.get(), false);
+ configs->duration = GetDuration();
if (demuxer_client_)
demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
is_video_encrypted_ = configs->is_video_encrypted;
}
-int MediaSourceDelegate::GetDurationMs() {
- DCHECK(media_loop_->BelongsToCurrentThread());
+base::TimeDelta MediaSourceDelegate::GetDuration() const {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
if (!chunk_demuxer_)
- return -1;
+ return media::kNoTimestamp();
- double duration_ms = chunk_demuxer_->GetDuration() * 1000;
- if (duration_ms > std::numeric_limits<int32>::max()) {
- LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably "
- "something has gone wrong.";
- return std::numeric_limits<int32>::max();
- }
- return duration_ms;
+ double duration = chunk_demuxer_->GetDuration();
+ if (duration == std::numeric_limits<double>::infinity())
+ return media::kInfiniteDuration();
+
+ return media::ConvertSecondsToTimestamp(duration);
}
void MediaSourceDelegate::OnDemuxerOpened() {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
if (media_source_opened_cb_.is_null())
return;
- media_source_opened_cb_.Run(new WebMediaSourceImpl(
+ media_source_opened_cb_.Run(new media::WebMediaSourceImpl(
chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
}
void MediaSourceDelegate::OnNeedKey(const std::string& type,
const std::vector<uint8>& init_data) {
- DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
if (need_key_cb_.is_null())
return;
return seek_time;
}
+bool MediaSourceDelegate::GetDemuxerConfigFromStream(
+ media::DemuxerConfigs* configs, bool is_audio) {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+ if (!is_demuxer_ready_)
+ return false;
+ if (is_audio && audio_stream_) {
+ media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
+ configs->audio_codec = config.codec();
+ configs->audio_channels =
+ media::ChannelLayoutToChannelCount(config.channel_layout());
+ configs->audio_sampling_rate = config.samples_per_second();
+ configs->is_audio_encrypted = config.is_encrypted();
+ configs->audio_extra_data = std::vector<uint8>(
+ config.extra_data(), config.extra_data() + config.extra_data_size());
+ return true;
+ }
+ if (!is_audio && video_stream_) {
+ media::VideoDecoderConfig config = video_stream_->video_decoder_config();
+ configs->video_codec = config.codec();
+ configs->video_size = config.natural_size();
+ configs->is_video_encrypted = config.is_encrypted();
+ configs->video_extra_data = std::vector<uint8>(
+ config.extra_data(), config.extra_data() + config.extra_data_size());
+ return true;
+ }
+ return false;
+}
+
} // namespace content