summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-27 20:45:42 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-27 20:45:42 +0000
commit1e04260f2a0311b43b0d6dc060ff2eabe3e6cf42 (patch)
tree1001e11d141bbca9b4ac0cf9c9763392e26b3521
parentad0e54c0b0cf51ccd29a105b4117244faf361081 (diff)
downloadchromium_src-1e04260f2a0311b43b0d6dc060ff2eabe3e6cf42.zip
chromium_src-1e04260f2a0311b43b0d6dc060ff2eabe3e6cf42.tar.gz
chromium_src-1e04260f2a0311b43b0d6dc060ff2eabe3e6cf42.tar.bz2
Enable MSE for TV
BUG=215275 R=acolwell@chromium.org, jamesr@chromium.org, palmer@chromium.org, qinmin@chromium.org, yfriedman@chromium.org Review URL: https://codereview.chromium.org/14341010 Patch from Yuncheol Heo <ycheo@chromium.org>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196968 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/android/media_player_manager_android.cc40
-rw-r--r--content/browser/android/media_player_manager_android.h16
-rw-r--r--content/common/media/media_player_messages.h65
-rw-r--r--content/renderer/media/webmediaplayer_proxy_impl_android.cc29
-rw-r--r--content/renderer/media/webmediaplayer_proxy_impl_android.h11
-rw-r--r--content/renderer/render_view_impl.cc3
-rw-r--r--media/base/android/demuxer_stream_player_params.cc32
-rw-r--r--media/base/android/demuxer_stream_player_params.h61
-rw-r--r--media/base/android/media_player_bridge.cc74
-rw-r--r--media/base/android/media_player_bridge.h52
-rw-r--r--media/filters/stream_parser_factory.cc8
-rw-r--r--media/media.gyp8
-rw-r--r--webkit/media/android/media_source_delegate.cc444
-rw-r--r--webkit/media/android/media_source_delegate.h160
-rw-r--r--webkit/media/android/webmediaplayer_android.cc117
-rw-r--r--webkit/media/android/webmediaplayer_android.h35
-rw-r--r--webkit/media/android/webmediaplayer_proxy_android.h14
-rw-r--r--webkit/media/webkit_media.gypi4
-rw-r--r--webkit/media/webmediaplayer_impl.cc10
-rw-r--r--webkit/media/webmediaplayer_util.cc10
-rw-r--r--webkit/media/webmediaplayer_util.h5
21 files changed, 1153 insertions, 45 deletions
diff --git a/content/browser/android/media_player_manager_android.cc b/content/browser/android/media_player_manager_android.cc
index e024ba1..c046e59 100644
--- a/content/browser/android/media_player_manager_android.cc
+++ b/content/browser/android/media_player_manager_android.cc
@@ -50,6 +50,10 @@ bool MediaPlayerManagerAndroid::OnMessageReceived(const IPC::Message& msg) {
OnRequestExternalSurface)
IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_NotifyGeometryChange,
OnNotifyGeometryChange)
+ IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DemuxerReady,
+ OnDemuxerReady)
+ IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ReadFromDemuxerAck,
+ OnReadFromDemuxerAck)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -103,7 +107,9 @@ void MediaPlayerManagerAndroid::SetVideoSurface(jobject surface) {
}
void MediaPlayerManagerAndroid::OnInitialize(
- int player_id, const GURL& url, const GURL& first_party_for_cookies) {
+ int player_id, const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies) {
for (ScopedVector<MediaPlayerBridge>::iterator it = players_.begin();
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id) {
@@ -117,11 +123,15 @@ void MediaPlayerManagerAndroid::OnInitialize(
StoragePartition* partition = host->GetStoragePartition();
fileapi::FileSystemContext* file_system_context =
partition ? partition->GetFileSystemContext() : NULL;
- players_.push_back(new MediaPlayerBridge(
- player_id, url, first_party_for_cookies,
+ players_.push_back(media::MediaPlayerBridge::Create(
+ player_id, url, is_media_source, first_party_for_cookies,
new MediaResourceGetterImpl(context, file_system_context, host->GetID(),
routing_id()),
context->IsOffTheRecord(), this,
+#if defined(GOOGLE_TV)
+ base::Bind(&MediaPlayerManagerAndroid::OnReadFromDemuxer,
+ base::Unretained(this)),
+#endif
base::Bind(&MediaPlayerManagerAndroid::OnError, base::Unretained(this)),
base::Bind(&MediaPlayerManagerAndroid::OnVideoSizeChanged,
base::Unretained(this)),
@@ -237,6 +247,22 @@ void MediaPlayerManagerAndroid::OnNotifyGeometryChange(int player_id,
if (view)
view->NotifyGeometryChange(player_id, rect);
}
+
+void MediaPlayerManagerAndroid::OnDemuxerReady(
+ int player_id,
+ const media::MediaPlayerHostMsg_DemuxerReady_Params& params) {
+ MediaPlayerBridge* player = GetPlayer(player_id);
+ if (player)
+ player->DemuxerReady(params);
+}
+
+void MediaPlayerManagerAndroid::OnReadFromDemuxerAck(
+ int player_id,
+ const media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) {
+ MediaPlayerBridge* player = GetPlayer(player_id);
+ if (player)
+ player->ReadFromDemuxerAck(params);
+}
#endif
MediaPlayerBridge* MediaPlayerManagerAndroid::GetPlayer(int player_id) {
@@ -307,6 +333,14 @@ void MediaPlayerManagerAndroid::OnTimeUpdate(int player_id,
routing_id(), player_id, current_time));
}
+#if defined(GOOGLE_TV)
+void MediaPlayerManagerAndroid::OnReadFromDemuxer(
+ int player_id, media::DemuxerStream::Type type, bool seek_done) {
+ Send(new MediaPlayerMsg_ReadFromDemuxer(
+ routing_id(), player_id, type, seek_done));
+}
+#endif
+
void MediaPlayerManagerAndroid::RequestMediaResources(
MediaPlayerBridge* player) {
if (player == NULL)
diff --git a/content/browser/android/media_player_manager_android.h b/content/browser/android/media_player_manager_android.h
index c21cb6d..7021b69 100644
--- a/content/browser/android/media_player_manager_android.h
+++ b/content/browser/android/media_player_manager_android.h
@@ -14,6 +14,9 @@
#include "content/browser/android/content_video_view.h"
#include "content/public/browser/render_view_host_observer.h"
#include "googleurl/src/gurl.h"
+#if defined(GOOGLE_TV)
+#include "media/base/android/demuxer_stream_player_params.h"
+#endif
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_player_bridge_manager.h"
#include "ui/gfx/rect_f.h"
@@ -59,6 +62,12 @@ class MediaPlayerManagerAndroid
void OnError(int player_id, int error);
void OnVideoSizeChanged(int player_id, int width, int height);
+#if defined(GOOGLE_TV)
+ // Callbacks needed by media::DemuxerStreamPlayer.
+ void OnReadFromDemuxer(
+ int player_id, media::DemuxerStream::Type type, bool seek_done);
+#endif
+
// media::MediaPlayerBridgeManager overrides.
virtual void RequestMediaResources(media::MediaPlayerBridge* player) OVERRIDE;
virtual void ReleaseMediaResources(media::MediaPlayerBridge* player) OVERRIDE;
@@ -79,6 +88,7 @@ class MediaPlayerManagerAndroid
void OnEnterFullscreen(int player_id);
void OnExitFullscreen(int player_id);
void OnInitialize(int player_id, const GURL& url,
+ bool is_media_source,
const GURL& first_party_for_cookies);
void OnStart(int player_id);
void OnSeek(int player_id, base::TimeDelta time);
@@ -88,6 +98,12 @@ class MediaPlayerManagerAndroid
#if defined(GOOGLE_TV)
void OnRequestExternalSurface(int player_id);
void OnNotifyGeometryChange(int player_id, const gfx::RectF& rect);
+ void OnDemuxerReady(
+ int player_id,
+ const media::MediaPlayerHostMsg_DemuxerReady_Params& params);
+ void OnReadFromDemuxerAck(
+ int player_id,
+ const media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params);
#endif
// An array of managed players.
diff --git a/content/common/media/media_player_messages.h b/content/common/media/media_player_messages.h
index e2871bf..3df3c0c 100644
--- a/content/common/media/media_player_messages.h
+++ b/content/common/media/media_player_messages.h
@@ -17,6 +17,50 @@
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
#define IPC_MESSAGE_START MediaPlayerMsgStart
+#if defined(GOOGLE_TV)
+#include "media/base/android/demuxer_stream_player_params.h"
+
+IPC_ENUM_TRAITS(media::AudioCodec)
+IPC_ENUM_TRAITS(media::DemuxerStream::Status)
+IPC_ENUM_TRAITS(media::DemuxerStream::Type)
+IPC_ENUM_TRAITS(media::VideoCodec)
+
+IPC_STRUCT_TRAITS_BEGIN(media::MediaPlayerHostMsg_DemuxerReady_Params)
+ IPC_STRUCT_TRAITS_MEMBER(audio_codec)
+ IPC_STRUCT_TRAITS_MEMBER(audio_channels)
+ IPC_STRUCT_TRAITS_MEMBER(audio_sampling_rate)
+ IPC_STRUCT_TRAITS_MEMBER(is_audio_encrypted)
+
+ IPC_STRUCT_TRAITS_MEMBER(video_codec)
+ IPC_STRUCT_TRAITS_MEMBER(video_size)
+ IPC_STRUCT_TRAITS_MEMBER(is_video_encrypted)
+
+ IPC_STRUCT_TRAITS_MEMBER(duration_ms)
+ IPC_STRUCT_TRAITS_MEMBER(key_system)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(access_units)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit)
+ IPC_STRUCT_TRAITS_MEMBER(status)
+ IPC_STRUCT_TRAITS_MEMBER(end_of_stream)
+ IPC_STRUCT_TRAITS_MEMBER(data)
+ IPC_STRUCT_TRAITS_MEMBER(timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(key_id)
+ IPC_STRUCT_TRAITS_MEMBER(iv)
+ IPC_STRUCT_TRAITS_MEMBER(subsamples)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::SubsampleEntry)
+ IPC_STRUCT_TRAITS_MEMBER(clear_bytes)
+ IPC_STRUCT_TRAITS_MEMBER(cypher_bytes)
+IPC_STRUCT_TRAITS_END()
+#endif
+
// Messages for notifying the render process of media playback status -------
// Media buffering has updated.
@@ -77,6 +121,14 @@ IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidMediaPlayerPlay,
IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidMediaPlayerPause,
int /* player_id */)
+#if defined(GOOGLE_TV)
+// The media source player reads data from demuxer
+IPC_MESSAGE_ROUTED3(MediaPlayerMsg_ReadFromDemuxer,
+ int /* player_id */,
+ media::DemuxerStream::Type /* type */,
+ bool /* seek_done */)
+#endif
+
// Messages for controllering the media playback in browser process ----------
// Destroy the media player object.
@@ -87,9 +139,10 @@ IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_DestroyMediaPlayer,
IPC_MESSAGE_ROUTED0(MediaPlayerHostMsg_DestroyAllMediaPlayers)
// Initialize a media player object with the given player_id.
-IPC_MESSAGE_ROUTED3(MediaPlayerHostMsg_MediaPlayerInitialize,
+IPC_MESSAGE_ROUTED4(MediaPlayerHostMsg_MediaPlayerInitialize,
int /* player_id */,
GURL /* url */,
+ bool /* is_media_source */,
GURL /* first_party_for_cookies */)
// Pause the player.
@@ -126,4 +179,14 @@ IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_RequestExternalSurface,
IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_NotifyGeometryChange,
int /* player_id */,
gfx::RectF /* rect */)
+
+// Inform the media source player that the demuxer is ready.
+IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_DemuxerReady,
+ int /* player_id */,
+ media::MediaPlayerHostMsg_DemuxerReady_Params)
+
+// Sent when the data was read from the ChunkDemuxer.
+IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_ReadFromDemuxerAck,
+ int /* player_id */,
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params)
#endif
diff --git a/content/renderer/media/webmediaplayer_proxy_impl_android.cc b/content/renderer/media/webmediaplayer_proxy_impl_android.cc
index 0a164ae..652964a 100644
--- a/content/renderer/media/webmediaplayer_proxy_impl_android.cc
+++ b/content/renderer/media/webmediaplayer_proxy_impl_android.cc
@@ -44,15 +44,20 @@ bool WebMediaPlayerProxyImplAndroid::OnMessageReceived(
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
+#if defined(GOOGLE_TV)
+ IPC_MESSAGE_HANDLER(MediaPlayerMsg_ReadFromDemuxer, OnReadFromDemuxer)
+#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void WebMediaPlayerProxyImplAndroid::Initialize(
- int player_id, const GURL& url, const GURL& first_party_for_cookies) {
+ int player_id, const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies) {
Send(new MediaPlayerHostMsg_MediaPlayerInitialize(
- routing_id(), player_id, url, first_party_for_cookies));
+ routing_id(), player_id, url, is_media_source, first_party_for_cookies));
}
void WebMediaPlayerProxyImplAndroid::Start(int player_id) {
@@ -185,6 +190,26 @@ void WebMediaPlayerProxyImplAndroid::DidCommitCompositorFrame() {
it->second));
}
}
+
+void WebMediaPlayerProxyImplAndroid::DemuxerReady(
+ int player_id,
+ const media::MediaPlayerHostMsg_DemuxerReady_Params& params) {
+ Send(new MediaPlayerHostMsg_DemuxerReady(routing_id(), player_id, params));
+}
+
+void WebMediaPlayerProxyImplAndroid::ReadFromDemuxerAck(
+ int player_id,
+ const media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) {
+ Send(new MediaPlayerHostMsg_ReadFromDemuxerAck(
+ routing_id(), player_id, params));
+
+}
+void WebMediaPlayerProxyImplAndroid::OnReadFromDemuxer(
+ int player_id, media::DemuxerStream::Type type, bool seek_done) {
+ webkit_media::WebMediaPlayerAndroid* player = GetWebMediaPlayer(player_id);
+ if (player)
+ player->OnReadFromDemuxer(type, seek_done);
+}
#endif
webkit_media::WebMediaPlayerAndroid*
diff --git a/content/renderer/media/webmediaplayer_proxy_impl_android.h b/content/renderer/media/webmediaplayer_proxy_impl_android.h
index 74830cd..a990459 100644
--- a/content/renderer/media/webmediaplayer_proxy_impl_android.h
+++ b/content/renderer/media/webmediaplayer_proxy_impl_android.h
@@ -36,6 +36,7 @@ class WebMediaPlayerProxyImplAndroid
// Methods inherited from WebMediaPlayerProxyAndroid.
virtual void Initialize(int player_id, const GURL& url,
+ bool is_media_source,
const GURL& first_party_for_cookies) OVERRIDE;
virtual void Start(int player_id) OVERRIDE;
virtual void Pause(int player_id) OVERRIDE;
@@ -46,6 +47,12 @@ class WebMediaPlayerProxyImplAndroid
virtual void ExitFullscreen(int player_id) OVERRIDE;
#if defined(GOOGLE_TV)
virtual void RequestExternalSurface(int player_id) OVERRIDE;
+ virtual void DemuxerReady(
+ int player_id,
+ const media::MediaPlayerHostMsg_DemuxerReady_Params& params) OVERRIDE;
+ virtual void ReadFromDemuxerAck(
+ int player_id,
+ const media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params&) OVERRIDE;
// Methods inherited from RenderViewObserver.
virtual void DidCommitCompositorFrame() OVERRIDE;
@@ -68,6 +75,10 @@ class WebMediaPlayerProxyImplAndroid
void OnDidEnterFullscreen(int player_id);
void OnPlayerPlay(int player_id);
void OnPlayerPause(int player_id);
+#if defined(GOOGLE_TV)
+ void OnReadFromDemuxer(
+ int player_id, media::DemuxerStream::Type type, bool seek_done);
+#endif
webkit_media::WebMediaPlayerManagerAndroid* manager_;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 2383846..17a2150 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2711,7 +2711,8 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
media_player_manager_.get(),
media_player_proxy_,
new StreamTextureFactoryImpl(
- context_provider->Context3d(), gpu_channel_host, routing_id_));
+ context_provider->Context3d(), gpu_channel_host, routing_id_),
+ new RenderMediaLog());
#endif
scoped_refptr<media::AudioRendererSink> sink;
diff --git a/media/base/android/demuxer_stream_player_params.cc b/media/base/android/demuxer_stream_player_params.cc
new file mode 100644
index 0000000..ab9fcaf
--- /dev/null
+++ b/media/base/android/demuxer_stream_player_params.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 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 "media/base/android/demuxer_stream_player_params.h"
+
+namespace media {
+
+MediaPlayerHostMsg_DemuxerReady_Params::
+ MediaPlayerHostMsg_DemuxerReady_Params()
+ : audio_channels(0),
+ audio_sampling_rate(0),
+ is_audio_encrypted(false),
+ is_video_encrypted(false),
+ duration_ms(0) {}
+
+MediaPlayerHostMsg_DemuxerReady_Params::
+ ~MediaPlayerHostMsg_DemuxerReady_Params() {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
+ MediaPlayerHostMsg_ReadFromDemuxerAck_Params()
+ : type(DemuxerStream::UNKNOWN) {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
+ ~MediaPlayerHostMsg_ReadFromDemuxerAck_Params() {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::AccessUnit()
+ : end_of_stream(false) {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::~AccessUnit() {}
+
+} // namespace media
diff --git a/media/base/android/demuxer_stream_player_params.h b/media/base/android/demuxer_stream_player_params.h
new file mode 100644
index 0000000..face665
--- /dev/null
+++ b/media/base/android/demuxer_stream_player_params.h
@@ -0,0 +1,61 @@
+// Copyright (c) 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.
+
+#ifndef MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
+#define MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
+
+#include <string>
+#include <vector>
+
+#include "media/base/audio_decoder_config.h"
+#include "media/base/decrypt_config.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/media_export.h"
+#include "media/base/video_decoder_config.h"
+#include "ui/gfx/size.h"
+
+namespace media {
+
+struct MEDIA_EXPORT MediaPlayerHostMsg_DemuxerReady_Params {
+ MediaPlayerHostMsg_DemuxerReady_Params();
+ ~MediaPlayerHostMsg_DemuxerReady_Params();
+
+ AudioCodec audio_codec;
+ int audio_channels;
+ int audio_sampling_rate;
+ bool is_audio_encrypted;
+
+ VideoCodec video_codec;
+ gfx::Size video_size;
+ bool is_video_encrypted;
+
+ int duration_ms;
+ std::string key_system;
+};
+
+struct MEDIA_EXPORT MediaPlayerHostMsg_ReadFromDemuxerAck_Params {
+ struct MEDIA_EXPORT AccessUnit {
+ AccessUnit();
+ ~AccessUnit();
+
+ DemuxerStream::Status status;
+ bool end_of_stream;
+ // TODO(ycheo): Use the shared memory to transfer the block data.
+ std::vector<unsigned char> data;
+ base::TimeDelta timestamp;
+ std::vector<char> key_id;
+ std::vector<char> iv;
+ std::vector<media::SubsampleEntry> subsamples;
+ };
+
+ MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
+ ~MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
+
+ DemuxerStream::Type type;
+ std::vector<AccessUnit> access_units;
+};
+
+}; // namespace media
+
+#endif // MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index cc3d5f9..267cfe7 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -29,6 +29,43 @@ static const int kTemporaryDuration = 100;
namespace media {
+#if !defined(GOOGLE_TV)
+// static
+MediaPlayerBridge* MediaPlayerBridge::Create(
+ int player_id,
+ const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies,
+ MediaResourceGetter* resource_getter,
+ bool hide_url_log,
+ MediaPlayerBridgeManager* manager,
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const MediaMetadataChangedCB& media_prepared_cb,
+ const PlaybackCompleteCB& playback_complete_cb,
+ const SeekCompleteCB& seek_complete_cb,
+ const TimeUpdateCB& time_update_cb,
+ const MediaInterruptedCB& media_interrupted_cb) {
+ LOG_IF(WARNING, is_media_source) << "MSE is not supported";
+ return new MediaPlayerBridge(
+ player_id,
+ url,
+ first_party_for_cookies,
+ resource_getter,
+ hide_url_log,
+ manager,
+ media_error_cb,
+ video_size_changed_cb,
+ buffering_update_cb,
+ media_prepared_cb,
+ playback_complete_cb,
+ seek_complete_cb,
+ time_update_cb,
+ media_interrupted_cb);
+}
+#endif
+
MediaPlayerBridge::MediaPlayerBridge(
int player_id,
const GURL& url,
@@ -100,6 +137,17 @@ void MediaPlayerBridge::CreateMediaPlayer() {
j_media_player_.Reset(JNI_MediaPlayer::Java_MediaPlayer_Constructor(env));
+ SetMediaPlayerListener();
+}
+
+void MediaPlayerBridge::SetMediaPlayer(jobject j_media_player) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ CHECK(env);
+
+ j_media_player_.Reset(env, j_media_player);
+}
+
+void MediaPlayerBridge::SetMediaPlayerListener() {
jobject j_context = base::android::GetApplicationContext();
DCHECK(j_context);
@@ -149,8 +197,7 @@ void MediaPlayerBridge::SetDataSource(const std::string& url) {
if (Java_MediaPlayerBridge_setDataSource(
env, j_media_player_.obj(), j_context, j_url_string.obj(),
j_cookies.obj(), hide_url_log_)) {
- if (manager_)
- manager_->RequestMediaResources(this);
+ RequestMediaResourcesFromManager();
JNI_MediaPlayer::Java_MediaPlayer_prepareAsync(
env, j_media_player_.obj());
} else {
@@ -180,6 +227,11 @@ void MediaPlayerBridge::OnMediaMetadataExtracted(
success);
}
+void MediaPlayerBridge::RequestMediaResourcesFromManager() {
+ if (manager_)
+ manager_->RequestMediaResources(this);
+}
+
void MediaPlayerBridge::Start() {
if (j_media_player_.is_null()) {
pending_play_ = true;
@@ -339,7 +391,7 @@ void MediaPlayerBridge::OnMediaPrepared() {
// If media player was recovered from a saved state, consume all the pending
// events.
- SeekInternal(pending_seek_);
+ PendingSeekInternal(pending_seek_);
if (pending_play_) {
StartInternal();
@@ -380,6 +432,10 @@ void MediaPlayerBridge::PauseInternal() {
time_update_timer_.Stop();
}
+void MediaPlayerBridge::PendingSeekInternal(base::TimeDelta time) {
+ SeekInternal(time);
+}
+
void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
@@ -397,4 +453,16 @@ bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
return ret;
}
+#if defined(GOOGLE_TV)
+void MediaPlayerBridge::DemuxerReady(
+ const MediaPlayerHostMsg_DemuxerReady_Params& params) {
+ NOTREACHED() << "Unexpected ipc received";
+}
+
+void MediaPlayerBridge::ReadFromDemuxerAck(
+ const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) {
+ NOTREACHED() << "Unexpected ipc received";
+}
+#endif
+
} // namespace media
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
index 1287de4..c6db77b 100644
--- a/media/base/android/media_player_bridge.h
+++ b/media/base/android/media_player_bridge.h
@@ -17,6 +17,9 @@
#include "base/timer.h"
#include "googleurl/src/gurl.h"
#include "media/base/media_export.h"
+#if defined(GOOGLE_TV)
+#include "media/base/android/demuxer_stream_player_params.h"
+#endif
#include "media/base/android/media_player_listener.h"
namespace media {
@@ -68,8 +71,34 @@ class MEDIA_EXPORT MediaPlayerBridge {
// current time.
typedef base::Callback<void(int, base::TimeDelta)> TimeUpdateCB;
+#if defined(GOOGLE_TV)
+ // Callback when DemuxerStreamPlayer wants to read data from the demuxer.
+ typedef base::Callback<void(int, DemuxerStream::Type, bool)>
+ ReadFromDemuxerCB;
+#endif
+
static bool RegisterMediaPlayerBridge(JNIEnv* env);
+ static MediaPlayerBridge* Create(
+ int player_id,
+ const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies,
+ MediaResourceGetter* resource_getter,
+ bool hide_url_log,
+ MediaPlayerBridgeManager* manager,
+#if defined(GOOGLE_TV)
+ const ReadFromDemuxerCB read_from_demuxer_cb,
+#endif
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const MediaMetadataChangedCB& media_prepared_cb,
+ const PlaybackCompleteCB& playback_complete_cb,
+ const SeekCompleteCB& seek_complete_cb,
+ const TimeUpdateCB& time_update_cb,
+ const MediaInterruptedCB& media_interrupted_cb);
+
// Construct a MediaPlayerBridge object with all the needed media player
// callbacks. This object needs to call |manager|'s RequestMediaResources()
// before decoding the media stream. This allows |manager| to track
@@ -89,7 +118,7 @@ class MEDIA_EXPORT MediaPlayerBridge {
const SeekCompleteCB& seek_complete_cb,
const TimeUpdateCB& time_update_cb,
const MediaInterruptedCB& media_interrupted_cb);
- ~MediaPlayerBridge();
+ virtual ~MediaPlayerBridge();
typedef std::map<std::string, std::string> HeadersMap;
@@ -106,7 +135,7 @@ class MEDIA_EXPORT MediaPlayerBridge {
void SeekTo(base::TimeDelta time);
// Release the player resources.
- void Release();
+ virtual void Release();
// Set the player volume.
void SetVolume(float leftVolume, float rightVolume);
@@ -121,6 +150,16 @@ class MEDIA_EXPORT MediaPlayerBridge {
// Get allowed operations from the player.
void GetAllowedOperations();
+#if defined(GOOGLE_TV)
+ // Methods for DeumxerStreamPlayer.
+ // Informs DemuxerStreamPlayer that the demuxer is ready.
+ virtual void DemuxerReady(
+ const MediaPlayerHostMsg_DemuxerReady_Params& params);
+ // Called when the requested data is received from the demuxer.
+ virtual void ReadFromDemuxerAck(
+ const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params);
+#endif
+
// Called by the timer to check for current time routinely and generates
// time update events.
void DoTimeUpdate();
@@ -138,7 +177,7 @@ class MEDIA_EXPORT MediaPlayerBridge {
// Prepare the player for playback, asynchronously. When succeeds,
// OnMediaPrepared() will be called. Otherwise, OnMediaError() will
// be called with an error type.
- void Prepare();
+ virtual void Prepare();
// Callback function passed to |resource_getter_|. Called when the cookies
// are retrieved.
@@ -150,6 +189,13 @@ class MEDIA_EXPORT MediaPlayerBridge {
bool can_seek_backward() { return can_seek_backward_; }
bool prepared() { return prepared_; }
+ protected:
+ void SetMediaPlayer(jobject j_media_player);
+ void SetMediaPlayerListener();
+ void RequestMediaResourcesFromManager();
+
+ virtual void PendingSeekInternal(base::TimeDelta time);
+
private:
// Initialize this object and extract the metadata from the media.
void Initialize();
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc
index 43b6729..93b0e8b 100644
--- a/media/filters/stream_parser_factory.cc
+++ b/media/filters/stream_parser_factory.cc
@@ -62,11 +62,7 @@ static const CodecInfo* kAudioWebMCodecs[] = {
static media::StreamParser* BuildWebMParser(
const std::vector<std::string>& codecs,
const media::LogCB& log_cb) {
-#if defined(OS_ANDROID)
- return NULL;
-#else
return new media::WebMStreamParser();
-#endif
}
#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
@@ -127,9 +123,6 @@ static const CodecInfo* kAudioMP4Codecs[] = {
static media::StreamParser* BuildMP4Parser(
const std::vector<std::string>& codecs, const media::LogCB& log_cb) {
-#if defined(OS_ANDROID)
- return NULL;
-#else
std::set<int> audio_object_types;
bool has_sbr = false;
for (size_t i = 0; i < codecs.size(); ++i) {
@@ -150,7 +143,6 @@ static media::StreamParser* BuildMP4Parser(
}
return new media::mp4::MP4StreamParser(audio_object_types, has_sbr);
-#endif
}
#endif
diff --git a/media/media.gyp b/media/media.gyp
index a49fc64..692e7bc 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1546,6 +1546,14 @@
'base/android/webaudio_media_codec_bridge.cc',
'base/android/webaudio_media_codec_bridge.h',
],
+ 'conditions': [
+ ['google_tv == 1', {
+ 'sources': [
+ 'base/android/demuxer_stream_player_params.cc',
+ 'base/android/demuxer_stream_player_params.h',
+ ],
+ }],
+ ],
'dependencies': [
'../base/base.gyp:base',
'media_android_jni_headers',
diff --git a/webkit/media/android/media_source_delegate.cc b/webkit/media/android/media_source_delegate.cc
new file mode 100644
index 0000000..908a4fa
--- /dev/null
+++ b/webkit/media/android/media_source_delegate.cc
@@ -0,0 +1,444 @@
+// Copyright (c) 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/media/android/media_source_delegate.h"
+
+#include "base/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/Source/Platform/chromium/public/WebString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaSource.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h"
+#include "webkit/media/android/webmediaplayer_proxy_android.h"
+#include "webkit/media/crypto/key_systems.h"
+#include "webkit/media/crypto/proxy_decryptor.h"
+#include "webkit/media/webmediaplayer_util.h"
+#include "webkit/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.
+// 16: approximately 250ms of content in 60 fps movies.
+const size_t kAccessUnitSize = 16;
+
+} // 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(
+ WebKit::WebFrame* frame,
+ WebKit::WebMediaPlayerClient* client,
+ WebMediaPlayerProxyAndroid* proxy,
+ int player_id,
+ media::MediaLog* media_log)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
+ client_(client),
+ proxy_(proxy),
+ player_id_(player_id),
+ media_log_(media_log),
+ audio_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
+ video_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
+ seeking_(false) {
+ if (WebKit::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
+ decryptor_.reset(new ProxyDecryptor(
+ client,
+ frame,
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnKeyAdded),
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnKeyError),
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnKeyMessage),
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnNeedKey)));
+ decryptor_->SetDecryptorReadyCB(
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDecryptorReady));
+ }
+}
+
+MediaSourceDelegate::~MediaSourceDelegate() {}
+
+void MediaSourceDelegate::Initialize(
+ scoped_ptr<WebKit::WebMediaSource> media_source,
+ const UpdateNetworkStateCB& update_network_state_cb) {
+ DCHECK(media_source);
+ media_source_ = media_source.Pass();
+ update_network_state_cb_ = update_network_state_cb;
+
+ chunk_demuxer_.reset(new media::ChunkDemuxer(
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened),
+ BIND_TO_RENDER_LOOP_2(&MediaSourceDelegate::OnNeedKey, "", ""),
+ base::Bind(&LogMediaSourceError, media_log_)));
+ chunk_demuxer_->Initialize(this,
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
+}
+
+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;
+}
+
+WebMediaPlayer::MediaKeyException MediaSourceDelegate::GenerateKeyRequest(
+ const WebString& key_system,
+ const unsigned char* init_data,
+ size_t init_data_length) {
+ if (!IsSupportedKeySystem(key_system))
+ return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
+
+ // We do not support run-time switching between key systems for now.
+ if (current_key_system_.isEmpty())
+ current_key_system_ = key_system;
+ else if (key_system != current_key_system_)
+ return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
+
+ DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
+ << std::string(reinterpret_cast<const char*>(init_data),
+ init_data_length);
+
+ // TODO(xhwang): We assume all streams are from the same container (thus have
+ // the same "type") for now. In the future, the "type" should be passed down
+ // from the application.
+ if (!decryptor_->GenerateKeyRequest(key_system.utf8(),
+ init_data_type_,
+ init_data, init_data_length)) {
+ current_key_system_.reset();
+ return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
+ }
+
+ return WebMediaPlayer::MediaKeyExceptionNoError;
+}
+
+WebMediaPlayer::MediaKeyException MediaSourceDelegate::AddKey(
+ const WebString& key_system,
+ const unsigned char* key,
+ size_t key_length,
+ const unsigned char* init_data,
+ size_t init_data_length,
+ const WebString& session_id) {
+ DCHECK(key);
+ DCHECK_EQ(key_length, 16u);
+
+ if (!IsSupportedKeySystem(key_system))
+ return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
+
+ if (current_key_system_.isEmpty() || key_system != current_key_system_)
+ return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
+
+ DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
+ << base::HexEncode(key, key_length) << ", "
+ << base::HexEncode(init_data, std::max(init_data_length, 256u))
+ << " [" << session_id.utf8().data() << "]";
+
+ decryptor_->AddKey(key_system.utf8(), key, key_length,
+ init_data, init_data_length, session_id.utf8());
+ return WebMediaPlayer::MediaKeyExceptionNoError;
+}
+
+WebMediaPlayer::MediaKeyException MediaSourceDelegate::CancelKeyRequest(
+ const WebString& key_system,
+ const WebString& session_id) {
+ if (!IsSupportedKeySystem(key_system))
+ return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
+
+ if (current_key_system_.isEmpty() || key_system != current_key_system_)
+ return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
+
+ decryptor_->CancelKeyRequest(key_system.utf8(), session_id.utf8());
+ return WebMediaPlayer::MediaKeyExceptionNoError;
+}
+
+void MediaSourceDelegate::Seek(base::TimeDelta time) {
+ seeking_ = true;
+ DCHECK(chunk_demuxer_);
+ if (!chunk_demuxer_)
+ return;
+ chunk_demuxer_->StartWaitingForSeek();
+ chunk_demuxer_->Seek(time,
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerError));
+}
+
+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) {
+ // Do nothing
+}
+
+void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type,
+ bool seek_done) {
+ if (seeking_ && !seek_done)
+ return; // Drop the request during seeking.
+ seeking_ = false;
+
+ DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
+ MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params =
+ type == DemuxerStream::AUDIO ? audio_params_.get() : video_params_.get();
+ params->type = type;
+ params->access_units.resize(kAccessUnitSize);
+ DemuxerStream* stream = chunk_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) {
+ 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<unsigned char>(
+ buffer->GetData(),
+ buffer->GetData() + buffer->GetDataSize());
+ 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) {
+ if (status != media::PIPELINE_OK) {
+ DCHECK(status == media::DEMUXER_ERROR_COULD_NOT_OPEN ||
+ status == media::DEMUXER_ERROR_COULD_NOT_PARSE ||
+ status == media::DEMUXER_ERROR_NO_SUPPORTED_STREAMS)
+ << "Unexpected error from demuxer: " << static_cast<int>(status);
+ if (!update_network_state_cb_.is_null())
+ update_network_state_cb_.Run(WebMediaPlayer::NetworkStateFormatError);
+ }
+}
+
+void MediaSourceDelegate::OnDemuxerInitDone(
+ media::PipelineStatus status) {
+ if (status != media::PIPELINE_OK) {
+ OnDemuxerError(status);
+ return;
+ }
+ NotifyDemuxerReady("");
+}
+
+void MediaSourceDelegate::NotifyDemuxerReady(
+ const std::string& key_system) {
+ MediaPlayerHostMsg_DemuxerReady_Params params;
+ DemuxerStream* audio_stream = chunk_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();
+ }
+ DemuxerStream* video_stream = chunk_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();
+ }
+ double duration_ms = chunk_demuxer_->GetDuration() * 1000;
+ DCHECK(duration_ms >= 0);
+ if (duration_ms > std::numeric_limits<int>::max())
+ duration_ms = std::numeric_limits<int>::max();
+ params.duration_ms = duration_ms;
+ params.key_system = key_system;
+
+ bool ready_to_send = (!params.is_audio_encrypted &&
+ !params.is_video_encrypted) || !key_system.empty();
+ if (proxy_ && ready_to_send)
+ proxy_->DemuxerReady(player_id_, params);
+}
+
+void MediaSourceDelegate::OnDemuxerOpened() {
+ media_source_->open(new WebMediaSourceClientImpl(
+ chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
+}
+
+void MediaSourceDelegate::OnKeyError(const std::string& key_system,
+ const std::string& session_id,
+ media::Decryptor::KeyError error_code,
+ int system_code) {
+ client_->keyError(
+ WebString::fromUTF8(key_system),
+ WebString::fromUTF8(session_id),
+ static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
+ system_code);
+}
+
+void MediaSourceDelegate::OnKeyMessage(const std::string& key_system,
+ const std::string& session_id,
+ const std::string& message,
+ const std::string& default_url) {
+ const GURL default_url_gurl(default_url);
+ DLOG_IF(WARNING, !default_url.empty() && !default_url_gurl.is_valid())
+ << "Invalid URL in default_url: " << default_url;
+
+ client_->keyMessage(WebString::fromUTF8(key_system),
+ WebString::fromUTF8(session_id),
+ reinterpret_cast<const uint8*>(message.data()),
+ message.size(),
+ default_url_gurl);
+}
+
+void MediaSourceDelegate::OnKeyAdded(const std::string& key_system,
+ const std::string& session_id) {
+ NotifyDemuxerReady(key_system);
+ client_->keyAdded(WebString::fromUTF8(key_system),
+ WebString::fromUTF8(session_id));
+}
+
+void MediaSourceDelegate::OnNeedKey(const std::string& key_system,
+ const std::string& session_id,
+ const std::string& type,
+ scoped_ptr<uint8[]> init_data,
+ int init_data_size) {
+ // Do not fire NeedKey event if encrypted media is not enabled.
+ if (!decryptor_)
+ return;
+
+ CHECK(init_data_size >= 0);
+ DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
+ if (init_data_type_.empty())
+ init_data_type_ = type;
+
+ client_->keyNeeded(WebString::fromUTF8(key_system),
+ WebString::fromUTF8(session_id),
+ init_data.get(),
+ init_data_size);
+}
+
+void MediaSourceDelegate::OnDecryptorReady(media::Decryptor* decryptor) {}
+
+} // namespace webkit_media
diff --git a/webkit/media/android/media_source_delegate.h b/webkit/media/android/media_source_delegate.h
new file mode 100644
index 0000000..482f110
--- /dev/null
+++ b/webkit/media/android/media_source_delegate.h
@@ -0,0 +1,160 @@
+// Copyright (c) 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.
+
+#ifndef WEBKIT_MEDIA_ANDROID_MEDIA_SOURCE_DELEGATE_H_
+#define WEBKIT_MEDIA_ANDROID_MEDIA_SOURCE_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
+#include "media/base/decryptor.h"
+#include "media/base/demuxer.h"
+#include "media/base/pipeline_status.h"
+#include "media/base/ranges.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h"
+
+namespace media {
+class ChunkDemuxer;
+class DecoderBuffer;
+class DemuxerStream;
+class MediaLog;
+struct MediaPlayerHostMsg_ReadFromDemuxerAck_Params;
+}
+
+namespace WebKit {
+class WebFrame;
+class WebMediaSource;
+}
+
+namespace webkit_media {
+
+class ProxyDecryptor;
+class WebMediaPlayerProxyAndroid;
+
+class MediaSourceDelegate : public media::DemuxerHost {
+ public:
+ typedef base::Callback<void(WebKit::WebMediaPlayer::NetworkState)>
+ UpdateNetworkStateCB;
+
+ MediaSourceDelegate(WebKit::WebFrame* frame,
+ WebKit::WebMediaPlayerClient* client,
+ WebMediaPlayerProxyAndroid* proxy,
+ int player_id,
+ media::MediaLog* media_log);
+ virtual ~MediaSourceDelegate();
+
+ void Initialize(scoped_ptr<WebKit::WebMediaSource> media_source,
+ const UpdateNetworkStateCB& update_network_state_cb);
+
+ const WebKit::WebTimeRanges& Buffered();
+ size_t DecodedFrameCount() const;
+ size_t DroppedFrameCount() const;
+ size_t AudioDecodedByteCount() const;
+ size_t VideoDecodedByteCount() const;
+
+ WebKit::WebMediaPlayer::MediaKeyException GenerateKeyRequest(
+ const WebKit::WebString& key_system,
+ const unsigned char* init_data,
+ size_t init_data_length);
+ WebKit::WebMediaPlayer::MediaKeyException AddKey(
+ const WebKit::WebString& key_system,
+ const unsigned char* key,
+ size_t key_length,
+ const unsigned char* init_data,
+ size_t init_data_length,
+ const WebKit::WebString& session_id);
+ WebKit::WebMediaPlayer::MediaKeyException CancelKeyRequest(
+ const WebKit::WebString& key_system,
+ const WebKit::WebString& session_id);
+
+ void Seek(base::TimeDelta time);
+
+ // Called when DemuxerStreamPlayer needs to read data from ChunkDemuxer.
+ // If it's the first request after the seek, |seek_done| will be true.
+ void OnReadFromDemuxer(media::DemuxerStream::Type type, bool seek_done);
+
+ private:
+ // Methods inherited from DemuxerHost.
+ virtual void SetTotalBytes(int64 total_bytes) OVERRIDE;
+ virtual void AddBufferedByteRange(int64 start, int64 end) OVERRIDE;
+ virtual void AddBufferedTimeRange(base::TimeDelta start,
+ base::TimeDelta end) OVERRIDE;
+ virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
+ virtual void OnDemuxerError(media::PipelineStatus status) OVERRIDE;
+
+ // Callbacks for ChunkDemuxer & Decryptor.
+ void OnDemuxerInitDone(media::PipelineStatus status);
+ void OnDemuxerOpened();
+ void OnKeyAdded(const std::string& key_system, const std::string& session_id);
+ void OnKeyError(const std::string& key_system,
+ const std::string& session_id,
+ media::Decryptor::KeyError error_code,
+ int system_code);
+ void OnKeyMessage(const std::string& key_system,
+ const std::string& session_id,
+ const std::string& message,
+ const std::string& default_url);
+ void OnNeedKey(const std::string& key_system,
+ const std::string& type,
+ const std::string& session_id,
+ scoped_ptr<uint8[]> init_data,
+ int init_data_size);
+ void OnDecryptorReady(media::Decryptor*);
+
+ // Reads an access unit from the demuxer stream |stream| and stores it in
+ // the |index|th access unit in |params|.
+ void ReadFromDemuxerStream(
+ media::DemuxerStream* stream,
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+ size_t index);
+ void OnBufferReady(
+ media::DemuxerStream* stream,
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+ size_t index,
+ media::DemuxerStream::Status status,
+ const scoped_refptr<media::DecoderBuffer>& buffer);
+
+ void NotifyDemuxerReady(const std::string& key_system);
+
+ base::WeakPtrFactory<MediaSourceDelegate> weak_this_;
+
+ WebKit::WebMediaPlayerClient* const client_;
+ WebMediaPlayerProxyAndroid* proxy_;
+ int player_id_;
+
+ scoped_refptr<media::MediaLog> media_log_;
+ UpdateNetworkStateCB update_network_state_cb_;
+
+ scoped_ptr<media::ChunkDemuxer> chunk_demuxer_;
+ scoped_ptr<WebKit::WebMediaSource> media_source_;
+
+ media::PipelineStatistics statistics_;
+ media::Ranges<base::TimeDelta> buffered_time_ranges_;
+ // Keep a list of buffered time ranges.
+ WebKit::WebTimeRanges buffered_web_time_ranges_;
+
+ // The decryptor that manages decryption keys and decrypts encrypted frames.
+ scoped_ptr<ProxyDecryptor> decryptor_;
+
+ // The currently selected key system. Empty string means that no key system
+ // has been selected.
+ WebKit::WebString current_key_system_;
+
+ // Temporary for EME v0.1. In the future the init data type should be passed
+ // through GenerateKeyRequest() directly from WebKit.
+ std::string init_data_type_;
+
+ scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> audio_params_;
+ scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> video_params_;
+
+ bool seeking_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSourceDelegate);
+};
+
+} // namespace webkit_media
+#endif // WEBKIT_MEDIA_ANDROID_MEDIA_SOURCE_DELEGATE_H_
+
diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc
index 317c256..7907512 100644
--- a/webkit/media/android/webmediaplayer_android.cc
+++ b/webkit/media/android/webmediaplayer_android.cc
@@ -13,9 +13,11 @@
#include "media/base/android/media_player_bridge.h"
#include "media/base/video_frame.h"
#include "net/base/mime_util.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaSource.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "webkit/compositor_bindings/web_layer_impl.h"
#include "webkit/media/android/webmediaplayer_manager_android.h"
@@ -23,11 +25,16 @@
#include "webkit/media/media_switches.h"
#include "webkit/media/webmediaplayer_util.h"
+#if defined(GOOGLE_TV)
+#include "webkit/media/android/media_source_delegate.h"
+#endif
+
static const uint32 kGLTextureExternalOES = 0x8D65;
using WebKit::WebMediaPlayer;
using WebKit::WebMediaSource;
using WebKit::WebSize;
+using WebKit::WebString;
using WebKit::WebTimeRanges;
using WebKit::WebURL;
using media::MediaPlayerBridge;
@@ -40,7 +47,8 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
WebKit::WebMediaPlayerClient* client,
WebMediaPlayerManagerAndroid* manager,
WebMediaPlayerProxyAndroid* proxy,
- StreamTextureFactory* factory)
+ StreamTextureFactory* factory,
+ media::MediaLog* media_log)
: frame_(frame),
client_(client),
buffered_(1u),
@@ -58,7 +66,8 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
needs_external_surface_(false),
video_frame_provider_client_(NULL),
proxy_(proxy),
- current_time_(0) {
+ current_time_(0),
+ media_log_(media_log) {
main_loop_->AddDestructionObserver(this);
if (manager_)
player_id_ = manager_->RegisterMediaPlayer(this);
@@ -88,13 +97,33 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
}
void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
+ load(url, NULL, cors_mode);
+}
+
+void WebMediaPlayerAndroid::load(const WebURL& url,
+ WebMediaSource* media_source,
+ CORSMode cors_mode) {
if (cors_mode != CORSModeUnspecified)
NOTIMPLEMENTED() << "No CORS support";
+ scoped_ptr<WebKit::WebMediaSource> scoped_media_source(media_source);
+#if defined(GOOGLE_TV)
+ if (media_source) {
+ media_source_delegate_.reset(
+ new MediaSourceDelegate(
+ frame_, client_, proxy_, player_id_, media_log_));
+ // |media_source_delegate_| is owned, so Unretained() is safe here.
+ media_source_delegate_->Initialize(
+ scoped_media_source.Pass(),
+ base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
+ base::Unretained(this)));
+ }
+#endif
+
url_ = url;
GURL first_party_url = frame_->document().firstPartyForCookies();
if (proxy_) {
- proxy_->Initialize(player_id_, url_, first_party_url);
+ proxy_->Initialize(player_id_, url_, media_source != NULL, first_party_url);
if (manager_->IsInFullscreen(frame_))
proxy_->EnterFullscreen(player_id_);
}
@@ -103,12 +132,6 @@ void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
}
-void WebMediaPlayerAndroid::load(const WebURL& url,
- WebMediaSource* media_source,
- CORSMode cors_mode) {
- NOTIMPLEMENTED();
-}
-
void WebMediaPlayerAndroid::cancelLoad() {
NOTIMPLEMENTED();
}
@@ -139,8 +162,13 @@ void WebMediaPlayerAndroid::seek(double seconds) {
pending_seek_ = seconds;
seeking_ = true;
+ base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ media_source_delegate_->Seek(seek_time);
+#endif
if (proxy_)
- proxy_->Seek(player_id_, ConvertSecondsToTimestamp(seconds));
+ proxy_->Seek(player_id_, seek_time);
}
bool WebMediaPlayerAndroid::supportsFullscreen() const {
@@ -234,6 +262,10 @@ WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
}
const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ return media_source_delegate_->Buffered();
+#endif
return buffered_;
}
@@ -314,21 +346,37 @@ double WebMediaPlayerAndroid::mediaTimeForTimeValue(double timeValue) const {
}
unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ return media_source_delegate_->DecodedFrameCount();
+#endif
NOTIMPLEMENTED();
return 0;
}
unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ return media_source_delegate_->DroppedFrameCount();
+#endif
NOTIMPLEMENTED();
return 0;
}
unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ return media_source_delegate_->AudioDecodedByteCount();
+#endif
NOTIMPLEMENTED();
return 0;
}
unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
+#if defined(GOOGLE_TV)
+ if (media_source_delegate_)
+ return media_source_delegate_->VideoDecodedByteCount();
+#endif
NOTIMPLEMENTED();
return 0;
}
@@ -417,11 +465,13 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
switches::kUseExternalVideoSurfaceThresholdInPixels),
&threshold);
- if (parsed_arg && threshold <= width * height) {
+ if ((parsed_arg && threshold <= width * height) ||
+ // Use H/W surface for MSE as the content is protected.
+ media_source_delegate_) {
needs_external_surface_ = true;
SetNeedsEstablishPeer(false);
- if (!paused())
- RequestExternalSurface();
+ if (!paused() && proxy_)
+ proxy_->RequestExternalSurface(player_id_);
}
#endif
@@ -603,6 +653,47 @@ bool WebMediaPlayerAndroid::RetrieveGeometryChange(gfx::RectF* rect) {
last_computed_rect_ = *rect;
return true;
}
+
+WebMediaPlayer::MediaKeyException
+WebMediaPlayerAndroid::generateKeyRequest(const WebString& key_system,
+ const unsigned char* init_data,
+ unsigned init_data_length) {
+ if (media_source_delegate_) {
+ return media_source_delegate_->GenerateKeyRequest(
+ key_system, init_data, init_data_length);
+ }
+ return MediaKeyExceptionKeySystemNotSupported;
+}
+
+WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::addKey(
+ const WebString& key_system,
+ const unsigned char* key,
+ unsigned key_length,
+ const unsigned char* init_data,
+ unsigned init_data_length,
+ const WebString& session_id) {
+ if (media_source_delegate_) {
+ return media_source_delegate_->AddKey(
+ key_system, key, key_length, init_data, init_data_length, session_id);
+ }
+ return MediaKeyExceptionKeySystemNotSupported;
+}
+
+WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::cancelKeyRequest(
+ const WebString& key_system,
+ const WebString& session_id) {
+ if (media_source_delegate_)
+ return media_source_delegate_->CancelKeyRequest(key_system, session_id);
+ return MediaKeyExceptionKeySystemNotSupported;
+}
+
+void WebMediaPlayerAndroid::OnReadFromDemuxer(
+ media::DemuxerStream::Type type, bool seek_done) {
+ if (media_source_delegate_)
+ media_source_delegate_->OnReadFromDemuxer(type, seek_done);
+ else
+ NOTIMPLEMENTED();
+}
#endif
void WebMediaPlayerAndroid::enterFullscreen() {
diff --git a/webkit/media/android/webmediaplayer_android.h b/webkit/media/android/webmediaplayer_android.h
index d488786..e07d48f 100644
--- a/webkit/media/android/webmediaplayer_android.h
+++ b/webkit/media/android/webmediaplayer_android.h
@@ -12,6 +12,9 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/time.h"
+#if defined(GOOGLE_TV)
+#include "media/base/demuxer_stream.h"
+#endif
#include "cc/layers/video_frame_provider.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
@@ -20,6 +23,10 @@
#include "ui/gfx/rect_f.h"
#include "webkit/media/android/stream_texture_factory_android.h"
+namespace media {
+class MediaLog;
+}
+
namespace WebKit {
class WebFrame;
}
@@ -30,6 +37,9 @@ class WebLayerImpl;
namespace webkit_media {
+#if defined(GOOGLE_TV)
+class MediaSourceDelegate;
+#endif
class WebMediaPlayerManagerAndroid;
class WebMediaPlayerProxyAndroid;
@@ -53,7 +63,8 @@ class WebMediaPlayerAndroid
WebKit::WebMediaPlayerClient* client,
WebMediaPlayerManagerAndroid* manager,
WebMediaPlayerProxyAndroid* proxy,
- StreamTextureFactory* factory);
+ StreamTextureFactory* factory,
+ media::MediaLog* media_log);
virtual ~WebMediaPlayerAndroid();
// WebKit::WebMediaPlayer implementation.
@@ -175,6 +186,24 @@ class WebMediaPlayerAndroid
// frame) if changed. Returns true only if the geometry has been changed since
// the last call.
bool RetrieveGeometryChange(gfx::RectF* rect);
+
+ virtual MediaKeyException generateKeyRequest(
+ const WebKit::WebString& key_system,
+ const unsigned char* init_data,
+ unsigned init_data_length) OVERRIDE;
+ virtual MediaKeyException addKey(
+ const WebKit::WebString& key_system,
+ const unsigned char* key,
+ unsigned key_length,
+ const unsigned char* init_data,
+ unsigned init_data_length,
+ const WebKit::WebString& session_id) OVERRIDE;
+ virtual MediaKeyException cancelKeyRequest(
+ const WebKit::WebString& key_system,
+ const WebKit::WebString& session_id) OVERRIDE;
+
+ // Called when DemuxerStreamPlayer needs to read data from ChunkDemuxer.
+ void OnReadFromDemuxer(media::DemuxerStream::Type type, bool seek_done);
#endif
protected:
@@ -276,6 +305,8 @@ class WebMediaPlayerAndroid
// A rectangle represents the geometry of video frame, when computed last
// time.
gfx::RectF last_computed_rect_;
+
+ scoped_ptr<MediaSourceDelegate> media_source_delegate_;
#endif
// Proxy object that delegates method calls on Render Thread.
@@ -288,6 +319,8 @@ class WebMediaPlayerAndroid
// OnTimeUpdate().
float current_time_;
+ media::MediaLog* media_log_;
+
DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerAndroid);
};
diff --git a/webkit/media/android/webmediaplayer_proxy_android.h b/webkit/media/android/webmediaplayer_proxy_android.h
index 2961c2f..bc29479 100644
--- a/webkit/media/android/webmediaplayer_proxy_android.h
+++ b/webkit/media/android/webmediaplayer_proxy_android.h
@@ -9,6 +9,9 @@
#include "base/time.h"
#include "googleurl/src/gurl.h"
+#if defined(GOOGLE_TV)
+#include "media/base/android/demuxer_stream_player_params.h"
+#endif
namespace webkit_media {
@@ -22,6 +25,7 @@ class WebMediaPlayerProxyAndroid {
// Initialize a MediaPlayerBridge object in browser process
virtual void Initialize(int player_id, const GURL& url,
+ bool is_media_source,
const GURL& first_party_for_cookies) = 0;
// Start the player.
@@ -48,6 +52,16 @@ class WebMediaPlayerProxyAndroid {
#if defined(GOOGLE_TV)
// Request an external surface for out-of-band compositing.
virtual void RequestExternalSurface(int player_id) = 0;
+
+ // Inform the media source player that the demuxer is ready.
+ virtual void DemuxerReady(
+ int player_id,
+ const media::MediaPlayerHostMsg_DemuxerReady_Params&) = 0;
+
+ // Return the data to the media source player when data is ready.
+ virtual void ReadFromDemuxerAck(
+ int player_id,
+ const media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) = 0;
#endif
};
diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi
index 60cfd69..6cbd9cd 100644
--- a/webkit/media/webkit_media.gypi
+++ b/webkit/media/webkit_media.gypi
@@ -124,6 +124,10 @@
],
}],
['google_tv == 1', {
+ 'sources': [
+ 'android/media_source_delegate.cc',
+ 'android/media_source_delegate.h',
+ ],
'sources!': [
'crypto/key_systems_info.cc',
],
diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc
index ba2834b..a589f16 100644
--- a/webkit/media/webmediaplayer_impl.cc
+++ b/webkit/media/webmediaplayer_impl.cc
@@ -114,16 +114,6 @@ COMPILE_ASSERT_MATCHING_ENUM(UseCredentials);
#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1, arg2))
-static WebKit::WebTimeRanges ConvertToWebTimeRanges(
- const media::Ranges<base::TimeDelta>& ranges) {
- WebKit::WebTimeRanges result(ranges.size());
- for (size_t i = 0; i < ranges.size(); i++) {
- result[i].start = ranges.start(i).InSecondsF();
- result[i].end = ranges.end(i).InSecondsF();
- }
- return result;
-}
-
static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
const std::string& error) {
media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
diff --git a/webkit/media/webmediaplayer_util.cc b/webkit/media/webmediaplayer_util.cc
index 17e603e..ebac0f8 100644
--- a/webkit/media/webmediaplayer_util.cc
+++ b/webkit/media/webmediaplayer_util.cc
@@ -14,4 +14,14 @@ base::TimeDelta ConvertSecondsToTimestamp(double seconds) {
microseconds > 0 ? microseconds + 0.5 : ceil(microseconds - 0.5));
}
+WebKit::WebTimeRanges ConvertToWebTimeRanges(
+ const media::Ranges<base::TimeDelta>& ranges) {
+ WebKit::WebTimeRanges result(ranges.size());
+ for (size_t i = 0; i < ranges.size(); i++) {
+ result[i].start = ranges.start(i).InSecondsF();
+ result[i].end = ranges.end(i).InSecondsF();
+ }
+ return result;
+}
+
} // namespace webkit_media
diff --git a/webkit/media/webmediaplayer_util.h b/webkit/media/webmediaplayer_util.h
index 27888db..b18a961 100644
--- a/webkit/media/webmediaplayer_util.h
+++ b/webkit/media/webmediaplayer_util.h
@@ -6,6 +6,8 @@
#define WEBKIT_MEDIA_WEBMEDIAPLAYER_UTIL_H_
#include "base/time.h"
+#include "media/base/ranges.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebTimeRange.h"
namespace webkit_media {
@@ -15,6 +17,9 @@ namespace webkit_media {
// Refer to https://bugs.webkit.org/show_bug.cgi?id=52697 for details.
base::TimeDelta ConvertSecondsToTimestamp(double seconds);
+WebKit::WebTimeRanges ConvertToWebTimeRanges(
+ const media::Ranges<base::TimeDelta>& ranges);
+
} // namespace webkit_media
#endif // WEBKIT_MEDIA_WEBMEDIAPLAYER_UTIL_H_