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

Side by Side Diff: media/blink/webmediaplayer_cast_android.cc

Issue 1567123002: Support CAST+WMPI on android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: build fixes + comments addressed Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/blink/webmediaplayer_cast_android.h ('k') | media/blink/webmediaplayer_impl.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 2016 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 "media/blink/webmediaplayer_cast_android.h"
6
7 #include "gpu/GLES2/gl2extchromium.h"
8 #include "gpu/blink/webgraphicscontext3d_impl.h"
9 #include "gpu/command_buffer/client/gles2_interface.h"
10 #include "gpu/command_buffer/common/sync_token.h"
11 #include "media/base/android/media_common_android.h"
12 #include "media/base/bind_to_current_loop.h"
13 #include "media/blink/webmediaplayer_impl.h"
14 #include "media/blink/webmediaplayer_params.h"
15 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "third_party/skia/include/core/SkPaint.h"
20 #include "third_party/skia/include/core/SkTypeface.h"
21 #include "third_party/skia/include/gpu/GrContext.h"
22 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
23
24 using gpu::gles2::GLES2Interface;
25
26 namespace media {
27
28 namespace {
29 // File-static function is to allow it to run even after WMPI is deleted.
30 void OnReleaseTexture(
31 const base::Callback<gpu::gles2::GLES2Interface*()>& context_3d_cb,
32 GLuint texture_id,
33 const gpu::SyncToken& sync_token) {
34 GLES2Interface* gl = context_3d_cb.Run();
35 if (!gl)
36 return;
37
38 gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
39 gl->DeleteTextures(1, &texture_id);
40 // Flush to ensure that the texture gets deleted in a timely fashion.
41 gl->ShallowFlushCHROMIUM();
42 }
43
44 GLES2Interface* GLCBShim(
45 const WebMediaPlayerParams::Context3DCB& context_3d_cb) {
46 return context_3d_cb.Run().gl;
47 }
48
49 } // namespace
50
51 scoped_refptr<VideoFrame> MakeTextFrameForCast(
52 const std::string& remote_playback_message,
53 gfx::Size canvas_size,
54 gfx::Size natural_size,
55 const base::Callback<gpu::gles2::GLES2Interface*()>& context_3d_cb) {
56 SkBitmap bitmap;
57 bitmap.allocN32Pixels(canvas_size.width(), canvas_size.height());
58
59 // Create the canvas and draw the "Casting to <Chromecast>" text on it.
60 SkCanvas canvas(bitmap);
61 canvas.drawColor(SK_ColorBLACK);
62
63 const SkScalar kTextSize(40);
64 const SkScalar kMinPadding(40);
65
66 SkPaint paint;
67 paint.setAntiAlias(true);
68 paint.setFilterQuality(kHigh_SkFilterQuality);
69 paint.setColor(SK_ColorWHITE);
70 paint.setTypeface(SkTypeface::CreateFromName("sans", SkTypeface::kBold));
71 paint.setTextSize(kTextSize);
72
73 // Calculate the vertical margin from the top
74 SkPaint::FontMetrics font_metrics;
75 paint.getFontMetrics(&font_metrics);
76 SkScalar sk_vertical_margin = kMinPadding - font_metrics.fAscent;
77
78 // Measure the width of the entire text to display
79 size_t display_text_width = paint.measureText(remote_playback_message.c_str(),
80 remote_playback_message.size());
81 std::string display_text(remote_playback_message);
82
83 if (display_text_width + (kMinPadding * 2) > canvas_size.width()) {
84 // The text is too long to fit in one line, truncate it and append ellipsis
85 // to the end.
86
87 // First, figure out how much of the canvas the '...' will take up.
88 const std::string kTruncationEllipsis("\xE2\x80\xA6");
89 SkScalar sk_ellipse_width = paint.measureText(kTruncationEllipsis.c_str(),
90 kTruncationEllipsis.size());
91
92 // Then calculate how much of the text can be drawn with the '...' appended
93 // to the end of the string.
94 SkScalar sk_max_original_text_width(canvas_size.width() -
95 (kMinPadding * 2) - sk_ellipse_width);
96 size_t sk_max_original_text_length = paint.breakText(
97 remote_playback_message.c_str(), remote_playback_message.size(),
98 sk_max_original_text_width);
99
100 // Remove the part of the string that doesn't fit and append '...'.
101 display_text.erase(
102 sk_max_original_text_length,
103 remote_playback_message.size() - sk_max_original_text_length);
104 display_text.append(kTruncationEllipsis);
105 display_text_width =
106 paint.measureText(display_text.c_str(), display_text.size());
107 }
108
109 // Center the text horizontally.
110 SkScalar sk_horizontal_margin =
111 (canvas_size.width() - display_text_width) / 2.0;
112 canvas.drawText(display_text.c_str(), display_text.size(),
113 sk_horizontal_margin, sk_vertical_margin, paint);
114
115 GLES2Interface* gl = context_3d_cb.Run();
116
117 // GPU Process crashed.
118 if (!gl)
119 return nullptr;
120 GLuint remote_playback_texture_id = 0;
121 gl->GenTextures(1, &remote_playback_texture_id);
122 GLuint texture_target = GL_TEXTURE_2D;
123 gl->BindTexture(texture_target, remote_playback_texture_id);
124 gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
125 gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
126 gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
127 gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
128
129 {
130 SkAutoLockPixels lock(bitmap);
131 gl->TexImage2D(texture_target, 0 /* level */, GL_RGBA /* internalformat */,
132 bitmap.width(), bitmap.height(), 0 /* border */,
133 GL_RGBA /* format */, GL_UNSIGNED_BYTE /* type */,
134 bitmap.getPixels());
135 }
136
137 gpu::Mailbox texture_mailbox;
138 gl->GenMailboxCHROMIUM(texture_mailbox.name);
139 gl->ProduceTextureCHROMIUM(texture_target, texture_mailbox.name);
140 gl->Flush();
141 gpu::SyncToken texture_mailbox_sync_token(gl->InsertSyncPointCHROMIUM());
142
143 return VideoFrame::WrapNativeTexture(
144 media::PIXEL_FORMAT_ARGB,
145 gpu::MailboxHolder(texture_mailbox, texture_mailbox_sync_token,
146 texture_target),
147 media::BindToCurrentLoop(base::Bind(&OnReleaseTexture, context_3d_cb,
148 remote_playback_texture_id)),
149 canvas_size /* coded_size */, gfx::Rect(canvas_size) /* visible_rect */,
150 natural_size /* natural_size */, base::TimeDelta() /* timestamp */);
151 }
152
153 WebMediaPlayerCast::WebMediaPlayerCast(
154 WebMediaPlayerImpl* impl,
155 blink::WebMediaPlayerClient* client,
156 const WebMediaPlayerParams::Context3DCB& context_3d_cb,
157 base::WeakPtr<WebMediaPlayerDelegate> delegate)
158 : webmediaplayer_(impl),
159 client_(client),
160 context_3d_cb_(context_3d_cb),
161 delegate_(delegate) {}
162
163 WebMediaPlayerCast::~WebMediaPlayerCast() {
164 if (player_manager_) {
165 if (is_player_initialized_)
166 player_manager_->DestroyPlayer(player_id_);
167
168 player_manager_->UnregisterMediaPlayer(player_id_);
169 }
170 }
171
172 void WebMediaPlayerCast::Initialize(const GURL& url,
173 blink::WebLocalFrame* frame) {
174 player_manager_->Initialize(MEDIA_PLAYER_TYPE_REMOTE_ONLY, player_id_, url,
175 frame->document().firstPartyForCookies(), 0,
176 frame->document().url(), true);
177 is_player_initialized_ = true;
178 }
179
180 void WebMediaPlayerCast::SetMediaPlayerManager(
181 RendererMediaPlayerManagerInterface* media_player_manager) {
182 player_manager_ = media_player_manager;
183 player_id_ = player_manager_->RegisterMediaPlayer(this);
184 }
185
186 void WebMediaPlayerCast::requestRemotePlayback() {
187 player_manager_->Seek(player_id_, base::TimeDelta::FromSecondsD(
188 webmediaplayer_->currentTime()));
189 player_manager_->RequestRemotePlayback(player_id_);
190 }
191
192 void WebMediaPlayerCast::requestRemotePlaybackControl() {
193 player_manager_->RequestRemotePlaybackControl(player_id_);
194 }
195
196 void WebMediaPlayerCast::OnMediaMetadataChanged(base::TimeDelta duration,
197 int width,
198 int height,
199 bool success) {}
200
201 void WebMediaPlayerCast::OnPlaybackComplete() {
202 DVLOG(1) << __FUNCTION__;
203 webmediaplayer_->OnRemotePlaybackEnded();
204 }
205
206 void WebMediaPlayerCast::OnBufferingUpdate(int percentage) {
207 DVLOG(1) << __FUNCTION__;
208 }
209
210 void WebMediaPlayerCast::OnSeekRequest(const base::TimeDelta& time_to_seek) {
211 DVLOG(1) << __FUNCTION__;
212 client_->requestSeek(time_to_seek.InSecondsF());
213 }
214
215 void WebMediaPlayerCast::OnSeekComplete(const base::TimeDelta& current_time) {
216 DVLOG(1) << __FUNCTION__;
217 remote_time_at_ = base::TimeTicks::Now();
218 remote_time_ = current_time;
219 webmediaplayer_->OnPipelineSeeked(true, PIPELINE_OK);
220 }
221
222 void WebMediaPlayerCast::OnMediaError(int error_type) {
223 DVLOG(1) << __FUNCTION__;
224 }
225
226 void WebMediaPlayerCast::OnVideoSizeChanged(int width, int height) {
227 DVLOG(1) << __FUNCTION__;
228 }
229
230 void WebMediaPlayerCast::OnTimeUpdate(base::TimeDelta current_timestamp,
231 base::TimeTicks current_time_ticks) {
232 DVLOG(1) << __FUNCTION__ << " " << current_timestamp.InSecondsF();
233 remote_time_at_ = current_time_ticks;
234 remote_time_ = current_timestamp;
235 }
236
237 void WebMediaPlayerCast::OnPlayerReleased() {
238 DVLOG(1) << __FUNCTION__;
239 }
240
241 void WebMediaPlayerCast::OnConnectedToRemoteDevice(
242 const std::string& remote_playback_message) {
243 DVLOG(1) << __FUNCTION__;
244 remote_time_ = base::TimeDelta::FromSecondsD(webmediaplayer_->currentTime());
245 is_remote_ = true;
246 initializing_ = true;
247 paused_ = false;
248 if (delegate_)
249 delegate_->DidPlay(webmediaplayer_);
250 client_->playbackStateChanged();
251
252 remote_playback_message_ = remote_playback_message;
253 webmediaplayer_->SuspendForRemote();
254 client_->connectedToRemoteDevice();
255 }
256
257 double WebMediaPlayerCast::currentTime() const {
258 base::TimeDelta ret = remote_time_;
259 if (!paused_ && !initializing_) {
260 ret += base::TimeTicks::Now() - remote_time_at_;
261 }
262 return ret.InSecondsF();
263 }
264
265 void WebMediaPlayerCast::play() {
266 if (!paused_)
267 return;
268
269 player_manager_->Start(player_id_);
270 remote_time_at_ = base::TimeTicks::Now();
271 paused_ = false;
272 if (delegate_)
273 delegate_->DidPlay(webmediaplayer_);
274 }
275
276 void WebMediaPlayerCast::pause() {
277 player_manager_->Pause(player_id_, true);
278 }
279
280 void WebMediaPlayerCast::seek(base::TimeDelta t) {
281 should_notify_time_changed_ = true;
282 player_manager_->Seek(player_id_, t);
283 }
284
285 void WebMediaPlayerCast::OnDisconnectedFromRemoteDevice() {
286 DVLOG(1) << __FUNCTION__;
287 if (!paused_) {
288 paused_ = true;
289 if (delegate_)
290 delegate_->DidPause(webmediaplayer_);
291 }
292 is_remote_ = false;
293 double t = currentTime();
294 if (t + media::kTimeUpdateInterval * 2 / 1000 > webmediaplayer_->duration()) {
295 t = webmediaplayer_->duration();
296 }
297 webmediaplayer_->OnDisconnectedFromRemoteDevice(t);
298 }
299
300 void WebMediaPlayerCast::OnDidExitFullscreen() {
301 DVLOG(1) << __FUNCTION__;
302 }
303
304 void WebMediaPlayerCast::OnMediaPlayerPlay() {
305 DVLOG(1) << __FUNCTION__ << " is_remote_ = " << is_remote_;
306 initializing_ = false;
307 if (is_remote_ && paused_) {
308 paused_ = false;
309 if (paused_)
310 delegate_->DidPlay(webmediaplayer_);
311 remote_time_at_ = base::TimeTicks::Now();
312 client_->playbackStateChanged();
313 }
314 // Blink expects a timeChanged() in response to a seek().
315 if (should_notify_time_changed_)
316 client_->timeChanged();
317 }
318
319 void WebMediaPlayerCast::OnMediaPlayerPause() {
320 DVLOG(1) << __FUNCTION__ << " is_remote_ = " << is_remote_;
321 if (is_remote_ && !paused_) {
322 paused_ = true;
323 if (delegate_)
324 delegate_->DidPause(webmediaplayer_);
325 client_->playbackStateChanged();
326 }
327 }
328
329 void WebMediaPlayerCast::OnRemoteRouteAvailabilityChanged(
330 bool routes_available) {
331 DVLOG(1) << __FUNCTION__;
332 client_->remoteRouteAvailabilityChanged(routes_available);
333 }
334
335 void WebMediaPlayerCast::SuspendAndReleaseResources() {}
336 void WebMediaPlayerCast::OnWaitingForDecryptionKey() {}
337
338 bool WebMediaPlayerCast::hasVideo() const {
339 return true;
340 }
341
342 bool WebMediaPlayerCast::paused() const {
343 return paused_;
344 }
345
346 #if defined(VIDEO_HOLE)
347 bool WebMediaPlayerCast::UpdateBoundaryRectangle() {
348 return false;
349 }
350
351 const gfx::RectF WebMediaPlayerCast::GetBoundaryRectangle() {
352 return gfx::RectF();
353 }
354 #endif // defined(VIDEO_HOLE)
355
356 void WebMediaPlayerCast::SetDeviceScaleFactor(float scale_factor) {
357 device_scale_factor_ = scale_factor;
358 }
359
360 scoped_refptr<VideoFrame> WebMediaPlayerCast::GetCastingBanner() {
361 DVLOG(1) << __FUNCTION__;
362
363 // TODO(johnme): Should redraw this frame if the layer bounds change; but
364 // there seems no easy way to listen for the layer resizing (as opposed to
365 // OnVideoSizeChanged, which is when the frame sizes of the video file
366 // change). Perhaps have to poll (on main thread of course)?
367 gfx::Size video_size_css_px = webmediaplayer_->GetCanvasSize();
368 if (!video_size_css_px.width())
369 return nullptr;
370
371 // canvas_size will be the size in device pixels when pageScaleFactor == 1
372 gfx::Size canvas_size(
373 static_cast<int>(video_size_css_px.width() * device_scale_factor_),
374 static_cast<int>(video_size_css_px.height() * device_scale_factor_));
375
376 if (!canvas_size.width())
377 return nullptr;
378
379 return MakeTextFrameForCast(remote_playback_message_, canvas_size,
380 webmediaplayer_->naturalSize(),
381 base::Bind(&GLCBShim, context_3d_cb_));
382 }
383
384 } // namespace media
OLDNEW
« no previous file with comments | « media/blink/webmediaplayer_cast_android.h ('k') | media/blink/webmediaplayer_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698