Index: webkit/renderer/media/webmediaplayer_impl.cc |
diff --git a/webkit/renderer/media/webmediaplayer_impl.cc b/webkit/renderer/media/webmediaplayer_impl.cc |
deleted file mode 100644 |
index 65fd073d3619dc666c8ea2e2766e1f9cc57bf091..0000000000000000000000000000000000000000 |
--- a/webkit/renderer/media/webmediaplayer_impl.cc |
+++ /dev/null |
@@ -1,1226 +0,0 @@ |
-// Copyright 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "webkit/renderer/media/webmediaplayer_impl.h" |
- |
-#include <algorithm> |
-#include <limits> |
-#include <string> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/command_line.h" |
-#include "base/debug/crash_logging.h" |
-#include "base/message_loop/message_loop_proxy.h" |
-#include "base/metrics/histogram.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/synchronization/waitable_event.h" |
-#include "cc/layers/video_layer.h" |
-#include "gpu/GLES2/gl2extchromium.h" |
-#include "media/audio/null_audio_sink.h" |
-#include "media/base/bind_to_loop.h" |
-#include "media/base/filter_collection.h" |
-#include "media/base/limits.h" |
-#include "media/base/media_log.h" |
-#include "media/base/media_switches.h" |
-#include "media/base/pipeline.h" |
-#include "media/base/video_frame.h" |
-#include "media/filters/audio_renderer_impl.h" |
-#include "media/filters/chunk_demuxer.h" |
-#include "media/filters/ffmpeg_audio_decoder.h" |
-#include "media/filters/ffmpeg_demuxer.h" |
-#include "media/filters/ffmpeg_video_decoder.h" |
-#include "media/filters/opus_audio_decoder.h" |
-#include "media/filters/video_renderer_base.h" |
-#include "media/filters/vpx_video_decoder.h" |
-#include "third_party/WebKit/public/platform/WebRect.h" |
-#include "third_party/WebKit/public/platform/WebSize.h" |
-#include "third_party/WebKit/public/platform/WebString.h" |
-#include "third_party/WebKit/public/platform/WebURL.h" |
-#include "third_party/WebKit/public/web/WebMediaSource.h" |
-#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" |
-#include "third_party/WebKit/public/web/WebView.h" |
-#include "v8/include/v8.h" |
-#include "webkit/plugins/ppapi/ppapi_webplugin_impl.h" |
-#include "webkit/renderer/compositor_bindings/web_layer_impl.h" |
-#include "webkit/renderer/media/buffered_data_source.h" |
-#include "webkit/renderer/media/crypto/key_systems.h" |
-#include "webkit/renderer/media/texttrack_impl.h" |
-#include "webkit/renderer/media/webaudiosourceprovider_impl.h" |
-#include "webkit/renderer/media/webinbandtexttrack_impl.h" |
-#include "webkit/renderer/media/webmediaplayer_delegate.h" |
-#include "webkit/renderer/media/webmediaplayer_params.h" |
-#include "webkit/renderer/media/webmediaplayer_util.h" |
-#include "webkit/renderer/media/webmediasourceclient_impl.h" |
- |
-using WebKit::WebCanvas; |
-using WebKit::WebMediaPlayer; |
-using WebKit::WebRect; |
-using WebKit::WebSize; |
-using WebKit::WebString; |
-using media::PipelineStatus; |
- |
-namespace { |
- |
-// Amount of extra memory used by each player instance reported to V8. |
-// It is not exact number -- first, it differs on different platforms, |
-// and second, it is very hard to calculate. Instead, use some arbitrary |
-// value that will cause garbage collection from time to time. We don't want |
-// it to happen on every allocation, but don't want 5k players to sit in memory |
-// either. Looks that chosen constant achieves both goals, at least for audio |
-// objects. (Do not worry about video objects yet, JS programs do not create |
-// thousands of them...) |
-const int kPlayerExtraMemory = 1024 * 1024; |
- |
-// Limits the range of playback rate. |
-// |
-// TODO(kylep): Revisit these. |
-// |
-// Vista has substantially lower performance than XP or Windows7. If you speed |
-// up a video too much, it can't keep up, and rendering stops updating except on |
-// the time bar. For really high speeds, audio becomes a bottleneck and we just |
-// use up the data we have, which may not achieve the speed requested, but will |
-// not crash the tab. |
-// |
-// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems |
-// like a busy loop). It gets unresponsive, although its not completely dead. |
-// |
-// Also our timers are not very accurate (especially for ogg), which becomes |
-// evident at low speeds and on Vista. Since other speeds are risky and outside |
-// the norms, we think 1/16x to 16x is a safe and useful range for now. |
-const double kMinRate = 0.0625; |
-const double kMaxRate = 16.0; |
- |
-// Prefix for histograms related to Encrypted Media Extensions. |
-const char* kMediaEme = "Media.EME."; |
-} // namespace |
- |
-namespace webkit_media { |
- |
-#define COMPILE_ASSERT_MATCHING_ENUM(name) \ |
- COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \ |
- static_cast<int>(BufferedResourceLoader::k ## name), \ |
- mismatching_enums) |
-COMPILE_ASSERT_MATCHING_ENUM(Unspecified); |
-COMPILE_ASSERT_MATCHING_ENUM(Anonymous); |
-COMPILE_ASSERT_MATCHING_ENUM(UseCredentials); |
-#undef COMPILE_ASSERT_MATCHING_ENUM |
- |
-#define BIND_TO_RENDER_LOOP(function) \ |
- media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr())) |
- |
-#define BIND_TO_RENDER_LOOP_1(function, arg1) \ |
- media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1)) |
- |
-#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \ |
- media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1, arg2)) |
- |
-static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, |
- const std::string& error) { |
- media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); |
-} |
- |
-WebMediaPlayerImpl::WebMediaPlayerImpl( |
- WebKit::WebFrame* frame, |
- WebKit::WebMediaPlayerClient* client, |
- base::WeakPtr<WebMediaPlayerDelegate> delegate, |
- const WebMediaPlayerParams& params) |
- : frame_(frame), |
- network_state_(WebMediaPlayer::NetworkStateEmpty), |
- ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
- main_loop_(base::MessageLoopProxy::current()), |
- media_loop_(params.message_loop_proxy()), |
- paused_(true), |
- seeking_(false), |
- playback_rate_(0.0f), |
- pending_seek_(false), |
- pending_seek_seconds_(0.0f), |
- client_(client), |
- delegate_(delegate), |
- media_log_(params.media_log()), |
- accelerated_compositing_reported_(false), |
- incremented_externally_allocated_memory_(false), |
- gpu_factories_(params.gpu_factories()), |
- is_local_source_(false), |
- supports_save_(true), |
- starting_(false), |
- chunk_demuxer_(NULL), |
- pending_repaint_(false), |
- pending_size_change_(false), |
- video_frame_provider_client_(NULL), |
- text_track_index_(0) { |
- media_log_->AddEvent( |
- media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); |
- |
- pipeline_.reset(new media::Pipeline(media_loop_, media_log_.get())); |
- |
- // Let V8 know we started new thread if we did not do it yet. |
- // Made separate task to avoid deletion of player currently being created. |
- // Also, delaying GC until after player starts gets rid of starting lag -- |
- // collection happens in parallel with playing. |
- // |
- // TODO(enal): remove when we get rid of per-audio-stream thread. |
- main_loop_->PostTask( |
- FROM_HERE, |
- base::Bind(&WebMediaPlayerImpl::IncrementExternallyAllocatedMemory, |
- AsWeakPtr())); |
- |
- // Also we want to be notified of |main_loop_| destruction. |
- base::MessageLoop::current()->AddDestructionObserver(this); |
- |
- if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) { |
- decryptor_.reset(new ProxyDecryptor( |
-#if defined(ENABLE_PEPPER_CDMS) |
- client, |
- frame, |
-#endif |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyAdded), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyError), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyMessage))); |
- } |
- |
- // Use the null sink if no sink was provided. |
- audio_source_provider_ = new WebAudioSourceProviderImpl( |
- params.audio_renderer_sink().get() |
- ? params.audio_renderer_sink() |
- : new media::NullAudioSink(media_loop_)); |
-} |
- |
-WebMediaPlayerImpl::~WebMediaPlayerImpl() { |
- SetVideoFrameProviderClient(NULL); |
- GetClient()->setWebLayer(NULL); |
- |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- media_log_->AddEvent( |
- media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); |
- |
- if (delegate_.get()) |
- delegate_->PlayerGone(this); |
- |
- Destroy(); |
- |
- // Remove destruction observer if we're being destroyed but the main thread is |
- // still running. |
- if (base::MessageLoop::current()) |
- base::MessageLoop::current()->RemoveDestructionObserver(this); |
-} |
- |
-namespace { |
- |
-// Helper enum for reporting scheme histograms. |
-enum URLSchemeForHistogram { |
- kUnknownURLScheme, |
- kMissingURLScheme, |
- kHttpURLScheme, |
- kHttpsURLScheme, |
- kFtpURLScheme, |
- kChromeExtensionURLScheme, |
- kJavascriptURLScheme, |
- kFileURLScheme, |
- kBlobURLScheme, |
- kDataURLScheme, |
- kFileSystemScheme, |
- kMaxURLScheme = kFileSystemScheme // Must be equal to highest enum value. |
-}; |
- |
-URLSchemeForHistogram URLScheme(const GURL& url) { |
- if (!url.has_scheme()) return kMissingURLScheme; |
- if (url.SchemeIs("http")) return kHttpURLScheme; |
- if (url.SchemeIs("https")) return kHttpsURLScheme; |
- if (url.SchemeIs("ftp")) return kFtpURLScheme; |
- if (url.SchemeIs("chrome-extension")) return kChromeExtensionURLScheme; |
- if (url.SchemeIs("javascript")) return kJavascriptURLScheme; |
- if (url.SchemeIs("file")) return kFileURLScheme; |
- if (url.SchemeIs("blob")) return kBlobURLScheme; |
- if (url.SchemeIs("data")) return kDataURLScheme; |
- if (url.SchemeIs("filesystem")) return kFileSystemScheme; |
- return kUnknownURLScheme; |
-} |
- |
-} // anonymous namespace |
- |
-void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- LoadSetup(url); |
- |
- // Otherwise it's a regular request which requires resolving the URL first. |
- GURL gurl(url); |
- data_source_.reset(new BufferedDataSource( |
- main_loop_, |
- frame_, |
- media_log_.get(), |
- base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr()))); |
- data_source_->Initialize( |
- url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode), |
- base::Bind( |
- &WebMediaPlayerImpl::DataSourceInitialized, |
- AsWeakPtr(), gurl)); |
- |
- is_local_source_ = !gurl.SchemeIs("http") && !gurl.SchemeIs("https"); |
-} |
- |
-void WebMediaPlayerImpl::load(const WebKit::WebURL& url, |
- WebKit::WebMediaSource* media_source, |
- CORSMode cors_mode) { |
- LoadSetup(url); |
- |
- // Media source pipelines can start immediately. |
- supports_save_ = false; |
- StartPipeline(media_source); |
-} |
- |
-void WebMediaPlayerImpl::LoadSetup(const WebKit::WebURL& url) { |
- GURL gurl(url); |
- UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(gurl), kMaxURLScheme); |
- |
- // Set subresource URL for crash reporting. |
- base::debug::SetCrashKeyValue("subresource_url", gurl.spec()); |
- |
- // Handle any volume/preload changes that occurred before load(). |
- setVolume(GetClient()->volume()); |
- setPreload(GetClient()->preload()); |
- |
- SetNetworkState(WebMediaPlayer::NetworkStateLoading); |
- SetReadyState(WebMediaPlayer::ReadyStateHaveNothing); |
- media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec())); |
-} |
- |
-void WebMediaPlayerImpl::play() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- paused_ = false; |
- pipeline_->SetPlaybackRate(playback_rate_); |
- |
- media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); |
- |
- if (delegate_.get()) |
- delegate_->DidPlay(this); |
-} |
- |
-void WebMediaPlayerImpl::pause() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- paused_ = true; |
- pipeline_->SetPlaybackRate(0.0f); |
- paused_time_ = pipeline_->GetMediaTime(); |
- |
- media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE)); |
- |
- if (delegate_.get()) |
- delegate_->DidPause(this); |
-} |
- |
-bool WebMediaPlayerImpl::supportsFullscreen() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return true; |
-} |
- |
-bool WebMediaPlayerImpl::supportsSave() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return supports_save_; |
-} |
- |
-void WebMediaPlayerImpl::seek(double seconds) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds); |
- |
- if (starting_ || seeking_) { |
- pending_seek_ = true; |
- pending_seek_seconds_ = seconds; |
- if (chunk_demuxer_) |
- chunk_demuxer_->CancelPendingSeek(seek_time); |
- return; |
- } |
- |
- media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); |
- |
- // Update our paused time. |
- if (paused_) |
- paused_time_ = seek_time; |
- |
- seeking_ = true; |
- |
- if (chunk_demuxer_) |
- chunk_demuxer_->StartWaitingForSeek(seek_time); |
- |
- // Kick off the asynchronous seek! |
- pipeline_->Seek( |
- seek_time, |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek)); |
-} |
- |
-void WebMediaPlayerImpl::setRate(double rate) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- // TODO(kylep): Remove when support for negatives is added. Also, modify the |
- // following checks so rewind uses reasonable values also. |
- if (rate < 0.0) |
- return; |
- |
- // Limit rates to reasonable values by clamping. |
- if (rate != 0.0) { |
- if (rate < kMinRate) |
- rate = kMinRate; |
- else if (rate > kMaxRate) |
- rate = kMaxRate; |
- } |
- |
- playback_rate_ = rate; |
- if (!paused_) { |
- pipeline_->SetPlaybackRate(rate); |
- } |
-} |
- |
-void WebMediaPlayerImpl::setVolume(double volume) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- pipeline_->SetVolume(volume); |
-} |
- |
-#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \ |
- COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::webkit_name) == \ |
- static_cast<int>(webkit_media::chromium_name), \ |
- mismatching_enums) |
-COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE); |
-COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA); |
-COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO); |
-#undef COMPILE_ASSERT_MATCHING_ENUM |
- |
-void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- if (data_source_) |
- data_source_->SetPreload(static_cast<webkit_media::Preload>(preload)); |
-} |
- |
-bool WebMediaPlayerImpl::hasVideo() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- return pipeline_->HasVideo(); |
-} |
- |
-bool WebMediaPlayerImpl::hasAudio() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- return pipeline_->HasAudio(); |
-} |
- |
-WebKit::WebSize WebMediaPlayerImpl::naturalSize() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- gfx::Size size; |
- pipeline_->GetNaturalVideoSize(&size); |
- return WebKit::WebSize(size); |
-} |
- |
-bool WebMediaPlayerImpl::paused() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- return pipeline_->GetPlaybackRate() == 0.0f; |
-} |
- |
-bool WebMediaPlayerImpl::seeking() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
- return false; |
- |
- return seeking_; |
-} |
- |
-double WebMediaPlayerImpl::duration() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
- return std::numeric_limits<double>::quiet_NaN(); |
- |
- return GetPipelineDuration(); |
-} |
- |
-double WebMediaPlayerImpl::currentTime() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF(); |
-} |
- |
-WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return network_state_; |
-} |
- |
-WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return ready_state_; |
-} |
- |
-const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- WebKit::WebTimeRanges web_ranges( |
- ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges())); |
- buffered_.swap(web_ranges); |
- return buffered_; |
-} |
- |
-double WebMediaPlayerImpl::maxTimeSeekable() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- // If we haven't even gotten to ReadyStateHaveMetadata yet then just |
- // return 0 so that the seekable range is empty. |
- if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) |
- return 0.0; |
- |
- // We don't support seeking in streaming media. |
- if (data_source_ && data_source_->IsStreaming()) |
- return 0.0; |
- return duration(); |
-} |
- |
-bool WebMediaPlayerImpl::didLoadingProgress() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- return pipeline_->DidLoadingProgress(); |
-} |
- |
-void WebMediaPlayerImpl::paint(WebCanvas* canvas, |
- const WebRect& rect, |
- unsigned char alpha) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- if (!accelerated_compositing_reported_) { |
- accelerated_compositing_reported_ = true; |
- // Normally paint() is only called in non-accelerated rendering, but there |
- // are exceptions such as webgl where compositing is used in the WebView but |
- // video frames are still rendered to a canvas. |
- UMA_HISTOGRAM_BOOLEAN( |
- "Media.AcceleratedCompositingActive", |
- frame_->view()->isAcceleratedCompositingActive()); |
- } |
- |
- // Avoid locking and potentially blocking the video rendering thread while |
- // painting in software. |
- scoped_refptr<media::VideoFrame> video_frame; |
- { |
- base::AutoLock auto_lock(lock_); |
- video_frame = current_frame_; |
- } |
- gfx::Rect gfx_rect(rect); |
- skcanvas_video_renderer_.Paint(video_frame.get(), canvas, gfx_rect, alpha); |
-} |
- |
-bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const { |
- if (data_source_) |
- return data_source_->HasSingleOrigin(); |
- return true; |
-} |
- |
-bool WebMediaPlayerImpl::didPassCORSAccessCheck() const { |
- if (data_source_) |
- return data_source_->DidPassCORSAccessCheck(); |
- return false; |
-} |
- |
-double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const { |
- return ConvertSecondsToTimestamp(timeValue).InSecondsF(); |
-} |
- |
-unsigned WebMediaPlayerImpl::decodedFrameCount() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- media::PipelineStatistics stats = pipeline_->GetStatistics(); |
- return stats.video_frames_decoded; |
-} |
- |
-unsigned WebMediaPlayerImpl::droppedFrameCount() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- media::PipelineStatistics stats = pipeline_->GetStatistics(); |
- return stats.video_frames_dropped; |
-} |
- |
-unsigned WebMediaPlayerImpl::audioDecodedByteCount() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- media::PipelineStatistics stats = pipeline_->GetStatistics(); |
- return stats.audio_bytes_decoded; |
-} |
- |
-unsigned WebMediaPlayerImpl::videoDecodedByteCount() const { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- media::PipelineStatistics stats = pipeline_->GetStatistics(); |
- return stats.video_bytes_decoded; |
-} |
- |
-void WebMediaPlayerImpl::SetVideoFrameProviderClient( |
- cc::VideoFrameProvider::Client* client) { |
- // This is called from both the main renderer thread and the compositor |
- // thread (when the main thread is blocked). |
- if (video_frame_provider_client_) |
- video_frame_provider_client_->StopUsingProvider(); |
- video_frame_provider_client_ = client; |
-} |
- |
-scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() { |
- base::AutoLock auto_lock(lock_); |
- return current_frame_; |
-} |
- |
-void WebMediaPlayerImpl::PutCurrentFrame( |
- const scoped_refptr<media::VideoFrame>& frame) { |
- if (!accelerated_compositing_reported_) { |
- accelerated_compositing_reported_ = true; |
- DCHECK(frame_->view()->isAcceleratedCompositingActive()); |
- UMA_HISTOGRAM_BOOLEAN("Media.AcceleratedCompositingActive", true); |
- } |
-} |
- |
-bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture( |
- WebKit::WebGraphicsContext3D* web_graphics_context, |
- unsigned int texture, |
- unsigned int level, |
- unsigned int internal_format, |
- unsigned int type, |
- bool premultiply_alpha, |
- bool flip_y) { |
- scoped_refptr<media::VideoFrame> video_frame; |
- { |
- base::AutoLock auto_lock(lock_); |
- video_frame = current_frame_; |
- } |
- |
- if (!video_frame.get()) |
- return false; |
- if (video_frame->format() != media::VideoFrame::NATIVE_TEXTURE) |
- return false; |
- if (video_frame->texture_target() != GL_TEXTURE_2D) |
- return false; |
- |
- scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder = |
- video_frame->texture_mailbox(); |
- |
- uint32 source_texture = web_graphics_context->createTexture(); |
- |
- web_graphics_context->waitSyncPoint(mailbox_holder->sync_point()); |
- web_graphics_context->bindTexture(GL_TEXTURE_2D, source_texture); |
- web_graphics_context->consumeTextureCHROMIUM(GL_TEXTURE_2D, |
- mailbox_holder->mailbox().name); |
- |
- // The video is stored in a unmultiplied format, so premultiply |
- // if necessary. |
- web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, |
- premultiply_alpha); |
- // Application itself needs to take care of setting the right flip_y |
- // value down to get the expected result. |
- // flip_y==true means to reverse the video orientation while |
- // flip_y==false means to keep the intrinsic orientation. |
- web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y); |
- web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D, |
- source_texture, |
- texture, |
- level, |
- internal_format, |
- type); |
- web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); |
- web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, |
- false); |
- |
- web_graphics_context->deleteTexture(source_texture); |
- |
- // The flush() operation is not necessary here. It is kept since the |
- // performance will be better when it is added than not. |
- web_graphics_context->flush(); |
- return true; |
-} |
- |
-// Helper functions to report media EME related stats to UMA. They follow the |
-// convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and |
-// UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is |
-// that UMA_* macros require the names to be constant throughout the process' |
-// lifetime. |
-static void EmeUMAHistogramEnumeration(const WebKit::WebString& key_system, |
- const std::string& method, |
- int sample, |
- int boundary_value) { |
- base::LinearHistogram::FactoryGet( |
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method, |
- 1, boundary_value, boundary_value + 1, |
- base::Histogram::kUmaTargetedHistogramFlag)->Add(sample); |
-} |
- |
-static void EmeUMAHistogramCounts(const WebKit::WebString& key_system, |
- const std::string& method, |
- int sample) { |
- // Use the same parameters as UMA_HISTOGRAM_COUNTS. |
- base::Histogram::FactoryGet( |
- kMediaEme + KeySystemNameForUMA(key_system) + "." + method, |
- 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample); |
-} |
- |
-// Helper enum for reporting generateKeyRequest/addKey histograms. |
-enum MediaKeyException { |
- kUnknownResultId, |
- kSuccess, |
- kKeySystemNotSupported, |
- kInvalidPlayerState, |
- kMaxMediaKeyException |
-}; |
- |
-static MediaKeyException MediaKeyExceptionForUMA( |
- WebMediaPlayer::MediaKeyException e) { |
- switch (e) { |
- case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported: |
- return kKeySystemNotSupported; |
- case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState: |
- return kInvalidPlayerState; |
- case WebMediaPlayer::MediaKeyExceptionNoError: |
- return kSuccess; |
- default: |
- return kUnknownResultId; |
- } |
-} |
- |
-// Helper for converting |key_system| name and exception |e| to a pair of enum |
-// values from above, for reporting to UMA. |
-static void ReportMediaKeyExceptionToUMA( |
- const std::string& method, |
- const WebString& key_system, |
- WebMediaPlayer::MediaKeyException e) { |
- MediaKeyException result_id = MediaKeyExceptionForUMA(e); |
- DCHECK_NE(result_id, kUnknownResultId) << e; |
- EmeUMAHistogramEnumeration( |
- key_system, method, result_id, kMaxMediaKeyException); |
-} |
- |
-WebMediaPlayer::MediaKeyException |
-WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system, |
- const unsigned char* init_data, |
- unsigned init_data_length) { |
- WebMediaPlayer::MediaKeyException e = |
- GenerateKeyRequestInternal(key_system, init_data, init_data_length); |
- ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e); |
- return e; |
-} |
- |
-WebMediaPlayer::MediaKeyException |
-WebMediaPlayerImpl::GenerateKeyRequestInternal( |
- const WebString& key_system, |
- const unsigned char* init_data, |
- unsigned init_data_length) { |
- DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": " |
- << std::string(reinterpret_cast<const char*>(init_data), |
- static_cast<size_t>(init_data_length)); |
- |
- if (!IsSupportedKeySystem(key_system)) |
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; |
- |
- // We do not support run-time switching between key systems for now. |
- if (current_key_system_.isEmpty()) { |
- if (!decryptor_->InitializeCDM(key_system.utf8())) |
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; |
- current_key_system_ = key_system; |
- } |
- else if (key_system != current_key_system_) { |
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; |
- } |
- |
- // TODO(xhwang): We assume all streams are from the same container (thus have |
- // the same "type") for now. In the future, the "type" should be passed down |
- // from the application. |
- if (!decryptor_->GenerateKeyRequest(init_data_type_, |
- init_data, init_data_length)) { |
- current_key_system_.reset(); |
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; |
- } |
- |
- return WebMediaPlayer::MediaKeyExceptionNoError; |
-} |
- |
-WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey( |
- const WebString& key_system, |
- const unsigned char* key, |
- unsigned key_length, |
- const unsigned char* init_data, |
- unsigned init_data_length, |
- const WebString& session_id) { |
- WebMediaPlayer::MediaKeyException e = AddKeyInternal( |
- key_system, key, key_length, init_data, init_data_length, session_id); |
- ReportMediaKeyExceptionToUMA("addKey", key_system, e); |
- return e; |
-} |
- |
-WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::AddKeyInternal( |
- const WebString& key_system, |
- const unsigned char* key, |
- unsigned key_length, |
- const unsigned char* init_data, |
- unsigned init_data_length, |
- const WebString& session_id) { |
- DCHECK(key); |
- DCHECK_GT(key_length, 0u); |
- DVLOG(1) << "addKey: " << key_system.utf8().data() << ": " |
- << std::string(reinterpret_cast<const char*>(key), |
- static_cast<size_t>(key_length)) << ", " |
- << std::string(reinterpret_cast<const char*>(init_data), |
- static_cast<size_t>(init_data_length)) |
- << " [" << session_id.utf8().data() << "]"; |
- |
- |
- if (!IsSupportedKeySystem(key_system)) |
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; |
- |
- if (current_key_system_.isEmpty() || key_system != current_key_system_) |
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; |
- |
- decryptor_->AddKey(key, key_length, |
- init_data, init_data_length, session_id.utf8()); |
- return WebMediaPlayer::MediaKeyExceptionNoError; |
-} |
- |
-WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest( |
- const WebString& key_system, |
- const WebString& session_id) { |
- WebMediaPlayer::MediaKeyException e = |
- CancelKeyRequestInternal(key_system, session_id); |
- ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e); |
- return e; |
-} |
- |
-WebMediaPlayer::MediaKeyException |
-WebMediaPlayerImpl::CancelKeyRequestInternal( |
- const WebString& key_system, |
- const WebString& session_id) { |
- if (!IsSupportedKeySystem(key_system)) |
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; |
- |
- if (current_key_system_.isEmpty() || key_system != current_key_system_) |
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; |
- |
- decryptor_->CancelKeyRequest(session_id.utf8()); |
- return WebMediaPlayer::MediaKeyExceptionNoError; |
-} |
- |
-void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() { |
- Destroy(); |
-} |
- |
-void WebMediaPlayerImpl::Repaint() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- bool size_changed = false; |
- { |
- base::AutoLock auto_lock(lock_); |
- std::swap(pending_size_change_, size_changed); |
- pending_repaint_ = false; |
- } |
- |
- if (size_changed) |
- GetClient()->sizeChanged(); |
- |
- GetClient()->repaint(); |
-} |
- |
-void WebMediaPlayerImpl::OnPipelineSeek(PipelineStatus status) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- starting_ = false; |
- seeking_ = false; |
- if (pending_seek_) { |
- pending_seek_ = false; |
- seek(pending_seek_seconds_); |
- return; |
- } |
- |
- if (status != media::PIPELINE_OK) { |
- OnPipelineError(status); |
- return; |
- } |
- |
- // Update our paused time. |
- if (paused_) |
- paused_time_ = pipeline_->GetMediaTime(); |
- |
- GetClient()->timeChanged(); |
-} |
- |
-void WebMediaPlayerImpl::OnPipelineEnded() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- GetClient()->timeChanged(); |
-} |
- |
-void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- DCHECK_NE(error, media::PIPELINE_OK); |
- |
- if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) { |
- // Any error that occurs before reaching ReadyStateHaveMetadata should |
- // be considered a format error. |
- SetNetworkState(WebMediaPlayer::NetworkStateFormatError); |
- Repaint(); |
- return; |
- } |
- |
- SetNetworkState(PipelineErrorToNetworkState(error)); |
- |
- if (error == media::PIPELINE_ERROR_DECRYPT) |
- EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1); |
- |
- // Repaint to trigger UI update. |
- Repaint(); |
-} |
- |
-void WebMediaPlayerImpl::OnPipelineBufferingState( |
- media::Pipeline::BufferingState buffering_state) { |
- DVLOG(1) << "OnPipelineBufferingState(" << buffering_state << ")"; |
- |
- switch (buffering_state) { |
- case media::Pipeline::kHaveMetadata: |
- SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
- |
- if (hasVideo() && GetClient()->needsWebLayerForVideo()) { |
- DCHECK(!video_weblayer_); |
- video_weblayer_.reset( |
- new webkit::WebLayerImpl(cc::VideoLayer::Create(this))); |
- GetClient()->setWebLayer(video_weblayer_.get()); |
- } |
- break; |
- case media::Pipeline::kPrerollCompleted: |
- // Only transition to ReadyStateHaveEnoughData if we don't have |
- // any pending seeks because the transition can cause Blink to |
- // report that the most recent seek has completed. |
- if (!pending_seek_) |
- SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
- break; |
- } |
- |
- // Repaint to trigger UI update. |
- Repaint(); |
-} |
- |
-void WebMediaPlayerImpl::OnDemuxerOpened( |
- scoped_ptr<WebKit::WebMediaSource> media_source) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- media_source->open(new WebMediaSourceClientImpl( |
- chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_))); |
-} |
- |
-void WebMediaPlayerImpl::OnKeyAdded(const std::string& session_id) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1); |
- GetClient()->keyAdded(current_key_system_, |
- WebString::fromUTF8(session_id)); |
-} |
- |
-void WebMediaPlayerImpl::OnNeedKey(const std::string& session_id, |
- const std::string& type, |
- scoped_ptr<uint8[]> init_data, |
- int init_data_size) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- // Do not fire NeedKey event if encrypted media is not enabled. |
- if (!decryptor_) |
- return; |
- |
- UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1); |
- |
- DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_); |
- if (init_data_type_.empty()) |
- init_data_type_ = type; |
- |
- GetClient()->keyNeeded(WebString(), |
- WebString::fromUTF8(session_id), |
- init_data.get(), |
- init_data_size); |
-} |
- |
-scoped_ptr<media::TextTrack> |
-WebMediaPlayerImpl::OnTextTrack(media::TextKind kind, |
- const std::string& label, |
- const std::string& language) { |
- typedef WebInbandTextTrackImpl::Kind webkind_t; |
- const webkind_t webkind = static_cast<webkind_t>(kind); |
- const WebKit::WebString weblabel = WebKit::WebString::fromUTF8(label); |
- const WebKit::WebString weblanguage = WebKit::WebString::fromUTF8(language); |
- |
- WebInbandTextTrackImpl* const text_track = |
- new WebInbandTextTrackImpl(webkind, weblabel, weblanguage, |
- text_track_index_++); |
- GetClient()->addTextTrack(text_track); |
- |
- return scoped_ptr<media::TextTrack>(new TextTrackImpl(text_track)); |
-} |
- |
-void WebMediaPlayerImpl::OnKeyError(const std::string& session_id, |
- media::MediaKeys::KeyError error_code, |
- int system_code) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- EmeUMAHistogramEnumeration(current_key_system_, "KeyError", |
- error_code, media::MediaKeys::kMaxKeyError); |
- |
- GetClient()->keyError( |
- current_key_system_, |
- WebString::fromUTF8(session_id), |
- static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code), |
- system_code); |
-} |
- |
-void WebMediaPlayerImpl::OnKeyMessage(const std::string& session_id, |
- const std::string& message, |
- const std::string& default_url) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- const GURL default_url_gurl(default_url); |
- DLOG_IF(WARNING, !default_url.empty() && !default_url_gurl.is_valid()) |
- << "Invalid URL in default_url: " << default_url; |
- |
- GetClient()->keyMessage(current_key_system_, |
- WebString::fromUTF8(session_id), |
- reinterpret_cast<const uint8*>(message.data()), |
- message.size(), |
- default_url_gurl); |
-} |
- |
-void WebMediaPlayerImpl::SetOpaque(bool opaque) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- GetClient()->setOpaque(opaque); |
-} |
- |
-void WebMediaPlayerImpl::DataSourceInitialized(const GURL& gurl, bool success) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- if (!success) { |
- SetNetworkState(WebMediaPlayer::NetworkStateFormatError); |
- Repaint(); |
- return; |
- } |
- |
- StartPipeline(NULL); |
-} |
- |
-void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) { |
- if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading) |
- SetNetworkState(WebMediaPlayer::NetworkStateIdle); |
- else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle) |
- SetNetworkState(WebMediaPlayer::NetworkStateLoading); |
- media_log_->AddEvent( |
- media_log_->CreateBooleanEvent( |
- media::MediaLogEvent::NETWORK_ACTIVITY_SET, |
- "is_downloading_data", is_downloading)); |
-} |
- |
-void WebMediaPlayerImpl::StartPipeline(WebKit::WebMediaSource* media_source) { |
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
- bool increase_preroll_on_underflow = true; |
- |
- // Keep track if this is a MSE or non-MSE playback. |
- UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback", (media_source != NULL)); |
- |
- // Figure out which demuxer to use. |
- if (!media_source) { |
- DCHECK(!chunk_demuxer_); |
- DCHECK(data_source_); |
- |
- demuxer_.reset(new media::FFmpegDemuxer( |
- media_loop_, data_source_.get(), |
- BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""))); |
- } else { |
- DCHECK(!chunk_demuxer_); |
- DCHECK(!data_source_); |
- |
- scoped_ptr<WebKit::WebMediaSource> ms(media_source); |
- chunk_demuxer_ = new media::ChunkDemuxer( |
- BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnDemuxerOpened, |
- base::Passed(&ms)), |
- BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""), |
- base::Bind(&WebMediaPlayerImpl::OnTextTrack, base::Unretained(this)), |
- base::Bind(&LogMediaSourceError, media_log_)); |
- demuxer_.reset(chunk_demuxer_); |
- |
- // Disable GpuVideoDecoder creation until it supports codec config changes. |
- // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed. |
- gpu_factories_ = NULL; |
- |
- // Disable preroll increases on underflow since the web application has no |
- // way to detect that this is happening and runs the risk of triggering |
- // unwanted garbage collection if it is to aggressive about appending data. |
- // TODO(acolwell): Remove this once http://crbug.com/144683 is fixed. |
- increase_preroll_on_underflow = false; |
- } |
- |
- scoped_ptr<media::FilterCollection> filter_collection( |
- new media::FilterCollection()); |
- filter_collection->SetDemuxer(demuxer_.get()); |
- |
- // Figure out if EME is enabled. |
- media::SetDecryptorReadyCB set_decryptor_ready_cb; |
- if (decryptor_) { |
- set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB, |
- base::Unretained(decryptor_.get())); |
- } |
- |
- // Create our audio decoders and renderer. |
- ScopedVector<media::AudioDecoder> audio_decoders; |
- audio_decoders.push_back(new media::FFmpegAudioDecoder(media_loop_)); |
- if (cmd_line->HasSwitch(switches::kEnableOpusPlayback)) { |
- audio_decoders.push_back(new media::OpusAudioDecoder(media_loop_)); |
- } |
- |
- scoped_ptr<media::AudioRenderer> audio_renderer( |
- new media::AudioRendererImpl(media_loop_, |
- audio_source_provider_.get(), |
- audio_decoders.Pass(), |
- set_decryptor_ready_cb, |
- increase_preroll_on_underflow)); |
- filter_collection->SetAudioRenderer(audio_renderer.Pass()); |
- |
- // Create our video decoders and renderer. |
- ScopedVector<media::VideoDecoder> video_decoders; |
- |
- if (gpu_factories_.get()) { |
- video_decoders.push_back(new media::GpuVideoDecoder( |
- media_loop_, gpu_factories_)); |
- } |
- |
- // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released |
- // (http://crbug.com/174287) . |
-#if !defined(MEDIA_DISABLE_LIBVPX) |
- video_decoders.push_back(new media::VpxVideoDecoder(media_loop_)); |
-#endif // !defined(MEDIA_DISABLE_LIBVPX) |
- |
- video_decoders.push_back(new media::FFmpegVideoDecoder(media_loop_)); |
- |
- scoped_ptr<media::VideoRenderer> video_renderer( |
- new media::VideoRendererBase( |
- media_loop_, |
- video_decoders.Pass(), |
- set_decryptor_ready_cb, |
- base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque), |
- true)); |
- filter_collection->SetVideoRenderer(video_renderer.Pass()); |
- |
- // ... and we're ready to go! |
- starting_ = true; |
- pipeline_->Start( |
- filter_collection.Pass(), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingState), |
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChange)); |
-} |
- |
-void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- DVLOG(1) << "SetNetworkState: " << state; |
- network_state_ = state; |
- // Always notify to ensure client has the latest value. |
- GetClient()->networkStateChanged(); |
-} |
- |
-void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- DVLOG(1) << "SetReadyState: " << state; |
- |
- if (state == WebMediaPlayer::ReadyStateHaveEnoughData && |
- is_local_source_ && |
- network_state_ == WebMediaPlayer::NetworkStateLoading) |
- SetNetworkState(WebMediaPlayer::NetworkStateLoaded); |
- |
- ready_state_ = state; |
- // Always notify to ensure client has the latest value. |
- GetClient()->readyStateChanged(); |
-} |
- |
-void WebMediaPlayerImpl::Destroy() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- |
- // Abort any pending IO so stopping the pipeline doesn't get blocked. |
- if (data_source_) |
- data_source_->Abort(); |
- if (chunk_demuxer_) { |
- chunk_demuxer_->Shutdown(); |
- chunk_demuxer_ = NULL; |
- } |
- |
- if (gpu_factories_.get()) { |
- gpu_factories_->Abort(); |
- gpu_factories_ = NULL; |
- } |
- |
- // Make sure to kill the pipeline so there's no more media threads running. |
- // Note: stopping the pipeline might block for a long time. |
- base::WaitableEvent waiter(false, false); |
- pipeline_->Stop(base::Bind( |
- &base::WaitableEvent::Signal, base::Unretained(&waiter))); |
- waiter.Wait(); |
- |
- // Let V8 know we are not using extra resources anymore. |
- if (incremented_externally_allocated_memory_) { |
- v8::V8::AdjustAmountOfExternalAllocatedMemory(-kPlayerExtraMemory); |
- incremented_externally_allocated_memory_ = false; |
- } |
- |
- // Release any final references now that everything has stopped. |
- pipeline_.reset(); |
- demuxer_.reset(); |
- data_source_.reset(); |
-} |
- |
-WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- DCHECK(client_); |
- return client_; |
-} |
- |
-WebKit::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() { |
- return audio_source_provider_.get(); |
-} |
- |
-void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() { |
- DCHECK(main_loop_->BelongsToCurrentThread()); |
- incremented_externally_allocated_memory_ = true; |
- v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory); |
-} |
- |
-double WebMediaPlayerImpl::GetPipelineDuration() const { |
- base::TimeDelta duration = pipeline_->GetMediaDuration(); |
- |
- // Return positive infinity if the resource is unbounded. |
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration |
- if (duration == media::kInfiniteDuration()) |
- return std::numeric_limits<double>::infinity(); |
- |
- return duration.InSecondsF(); |
-} |
- |
-void WebMediaPlayerImpl::OnDurationChange() { |
- if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
- return; |
- |
- GetClient()->durationChanged(); |
-} |
- |
-void WebMediaPlayerImpl::FrameReady( |
- const scoped_refptr<media::VideoFrame>& frame) { |
- base::AutoLock auto_lock(lock_); |
- |
- if (current_frame_.get() && |
- current_frame_->natural_size() != frame->natural_size() && |
- !pending_size_change_) { |
- pending_size_change_ = true; |
- } |
- |
- current_frame_ = frame; |
- |
- if (pending_repaint_) |
- return; |
- |
- pending_repaint_ = true; |
- main_loop_->PostTask(FROM_HERE, base::Bind( |
- &WebMediaPlayerImpl::Repaint, AsWeakPtr())); |
-} |
- |
-} // namespace webkit_media |