Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: webkit/renderer/media/webmediaplayer_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698