Home | History | Annotate | Download | only in media
      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/webmediaplayer_impl.h"
      6 
      7 #include <algorithm>
      8 #include <limits>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/bind.h"
     13 #include "base/callback.h"
     14 #include "base/command_line.h"
     15 #include "base/debug/crash_logging.h"
     16 #include "base/message_loop/message_loop_proxy.h"
     17 #include "base/metrics/histogram.h"
     18 #include "base/strings/string_number_conversions.h"
     19 #include "base/synchronization/waitable_event.h"
     20 #include "cc/layers/video_layer.h"
     21 #include "content/public/common/content_switches.h"
     22 #include "content/renderer/media/buffered_data_source.h"
     23 #include "content/renderer/media/crypto/key_systems.h"
     24 #include "content/renderer/media/texttrack_impl.h"
     25 #include "content/renderer/media/webaudiosourceprovider_impl.h"
     26 #include "content/renderer/media/webinbandtexttrack_impl.h"
     27 #include "content/renderer/media/webmediaplayer_delegate.h"
     28 #include "content/renderer/media/webmediaplayer_params.h"
     29 #include "content/renderer/media/webmediaplayer_util.h"
     30 #include "content/renderer/media/webmediasourceclient_impl.h"
     31 #include "content/renderer/pepper/pepper_webplugin_impl.h"
     32 #include "gpu/GLES2/gl2extchromium.h"
     33 #include "media/audio/null_audio_sink.h"
     34 #include "media/base/bind_to_loop.h"
     35 #include "media/base/filter_collection.h"
     36 #include "media/base/limits.h"
     37 #include "media/base/media_log.h"
     38 #include "media/base/media_switches.h"
     39 #include "media/base/pipeline.h"
     40 #include "media/base/video_frame.h"
     41 #include "media/filters/audio_renderer_impl.h"
     42 #include "media/filters/chunk_demuxer.h"
     43 #include "media/filters/ffmpeg_audio_decoder.h"
     44 #include "media/filters/ffmpeg_demuxer.h"
     45 #include "media/filters/ffmpeg_video_decoder.h"
     46 #include "media/filters/gpu_video_decoder.h"
     47 #include "media/filters/gpu_video_decoder_factories.h"
     48 #include "media/filters/opus_audio_decoder.h"
     49 #include "media/filters/video_renderer_base.h"
     50 #include "media/filters/vpx_video_decoder.h"
     51 #include "third_party/WebKit/public/platform/WebRect.h"
     52 #include "third_party/WebKit/public/platform/WebSize.h"
     53 #include "third_party/WebKit/public/platform/WebString.h"
     54 #include "third_party/WebKit/public/platform/WebURL.h"
     55 #include "third_party/WebKit/public/web/WebMediaSource.h"
     56 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
     57 #include "third_party/WebKit/public/web/WebView.h"
     58 #include "v8/include/v8.h"
     59 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
     60 
     61 using WebKit::WebCanvas;
     62 using WebKit::WebMediaPlayer;
     63 using WebKit::WebRect;
     64 using WebKit::WebSize;
     65 using WebKit::WebString;
     66 using media::PipelineStatus;
     67 
     68 namespace {
     69 
     70 // Amount of extra memory used by each player instance reported to V8.
     71 // It is not exact number -- first, it differs on different platforms,
     72 // and second, it is very hard to calculate. Instead, use some arbitrary
     73 // value that will cause garbage collection from time to time. We don't want
     74 // it to happen on every allocation, but don't want 5k players to sit in memory
     75 // either. Looks that chosen constant achieves both goals, at least for audio
     76 // objects. (Do not worry about video objects yet, JS programs do not create
     77 // thousands of them...)
     78 const int kPlayerExtraMemory = 1024 * 1024;
     79 
     80 // Limits the range of playback rate.
     81 //
     82 // TODO(kylep): Revisit these.
     83 //
     84 // Vista has substantially lower performance than XP or Windows7.  If you speed
     85 // up a video too much, it can't keep up, and rendering stops updating except on
     86 // the time bar. For really high speeds, audio becomes a bottleneck and we just
     87 // use up the data we have, which may not achieve the speed requested, but will
     88 // not crash the tab.
     89 //
     90 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
     91 // like a busy loop). It gets unresponsive, although its not completely dead.
     92 //
     93 // Also our timers are not very accurate (especially for ogg), which becomes
     94 // evident at low speeds and on Vista. Since other speeds are risky and outside
     95 // the norms, we think 1/16x to 16x is a safe and useful range for now.
     96 const double kMinRate = 0.0625;
     97 const double kMaxRate = 16.0;
     98 
     99 // Prefix for histograms related to Encrypted Media Extensions.
    100 const char* kMediaEme = "Media.EME.";
    101 
    102 }  // namespace
    103 
    104 namespace content {
    105 
    106 #define COMPILE_ASSERT_MATCHING_ENUM(name) \
    107   COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \
    108                  static_cast<int>(BufferedResourceLoader::k ## name), \
    109                  mismatching_enums)
    110 COMPILE_ASSERT_MATCHING_ENUM(Unspecified);
    111 COMPILE_ASSERT_MATCHING_ENUM(Anonymous);
    112 COMPILE_ASSERT_MATCHING_ENUM(UseCredentials);
    113 #undef COMPILE_ASSERT_MATCHING_ENUM
    114 
    115 #define BIND_TO_RENDER_LOOP(function) \
    116   media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr()))
    117 
    118 #define BIND_TO_RENDER_LOOP_1(function, arg1) \
    119   media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1))
    120 
    121 #define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
    122   media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1, arg2))
    123 
    124 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
    125                                 const std::string& error) {
    126   media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
    127 }
    128 
    129 WebMediaPlayerImpl::WebMediaPlayerImpl(
    130     WebKit::WebFrame* frame,
    131     WebKit::WebMediaPlayerClient* client,
    132     base::WeakPtr<WebMediaPlayerDelegate> delegate,
    133     const WebMediaPlayerParams& params)
    134     : frame_(frame),
    135       network_state_(WebMediaPlayer::NetworkStateEmpty),
    136       ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
    137       main_loop_(base::MessageLoopProxy::current()),
    138       media_loop_(params.message_loop_proxy()),
    139       paused_(true),
    140       seeking_(false),
    141       playback_rate_(0.0f),
    142       pending_seek_(false),
    143       pending_seek_seconds_(0.0f),
    144       client_(client),
    145       delegate_(delegate),
    146       defer_load_cb_(params.defer_load_cb()),
    147       media_log_(params.media_log()),
    148       accelerated_compositing_reported_(false),
    149       incremented_externally_allocated_memory_(false),
    150       gpu_factories_(params.gpu_factories()),
    151       is_local_source_(false),
    152       supports_save_(true),
    153       starting_(false),
    154       chunk_demuxer_(NULL),
    155       pending_repaint_(false),
    156       pending_size_change_(false),
    157       video_frame_provider_client_(NULL),
    158       text_track_index_(0) {
    159   media_log_->AddEvent(
    160       media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
    161 
    162   pipeline_.reset(new media::Pipeline(media_loop_, media_log_.get()));
    163 
    164   // Let V8 know we started new thread if we did not do it yet.
    165   // Made separate task to avoid deletion of player currently being created.
    166   // Also, delaying GC until after player starts gets rid of starting lag --
    167   // collection happens in parallel with playing.
    168   //
    169   // TODO(enal): remove when we get rid of per-audio-stream thread.
    170   main_loop_->PostTask(
    171       FROM_HERE,
    172       base::Bind(&WebMediaPlayerImpl::IncrementExternallyAllocatedMemory,
    173                  AsWeakPtr()));
    174 
    175   // Also we want to be notified of |main_loop_| destruction.
    176   base::MessageLoop::current()->AddDestructionObserver(this);
    177 
    178   if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
    179     decryptor_.reset(new ProxyDecryptor(
    180 #if defined(ENABLE_PEPPER_CDMS)
    181         client,
    182         frame,
    183 #endif
    184         BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyAdded),
    185         BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyError),
    186         BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyMessage)));
    187   }
    188 
    189   // Use the null sink if no sink was provided.
    190   audio_source_provider_ = new WebAudioSourceProviderImpl(
    191       params.audio_renderer_sink().get()
    192           ? params.audio_renderer_sink()
    193           : new media::NullAudioSink(media_loop_));
    194 }
    195 
    196 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
    197   SetVideoFrameProviderClient(NULL);
    198   GetClient()->setWebLayer(NULL);
    199 
    200   DCHECK(main_loop_->BelongsToCurrentThread());
    201   media_log_->AddEvent(
    202       media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
    203 
    204   if (delegate_.get())
    205     delegate_->PlayerGone(this);
    206 
    207   Destroy();
    208 
    209   // Remove destruction observer if we're being destroyed but the main thread is
    210   // still running.
    211   if (base::MessageLoop::current())
    212     base::MessageLoop::current()->RemoveDestructionObserver(this);
    213 }
    214 
    215 namespace {
    216 
    217 // Helper enum for reporting scheme histograms.
    218 enum URLSchemeForHistogram {
    219   kUnknownURLScheme,
    220   kMissingURLScheme,
    221   kHttpURLScheme,
    222   kHttpsURLScheme,
    223   kFtpURLScheme,
    224   kChromeExtensionURLScheme,
    225   kJavascriptURLScheme,
    226   kFileURLScheme,
    227   kBlobURLScheme,
    228   kDataURLScheme,
    229   kFileSystemScheme,
    230   kMaxURLScheme = kFileSystemScheme  // Must be equal to highest enum value.
    231 };
    232 
    233 URLSchemeForHistogram URLScheme(const GURL& url) {
    234   if (!url.has_scheme()) return kMissingURLScheme;
    235   if (url.SchemeIs("http")) return kHttpURLScheme;
    236   if (url.SchemeIs("https")) return kHttpsURLScheme;
    237   if (url.SchemeIs("ftp")) return kFtpURLScheme;
    238   if (url.SchemeIs("chrome-extension")) return kChromeExtensionURLScheme;
    239   if (url.SchemeIs("javascript")) return kJavascriptURLScheme;
    240   if (url.SchemeIs("file")) return kFileURLScheme;
    241   if (url.SchemeIs("blob")) return kBlobURLScheme;
    242   if (url.SchemeIs("data")) return kDataURLScheme;
    243   if (url.SchemeIs("filesystem")) return kFileSystemScheme;
    244   return kUnknownURLScheme;
    245 }
    246 
    247 }  // anonymous namespace
    248 
    249 void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) {
    250   load(url, NULL, cors_mode);
    251 }
    252 
    253 void WebMediaPlayerImpl::load(const WebKit::WebURL& url,
    254                               WebKit::WebMediaSource* media_source,
    255                               CORSMode cors_mode) {
    256   if (!defer_load_cb_.is_null()) {
    257     defer_load_cb_.Run(base::Bind(
    258         &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), url, media_source,
    259         cors_mode));
    260     return;
    261   }
    262   DoLoad(url, media_source, cors_mode);
    263 }
    264 
    265 void WebMediaPlayerImpl::DoLoad(const WebKit::WebURL& url,
    266                                 WebKit::WebMediaSource* media_source,
    267                                 CORSMode cors_mode) {
    268   DCHECK(main_loop_->BelongsToCurrentThread());
    269 
    270   GURL gurl(url);
    271   UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(gurl), kMaxURLScheme);
    272 
    273   // Set subresource URL for crash reporting.
    274   base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
    275 
    276   // Handle any volume/preload changes that occurred before load().
    277   setVolume(GetClient()->volume());
    278   setPreload(GetClient()->preload());
    279 
    280   SetNetworkState(WebMediaPlayer::NetworkStateLoading);
    281   SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
    282   media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
    283 
    284   // Media source pipelines can start immediately.
    285   if (media_source) {
    286     supports_save_ = false;
    287     StartPipeline(media_source);
    288     return;
    289   }
    290 
    291   // Otherwise it's a regular request which requires resolving the URL first.
    292   data_source_.reset(new BufferedDataSource(
    293       main_loop_,
    294       frame_,
    295       media_log_.get(),
    296       base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
    297   data_source_->Initialize(
    298       url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
    299       base::Bind(
    300           &WebMediaPlayerImpl::DataSourceInitialized,
    301           AsWeakPtr(), gurl));
    302 
    303   is_local_source_ = !gurl.SchemeIs("http") && !gurl.SchemeIs("https");
    304 }
    305 
    306 void WebMediaPlayerImpl::play() {
    307   DCHECK(main_loop_->BelongsToCurrentThread());
    308 
    309   paused_ = false;
    310   pipeline_->SetPlaybackRate(playback_rate_);
    311 
    312   media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
    313 
    314   if (delegate_.get())
    315     delegate_->DidPlay(this);
    316 }
    317 
    318 void WebMediaPlayerImpl::pause() {
    319   DCHECK(main_loop_->BelongsToCurrentThread());
    320 
    321   paused_ = true;
    322   pipeline_->SetPlaybackRate(0.0f);
    323   paused_time_ = pipeline_->GetMediaTime();
    324 
    325   media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
    326 
    327   if (delegate_.get())
    328     delegate_->DidPause(this);
    329 }
    330 
    331 bool WebMediaPlayerImpl::supportsFullscreen() const {
    332   DCHECK(main_loop_->BelongsToCurrentThread());
    333   return true;
    334 }
    335 
    336 bool WebMediaPlayerImpl::supportsSave() const {
    337   DCHECK(main_loop_->BelongsToCurrentThread());
    338   return supports_save_;
    339 }
    340 
    341 void WebMediaPlayerImpl::seek(double seconds) {
    342   DCHECK(main_loop_->BelongsToCurrentThread());
    343 
    344   base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
    345 
    346   if (starting_ || seeking_) {
    347     pending_seek_ = true;
    348     pending_seek_seconds_ = seconds;
    349     if (chunk_demuxer_)
    350       chunk_demuxer_->CancelPendingSeek(seek_time);
    351     return;
    352   }
    353 
    354   media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
    355 
    356   // Update our paused time.
    357   if (paused_)
    358     paused_time_ = seek_time;
    359 
    360   seeking_ = true;
    361 
    362   if (chunk_demuxer_)
    363     chunk_demuxer_->StartWaitingForSeek(seek_time);
    364 
    365   // Kick off the asynchronous seek!
    366   pipeline_->Seek(
    367       seek_time,
    368       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek));
    369 }
    370 
    371 void WebMediaPlayerImpl::setRate(double rate) {
    372   DCHECK(main_loop_->BelongsToCurrentThread());
    373 
    374   // TODO(kylep): Remove when support for negatives is added. Also, modify the
    375   // following checks so rewind uses reasonable values also.
    376   if (rate < 0.0)
    377     return;
    378 
    379   // Limit rates to reasonable values by clamping.
    380   if (rate != 0.0) {
    381     if (rate < kMinRate)
    382       rate = kMinRate;
    383     else if (rate > kMaxRate)
    384       rate = kMaxRate;
    385   }
    386 
    387   playback_rate_ = rate;
    388   if (!paused_) {
    389     pipeline_->SetPlaybackRate(rate);
    390   }
    391 }
    392 
    393 void WebMediaPlayerImpl::setVolume(double volume) {
    394   DCHECK(main_loop_->BelongsToCurrentThread());
    395 
    396   pipeline_->SetVolume(volume);
    397 }
    398 
    399 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
    400     COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::webkit_name) == \
    401                    static_cast<int>(content::chromium_name), \
    402                    mismatching_enums)
    403 COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
    404 COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
    405 COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
    406 #undef COMPILE_ASSERT_MATCHING_ENUM
    407 
    408 void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
    409   DCHECK(main_loop_->BelongsToCurrentThread());
    410 
    411   if (data_source_)
    412     data_source_->SetPreload(static_cast<content::Preload>(preload));
    413 }
    414 
    415 bool WebMediaPlayerImpl::hasVideo() const {
    416   DCHECK(main_loop_->BelongsToCurrentThread());
    417 
    418   return pipeline_->HasVideo();
    419 }
    420 
    421 bool WebMediaPlayerImpl::hasAudio() const {
    422   DCHECK(main_loop_->BelongsToCurrentThread());
    423 
    424   return pipeline_->HasAudio();
    425 }
    426 
    427 WebKit::WebSize WebMediaPlayerImpl::naturalSize() const {
    428   DCHECK(main_loop_->BelongsToCurrentThread());
    429 
    430   gfx::Size size;
    431   pipeline_->GetNaturalVideoSize(&size);
    432   return WebKit::WebSize(size);
    433 }
    434 
    435 bool WebMediaPlayerImpl::paused() const {
    436   DCHECK(main_loop_->BelongsToCurrentThread());
    437 
    438   return pipeline_->GetPlaybackRate() == 0.0f;
    439 }
    440 
    441 bool WebMediaPlayerImpl::seeking() const {
    442   DCHECK(main_loop_->BelongsToCurrentThread());
    443 
    444   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
    445     return false;
    446 
    447   return seeking_;
    448 }
    449 
    450 double WebMediaPlayerImpl::duration() const {
    451   DCHECK(main_loop_->BelongsToCurrentThread());
    452 
    453   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
    454     return std::numeric_limits<double>::quiet_NaN();
    455 
    456   return GetPipelineDuration();
    457 }
    458 
    459 double WebMediaPlayerImpl::currentTime() const {
    460   DCHECK(main_loop_->BelongsToCurrentThread());
    461   return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF();
    462 }
    463 
    464 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
    465   DCHECK(main_loop_->BelongsToCurrentThread());
    466   return network_state_;
    467 }
    468 
    469 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
    470   DCHECK(main_loop_->BelongsToCurrentThread());
    471   return ready_state_;
    472 }
    473 
    474 const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() {
    475   DCHECK(main_loop_->BelongsToCurrentThread());
    476   WebKit::WebTimeRanges web_ranges(
    477       ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges()));
    478   buffered_.swap(web_ranges);
    479   return buffered_;
    480 }
    481 
    482 double WebMediaPlayerImpl::maxTimeSeekable() const {
    483   DCHECK(main_loop_->BelongsToCurrentThread());
    484 
    485   // If we haven't even gotten to ReadyStateHaveMetadata yet then just
    486   // return 0 so that the seekable range is empty.
    487   if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
    488     return 0.0;
    489 
    490   // We don't support seeking in streaming media.
    491   if (data_source_ && data_source_->IsStreaming())
    492     return 0.0;
    493   return duration();
    494 }
    495 
    496 bool WebMediaPlayerImpl::didLoadingProgress() const {
    497   DCHECK(main_loop_->BelongsToCurrentThread());
    498   return pipeline_->DidLoadingProgress();
    499 }
    500 
    501 void WebMediaPlayerImpl::paint(WebCanvas* canvas,
    502                                const WebRect& rect,
    503                                unsigned char alpha) {
    504   DCHECK(main_loop_->BelongsToCurrentThread());
    505 
    506   if (!accelerated_compositing_reported_) {
    507     accelerated_compositing_reported_ = true;
    508     // Normally paint() is only called in non-accelerated rendering, but there
    509     // are exceptions such as webgl where compositing is used in the WebView but
    510     // video frames are still rendered to a canvas.
    511     UMA_HISTOGRAM_BOOLEAN(
    512         "Media.AcceleratedCompositingActive",
    513         frame_->view()->isAcceleratedCompositingActive());
    514   }
    515 
    516   // Avoid locking and potentially blocking the video rendering thread while
    517   // painting in software.
    518   scoped_refptr<media::VideoFrame> video_frame;
    519   {
    520     base::AutoLock auto_lock(lock_);
    521     video_frame = current_frame_;
    522   }
    523   gfx::Rect gfx_rect(rect);
    524   skcanvas_video_renderer_.Paint(video_frame.get(), canvas, gfx_rect, alpha);
    525 }
    526 
    527 bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
    528   if (data_source_)
    529     return data_source_->HasSingleOrigin();
    530   return true;
    531 }
    532 
    533 bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
    534   if (data_source_)
    535     return data_source_->DidPassCORSAccessCheck();
    536   return false;
    537 }
    538 
    539 double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
    540   return ConvertSecondsToTimestamp(timeValue).InSecondsF();
    541 }
    542 
    543 unsigned WebMediaPlayerImpl::decodedFrameCount() const {
    544   DCHECK(main_loop_->BelongsToCurrentThread());
    545 
    546   media::PipelineStatistics stats = pipeline_->GetStatistics();
    547   return stats.video_frames_decoded;
    548 }
    549 
    550 unsigned WebMediaPlayerImpl::droppedFrameCount() const {
    551   DCHECK(main_loop_->BelongsToCurrentThread());
    552 
    553   media::PipelineStatistics stats = pipeline_->GetStatistics();
    554   return stats.video_frames_dropped;
    555 }
    556 
    557 unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
    558   DCHECK(main_loop_->BelongsToCurrentThread());
    559 
    560   media::PipelineStatistics stats = pipeline_->GetStatistics();
    561   return stats.audio_bytes_decoded;
    562 }
    563 
    564 unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
    565   DCHECK(main_loop_->BelongsToCurrentThread());
    566 
    567   media::PipelineStatistics stats = pipeline_->GetStatistics();
    568   return stats.video_bytes_decoded;
    569 }
    570 
    571 void WebMediaPlayerImpl::SetVideoFrameProviderClient(
    572     cc::VideoFrameProvider::Client* client) {
    573   // This is called from both the main renderer thread and the compositor
    574   // thread (when the main thread is blocked).
    575   if (video_frame_provider_client_)
    576     video_frame_provider_client_->StopUsingProvider();
    577   video_frame_provider_client_ = client;
    578 }
    579 
    580 scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() {
    581   base::AutoLock auto_lock(lock_);
    582   return current_frame_;
    583 }
    584 
    585 void WebMediaPlayerImpl::PutCurrentFrame(
    586     const scoped_refptr<media::VideoFrame>& frame) {
    587   if (!accelerated_compositing_reported_) {
    588     accelerated_compositing_reported_ = true;
    589     DCHECK(frame_->view()->isAcceleratedCompositingActive());
    590     UMA_HISTOGRAM_BOOLEAN("Media.AcceleratedCompositingActive", true);
    591   }
    592 }
    593 
    594 bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
    595     WebKit::WebGraphicsContext3D* web_graphics_context,
    596     unsigned int texture,
    597     unsigned int level,
    598     unsigned int internal_format,
    599     unsigned int type,
    600     bool premultiply_alpha,
    601     bool flip_y) {
    602   scoped_refptr<media::VideoFrame> video_frame;
    603   {
    604     base::AutoLock auto_lock(lock_);
    605     video_frame = current_frame_;
    606   }
    607 
    608   if (!video_frame.get())
    609     return false;
    610   if (video_frame->format() != media::VideoFrame::NATIVE_TEXTURE)
    611     return false;
    612   if (video_frame->texture_target() != GL_TEXTURE_2D)
    613     return false;
    614 
    615   scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder =
    616       video_frame->texture_mailbox();
    617 
    618   uint32 source_texture = web_graphics_context->createTexture();
    619 
    620   web_graphics_context->waitSyncPoint(mailbox_holder->sync_point());
    621   web_graphics_context->bindTexture(GL_TEXTURE_2D, source_texture);
    622   web_graphics_context->consumeTextureCHROMIUM(GL_TEXTURE_2D,
    623                                                mailbox_holder->mailbox().name);
    624 
    625   // The video is stored in a unmultiplied format, so premultiply
    626   // if necessary.
    627   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
    628                                     premultiply_alpha);
    629   // Application itself needs to take care of setting the right flip_y
    630   // value down to get the expected result.
    631   // flip_y==true means to reverse the video orientation while
    632   // flip_y==false means to keep the intrinsic orientation.
    633   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
    634   web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D,
    635                                             source_texture,
    636                                             texture,
    637                                             level,
    638                                             internal_format,
    639                                             type);
    640   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
    641   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
    642                                     false);
    643 
    644   web_graphics_context->deleteTexture(source_texture);
    645 
    646   // The flush() operation is not necessary here. It is kept since the
    647   // performance will be better when it is added than not.
    648   web_graphics_context->flush();
    649   return true;
    650 }
    651 
    652 // Helper functions to report media EME related stats to UMA. They follow the
    653 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
    654 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
    655 // that UMA_* macros require the names to be constant throughout the process'
    656 // lifetime.
    657 static void EmeUMAHistogramEnumeration(const WebKit::WebString& key_system,
    658                                        const std::string& method,
    659                                        int sample,
    660                                        int boundary_value) {
    661   base::LinearHistogram::FactoryGet(
    662       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
    663       1, boundary_value, boundary_value + 1,
    664       base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
    665 }
    666 
    667 static void EmeUMAHistogramCounts(const WebKit::WebString& key_system,
    668                                   const std::string& method,
    669                                   int sample) {
    670   // Use the same parameters as UMA_HISTOGRAM_COUNTS.
    671   base::Histogram::FactoryGet(
    672       kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
    673       1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
    674 }
    675 
    676 // Helper enum for reporting generateKeyRequest/addKey histograms.
    677 enum MediaKeyException {
    678   kUnknownResultId,
    679   kSuccess,
    680   kKeySystemNotSupported,
    681   kInvalidPlayerState,
    682   kMaxMediaKeyException
    683 };
    684 
    685 static MediaKeyException MediaKeyExceptionForUMA(
    686     WebMediaPlayer::MediaKeyException e) {
    687   switch (e) {
    688     case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
    689       return kKeySystemNotSupported;
    690     case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
    691       return kInvalidPlayerState;
    692     case WebMediaPlayer::MediaKeyExceptionNoError:
    693       return kSuccess;
    694     default:
    695       return kUnknownResultId;
    696   }
    697 }
    698 
    699 // Helper for converting |key_system| name and exception |e| to a pair of enum
    700 // values from above, for reporting to UMA.
    701 static void ReportMediaKeyExceptionToUMA(
    702     const std::string& method,
    703     const WebString& key_system,
    704     WebMediaPlayer::MediaKeyException e) {
    705   MediaKeyException result_id = MediaKeyExceptionForUMA(e);
    706   DCHECK_NE(result_id, kUnknownResultId) << e;
    707   EmeUMAHistogramEnumeration(
    708       key_system, method, result_id, kMaxMediaKeyException);
    709 }
    710 
    711 WebMediaPlayer::MediaKeyException
    712 WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
    713                                        const unsigned char* init_data,
    714                                        unsigned init_data_length) {
    715   WebMediaPlayer::MediaKeyException e =
    716       GenerateKeyRequestInternal(key_system, init_data, init_data_length);
    717   ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
    718   return e;
    719 }
    720 
    721 WebMediaPlayer::MediaKeyException
    722 WebMediaPlayerImpl::GenerateKeyRequestInternal(
    723     const WebString& key_system,
    724     const unsigned char* init_data,
    725     unsigned init_data_length) {
    726   DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
    727            << std::string(reinterpret_cast<const char*>(init_data),
    728                           static_cast<size_t>(init_data_length));
    729 
    730   if (!IsSupportedKeySystem(key_system))
    731     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
    732 
    733   // We do not support run-time switching between key systems for now.
    734   if (current_key_system_.isEmpty()) {
    735     if (!decryptor_->InitializeCDM(key_system.utf8()))
    736       return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
    737     current_key_system_ = key_system;
    738   }
    739   else if (key_system != current_key_system_) {
    740     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
    741   }
    742 
    743   // TODO(xhwang): We assume all streams are from the same container (thus have
    744   // the same "type") for now. In the future, the "type" should be passed down
    745   // from the application.
    746   if (!decryptor_->GenerateKeyRequest(init_data_type_,
    747                                       init_data, init_data_length)) {
    748     current_key_system_.reset();
    749     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
    750   }
    751 
    752   return WebMediaPlayer::MediaKeyExceptionNoError;
    753 }
    754 
    755 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
    756     const WebString& key_system,
    757     const unsigned char* key,
    758     unsigned key_length,
    759     const unsigned char* init_data,
    760     unsigned init_data_length,
    761     const WebString& session_id) {
    762   WebMediaPlayer::MediaKeyException e = AddKeyInternal(
    763       key_system, key, key_length, init_data, init_data_length, session_id);
    764   ReportMediaKeyExceptionToUMA("addKey", key_system, e);
    765   return e;
    766 }
    767 
    768 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::AddKeyInternal(
    769     const WebString& key_system,
    770     const unsigned char* key,
    771     unsigned key_length,
    772     const unsigned char* init_data,
    773     unsigned init_data_length,
    774     const WebString& session_id) {
    775   DCHECK(key);
    776   DCHECK_GT(key_length, 0u);
    777   DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
    778            << std::string(reinterpret_cast<const char*>(key),
    779                           static_cast<size_t>(key_length)) << ", "
    780            << std::string(reinterpret_cast<const char*>(init_data),
    781                           static_cast<size_t>(init_data_length))
    782            << " [" << session_id.utf8().data() << "]";
    783 
    784 
    785   if (!IsSupportedKeySystem(key_system))
    786     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
    787 
    788   if (current_key_system_.isEmpty() || key_system != current_key_system_)
    789     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
    790 
    791   decryptor_->AddKey(key, key_length,
    792                      init_data, init_data_length, session_id.utf8());
    793   return WebMediaPlayer::MediaKeyExceptionNoError;
    794 }
    795 
    796 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
    797     const WebString& key_system,
    798     const WebString& session_id) {
    799   WebMediaPlayer::MediaKeyException e =
    800       CancelKeyRequestInternal(key_system, session_id);
    801   ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
    802   return e;
    803 }
    804 
    805 WebMediaPlayer::MediaKeyException
    806 WebMediaPlayerImpl::CancelKeyRequestInternal(
    807     const WebString& key_system,
    808     const WebString& session_id) {
    809   if (!IsSupportedKeySystem(key_system))
    810     return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
    811 
    812   if (current_key_system_.isEmpty() || key_system != current_key_system_)
    813     return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
    814 
    815   decryptor_->CancelKeyRequest(session_id.utf8());
    816   return WebMediaPlayer::MediaKeyExceptionNoError;
    817 }
    818 
    819 void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
    820   Destroy();
    821 }
    822 
    823 void WebMediaPlayerImpl::Repaint() {
    824   DCHECK(main_loop_->BelongsToCurrentThread());
    825 
    826   bool size_changed = false;
    827   {
    828     base::AutoLock auto_lock(lock_);
    829     std::swap(pending_size_change_, size_changed);
    830     pending_repaint_ = false;
    831   }
    832 
    833   if (size_changed)
    834     GetClient()->sizeChanged();
    835 
    836   GetClient()->repaint();
    837 }
    838 
    839 void WebMediaPlayerImpl::OnPipelineSeek(PipelineStatus status) {
    840   DCHECK(main_loop_->BelongsToCurrentThread());
    841   starting_ = false;
    842   seeking_ = false;
    843   if (pending_seek_) {
    844     pending_seek_ = false;
    845     seek(pending_seek_seconds_);
    846     return;
    847   }
    848 
    849   if (status != media::PIPELINE_OK) {
    850     OnPipelineError(status);
    851     return;
    852   }
    853 
    854   // Update our paused time.
    855   if (paused_)
    856     paused_time_ = pipeline_->GetMediaTime();
    857 
    858   GetClient()->timeChanged();
    859 }
    860 
    861 void WebMediaPlayerImpl::OnPipelineEnded() {
    862   DCHECK(main_loop_->BelongsToCurrentThread());
    863   GetClient()->timeChanged();
    864 }
    865 
    866 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
    867   DCHECK(main_loop_->BelongsToCurrentThread());
    868   DCHECK_NE(error, media::PIPELINE_OK);
    869 
    870   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
    871     // Any error that occurs before reaching ReadyStateHaveMetadata should
    872     // be considered a format error.
    873     SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
    874     Repaint();
    875     return;
    876   }
    877 
    878   SetNetworkState(PipelineErrorToNetworkState(error));
    879 
    880   if (error == media::PIPELINE_ERROR_DECRYPT)
    881     EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1);
    882 
    883   // Repaint to trigger UI update.
    884   Repaint();
    885 }
    886 
    887 void WebMediaPlayerImpl::OnPipelineBufferingState(
    888     media::Pipeline::BufferingState buffering_state) {
    889   DVLOG(1) << "OnPipelineBufferingState(" << buffering_state << ")";
    890 
    891   switch (buffering_state) {
    892     case media::Pipeline::kHaveMetadata:
    893       SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
    894 
    895       if (hasVideo() && GetClient()->needsWebLayerForVideo()) {
    896         DCHECK(!video_weblayer_);
    897         video_weblayer_.reset(
    898             new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
    899         GetClient()->setWebLayer(video_weblayer_.get());
    900       }
    901       break;
    902     case media::Pipeline::kPrerollCompleted:
    903       // Only transition to ReadyStateHaveEnoughData if we don't have
    904       // any pending seeks because the transition can cause Blink to
    905       // report that the most recent seek has completed.
    906       if (!pending_seek_)
    907         SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
    908       break;
    909   }
    910 
    911   // Repaint to trigger UI update.
    912   Repaint();
    913 }
    914 
    915 void WebMediaPlayerImpl::OnDemuxerOpened(
    916     scoped_ptr<WebKit::WebMediaSource> media_source) {
    917   DCHECK(main_loop_->BelongsToCurrentThread());
    918   media_source->open(new WebMediaSourceClientImpl(
    919       chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
    920 }
    921 
    922 void WebMediaPlayerImpl::OnKeyAdded(const std::string& session_id) {
    923   DCHECK(main_loop_->BelongsToCurrentThread());
    924   EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
    925   GetClient()->keyAdded(current_key_system_,
    926                         WebString::fromUTF8(session_id));
    927 }
    928 
    929 void WebMediaPlayerImpl::OnNeedKey(const std::string& session_id,
    930                                    const std::string& type,
    931                                    scoped_ptr<uint8[]> init_data,
    932                                    int init_data_size) {
    933   DCHECK(main_loop_->BelongsToCurrentThread());
    934 
    935   // Do not fire NeedKey event if encrypted media is not enabled.
    936   if (!decryptor_)
    937     return;
    938 
    939   UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
    940 
    941   DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
    942   if (init_data_type_.empty())
    943     init_data_type_ = type;
    944 
    945   GetClient()->keyNeeded(WebString(),
    946                          WebString::fromUTF8(session_id),
    947                          init_data.get(),
    948                          init_data_size);
    949 }
    950 
    951 scoped_ptr<media::TextTrack>
    952 WebMediaPlayerImpl::OnTextTrack(media::TextKind kind,
    953                                 const std::string& label,
    954                                 const std::string& language) {
    955   typedef WebInbandTextTrackImpl::Kind webkind_t;
    956   const webkind_t webkind = static_cast<webkind_t>(kind);
    957   const WebKit::WebString weblabel = WebKit::WebString::fromUTF8(label);
    958   const WebKit::WebString weblanguage = WebKit::WebString::fromUTF8(language);
    959 
    960   WebInbandTextTrackImpl* const text_track =
    961     new WebInbandTextTrackImpl(webkind, weblabel, weblanguage,
    962                                text_track_index_++);
    963 
    964   return scoped_ptr<media::TextTrack>(new TextTrackImpl(GetClient(),
    965                                                         text_track));
    966 }
    967 
    968 void WebMediaPlayerImpl::OnKeyError(const std::string& session_id,
    969                                     media::MediaKeys::KeyError error_code,
    970                                     int system_code) {
    971   DCHECK(main_loop_->BelongsToCurrentThread());
    972 
    973   EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
    974                              error_code, media::MediaKeys::kMaxKeyError);
    975 
    976   GetClient()->keyError(
    977       current_key_system_,
    978       WebString::fromUTF8(session_id),
    979       static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
    980       system_code);
    981 }
    982 
    983 void WebMediaPlayerImpl::OnKeyMessage(const std::string& session_id,
    984                                       const std::vector<uint8>& message,
    985                                       const std::string& default_url) {
    986   DCHECK(main_loop_->BelongsToCurrentThread());
    987 
    988   const GURL default_url_gurl(default_url);
    989   DLOG_IF(WARNING, !default_url.empty() && !default_url_gurl.is_valid())
    990       << "Invalid URL in default_url: " << default_url;
    991 
    992   GetClient()->keyMessage(current_key_system_,
    993                           WebString::fromUTF8(session_id),
    994                           message.empty() ? NULL : &message[0],
    995                           message.size(),
    996                           default_url_gurl);
    997 }
    998 
    999 void WebMediaPlayerImpl::SetOpaque(bool opaque) {
   1000   DCHECK(main_loop_->BelongsToCurrentThread());
   1001 
   1002   GetClient()->setOpaque(opaque);
   1003 }
   1004 
   1005 void WebMediaPlayerImpl::DataSourceInitialized(const GURL& gurl, bool success) {
   1006   DCHECK(main_loop_->BelongsToCurrentThread());
   1007 
   1008   if (!success) {
   1009     SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
   1010     Repaint();
   1011     return;
   1012   }
   1013 
   1014   StartPipeline(NULL);
   1015 }
   1016 
   1017 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
   1018   if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
   1019     SetNetworkState(WebMediaPlayer::NetworkStateIdle);
   1020   else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
   1021     SetNetworkState(WebMediaPlayer::NetworkStateLoading);
   1022   media_log_->AddEvent(
   1023       media_log_->CreateBooleanEvent(
   1024           media::MediaLogEvent::NETWORK_ACTIVITY_SET,
   1025           "is_downloading_data", is_downloading));
   1026 }
   1027 
   1028 void WebMediaPlayerImpl::StartPipeline(WebKit::WebMediaSource* media_source) {
   1029   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
   1030   bool increase_preroll_on_underflow = true;
   1031 
   1032   // Keep track if this is a MSE or non-MSE playback.
   1033   UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback", (media_source != NULL));
   1034 
   1035   // Figure out which demuxer to use.
   1036   if (!media_source) {
   1037     DCHECK(!chunk_demuxer_);
   1038     DCHECK(data_source_);
   1039 
   1040     demuxer_.reset(new media::FFmpegDemuxer(
   1041         media_loop_, data_source_.get(),
   1042         BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""),
   1043         media_log_));
   1044   } else {
   1045     DCHECK(!chunk_demuxer_);
   1046     DCHECK(!data_source_);
   1047 
   1048     media::AddTextTrackCB add_text_track_cb;
   1049 
   1050     if (cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) {
   1051       add_text_track_cb =
   1052           base::Bind(&WebMediaPlayerImpl::OnTextTrack, base::Unretained(this));
   1053     }
   1054 
   1055     scoped_ptr<WebKit::WebMediaSource> ms(media_source);
   1056     chunk_demuxer_ = new media::ChunkDemuxer(
   1057         BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnDemuxerOpened,
   1058                               base::Passed(&ms)),
   1059         BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""),
   1060         add_text_track_cb,
   1061         base::Bind(&LogMediaSourceError, media_log_));
   1062     demuxer_.reset(chunk_demuxer_);
   1063 
   1064 #if !defined(OS_CHROMEOS)
   1065     // Disable GpuVideoDecoder creation on platforms other than CrOS until
   1066     // they support codec config changes.
   1067     // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed.
   1068     gpu_factories_ = NULL;
   1069 #endif
   1070 
   1071     // Disable preroll increases on underflow since the web application has no
   1072     // way to detect that this is happening and runs the risk of triggering
   1073     // unwanted garbage collection if it is to aggressive about appending data.
   1074     // TODO(acolwell): Remove this once http://crbug.com/144683 is fixed.
   1075     increase_preroll_on_underflow = false;
   1076   }
   1077 
   1078   scoped_ptr<media::FilterCollection> filter_collection(
   1079       new media::FilterCollection());
   1080   filter_collection->SetDemuxer(demuxer_.get());
   1081 
   1082   // Figure out if EME is enabled.
   1083   media::SetDecryptorReadyCB set_decryptor_ready_cb;
   1084   if (decryptor_) {
   1085     set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
   1086                                         base::Unretained(decryptor_.get()));
   1087   }
   1088 
   1089   // Create our audio decoders and renderer.
   1090   ScopedVector<media::AudioDecoder> audio_decoders;
   1091   audio_decoders.push_back(new media::FFmpegAudioDecoder(media_loop_));
   1092   if (cmd_line->HasSwitch(switches::kEnableOpusPlayback)) {
   1093     audio_decoders.push_back(new media::OpusAudioDecoder(media_loop_));
   1094   }
   1095 
   1096   scoped_ptr<media::AudioRenderer> audio_renderer(
   1097       new media::AudioRendererImpl(media_loop_,
   1098                                    audio_source_provider_.get(),
   1099                                    audio_decoders.Pass(),
   1100                                    set_decryptor_ready_cb,
   1101                                    increase_preroll_on_underflow));
   1102   filter_collection->SetAudioRenderer(audio_renderer.Pass());
   1103 
   1104   // Create our video decoders and renderer.
   1105   ScopedVector<media::VideoDecoder> video_decoders;
   1106 
   1107   if (gpu_factories_.get())
   1108     video_decoders.push_back(new media::GpuVideoDecoder(gpu_factories_));
   1109 
   1110   // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released
   1111   // (http://crbug.com/174287) .
   1112 #if !defined(MEDIA_DISABLE_LIBVPX)
   1113   video_decoders.push_back(new media::VpxVideoDecoder(media_loop_));
   1114 #endif  // !defined(MEDIA_DISABLE_LIBVPX)
   1115 
   1116   video_decoders.push_back(new media::FFmpegVideoDecoder(media_loop_));
   1117 
   1118   scoped_ptr<media::VideoRenderer> video_renderer(
   1119       new media::VideoRendererBase(
   1120           media_loop_,
   1121           video_decoders.Pass(),
   1122           set_decryptor_ready_cb,
   1123           base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
   1124           BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
   1125           true));
   1126   filter_collection->SetVideoRenderer(video_renderer.Pass());
   1127 
   1128   // ... and we're ready to go!
   1129   starting_ = true;
   1130   pipeline_->Start(
   1131       filter_collection.Pass(),
   1132       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
   1133       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
   1134       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek),
   1135       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingState),
   1136       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChange));
   1137 }
   1138 
   1139 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
   1140   DCHECK(main_loop_->BelongsToCurrentThread());
   1141   DVLOG(1) << "SetNetworkState: " << state;
   1142   network_state_ = state;
   1143   // Always notify to ensure client has the latest value.
   1144   GetClient()->networkStateChanged();
   1145 }
   1146 
   1147 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
   1148   DCHECK(main_loop_->BelongsToCurrentThread());
   1149   DVLOG(1) << "SetReadyState: " << state;
   1150 
   1151   if (state == WebMediaPlayer::ReadyStateHaveEnoughData &&
   1152       is_local_source_ &&
   1153       network_state_ == WebMediaPlayer::NetworkStateLoading)
   1154     SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
   1155 
   1156   ready_state_ = state;
   1157   // Always notify to ensure client has the latest value.
   1158   GetClient()->readyStateChanged();
   1159 }
   1160 
   1161 void WebMediaPlayerImpl::Destroy() {
   1162   DCHECK(main_loop_->BelongsToCurrentThread());
   1163 
   1164   // Abort any pending IO so stopping the pipeline doesn't get blocked.
   1165   if (data_source_)
   1166     data_source_->Abort();
   1167   if (chunk_demuxer_) {
   1168     chunk_demuxer_->Shutdown();
   1169     chunk_demuxer_ = NULL;
   1170   }
   1171 
   1172   if (gpu_factories_.get()) {
   1173     gpu_factories_->Abort();
   1174     gpu_factories_ = NULL;
   1175   }
   1176 
   1177   // Make sure to kill the pipeline so there's no more media threads running.
   1178   // Note: stopping the pipeline might block for a long time.
   1179   base::WaitableEvent waiter(false, false);
   1180   pipeline_->Stop(base::Bind(
   1181       &base::WaitableEvent::Signal, base::Unretained(&waiter)));
   1182   waiter.Wait();
   1183 
   1184   // Let V8 know we are not using extra resources anymore.
   1185   if (incremented_externally_allocated_memory_) {
   1186     v8::V8::AdjustAmountOfExternalAllocatedMemory(-kPlayerExtraMemory);
   1187     incremented_externally_allocated_memory_ = false;
   1188   }
   1189 
   1190   // Release any final references now that everything has stopped.
   1191   pipeline_.reset();
   1192   demuxer_.reset();
   1193   data_source_.reset();
   1194 }
   1195 
   1196 WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
   1197   DCHECK(main_loop_->BelongsToCurrentThread());
   1198   DCHECK(client_);
   1199   return client_;
   1200 }
   1201 
   1202 WebKit::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
   1203   return audio_source_provider_.get();
   1204 }
   1205 
   1206 void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() {
   1207   DCHECK(main_loop_->BelongsToCurrentThread());
   1208   incremented_externally_allocated_memory_ = true;
   1209   v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory);
   1210 }
   1211 
   1212 double WebMediaPlayerImpl::GetPipelineDuration() const {
   1213   base::TimeDelta duration = pipeline_->GetMediaDuration();
   1214 
   1215   // Return positive infinity if the resource is unbounded.
   1216   // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
   1217   if (duration == media::kInfiniteDuration())
   1218     return std::numeric_limits<double>::infinity();
   1219 
   1220   return duration.InSecondsF();
   1221 }
   1222 
   1223 void WebMediaPlayerImpl::OnDurationChange() {
   1224   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
   1225     return;
   1226 
   1227   GetClient()->durationChanged();
   1228 }
   1229 
   1230 void WebMediaPlayerImpl::FrameReady(
   1231     const scoped_refptr<media::VideoFrame>& frame) {
   1232   base::AutoLock auto_lock(lock_);
   1233 
   1234   if (current_frame_.get() &&
   1235       current_frame_->natural_size() != frame->natural_size() &&
   1236       !pending_size_change_) {
   1237     pending_size_change_ = true;
   1238   }
   1239 
   1240   current_frame_ = frame;
   1241 
   1242   if (pending_repaint_)
   1243     return;
   1244 
   1245   pending_repaint_ = true;
   1246   main_loop_->PostTask(FROM_HERE, base::Bind(
   1247       &WebMediaPlayerImpl::Repaint, AsWeakPtr()));
   1248 }
   1249 
   1250 }  // namespace content
   1251