Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / blink / 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 "media/blink/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/debug/alias.h"
16 #include "base/debug/crash_logging.h"
17 #include "base/debug/trace_event.h"
18 #include "base/float_util.h"
19 #include "base/message_loop/message_loop_proxy.h"
20 #include "base/metrics/histogram.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "cc/blink/web_layer_impl.h"
24 #include "cc/layers/video_layer.h"
25 #include "gpu/GLES2/gl2extchromium.h"
26 #include "gpu/command_buffer/common/mailbox_holder.h"
27 #include "media/audio/null_audio_sink.h"
28 #include "media/base/audio_hardware_config.h"
29 #include "media/base/bind_to_current_loop.h"
30 #include "media/base/limits.h"
31 #include "media/base/media_log.h"
32 #include "media/base/pipeline.h"
33 #include "media/base/text_renderer.h"
34 #include "media/base/video_frame.h"
35 #include "media/blink/buffered_data_source.h"
36 #include "media/blink/encrypted_media_player_support.h"
37 #include "media/blink/texttrack_impl.h"
38 #include "media/blink/webaudiosourceprovider_impl.h"
39 #include "media/blink/webinbandtexttrack_impl.h"
40 #include "media/blink/webmediaplayer_delegate.h"
41 #include "media/blink/webmediaplayer_params.h"
42 #include "media/blink/webmediaplayer_util.h"
43 #include "media/blink/webmediasource_impl.h"
44 #include "media/filters/audio_renderer_impl.h"
45 #include "media/filters/chunk_demuxer.h"
46 #include "media/filters/ffmpeg_audio_decoder.h"
47 #include "media/filters/ffmpeg_demuxer.h"
48 #include "media/filters/ffmpeg_video_decoder.h"
49 #include "media/filters/gpu_video_accelerator_factories.h"
50 #include "media/filters/gpu_video_decoder.h"
51 #include "media/filters/opus_audio_decoder.h"
52 #include "media/filters/renderer_impl.h"
53 #include "media/filters/video_renderer_impl.h"
54 #include "media/filters/vpx_video_decoder.h"
55 #include "third_party/WebKit/public/platform/WebMediaSource.h"
56 #include "third_party/WebKit/public/platform/WebRect.h"
57 #include "third_party/WebKit/public/platform/WebSize.h"
58 #include "third_party/WebKit/public/platform/WebString.h"
59 #include "third_party/WebKit/public/platform/WebURL.h"
60 #include "third_party/WebKit/public/web/WebLocalFrame.h"
61 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
62 #include "third_party/WebKit/public/web/WebView.h"
63
64 using blink::WebCanvas;
65 using blink::WebMediaPlayer;
66 using blink::WebRect;
67 using blink::WebSize;
68 using blink::WebString;
69
70 namespace {
71
72 // Limits the range of playback rate.
73 //
74 // TODO(kylep): Revisit these.
75 //
76 // Vista has substantially lower performance than XP or Windows7.  If you speed
77 // up a video too much, it can't keep up, and rendering stops updating except on
78 // the time bar. For really high speeds, audio becomes a bottleneck and we just
79 // use up the data we have, which may not achieve the speed requested, but will
80 // not crash the tab.
81 //
82 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
83 // like a busy loop). It gets unresponsive, although its not completely dead.
84 //
85 // Also our timers are not very accurate (especially for ogg), which becomes
86 // evident at low speeds and on Vista. Since other speeds are risky and outside
87 // the norms, we think 1/16x to 16x is a safe and useful range for now.
88 const double kMinRate = 0.0625;
89 const double kMaxRate = 16.0;
90
91 class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
92  public:
93   explicit SyncPointClientImpl(
94       blink::WebGraphicsContext3D* web_graphics_context)
95       : web_graphics_context_(web_graphics_context) {}
96   ~SyncPointClientImpl() override {}
97   uint32 InsertSyncPoint() override {
98     return web_graphics_context_->insertSyncPoint();
99   }
100   void WaitSyncPoint(uint32 sync_point) override {
101     web_graphics_context_->waitSyncPoint(sync_point);
102   }
103
104  private:
105   blink::WebGraphicsContext3D* web_graphics_context_;
106 };
107
108 }  // namespace
109
110 namespace media {
111
112 class BufferedDataSourceHostImpl;
113
114 #define COMPILE_ASSERT_MATCHING_ENUM(name) \
115   COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \
116                  static_cast<int>(BufferedResourceLoader::k ## name), \
117                  mismatching_enums)
118 COMPILE_ASSERT_MATCHING_ENUM(Unspecified);
119 COMPILE_ASSERT_MATCHING_ENUM(Anonymous);
120 COMPILE_ASSERT_MATCHING_ENUM(UseCredentials);
121 #undef COMPILE_ASSERT_MATCHING_ENUM
122
123 #define BIND_TO_RENDER_LOOP(function) \
124   (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
125   BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
126
127 #define BIND_TO_RENDER_LOOP1(function, arg1) \
128   (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
129   BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
130
131 static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log,
132                                 const std::string& error) {
133   media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
134 }
135
136 WebMediaPlayerImpl::WebMediaPlayerImpl(
137     blink::WebLocalFrame* frame,
138     blink::WebMediaPlayerClient* client,
139     base::WeakPtr<WebMediaPlayerDelegate> delegate,
140     scoped_ptr<Renderer> renderer,
141     const WebMediaPlayerParams& params)
142     : frame_(frame),
143       network_state_(WebMediaPlayer::NetworkStateEmpty),
144       ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
145       preload_(BufferedDataSource::AUTO),
146       main_task_runner_(base::MessageLoopProxy::current()),
147       media_task_runner_(params.media_task_runner()),
148       media_log_(params.media_log()),
149       pipeline_(media_task_runner_, media_log_.get()),
150       load_type_(LoadTypeURL),
151       opaque_(false),
152       paused_(true),
153       seeking_(false),
154       playback_rate_(0.0f),
155       ended_(false),
156       pending_seek_(false),
157       pending_seek_seconds_(0.0f),
158       should_notify_time_changed_(false),
159       client_(client),
160       delegate_(delegate),
161       defer_load_cb_(params.defer_load_cb()),
162       gpu_factories_(params.gpu_factories()),
163       supports_save_(true),
164       chunk_demuxer_(NULL),
165       compositor_task_runner_(params.compositor_task_runner()),
166       compositor_(new VideoFrameCompositor(
167           BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChanged),
168           BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnOpacityChanged))),
169       text_track_index_(0),
170       encrypted_media_support_(
171           params.CreateEncryptedMediaPlayerSupport(client)),
172       audio_hardware_config_(params.audio_hardware_config()),
173       renderer_(renderer.Pass()) {
174   DCHECK(encrypted_media_support_);
175
176   // Threaded compositing isn't enabled universally yet.
177   if (!compositor_task_runner_.get())
178     compositor_task_runner_ = base::MessageLoopProxy::current();
179
180   media_log_->AddEvent(
181       media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
182
183   // TODO(xhwang): When we use an external Renderer, many methods won't work,
184   // e.g. GetCurrentFrameFromCompositor(). Fix this in a future CL.
185   if (renderer_)
186     return;
187
188   // |gpu_factories_| requires that its entry points be called on its
189   // |GetTaskRunner()|.  Since |pipeline_| will own decoders created from the
190   // factories, require that their message loops are identical.
191   DCHECK(!gpu_factories_.get() ||
192          (gpu_factories_->GetTaskRunner() == media_task_runner_.get()));
193
194   // Use the null sink if no sink was provided.
195   audio_source_provider_ = new WebAudioSourceProviderImpl(
196       params.audio_renderer_sink().get()
197           ? params.audio_renderer_sink()
198           : new NullAudioSink(media_task_runner_));
199 }
200
201 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
202   client_->setWebLayer(NULL);
203
204   DCHECK(main_task_runner_->BelongsToCurrentThread());
205   media_log_->AddEvent(
206       media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
207
208   if (delegate_)
209     delegate_->PlayerGone(this);
210
211   // Abort any pending IO so stopping the pipeline doesn't get blocked.
212   if (data_source_)
213     data_source_->Abort();
214   if (chunk_demuxer_) {
215     chunk_demuxer_->Shutdown();
216     chunk_demuxer_ = NULL;
217   }
218
219   gpu_factories_ = NULL;
220
221   // Make sure to kill the pipeline so there's no more media threads running.
222   // Note: stopping the pipeline might block for a long time.
223   base::WaitableEvent waiter(false, false);
224   pipeline_.Stop(
225       base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter)));
226   waiter.Wait();
227
228   compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
229 }
230
231 void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
232                               CORSMode cors_mode) {
233   DVLOG(1) << __FUNCTION__ << "(" << load_type << ", " << url << ", "
234            << cors_mode << ")";
235   if (!defer_load_cb_.is_null()) {
236     defer_load_cb_.Run(base::Bind(
237         &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
238     return;
239   }
240   DoLoad(load_type, url, cors_mode);
241 }
242
243 void WebMediaPlayerImpl::DoLoad(LoadType load_type,
244                                 const blink::WebURL& url,
245                                 CORSMode cors_mode) {
246   DCHECK(main_task_runner_->BelongsToCurrentThread());
247
248   GURL gurl(url);
249   ReportMediaSchemeUma(gurl);
250
251   // Set subresource URL for crash reporting.
252   base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
253
254   load_type_ = load_type;
255
256   SetNetworkState(WebMediaPlayer::NetworkStateLoading);
257   SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
258   media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
259
260   // Media source pipelines can start immediately.
261   if (load_type == LoadTypeMediaSource) {
262     supports_save_ = false;
263     StartPipeline();
264     return;
265   }
266
267   // Otherwise it's a regular request which requires resolving the URL first.
268   data_source_.reset(new BufferedDataSource(
269       url,
270       static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
271       main_task_runner_,
272       frame_,
273       media_log_.get(),
274       &buffered_data_source_host_,
275       base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
276   data_source_->Initialize(
277       base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
278   data_source_->SetPreload(preload_);
279 }
280
281 void WebMediaPlayerImpl::play() {
282   DVLOG(1) << __FUNCTION__;
283   DCHECK(main_task_runner_->BelongsToCurrentThread());
284
285   paused_ = false;
286   pipeline_.SetPlaybackRate(playback_rate_);
287   if (data_source_)
288     data_source_->MediaIsPlaying();
289
290   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
291
292   if (delegate_ && playback_rate_ > 0)
293     delegate_->DidPlay(this);
294 }
295
296 void WebMediaPlayerImpl::pause() {
297   DVLOG(1) << __FUNCTION__;
298   DCHECK(main_task_runner_->BelongsToCurrentThread());
299
300   const bool was_already_paused = paused_ || playback_rate_ == 0;
301   paused_ = true;
302   pipeline_.SetPlaybackRate(0.0f);
303   if (data_source_)
304     data_source_->MediaIsPaused();
305   paused_time_ = pipeline_.GetMediaTime();
306
307   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
308
309   if (!was_already_paused && delegate_)
310     delegate_->DidPause(this);
311 }
312
313 bool WebMediaPlayerImpl::supportsSave() const {
314   DCHECK(main_task_runner_->BelongsToCurrentThread());
315   return supports_save_;
316 }
317
318 void WebMediaPlayerImpl::seek(double seconds) {
319   DVLOG(1) << __FUNCTION__ << "(" << seconds << ")";
320   DCHECK(main_task_runner_->BelongsToCurrentThread());
321
322   ended_ = false;
323
324   if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
325     SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
326
327   base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
328
329   if (seeking_) {
330     pending_seek_ = true;
331     pending_seek_seconds_ = seconds;
332     if (chunk_demuxer_)
333       chunk_demuxer_->CancelPendingSeek(seek_time);
334     return;
335   }
336
337   media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
338
339   // Update our paused time.
340   if (paused_)
341     paused_time_ = seek_time;
342
343   seeking_ = true;
344
345   if (chunk_demuxer_)
346     chunk_demuxer_->StartWaitingForSeek(seek_time);
347
348   // Kick off the asynchronous seek!
349   pipeline_.Seek(
350       seek_time,
351       BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, true));
352 }
353
354 void WebMediaPlayerImpl::setRate(double rate) {
355   DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
356   DCHECK(main_task_runner_->BelongsToCurrentThread());
357
358   // TODO(kylep): Remove when support for negatives is added. Also, modify the
359   // following checks so rewind uses reasonable values also.
360   if (rate < 0.0)
361     return;
362
363   // Limit rates to reasonable values by clamping.
364   if (rate != 0.0) {
365     if (rate < kMinRate)
366       rate = kMinRate;
367     else if (rate > kMaxRate)
368       rate = kMaxRate;
369     if (playback_rate_ == 0 && !paused_ && delegate_)
370       delegate_->DidPlay(this);
371   } else if (playback_rate_ != 0 && !paused_ && delegate_) {
372     delegate_->DidPause(this);
373   }
374
375   playback_rate_ = rate;
376   if (!paused_) {
377     pipeline_.SetPlaybackRate(rate);
378     if (data_source_)
379       data_source_->MediaPlaybackRateChanged(rate);
380   }
381 }
382
383 void WebMediaPlayerImpl::setVolume(double volume) {
384   DVLOG(1) << __FUNCTION__ << "(" << volume << ")";
385   DCHECK(main_task_runner_->BelongsToCurrentThread());
386
387   pipeline_.SetVolume(volume);
388 }
389
390 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
391     COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::webkit_name) == \
392                    static_cast<int>(BufferedDataSource::chromium_name), \
393                    mismatching_enums)
394 COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
395 COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
396 COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
397 #undef COMPILE_ASSERT_MATCHING_ENUM
398
399 void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
400   DVLOG(1) << __FUNCTION__ << "(" << preload << ")";
401   DCHECK(main_task_runner_->BelongsToCurrentThread());
402
403   preload_ = static_cast<BufferedDataSource::Preload>(preload);
404   if (data_source_)
405     data_source_->SetPreload(preload_);
406 }
407
408 bool WebMediaPlayerImpl::hasVideo() const {
409   DCHECK(main_task_runner_->BelongsToCurrentThread());
410
411   return pipeline_metadata_.has_video;
412 }
413
414 bool WebMediaPlayerImpl::hasAudio() const {
415   DCHECK(main_task_runner_->BelongsToCurrentThread());
416
417   return pipeline_metadata_.has_audio;
418 }
419
420 blink::WebSize WebMediaPlayerImpl::naturalSize() const {
421   DCHECK(main_task_runner_->BelongsToCurrentThread());
422
423   return blink::WebSize(pipeline_metadata_.natural_size);
424 }
425
426 bool WebMediaPlayerImpl::paused() const {
427   DCHECK(main_task_runner_->BelongsToCurrentThread());
428
429   return pipeline_.GetPlaybackRate() == 0.0f;
430 }
431
432 bool WebMediaPlayerImpl::seeking() const {
433   DCHECK(main_task_runner_->BelongsToCurrentThread());
434
435   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
436     return false;
437
438   return seeking_;
439 }
440
441 double WebMediaPlayerImpl::duration() const {
442   DCHECK(main_task_runner_->BelongsToCurrentThread());
443
444   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
445     return std::numeric_limits<double>::quiet_NaN();
446
447   return GetPipelineDuration();
448 }
449
450 double WebMediaPlayerImpl::timelineOffset() const {
451   DCHECK(main_task_runner_->BelongsToCurrentThread());
452
453   if (pipeline_metadata_.timeline_offset.is_null())
454     return std::numeric_limits<double>::quiet_NaN();
455
456   return pipeline_metadata_.timeline_offset.ToJsTime();
457 }
458
459 double WebMediaPlayerImpl::currentTime() const {
460   DCHECK(main_task_runner_->BelongsToCurrentThread());
461   DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
462
463   // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
464   // see http://crbug.com/409280
465   if (ended_)
466     return duration();
467
468   return (paused_ ? paused_time_ : pipeline_.GetMediaTime()).InSecondsF();
469 }
470
471 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
472   DCHECK(main_task_runner_->BelongsToCurrentThread());
473   return network_state_;
474 }
475
476 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
477   DCHECK(main_task_runner_->BelongsToCurrentThread());
478   return ready_state_;
479 }
480
481 blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
482   DCHECK(main_task_runner_->BelongsToCurrentThread());
483
484   Ranges<base::TimeDelta> buffered_time_ranges =
485       pipeline_.GetBufferedTimeRanges();
486
487   const base::TimeDelta duration = pipeline_.GetMediaDuration();
488   if (duration != kInfiniteDuration()) {
489     buffered_data_source_host_.AddBufferedTimeRanges(
490         &buffered_time_ranges, duration);
491   }
492   return ConvertToWebTimeRanges(buffered_time_ranges);
493 }
494
495 blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
496   DCHECK(main_task_runner_->BelongsToCurrentThread());
497
498   if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
499     return blink::WebTimeRanges();
500
501   const double seekable_end = duration();
502
503   // Allow a special exception for seeks to zero for streaming sources with a
504   // finite duration; this allows looping to work.
505   const bool allow_seek_to_zero = data_source_ && data_source_->IsStreaming() &&
506                                   base::IsFinite(seekable_end);
507
508   // TODO(dalecurtis): Technically this allows seeking on media which return an
509   // infinite duration so long as DataSource::IsStreaming() is false.  While not
510   // expected, disabling this breaks semi-live players, http://crbug.com/427412.
511   const blink::WebTimeRange seekable_range(
512       0.0, allow_seek_to_zero ? 0.0 : seekable_end);
513   return blink::WebTimeRanges(&seekable_range, 1);
514 }
515
516 bool WebMediaPlayerImpl::didLoadingProgress() {
517   DCHECK(main_task_runner_->BelongsToCurrentThread());
518   bool pipeline_progress = pipeline_.DidLoadingProgress();
519   bool data_progress = buffered_data_source_host_.DidLoadingProgress();
520   return pipeline_progress || data_progress;
521 }
522
523 void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
524                                const blink::WebRect& rect,
525                                unsigned char alpha,
526                                SkXfermode::Mode mode) {
527   DCHECK(main_task_runner_->BelongsToCurrentThread());
528   TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
529
530   // TODO(scherkus): Clarify paint() API contract to better understand when and
531   // why it's being called. For example, today paint() is called when:
532   //   - We haven't reached HAVE_CURRENT_DATA and need to paint black
533   //   - We're painting to a canvas
534   // See http://crbug.com/341225 http://crbug.com/342621 for details.
535   scoped_refptr<VideoFrame> video_frame =
536       GetCurrentFrameFromCompositor();
537
538   gfx::Rect gfx_rect(rect);
539
540   skcanvas_video_renderer_.Paint(video_frame,
541                                  canvas,
542                                  gfx_rect,
543                                  alpha,
544                                  mode,
545                                  pipeline_metadata_.video_rotation);
546 }
547
548 bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
549   if (data_source_)
550     return data_source_->HasSingleOrigin();
551   return true;
552 }
553
554 bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
555   if (data_source_)
556     return data_source_->DidPassCORSAccessCheck();
557   return false;
558 }
559
560 double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
561   return ConvertSecondsToTimestamp(timeValue).InSecondsF();
562 }
563
564 unsigned WebMediaPlayerImpl::decodedFrameCount() const {
565   DCHECK(main_task_runner_->BelongsToCurrentThread());
566
567   PipelineStatistics stats = pipeline_.GetStatistics();
568   return stats.video_frames_decoded;
569 }
570
571 unsigned WebMediaPlayerImpl::droppedFrameCount() const {
572   DCHECK(main_task_runner_->BelongsToCurrentThread());
573
574   PipelineStatistics stats = pipeline_.GetStatistics();
575   return stats.video_frames_dropped;
576 }
577
578 unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
579   DCHECK(main_task_runner_->BelongsToCurrentThread());
580
581   PipelineStatistics stats = pipeline_.GetStatistics();
582   return stats.audio_bytes_decoded;
583 }
584
585 unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
586   DCHECK(main_task_runner_->BelongsToCurrentThread());
587
588   PipelineStatistics stats = pipeline_.GetStatistics();
589   return stats.video_bytes_decoded;
590 }
591
592 bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
593     blink::WebGraphicsContext3D* web_graphics_context,
594     unsigned int texture,
595     unsigned int level,
596     unsigned int internal_format,
597     unsigned int type,
598     bool premultiply_alpha,
599     bool flip_y) {
600   TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
601
602   scoped_refptr<VideoFrame> video_frame =
603       GetCurrentFrameFromCompositor();
604
605   if (!video_frame.get())
606     return false;
607   if (video_frame->format() != VideoFrame::NATIVE_TEXTURE)
608     return false;
609
610   const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
611   if (mailbox_holder->texture_target != GL_TEXTURE_2D)
612     return false;
613
614   web_graphics_context->waitSyncPoint(mailbox_holder->sync_point);
615   uint32 source_texture = web_graphics_context->createAndConsumeTextureCHROMIUM(
616       GL_TEXTURE_2D, mailbox_holder->mailbox.name);
617
618   // The video is stored in a unmultiplied format, so premultiply
619   // if necessary.
620   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
621                                     premultiply_alpha);
622   // Application itself needs to take care of setting the right flip_y
623   // value down to get the expected result.
624   // flip_y==true means to reverse the video orientation while
625   // flip_y==false means to keep the intrinsic orientation.
626   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
627   web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D,
628                                             source_texture,
629                                             texture,
630                                             level,
631                                             internal_format,
632                                             type);
633   web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
634   web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
635                                     false);
636
637   web_graphics_context->deleteTexture(source_texture);
638   web_graphics_context->flush();
639
640   SyncPointClientImpl client(web_graphics_context);
641   video_frame->UpdateReleaseSyncPoint(&client);
642   return true;
643 }
644
645 WebMediaPlayer::MediaKeyException
646 WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
647                                        const unsigned char* init_data,
648                                        unsigned init_data_length) {
649   DCHECK(main_task_runner_->BelongsToCurrentThread());
650
651   return encrypted_media_support_->GenerateKeyRequest(
652       frame_, key_system, init_data, init_data_length);
653 }
654
655 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
656     const WebString& key_system,
657     const unsigned char* key,
658     unsigned key_length,
659     const unsigned char* init_data,
660     unsigned init_data_length,
661     const WebString& session_id) {
662   DCHECK(main_task_runner_->BelongsToCurrentThread());
663
664   return encrypted_media_support_->AddKey(
665       key_system, key, key_length, init_data, init_data_length, session_id);
666 }
667
668 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
669     const WebString& key_system,
670     const WebString& session_id) {
671   DCHECK(main_task_runner_->BelongsToCurrentThread());
672
673   return encrypted_media_support_->CancelKeyRequest(key_system, session_id);
674 }
675
676 void WebMediaPlayerImpl::setContentDecryptionModule(
677     blink::WebContentDecryptionModule* cdm) {
678   DCHECK(main_task_runner_->BelongsToCurrentThread());
679
680   encrypted_media_support_->SetContentDecryptionModule(cdm);
681 }
682
683 void WebMediaPlayerImpl::setContentDecryptionModule(
684     blink::WebContentDecryptionModule* cdm,
685     blink::WebContentDecryptionModuleResult result) {
686   DCHECK(main_task_runner_->BelongsToCurrentThread());
687
688   encrypted_media_support_->SetContentDecryptionModule(cdm, result);
689 }
690
691 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed,
692                                           PipelineStatus status) {
693   DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")";
694   DCHECK(main_task_runner_->BelongsToCurrentThread());
695   seeking_ = false;
696   if (pending_seek_) {
697     pending_seek_ = false;
698     seek(pending_seek_seconds_);
699     return;
700   }
701
702   if (status != PIPELINE_OK) {
703     OnPipelineError(status);
704     return;
705   }
706
707   // Update our paused time.
708   if (paused_)
709     paused_time_ = pipeline_.GetMediaTime();
710
711   should_notify_time_changed_ = time_changed;
712 }
713
714 void WebMediaPlayerImpl::OnPipelineEnded() {
715   DVLOG(1) << __FUNCTION__;
716   DCHECK(main_task_runner_->BelongsToCurrentThread());
717
718   // Ignore state changes until we've completed all outstanding seeks.
719   if (seeking_ || pending_seek_)
720     return;
721
722   ended_ = true;
723   client_->timeChanged();
724 }
725
726 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
727   DCHECK(main_task_runner_->BelongsToCurrentThread());
728   DCHECK_NE(error, PIPELINE_OK);
729
730   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
731     // Any error that occurs before reaching ReadyStateHaveMetadata should
732     // be considered a format error.
733     SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
734     return;
735   }
736
737   SetNetworkState(PipelineErrorToNetworkState(error));
738
739   if (error == PIPELINE_ERROR_DECRYPT)
740     encrypted_media_support_->OnPipelineDecryptError();
741 }
742
743 void WebMediaPlayerImpl::OnPipelineMetadata(
744     PipelineMetadata metadata) {
745   DVLOG(1) << __FUNCTION__;
746
747   pipeline_metadata_ = metadata;
748
749   UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation",
750                             metadata.video_rotation,
751                             VIDEO_ROTATION_MAX + 1);
752   SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
753
754   if (hasVideo()) {
755     DCHECK(!video_weblayer_);
756     scoped_refptr<cc::VideoLayer> layer =
757         cc::VideoLayer::Create(compositor_, pipeline_metadata_.video_rotation);
758
759     if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
760         pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
761       gfx::Size size = pipeline_metadata_.natural_size;
762       pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
763     }
764
765     video_weblayer_.reset(new cc_blink::WebLayerImpl(layer));
766     video_weblayer_->setOpaque(opaque_);
767     client_->setWebLayer(video_weblayer_.get());
768   }
769 }
770
771 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged(
772     BufferingState buffering_state) {
773   DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")";
774
775   // Ignore buffering state changes until we've completed all outstanding seeks.
776   if (seeking_ || pending_seek_)
777     return;
778
779   // TODO(scherkus): Handle other buffering states when Pipeline starts using
780   // them and translate them ready state changes http://crbug.com/144683
781   DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH);
782   SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
783
784   // Blink expects a timeChanged() in response to a seek().
785   if (should_notify_time_changed_)
786     client_->timeChanged();
787 }
788
789 void WebMediaPlayerImpl::OnDemuxerOpened() {
790   DCHECK(main_task_runner_->BelongsToCurrentThread());
791   client_->mediaSourceOpened(new WebMediaSourceImpl(
792       chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
793 }
794
795 void WebMediaPlayerImpl::OnAddTextTrack(
796     const TextTrackConfig& config,
797     const AddTextTrackDoneCB& done_cb) {
798   DCHECK(main_task_runner_->BelongsToCurrentThread());
799
800   const WebInbandTextTrackImpl::Kind web_kind =
801       static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
802   const blink::WebString web_label =
803       blink::WebString::fromUTF8(config.label());
804   const blink::WebString web_language =
805       blink::WebString::fromUTF8(config.language());
806   const blink::WebString web_id =
807       blink::WebString::fromUTF8(config.id());
808
809   scoped_ptr<WebInbandTextTrackImpl> web_inband_text_track(
810       new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id,
811                                  text_track_index_++));
812
813   scoped_ptr<TextTrack> text_track(new TextTrackImpl(
814       main_task_runner_, client_, web_inband_text_track.Pass()));
815
816   done_cb.Run(text_track.Pass());
817 }
818
819 void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
820   DCHECK(main_task_runner_->BelongsToCurrentThread());
821
822   if (!success) {
823     SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
824     return;
825   }
826
827   StartPipeline();
828 }
829
830 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
831   if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
832     SetNetworkState(WebMediaPlayer::NetworkStateIdle);
833   else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
834     SetNetworkState(WebMediaPlayer::NetworkStateLoading);
835   media_log_->AddEvent(
836       media_log_->CreateBooleanEvent(
837           MediaLogEvent::NETWORK_ACTIVITY_SET,
838           "is_downloading_data", is_downloading));
839 }
840
841 // TODO(xhwang): Move this to a factory class so that we can create different
842 // renderers.
843 scoped_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
844   SetDecryptorReadyCB set_decryptor_ready_cb =
845       encrypted_media_support_->CreateSetDecryptorReadyCB();
846
847   // Create our audio decoders and renderer.
848   ScopedVector<AudioDecoder> audio_decoders;
849
850   audio_decoders.push_back(new media::FFmpegAudioDecoder(
851       media_task_runner_, base::Bind(&LogMediaSourceError, media_log_)));
852   audio_decoders.push_back(new media::OpusAudioDecoder(media_task_runner_));
853
854   scoped_ptr<AudioRenderer> audio_renderer(
855       new AudioRendererImpl(media_task_runner_,
856                             audio_source_provider_.get(),
857                             audio_decoders.Pass(),
858                             set_decryptor_ready_cb,
859                             audio_hardware_config_,
860                             media_log_));
861
862   // Create our video decoders and renderer.
863   ScopedVector<VideoDecoder> video_decoders;
864
865   if (gpu_factories_.get())
866     video_decoders.push_back(new GpuVideoDecoder(gpu_factories_));
867
868 #if !defined(MEDIA_DISABLE_LIBVPX)
869   video_decoders.push_back(new VpxVideoDecoder(media_task_runner_));
870 #endif  // !defined(MEDIA_DISABLE_LIBVPX)
871
872   video_decoders.push_back(new FFmpegVideoDecoder(media_task_runner_));
873
874   scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl(
875       media_task_runner_,
876       video_decoders.Pass(),
877       set_decryptor_ready_cb,
878       base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
879       true,
880       media_log_));
881
882   // Create renderer.
883   return scoped_ptr<Renderer>(new RendererImpl(
884       media_task_runner_, audio_renderer.Pass(), video_renderer.Pass()));
885 }
886
887 void WebMediaPlayerImpl::StartPipeline() {
888   DCHECK(main_task_runner_->BelongsToCurrentThread());
889
890   // Keep track if this is a MSE or non-MSE playback.
891   UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback",
892                         (load_type_ == LoadTypeMediaSource));
893
894   LogCB mse_log_cb;
895   Demuxer::NeedKeyCB need_key_cb =
896       encrypted_media_support_->CreateNeedKeyCB();
897
898   // Figure out which demuxer to use.
899   if (load_type_ != LoadTypeMediaSource) {
900     DCHECK(!chunk_demuxer_);
901     DCHECK(data_source_);
902
903     demuxer_.reset(new FFmpegDemuxer(
904         media_task_runner_, data_source_.get(),
905         need_key_cb,
906         media_log_));
907   } else {
908     DCHECK(!chunk_demuxer_);
909     DCHECK(!data_source_);
910
911     mse_log_cb = base::Bind(&LogMediaSourceError, media_log_);
912
913     chunk_demuxer_ = new ChunkDemuxer(
914         BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
915         need_key_cb,
916         mse_log_cb,
917         true);
918     demuxer_.reset(chunk_demuxer_);
919   }
920
921   // ... and we're ready to go!
922   seeking_ = true;
923
924   if (!renderer_)
925     renderer_ = CreateRenderer();
926
927   pipeline_.Start(
928       demuxer_.get(),
929       renderer_.Pass(),
930       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
931       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
932       BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false),
933       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata),
934       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged),
935       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged),
936       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack));
937 }
938
939 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
940   DVLOG(1) << __FUNCTION__ << "(" << state << ")";
941   DCHECK(main_task_runner_->BelongsToCurrentThread());
942   network_state_ = state;
943   // Always notify to ensure client has the latest value.
944   client_->networkStateChanged();
945 }
946
947 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
948   DVLOG(1) << __FUNCTION__ << "(" << state << ")";
949   DCHECK(main_task_runner_->BelongsToCurrentThread());
950
951   if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
952       data_source_->assume_fully_buffered() &&
953       network_state_ == WebMediaPlayer::NetworkStateLoading)
954     SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
955
956   ready_state_ = state;
957   // Always notify to ensure client has the latest value.
958   client_->readyStateChanged();
959 }
960
961 blink::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
962   return audio_source_provider_.get();
963 }
964
965 double WebMediaPlayerImpl::GetPipelineDuration() const {
966   base::TimeDelta duration = pipeline_.GetMediaDuration();
967
968   // Return positive infinity if the resource is unbounded.
969   // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
970   if (duration == kInfiniteDuration())
971     return std::numeric_limits<double>::infinity();
972
973   return duration.InSecondsF();
974 }
975
976 void WebMediaPlayerImpl::OnDurationChanged() {
977   if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
978     return;
979
980   client_->durationChanged();
981 }
982
983 void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) {
984   DCHECK(main_task_runner_->BelongsToCurrentThread());
985   DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
986   TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
987
988   media_log_->AddEvent(
989       media_log_->CreateVideoSizeSetEvent(size.width(), size.height()));
990   pipeline_metadata_.natural_size = size;
991
992   client_->sizeChanged();
993 }
994
995 void WebMediaPlayerImpl::OnOpacityChanged(bool opaque) {
996   DCHECK(main_task_runner_->BelongsToCurrentThread());
997   DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
998
999   opaque_ = opaque;
1000   if (video_weblayer_)
1001     video_weblayer_->setOpaque(opaque_);
1002 }
1003
1004 void WebMediaPlayerImpl::FrameReady(
1005     const scoped_refptr<VideoFrame>& frame) {
1006   compositor_task_runner_->PostTask(
1007       FROM_HERE,
1008       base::Bind(&VideoFrameCompositor::UpdateCurrentFrame,
1009                  base::Unretained(compositor_),
1010                  frame));
1011 }
1012
1013 static void GetCurrentFrameAndSignal(
1014     VideoFrameCompositor* compositor,
1015     scoped_refptr<VideoFrame>* video_frame_out,
1016     base::WaitableEvent* event) {
1017   TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
1018   *video_frame_out = compositor->GetCurrentFrame();
1019   event->Signal();
1020 }
1021
1022 scoped_refptr<VideoFrame>
1023 WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
1024   TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
1025   if (compositor_task_runner_->BelongsToCurrentThread())
1026     return compositor_->GetCurrentFrame();
1027
1028   // Use a posted task and waitable event instead of a lock otherwise
1029   // WebGL/Canvas can see different content than what the compositor is seeing.
1030   scoped_refptr<VideoFrame> video_frame;
1031   base::WaitableEvent event(false, false);
1032   compositor_task_runner_->PostTask(FROM_HERE,
1033                                     base::Bind(&GetCurrentFrameAndSignal,
1034                                                base::Unretained(compositor_),
1035                                                &video_frame,
1036                                                &event));
1037   event.Wait();
1038   return video_frame;
1039 }
1040
1041 }  // namespace media