Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / android / webmediaplayer_android.cc
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 "content/renderer/media/android/webmediaplayer_android.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "cc/layers/video_layer.h"
19 #include "content/public/common/content_client.h"
20 #include "content/public/renderer/render_frame.h"
21 #include "content/renderer/media/android/proxy_media_keys.h"
22 #include "content/renderer/media/android/renderer_demuxer_android.h"
23 #include "content/renderer/media/android/renderer_media_player_manager.h"
24 #include "content/renderer/media/crypto/key_systems.h"
25 #include "content/renderer/media/webmediaplayer_delegate.h"
26 #include "content/renderer/media/webmediaplayer_util.h"
27 #include "content/renderer/render_frame_impl.h"
28 #include "content/renderer/render_thread_impl.h"
29 #include "gpu/GLES2/gl2extchromium.h"
30 #include "gpu/command_buffer/client/gles2_interface.h"
31 #include "gpu/command_buffer/common/mailbox_holder.h"
32 #include "grit/content_resources.h"
33 #include "media/base/android/media_player_android.h"
34 #include "media/base/bind_to_current_loop.h"
35 #include "media/base/media_switches.h"
36 #include "media/base/video_frame.h"
37 #include "net/base/mime_util.h"
38 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
39 #include "third_party/WebKit/public/platform/WebString.h"
40 #include "third_party/WebKit/public/platform/WebURL.h"
41 #include "third_party/WebKit/public/web/WebDocument.h"
42 #include "third_party/WebKit/public/web/WebFrame.h"
43 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
44 #include "third_party/WebKit/public/web/WebView.h"
45 #include "third_party/skia/include/core/SkBitmap.h"
46 #include "third_party/skia/include/core/SkCanvas.h"
47 #include "third_party/skia/include/core/SkPaint.h"
48 #include "ui/gfx/image/image.h"
49 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
50
51 static const uint32 kGLTextureExternalOES = 0x8D65;
52
53 using blink::WebMediaPlayer;
54 using blink::WebSize;
55 using blink::WebString;
56 using blink::WebTimeRanges;
57 using blink::WebURL;
58 using gpu::gles2::GLES2Interface;
59 using media::MediaPlayerAndroid;
60 using media::VideoFrame;
61
62 namespace {
63 // Prefix for histograms related to Encrypted Media Extensions.
64 const char* kMediaEme = "Media.EME.";
65 }  // namespace
66
67 namespace content {
68
69 // static
70 void WebMediaPlayerAndroid::OnReleaseRemotePlaybackTexture(
71     const scoped_refptr<base::MessageLoopProxy>& main_loop,
72     const base::WeakPtr<WebMediaPlayerAndroid>& player,
73     scoped_ptr<gpu::MailboxHolder> mailbox_holder) {
74   main_loop->PostTask(
75       FROM_HERE,
76       base::Bind(&WebMediaPlayerAndroid::DoReleaseRemotePlaybackTexture,
77                  player,
78                  mailbox_holder->sync_point));
79 }
80
81 WebMediaPlayerAndroid::WebMediaPlayerAndroid(
82     blink::WebFrame* frame,
83     blink::WebMediaPlayerClient* client,
84     base::WeakPtr<WebMediaPlayerDelegate> delegate,
85     RendererMediaPlayerManager* manager,
86     StreamTextureFactory* factory,
87     const scoped_refptr<base::MessageLoopProxy>& media_loop,
88     media::MediaLog* media_log)
89     : RenderFrameObserver(RenderFrame::FromWebFrame(frame)),
90       frame_(frame),
91       client_(client),
92       delegate_(delegate),
93       buffered_(1u),
94       main_loop_(base::MessageLoopProxy::current()),
95       media_loop_(media_loop),
96       ignore_metadata_duration_change_(false),
97       pending_seek_(false),
98       seeking_(false),
99       did_loading_progress_(false),
100       manager_(manager),
101       network_state_(WebMediaPlayer::NetworkStateEmpty),
102       ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
103       remote_playback_texture_id_(0),
104       texture_id_(0),
105       texture_mailbox_sync_point_(0),
106       stream_id_(0),
107       is_playing_(false),
108       playing_started_(false),
109       needs_establish_peer_(true),
110       stream_texture_proxy_initialized_(false),
111       has_size_info_(false),
112       has_media_metadata_(false),
113       has_media_info_(false),
114       stream_texture_factory_(factory),
115       needs_external_surface_(false),
116       video_frame_provider_client_(NULL),
117       pending_playback_(false),
118       player_type_(MEDIA_PLAYER_TYPE_URL),
119       current_time_(0),
120       is_remote_(false),
121       media_log_(media_log),
122       weak_factory_(this) {
123   DCHECK(manager_);
124
125   DCHECK(main_thread_checker_.CalledOnValidThread());
126
127   player_id_ = manager_->RegisterMediaPlayer(this);
128
129 #if defined(VIDEO_HOLE)
130   // Defer stream texture creation until we are sure it's necessary.
131   needs_establish_peer_ = false;
132   current_frame_ = VideoFrame::CreateBlackFrame(gfx::Size(1, 1));
133 #endif  // defined(VIDEO_HOLE)
134   TryCreateStreamTextureProxyIfNeeded();
135 }
136
137 WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
138   SetVideoFrameProviderClient(NULL);
139   client_->setWebLayer(NULL);
140
141   if (manager_) {
142     manager_->DestroyPlayer(player_id_);
143     manager_->UnregisterMediaPlayer(player_id_);
144   }
145
146   if (stream_id_)
147     stream_texture_factory_->DestroyStreamTexture(texture_id_);
148
149   if (remote_playback_texture_id_) {
150     stream_texture_factory_->ContextGL()->
151         DeleteTextures(1, &remote_playback_texture_id_);
152   }
153
154   if (player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE && delegate_)
155     delegate_->PlayerGone(this);
156 }
157
158 void WebMediaPlayerAndroid::load(LoadType load_type,
159                                  const blink::WebURL& url,
160                                  CORSMode cors_mode) {
161   switch (load_type) {
162     case LoadTypeURL:
163       player_type_ = MEDIA_PLAYER_TYPE_URL;
164       break;
165
166     case LoadTypeMediaSource:
167       player_type_ = MEDIA_PLAYER_TYPE_MEDIA_SOURCE;
168       break;
169
170     case LoadTypeMediaStream:
171       CHECK(false) << "WebMediaPlayerAndroid doesn't support MediaStream on "
172                       "this platform";
173       return;
174   }
175
176   has_media_metadata_ = false;
177   has_media_info_ = false;
178
179   int demuxer_client_id = 0;
180   if (player_type_ != MEDIA_PLAYER_TYPE_URL) {
181     has_media_info_ = true;
182
183     RendererDemuxerAndroid* demuxer =
184         RenderThreadImpl::current()->renderer_demuxer();
185     demuxer_client_id = demuxer->GetNextDemuxerClientID();
186
187     media_source_delegate_.reset(new MediaSourceDelegate(
188         demuxer, demuxer_client_id, media_loop_, media_log_));
189
190     if (player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE) {
191       media::SetDecryptorReadyCB set_decryptor_ready_cb =
192           media::BindToCurrentLoop(
193               base::Bind(&WebMediaPlayerAndroid::SetDecryptorReadyCB,
194                          weak_factory_.GetWeakPtr()));
195
196       media_source_delegate_->InitializeMediaSource(
197           base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,
198                      weak_factory_.GetWeakPtr()),
199           base::Bind(&WebMediaPlayerAndroid::OnNeedKey,
200                      weak_factory_.GetWeakPtr()),
201           set_decryptor_ready_cb,
202           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
203                      weak_factory_.GetWeakPtr()),
204           base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
205                      weak_factory_.GetWeakPtr()));
206     }
207   } else {
208     info_loader_.reset(
209         new MediaInfoLoader(
210             url,
211             cors_mode,
212             base::Bind(&WebMediaPlayerAndroid::DidLoadMediaInfo,
213                        weak_factory_.GetWeakPtr())));
214     info_loader_->Start(frame_);
215   }
216
217   url_ = url;
218   GURL first_party_url = frame_->document().firstPartyForCookies();
219   manager_->Initialize(
220       player_type_, player_id_, url, first_party_url, demuxer_client_id);
221
222   if (manager_->ShouldEnterFullscreen(frame_))
223     manager_->EnterFullscreen(player_id_, frame_);
224
225   UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
226   UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
227 }
228
229 void WebMediaPlayerAndroid::DidLoadMediaInfo(MediaInfoLoader::Status status) {
230   DCHECK(!media_source_delegate_);
231   if (status == MediaInfoLoader::kFailed) {
232     info_loader_.reset();
233     UpdateNetworkState(WebMediaPlayer::NetworkStateNetworkError);
234     return;
235   }
236
237   has_media_info_ = true;
238   if (has_media_metadata_ &&
239       ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
240     UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
241     UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
242   }
243   // Android doesn't start fetching resources until an implementation-defined
244   // event (e.g. playback request) occurs. Sets the network state to IDLE
245   // if play is not requested yet.
246   if (!playing_started_)
247     UpdateNetworkState(WebMediaPlayer::NetworkStateIdle);
248 }
249
250 void WebMediaPlayerAndroid::play() {
251 #if defined(VIDEO_HOLE)
252   if (hasVideo() && needs_external_surface_ &&
253       !manager_->IsInFullscreen(frame_)) {
254     DCHECK(!needs_establish_peer_);
255     manager_->RequestExternalSurface(player_id_, last_computed_rect_);
256   }
257 #endif  // defined(VIDEO_HOLE)
258
259   TryCreateStreamTextureProxyIfNeeded();
260   if (hasVideo() && needs_establish_peer_)
261     EstablishSurfaceTexturePeer();
262
263   if (paused())
264     manager_->Start(player_id_);
265   UpdatePlayingState(true);
266   UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
267   playing_started_ = true;
268 }
269
270 void WebMediaPlayerAndroid::pause() {
271   Pause(true);
272 }
273
274 void WebMediaPlayerAndroid::seek(double seconds) {
275   DCHECK(main_loop_->BelongsToCurrentThread());
276   DVLOG(1) << __FUNCTION__ << "(" << seconds << ")";
277
278   base::TimeDelta new_seek_time = ConvertSecondsToTimestamp(seconds);
279
280   if (seeking_) {
281     if (new_seek_time == seek_time_) {
282       if (media_source_delegate_) {
283         if (!pending_seek_) {
284           // If using media source demuxer, only suppress redundant seeks if
285           // there is no pending seek. This enforces that any pending seek that
286           // results in a demuxer seek is preceded by matching
287           // CancelPendingSeek() and StartWaitingForSeek() calls.
288           return;
289         }
290       } else {
291         // Suppress all redundant seeks if unrestricted by media source
292         // demuxer API.
293         pending_seek_ = false;
294         return;
295       }
296     }
297
298     pending_seek_ = true;
299     pending_seek_time_ = new_seek_time;
300
301     if (media_source_delegate_)
302       media_source_delegate_->CancelPendingSeek(pending_seek_time_);
303
304     // Later, OnSeekComplete will trigger the pending seek.
305     return;
306   }
307
308   seeking_ = true;
309   seek_time_ = new_seek_time;
310
311   if (media_source_delegate_)
312     media_source_delegate_->StartWaitingForSeek(seek_time_);
313
314   // Kick off the asynchronous seek!
315   manager_->Seek(player_id_, seek_time_);
316 }
317
318 bool WebMediaPlayerAndroid::supportsSave() const {
319   return false;
320 }
321
322 void WebMediaPlayerAndroid::setRate(double rate) {
323   NOTIMPLEMENTED();
324 }
325
326 void WebMediaPlayerAndroid::setVolume(double volume) {
327   manager_->SetVolume(player_id_, volume);
328 }
329
330 bool WebMediaPlayerAndroid::hasVideo() const {
331   // If we have obtained video size information before, use it.
332   if (has_size_info_)
333     return !natural_size_.isEmpty();
334
335   // TODO(qinmin): need a better method to determine whether the current media
336   // content contains video. Android does not provide any function to do
337   // this.
338   // We don't know whether the current media content has video unless
339   // the player is prepared. If the player is not prepared, we fall back
340   // to the mime-type. There may be no mime-type on a redirect URL.
341   // In that case, we conservatively assume it contains video so that
342   // enterfullscreen call will not fail.
343   if (!url_.has_path())
344     return false;
345   std::string mime;
346   if (!net::GetMimeTypeFromFile(base::FilePath(url_.path()), &mime))
347     return true;
348   return mime.find("audio/") == std::string::npos;
349 }
350
351 bool WebMediaPlayerAndroid::hasAudio() const {
352   if (!url_.has_path())
353     return false;
354   std::string mime;
355   if (!net::GetMimeTypeFromFile(base::FilePath(url_.path()), &mime))
356     return true;
357
358   if (mime.find("audio/") != std::string::npos ||
359       mime.find("video/") != std::string::npos ||
360       mime.find("application/ogg") != std::string::npos) {
361     return true;
362   }
363   return false;
364 }
365
366 bool WebMediaPlayerAndroid::paused() const {
367   return !is_playing_;
368 }
369
370 bool WebMediaPlayerAndroid::seeking() const {
371   return seeking_;
372 }
373
374 double WebMediaPlayerAndroid::duration() const {
375   // HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING
376   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
377     return std::numeric_limits<double>::quiet_NaN();
378
379   if (duration_ == media::kInfiniteDuration())
380     return std::numeric_limits<double>::infinity();
381
382   return duration_.InSecondsF();
383 }
384
385 double WebMediaPlayerAndroid::currentTime() const {
386   // If the player is processing a seek, return the seek time.
387   // Blink may still query us if updatePlaybackState() occurs while seeking.
388   if (seeking()) {
389     return pending_seek_ ?
390         pending_seek_time_.InSecondsF() : seek_time_.InSecondsF();
391   }
392
393   return current_time_;
394 }
395
396 WebSize WebMediaPlayerAndroid::naturalSize() const {
397   return natural_size_;
398 }
399
400 WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
401   return network_state_;
402 }
403
404 WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
405   return ready_state_;
406 }
407
408 const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
409   if (media_source_delegate_)
410     return media_source_delegate_->Buffered();
411   return buffered_;
412 }
413
414 double WebMediaPlayerAndroid::maxTimeSeekable() const {
415   // If we haven't even gotten to ReadyStateHaveMetadata yet then just
416   // return 0 so that the seekable range is empty.
417   if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
418     return 0.0;
419
420   if (duration() == std::numeric_limits<double>::infinity())
421     return 0.0;
422
423   return std::min(std::numeric_limits<int32>::max() / 1000.0, duration());
424 }
425
426 bool WebMediaPlayerAndroid::didLoadingProgress() const {
427   bool ret = did_loading_progress_;
428   did_loading_progress_ = false;
429   return ret;
430 }
431
432 void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
433                                   const blink::WebRect& rect,
434                                   unsigned char alpha) {
435   NOTIMPLEMENTED();
436 }
437
438 bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
439     blink::WebGraphicsContext3D* web_graphics_context,
440     unsigned int texture,
441     unsigned int level,
442     unsigned int internal_format,
443     unsigned int type,
444     bool premultiply_alpha,
445     bool flip_y) {
446   if (is_remote_ || !texture_id_)
447     return false;
448
449   // For hidden video element (with style "display:none"), ensure the texture
450   // size is set.
451   if (cached_stream_texture_size_.width != natural_size_.width ||
452       cached_stream_texture_size_.height != natural_size_.height) {
453     stream_texture_factory_->SetStreamTextureSize(
454         stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
455     cached_stream_texture_size_ = natural_size_;
456   }
457
458   // Ensure the target of texture is set before copyTextureCHROMIUM, otherwise
459   // an invalid texture target may be used for copy texture.
460   web_graphics_context->bindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
461
462   // The video is stored in an unmultiplied format, so premultiply if
463   // necessary.
464   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
465                                     premultiply_alpha);
466
467   // Application itself needs to take care of setting the right flip_y
468   // value down to get the expected result.
469   // flip_y==true means to reverse the video orientation while
470   // flip_y==false means to keep the intrinsic orientation.
471   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
472   web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, texture_id_,
473                                             texture, level, internal_format,
474                                             type);
475   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
476   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
477                                     false);
478
479   web_graphics_context->bindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
480   return true;
481 }
482
483 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
484   if (info_loader_)
485     return info_loader_->HasSingleOrigin();
486   // The info loader may have failed.
487   if (player_type_ == MEDIA_PLAYER_TYPE_URL)
488     return false;
489   return true;
490 }
491
492 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
493   if (info_loader_)
494     return info_loader_->DidPassCORSAccessCheck();
495   return false;
496 }
497
498 double WebMediaPlayerAndroid::mediaTimeForTimeValue(double timeValue) const {
499   return ConvertSecondsToTimestamp(timeValue).InSecondsF();
500 }
501
502 unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
503   if (media_source_delegate_)
504     return media_source_delegate_->DecodedFrameCount();
505   NOTIMPLEMENTED();
506   return 0;
507 }
508
509 unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
510   if (media_source_delegate_)
511     return media_source_delegate_->DroppedFrameCount();
512   NOTIMPLEMENTED();
513   return 0;
514 }
515
516 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
517   if (media_source_delegate_)
518     return media_source_delegate_->AudioDecodedByteCount();
519   NOTIMPLEMENTED();
520   return 0;
521 }
522
523 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
524   if (media_source_delegate_)
525     return media_source_delegate_->VideoDecodedByteCount();
526   NOTIMPLEMENTED();
527   return 0;
528 }
529
530 void WebMediaPlayerAndroid::OnMediaMetadataChanged(
531     const base::TimeDelta& duration, int width, int height, bool success) {
532   bool need_to_signal_duration_changed = false;
533
534   if (url_.SchemeIs("file") || url_.SchemeIs("app"))
535     UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded);
536
537   // Update duration, if necessary, prior to ready state updates that may
538   // cause duration() query.
539   if (!ignore_metadata_duration_change_ && duration_ != duration) {
540     duration_ = duration;
541
542     // Client readyState transition from HAVE_NOTHING to HAVE_METADATA
543     // already triggers a durationchanged event. If this is a different
544     // transition, remember to signal durationchanged.
545     // Do not ever signal durationchanged on metadata change in MSE case
546     // because OnDurationChanged() handles this.
547     if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing &&
548         player_type_ != MEDIA_PLAYER_TYPE_MEDIA_SOURCE) {
549       need_to_signal_duration_changed = true;
550     }
551   }
552
553   has_media_metadata_ = true;
554   if (has_media_info_ &&
555       ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
556     UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
557     UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
558   }
559
560   // TODO(wolenetz): Should we just abort early and set network state to an
561   // error if success == false? See http://crbug.com/248399
562   if (success)
563     OnVideoSizeChanged(width, height);
564
565   if (need_to_signal_duration_changed)
566     client_->durationChanged();
567 }
568
569 void WebMediaPlayerAndroid::OnPlaybackComplete() {
570   // When playback is about to finish, android media player often stops
571   // at a time which is smaller than the duration. This makes webkit never
572   // know that the playback has finished. To solve this, we set the
573   // current time to media duration when OnPlaybackComplete() get called.
574   OnTimeUpdate(duration_);
575   client_->timeChanged();
576
577   // if the loop attribute is set, timeChanged() will update the current time
578   // to 0. It will perform a seek to 0. As the requests to the renderer
579   // process are sequential, the OnSeekComplete() will only occur
580   // once OnPlaybackComplete() is done. As the playback can only be executed
581   // upon completion of OnSeekComplete(), the request needs to be saved.
582   is_playing_ = false;
583   if (seeking_ && seek_time_ == base::TimeDelta())
584     pending_playback_ = true;
585 }
586
587 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
588   buffered_[0].end = duration() * percentage / 100;
589   did_loading_progress_ = true;
590 }
591
592 void WebMediaPlayerAndroid::OnSeekRequest(const base::TimeDelta& time_to_seek) {
593   DCHECK(main_loop_->BelongsToCurrentThread());
594   client_->requestSeek(time_to_seek.InSecondsF());
595 }
596
597 void WebMediaPlayerAndroid::OnSeekComplete(
598     const base::TimeDelta& current_time) {
599   DCHECK(main_loop_->BelongsToCurrentThread());
600   seeking_ = false;
601   if (pending_seek_) {
602     pending_seek_ = false;
603     seek(pending_seek_time_.InSecondsF());
604     return;
605   }
606
607   OnTimeUpdate(current_time);
608
609   UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
610
611   client_->timeChanged();
612
613   if (pending_playback_) {
614     play();
615     pending_playback_ = false;
616   }
617 }
618
619 void WebMediaPlayerAndroid::OnMediaError(int error_type) {
620   switch (error_type) {
621     case MediaPlayerAndroid::MEDIA_ERROR_FORMAT:
622       UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
623       break;
624     case MediaPlayerAndroid::MEDIA_ERROR_DECODE:
625       UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError);
626       break;
627     case MediaPlayerAndroid::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
628       UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
629       break;
630     case MediaPlayerAndroid::MEDIA_ERROR_INVALID_CODE:
631       break;
632   }
633   client_->repaint();
634 }
635
636 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
637   has_size_info_ = true;
638   if (natural_size_.width == width && natural_size_.height == height)
639     return;
640
641 #if defined(VIDEO_HOLE)
642   // Use H/W surface for encrypted video.
643   // TODO(qinmin): Change this so that only EME needs the H/W surface
644   if (media_source_delegate_ && media_source_delegate_->IsVideoEncrypted()) {
645     needs_external_surface_ = true;
646     if (!paused() && !manager_->IsInFullscreen(frame_))
647       manager_->RequestExternalSurface(player_id_, last_computed_rect_);
648   } else if (stream_texture_factory_ && !stream_id_) {
649     // Do deferred stream texture creation finally.
650     DoCreateStreamTexture();
651     if (paused()) {
652       SetNeedsEstablishPeer(true);
653     } else {
654       EstablishSurfaceTexturePeer();
655     }
656   }
657 #else
658   // When play() gets called, |natural_size_| may still be empty and
659   // EstablishSurfaceTexturePeer() will not get called. As a result, the video
660   // may play without a surface texture. When we finally get the valid video
661   // size here, we should call EstablishSurfaceTexturePeer() if it has not been
662   // previously called.
663   if (!paused() && needs_establish_peer_)
664     EstablishSurfaceTexturePeer();
665 #endif  // defined(VIDEO_HOLE)
666
667   natural_size_.width = width;
668   natural_size_.height = height;
669   ReallocateVideoFrame();
670   CreateWebLayerIfNeeded();
671   // TODO(qinmin): This is a hack. We need the media element to stop showing the
672   // poster image by forcing it to call setDisplayMode(video). Should move the
673   // logic into HTMLMediaElement.cpp.
674   client_->timeChanged();
675 }
676
677 void WebMediaPlayerAndroid::OnTimeUpdate(const base::TimeDelta& current_time) {
678   DCHECK(main_loop_->BelongsToCurrentThread());
679   current_time_ = current_time.InSecondsF();
680 }
681
682 void WebMediaPlayerAndroid::OnConnectedToRemoteDevice() {
683   DCHECK(main_thread_checker_.CalledOnValidThread());
684   DCHECK(!media_source_delegate_);
685   DrawRemotePlaybackIcon();
686   is_remote_ = true;
687   SetNeedsEstablishPeer(false);
688 }
689
690 void WebMediaPlayerAndroid::OnDisconnectedFromRemoteDevice() {
691   DCHECK(main_thread_checker_.CalledOnValidThread());
692   DCHECK(!media_source_delegate_);
693   SetNeedsEstablishPeer(true);
694   if (!paused())
695     EstablishSurfaceTexturePeer();
696   is_remote_ = false;
697   ReallocateVideoFrame();
698 }
699
700 void WebMediaPlayerAndroid::OnDidEnterFullscreen() {
701   if (!manager_->IsInFullscreen(frame_)) {
702     frame_->view()->willEnterFullScreen();
703     frame_->view()->didEnterFullScreen();
704     manager_->DidEnterFullscreen(frame_);
705   }
706 }
707
708 void WebMediaPlayerAndroid::OnDidExitFullscreen() {
709   // |needs_external_surface_| is always false on non-TV devices.
710   if (!needs_external_surface_)
711     SetNeedsEstablishPeer(true);
712   // We had the fullscreen surface connected to Android MediaPlayer,
713   // so reconnect our surface texture for embedded playback.
714   if (!paused() && needs_establish_peer_)
715     EstablishSurfaceTexturePeer();
716
717 #if defined(VIDEO_HOLE)
718   if (!paused() && needs_external_surface_)
719     manager_->RequestExternalSurface(player_id_, last_computed_rect_);
720 #endif  // defined(VIDEO_HOLE)
721
722   frame_->view()->willExitFullScreen();
723   frame_->view()->didExitFullScreen();
724   manager_->DidExitFullscreen();
725   client_->repaint();
726 }
727
728 void WebMediaPlayerAndroid::OnMediaPlayerPlay() {
729   UpdatePlayingState(true);
730   client_->playbackStateChanged();
731 }
732
733 void WebMediaPlayerAndroid::OnMediaPlayerPause() {
734   UpdatePlayingState(false);
735   client_->playbackStateChanged();
736 }
737
738 void WebMediaPlayerAndroid::OnRequestFullscreen() {
739   client_->requestFullscreen();
740 }
741
742 void WebMediaPlayerAndroid::OnDurationChanged(const base::TimeDelta& duration) {
743   DCHECK(main_loop_->BelongsToCurrentThread());
744   // Only MSE |player_type_| registers this callback.
745   DCHECK_EQ(player_type_, MEDIA_PLAYER_TYPE_MEDIA_SOURCE);
746
747   // Cache the new duration value and trust it over any subsequent duration
748   // values received in OnMediaMetadataChanged().
749   duration_ = duration;
750   ignore_metadata_duration_change_ = true;
751
752   // Notify MediaPlayerClient that duration has changed, if > HAVE_NOTHING.
753   if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing)
754     client_->durationChanged();
755 }
756
757 void WebMediaPlayerAndroid::UpdateNetworkState(
758     WebMediaPlayer::NetworkState state) {
759   DCHECK(main_loop_->BelongsToCurrentThread());
760   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing &&
761       (state == WebMediaPlayer::NetworkStateNetworkError ||
762        state == WebMediaPlayer::NetworkStateDecodeError)) {
763     // Any error that occurs before reaching ReadyStateHaveMetadata should
764     // be considered a format error.
765     network_state_ = WebMediaPlayer::NetworkStateFormatError;
766   } else {
767     network_state_ = state;
768   }
769   client_->networkStateChanged();
770 }
771
772 void WebMediaPlayerAndroid::UpdateReadyState(
773     WebMediaPlayer::ReadyState state) {
774   ready_state_ = state;
775   client_->readyStateChanged();
776 }
777
778 void WebMediaPlayerAndroid::OnPlayerReleased() {
779   // |needs_external_surface_| is always false on non-TV devices.
780   if (!needs_external_surface_)
781     needs_establish_peer_ = true;
782
783   if (is_playing_)
784     OnMediaPlayerPause();
785
786 #if defined(VIDEO_HOLE)
787   last_computed_rect_ = gfx::RectF();
788 #endif  // defined(VIDEO_HOLE)
789 }
790
791 void WebMediaPlayerAndroid::ReleaseMediaResources() {
792   switch (network_state_) {
793     // Pause the media player and inform WebKit if the player is in a good
794     // shape.
795     case WebMediaPlayer::NetworkStateIdle:
796     case WebMediaPlayer::NetworkStateLoading:
797     case WebMediaPlayer::NetworkStateLoaded:
798       Pause(false);
799       client_->playbackStateChanged();
800       break;
801     // If a WebMediaPlayer instance has entered into one of these states,
802     // the internal network state in HTMLMediaElement could be set to empty.
803     // And calling playbackStateChanged() could get this object deleted.
804     case WebMediaPlayer::NetworkStateEmpty:
805     case WebMediaPlayer::NetworkStateFormatError:
806     case WebMediaPlayer::NetworkStateNetworkError:
807     case WebMediaPlayer::NetworkStateDecodeError:
808       break;
809   }
810   manager_->ReleaseResources(player_id_);
811   OnPlayerReleased();
812 }
813
814 void WebMediaPlayerAndroid::OnDestruct() {
815   if (manager_)
816     manager_->UnregisterMediaPlayer(player_id_);
817   Detach();
818 }
819
820 void WebMediaPlayerAndroid::Detach() {
821   if (stream_id_) {
822     stream_texture_factory_->DestroyStreamTexture(texture_id_);
823     stream_id_ = 0;
824   }
825
826   media_source_delegate_.reset();
827   {
828     base::AutoLock auto_lock(current_frame_lock_);
829     current_frame_ = NULL;
830   }
831   is_remote_ = false;
832   manager_ = NULL;
833 }
834
835 void WebMediaPlayerAndroid::Pause(bool is_media_related_action) {
836   manager_->Pause(player_id_, is_media_related_action);
837   UpdatePlayingState(false);
838 }
839
840 void WebMediaPlayerAndroid::DrawRemotePlaybackIcon() {
841   DCHECK(main_thread_checker_.CalledOnValidThread());
842   if (!video_weblayer_)
843     return;
844
845   // TODO(johnme): Should redraw this frame if the layer bounds change; but
846   // there seems no easy way to listen for the layer resizing (as opposed to
847   // OnVideoSizeChanged, which is when the frame sizes of the video file
848   // change). Perhaps have to poll (on main thread of course)?
849   gfx::Size video_size_css_px = video_weblayer_->bounds();
850   float device_scale_factor = frame_->view()->deviceScaleFactor();
851   // canvas_size will be the size in device pixels when pageScaleFactor == 1
852   gfx::Size canvas_size(
853       static_cast<int>(video_size_css_px.width() * device_scale_factor),
854       static_cast<int>(video_size_css_px.height() * device_scale_factor));
855
856   SkBitmap bitmap;
857   bitmap.setConfig(
858       SkBitmap::kARGB_8888_Config, canvas_size.width(), canvas_size.height());
859   bitmap.allocPixels();
860
861   SkCanvas canvas(bitmap);
862   canvas.drawColor(SK_ColorBLACK);
863   SkPaint paint;
864   paint.setAntiAlias(true);
865   paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
866   const SkBitmap* icon_bitmap =
867       GetContentClient()
868           ->GetNativeImageNamed(IDR_MEDIAPLAYER_REMOTE_PLAYBACK_ICON)
869           .ToSkBitmap();
870   // In order to get a reasonable margin around the icon:
871   // - the icon should be under half the frame width
872   // - the icon should be at most 3/5 of the frame height
873   // Additionally, on very large screens, the icon size should be capped. A max
874   // width of 320 was arbitrarily chosen; since this is half the resource's
875   // pixel width, it should look crisp even on 2x deviceScaleFactor displays.
876   int icon_width = 320;
877   icon_width = std::min(icon_width, canvas_size.width() / 2);
878   icon_width = std::min(icon_width,
879                         canvas_size.height() * icon_bitmap->width() /
880                             icon_bitmap->height() * 3 / 5);
881   int icon_height = icon_width * icon_bitmap->height() / icon_bitmap->width();
882   // Center the icon within the frame
883   SkRect icon_rect = SkRect::MakeXYWH((canvas_size.width() - icon_width) / 2,
884                                       (canvas_size.height() - icon_height) / 2,
885                                       icon_width,
886                                       icon_height);
887   canvas.drawBitmapRectToRect(
888       *icon_bitmap, NULL /* src */, icon_rect /* dest */, &paint);
889
890   GLES2Interface* gl = stream_texture_factory_->ContextGL();
891
892   if (!remote_playback_texture_id_)
893     gl->GenTextures(1, &remote_playback_texture_id_);
894   GLuint texture_target = GL_TEXTURE_2D;
895   gl->BindTexture(texture_target, remote_playback_texture_id_);
896   gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
897   gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
898   gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
899   gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
900
901   {
902     SkAutoLockPixels lock(bitmap);
903     gl->TexImage2D(texture_target,
904                    0 /* level */,
905                    GL_RGBA /* internalformat */,
906                    bitmap.width(),
907                    bitmap.height(),
908                    0 /* border */,
909                    GL_RGBA /* format */,
910                    GL_UNSIGNED_BYTE /* type */,
911                    bitmap.getPixels());
912   }
913
914   gpu::Mailbox texture_mailbox;
915   gl->GenMailboxCHROMIUM(texture_mailbox.name);
916   gl->ProduceTextureCHROMIUM(texture_target, texture_mailbox.name);
917   gl->Flush();
918   GLuint texture_mailbox_sync_point = gl->InsertSyncPointCHROMIUM();
919
920   scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
921       make_scoped_ptr(new gpu::MailboxHolder(
922           texture_mailbox, texture_target, texture_mailbox_sync_point)),
923       base::Bind(&WebMediaPlayerAndroid::OnReleaseRemotePlaybackTexture,
924                  main_loop_,
925                  weak_factory_.GetWeakPtr()),
926       canvas_size /* coded_size */,
927       gfx::Rect(canvas_size) /* visible_rect */,
928       canvas_size /* natural_size */,
929       base::TimeDelta() /* timestamp */,
930       VideoFrame::ReadPixelsCB());
931   SetCurrentFrameInternal(new_frame);
932 }
933
934 void WebMediaPlayerAndroid::ReallocateVideoFrame() {
935   if (needs_external_surface_) {
936     // VideoFrame::CreateHoleFrame is only defined under VIDEO_HOLE.
937 #if defined(VIDEO_HOLE)
938     if (!natural_size_.isEmpty()) {
939       scoped_refptr<VideoFrame> new_frame =
940           VideoFrame::CreateHoleFrame(natural_size_);
941       SetCurrentFrameInternal(new_frame);
942       // Force the client to grab the hole frame.
943       client_->repaint();
944     }
945 #else
946     NOTIMPLEMENTED() << "Hole punching not supported without VIDEO_HOLE flag";
947 #endif  // defined(VIDEO_HOLE)
948   } else if (!is_remote_ && texture_id_) {
949     scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
950         make_scoped_ptr(new gpu::MailboxHolder(texture_mailbox_,
951                                                kGLTextureExternalOES,
952                                                texture_mailbox_sync_point_)),
953         media::VideoFrame::ReleaseMailboxCB(),
954         natural_size_,
955         gfx::Rect(natural_size_),
956         natural_size_,
957         base::TimeDelta(),
958         VideoFrame::ReadPixelsCB());
959     SetCurrentFrameInternal(new_frame);
960   }
961 }
962
963 void WebMediaPlayerAndroid::CreateWebLayerIfNeeded() {
964   if (!hasVideo() || video_weblayer_ || !client_->needsWebLayerForVideo())
965     return;
966   video_weblayer_.reset(new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
967   client_->setWebLayer(video_weblayer_.get());
968 }
969
970 void WebMediaPlayerAndroid::SetVideoFrameProviderClient(
971     cc::VideoFrameProvider::Client* client) {
972   // This is called from both the main renderer thread and the compositor
973   // thread (when the main thread is blocked).
974   if (video_frame_provider_client_)
975     video_frame_provider_client_->StopUsingProvider();
976   video_frame_provider_client_ = client;
977
978   // Set the callback target when a frame is produced.
979   if (stream_texture_proxy_)
980     stream_texture_proxy_->SetClient(client);
981 }
982
983 void WebMediaPlayerAndroid::SetCurrentFrameInternal(
984     scoped_refptr<media::VideoFrame>& video_frame) {
985   base::AutoLock auto_lock(current_frame_lock_);
986   current_frame_ = video_frame;
987 }
988
989 scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
990   scoped_refptr<VideoFrame> video_frame;
991   {
992     base::AutoLock auto_lock(current_frame_lock_);
993     video_frame = current_frame_;
994   }
995
996   if (!stream_texture_proxy_initialized_ && stream_texture_proxy_ &&
997       stream_id_ && !needs_external_surface_ && !is_remote_) {
998     gfx::Size natural_size = video_frame->natural_size();
999     // TODO(sievers): These variables are accessed on the wrong thread here.
1000     stream_texture_proxy_->BindToCurrentThread(stream_id_);
1001     stream_texture_factory_->SetStreamTextureSize(stream_id_, natural_size);
1002     stream_texture_proxy_initialized_ = true;
1003     cached_stream_texture_size_ = natural_size;
1004   }
1005
1006   return video_frame;
1007 }
1008
1009 void WebMediaPlayerAndroid::PutCurrentFrame(
1010     const scoped_refptr<media::VideoFrame>& frame) {
1011 }
1012
1013 void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
1014   // Already created.
1015   if (stream_texture_proxy_)
1016     return;
1017
1018   // No factory to create proxy.
1019   if (!stream_texture_factory_)
1020     return;
1021
1022   stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
1023   if (needs_establish_peer_ && stream_texture_proxy_) {
1024     DoCreateStreamTexture();
1025     ReallocateVideoFrame();
1026   }
1027
1028   if (stream_texture_proxy_ && video_frame_provider_client_)
1029     stream_texture_proxy_->SetClient(video_frame_provider_client_);
1030 }
1031
1032 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
1033   if (!stream_texture_proxy_)
1034     return;
1035
1036   if (stream_texture_factory_.get() && stream_id_)
1037     stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
1038   needs_establish_peer_ = false;
1039 }
1040
1041 void WebMediaPlayerAndroid::DoCreateStreamTexture() {
1042   DCHECK(!stream_id_);
1043   DCHECK(!texture_id_);
1044   DCHECK(!texture_mailbox_sync_point_);
1045   stream_id_ = stream_texture_factory_->CreateStreamTexture(
1046       kGLTextureExternalOES,
1047       &texture_id_,
1048       &texture_mailbox_,
1049       &texture_mailbox_sync_point_);
1050 }
1051
1052 void WebMediaPlayerAndroid::SetNeedsEstablishPeer(bool needs_establish_peer) {
1053   needs_establish_peer_ = needs_establish_peer;
1054 }
1055
1056 void WebMediaPlayerAndroid::setPoster(const blink::WebURL& poster) {
1057   manager_->SetPoster(player_id_, poster);
1058 }
1059
1060 void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) {
1061   is_playing_ = is_playing;
1062   if (!delegate_)
1063     return;
1064   if (is_playing)
1065     delegate_->DidPlay(this);
1066   else
1067     delegate_->DidPause(this);
1068 }
1069
1070 #if defined(VIDEO_HOLE)
1071 bool WebMediaPlayerAndroid::UpdateBoundaryRectangle() {
1072   if (!video_weblayer_)
1073     return false;
1074
1075   // Compute the geometry of video frame layer.
1076   cc::Layer* layer = video_weblayer_->layer();
1077   gfx::RectF rect(layer->bounds());
1078   while (layer) {
1079     rect.Offset(layer->position().OffsetFromOrigin());
1080     layer = layer->parent();
1081   }
1082
1083   // Return false when the geometry hasn't been changed from the last time.
1084   if (last_computed_rect_ == rect)
1085     return false;
1086
1087   // Store the changed geometry information when it is actually changed.
1088   last_computed_rect_ = rect;
1089   return true;
1090 }
1091
1092 const gfx::RectF WebMediaPlayerAndroid::GetBoundaryRectangle() {
1093   return last_computed_rect_;
1094 }
1095 #endif
1096
1097 // The following EME related code is copied from WebMediaPlayerImpl.
1098 // TODO(xhwang): Remove duplicate code between WebMediaPlayerAndroid and
1099 // WebMediaPlayerImpl.
1100 // TODO(kjyoun): Update Google TV EME implementation to use IPC.
1101
1102 // Helper functions to report media EME related stats to UMA. They follow the
1103 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
1104 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
1105 // that UMA_* macros require the names to be constant throughout the process'
1106 // lifetime.
1107 static void EmeUMAHistogramEnumeration(const blink::WebString& key_system,
1108                                        const std::string& method,
1109                                        int sample,
1110                                        int boundary_value) {
1111   base::LinearHistogram::FactoryGet(
1112       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
1113       1, boundary_value, boundary_value + 1,
1114       base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
1115 }
1116
1117 static void EmeUMAHistogramCounts(const blink::WebString& key_system,
1118                                   const std::string& method,
1119                                   int sample) {
1120   // Use the same parameters as UMA_HISTOGRAM_COUNTS.
1121   base::Histogram::FactoryGet(
1122       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
1123       1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
1124 }
1125
1126 // Helper enum for reporting generateKeyRequest/addKey histograms.
1127 enum MediaKeyException {
1128   kUnknownResultId,
1129   kSuccess,
1130   kKeySystemNotSupported,
1131   kInvalidPlayerState,
1132   kMaxMediaKeyException
1133 };
1134
1135 static MediaKeyException MediaKeyExceptionForUMA(
1136     WebMediaPlayer::MediaKeyException e) {
1137   switch (e) {
1138     case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
1139       return kKeySystemNotSupported;
1140     case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
1141       return kInvalidPlayerState;
1142     case WebMediaPlayer::MediaKeyExceptionNoError:
1143       return kSuccess;
1144     default:
1145       return kUnknownResultId;
1146   }
1147 }
1148
1149 // Helper for converting |key_system| name and exception |e| to a pair of enum
1150 // values from above, for reporting to UMA.
1151 static void ReportMediaKeyExceptionToUMA(
1152     const std::string& method,
1153     const WebString& key_system,
1154     WebMediaPlayer::MediaKeyException e) {
1155   MediaKeyException result_id = MediaKeyExceptionForUMA(e);
1156   DCHECK_NE(result_id, kUnknownResultId) << e;
1157   EmeUMAHistogramEnumeration(
1158       key_system, method, result_id, kMaxMediaKeyException);
1159 }
1160
1161 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::generateKeyRequest(
1162     const WebString& key_system,
1163     const unsigned char* init_data,
1164     unsigned init_data_length) {
1165   WebMediaPlayer::MediaKeyException e =
1166       GenerateKeyRequestInternal(key_system, init_data, init_data_length);
1167   ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
1168   return e;
1169 }
1170
1171 bool WebMediaPlayerAndroid::IsKeySystemSupported(const WebString& key_system) {
1172   // On Android, EME only works with MSE.
1173   return player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE &&
1174          IsConcreteSupportedKeySystem(key_system);
1175 }
1176
1177 // TODO(xhwang): Report an error when there is encrypted stream but EME is
1178 // not enabled. Currently the player just doesn't start and waits for
1179 // ever.
1180 WebMediaPlayer::MediaKeyException
1181 WebMediaPlayerAndroid::GenerateKeyRequestInternal(
1182     const WebString& key_system,
1183     const unsigned char* init_data,
1184     unsigned init_data_length) {
1185   DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
1186            << std::string(reinterpret_cast<const char*>(init_data),
1187                           static_cast<size_t>(init_data_length));
1188
1189   if (!IsKeySystemSupported(key_system))
1190     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1191
1192   // We do not support run-time switching between key systems for now.
1193   if (current_key_system_.isEmpty()) {
1194     if (!proxy_decryptor_) {
1195       proxy_decryptor_.reset(new ProxyDecryptor(
1196 #if defined(ENABLE_PEPPER_CDMS)
1197           client_,
1198           frame_,
1199 #else
1200           manager_,
1201           player_id_,  // TODO(xhwang): Use media_keys_id when MediaKeys are
1202                        // separated from WebMediaPlayer.
1203 #endif  // defined(ENABLE_PEPPER_CDMS)
1204           base::Bind(&WebMediaPlayerAndroid::OnKeyAdded,
1205                      weak_factory_.GetWeakPtr()),
1206           base::Bind(&WebMediaPlayerAndroid::OnKeyError,
1207                      weak_factory_.GetWeakPtr()),
1208           base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
1209                      weak_factory_.GetWeakPtr())));
1210     }
1211
1212     if (!proxy_decryptor_->InitializeCDM(key_system.utf8(),
1213                                          frame_->document().url())) {
1214       return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1215     }
1216
1217     if (proxy_decryptor_ && !decryptor_ready_cb_.is_null()) {
1218       base::ResetAndReturn(&decryptor_ready_cb_)
1219           .Run(proxy_decryptor_->GetDecryptor());
1220     }
1221
1222     current_key_system_ = key_system;
1223   } else if (key_system != current_key_system_) {
1224     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
1225   }
1226
1227   // TODO(xhwang): We assume all streams are from the same container (thus have
1228   // the same "type") for now. In the future, the "type" should be passed down
1229   // from the application.
1230   if (!proxy_decryptor_->GenerateKeyRequest(
1231            init_data_type_, init_data, init_data_length)) {
1232     current_key_system_.reset();
1233     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1234   }
1235
1236   return WebMediaPlayer::MediaKeyExceptionNoError;
1237 }
1238
1239 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::addKey(
1240     const WebString& key_system,
1241     const unsigned char* key,
1242     unsigned key_length,
1243     const unsigned char* init_data,
1244     unsigned init_data_length,
1245     const WebString& session_id) {
1246   WebMediaPlayer::MediaKeyException e = AddKeyInternal(
1247       key_system, key, key_length, init_data, init_data_length, session_id);
1248   ReportMediaKeyExceptionToUMA("addKey", key_system, e);
1249   return e;
1250 }
1251
1252 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::AddKeyInternal(
1253     const WebString& key_system,
1254     const unsigned char* key,
1255     unsigned key_length,
1256     const unsigned char* init_data,
1257     unsigned init_data_length,
1258     const WebString& session_id) {
1259   DCHECK(key);
1260   DCHECK_GT(key_length, 0u);
1261   DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
1262            << std::string(reinterpret_cast<const char*>(key),
1263                           static_cast<size_t>(key_length)) << ", "
1264            << std::string(reinterpret_cast<const char*>(init_data),
1265                           static_cast<size_t>(init_data_length))
1266            << " [" << session_id.utf8().data() << "]";
1267
1268   if (!IsKeySystemSupported(key_system))
1269     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1270
1271   if (current_key_system_.isEmpty() || key_system != current_key_system_)
1272     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
1273
1274   proxy_decryptor_->AddKey(
1275       key, key_length, init_data, init_data_length, session_id.utf8());
1276   return WebMediaPlayer::MediaKeyExceptionNoError;
1277 }
1278
1279 WebMediaPlayer::MediaKeyException WebMediaPlayerAndroid::cancelKeyRequest(
1280     const WebString& key_system,
1281     const WebString& session_id) {
1282   WebMediaPlayer::MediaKeyException e =
1283       CancelKeyRequestInternal(key_system, session_id);
1284   ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
1285   return e;
1286 }
1287
1288 WebMediaPlayer::MediaKeyException
1289 WebMediaPlayerAndroid::CancelKeyRequestInternal(
1290     const WebString& key_system,
1291     const WebString& session_id) {
1292   if (!IsKeySystemSupported(key_system))
1293     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
1294
1295   if (current_key_system_.isEmpty() || key_system != current_key_system_)
1296     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
1297
1298   proxy_decryptor_->CancelKeyRequest(session_id.utf8());
1299   return WebMediaPlayer::MediaKeyExceptionNoError;
1300 }
1301
1302 void WebMediaPlayerAndroid::OnKeyAdded(const std::string& session_id) {
1303   EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
1304
1305   client_->keyAdded(current_key_system_, WebString::fromUTF8(session_id));
1306 }
1307
1308 void WebMediaPlayerAndroid::OnKeyError(const std::string& session_id,
1309                                        media::MediaKeys::KeyError error_code,
1310                                        int system_code) {
1311   EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
1312                              error_code, media::MediaKeys::kMaxKeyError);
1313
1314   client_->keyError(
1315       current_key_system_,
1316       WebString::fromUTF8(session_id),
1317       static_cast<blink::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
1318       system_code);
1319 }
1320
1321 void WebMediaPlayerAndroid::OnKeyMessage(const std::string& session_id,
1322                                          const std::vector<uint8>& message,
1323                                          const std::string& destination_url) {
1324   const GURL destination_url_gurl(destination_url);
1325   DLOG_IF(WARNING, !destination_url.empty() && !destination_url_gurl.is_valid())
1326       << "Invalid URL in destination_url: " << destination_url;
1327
1328   client_->keyMessage(current_key_system_,
1329                       WebString::fromUTF8(session_id),
1330                       message.empty() ? NULL : &message[0],
1331                       message.size(),
1332                       destination_url_gurl);
1333 }
1334
1335 void WebMediaPlayerAndroid::OnMediaSourceOpened(
1336     blink::WebMediaSource* web_media_source) {
1337   client_->mediaSourceOpened(web_media_source);
1338 }
1339
1340 void WebMediaPlayerAndroid::OnNeedKey(const std::string& type,
1341                                       const std::vector<uint8>& init_data) {
1342   DCHECK(main_loop_->BelongsToCurrentThread());
1343
1344   // Do not fire NeedKey event if encrypted media is not enabled.
1345   if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() &&
1346       !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
1347     return;
1348   }
1349
1350   UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
1351
1352   DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
1353   if (init_data_type_.empty())
1354     init_data_type_ = type;
1355
1356   const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
1357   client_->keyNeeded(
1358       WebString::fromUTF8(type), init_data_ptr, init_data.size());
1359 }
1360
1361 void WebMediaPlayerAndroid::SetDecryptorReadyCB(
1362     const media::DecryptorReadyCB& decryptor_ready_cb) {
1363   DCHECK(main_loop_->BelongsToCurrentThread());
1364
1365   // Cancels the previous decryptor request.
1366   if (decryptor_ready_cb.is_null()) {
1367     if (!decryptor_ready_cb_.is_null())
1368       base::ResetAndReturn(&decryptor_ready_cb_).Run(NULL);
1369     return;
1370   }
1371
1372   // TODO(xhwang): Support multiple decryptor notification request (e.g. from
1373   // video and audio). The current implementation is okay for the current
1374   // media pipeline since we initialize audio and video decoders in sequence.
1375   // But WebMediaPlayerImpl should not depend on media pipeline's implementation
1376   // detail.
1377   DCHECK(decryptor_ready_cb_.is_null());
1378
1379   if (proxy_decryptor_) {
1380     decryptor_ready_cb.Run(proxy_decryptor_->GetDecryptor());
1381     return;
1382   }
1383
1384   // TODO(xhwang): Also notify |web_cdm_| when we implement
1385   // setContentDecryptionModule(). See: http://crbug.com/224786
1386
1387   decryptor_ready_cb_ = decryptor_ready_cb;
1388 }
1389
1390 void WebMediaPlayerAndroid::DoReleaseRemotePlaybackTexture(uint32 sync_point) {
1391   DCHECK(main_thread_checker_.CalledOnValidThread());
1392   DCHECK(remote_playback_texture_id_);
1393
1394   GLES2Interface* gl = stream_texture_factory_->ContextGL();
1395
1396   if (sync_point)
1397     gl->WaitSyncPointCHROMIUM(sync_point);
1398   gl->DeleteTextures(1, &remote_playback_texture_id_);
1399   remote_playback_texture_id_ = 0;
1400 }
1401
1402 void WebMediaPlayerAndroid::enterFullscreen() {
1403   if (manager_->CanEnterFullscreen(frame_)) {
1404     manager_->EnterFullscreen(player_id_, frame_);
1405     SetNeedsEstablishPeer(false);
1406   }
1407 }
1408
1409 void WebMediaPlayerAndroid::exitFullscreen() {
1410   manager_->ExitFullscreen(player_id_);
1411 }
1412
1413 bool WebMediaPlayerAndroid::canEnterFullscreen() const {
1414   return manager_->CanEnterFullscreen(frame_);
1415 }
1416
1417 }  // namespace content