|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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/media/webmediaplayer_ms.h" | |
6 | |
7 #include <limits> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/callback.h" | |
11 #include "base/metrics/histogram.h" | |
12 #include "media/base/media_log.h" | |
13 #include "media/base/video_frame.h" | |
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient. h" | |
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h" | |
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" | |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" | |
21 #include "v8/include/v8.h" | |
22 #include "webkit/media/media_stream_client.h" | |
23 #include "webkit/media/video_frame_provider.h" | |
24 #include "webkit/media/webmediaplayer_delegate.h" | |
25 #include "webkit/media/webmediaplayer_util.h" | |
26 #include "webkit/media/webvideoframe_impl.h" | |
27 | |
28 using WebKit::WebCanvas; | |
29 using WebKit::WebMediaPlayer; | |
30 using WebKit::WebRect; | |
31 using WebKit::WebSize; | |
32 | |
33 namespace { | |
34 | |
35 // Amount of extra memory used by each player instance reported to V8. | |
36 // It is not exact number -- first, it differs on different platforms, | |
37 // and second, it is very hard to calculate. Instead, use some arbitrary | |
38 // value that will cause garbage collection from time to time. We don't want | |
39 // it to happen on every allocation, but don't want 5k players to sit in memory | |
40 // either. Looks that chosen constant achieves both goals, at least for audio | |
41 // objects. (Do not worry about video objects yet, JS programs do not create | |
42 // thousands of them...) | |
43 const int kPlayerExtraMemory = 1024 * 1024; | |
44 | |
45 } // namespace | |
46 | |
47 namespace webkit_media { | |
48 | |
49 WebMediaPlayerMS::WebMediaPlayerMS( | |
50 WebKit::WebFrame* frame, | |
51 WebKit::WebMediaPlayerClient* client, | |
52 base::WeakPtr<WebMediaPlayerDelegate> delegate, | |
53 MediaStreamClient* media_stream_client, | |
54 media::MediaLog* media_log) | |
55 : frame_(frame), | |
56 network_state_(WebMediaPlayer::NetworkStateEmpty), | |
57 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | |
58 buffered_(static_cast<size_t>(1)), | |
59 main_loop_(MessageLoop::current()), | |
scherkus (not reviewing)
2012/09/07 11:44:03
You don't need this member variable as you're only
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
60 client_(client), | |
61 delegate_(delegate), | |
62 media_stream_client_(media_stream_client), | |
63 video_frame_provider_started_(false), | |
64 paused_(true), | |
65 pending_repaint_(false), | |
66 got_first_frame_(false), | |
67 total_frame_count_(0), | |
68 dropped_frame_count_(0), | |
69 media_log_(media_log), | |
70 accelerated_compositing_reported_(false), | |
71 incremented_externally_allocated_memory_(false) { | |
72 DVLOG(1) << "WebMediaPlayerMS::ctor"; | |
73 DCHECK(media_stream_client); | |
74 media_log_->AddEvent( | |
scherkus (not reviewing)
2012/09/07 11:44:03
this will end up on chrome://media-internals but I
wjia(left Chromium)
2012/09/13 01:22:07
I'd keep it for now.
| |
75 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); | |
76 | |
77 // Let V8 know we started new thread if we did not did it yet. | |
78 // Made separate task to avoid deletion of player currently being created. | |
79 // Also, delaying GC until after player starts gets rid of starting lag -- | |
80 // collection happens in parallel with playing. | |
81 // | |
82 // TODO(enal): remove when we get rid of per-audio-stream thread. | |
83 MessageLoop::current()->PostTask( | |
84 FROM_HERE, | |
85 base::Bind(&WebMediaPlayerMS::IncrementExternallyAllocatedMemory, | |
86 AsWeakPtr())); | |
87 | |
88 // Also we want to be notified of |main_loop_| destruction. | |
89 main_loop_->AddDestructionObserver(this); | |
scherkus (not reviewing)
2012/09/07 11:44:03
I don't think you need a destruction observer as y
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
90 } | |
91 | |
92 WebMediaPlayerMS::~WebMediaPlayerMS() { | |
93 DVLOG(1) << "WebMediaPlayerMS::dtor"; | |
94 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
95 Destroy(); | |
96 media_log_->AddEvent( | |
97 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); | |
98 | |
99 if (delegate_) | |
100 delegate_->PlayerGone(this); | |
101 | |
102 // Finally tell the |main_loop_| we don't want to be notified of destruction | |
103 // event. | |
104 if (main_loop_) { | |
105 main_loop_->RemoveDestructionObserver(this); | |
106 } | |
107 } | |
108 | |
109 void WebMediaPlayerMS::load(const WebKit::WebURL& url, CORSMode cors_mode) { | |
110 DVLOG(1) << "WebMediaPlayerMS::load"; | |
111 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
112 | |
113 GURL gurl(url); | |
114 | |
115 setVolume(GetClient()->volume()); | |
116 SetNetworkState(WebMediaPlayer::NetworkStateLoading); | |
117 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing); | |
118 media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec())); | |
119 | |
120 // Check if this url is media stream. | |
121 video_frame_provider_ = media_stream_client_->GetVideoFrameProvider( | |
122 url, | |
123 base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()), | |
124 base::Bind(&WebMediaPlayerMS::Repaint, AsWeakPtr())); | |
125 if (video_frame_provider_) { | |
126 SetNetworkState(WebMediaPlayer::NetworkStateLoaded); | |
127 GetClient()->sourceOpened(); | |
128 GetClient()->setOpaque(true); | |
129 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | |
130 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | |
131 RepaintInternal(); | |
132 } else { | |
133 SetNetworkState(WebMediaPlayer::NetworkStateNetworkError); | |
134 } | |
135 } | |
136 | |
137 void WebMediaPlayerMS::cancelLoad() { | |
138 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
139 } | |
140 | |
141 void WebMediaPlayerMS::play() { | |
142 DVLOG(1) << "WebMediaPlayerMS::play"; | |
143 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
144 | |
145 paused_ = false; | |
146 if (video_frame_provider_) { | |
147 if (video_frame_provider_started_) { | |
148 video_frame_provider_->Play(); | |
149 } else { | |
150 video_frame_provider_started_ = true; | |
151 video_frame_provider_->Start(); | |
152 } | |
153 } | |
154 // TODO: add audio. | |
scherkus (not reviewing)
2012/09/07 11:44:03
TODO(wjia)?
is there a bug filed for WebRTC audio
wjia(left Chromium)
2012/09/13 01:22:07
Done. I'd use the same bug for adding WebRTC audio
| |
155 | |
156 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); | |
157 | |
158 if (delegate_) | |
159 delegate_->DidPlay(this); | |
160 } | |
161 | |
162 void WebMediaPlayerMS::pause() { | |
163 DVLOG(1) << "WebMediaPlayerMS::pause"; | |
164 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
165 | |
166 if (video_frame_provider_) | |
167 video_frame_provider_->Pause(); | |
168 // TODO: add audio. | |
scherkus (not reviewing)
2012/09/07 11:44:03
ditto
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
169 paused_ = true; | |
170 | |
171 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE)); | |
172 | |
173 if (delegate_) | |
174 delegate_->DidPause(this); | |
175 } | |
176 | |
177 bool WebMediaPlayerMS::supportsFullscreen() const { | |
178 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
179 return true; | |
180 } | |
181 | |
182 bool WebMediaPlayerMS::supportsSave() const { | |
183 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
184 return false; | |
185 } | |
186 | |
187 void WebMediaPlayerMS::seek(float seconds) { | |
188 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
189 } | |
190 | |
191 void WebMediaPlayerMS::setEndTime(float seconds) { | |
192 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
193 } | |
194 | |
195 void WebMediaPlayerMS::setRate(float rate) { | |
196 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
197 } | |
198 | |
199 void WebMediaPlayerMS::setVolume(float volume) { | |
200 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
201 // TODO: set audio volume. | |
scherkus (not reviewing)
2012/09/07 11:44:03
TODO(wjia)?
NOTIMPLEMENTED?
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
202 } | |
203 | |
204 void WebMediaPlayerMS::setVisible(bool visible) { | |
205 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
206 } | |
207 | |
208 void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload) { | |
209 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
210 } | |
211 | |
212 bool WebMediaPlayerMS::totalBytesKnown() { | |
213 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
214 return false; | |
215 } | |
216 | |
217 bool WebMediaPlayerMS::hasVideo() const { | |
218 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
219 return !!video_frame_provider_; | |
scherkus (not reviewing)
2012/09/07 11:44:03
use != NULL
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
220 } | |
221 | |
222 bool WebMediaPlayerMS::hasAudio() const { | |
223 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
224 // TODO: add audio support. | |
scherkus (not reviewing)
2012/09/07 11:44:03
TODO(wjia)?
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
225 return false; | |
226 } | |
227 | |
228 WebKit::WebSize WebMediaPlayerMS::naturalSize() const { | |
229 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
230 | |
231 gfx::Size size; | |
232 if (current_frame_) | |
233 size = current_frame_->natural_size(); | |
234 DVLOG(1) << "WebMediaPlayerMS::naturalSize, " << size.ToString(); | |
235 return WebKit::WebSize(size); | |
236 } | |
237 | |
238 bool WebMediaPlayerMS::paused() const { | |
239 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
240 return paused_; | |
241 } | |
242 | |
243 bool WebMediaPlayerMS::seeking() const { | |
244 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
245 return false; | |
246 } | |
247 | |
248 float WebMediaPlayerMS::duration() const { | |
249 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
250 return std::numeric_limits<float>::infinity(); | |
251 } | |
252 | |
253 float WebMediaPlayerMS::currentTime() const { | |
254 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
255 base::TimeDelta current_time; | |
256 if (current_frame_.get()) { | |
scherkus (not reviewing)
2012/09/07 11:44:03
how about:
if (current_frame_.get())
return cur
wjia(left Chromium)
2012/09/13 01:22:07
Done.
| |
257 current_time = current_frame_->GetTimestamp(); | |
258 } | |
259 return static_cast<float>(current_time.InSecondsF()); | |
260 } | |
261 | |
262 int WebMediaPlayerMS::dataRate() const { | |
263 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
264 return 0; | |
265 } | |
266 | |
267 WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const { | |
268 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
269 DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_; | |
270 return network_state_; | |
271 } | |
272 | |
273 WebMediaPlayer::ReadyState WebMediaPlayerMS::readyState() const { | |
274 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
275 DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_; | |
276 return ready_state_; | |
277 } | |
278 | |
279 const WebKit::WebTimeRanges& WebMediaPlayerMS::buffered() { | |
280 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
281 return buffered_; | |
scherkus (not reviewing)
2012/09/07 11:44:03
you don't need this variable -- just alloc + retur
wjia(left Chromium)
2012/09/13 01:22:07
This variable has to be here. If a WebTimeRanges i
scherkus (not reviewing)
2012/09/13 10:22:43
ah didn't see the const-ref return value
| |
282 } | |
283 | |
284 float WebMediaPlayerMS::maxTimeSeekable() const { | |
285 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
286 return 0.0f; | |
287 } | |
288 | |
289 bool WebMediaPlayerMS::didLoadingProgress() const { | |
290 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
291 return false; | |
292 } | |
293 | |
294 unsigned long long WebMediaPlayerMS::totalBytes() const { | |
295 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
296 return 0; | |
297 } | |
298 | |
299 void WebMediaPlayerMS::setSize(const WebSize& size) { | |
300 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
301 // Don't need to do anything as we use the dimensions passed in via paint(). | |
302 } | |
303 | |
304 void WebMediaPlayerMS::paint(WebCanvas* canvas, | |
305 const WebRect& rect, | |
306 uint8_t alpha) { | |
307 DVLOG(1) << "WebMediaPlayerMS::paint"; | |
308 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
309 | |
310 if (!accelerated_compositing_reported_) { | |
311 accelerated_compositing_reported_ = true; | |
312 // Normally paint() is only called in non-accelerated rendering, but there | |
313 // are exceptions such as webgl where compositing is used in the WebView but | |
314 // video frames are still rendered to a canvas. | |
315 UMA_HISTOGRAM_BOOLEAN( | |
316 "Media.AcceleratedCompositingActive", | |
317 frame_->view()->isAcceleratedCompositingActive()); | |
318 } | |
319 | |
320 video_renderer_.Paint(current_frame_, canvas, rect, alpha); | |
321 } | |
322 | |
323 bool WebMediaPlayerMS::hasSingleSecurityOrigin() const { | |
324 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
325 return true; | |
326 } | |
327 | |
328 bool WebMediaPlayerMS::didPassCORSAccessCheck() const { | |
329 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
330 return true; | |
331 } | |
332 | |
333 WebMediaPlayer::MovieLoadType WebMediaPlayerMS::movieLoadType() const { | |
334 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
335 return WebMediaPlayer::MovieLoadTypeUnknown; | |
336 } | |
337 | |
338 float WebMediaPlayerMS::mediaTimeForTimeValue(float timeValue) const { | |
339 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); | |
340 } | |
341 | |
342 unsigned WebMediaPlayerMS::decodedFrameCount() const { | |
343 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
344 DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_; | |
345 return total_frame_count_; | |
346 } | |
347 | |
348 unsigned WebMediaPlayerMS::droppedFrameCount() const { | |
349 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
350 DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_; | |
351 return dropped_frame_count_; | |
352 } | |
353 | |
354 unsigned WebMediaPlayerMS::audioDecodedByteCount() const { | |
355 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
356 NOTIMPLEMENTED(); | |
357 return 0; | |
358 } | |
359 | |
360 unsigned WebMediaPlayerMS::videoDecodedByteCount() const { | |
361 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
362 NOTIMPLEMENTED(); | |
363 return 0; | |
364 } | |
365 | |
366 WebKit::WebVideoFrame* WebMediaPlayerMS::getCurrentFrame() { | |
367 DVLOG(1) << "WebMediaPlayerMS::getCurrentFrame"; | |
368 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
369 DCHECK(!pending_repaint_); | |
370 pending_repaint_ = true; | |
scherkus (not reviewing)
2012/09/07 11:44:03
this seems odd -- what exactly is pending_repaint_
wjia(left Chromium)
2012/09/13 01:22:07
|pending_repaint_| is used to ensure client->repai
| |
371 if (current_frame_.get()) | |
372 return new webkit_media::WebVideoFrameImpl(current_frame_); | |
373 return NULL; | |
374 } | |
375 | |
376 void WebMediaPlayerMS::putCurrentFrame( | |
377 WebKit::WebVideoFrame* web_video_frame) { | |
378 DVLOG(1) << "WebMediaPlayerMS::putCurrentFrame"; | |
379 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
380 DCHECK(pending_repaint_); | |
381 pending_repaint_ = false; | |
382 if (!accelerated_compositing_reported_) { | |
383 accelerated_compositing_reported_ = true; | |
384 UMA_HISTOGRAM_BOOLEAN("Media.AcceleratedCompositingActive", | |
385 frame_->view()->isAcceleratedCompositingActive()); | |
386 } | |
387 if (web_video_frame) { | |
388 delete web_video_frame; | |
389 } | |
390 } | |
391 | |
392 void WebMediaPlayerMS::WillDestroyCurrentMessageLoop() { | |
393 Destroy(); | |
394 main_loop_ = NULL; | |
395 } | |
396 | |
397 void WebMediaPlayerMS::Repaint(const scoped_refptr<media::VideoFrame>& frame) { | |
398 DVLOG(1) << "WebMediaPlayerMS::Repaint with frame"; | |
399 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
400 ++total_frame_count_; | |
401 if (!got_first_frame_) { | |
402 got_first_frame_ = true; | |
403 start_time_ = frame->GetTimestamp(); | |
404 } | |
405 current_frame_ = frame; | |
406 current_frame_->SetTimestamp(frame->GetTimestamp() - start_time_); | |
407 if (pending_repaint_) { | |
scherkus (not reviewing)
2012/09/07 11:44:03
considering you only set this in the HW decode pat
wjia(left Chromium)
2012/09/13 01:22:07
Removed dropped_frame_count_ for now. Is it possib
scherkus (not reviewing)
2012/09/13 10:22:43
I wouldn't say the two are mutually exclusive -- f
| |
408 ++dropped_frame_count_; | |
409 } else { | |
410 GetClient()->repaint(); | |
411 } | |
412 } | |
413 | |
414 void WebMediaPlayerMS::RepaintInternal() { | |
415 DVLOG(1) << "WebMediaPlayerMS::Repaint"; | |
416 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
417 if (!pending_repaint_) { | |
418 GetClient()->repaint(); | |
419 } | |
420 } | |
421 | |
422 void WebMediaPlayerMS::OnSourceError() { | |
423 DVLOG(1) << "WebMediaPlayerMS::OnSourceError"; | |
424 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
425 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); | |
426 RepaintInternal(); | |
427 } | |
428 | |
429 void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state) { | |
430 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
431 network_state_ = state; | |
432 // Always notify to ensure client has the latest value. | |
433 GetClient()->networkStateChanged(); | |
434 } | |
435 | |
436 void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state) { | |
437 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
438 ready_state_ = state; | |
439 // Always notify to ensure client has the latest value. | |
440 GetClient()->readyStateChanged(); | |
441 } | |
442 | |
443 void WebMediaPlayerMS::Destroy() { | |
444 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
445 | |
446 if (video_frame_provider_) { | |
447 video_frame_provider_->Stop(); | |
scherkus (not reviewing)
2012/09/07 11:44:03
considering Stop() is synchronous how about replac
wjia(left Chromium)
2012/09/13 01:22:07
That won't work for LocalVideoCapture, since Start
scherkus (not reviewing)
2012/09/13 10:22:43
Let's see if I can untangle this a bit...
VideoFr
wjia(left Chromium)
2012/09/19 03:22:06
Please see my comments in local_video_capture.cc a
| |
448 } | |
449 | |
450 // Let V8 know we are not using extra resources anymore. | |
451 if (incremented_externally_allocated_memory_) { | |
452 v8::V8::AdjustAmountOfExternalAllocatedMemory(-kPlayerExtraMemory); | |
453 incremented_externally_allocated_memory_ = false; | |
454 } | |
455 } | |
456 | |
457 WebKit::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() { | |
458 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
459 DCHECK(client_); | |
460 return client_; | |
461 } | |
462 | |
463 void WebMediaPlayerMS::IncrementExternallyAllocatedMemory() { | |
464 DCHECK_EQ(main_loop_, MessageLoop::current()); | |
465 incremented_externally_allocated_memory_ = true; | |
466 v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory); | |
467 } | |
468 | |
469 } // namespace webkit_media | |
OLD | NEW |