Skip to content

Commit 0a34d05

Browse files
authored
browser(webkit): encode screencast frames on a dedicated thread (#2433)
1 parent 4544110 commit 0a34d05

File tree

2 files changed

+132
-60
lines changed

2 files changed

+132
-60
lines changed

browser_patches/webkit/BUILD_NUMBER

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1250
1+
1251

browser_patches/webkit/patches/bootstrap.diff

Lines changed: 131 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8649,10 +8649,10 @@ index 59cdfdafab1d85ea3a5aecb3cd2293e6dfb1eb8d..52fe7990b1c18b964ee3cfa9f324e3c2
86498649
// The timeout we use when waiting for a DidUpdateGeometry message.
86508650
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp
86518651
new file mode 100644
8652-
index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f2f97c8fa
8652+
index 0000000000000000000000000000000000000000..b58cea323c822ca6352e1cf907ab214e25345592
86538653
--- /dev/null
86548654
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp
8655-
@@ -0,0 +1,252 @@
8655+
@@ -0,0 +1,253 @@
86568656
+/*
86578657
+ * Copyright (C) 2020 Microsoft Corporation.
86588658
+ *
@@ -8815,9 +8815,10 @@ index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f
88158815
+ if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(m_page.drawingArea()))
88168816
+ drawingArea->setPaintCallback(nullptr);
88178817
+
8818-
+ m_encoder->finish();
8818+
+ m_encoder->finish([protectRef = m_encoder.copyRef(), callback = WTFMove(callback)] {
8819+
+ callback->sendSuccess();
8820+
+ });
88198821
+ m_encoder = nullptr;
8820-
+ callback->sendSuccess();
88218822
+#else
88228823
+ callback->sendFailure("Not implemented."_s);
88238824
+#endif
@@ -8907,7 +8908,7 @@ index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f
89078908
+} // namespace WebKit
89088909
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
89098910
new file mode 100644
8910-
index 0000000000000000000000000000000000000000..a957c3b2586d67caa78b96bb8644bab8d8919e14
8911+
index 0000000000000000000000000000000000000000..77d4a06e4717629916241dc47cb057f4f6121743
89118912
--- /dev/null
89128913
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
89138914
@@ -0,0 +1,85 @@
@@ -8991,17 +8992,17 @@ index 0000000000000000000000000000000000000000..a957c3b2586d67caa78b96bb8644bab8
89918992
+ ImageFormat m_format { ImageFormat::Jpeg };
89928993
+ Optional<int> m_quality;
89938994
+#if PLATFORM(GTK)
8994-
+ std::unique_ptr<ScreencastEncoder> m_encoder;
8995+
+ RefPtr<ScreencastEncoder> m_encoder;
89958996
+#endif
89968997
+};
89978998
+
89988999
+} // namespace WebKit
89999000
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp
90009001
new file mode 100644
9001-
index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324ddd10d22
9002+
index 0000000000000000000000000000000000000000..46b324bf95e2d61fd4b9e67b7d646105fab943b1
90029003
--- /dev/null
90039004
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp
9004-
@@ -0,0 +1,335 @@
9005+
@@ -0,0 +1,400 @@
90059006
+/*
90069007
+ * Copyright (c) 2010, The WebM Project authors. All rights reserved.
90079008
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
@@ -9038,6 +9039,9 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
90389039
+#include <vpx/vp8.h>
90399040
+#include <vpx/vp8cx.h>
90409041
+#include <vpx/vpx_encoder.h>
9042+
+#include <wtf/MonotonicTime.h>
9043+
+#include <wtf/RunLoop.h>
9044+
+#include <wtf/WorkQueue.h>
90419045
+
90429046
+using namespace WebCore;
90439047
+
@@ -9157,23 +9161,88 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
91579161
+
91589162
+} // namespace
91599163
+
9164+
+class ScreencastEncoder::VPXFrame {
9165+
+ WTF_MAKE_NONCOPYABLE(VPXFrame);
9166+
+ WTF_MAKE_FAST_ALLOCATED;
9167+
+public:
9168+
+ VPXFrame(RefPtr<cairo_surface_t>&& surface, IntSize size)
9169+
+ : m_surface(WTFMove(surface))
9170+
+ , m_size(size)
9171+
+ { }
9172+
+
9173+
+ void setDuration(int duration) { m_duration = duration; }
9174+
+ int duration() const { return m_duration; }
9175+
+
9176+
+ vpx_image_t* convertToVpxImage()
9177+
+ {
9178+
+ if (m_image)
9179+
+ return m_image.get();
9180+
+
9181+
+ createImage(m_size, m_image, m_imageBuffer);
9182+
+
9183+
+ // Convert the updated region to YUV ready for encoding.
9184+
+ const uint8_t* rgba_data = cairo_image_surface_get_data(m_surface.get());
9185+
+ int rgba_stride = cairo_image_surface_get_stride(m_surface.get());
9186+
+
9187+
+ const int y_stride = m_image->stride[0];
9188+
+ ASSERT(m_image->stride[1] == m_image->stride[2]);
9189+
+ const int uv_stride = m_image->stride[1];
9190+
+ uint8_t* y_data = m_image->planes[0];
9191+
+ uint8_t* u_data = m_image->planes[1];
9192+
+ uint8_t* v_data = m_image->planes[2];
9193+
+
9194+
+ // TODO: redraw only damaged regions?
9195+
+ libyuv::ARGBToI420(rgba_data, rgba_stride,
9196+
+ y_data, y_stride,
9197+
+ u_data, uv_stride,
9198+
+ v_data, uv_stride,
9199+
+ m_size.width(), m_size.height());
9200+
+
9201+
+ return m_image.get();
9202+
+ }
9203+
+
9204+
+private:
9205+
+ RefPtr<cairo_surface_t> m_surface;
9206+
+ IntSize m_size;
9207+
+ int m_duration = 0;
9208+
+ std::unique_ptr<uint8_t[]> m_imageBuffer;
9209+
+ std::unique_ptr<vpx_image_t> m_image;
9210+
+};
9211+
+
9212+
+
91609213
+class ScreencastEncoder::VPXCodec {
91619214
+public:
91629215
+ VPXCodec(uint32_t fourcc, vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file)
9163-
+ : m_fourcc(fourcc)
9216+
+ : m_encoderQueue(WorkQueue::create("Screencast encoder"))
9217+
+ , m_fourcc(fourcc)
91649218
+ , m_codec(codec)
91659219
+ , m_cfg(cfg)
91669220
+ , m_file(file)
91679221
+ {
91689222
+ ivf_write_file_header(m_file, &m_cfg, m_fourcc, 0);
91699223
+ }
91709224
+
9171-
+ bool encodeFrame(vpx_image_t *img)
9225+
+ void encodeFrameAsync(std::unique_ptr<VPXFrame>&& frame)
9226+
+ {
9227+
+ m_encoderQueue->dispatch([this, frame = WTFMove(frame)] {
9228+
+ encodeFrame(frame->convertToVpxImage(), frame->duration());
9229+
+ });
9230+
+ }
9231+
+
9232+
+ void finishAsync(Function<void()>&& callback)
9233+
+ {
9234+
+ m_encoderQueue->dispatch([this, callback = WTFMove(callback)] {
9235+
+ finish();
9236+
+ callback();
9237+
+ });
9238+
+ }
9239+
+
9240+
+private:
9241+
+ bool encodeFrame(vpx_image_t *img, int duration)
91729242
+ {
91739243
+ vpx_codec_iter_t iter = nullptr;
91749244
+ const vpx_codec_cx_pkt_t *pkt = nullptr;
91759245
+ int flags = 0;
9176-
+ unsigned long duration = 1;
91779246
+ const vpx_codec_err_t res = vpx_codec_encode(&m_codec, img, m_pts, duration, flags, VPX_DL_REALTIME);
91789247
+ if (res != VPX_CODEC_OK) {
91799248
+ fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(&m_codec));
@@ -9191,9 +9260,9 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
91919260
+ return 0;
91929261
+ }
91939262
+ bool keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
9194-
+ fprintf(stderr, " %spts=%ld sz=%ld\n", keyframe ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz);
9195-
+ m_pts += pkt->data.frame.duration;
91969263
+ ++m_frameCount;
9264+
+ fprintf(stderr, " #%03d %spts=%ld sz=%ld\n", m_frameCount, keyframe ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz);
9265+
+ m_pts += pkt->data.frame.duration;
91979266
+ }
91989267
+ }
91999268
+
@@ -9203,7 +9272,7 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92039272
+ void finish()
92049273
+ {
92059274
+ // Flush encoder.
9206-
+ while (encodeFrame(nullptr))
9275+
+ while (encodeFrame(nullptr, 1))
92079276
+ ++m_frameCount;
92089277
+
92099278
+ rewind(m_file);
@@ -9213,13 +9282,13 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92139282
+ fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount);
92149283
+ }
92159284
+
9216-
+private:
9217-
+ uint32_t m_fourcc = 0;
9285+
+ Ref<WorkQueue> m_encoderQueue;
9286+
+ uint32_t m_fourcc { 0 };
92189287
+ vpx_codec_ctx_t m_codec;
92199288
+ vpx_codec_enc_cfg_t m_cfg;
9220-
+ FILE* m_file = nullptr;
9221-
+ int m_frameCount = 0;
9222-
+ int64_t m_pts;
9289+
+ FILE* m_file { nullptr };
9290+
+ int m_frameCount { 0 };
9291+
+ int64_t m_pts { 0 };
92239292
+};
92249293
+
92259294
+ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec)
@@ -9229,13 +9298,15 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92299298
+
92309299
+ScreencastEncoder::~ScreencastEncoder()
92319300
+{
9232-
+ finish();
92339301
+}
92349302
+
92359303
+#define VP8_FOURCC 0x30385056
92369304
+#define VP9_FOURCC 0x30395056
92379305
+
9238-
+std::unique_ptr<ScreencastEncoder> ScreencastEncoder::create(String& errorString, const String& filePath, int w, int h)
9306+
+static const int fps = 30;
9307+
+
9308+
+
9309+
+RefPtr<ScreencastEncoder> ScreencastEncoder::create(String& errorString, const String& filePath, int w, int h)
92399310
+{
92409311
+ const uint32_t fourcc = VP8_FOURCC;
92419312
+ vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx();
@@ -9259,7 +9330,6 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92599330
+
92609331
+ cfg.g_w = w;
92619332
+ cfg.g_h = h;
9262-
+ const int fps = 30;
92639333
+ cfg.g_timebase.num = 1;
92649334
+ cfg.g_timebase.den = fps;
92659335
+ cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
@@ -9278,13 +9348,25 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92789348
+
92799349
+ std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(fourcc, codec, cfg, file));
92809350
+ fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface));
9281-
+ return makeUnique<ScreencastEncoder>(WTFMove(vpxCodec));
9351+
+ return adoptRef(new ScreencastEncoder(WTFMove(vpxCodec)));
9352+
+}
9353+
+
9354+
+void ScreencastEncoder::flushLastFrame()
9355+
+{
9356+
+ MonotonicTime now = MonotonicTime::now();
9357+
+ if (m_lastFrameTimestamp) {
9358+
+ Seconds seconds = now - m_lastFrameTimestamp;
9359+
+ int duration = 1 + seconds.seconds() * fps; // Duration in timebase units
9360+
+ m_lastFrame->setDuration(duration);
9361+
+ m_vpxCodec->encodeFrameAsync(WTFMove(m_lastFrame));
9362+
+ }
9363+
+ m_lastFrameTimestamp = now;
92829364
+}
92839365
+
92849366
+void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface)
92859367
+{
92869368
+ fprintf(stderr, "ScreencastEncoder::encodeFrame\n");
9287-
+
9369+
+ flushLastFrame();
92889370
+ IntSize size = cairoSurfaceSize(drawingAreaSurface);
92899371
+ if (size.isZero()) {
92909372
+ fprintf(stderr, "Cairo surface size is 0\n");
@@ -9293,56 +9375,40 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
92939375
+
92949376
+ // TODO: scale image if the size has changed.
92959377
+ // TODO: adjust device scale factor?
9296-
+ RefPtr<cairo_surface_t> newSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height()));
9378+
+ RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height()));
92979379
+ {
9298-
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get()));
9380+
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
92999381
+ cairo_set_source_surface(cr.get(), drawingAreaSurface, 0, 0);
93009382
+ cairo_paint(cr.get());
93019383
+ }
9302-
+ cairo_surface_flush(newSurface.get());
9303-
+
9304-
+ std::unique_ptr<vpx_image_t> image;
9305-
+ std::unique_ptr<uint8_t[]> image_buffer;
9306-
+ createImage(size, image, image_buffer);
9307-
+
9308-
+
9309-
+ // Convert the updated region to YUV ready for encoding.
9310-
+ const uint8_t* rgba_data = cairo_image_surface_get_data(newSurface.get());
9311-
+ int rgba_stride = cairo_image_surface_get_stride(newSurface.get());
9384+
+ cairo_surface_flush(surface.get());
93129385
+
9313-
+ const int y_stride = image->stride[0];
9314-
+ ASSERT(image->stride[1] == image->stride[2]);
9315-
+ const int uv_stride = image->stride[1];
9316-
+ uint8_t* y_data = image->planes[0];
9317-
+ uint8_t* u_data = image->planes[1];
9318-
+ uint8_t* v_data = image->planes[2];
9319-
+
9320-
+ // TODO: redraw only damaged regions?
9321-
+ libyuv::ARGBToI420(rgba_data, rgba_stride,
9322-
+ y_data, y_stride,
9323-
+ u_data, uv_stride,
9324-
+ v_data, uv_stride,
9325-
+ size.width(), size.height());
9326-
+ m_vpxCodec->encodeFrame(image.get());
9386+
+ m_lastFrame = makeUnique<VPXFrame>(WTFMove(surface), size);
93279387
+}
93289388
+
9329-
+void ScreencastEncoder::finish()
9389+
+void ScreencastEncoder::finish(Function<void()>&& callback)
93309390
+{
9331-
+ if (!m_vpxCodec)
9391+
+ if (!m_vpxCodec) {
9392+
+ callback();
93329393
+ return;
9394+
+ }
93339395
+
9334-
+ m_vpxCodec->finish();
9335-
+ m_vpxCodec = nullptr;
9396+
+ flushLastFrame();
9397+
+ m_vpxCodec->finishAsync([callback = WTFMove(callback)] () mutable {
9398+
+ RunLoop::main().dispatch([callback = WTFMove(callback)] {
9399+
+ callback();
9400+
+ });
9401+
+ });
93369402
+}
93379403
+
93389404
+
93399405
+} // namespace WebKit
93409406
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
93419407
new file mode 100644
9342-
index 0000000000000000000000000000000000000000..6ab23625bca03927ef060cc5be6919fe70b836bd
9408+
index 0000000000000000000000000000000000000000..b0c8e5aadcdc44e741fe1b2df5f28eee20f7be3f
93439409
--- /dev/null
93449410
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
9345-
@@ -0,0 +1,53 @@
9411+
@@ -0,0 +1,59 @@
93469412
+/*
93479413
+ * Copyright (C) 2020 Microsoft Corporation.
93489414
+ *
@@ -9372,27 +9438,33 @@ index 0000000000000000000000000000000000000000..6ab23625bca03927ef060cc5be6919fe
93729438
+
93739439
+#include <wtf/Forward.h>
93749440
+#include <wtf/Noncopyable.h>
9441+
+#include <wtf/ThreadSafeRefCounted.h>
93759442
+#include <wtf/WeakPtr.h>
93769443
+
93779444
+namespace WebKit {
93789445
+
93799446
+class WebPageProxy;
93809447
+
9381-
+class ScreencastEncoder {
9448+
+class ScreencastEncoder : public ThreadSafeRefCounted<ScreencastEncoder> {
93829449
+ WTF_MAKE_NONCOPYABLE(ScreencastEncoder);
93839450
+ WTF_MAKE_FAST_ALLOCATED;
93849451
+public:
9385-
+ static std::unique_ptr<ScreencastEncoder> create(String& errorString, const String& filePath, int width, int height);
9452+
+ static RefPtr<ScreencastEncoder> create(String& errorString, const String& filePath, int width, int height);
93869453
+
93879454
+ class VPXCodec;
93889455
+ explicit ScreencastEncoder(std::unique_ptr<VPXCodec>&&);
93899456
+ ~ScreencastEncoder();
93909457
+
93919458
+ void encodeFrame(cairo_surface_t*);
9392-
+ void finish();
9459+
+ void finish(Function<void()>&& callback);
93939460
+
93949461
+private:
9462+
+ void flushLastFrame();
9463+
+
93959464
+ std::unique_ptr<VPXCodec> m_vpxCodec;
9465+
+ MonotonicTime m_lastFrameTimestamp;
9466+
+ class VPXFrame;
9467+
+ std::unique_ptr<VPXFrame> m_lastFrame;
93969468
+};
93979469
+
93989470
+} // namespace WebKit

0 commit comments

Comments
 (0)