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
64using blink::WebCanvas;
65using blink::WebMediaPlayer;
66using blink::WebRect;
67using blink::WebSize;
68using blink::WebString;
69using media::PipelineStatus;
70
71namespace {
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...)
81const 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.
99const double kMinRate = 0.0625;
100const double kMaxRate = 16.0;
101
102// Prefix for histograms related to Encrypted Media Extensions.
103const char* kMediaEme = "Media.EME.";
104
105}  // namespace
106
107namespace 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)
113COMPILE_ASSERT_MATCHING_ENUM(Unspecified);
114COMPILE_ASSERT_MATCHING_ENUM(Anonymous);
115COMPILE_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
127static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
128                                const std::string& error) {
129  media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
130}
131
132WebMediaPlayerImpl::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
205WebMediaPlayerImpl::~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
219namespace {
220
221// Helper enum for reporting scheme histograms.
222enum 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
237URLSchemeForHistogram 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
253void 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
263void 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
306void 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
320void 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
335bool WebMediaPlayerImpl::supportsFullscreen() const {
336  DCHECK(main_loop_->BelongsToCurrentThread());
337  return true;
338}
339
340bool WebMediaPlayerImpl::supportsSave() const {
341  DCHECK(main_loop_->BelongsToCurrentThread());
342  return supports_save_;
343}
344
345void 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
378void 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
402void 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)
412COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
413COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
414COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
415#undef COMPILE_ASSERT_MATCHING_ENUM
416
417void 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
424bool WebMediaPlayerImpl::hasVideo() const {
425  DCHECK(main_loop_->BelongsToCurrentThread());
426
427  return pipeline_->HasVideo();
428}
429
430bool WebMediaPlayerImpl::hasAudio() const {
431  DCHECK(main_loop_->BelongsToCurrentThread());
432
433  return pipeline_->HasAudio();
434}
435
436blink::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
444bool WebMediaPlayerImpl::paused() const {
445  DCHECK(main_loop_->BelongsToCurrentThread());
446
447  return pipeline_->GetPlaybackRate() == 0.0f;
448}
449
450bool WebMediaPlayerImpl::seeking() const {
451  DCHECK(main_loop_->BelongsToCurrentThread());
452
453  if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
454    return false;
455
456  return seeking_;
457}
458
459double 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
468double WebMediaPlayerImpl::currentTime() const {
469  DCHECK(main_loop_->BelongsToCurrentThread());
470  return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF();
471}
472
473WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
474  DCHECK(main_loop_->BelongsToCurrentThread());
475  return network_state_;
476}
477
478WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
479  DCHECK(main_loop_->BelongsToCurrentThread());
480  return ready_state_;
481}
482
483const 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
491double 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
505bool WebMediaPlayerImpl::didLoadingProgress() const {
506  DCHECK(main_loop_->BelongsToCurrentThread());
507  return pipeline_->DidLoadingProgress();
508}
509
510void 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
538bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
539  if (data_source_)
540    return data_source_->HasSingleOrigin();
541  return true;
542}
543
544bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
545  if (data_source_)
546    return data_source_->DidPassCORSAccessCheck();
547  return false;
548}
549
550double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
551  return ConvertSecondsToTimestamp(timeValue).InSecondsF();
552}
553
554unsigned WebMediaPlayerImpl::decodedFrameCount() const {
555  DCHECK(main_loop_->BelongsToCurrentThread());
556
557  media::PipelineStatistics stats = pipeline_->GetStatistics();
558  return stats.video_frames_decoded;
559}
560
561unsigned 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
573unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
574  DCHECK(main_loop_->BelongsToCurrentThread());
575
576  media::PipelineStatistics stats = pipeline_->GetStatistics();
577  return stats.audio_bytes_decoded;
578}
579
580unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
581  DCHECK(main_loop_->BelongsToCurrentThread());
582
583  media::PipelineStatistics stats = pipeline_->GetStatistics();
584  return stats.video_bytes_decoded;
585}
586
587void 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
596scoped_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
604void 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
614bool 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.
694static 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
704static 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.
714enum MediaKeyException {
715  kUnknownResultId,
716  kSuccess,
717  kKeySystemNotSupported,
718  kInvalidPlayerState,
719  kMaxMediaKeyException
720};
721
722static 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.
738static 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
748WebMediaPlayer::MediaKeyException
749WebMediaPlayerImpl::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
758WebMediaPlayer::MediaKeyException
759WebMediaPlayerImpl::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
792WebMediaPlayer::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
805WebMediaPlayer::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
833WebMediaPlayer::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
842WebMediaPlayer::MediaKeyException
843WebMediaPlayerImpl::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
856void WebMediaPlayerImpl::OnDestruct() {
857  Destroy();
858}
859
860void 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
884void 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
906void WebMediaPlayerImpl::OnPipelineEnded() {
907  DCHECK(main_loop_->BelongsToCurrentThread());
908  GetClient()->timeChanged();
909}
910
911void 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
932void 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
960void WebMediaPlayerImpl::OnDemuxerOpened() {
961  DCHECK(main_loop_->BelongsToCurrentThread());
962  GetClient()->mediaSourceOpened(new WebMediaSourceImpl(
963      chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
964}
965
966void 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
973void 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
994void 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
1018void 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
1033void 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
1049void WebMediaPlayerImpl::SetOpaque(bool opaque) {
1050  DCHECK(main_loop_->BelongsToCurrentThread());
1051
1052  GetClient()->setOpaque(opaque);
1053}
1054
1055void 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
1067void 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
1078void 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
1174void 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
1182void 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
1196void 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
1232blink::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
1233  DCHECK(main_loop_->BelongsToCurrentThread());
1234  DCHECK(client_);
1235  return client_;
1236}
1237
1238blink::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
1239  return audio_source_provider_.get();
1240}
1241
1242void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() {
1243  DCHECK(main_loop_->BelongsToCurrentThread());
1244  incremented_externally_allocated_memory_ = true;
1245  v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
1246      kPlayerExtraMemory);
1247}
1248
1249double 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
1260void WebMediaPlayerImpl::OnDurationChange() {
1261  if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1262    return;
1263
1264  GetClient()->durationChanged();
1265}
1266
1267void 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
1292void 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