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