Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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/glue/webmediaplayer_impl.h"
      6 
      7 #include <limits>
      8 #include <string>
      9 
     10 #include "base/callback.h"
     11 #include "base/command_line.h"
     12 #include "media/base/composite_data_source_factory.h"
     13 #include "media/base/filter_collection.h"
     14 #include "media/base/limits.h"
     15 #include "media/base/media_format.h"
     16 #include "media/base/media_switches.h"
     17 #include "media/base/pipeline_impl.h"
     18 #include "media/base/video_frame.h"
     19 #include "media/filters/adaptive_demuxer.h"
     20 #include "media/filters/ffmpeg_audio_decoder.h"
     21 #include "media/filters/ffmpeg_demuxer_factory.h"
     22 #include "media/filters/ffmpeg_video_decoder.h"
     23 #include "media/filters/rtc_video_decoder.h"
     24 #include "media/filters/null_audio_renderer.h"
     25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
     26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
     27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
     28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h"
     29 #include "webkit/glue/media/buffered_data_source.h"
     30 #include "webkit/glue/media/simple_data_source.h"
     31 #include "webkit/glue/media/video_renderer_impl.h"
     32 #include "webkit/glue/media/web_video_renderer.h"
     33 #include "webkit/glue/webvideoframe_impl.h"
     34 
     35 using WebKit::WebCanvas;
     36 using WebKit::WebRect;
     37 using WebKit::WebSize;
     38 using media::PipelineStatus;
     39 
     40 namespace {
     41 
     42 // Limits the maximum outstanding repaints posted on render thread.
     43 // This number of 50 is a guess, it does not take too much memory on the task
     44 // queue but gives up a pretty good latency on repaint.
     45 const int kMaxOutstandingRepaints = 50;
     46 
     47 // Limits the range of playback rate.
     48 //
     49 // TODO(kylep): Revisit these.
     50 //
     51 // Vista has substantially lower performance than XP or Windows7.  If you speed
     52 // up a video too much, it can't keep up, and rendering stops updating except on
     53 // the time bar. For really high speeds, audio becomes a bottleneck and we just
     54 // use up the data we have, which may not achieve the speed requested, but will
     55 // not crash the tab.
     56 //
     57 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
     58 // like a busy loop). It gets unresponsive, although its not completely dead.
     59 //
     60 // Also our timers are not very accurate (especially for ogg), which becomes
     61 // evident at low speeds and on Vista. Since other speeds are risky and outside
     62 // the norms, we think 1/16x to 16x is a safe and useful range for now.
     63 const float kMinRate = 0.0625f;
     64 const float kMaxRate = 16.0f;
     65 
     66 // Platform independent method for converting and rounding floating point
     67 // seconds to an int64 timestamp.
     68 //
     69 // Refer to https://bugs.webkit.org/show_bug.cgi?id=52697 for details.
     70 base::TimeDelta ConvertSecondsToTimestamp(float seconds) {
     71   float microseconds = seconds * base::Time::kMicrosecondsPerSecond;
     72   float integer = ceilf(microseconds);
     73   float difference = integer - microseconds;
     74 
     75   // Round down if difference is large enough.
     76   if ((microseconds > 0 && difference > 0.5f) ||
     77       (microseconds <= 0 && difference >= 0.5f)) {
     78     integer -= 1.0f;
     79   }
     80 
     81   // Now we can safely cast to int64 microseconds.
     82   return base::TimeDelta::FromMicroseconds(static_cast<int64>(integer));
     83 }
     84 
     85 }  // namespace
     86 
     87 namespace webkit_glue {
     88 
     89 /////////////////////////////////////////////////////////////////////////////
     90 // WebMediaPlayerImpl::Proxy implementation
     91 
     92 WebMediaPlayerImpl::Proxy::Proxy(MessageLoop* render_loop,
     93                                  WebMediaPlayerImpl* webmediaplayer)
     94     : render_loop_(render_loop),
     95       webmediaplayer_(webmediaplayer),
     96       outstanding_repaints_(0) {
     97   DCHECK(render_loop_);
     98   DCHECK(webmediaplayer_);
     99 }
    100 
    101 WebMediaPlayerImpl::Proxy::~Proxy() {
    102   Detach();
    103 }
    104 
    105 void WebMediaPlayerImpl::Proxy::Repaint() {
    106   base::AutoLock auto_lock(lock_);
    107   if (outstanding_repaints_ < kMaxOutstandingRepaints) {
    108     ++outstanding_repaints_;
    109 
    110     render_loop_->PostTask(FROM_HERE,
    111         NewRunnableMethod(this, &WebMediaPlayerImpl::Proxy::RepaintTask));
    112   }
    113 }
    114 
    115 void WebMediaPlayerImpl::Proxy::SetVideoRenderer(
    116     scoped_refptr<WebVideoRenderer> video_renderer) {
    117   video_renderer_ = video_renderer;
    118 }
    119 
    120 WebDataSourceBuildObserverHack* WebMediaPlayerImpl::Proxy::GetBuildObserver() {
    121   if (!build_observer_.get())
    122     build_observer_.reset(NewCallback(this, &Proxy::AddDataSource));
    123   return build_observer_.get();
    124 }
    125 
    126 void WebMediaPlayerImpl::Proxy::Paint(SkCanvas* canvas,
    127                                       const gfx::Rect& dest_rect) {
    128   DCHECK(MessageLoop::current() == render_loop_);
    129   if (video_renderer_) {
    130     video_renderer_->Paint(canvas, dest_rect);
    131   }
    132 }
    133 
    134 void WebMediaPlayerImpl::Proxy::SetSize(const gfx::Rect& rect) {
    135   DCHECK(MessageLoop::current() == render_loop_);
    136   if (video_renderer_) {
    137     video_renderer_->SetRect(rect);
    138   }
    139 }
    140 
    141 bool WebMediaPlayerImpl::Proxy::HasSingleOrigin() {
    142   DCHECK(MessageLoop::current() == render_loop_);
    143 
    144   base::AutoLock auto_lock(data_sources_lock_);
    145 
    146   for (DataSourceList::iterator itr = data_sources_.begin();
    147        itr != data_sources_.end();
    148        itr++) {
    149     if (!(*itr)->HasSingleOrigin())
    150       return false;
    151   }
    152   return true;
    153 }
    154 
    155 void WebMediaPlayerImpl::Proxy::AbortDataSources() {
    156   DCHECK(MessageLoop::current() == render_loop_);
    157   base::AutoLock auto_lock(data_sources_lock_);
    158 
    159   for (DataSourceList::iterator itr = data_sources_.begin();
    160        itr != data_sources_.end();
    161        itr++) {
    162     (*itr)->Abort();
    163   }
    164 }
    165 
    166 void WebMediaPlayerImpl::Proxy::Detach() {
    167   DCHECK(MessageLoop::current() == render_loop_);
    168   webmediaplayer_ = NULL;
    169   video_renderer_ = NULL;
    170 
    171   {
    172     base::AutoLock auto_lock(data_sources_lock_);
    173     data_sources_.clear();
    174   }
    175 }
    176 
    177 void WebMediaPlayerImpl::Proxy::PipelineInitializationCallback(
    178     PipelineStatus status) {
    179   render_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    180       this, &WebMediaPlayerImpl::Proxy::PipelineInitializationTask, status));
    181 }
    182 
    183 void WebMediaPlayerImpl::Proxy::PipelineSeekCallback(PipelineStatus status) {
    184   render_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    185       this, &WebMediaPlayerImpl::Proxy::PipelineSeekTask, status));
    186 }
    187 
    188 void WebMediaPlayerImpl::Proxy::PipelineEndedCallback(PipelineStatus status) {
    189   render_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    190       this, &WebMediaPlayerImpl::Proxy::PipelineEndedTask, status));
    191 }
    192 
    193 void WebMediaPlayerImpl::Proxy::PipelineErrorCallback(PipelineStatus error) {
    194   DCHECK_NE(error, media::PIPELINE_OK);
    195   render_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    196       this, &WebMediaPlayerImpl::Proxy::PipelineErrorTask, error));
    197 }
    198 
    199 void WebMediaPlayerImpl::Proxy::NetworkEventCallback(PipelineStatus status) {
    200   render_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    201       this, &WebMediaPlayerImpl::Proxy::NetworkEventTask, status));
    202 }
    203 
    204 void WebMediaPlayerImpl::Proxy::AddDataSource(WebDataSource* data_source) {
    205   base::AutoLock auto_lock(data_sources_lock_);
    206   data_sources_.push_back(make_scoped_refptr(data_source));
    207 }
    208 
    209 void WebMediaPlayerImpl::Proxy::RepaintTask() {
    210   DCHECK(MessageLoop::current() == render_loop_);
    211   {
    212     base::AutoLock auto_lock(lock_);
    213     --outstanding_repaints_;
    214     DCHECK_GE(outstanding_repaints_, 0);
    215   }
    216   if (webmediaplayer_) {
    217     webmediaplayer_->Repaint();
    218   }
    219 }
    220 
    221 void WebMediaPlayerImpl::Proxy::PipelineInitializationTask(
    222     PipelineStatus status) {
    223   DCHECK(MessageLoop::current() == render_loop_);
    224   if (webmediaplayer_) {
    225     webmediaplayer_->OnPipelineInitialize(status);
    226   }
    227 }
    228 
    229 void WebMediaPlayerImpl::Proxy::PipelineSeekTask(PipelineStatus status) {
    230   DCHECK(MessageLoop::current() == render_loop_);
    231   if (webmediaplayer_) {
    232     webmediaplayer_->OnPipelineSeek(status);
    233   }
    234 }
    235 
    236 void WebMediaPlayerImpl::Proxy::PipelineEndedTask(PipelineStatus status) {
    237   DCHECK(MessageLoop::current() == render_loop_);
    238   if (webmediaplayer_) {
    239     webmediaplayer_->OnPipelineEnded(status);
    240   }
    241 }
    242 
    243 void WebMediaPlayerImpl::Proxy::PipelineErrorTask(PipelineStatus error) {
    244   DCHECK(MessageLoop::current() == render_loop_);
    245   if (webmediaplayer_) {
    246     webmediaplayer_->OnPipelineError(error);
    247   }
    248 }
    249 
    250 void WebMediaPlayerImpl::Proxy::NetworkEventTask(PipelineStatus status) {
    251   DCHECK(MessageLoop::current() == render_loop_);
    252   if (webmediaplayer_) {
    253     webmediaplayer_->OnNetworkEvent(status);
    254   }
    255 }
    256 
    257 void WebMediaPlayerImpl::Proxy::GetCurrentFrame(
    258     scoped_refptr<media::VideoFrame>* frame_out) {
    259   if (video_renderer_)
    260     video_renderer_->GetCurrentFrame(frame_out);
    261 }
    262 
    263 void WebMediaPlayerImpl::Proxy::PutCurrentFrame(
    264     scoped_refptr<media::VideoFrame> frame) {
    265   if (video_renderer_)
    266     video_renderer_->PutCurrentFrame(frame);
    267 }
    268 
    269 /////////////////////////////////////////////////////////////////////////////
    270 // WebMediaPlayerImpl implementation
    271 
    272 WebMediaPlayerImpl::WebMediaPlayerImpl(
    273     WebKit::WebMediaPlayerClient* client,
    274     media::FilterCollection* collection,
    275     media::MessageLoopFactory* message_loop_factory)
    276     : network_state_(WebKit::WebMediaPlayer::Empty),
    277       ready_state_(WebKit::WebMediaPlayer::HaveNothing),
    278       main_loop_(NULL),
    279       filter_collection_(collection),
    280       pipeline_(NULL),
    281       message_loop_factory_(message_loop_factory),
    282       paused_(true),
    283       seeking_(false),
    284       playback_rate_(0.0f),
    285       client_(client),
    286       proxy_(NULL) {
    287   // Saves the current message loop.
    288   DCHECK(!main_loop_);
    289   main_loop_ = MessageLoop::current();
    290 }
    291 
    292 bool WebMediaPlayerImpl::Initialize(
    293     WebKit::WebFrame* frame,
    294     bool use_simple_data_source,
    295     scoped_refptr<WebVideoRenderer> web_video_renderer) {
    296   MessageLoop* pipeline_message_loop =
    297       message_loop_factory_->GetMessageLoop("PipelineThread");
    298   if (!pipeline_message_loop) {
    299     NOTREACHED() << "Could not start PipelineThread";
    300     return false;
    301   }
    302 
    303   pipeline_ = new media::PipelineImpl(pipeline_message_loop);
    304 
    305   // Also we want to be notified of |main_loop_| destruction.
    306   main_loop_->AddDestructionObserver(this);
    307 
    308   // Creates the proxy.
    309   proxy_ = new Proxy(main_loop_, this);
    310   web_video_renderer->SetWebMediaPlayerImplProxy(proxy_);
    311   proxy_->SetVideoRenderer(web_video_renderer);
    312 
    313   // Set our pipeline callbacks.
    314   pipeline_->Init(
    315       NewCallback(proxy_.get(),
    316                   &WebMediaPlayerImpl::Proxy::PipelineEndedCallback),
    317       NewCallback(proxy_.get(),
    318                   &WebMediaPlayerImpl::Proxy::PipelineErrorCallback),
    319       NewCallback(proxy_.get(),
    320                   &WebMediaPlayerImpl::Proxy::NetworkEventCallback));
    321 
    322   // A simple data source that keeps all data in memory.
    323   scoped_ptr<media::DataSourceFactory> simple_data_source_factory(
    324       SimpleDataSource::CreateFactory(MessageLoop::current(), frame,
    325                                       proxy_->GetBuildObserver()));
    326 
    327   // A sophisticated data source that does memory caching.
    328   scoped_ptr<media::DataSourceFactory> buffered_data_source_factory(
    329       BufferedDataSource::CreateFactory(MessageLoop::current(), frame,
    330                                         proxy_->GetBuildObserver()));
    331 
    332   scoped_ptr<media::CompositeDataSourceFactory> data_source_factory(
    333       new media::CompositeDataSourceFactory());
    334 
    335   if (use_simple_data_source) {
    336     data_source_factory->AddFactory(simple_data_source_factory.release());
    337     data_source_factory->AddFactory(buffered_data_source_factory.release());
    338   } else {
    339     data_source_factory->AddFactory(buffered_data_source_factory.release());
    340     data_source_factory->AddFactory(simple_data_source_factory.release());
    341   }
    342 
    343   scoped_ptr<media::DemuxerFactory> demuxer_factory(
    344       new media::FFmpegDemuxerFactory(data_source_factory.release(),
    345                                       pipeline_message_loop));
    346   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdaptive)) {
    347     demuxer_factory.reset(new media::AdaptiveDemuxerFactory(
    348         demuxer_factory.release()));
    349   }
    350   filter_collection_->SetDemuxerFactory(demuxer_factory.release());
    351 
    352   // Add in the default filter factories.
    353   filter_collection_->AddAudioDecoder(new media::FFmpegAudioDecoder(
    354       message_loop_factory_->GetMessageLoop("AudioDecoderThread")));
    355   filter_collection_->AddVideoDecoder(new media::FFmpegVideoDecoder(
    356       message_loop_factory_->GetMessageLoop("VideoDecoderThread"), NULL));
    357   filter_collection_->AddAudioRenderer(new media::NullAudioRenderer());
    358 
    359   return true;
    360 }
    361 
    362 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
    363   Destroy();
    364 
    365   // Finally tell the |main_loop_| we don't want to be notified of destruction
    366   // event.
    367   if (main_loop_) {
    368     main_loop_->RemoveDestructionObserver(this);
    369   }
    370 }
    371 
    372 void WebMediaPlayerImpl::load(const WebKit::WebURL& url) {
    373   DCHECK(MessageLoop::current() == main_loop_);
    374   DCHECK(proxy_);
    375 
    376   if (media::RTCVideoDecoder::IsUrlSupported(url.spec())) {
    377     // Remove the default decoder
    378     scoped_refptr<media::VideoDecoder> old_videodecoder;
    379     filter_collection_->SelectVideoDecoder(&old_videodecoder);
    380     media::RTCVideoDecoder* rtc_video_decoder =
    381         new media::RTCVideoDecoder(
    382              message_loop_factory_->GetMessageLoop("VideoDecoderThread"),
    383              url.spec());
    384     filter_collection_->AddVideoDecoder(rtc_video_decoder);
    385   }
    386 
    387   // Handle any volume changes that occured before load().
    388   setVolume(GetClient()->volume());
    389   // Get the preload value.
    390   setPreload(GetClient()->preload());
    391 
    392   // Initialize the pipeline.
    393   SetNetworkState(WebKit::WebMediaPlayer::Loading);
    394   SetReadyState(WebKit::WebMediaPlayer::HaveNothing);
    395   pipeline_->Start(
    396       filter_collection_.release(),
    397       url.spec(),
    398       NewCallback(proxy_.get(),
    399                   &WebMediaPlayerImpl::Proxy::PipelineInitializationCallback));
    400 }
    401 
    402 void WebMediaPlayerImpl::cancelLoad() {
    403   DCHECK(MessageLoop::current() == main_loop_);
    404 }
    405 
    406 void WebMediaPlayerImpl::play() {
    407   DCHECK(MessageLoop::current() == main_loop_);
    408 
    409   paused_ = false;
    410   pipeline_->SetPlaybackRate(playback_rate_);
    411 }
    412 
    413 void WebMediaPlayerImpl::pause() {
    414   DCHECK(MessageLoop::current() == main_loop_);
    415 
    416   paused_ = true;
    417   pipeline_->SetPlaybackRate(0.0f);
    418   paused_time_ = pipeline_->GetCurrentTime();
    419 }
    420 
    421 bool WebMediaPlayerImpl::supportsFullscreen() const {
    422   DCHECK(MessageLoop::current() == main_loop_);
    423   return true;
    424 }
    425 
    426 bool WebMediaPlayerImpl::supportsSave() const {
    427   DCHECK(MessageLoop::current() == main_loop_);
    428   return true;
    429 }
    430 
    431 void WebMediaPlayerImpl::seek(float seconds) {
    432   DCHECK(MessageLoop::current() == main_loop_);
    433 
    434   // WebKit fires a seek(0) at the very start, however pipeline already does a
    435   // seek(0) internally.  Avoid doing seek(0) the second time because this will
    436   // cause extra pre-rolling and will break servers without range request
    437   // support.
    438   //
    439   // We still have to notify WebKit that time has changed otherwise
    440   // HTMLMediaElement gets into an inconsistent state.
    441   if (pipeline_->GetCurrentTime().ToInternalValue() == 0 && seconds == 0) {
    442     GetClient()->timeChanged();
    443     return;
    444   }
    445 
    446   base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
    447 
    448   // Update our paused time.
    449   if (paused_) {
    450     paused_time_ = seek_time;
    451   }
    452 
    453   seeking_ = true;
    454 
    455   // Kick off the asynchronous seek!
    456   pipeline_->Seek(
    457       seek_time,
    458       NewCallback(proxy_.get(),
    459                   &WebMediaPlayerImpl::Proxy::PipelineSeekCallback));
    460 }
    461 
    462 void WebMediaPlayerImpl::setEndTime(float seconds) {
    463   DCHECK(MessageLoop::current() == main_loop_);
    464 
    465   // TODO(hclam): add method call when it has been implemented.
    466   return;
    467 }
    468 
    469 void WebMediaPlayerImpl::setRate(float rate) {
    470   DCHECK(MessageLoop::current() == main_loop_);
    471 
    472   // TODO(kylep): Remove when support for negatives is added. Also, modify the
    473   // following checks so rewind uses reasonable values also.
    474   if (rate < 0.0f)
    475     return;
    476 
    477   // Limit rates to reasonable values by clamping.
    478   if (rate != 0.0f) {
    479     if (rate < kMinRate)
    480       rate = kMinRate;
    481     else if (rate > kMaxRate)
    482       rate = kMaxRate;
    483   }
    484 
    485   playback_rate_ = rate;
    486   if (!paused_) {
    487     pipeline_->SetPlaybackRate(rate);
    488   }
    489 }
    490 
    491 void WebMediaPlayerImpl::setVolume(float volume) {
    492   DCHECK(MessageLoop::current() == main_loop_);
    493 
    494   pipeline_->SetVolume(volume);
    495 }
    496 
    497 void WebMediaPlayerImpl::setVisible(bool visible) {
    498   DCHECK(MessageLoop::current() == main_loop_);
    499 
    500   // TODO(hclam): add appropriate method call when pipeline has it implemented.
    501   return;
    502 }
    503 
    504 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
    505         COMPILE_ASSERT(int(WebKit::WebMediaPlayer::webkit_name) == \
    506                        int(media::chromium_name), \
    507                        mismatching_enums)
    508 COMPILE_ASSERT_MATCHING_ENUM(None, NONE);
    509 COMPILE_ASSERT_MATCHING_ENUM(MetaData, METADATA);
    510 COMPILE_ASSERT_MATCHING_ENUM(Auto, AUTO);
    511 
    512 void WebMediaPlayerImpl::setPreload(WebKit::WebMediaPlayer::Preload preload) {
    513   DCHECK(MessageLoop::current() == main_loop_);
    514 
    515   pipeline_->SetPreload(static_cast<media::Preload>(preload));
    516 }
    517 
    518 bool WebMediaPlayerImpl::totalBytesKnown() {
    519   DCHECK(MessageLoop::current() == main_loop_);
    520 
    521   return pipeline_->GetTotalBytes() != 0;
    522 }
    523 
    524 bool WebMediaPlayerImpl::hasVideo() const {
    525   DCHECK(MessageLoop::current() == main_loop_);
    526 
    527   return pipeline_->HasVideo();
    528 }
    529 
    530 bool WebMediaPlayerImpl::hasAudio() const {
    531   DCHECK(MessageLoop::current() == main_loop_);
    532 
    533   return pipeline_->HasAudio();
    534 }
    535 
    536 WebKit::WebSize WebMediaPlayerImpl::naturalSize() const {
    537   DCHECK(MessageLoop::current() == main_loop_);
    538 
    539   size_t width, height;
    540   pipeline_->GetVideoSize(&width, &height);
    541   return WebKit::WebSize(width, height);
    542 }
    543 
    544 bool WebMediaPlayerImpl::paused() const {
    545   DCHECK(MessageLoop::current() == main_loop_);
    546 
    547   return pipeline_->GetPlaybackRate() == 0.0f;
    548 }
    549 
    550 bool WebMediaPlayerImpl::seeking() const {
    551   DCHECK(MessageLoop::current() == main_loop_);
    552 
    553   if (ready_state_ == WebKit::WebMediaPlayer::HaveNothing)
    554     return false;
    555 
    556   return seeking_;
    557 }
    558 
    559 float WebMediaPlayerImpl::duration() const {
    560   DCHECK(MessageLoop::current() == main_loop_);
    561 
    562   base::TimeDelta duration = pipeline_->GetMediaDuration();
    563   if (duration.InMicroseconds() == media::Limits::kMaxTimeInMicroseconds)
    564     return std::numeric_limits<float>::infinity();
    565   return static_cast<float>(duration.InSecondsF());
    566 }
    567 
    568 float WebMediaPlayerImpl::currentTime() const {
    569   DCHECK(MessageLoop::current() == main_loop_);
    570 
    571   if (paused_) {
    572     return static_cast<float>(paused_time_.InSecondsF());
    573   }
    574   return static_cast<float>(pipeline_->GetCurrentTime().InSecondsF());
    575 }
    576 
    577 int WebMediaPlayerImpl::dataRate() const {
    578   DCHECK(MessageLoop::current() == main_loop_);
    579 
    580   // TODO(hclam): Add this method call if pipeline has it in the interface.
    581   return 0;
    582 }
    583 
    584 WebKit::WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
    585   return network_state_;
    586 }
    587 
    588 WebKit::WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
    589   return ready_state_;
    590 }
    591 
    592 const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() {
    593   DCHECK(MessageLoop::current() == main_loop_);
    594 
    595   // Update buffered_ with the most recent buffered time.
    596   if (buffered_.size() > 0) {
    597     float buffered_time = static_cast<float>(
    598         pipeline_->GetBufferedTime().InSecondsF());
    599     if (buffered_time >= buffered_[0].start)
    600       buffered_[0].end = buffered_time;
    601   }
    602 
    603   return buffered_;
    604 }
    605 
    606 float WebMediaPlayerImpl::maxTimeSeekable() const {
    607   DCHECK(MessageLoop::current() == main_loop_);
    608 
    609   // If we are performing streaming, we report that we cannot seek at all.
    610   // We are using this flag to indicate if the data source supports seeking
    611   // or not. We should be able to seek even if we are performing streaming.
    612   // TODO(hclam): We need to update this when we have better caching.
    613   if (pipeline_->IsStreaming())
    614     return 0.0f;
    615   return static_cast<float>(pipeline_->GetMediaDuration().InSecondsF());
    616 }
    617 
    618 unsigned long long WebMediaPlayerImpl::bytesLoaded() const {
    619   DCHECK(MessageLoop::current() == main_loop_);
    620 
    621   return pipeline_->GetBufferedBytes();
    622 }
    623 
    624 unsigned long long WebMediaPlayerImpl::totalBytes() const {
    625   DCHECK(MessageLoop::current() == main_loop_);
    626 
    627   return pipeline_->GetTotalBytes();
    628 }
    629 
    630 void WebMediaPlayerImpl::setSize(const WebSize& size) {
    631   DCHECK(MessageLoop::current() == main_loop_);
    632   DCHECK(proxy_);
    633 
    634   proxy_->SetSize(gfx::Rect(0, 0, size.width, size.height));
    635 }
    636 
    637 void WebMediaPlayerImpl::paint(WebCanvas* canvas,
    638                                const WebRect& rect) {
    639   DCHECK(MessageLoop::current() == main_loop_);
    640   DCHECK(proxy_);
    641 
    642 #if WEBKIT_USING_SKIA
    643   proxy_->Paint(canvas, rect);
    644 #elif WEBKIT_USING_CG
    645   // Get the current scaling in X and Y.
    646   CGAffineTransform mat = CGContextGetCTM(canvas);
    647   float scale_x = sqrt(mat.a * mat.a + mat.b * mat.b);
    648   float scale_y = sqrt(mat.c * mat.c + mat.d * mat.d);
    649   float inverse_scale_x = SkScalarNearlyZero(scale_x) ? 0.0f : 1.0f / scale_x;
    650   float inverse_scale_y = SkScalarNearlyZero(scale_y) ? 0.0f : 1.0f / scale_y;
    651   int scaled_width = static_cast<int>(rect.width * fabs(scale_x));
    652   int scaled_height = static_cast<int>(rect.height * fabs(scale_y));
    653 
    654   // Make sure we don't create a huge canvas.
    655   // TODO(hclam): Respect the aspect ratio.
    656   if (scaled_width > static_cast<int>(media::Limits::kMaxCanvas))
    657     scaled_width = media::Limits::kMaxCanvas;
    658   if (scaled_height > static_cast<int>(media::Limits::kMaxCanvas))
    659     scaled_height = media::Limits::kMaxCanvas;
    660 
    661   // If there is no preexisting platform canvas, or if the size has
    662   // changed, recreate the canvas.  This is to avoid recreating the bitmap
    663   // buffer over and over for each frame of video.
    664   if (!skia_canvas_.get() ||
    665       skia_canvas_->getDevice()->width() != scaled_width ||
    666       skia_canvas_->getDevice()->height() != scaled_height) {
    667     skia_canvas_.reset(
    668         new skia::PlatformCanvas(scaled_width, scaled_height, true));
    669   }
    670 
    671   // Draw to our temporary skia canvas.
    672   gfx::Rect normalized_rect(scaled_width, scaled_height);
    673   proxy_->Paint(skia_canvas_.get(), normalized_rect);
    674 
    675   // The mac coordinate system is flipped vertical from the normal skia
    676   // coordinates.  During painting of the frame, flip the coordinates
    677   // system and, for simplicity, also translate the clip rectangle to
    678   // start at 0,0.
    679   CGContextSaveGState(canvas);
    680   CGContextTranslateCTM(canvas, rect.x, rect.height + rect.y);
    681   CGContextScaleCTM(canvas, inverse_scale_x, -inverse_scale_y);
    682 
    683   // We need a local variable CGRect version for DrawToContext.
    684   CGRect normalized_cgrect =
    685       CGRectMake(normalized_rect.x(), normalized_rect.y(),
    686                  normalized_rect.width(), normalized_rect.height());
    687 
    688   // Copy the frame rendered to our temporary skia canvas onto the passed in
    689   // canvas.
    690   skia_canvas_->getTopPlatformDevice().DrawToContext(canvas, 0, 0,
    691                                                      &normalized_cgrect);
    692 
    693   CGContextRestoreGState(canvas);
    694 #else
    695   NOTIMPLEMENTED() << "We only support rendering to skia or CG";
    696 #endif
    697 }
    698 
    699 bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
    700   if (proxy_)
    701     return proxy_->HasSingleOrigin();
    702   return true;
    703 }
    704 
    705 WebKit::WebMediaPlayer::MovieLoadType
    706     WebMediaPlayerImpl::movieLoadType() const {
    707   DCHECK(MessageLoop::current() == main_loop_);
    708 
    709   // TODO(hclam): If the pipeline is performing streaming, we say that this is
    710   // a live stream. But instead it should be a StoredStream if we have proper
    711   // caching.
    712   if (pipeline_->IsStreaming())
    713     return WebKit::WebMediaPlayer::LiveStream;
    714   return WebKit::WebMediaPlayer::Unknown;
    715 }
    716 
    717 unsigned WebMediaPlayerImpl::decodedFrameCount() const {
    718   DCHECK(MessageLoop::current() == main_loop_);
    719 
    720   media::PipelineStatistics stats = pipeline_->GetStatistics();
    721   return stats.video_frames_decoded;
    722 }
    723 
    724 unsigned WebMediaPlayerImpl::droppedFrameCount() const {
    725   DCHECK(MessageLoop::current() == main_loop_);
    726 
    727   media::PipelineStatistics stats = pipeline_->GetStatistics();
    728   return stats.video_frames_dropped;
    729 }
    730 
    731 unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
    732   DCHECK(MessageLoop::current() == main_loop_);
    733 
    734   media::PipelineStatistics stats = pipeline_->GetStatistics();
    735   return stats.audio_bytes_decoded;
    736 }
    737 
    738 unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
    739   DCHECK(MessageLoop::current() == main_loop_);
    740 
    741   media::PipelineStatistics stats = pipeline_->GetStatistics();
    742   return stats.video_bytes_decoded;
    743 }
    744 
    745 WebKit::WebVideoFrame* WebMediaPlayerImpl::getCurrentFrame() {
    746   scoped_refptr<media::VideoFrame> video_frame;
    747   proxy_->GetCurrentFrame(&video_frame);
    748   if (video_frame.get())
    749     return new WebVideoFrameImpl(video_frame);
    750   return NULL;
    751 }
    752 
    753 void WebMediaPlayerImpl::putCurrentFrame(
    754     WebKit::WebVideoFrame* web_video_frame) {
    755   if (web_video_frame) {
    756     scoped_refptr<media::VideoFrame> video_frame(
    757         WebVideoFrameImpl::toVideoFrame(web_video_frame));
    758     proxy_->PutCurrentFrame(video_frame);
    759     delete web_video_frame;
    760   }
    761 }
    762 
    763 void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
    764   Destroy();
    765   main_loop_ = NULL;
    766 }
    767 
    768 void WebMediaPlayerImpl::Repaint() {
    769   DCHECK(MessageLoop::current() == main_loop_);
    770   GetClient()->repaint();
    771 }
    772 
    773 void WebMediaPlayerImpl::OnPipelineInitialize(PipelineStatus status) {
    774   DCHECK(MessageLoop::current() == main_loop_);
    775   if (status == media::PIPELINE_OK) {
    776     // Only keep one time range starting from 0.
    777     WebKit::WebTimeRanges new_buffered(static_cast<size_t>(1));
    778     new_buffered[0].start = 0.0f;
    779     new_buffered[0].end =
    780         static_cast<float>(pipeline_->GetMediaDuration().InSecondsF());
    781     buffered_.swap(new_buffered);
    782 
    783     // Since we have initialized the pipeline, say we have everything otherwise
    784     // we'll remain either loading/idle.
    785     // TODO(hclam): change this to report the correct status.
    786     SetReadyState(WebKit::WebMediaPlayer::HaveMetadata);
    787     SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData);
    788     if (pipeline_->IsLoaded()) {
    789       SetNetworkState(WebKit::WebMediaPlayer::Loaded);
    790     }
    791   } else {
    792     // TODO(hclam): should use |status| to determine the state
    793     // properly and reports error using MediaError.
    794     // WebKit uses FormatError to indicate an error for bogus URL or bad file.
    795     // Since we are at the initialization stage we can safely treat every error
    796     // as format error. Should post a task to call to |webmediaplayer_|.
    797     SetNetworkState(WebKit::WebMediaPlayer::FormatError);
    798   }
    799 
    800   // Repaint to trigger UI update.
    801   Repaint();
    802 }
    803 
    804 void WebMediaPlayerImpl::OnPipelineSeek(PipelineStatus status) {
    805   DCHECK(MessageLoop::current() == main_loop_);
    806   if (status == media::PIPELINE_OK) {
    807     // Update our paused time.
    808     if (paused_) {
    809       paused_time_ = pipeline_->GetCurrentTime();
    810     }
    811 
    812     SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData);
    813     seeking_ = false;
    814     GetClient()->timeChanged();
    815   }
    816 }
    817 
    818 void WebMediaPlayerImpl::OnPipelineEnded(PipelineStatus status) {
    819   DCHECK(MessageLoop::current() == main_loop_);
    820   if (status == media::PIPELINE_OK) {
    821     GetClient()->timeChanged();
    822   }
    823 }
    824 
    825 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
    826   DCHECK(MessageLoop::current() == main_loop_);
    827   switch (error) {
    828     case media::PIPELINE_OK:
    829       LOG(DFATAL) << "PIPELINE_OK isn't an error!";
    830       break;
    831 
    832     case media::PIPELINE_ERROR_INITIALIZATION_FAILED:
    833     case media::PIPELINE_ERROR_REQUIRED_FILTER_MISSING:
    834     case media::PIPELINE_ERROR_COULD_NOT_RENDER:
    835     case media::PIPELINE_ERROR_URL_NOT_FOUND:
    836     case media::PIPELINE_ERROR_NETWORK:
    837     case media::PIPELINE_ERROR_READ:
    838     case media::DEMUXER_ERROR_COULD_NOT_OPEN:
    839     case media::DEMUXER_ERROR_COULD_NOT_PARSE:
    840     case media::DEMUXER_ERROR_NO_SUPPORTED_STREAMS:
    841     case media::DEMUXER_ERROR_COULD_NOT_CREATE_THREAD:
    842     case media::DATASOURCE_ERROR_URL_NOT_SUPPORTED:
    843       // Format error.
    844       SetNetworkState(WebMediaPlayer::FormatError);
    845       break;
    846 
    847     case media::PIPELINE_ERROR_DECODE:
    848     case media::PIPELINE_ERROR_ABORT:
    849     case media::PIPELINE_ERROR_OUT_OF_MEMORY:
    850     case media::PIPELINE_ERROR_AUDIO_HARDWARE:
    851     case media::PIPELINE_ERROR_OPERATION_PENDING:
    852     case media::PIPELINE_ERROR_INVALID_STATE:
    853       // Decode error.
    854       SetNetworkState(WebMediaPlayer::DecodeError);
    855       break;
    856   }
    857 
    858   // Repaint to trigger UI update.
    859   Repaint();
    860 }
    861 
    862 void WebMediaPlayerImpl::OnNetworkEvent(PipelineStatus status) {
    863   DCHECK(MessageLoop::current() == main_loop_);
    864   if (status == media::PIPELINE_OK) {
    865     if (pipeline_->IsNetworkActive()) {
    866       SetNetworkState(WebKit::WebMediaPlayer::Loading);
    867     } else {
    868       // If we are inactive because we just finished receiving all the data,
    869       // do one final repaint to show final progress.
    870       if (bytesLoaded() == totalBytes() &&
    871           network_state_ != WebKit::WebMediaPlayer::Idle) {
    872         Repaint();
    873 
    874         SetNetworkState(WebKit::WebMediaPlayer::Loaded);
    875       }
    876 
    877       SetNetworkState(WebKit::WebMediaPlayer::Idle);
    878     }
    879   }
    880 }
    881 
    882 void WebMediaPlayerImpl::SetNetworkState(
    883     WebKit::WebMediaPlayer::NetworkState state) {
    884   DCHECK(MessageLoop::current() == main_loop_);
    885   // Always notify to ensure client has the latest value.
    886   network_state_ = state;
    887   GetClient()->networkStateChanged();
    888 }
    889 
    890 void WebMediaPlayerImpl::SetReadyState(
    891     WebKit::WebMediaPlayer::ReadyState state) {
    892   DCHECK(MessageLoop::current() == main_loop_);
    893   // Always notify to ensure client has the latest value.
    894   ready_state_ = state;
    895   GetClient()->readyStateChanged();
    896 }
    897 
    898 void WebMediaPlayerImpl::Destroy() {
    899   DCHECK(MessageLoop::current() == main_loop_);
    900 
    901   // Tell the data source to abort any pending reads so that the pipeline is
    902   // not blocked when issuing stop commands to the other filters.
    903   if (proxy_)
    904     proxy_->AbortDataSources();
    905 
    906   // Make sure to kill the pipeline so there's no more media threads running.
    907   // Note: stopping the pipeline might block for a long time.
    908   if (pipeline_) {
    909     media::PipelineStatusNotification note;
    910     pipeline_->Stop(note.Callback());
    911     note.Wait();
    912   }
    913 
    914   message_loop_factory_.reset();
    915 
    916   // And then detach the proxy, it may live on the render thread for a little
    917   // longer until all the tasks are finished.
    918   if (proxy_) {
    919     proxy_->Detach();
    920     proxy_ = NULL;
    921   }
    922 }
    923 
    924 WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
    925   DCHECK(MessageLoop::current() == main_loop_);
    926   DCHECK(client_);
    927   return client_;
    928 }
    929 
    930 }  // namespace webkit_glue
    931