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

Side by Side Diff: webkit/glue/webmediaplayer_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698