browser(firefox): exclude frame from screencast video (#3372)

This commit is contained in:
Yury Semikhatsky 2020-08-10 15:10:12 -07:00 committed by GitHub
parent 6c68435e7e
commit 538daf3302
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 34 deletions

View file

@ -1,2 +1,2 @@
1155 1156
Changed: lushnikov@chromium.org Fri Aug 7 15:25:51 PDT 2020 Changed: yurys@chromium.org Mon Aug 10 20:28:44 GMTST 2020

View file

@ -105,10 +105,10 @@ void createImage(unsigned int width, unsigned int height,
class ScreencastEncoder::VPXFrame { class ScreencastEncoder::VPXFrame {
public: public:
VPXFrame(rtc::scoped_refptr<webrtc::VideoFrameBuffer>&& buffer, Maybe<double> scale, int offsetTop) VPXFrame(rtc::scoped_refptr<webrtc::VideoFrameBuffer>&& buffer, Maybe<double> scale, const gfx::IntMargin& margin)
: m_frameBuffer(std::move(buffer)) : m_frameBuffer(std::move(buffer))
, m_scale(scale) , m_scale(scale)
, m_offsetTop(offsetTop) , m_margin(margin)
{ } { }
void setDuration(int duration) { m_duration = duration; } void setDuration(int duration) { m_duration = duration; }
@ -131,45 +131,45 @@ public:
uint8_t* v_data = image->planes[2]; uint8_t* v_data = image->planes[2];
if (m_scale) { if (m_scale) {
int src_width = src->width(); int src_width = src->width() - m_margin.LeftRight();
double dst_width = src_width * m_scale.value(); double dst_width = src_width * m_scale.value();
if (dst_width > image->w) { if (dst_width > image->w) {
src_width *= image->w / dst_width; src_width *= image->w / dst_width;
dst_width = image->w; dst_width = image->w;
} }
int src_height = src->height() - m_offsetTop; int src_height = src->height() - m_margin.TopBottom();
double dst_height = src_height * m_scale.value(); double dst_height = src_height * m_scale.value();
if (dst_height > image->h) { if (dst_height > image->h) {
src_height *= image->h / dst_height; src_height *= image->h / dst_height;
dst_height = image->h; dst_height = image->h;
} }
libyuv::I420Scale(src->DataY() + m_offsetTop * src->StrideY(), src->StrideY(), libyuv::I420Scale(src->DataY() + m_margin.top * src->StrideY() + m_margin.left, src->StrideY(),
src->DataU() + (m_offsetTop + 1) / 2 * src->StrideU(), src->StrideU(), src->DataU() + (m_margin.top * src->StrideU() + m_margin.left) / 2, src->StrideU(),
src->DataV() + (m_offsetTop + 1) / 2 * src->StrideV(), src->StrideV(), src->DataV() + (m_margin.top * src->StrideV() + m_margin.left) / 2, src->StrideV(),
src_width, src_height, src_width, src_height,
y_data, y_stride, y_data, y_stride,
u_data, uv_stride, u_data, uv_stride,
v_data, uv_stride, v_data, uv_stride,
dst_width, dst_height, dst_width, dst_height,
libyuv::kFilterBilinear); libyuv::kFilterBilinear);
} else { } else {
int width = std::min<int>(image->w, src->width()); int width = std::min<int>(image->w, src->width() - m_margin.LeftRight());
int height = std::min<int>(image->h, src->height() - m_offsetTop); int height = std::min<int>(image->h, src->height() - m_margin.TopBottom());
libyuv::I420Copy(src->DataY() + m_offsetTop * src->StrideY(), src->StrideY(), libyuv::I420Copy(src->DataY() + m_margin.top * src->StrideY() + m_margin.left, src->StrideY(),
src->DataU() + (m_offsetTop + 1) / 2 * src->StrideU(), src->StrideU(), src->DataU() + (m_margin.top * src->StrideU() + m_margin.left) / 2, src->StrideU(),
src->DataV() + (m_offsetTop + 1) / 2 * src->StrideV(), src->StrideV(), src->DataV() + (m_margin.top * src->StrideV() + m_margin.left) / 2, src->StrideV(),
y_data, y_stride, y_data, y_stride,
u_data, uv_stride, u_data, uv_stride,
v_data, uv_stride, v_data, uv_stride,
width, height); width, height);
} }
} }
private: private:
rtc::scoped_refptr<webrtc::VideoFrameBuffer> m_frameBuffer; rtc::scoped_refptr<webrtc::VideoFrameBuffer> m_frameBuffer;
Maybe<double> m_scale; Maybe<double> m_scale;
int m_offsetTop = 0; gfx::IntMargin m_margin;
int m_duration = 0; int m_duration = 0;
}; };
@ -264,10 +264,10 @@ private:
std::unique_ptr<vpx_image_t> m_image; std::unique_ptr<vpx_image_t> m_image;
}; };
ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec, Maybe<double> scale, int offsetTop) ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec, Maybe<double> scale, const gfx::IntMargin& margin)
: m_vpxCodec(std::move(vpxCodec)) : m_vpxCodec(std::move(vpxCodec))
, m_scale(scale) , m_scale(scale)
, m_offsetTop(offsetTop) , m_margin(margin)
{ {
} }
@ -277,7 +277,7 @@ ScreencastEncoder::~ScreencastEncoder()
static constexpr int fps = 24; static constexpr int fps = 24;
RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, const nsCString& filePath, int width, int height, Maybe<double> scale, int offsetTop) RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, const nsCString& filePath, int width, int height, Maybe<double> scale, const gfx::IntMargin& margin)
{ {
vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx();
if (!codec_interface) { if (!codec_interface) {
@ -318,7 +318,7 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(codec, cfg, file)); std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(codec, cfg, file));
fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface)); fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface));
return new ScreencastEncoder(std::move(vpxCodec), scale, offsetTop); return new ScreencastEncoder(std::move(vpxCodec), scale, margin);
} }
void ScreencastEncoder::flushLastFrame() void ScreencastEncoder::flushLastFrame()
@ -342,7 +342,7 @@ void ScreencastEncoder::encodeFrame(const webrtc::VideoFrame& videoFrame)
fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); fprintf(stderr, "ScreencastEncoder::encodeFrame\n");
flushLastFrame(); flushLastFrame();
m_lastFrame = std::make_unique<VPXFrame>(videoFrame.video_frame_buffer(), m_scale, m_offsetTop); m_lastFrame = std::make_unique<VPXFrame>(videoFrame.video_frame_buffer(), m_scale, m_margin);
} }
void ScreencastEncoder::finish(std::function<void()>&& callback) void ScreencastEncoder::finish(std::function<void()>&& callback)

View file

@ -6,6 +6,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include "mozilla/gfx/Rect.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
@ -21,10 +22,10 @@ class ScreencastEncoder {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ScreencastEncoder) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ScreencastEncoder)
public: public:
static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, Maybe<double> scale, int offsetTop); static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, Maybe<double> scale, const gfx::IntMargin& margin);
class VPXCodec; class VPXCodec;
ScreencastEncoder(std::unique_ptr<VPXCodec>&&, Maybe<double> scale, int offsetTop); ScreencastEncoder(std::unique_ptr<VPXCodec>&&, Maybe<double> scale, const gfx::IntMargin& margin);
void encodeFrame(const webrtc::VideoFrame& videoFrame); void encodeFrame(const webrtc::VideoFrame& videoFrame);
@ -37,7 +38,7 @@ private:
std::unique_ptr<VPXCodec> m_vpxCodec; std::unique_ptr<VPXCodec> m_vpxCodec;
Maybe<double> m_scale; Maybe<double> m_scale;
int m_offsetTop; gfx::IntMargin m_margin;
TimeStamp m_lastFrameTimestamp; TimeStamp m_lastFrameTimestamp;
class VPXFrame; class VPXFrame;
std::unique_ptr<VPXFrame> m_lastFrame; std::unique_ptr<VPXFrame> m_lastFrame;

View file

@ -147,7 +147,15 @@ nsresult nsScreencastService::StartVideoRecording(nsIDocShell* aDocShell, const
Maybe<double> maybeScale; Maybe<double> maybeScale;
if (scale) if (scale)
maybeScale = Some(scale); maybeScale = Some(scale);
RefPtr<ScreencastEncoder> encoder = ScreencastEncoder::create(error, PromiseFlatCString(aFileName), width, height, maybeScale, offsetTop);
auto bounds = widget->GetScreenBounds().ToUnknownRect();
auto clientBounds = widget->GetClientBounds().ToUnknownRect();
// Crop the image to exclude frame (if any).
gfx::IntMargin margin = bounds - clientBounds;
// Crop the image to exclude controls.
margin.top += offsetTop;
RefPtr<ScreencastEncoder> encoder = ScreencastEncoder::create(error, PromiseFlatCString(aFileName), width, height, maybeScale, margin);
if (!encoder) { if (!encoder) {
fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get()); fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get());
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;