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