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