@@ -8649,10 +8649,10 @@ index 59cdfdafab1d85ea3a5aecb3cd2293e6dfb1eb8d..52fe7990b1c18b964ee3cfa9f324e3c2
8649
8649
// The timeout we use when waiting for a DidUpdateGeometry message.
8650
8650
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp
8651
8651
new file mode 100644
8652
- index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f2f97c8fa
8652
+ index 0000000000000000000000000000000000000000..b58cea323c822ca6352e1cf907ab214e25345592
8653
8653
--- /dev/null
8654
8654
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp
8655
- @@ -0,0 +1,252 @@
8655
+ @@ -0,0 +1,253 @@
8656
8656
+/*
8657
8657
+ * Copyright (C) 2020 Microsoft Corporation.
8658
8658
+ *
@@ -8815,9 +8815,10 @@ index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f
8815
8815
+ if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(m_page.drawingArea()))
8816
8816
+ drawingArea->setPaintCallback(nullptr);
8817
8817
+
8818
- + m_encoder->finish();
8818
+ + m_encoder->finish([protectRef = m_encoder.copyRef(), callback = WTFMove(callback)] {
8819
+ + callback->sendSuccess();
8820
+ + });
8819
8821
+ m_encoder = nullptr;
8820
- + callback->sendSuccess();
8821
8822
+#else
8822
8823
+ callback->sendFailure("Not implemented."_s);
8823
8824
+#endif
@@ -8907,7 +8908,7 @@ index 0000000000000000000000000000000000000000..eac34bd46ae7b391d81fb0f21762024f
8907
8908
+} // namespace WebKit
8908
8909
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
8909
8910
new file mode 100644
8910
- index 0000000000000000000000000000000000000000..a957c3b2586d67caa78b96bb8644bab8d8919e14
8911
+ index 0000000000000000000000000000000000000000..77d4a06e4717629916241dc47cb057f4f6121743
8911
8912
--- /dev/null
8912
8913
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
8913
8914
@@ -0,0 +1,85 @@
@@ -8991,17 +8992,17 @@ index 0000000000000000000000000000000000000000..a957c3b2586d67caa78b96bb8644bab8
8991
8992
+ ImageFormat m_format { ImageFormat::Jpeg };
8992
8993
+ Optional<int> m_quality;
8993
8994
+#if PLATFORM(GTK)
8994
- + std::unique_ptr <ScreencastEncoder> m_encoder;
8995
+ + RefPtr <ScreencastEncoder> m_encoder;
8995
8996
+#endif
8996
8997
+};
8997
8998
+
8998
8999
+} // namespace WebKit
8999
9000
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp
9000
9001
new file mode 100644
9001
- index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324ddd10d22
9002
+ index 0000000000000000000000000000000000000000..46b324bf95e2d61fd4b9e67b7d646105fab943b1
9002
9003
--- /dev/null
9003
9004
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp
9004
- @@ -0,0 +1,335 @@
9005
+ @@ -0,0 +1,400 @@
9005
9006
+/*
9006
9007
+ * Copyright (c) 2010, The WebM Project authors. All rights reserved.
9007
9008
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
@@ -9038,6 +9039,9 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9038
9039
+#include <vpx/vp8.h>
9039
9040
+#include <vpx/vp8cx.h>
9040
9041
+#include <vpx/vpx_encoder.h>
9042
+ +#include <wtf/MonotonicTime.h>
9043
+ +#include <wtf/RunLoop.h>
9044
+ +#include <wtf/WorkQueue.h>
9041
9045
+
9042
9046
+using namespace WebCore;
9043
9047
+
@@ -9157,23 +9161,88 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9157
9161
+
9158
9162
+} // namespace
9159
9163
+
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
+ +
9160
9213
+class ScreencastEncoder::VPXCodec {
9161
9214
+public:
9162
9215
+ 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)
9164
9218
+ , m_codec(codec)
9165
9219
+ , m_cfg(cfg)
9166
9220
+ , m_file(file)
9167
9221
+ {
9168
9222
+ ivf_write_file_header(m_file, &m_cfg, m_fourcc, 0);
9169
9223
+ }
9170
9224
+
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)
9172
9242
+ {
9173
9243
+ vpx_codec_iter_t iter = nullptr;
9174
9244
+ const vpx_codec_cx_pkt_t *pkt = nullptr;
9175
9245
+ int flags = 0;
9176
- + unsigned long duration = 1;
9177
9246
+ const vpx_codec_err_t res = vpx_codec_encode(&m_codec, img, m_pts, duration, flags, VPX_DL_REALTIME);
9178
9247
+ if (res != VPX_CODEC_OK) {
9179
9248
+ fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(&m_codec));
@@ -9191,9 +9260,9 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9191
9260
+ return 0;
9192
9261
+ }
9193
9262
+ 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;
9196
9263
+ ++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;
9197
9266
+ }
9198
9267
+ }
9199
9268
+
@@ -9203,7 +9272,7 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9203
9272
+ void finish()
9204
9273
+ {
9205
9274
+ // Flush encoder.
9206
- + while (encodeFrame(nullptr))
9275
+ + while (encodeFrame(nullptr, 1 ))
9207
9276
+ ++m_frameCount;
9208
9277
+
9209
9278
+ rewind(m_file);
@@ -9213,13 +9282,13 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9213
9282
+ fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount);
9214
9283
+ }
9215
9284
+
9216
- +private:
9217
- + uint32_t m_fourcc = 0 ;
9285
+ + Ref<WorkQueue> m_encoderQueue;
9286
+ + uint32_t m_fourcc { 0 } ;
9218
9287
+ vpx_codec_ctx_t m_codec;
9219
9288
+ 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 } ;
9223
9292
+};
9224
9293
+
9225
9294
+ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec)
@@ -9229,13 +9298,15 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9229
9298
+
9230
9299
+ScreencastEncoder::~ScreencastEncoder()
9231
9300
+{
9232
- + finish();
9233
9301
+}
9234
9302
+
9235
9303
+#define VP8_FOURCC 0x30385056
9236
9304
+#define VP9_FOURCC 0x30395056
9237
9305
+
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)
9239
9310
+{
9240
9311
+ const uint32_t fourcc = VP8_FOURCC;
9241
9312
+ vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx();
@@ -9259,7 +9330,6 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9259
9330
+
9260
9331
+ cfg.g_w = w;
9261
9332
+ cfg.g_h = h;
9262
- + const int fps = 30;
9263
9333
+ cfg.g_timebase.num = 1;
9264
9334
+ cfg.g_timebase.den = fps;
9265
9335
+ cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
@@ -9278,13 +9348,25 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9278
9348
+
9279
9349
+ std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(fourcc, codec, cfg, file));
9280
9350
+ 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;
9282
9364
+}
9283
9365
+
9284
9366
+void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface)
9285
9367
+{
9286
9368
+ fprintf(stderr, "ScreencastEncoder::encodeFrame\n");
9287
- +
9369
+ + flushLastFrame();
9288
9370
+ IntSize size = cairoSurfaceSize(drawingAreaSurface);
9289
9371
+ if (size.isZero()) {
9290
9372
+ fprintf(stderr, "Cairo surface size is 0\n");
@@ -9293,56 +9375,40 @@ index 0000000000000000000000000000000000000000..6e0c7ffce5201430c04c95247e812324
9293
9375
+
9294
9376
+ // TODO: scale image if the size has changed.
9295
9377
+ // 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()));
9297
9379
+ {
9298
- + RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface .get()));
9380
+ + RefPtr<cairo_t> cr = adoptRef(cairo_create(surface .get()));
9299
9381
+ cairo_set_source_surface(cr.get(), drawingAreaSurface, 0, 0);
9300
9382
+ cairo_paint(cr.get());
9301
9383
+ }
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());
9312
9385
+
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);
9327
9387
+}
9328
9388
+
9329
- +void ScreencastEncoder::finish()
9389
+ +void ScreencastEncoder::finish(Function<void()>&& callback )
9330
9390
+{
9331
- + if (!m_vpxCodec)
9391
+ + if (!m_vpxCodec) {
9392
+ + callback();
9332
9393
+ return;
9394
+ + }
9333
9395
+
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
+ + });
9336
9402
+}
9337
9403
+
9338
9404
+
9339
9405
+} // namespace WebKit
9340
9406
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
9341
9407
new file mode 100644
9342
- index 0000000000000000000000000000000000000000..6ab23625bca03927ef060cc5be6919fe70b836bd
9408
+ index 0000000000000000000000000000000000000000..b0c8e5aadcdc44e741fe1b2df5f28eee20f7be3f
9343
9409
--- /dev/null
9344
9410
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
9345
- @@ -0,0 +1,53 @@
9411
+ @@ -0,0 +1,59 @@
9346
9412
+/*
9347
9413
+ * Copyright (C) 2020 Microsoft Corporation.
9348
9414
+ *
@@ -9372,27 +9438,33 @@ index 0000000000000000000000000000000000000000..6ab23625bca03927ef060cc5be6919fe
9372
9438
+
9373
9439
+#include <wtf/Forward.h>
9374
9440
+#include <wtf/Noncopyable.h>
9441
+ +#include <wtf/ThreadSafeRefCounted.h>
9375
9442
+#include <wtf/WeakPtr.h>
9376
9443
+
9377
9444
+namespace WebKit {
9378
9445
+
9379
9446
+class WebPageProxy;
9380
9447
+
9381
- +class ScreencastEncoder {
9448
+ +class ScreencastEncoder : public ThreadSafeRefCounted<ScreencastEncoder> {
9382
9449
+ WTF_MAKE_NONCOPYABLE(ScreencastEncoder);
9383
9450
+ WTF_MAKE_FAST_ALLOCATED;
9384
9451
+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);
9386
9453
+
9387
9454
+ class VPXCodec;
9388
9455
+ explicit ScreencastEncoder(std::unique_ptr<VPXCodec>&&);
9389
9456
+ ~ScreencastEncoder();
9390
9457
+
9391
9458
+ void encodeFrame(cairo_surface_t*);
9392
- + void finish();
9459
+ + void finish(Function<void()>&& callback );
9393
9460
+
9394
9461
+private:
9462
+ + void flushLastFrame();
9463
+ +
9395
9464
+ std::unique_ptr<VPXCodec> m_vpxCodec;
9465
+ + MonotonicTime m_lastFrameTimestamp;
9466
+ + class VPXFrame;
9467
+ + std::unique_ptr<VPXFrame> m_lastFrame;
9396
9468
+};
9397
9469
+
9398
9470
+} // namespace WebKit
0 commit comments