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