Index: webkit/renderer/media/android/media_source_delegate.cc |
diff --git a/webkit/renderer/media/android/media_source_delegate.cc b/webkit/renderer/media/android/media_source_delegate.cc |
deleted file mode 100644 |
index f428b124727aaaf3b148a5e5148d8f199d34e29b..0000000000000000000000000000000000000000 |
--- a/webkit/renderer/media/android/media_source_delegate.cc |
+++ /dev/null |
@@ -1,442 +0,0 @@ |
-// Copyright 2013 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 "webkit/renderer/media/android/media_source_delegate.h" |
- |
-#include "base/message_loop/message_loop_proxy.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "media/base/android/demuxer_stream_player_params.h" |
-#include "media/base/bind_to_loop.h" |
-#include "media/base/demuxer_stream.h" |
-#include "media/base/media_log.h" |
-#include "media/filters/chunk_demuxer.h" |
-#include "third_party/WebKit/public/platform/WebString.h" |
-#include "third_party/WebKit/public/web/WebMediaSource.h" |
-#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" |
-#include "webkit/renderer/media/android/webmediaplayer_proxy_android.h" |
-#include "webkit/renderer/media/webmediaplayer_util.h" |
-#include "webkit/renderer/media/webmediasourceclient_impl.h" |
- |
-using media::DemuxerStream; |
-using media::MediaPlayerHostMsg_DemuxerReady_Params; |
-using media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params; |
-using WebKit::WebMediaPlayer; |
-using WebKit::WebString; |
- |
-namespace { |
- |
-// The size of the access unit to transfer in an IPC in case of MediaSource. |
-// 16: approximately 250ms of content in 60 fps movies. |
-const size_t kAccessUnitSizeForMediaSource = 16; |
- |
-const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; |
- |
-} // namespace |
- |
-namespace webkit_media { |
- |
-#define BIND_TO_RENDER_LOOP(function) \ |
- media::BindToLoop(base::MessageLoopProxy::current(), \ |
- base::Bind(function, weak_this_.GetWeakPtr())) |
- |
-#define BIND_TO_RENDER_LOOP_1(function, arg1) \ |
- media::BindToLoop(base::MessageLoopProxy::current(), \ |
- base::Bind(function, weak_this_.GetWeakPtr(), arg1)) |
- |
-#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \ |
- media::BindToLoop(base::MessageLoopProxy::current(), \ |
- base::Bind(function, weak_this_.GetWeakPtr(), arg1, arg2)) |
- |
-#define BIND_TO_RENDER_LOOP_3(function, arg1, arg2, arg3) \ |
- media::BindToLoop(base::MessageLoopProxy::current(), \ |
- base::Bind(function, \ |
- weak_this_.GetWeakPtr(), arg1, arg2, arg3)) |
- |
-static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, |
- const std::string& error) { |
- media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); |
-} |
- |
-MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy, |
- int player_id, |
- media::MediaLog* media_log) |
- : weak_this_(this), |
- proxy_(proxy), |
- player_id_(player_id), |
- media_log_(media_log), |
- demuxer_(NULL), |
- audio_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params), |
- video_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params), |
- seeking_(false), |
- key_added_(false), |
- access_unit_size_(0) { |
-} |
- |
-MediaSourceDelegate::~MediaSourceDelegate() { |
- DVLOG(1) << "MediaSourceDelegate::~MediaSourceDelegate() : " << player_id_; |
- DCHECK(!chunk_demuxer_); |
- DCHECK(!demuxer_); |
-} |
- |
-void MediaSourceDelegate::Destroy() { |
- DVLOG(1) << "MediaSourceDelegate::Destroy() : " << player_id_; |
- if (!demuxer_) { |
- delete this; |
- return; |
- } |
- |
- duration_change_cb_.Reset(); |
- update_network_state_cb_.Reset(); |
- media_source_.reset(); |
- proxy_ = NULL; |
- |
- demuxer_ = NULL; |
- if (chunk_demuxer_) |
- chunk_demuxer_->Stop( |
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerStopDone)); |
-} |
- |
-void MediaSourceDelegate::InitializeMediaSource( |
- WebKit::WebMediaSource* media_source, |
- const media::NeedKeyCB& need_key_cb, |
- const UpdateNetworkStateCB& update_network_state_cb, |
- const DurationChangeCB& duration_change_cb) { |
- DCHECK(media_source); |
- media_source_.reset(media_source); |
- need_key_cb_ = need_key_cb; |
- update_network_state_cb_ = update_network_state_cb; |
- duration_change_cb_ = duration_change_cb; |
- |
- chunk_demuxer_.reset(new media::ChunkDemuxer( |
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened), |
- BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnNeedKey, ""), |
- base::Bind(&MediaSourceDelegate::OnAddTextTrack, |
- base::Unretained(this)), |
- base::Bind(&LogMediaSourceError, media_log_))); |
- chunk_demuxer_->Initialize(this, |
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone)); |
- demuxer_ = chunk_demuxer_.get(); |
- access_unit_size_ = kAccessUnitSizeForMediaSource; |
-} |
- |
-#if defined(GOOGLE_TV) |
-void MediaSourceDelegate::InitializeMediaStream( |
- media::Demuxer* demuxer, |
- const UpdateNetworkStateCB& update_network_state_cb) { |
- DCHECK(demuxer); |
- demuxer_ = demuxer; |
- update_network_state_cb_ = update_network_state_cb; |
- |
- demuxer_->Initialize(this, |
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone)); |
- // When playing Media Stream, don't wait to accumulate multiple packets per |
- // IPC communication. |
- access_unit_size_ = 1; |
-} |
-#endif |
- |
-const WebKit::WebTimeRanges& MediaSourceDelegate::Buffered() { |
- buffered_web_time_ranges_ = |
- ConvertToWebTimeRanges(buffered_time_ranges_); |
- return buffered_web_time_ranges_; |
-} |
- |
-size_t MediaSourceDelegate::DecodedFrameCount() const { |
- return statistics_.video_frames_decoded; |
-} |
- |
-size_t MediaSourceDelegate::DroppedFrameCount() const { |
- return statistics_.video_frames_dropped; |
-} |
- |
-size_t MediaSourceDelegate::AudioDecodedByteCount() const { |
- return statistics_.audio_bytes_decoded; |
-} |
- |
-size_t MediaSourceDelegate::VideoDecodedByteCount() const { |
- return statistics_.video_bytes_decoded; |
-} |
- |
-void MediaSourceDelegate::Seek(base::TimeDelta time) { |
- DVLOG(1) << "MediaSourceDelegate::Seek(" << time.InSecondsF() << ") : " |
- << player_id_; |
- seeking_ = true; |
- DCHECK(demuxer_); |
- if (chunk_demuxer_) |
- chunk_demuxer_->StartWaitingForSeek(); |
- demuxer_->Seek(time, |
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerError)); |
-} |
- |
-void MediaSourceDelegate::CancelPendingSeek() { |
- if (chunk_demuxer_) |
- chunk_demuxer_->CancelPendingSeek(); |
-} |
- |
-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) { |
- DVLOG(1) << "MediaSourceDelegate::SetDuration(" << duration.InSecondsF() |
- << ") : " << player_id_; |
- // Notify our owner (e.g. WebMediaPlayerAndroid) that |
- // duration has changed. |
- if (!duration_change_cb_.is_null()) |
- duration_change_cb_.Run(duration); |
-} |
- |
-void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type, |
- bool seek_done) { |
- DVLOG(1) << "MediaSourceDelegate::OnReadFromDemuxer(" << type |
- << ", " << seek_done << ") : " << player_id_; |
- if (seeking_ && !seek_done) |
- return; // Drop the request during seeking. |
- seeking_ = false; |
- |
- DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); |
- // The access unit size should have been initialized properly at this stage. |
- DCHECK_GT(access_unit_size_, 0u); |
- MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params = |
- type == DemuxerStream::AUDIO ? audio_params_.get() : video_params_.get(); |
- params->type = type; |
- params->access_units.resize(access_unit_size_); |
- DemuxerStream* stream = demuxer_->GetStream(type); |
- DCHECK(stream != NULL); |
- ReadFromDemuxerStream(stream, params, 0); |
-} |
- |
-void MediaSourceDelegate::ReadFromDemuxerStream( |
- DemuxerStream* stream, |
- MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, |
- size_t index) { |
- stream->Read(BIND_TO_RENDER_LOOP_3(&MediaSourceDelegate::OnBufferReady, |
- stream, params, index)); |
-} |
- |
-void MediaSourceDelegate::OnBufferReady( |
- DemuxerStream* stream, |
- MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params, |
- size_t index, |
- DemuxerStream::Status status, |
- const scoped_refptr<media::DecoderBuffer>& buffer) { |
- DVLOG(1) << "MediaSourceDelegate::OnBufferReady() : " << player_id_; |
- DCHECK(status == DemuxerStream::kAborted || |
- index < params->access_units.size()); |
- bool is_audio = stream->type() == DemuxerStream::AUDIO; |
- if (status != DemuxerStream::kAborted && |
- index >= params->access_units.size()) { |
- LOG(ERROR) << "The internal state inconsistency onBufferReady: " |
- << (is_audio ? "Audio" : "Video") << ", index " << index |
- <<", size " << params->access_units.size() |
- << ", status " << static_cast<int>(status); |
- return; |
- } |
- switch (status) { |
- case DemuxerStream::kAborted: |
- // Because the abort was caused by the seek, don't respond ack. |
- return; |
- |
- case DemuxerStream::kConfigChanged: |
- // In case of kConfigChanged, need to read decoder_config once |
- // for the next reads. |
- if (is_audio) { |
- stream->audio_decoder_config(); |
- } else { |
- gfx::Size size = stream->video_decoder_config().coded_size(); |
- DVLOG(1) << "Video config is changed: " << |
- size.width() << "x" << size.height(); |
- } |
- params->access_units[index].status = status; |
- params->access_units.resize(index + 1); |
- break; |
- |
- case DemuxerStream::kOk: |
- params->access_units[index].status = status; |
- if (buffer->IsEndOfStream()) { |
- params->access_units[index].end_of_stream = true; |
- params->access_units.resize(index + 1); |
- break; |
- } |
- // TODO(ycheo): We assume that the inputed stream will be decoded |
- // right away. |
- // Need to implement this properly using MediaPlayer.OnInfoListener. |
- if (is_audio) { |
- statistics_.audio_bytes_decoded += buffer->GetDataSize(); |
- } else { |
- statistics_.video_bytes_decoded += buffer->GetDataSize(); |
- statistics_.video_frames_decoded++; |
- } |
- params->access_units[index].timestamp = buffer->GetTimestamp(); |
- params->access_units[index].data = std::vector<uint8>( |
- buffer->GetData(), |
- buffer->GetData() + buffer->GetDataSize()); |
-#if !defined(GOOGLE_TV) |
- // Vorbis needs 4 extra bytes padding on Android. Check |
- // NuMediaExtractor.cpp in Android source code. |
- if (is_audio && media::kCodecVorbis == |
- stream->audio_decoder_config().codec()) { |
- params->access_units[index].data.insert( |
- params->access_units[index].data.end(), kVorbisPadding, |
- kVorbisPadding + 4); |
- } |
-#endif |
- if (buffer->GetDecryptConfig()) { |
- params->access_units[index].key_id = std::vector<char>( |
- buffer->GetDecryptConfig()->key_id().begin(), |
- buffer->GetDecryptConfig()->key_id().end()); |
- params->access_units[index].iv = std::vector<char>( |
- buffer->GetDecryptConfig()->iv().begin(), |
- buffer->GetDecryptConfig()->iv().end()); |
- params->access_units[index].subsamples = |
- buffer->GetDecryptConfig()->subsamples(); |
- } |
- if (++index < params->access_units.size()) { |
- ReadFromDemuxerStream(stream, params, index); |
- return; |
- } |
- break; |
- |
- default: |
- NOTREACHED(); |
- } |
- |
- if (proxy_) |
- proxy_->ReadFromDemuxerAck(player_id_, *params); |
- params->access_units.resize(0); |
-} |
- |
-void MediaSourceDelegate::OnDemuxerError( |
- media::PipelineStatus status) { |
- DVLOG(1) << "MediaSourceDelegate::OnDemuxerError(" << status << ") : " |
- << player_id_; |
- if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) |
- update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); |
-} |
- |
-void MediaSourceDelegate::OnDemuxerInitDone( |
- media::PipelineStatus status) { |
- DVLOG(1) << "MediaSourceDelegate::OnDemuxerInitDone(" << status << ") : " |
- << player_id_; |
- if (status != media::PIPELINE_OK) { |
- OnDemuxerError(status); |
- return; |
- } |
- if (CanNotifyDemuxerReady()) |
- NotifyDemuxerReady(""); |
-} |
- |
-void MediaSourceDelegate::OnDemuxerStopDone() { |
- DVLOG(1) << "MediaSourceDelegate::OnDemuxerStopDone() : " << player_id_; |
- chunk_demuxer_.reset(); |
- delete this; |
-} |
- |
-void MediaSourceDelegate::OnMediaConfigRequest() { |
- if (CanNotifyDemuxerReady()) |
- NotifyDemuxerReady(""); |
-} |
- |
-void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) { |
- // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady() |
- // For now, we calls it when the first key is added. |
- if (key_added_) |
- return; |
- key_added_ = true; |
- if (CanNotifyDemuxerReady()) |
- NotifyDemuxerReady(key_system); |
-} |
- |
-bool MediaSourceDelegate::CanNotifyDemuxerReady() { |
- if (key_added_) |
- return true; |
- DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO); |
- if (audio_stream && audio_stream->audio_decoder_config().is_encrypted()) |
- return false; |
- DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
- if (video_stream && video_stream->video_decoder_config().is_encrypted()) |
- return false; |
- return true; |
-} |
- |
-void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) { |
- DCHECK(demuxer_); |
- MediaPlayerHostMsg_DemuxerReady_Params params; |
- DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO); |
- if (audio_stream) { |
- const media::AudioDecoderConfig& config = |
- audio_stream->audio_decoder_config(); |
- params.audio_codec = config.codec(); |
- params.audio_channels = |
- media::ChannelLayoutToChannelCount(config.channel_layout()); |
- params.audio_sampling_rate = config.samples_per_second(); |
- params.is_audio_encrypted = config.is_encrypted(); |
- params.audio_extra_data = std::vector<uint8>( |
- config.extra_data(), config.extra_data() + config.extra_data_size()); |
- } |
- DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
- if (video_stream) { |
- const media::VideoDecoderConfig& config = |
- video_stream->video_decoder_config(); |
- params.video_codec = config.codec(); |
- params.video_size = config.natural_size(); |
- params.is_video_encrypted = config.is_encrypted(); |
- params.video_extra_data = std::vector<uint8>( |
- config.extra_data(), config.extra_data() + config.extra_data_size()); |
- } |
- params.duration_ms = GetDurationMs(); |
- params.key_system = key_system; |
- |
- if (proxy_) |
- proxy_->DemuxerReady(player_id_, params); |
-} |
- |
-int MediaSourceDelegate::GetDurationMs() { |
- if (!chunk_demuxer_) |
- return -1; |
- |
- 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; |
-} |
- |
-void MediaSourceDelegate::OnDemuxerOpened() { |
- if (!media_source_) |
- return; |
- |
- media_source_->open(new WebMediaSourceClientImpl( |
- chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); |
-} |
- |
-void MediaSourceDelegate::OnNeedKey(const std::string& session_id, |
- const std::string& type, |
- scoped_ptr<uint8[]> init_data, |
- int init_data_size) { |
- if (need_key_cb_.is_null()) |
- return; |
- |
- need_key_cb_.Run(session_id, type, init_data.Pass(), init_data_size); |
-} |
- |
-scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack( |
- media::TextKind kind, |
- const std::string& label, |
- const std::string& language) { |
- return scoped_ptr<media::TextTrack>(); |
-} |
- |
-} // namespace webkit_media |