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