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