Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: webkit/renderer/media/android/webmediaplayer_android.cc

Issue 17502007: Move webkit/renderer/media/android/ to content/renderer/media/android/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix shared lib Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/renderer/media/android/webmediaplayer_android.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "cc/layers/video_layer.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "media/base/android/media_player_android.h"
16 #include "media/base/bind_to_loop.h"
17 #include "media/base/media_switches.h"
18 #include "media/base/video_frame.h"
19 #include "net/base/mime_util.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/web/WebMediaPlayerClient.h"
24 #include "third_party/WebKit/public/web/WebMediaSource.h"
25 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
26 #include "third_party/WebKit/public/web/WebView.h"
27 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
28 #include "webkit/renderer/media/android/webmediaplayer_manager_android.h"
29 #include "webkit/renderer/media/android/webmediaplayer_proxy_android.h"
30 #include "webkit/renderer/media/crypto/key_systems.h"
31 #include "webkit/renderer/media/webmediaplayer_delegate.h"
32 #include "webkit/renderer/media/webmediaplayer_util.h"
33
34 #if defined(GOOGLE_TV)
35 #include "webkit/renderer/media/media_stream_audio_renderer.h"
36 #include "webkit/renderer/media/media_stream_client.h"
37 #endif
38
39 static const uint32 kGLTextureExternalOES = 0x8D65;
40
41 using WebKit::WebMediaPlayer;
42 using WebKit::WebMediaSource;
43 using WebKit::WebSize;
44 using WebKit::WebString;
45 using WebKit::WebTimeRanges;
46 using WebKit::WebURL;
47 using media::MediaPlayerAndroid;
48 using media::VideoFrame;
49
50 namespace {
51 // Prefix for histograms related to Encrypted Media Extensions.
52 const char* kMediaEme = "Media.EME.";
53 } // namespace
54
55 namespace webkit_media {
56
57 #define BIND_TO_RENDER_LOOP(function) \
58 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr()))
59
60 WebMediaPlayerAndroid::WebMediaPlayerAndroid(
61 WebKit::WebFrame* frame,
62 WebKit::WebMediaPlayerClient* client,
63 base::WeakPtr<WebMediaPlayerDelegate> delegate,
64 WebMediaPlayerManagerAndroid* manager,
65 WebMediaPlayerProxyAndroid* proxy,
66 StreamTextureFactory* factory,
67 media::MediaLog* media_log)
68 : frame_(frame),
69 client_(client),
70 delegate_(delegate),
71 buffered_(1u),
72 main_loop_(base::MessageLoopProxy::current()),
73 ignore_metadata_duration_change_(false),
74 pending_seek_(0),
75 seeking_(false),
76 did_loading_progress_(false),
77 manager_(manager),
78 network_state_(WebMediaPlayer::NetworkStateEmpty),
79 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
80 is_playing_(false),
81 needs_establish_peer_(true),
82 stream_texture_proxy_initialized_(false),
83 has_size_info_(false),
84 has_media_metadata_(false),
85 has_media_info_(false),
86 stream_texture_factory_(factory),
87 needs_external_surface_(false),
88 video_frame_provider_client_(NULL),
89 #if defined(GOOGLE_TV)
90 demuxer_(NULL),
91 #endif // defined(GOOGLE_TV)
92 source_type_(MediaPlayerAndroid::SOURCE_TYPE_URL),
93 proxy_(proxy),
94 current_time_(0),
95 media_log_(media_log),
96 media_stream_client_(NULL) {
97 DCHECK(proxy_);
98 DCHECK(manager_);
99
100 // We want to be notified of |main_loop_| destruction.
101 base::MessageLoop::current()->AddDestructionObserver(this);
102
103 player_id_ = manager_->RegisterMediaPlayer(this);
104
105 if (stream_texture_factory_) {
106 stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
107 stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_);
108 ReallocateVideoFrame();
109 }
110
111 if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
112 // |decryptor_| is owned, so Unretained() is safe here.
113 decryptor_.reset(new ProxyDecryptor(
114 #if defined(ENABLE_PEPPER_CDMS)
115 client,
116 frame,
117 #endif // defined(ENABLE_PEPPER_CDMS)
118 #if defined(OS_ANDROID) && !defined(GOOGLE_TV)
119 proxy_,
120 player_id_, // TODO(xhwang): Use media_keys_id when MediaKeys are
121 // separated from WebMediaPlayer.
122 #endif // defined(OS_ANDROID) && !defined(GOOGLE_TV)
123 base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, base::Unretained(this)),
124 base::Bind(&WebMediaPlayerAndroid::OnKeyError, base::Unretained(this)),
125 base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
126 base::Unretained(this))));
127 }
128 }
129
130 WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
131 SetVideoFrameProviderClient(NULL);
132 client_->setWebLayer(NULL);
133
134 if (proxy_)
135 proxy_->DestroyPlayer(player_id_);
136
137 if (stream_id_)
138 stream_texture_factory_->DestroyStreamTexture(texture_id_);
139
140 if (manager_)
141 manager_->UnregisterMediaPlayer(player_id_);
142
143 if (base::MessageLoop::current())
144 base::MessageLoop::current()->RemoveDestructionObserver(this);
145
146 if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE && delegate_)
147 delegate_->PlayerGone(this);
148
149 #if defined(GOOGLE_TV)
150 if (audio_renderer_) {
151 if (audio_renderer_->IsLocalRenderer()) {
152 audio_renderer_->Stop();
153 } else if (!paused()) {
154 // The |audio_renderer_| can be shared by multiple remote streams, and
155 // it will be stopped when WebRtcAudioDeviceImpl goes away. So we simply
156 // pause the |audio_renderer_| here to avoid re-creating the
157 // |audio_renderer_|.
158 audio_renderer_->Pause();
159 }
160 }
161 if (demuxer_ && !destroy_demuxer_cb_.is_null()) {
162 media_source_delegate_.reset();
163 destroy_demuxer_cb_.Run();
164 }
165 #endif
166 }
167
168 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
169 load(url, NULL, cors_mode);
170 }
171
172 void WebMediaPlayerAndroid::load(const WebURL& url,
173 WebMediaSource* media_source,
174 CORSMode cors_mode) {
175 source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL;
176 has_media_metadata_ = false;
177 has_media_info_ = false;
178
179 if (media_source)
180 source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE;
181 #if defined(GOOGLE_TV)
182 if (media_stream_client_) {
183 DCHECK(!media_source);
184 source_type_ = MediaPlayerAndroid::SOURCE_TYPE_STREAM;
185 }
186 #endif
187
188 if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) {
189 has_media_info_ = true;
190 media_source_delegate_.reset(
191 new MediaSourceDelegate(proxy_, player_id_, media_log_));
192 // |media_source_delegate_| is owned, so Unretained() is safe here.
193 if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE) {
194 media_source_delegate_->InitializeMediaSource(
195 media_source,
196 base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)),
197 base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
198 base::Unretained(this)),
199 BIND_TO_RENDER_LOOP(&WebMediaPlayerAndroid::OnDurationChange));
200 }
201 #if defined(GOOGLE_TV)
202 if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_STREAM) {
203 media_source_delegate_->InitializeMediaStream(
204 demuxer_,
205 base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
206 base::Unretained(this)));
207 audio_renderer_ = media_stream_client_->GetAudioRenderer(url);
208 if (audio_renderer_)
209 audio_renderer_->Start();
210 }
211 #endif
212 } else {
213 info_loader_.reset(
214 new MediaInfoLoader(
215 url,
216 cors_mode,
217 base::Bind(&WebMediaPlayerAndroid::DidLoadMediaInfo,
218 base::Unretained(this))));
219 info_loader_->Start(frame_);
220 }
221
222 InitializeMediaPlayer(url);
223 }
224
225 void WebMediaPlayerAndroid::InitializeMediaPlayer(const WebURL& url) {
226 url_ = url;
227 GURL first_party_url = frame_->document().firstPartyForCookies();
228 proxy_->Initialize(player_id_, url, source_type_, first_party_url);
229 if (manager_->IsInFullscreen(frame_))
230 proxy_->EnterFullscreen(player_id_);
231
232 UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
233 UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
234 }
235
236 void WebMediaPlayerAndroid::DidLoadMediaInfo(
237 MediaInfoLoader::Status status) {
238 DCHECK(!media_source_delegate_);
239 if (status == MediaInfoLoader::kFailed) {
240 info_loader_.reset();
241 UpdateNetworkState(WebMediaPlayer::NetworkStateNetworkError);
242 return;
243 }
244
245 has_media_info_ = true;
246 if (has_media_metadata_ &&
247 ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
248 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
249 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
250 }
251 }
252
253 void WebMediaPlayerAndroid::play() {
254 #if defined(GOOGLE_TV)
255 if (hasVideo() && needs_external_surface_) {
256 DCHECK(!needs_establish_peer_);
257 proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
258 }
259 if (audio_renderer_ && paused())
260 audio_renderer_->Play();
261 #endif
262 if (hasVideo() && needs_establish_peer_)
263 EstablishSurfaceTexturePeer();
264
265 if (paused())
266 proxy_->Start(player_id_);
267 UpdatePlayingState(true);
268 }
269
270 void WebMediaPlayerAndroid::pause() {
271 #if defined(GOOGLE_TV)
272 if (audio_renderer_ && !paused())
273 audio_renderer_->Pause();
274 #endif
275 proxy_->Pause(player_id_);
276 UpdatePlayingState(false);
277 }
278
279 void WebMediaPlayerAndroid::seek(double seconds) {
280 pending_seek_ = seconds;
281 if (seeking_ && media_source_delegate_)
282 media_source_delegate_->CancelPendingSeek();
283 seeking_ = true;
284
285 base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
286 #if defined(GOOGLE_TV)
287 // TODO(qinmin): check if GTV can also defer the seek until the browser side
288 // player is ready.
289 if (media_source_delegate_)
290 media_source_delegate_->Seek(seek_time);
291 #endif
292 proxy_->Seek(player_id_, seek_time);
293 }
294
295 bool WebMediaPlayerAndroid::supportsFullscreen() const {
296 return true;
297 }
298
299 bool WebMediaPlayerAndroid::supportsSave() const {
300 return false;
301 }
302
303 void WebMediaPlayerAndroid::setRate(double rate) {
304 NOTIMPLEMENTED();
305 }
306
307 void WebMediaPlayerAndroid::setVolume(double volume) {
308 NOTIMPLEMENTED();
309 }
310
311 bool WebMediaPlayerAndroid::hasVideo() const {
312 // If we have obtained video size information before, use it.
313 if (has_size_info_)
314 return !natural_size_.isEmpty();
315
316 // TODO(qinmin): need a better method to determine whether the current media
317 // content contains video. Android does not provide any function to do
318 // this.
319 // We don't know whether the current media content has video unless
320 // the player is prepared. If the player is not prepared, we fall back
321 // to the mime-type. There may be no mime-type on a redirect URL.
322 // In that case, we conservatively assume it contains video so that
323 // enterfullscreen call will not fail.
324 if (!url_.has_path())
325 return false;
326 std::string mime;
327 if(!net::GetMimeTypeFromFile(base::FilePath(url_.path()), &mime))
328 return true;
329 return mime.find("audio/") == std::string::npos;
330 }
331
332 bool WebMediaPlayerAndroid::hasAudio() const {
333 // TODO(hclam): Query status of audio and return the actual value.
334 return true;
335 }
336
337 bool WebMediaPlayerAndroid::paused() const {
338 return !is_playing_;
339 }
340
341 bool WebMediaPlayerAndroid::seeking() const {
342 return seeking_;
343 }
344
345 double WebMediaPlayerAndroid::duration() const {
346 // HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING
347 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
348 return std::numeric_limits<double>::quiet_NaN();
349
350 // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
351 // considers unseekable, including kInfiniteDuration().
352 // See http://crbug.com/248396
353 return duration_.InSecondsF();
354 }
355
356 double WebMediaPlayerAndroid::currentTime() const {
357 // If the player is pending for a seek, return the seek time.
358 if (seeking())
359 return pending_seek_;
360 return current_time_;
361 }
362
363 WebSize WebMediaPlayerAndroid::naturalSize() const {
364 return natural_size_;
365 }
366
367 WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
368 return network_state_;
369 }
370
371 WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
372 return ready_state_;
373 }
374
375 const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
376 if (media_source_delegate_)
377 return media_source_delegate_->Buffered();
378 return buffered_;
379 }
380
381 double WebMediaPlayerAndroid::maxTimeSeekable() const {
382 // If we haven't even gotten to ReadyStateHaveMetadata yet then just
383 // return 0 so that the seekable range is empty.
384 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
385 return 0.0;
386
387 // TODO(hclam): If this stream is not seekable this should return 0.
388 return duration();
389 }
390
391 bool WebMediaPlayerAndroid::didLoadingProgress() const {
392 bool ret = did_loading_progress_;
393 did_loading_progress_ = false;
394 return ret;
395 }
396
397 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
398 const WebKit::WebRect& rect,
399 unsigned char alpha) {
400 NOTIMPLEMENTED();
401 }
402
403 bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
404 WebKit::WebGraphicsContext3D* web_graphics_context,
405 unsigned int texture,
406 unsigned int level,
407 unsigned int internal_format,
408 unsigned int type,
409 bool premultiply_alpha,
410 bool flip_y) {
411 if (!texture_id_)
412 return false;
413
414 // The video is stored in an unmultiplied format, so premultiply if
415 // necessary.
416 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
417 premultiply_alpha);
418
419 // Application itself needs to take care of setting the right flip_y
420 // value down to get the expected result.
421 // flip_y==true means to reverse the video orientation while
422 // flip_y==false means to keep the intrinsic orientation.
423 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
424 web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, texture_id_,
425 texture, level, internal_format,
426 type);
427 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
428 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
429 false);
430 return true;
431 }
432
433 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
434 if (info_loader_)
435 return info_loader_->HasSingleOrigin();
436 // The info loader may have failed.
437 if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_URL)
438 return false;
439 return true;
440 }
441
442 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
443 if (info_loader_)
444 return info_loader_->DidPassCORSAccessCheck();
445 return false;
446 }
447
448 double WebMediaPlayerAndroid::mediaTimeForTimeValue(double timeValue) const {
449 return ConvertSecondsToTimestamp(timeValue).InSecondsF();
450 }
451
452 unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
453 if (media_source_delegate_)
454 return media_source_delegate_->DecodedFrameCount();
455 NOTIMPLEMENTED();
456 return 0;
457 }
458
459 unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
460 if (media_source_delegate_)
461 return media_source_delegate_->DroppedFrameCount();
462 NOTIMPLEMENTED();
463 return 0;
464 }
465
466 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
467 if (media_source_delegate_)
468 return media_source_delegate_->AudioDecodedByteCount();
469 NOTIMPLEMENTED();
470 return 0;
471 }
472
473 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
474 if (media_source_delegate_)
475 return media_source_delegate_->VideoDecodedByteCount();
476 NOTIMPLEMENTED();
477 return 0;
478 }
479
480 void WebMediaPlayerAndroid::OnMediaMetadataChanged(
481 base::TimeDelta duration, int width, int height, bool success) {
482 bool need_to_signal_duration_changed = false;
483
484 if (url_.SchemeIs("file"))
485 UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded);
486
487 // Update duration, if necessary, prior to ready state updates that may
488 // cause duration() query.
489 // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
490 // considers unseekable, including kInfiniteDuration().
491 // See http://crbug.com/248396
492 if (!ignore_metadata_duration_change_ && duration_ != duration) {
493 duration_ = duration;
494
495 // Client readyState transition from HAVE_NOTHING to HAVE_METADATA
496 // already triggers a durationchanged event. If this is a different
497 // transition, remember to signal durationchanged.
498 // Do not ever signal durationchanged on metadata change in MSE case
499 // because OnDurationChange() handles this.
500 if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing &&
501 source_type_ != MediaPlayerAndroid::SOURCE_TYPE_MSE) {
502 need_to_signal_duration_changed = true;
503 }
504 }
505
506 has_media_metadata_ = true;
507 if (has_media_info_ &&
508 ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
509 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
510 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
511 }
512
513 // TODO(wolenetz): Should we just abort early and set network state to an
514 // error if success == false? See http://crbug.com/248399
515 if (success)
516 OnVideoSizeChanged(width, height);
517
518 if (hasVideo() && !video_weblayer_ && client_->needsWebLayerForVideo()) {
519 video_weblayer_.reset(
520 new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
521 client_->setWebLayer(video_weblayer_.get());
522 }
523
524 if (need_to_signal_duration_changed)
525 client_->durationChanged();
526 }
527
528 void WebMediaPlayerAndroid::OnPlaybackComplete() {
529 // When playback is about to finish, android media player often stops
530 // at a time which is smaller than the duration. This makes webkit never
531 // know that the playback has finished. To solve this, we set the
532 // current time to media duration when OnPlaybackComplete() get called.
533 OnTimeUpdate(duration_);
534 client_->timeChanged();
535 }
536
537 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
538 buffered_[0].end = duration() * percentage / 100;
539 did_loading_progress_ = true;
540 }
541
542 void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) {
543 seeking_ = false;
544
545 OnTimeUpdate(current_time);
546
547 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
548
549 client_->timeChanged();
550 }
551
552 void WebMediaPlayerAndroid::OnMediaError(int error_type) {
553 switch (error_type) {
554 case MediaPlayerAndroid::MEDIA_ERROR_FORMAT:
555 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
556 break;
557 case MediaPlayerAndroid::MEDIA_ERROR_DECODE:
558 UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError);
559 break;
560 case MediaPlayerAndroid::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
561 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
562 break;
563 case MediaPlayerAndroid::MEDIA_ERROR_INVALID_CODE:
564 break;
565 }
566 client_->repaint();
567 }
568
569 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
570 has_size_info_ = true;
571 if (natural_size_.width == width && natural_size_.height == height)
572 return;
573
574 #if defined(GOOGLE_TV)
575 static bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch(
576 switches::kUseExternalVideoSurfaceThresholdInPixels);
577 static int threshold = 0;
578 static bool parsed_arg =
579 has_switch &&
580 base::StringToInt(
581 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
582 switches::kUseExternalVideoSurfaceThresholdInPixels),
583 &threshold);
584
585 if ((parsed_arg && threshold <= width * height) ||
586 // Use H/W surface for MSE as the content is protected.
587 media_source_delegate_) {
588 if (stream_texture_factory_) {
589 stream_texture_factory_->DestroyStreamTexture(texture_id_);
590 stream_id_ = 0;
591 texture_id_ = 0;
592 }
593 needs_external_surface_ = true;
594 SetNeedsEstablishPeer(false);
595 if (!paused())
596 proxy_->RequestExternalSurface(player_id_, last_computed_rect_);
597 }
598 #endif
599
600 natural_size_.width = width;
601 natural_size_.height = height;
602 ReallocateVideoFrame();
603 }
604
605 void WebMediaPlayerAndroid::OnTimeUpdate(base::TimeDelta current_time) {
606 current_time_ = current_time.InSecondsF();
607 }
608
609 void WebMediaPlayerAndroid::OnDidEnterFullscreen() {
610 if (!manager_->IsInFullscreen(frame_)) {
611 frame_->view()->willEnterFullScreen();
612 frame_->view()->didEnterFullScreen();
613 manager_->DidEnterFullscreen(frame_);
614 }
615 }
616
617 void WebMediaPlayerAndroid::OnDidExitFullscreen() {
618 // |needs_external_surface_| is always false on non-TV devices.
619 if (!needs_external_surface_)
620 SetNeedsEstablishPeer(true);
621 // We had the fullscreen surface connected to Android MediaPlayer,
622 // so reconnect our surface texture for embedded playback.
623 if (!paused())
624 EstablishSurfaceTexturePeer();
625
626 frame_->view()->willExitFullScreen();
627 frame_->view()->didExitFullScreen();
628 manager_->DidExitFullscreen();
629 client_->repaint();
630 }
631
632 void WebMediaPlayerAndroid::OnMediaPlayerPlay() {
633 UpdatePlayingState(true);
634 client_->playbackStateChanged();
635 }
636
637 void WebMediaPlayerAndroid::OnMediaPlayerPause() {
638 UpdatePlayingState(false);
639 client_->playbackStateChanged();
640 }
641
642 void WebMediaPlayerAndroid::OnMediaSeekRequest(base::TimeDelta time_to_seek) {
643 if (!media_source_delegate_)
644 return;
645
646 if (!seeking_)
647 media_source_delegate_->CancelPendingSeek();
648 media_source_delegate_->Seek(time_to_seek);
649 OnTimeUpdate(time_to_seek);
650 }
651
652 void WebMediaPlayerAndroid::OnMediaConfigRequest() {
653 if (!media_source_delegate_)
654 return;
655
656 media_source_delegate_->OnMediaConfigRequest();
657 }
658
659 void WebMediaPlayerAndroid::OnDurationChange(const base::TimeDelta& duration) {
660 // Only MSE |source_type_| registers this callback.
661 DCHECK(source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE);
662
663 // Cache the new duration value and trust it over any subsequent duration
664 // values received in OnMediaMetadataChanged().
665 // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer
666 // considers unseekable, including kInfiniteDuration().
667 // See http://crbug.com/248396
668 duration_ = duration;
669 ignore_metadata_duration_change_ = true;
670
671 // Send message to Android MediaSourcePlayer to update duration.
672 if (proxy_)
673 proxy_->DurationChanged(player_id_, duration_);
674
675 // Notify MediaPlayerClient that duration has changed, if > HAVE_NOTHING.
676 if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing)
677 client_->durationChanged();
678 }
679
680 void WebMediaPlayerAndroid::UpdateNetworkState(
681 WebMediaPlayer::NetworkState state) {
682 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing &&
683 (state == WebMediaPlayer::NetworkStateNetworkError ||
684 state == WebMediaPlayer::NetworkStateDecodeError)) {
685 // Any error that occurs before reaching ReadyStateHaveMetadata should
686 // be considered a format error.
687 network_state_ = WebMediaPlayer::NetworkStateFormatError;
688 } else {
689 network_state_ = state;
690 }
691 client_->networkStateChanged();
692 }
693
694 void WebMediaPlayerAndroid::UpdateReadyState(
695 WebMediaPlayer::ReadyState state) {
696 ready_state_ = state;
697 client_->readyStateChanged();
698 }
699
700 void WebMediaPlayerAndroid::OnPlayerReleased() {
701 // |needs_external_surface_| is always false on non-TV devices.
702 if (!needs_external_surface_)
703 needs_establish_peer_ = true;
704 }
705
706 void WebMediaPlayerAndroid::ReleaseMediaResources() {
707 switch (network_state_) {
708 // Pause the media player and inform WebKit if the player is in a good
709 // shape.
710 case WebMediaPlayer::NetworkStateIdle:
711 case WebMediaPlayer::NetworkStateLoading:
712 case WebMediaPlayer::NetworkStateLoaded:
713 pause();
714 client_->playbackStateChanged();
715 break;
716 // If a WebMediaPlayer instance has entered into one of these states,
717 // the internal network state in HTMLMediaElement could be set to empty.
718 // And calling playbackStateChanged() could get this object deleted.
719 case WebMediaPlayer::NetworkStateEmpty:
720 case WebMediaPlayer::NetworkStateFormatError:
721 case WebMediaPlayer::NetworkStateNetworkError:
722 case WebMediaPlayer::NetworkStateDecodeError:
723 break;
724 }
725 proxy_->ReleaseResources(player_id_);
726 OnPlayerReleased();
727 }
728
729 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() {
730 if (manager_)
731 manager_->UnregisterMediaPlayer(player_id_);
732 Detach();
733 }
734
735 void WebMediaPlayerAndroid::Detach() {
736 if (stream_id_) {
737 stream_texture_factory_->DestroyStreamTexture(texture_id_);
738 stream_id_ = 0;
739 }
740
741 media_source_delegate_.reset();
742 current_frame_ = NULL;
743 manager_ = NULL;
744 proxy_ = NULL;
745 }
746
747 void WebMediaPlayerAndroid::ReallocateVideoFrame() {
748 if (needs_external_surface_) {
749 // VideoFrame::CreateHoleFrame is only defined under GOOGLE_TV.
750 #if defined(GOOGLE_TV)
751 if (!natural_size_.isEmpty()) {
752 current_frame_ = VideoFrame::CreateHoleFrame(natural_size_);
753 // Force the client to grab the hole frame.
754 client_->repaint();
755 }
756 #else
757 NOTIMPLEMENTED() << "Hole punching not supported outside of Google TV";
758 #endif
759 } else if (texture_id_) {
760 current_frame_ = VideoFrame::WrapNativeTexture(
761 texture_id_, kGLTextureExternalOES, natural_size_,
762 gfx::Rect(natural_size_), natural_size_, base::TimeDelta(),
763 VideoFrame::ReadPixelsCB(),
764 base::Closure());
765 }
766 }
767
768 void WebMediaPlayerAndroid::SetVideoFrameProviderClient(
769 cc::VideoFrameProvider::Client* client) {
770 // This is called from both the main renderer thread and the compositor
771 // thread (when the main thread is blocked).
772 if (video_frame_provider_client_)
773 video_frame_provider_client_->StopUsingProvider();
774 video_frame_provider_client_ = client;
775
776 // Set the callback target when a frame is produced.
777 if (stream_texture_proxy_)
778 stream_texture_proxy_->SetClient(client);
779 }
780
781 scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
782 if (!stream_texture_proxy_initialized_ && stream_texture_proxy_ &&
783 stream_id_ && !needs_external_surface_) {
784 gfx::Size natural_size = current_frame_->natural_size();
785 stream_texture_proxy_->BindToCurrentThread(
786 stream_id_, natural_size.width(), natural_size.height());
787 stream_texture_proxy_initialized_ = true;
788 }
789 return current_frame_;
790 }
791
792 void WebMediaPlayerAndroid::PutCurrentFrame(
793 const scoped_refptr<media::VideoFrame>& frame) {
794 }
795
796 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
797 if (media_source_delegate_ && stream_texture_factory_) {
798 // MediaCodec will release the old surface when it goes away, we need to
799 // recreate a new one each time this is called.
800 stream_texture_factory_->DestroyStreamTexture(texture_id_);
801 stream_id_ = 0;
802 texture_id_ = 0;
803 stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_);
804 ReallocateVideoFrame();
805 stream_texture_proxy_initialized_ = false;
806 }
807 if (stream_texture_factory_.get() && stream_id_)
808 stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
809 needs_establish_peer_ = false;
810 }
811
812 void WebMediaPlayerAndroid::SetNeedsEstablishPeer(bool needs_establish_peer) {
813 needs_establish_peer_ = needs_establish_peer;
814 }
815
816 void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) {
817 is_playing_ = is_playing;
818 if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_MSE || !delegate_)
819 return;
820 if (is_playing)
821 delegate_->DidPlay(this);
822 else
823 delegate_->DidPause(this);
824 }
825
826 #if defined(GOOGLE_TV)
827 bool WebMediaPlayerAndroid::RetrieveGeometryChange(gfx::RectF* rect) {
828 if (!video_weblayer_)
829 return false;
830
831 // Compute the geometry of video frame layer.
832 cc::Layer* layer = video_weblayer_->layer();
833 rect->set_size(layer->bounds());
834 while (layer) {
835 rect->Offset(layer->position().OffsetFromOrigin());
836 layer = layer->parent();
837 }
838
839 // Return false when the geometry hasn't been changed from the last time.
840 if (last_computed_rect_ == *rect)
841 return false;
842
843 // Store the changed geometry information when it is actually changed.
844 last_computed_rect_ = *rect;
845 return true;
846 }
847 #endif
848
849 // The following EME related code is copied from WebMediaPlayerImpl.
850 // TODO(xhwang): Remove duplicate code between WebMediaPlayerAndroid and
851 // WebMediaPlayerImpl.
852 // TODO(kjyoun): Update Google TV EME implementation to use IPC.
853
854 // Helper functions to report media EME related stats to UMA. They follow the
855 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
856 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
857 // that UMA_* macros require the names to be constant throughout the process'
858 // lifetime.
859 static void EmeUMAHistogramEnumeration(const std::string& key_system,
860 const std::string& method,
861 int sample,
862 int boundary_value) {
863 base::LinearHistogram::FactoryGet(
864 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
865 1, boundary_value, boundary_value + 1,
866 base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
867 }
868
869 static void EmeUMAHistogramCounts(const std::string& key_system,
870 const std::string& method,
871 int sample) {
872 // Use the same parameters as UMA_HISTOGRAM_COUNTS.
873 base::Histogram::FactoryGet(
874 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
875 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
876 }
877
878 // Helper enum for reporting generateKeyRequest/addKey histograms.
879 enum MediaKeyException {
880 kUnknownResultId,
881 kSuccess,
882 kKeySystemNotSupported,
883 kInvalidPlayerState,
884 kMaxMediaKeyException
885 };
886
887 static MediaKeyException MediaKeyExceptionForUMA(
888 WebMediaPlayer::MediaKeyException e) {
889 switch (e) {
890 case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
891 return kKeySystemNotSupported;
892 case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
893 return kInvalidPlayerState;
894 case WebMediaPlayer::MediaKeyExceptionNoError:
895 return kSuccess;
896 default:
897 return kUnknownResultId;
898 }
899 }
900
901 // Helper for converting |key_system| name and exception |e| to a pair of enum
902 // values from above, for reporting to UMA.
903 static void ReportMediaKeyExceptionToUMA(
904 const std::string& method,
905 const WebString& key_system,
906 WebMediaPlayer::MediaKeyException e) {
907 MediaKeyException result_id = MediaKeyExceptionForUMA(e);
908 DCHECK_NE(result_id, kUnknownResultId) << e;
909 EmeUMAHistogramEnumeration(
910 key_system.utf8(), method, result_id, kMaxMediaKeyException);
911 }
912
913 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
914 const WebString& key_system,
915 const unsigned char* init_data,
916 unsigned init_data_length) {
917 WebMediaPlayer::MediaKeyException e =
918 GenerateKeyRequestInternal(key_system, init_data, init_data_length);
919 ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
920 return e;
921 }
922
923 WebMediaPlayer::MediaKeyException
924 WebMediaPlayerAndroid::GenerateKeyRequestInternal(
925 const WebString& key_system,
926 const unsigned char* init_data,
927 unsigned init_data_length) {
928 DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
929 << std::string(reinterpret_cast<const char*>(init_data),
930 static_cast<size_t>(init_data_length));
931
932 if (!IsSupportedKeySystem(key_system))
933 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
934
935 // We do not support run-time switching between key systems for now.
936 if (current_key_system_.isEmpty()) {
937 if (!decryptor_->InitializeCDM(key_system.utf8()))
938 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
939 current_key_system_ = key_system;
940 } else if (key_system != current_key_system_) {
941 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
942 }
943
944 // TODO(xhwang): We assume all streams are from the same container (thus have
945 // the same "type") for now. In the future, the "type" should be passed down
946 // from the application.
947 if (!decryptor_->GenerateKeyRequest(init_data_type_,
948 init_data, init_data_length)) {
949 current_key_system_.reset();
950 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
951 }
952
953 return WebMediaPlayer::MediaKeyExceptionNoError;
954 }
955
956 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::addKey(
957 const WebString& key_system,
958 const unsigned char* key,
959 unsigned key_length,
960 const unsigned char* init_data,
961 unsigned init_data_length,
962 const WebString& session_id) {
963 WebMediaPlayer::MediaKeyException e = AddKeyInternal(
964 key_system, key, key_length, init_data, init_data_length, session_id);
965 ReportMediaKeyExceptionToUMA("addKey", key_system, e);
966 return e;
967 }
968
969 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::AddKeyInternal(
970 const WebString& key_system,
971 const unsigned char* key,
972 unsigned key_length,
973 const unsigned char* init_data,
974 unsigned init_data_length,
975 const WebString& session_id) {
976 DCHECK(key);
977 DCHECK_GT(key_length, 0u);
978 DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
979 << std::string(reinterpret_cast<const char*>(key),
980 static_cast<size_t>(key_length)) << ", "
981 << std::string(reinterpret_cast<const char*>(init_data),
982 static_cast<size_t>(init_data_length))
983 << " [" << session_id.utf8().data() << "]";
984
985 if (!IsSupportedKeySystem(key_system))
986 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
987
988 if (current_key_system_.isEmpty() || key_system != current_key_system_)
989 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
990
991 decryptor_->AddKey(key, key_length, init_data, init_data_length,
992 session_id.utf8());
993 return WebMediaPlayer::MediaKeyExceptionNoError;
994 }
995
996 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::cancelKeyRequest(
997 const WebString& key_system,
998 const WebString& session_id) {
999 WebMediaPlayer::MediaKeyException e =
1000 CancelKeyRequestInternal(key_system, session_id);
1001 ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
1002 return e;
1003 }
1004
1005 WebMediaPlayer::MediaKeyException
1006 WebMediaPlayerAndroid::CancelKeyRequestInternal(
1007 const WebString& key_system,
1008 const WebString& session_id) {
1009 if (!IsSupportedKeySystem(key_system))
1010 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1011
1012 if (current_key_system_.isEmpty() || key_system != current_key_system_)
1013 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
1014
1015 decryptor_->CancelKeyRequest(session_id.utf8());
1016 return WebMediaPlayer::MediaKeyExceptionNoError;
1017 }
1018
1019 void WebMediaPlayerAndroid::OnKeyAdded(const std::string& session_id) {
1020 EmeUMAHistogramCounts(current_key_system_.utf8(), "KeyAdded", 1);
1021
1022 if (media_source_delegate_)
1023 media_source_delegate_->NotifyKeyAdded(current_key_system_.utf8());
1024
1025 client_->keyAdded(current_key_system_, WebString::fromUTF8(session_id));
1026 }
1027
1028 void WebMediaPlayerAndroid::OnKeyError(const std::string& session_id,
1029 media::MediaKeys::KeyError error_code,
1030 int system_code) {
1031 EmeUMAHistogramEnumeration(current_key_system_.utf8(), "KeyError",
1032 error_code, media::MediaKeys::kMaxKeyError);
1033
1034 client_->keyError(
1035 current_key_system_,
1036 WebString::fromUTF8(session_id),
1037 static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
1038 system_code);
1039 }
1040
1041 void WebMediaPlayerAndroid::OnKeyMessage(const std::string& session_id,
1042 const std::string& message,
1043 const std::string& destination_url) {
1044 const GURL destination_url_gurl(destination_url);
1045 DLOG_IF(WARNING, !destination_url.empty() && !destination_url_gurl.is_valid())
1046 << "Invalid URL in destination_url: " << destination_url;
1047
1048 client_->keyMessage(current_key_system_,
1049 WebString::fromUTF8(session_id),
1050 reinterpret_cast<const uint8*>(message.data()),
1051 message.size(),
1052 destination_url_gurl);
1053 }
1054
1055 void WebMediaPlayerAndroid::OnNeedKey(const std::string& session_id,
1056 const std::string& type,
1057 scoped_ptr<uint8[]> init_data,
1058 int init_data_size) {
1059 // Do not fire NeedKey event if encrypted media is not enabled.
1060 if (!WebKit::WebRuntimeFeatures::isEncryptedMediaEnabled() &&
1061 !WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
1062 return;
1063 }
1064
1065 UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
1066
1067 DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
1068 if (init_data_type_.empty())
1069 init_data_type_ = type;
1070
1071 client_->keyNeeded(WebString(),
1072 WebString::fromUTF8(session_id),
1073 init_data.get(),
1074 init_data_size);
1075 }
1076
1077 #if defined(GOOGLE_TV)
1078 bool WebMediaPlayerAndroid::InjectMediaStream(
1079 MediaStreamClient* media_stream_client,
1080 media::Demuxer* demuxer,
1081 const base::Closure& destroy_demuxer_cb) {
1082 DCHECK(!demuxer);
1083 media_stream_client_ = media_stream_client;
1084 demuxer_ = demuxer;
1085 destroy_demuxer_cb_ = destroy_demuxer_cb;
1086 return true;
1087 }
1088 #endif
1089
1090 void WebMediaPlayerAndroid::OnReadFromDemuxer(
1091 media::DemuxerStream::Type type, bool seek_done) {
1092 if (media_source_delegate_)
1093 media_source_delegate_->OnReadFromDemuxer(type, seek_done);
1094 else
1095 NOTIMPLEMENTED();
1096 }
1097
1098 void WebMediaPlayerAndroid::enterFullscreen() {
1099 if (manager_->CanEnterFullscreen(frame_)) {
1100 proxy_->EnterFullscreen(player_id_);
1101 SetNeedsEstablishPeer(false);
1102 }
1103 }
1104
1105 void WebMediaPlayerAndroid::exitFullscreen() {
1106 proxy_->ExitFullscreen(player_id_);
1107 }
1108
1109 bool WebMediaPlayerAndroid::canEnterFullscreen() const {
1110 return manager_->CanEnterFullscreen(frame_);
1111 }
1112
1113 } // namespace webkit_media
OLDNEW
« no previous file with comments | « webkit/renderer/media/android/webmediaplayer_android.h ('k') | webkit/renderer/media/android/webmediaplayer_manager_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698