Skip to content

Commit

Permalink
browser(firefox): support screencast frame size and scale configurati…
Browse files Browse the repository at this point in the history
…on (#2847)
  • Loading branch information
yury-s authored Jul 6, 2020
1 parent ac2185a commit fc18f2f
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 18 deletions.
4 changes: 2 additions & 2 deletions browser_patches/firefox/BUILD_NUMBER
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
1122
Changed: [email protected] Thu Jul 2 14:18:12 PDT 2020
1123
Changed: [email protected] Mon Jul 6 11:13:23 PDT 2020
7 changes: 6 additions & 1 deletion browser_patches/firefox/juggler/protocol/PageHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,14 @@ class PageHandler {
}

startVideoRecording({file, width, height, scale}) {
if (width < 10 || width > 10000 || height < 10 || height > 10000)
throw new Error("Invalid size");
if (scale && (scale <= 0 || scale > 1))
throw new Error("Unsupported scale");

const screencast = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService);
const docShell = this._pageTarget._gBrowser.ownerGlobal.docShell;
this._videoSessionId = screencast.startVideoRecording(docShell, file);
this._videoSessionId = screencast.startVideoRecording(docShell, file, width, height, scale || 0);
}

stopVideoRecording() {
Expand Down
54 changes: 42 additions & 12 deletions browser_patches/firefox/juggler/screencast/ScreencastEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "ScreencastEncoder.h"

#include <algorithm>
#include <libyuv.h>
#include <vpx/vp8.h>
#include <vpx/vp8cx.h>
Expand All @@ -47,7 +48,8 @@ const int kMacroBlockSize = 16;

void createImage(unsigned int width, unsigned int height,
std::unique_ptr<vpx_image_t>& out_image,
std::unique_ptr<uint8_t[]>& out_image_buffer) {
std::unique_ptr<uint8_t[]>& out_image_buffer,
int& out_buffer_size) {
std::unique_ptr<vpx_image_t> image(new vpx_image_t());
memset(image.get(), 0, sizeof(vpx_image_t));

Expand Down Expand Up @@ -78,11 +80,11 @@ void createImage(unsigned int width, unsigned int height,
const int uv_rows = y_rows >> image->y_chroma_shift;

// Allocate a YUV buffer large enough for the aligned data & padding.
const int buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows;
std::unique_ptr<uint8_t[]> image_buffer(new uint8_t[buffer_size]);
out_buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows;
std::unique_ptr<uint8_t[]> image_buffer(new uint8_t[out_buffer_size]);

// Reset image value to 128 so we just need to fill in the y plane.
memset(image_buffer.get(), 128, buffer_size);
memset(image_buffer.get(), 128, out_buffer_size);

// Fill in the information for |image_|.
unsigned char* uchar_buffer =
Expand Down Expand Up @@ -180,13 +182,39 @@ class ScreencastEncoder::VPXFrame {
uint8_t* u_data = image->planes[1];
uint8_t* v_data = image->planes[2];

libyuv::I420Copy(src->DataY(), src->StrideY(),
src->DataU(), src->StrideU(),
src->DataV(), src->StrideV(),
y_data, y_stride,
u_data, uv_stride,
v_data, uv_stride,
image->w, image->h);
if (m_scale) {
int src_width = src->width();
double dst_width = src_width * m_scale.value();
if (dst_width > image->w) {
src_width *= image->w / dst_width;
dst_width = image->w;
}
int src_height = src->height();
double dst_height = src_height * m_scale.value();
if (dst_height > image->h) {
src_height *= image->h / dst_height;
dst_height = image->h;
}
libyuv::I420Scale(src->DataY(), src->StrideY(),
src->DataU(), src->StrideU(),
src->DataV(), src->StrideV(),
src_width, src_height,
y_data, y_stride,
u_data, uv_stride,
v_data, uv_stride,
dst_width, dst_height,
libyuv::kFilterBilinear);
} else {
int width = std::min<int>(image->w, src->width());
int height = std::min<int>(image->h, src->height());
libyuv::I420Copy(src->DataY(), src->StrideY(),
src->DataU(), src->StrideU(),
src->DataV(), src->StrideV(),
y_data, y_stride,
u_data, uv_stride,
v_data, uv_stride,
width, height);
}
}

private:
Expand All @@ -212,7 +240,7 @@ class ScreencastEncoder::VPXCodec {

ivf_write_file_header(m_file, &m_cfg, m_fourcc, 0);

createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer);
createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer, m_imageBufferSize);
}

~VPXCodec() {
Expand All @@ -223,6 +251,7 @@ class ScreencastEncoder::VPXCodec {
void encodeFrameAsync(std::unique_ptr<VPXFrame>&& frame)
{
m_encoderQueue->Dispatch(NS_NewRunnableFunction("VPXCodec::encodeFrameAsync", [this, frame = std::move(frame)] {
memset(m_imageBuffer.get(), 128, m_imageBufferSize);
frame->convertToVpxImage(m_image.get());
// TODO: figure out why passing duration to the codec results in much
// worse visual quality and makes video stutter.
Expand Down Expand Up @@ -292,6 +321,7 @@ class ScreencastEncoder::VPXCodec {
int m_frameCount { 0 };
int64_t m_pts { 0 };
std::unique_ptr<uint8_t[]> m_imageBuffer;
int m_imageBufferSize { 0 };
std::unique_ptr<vpx_image_t> m_image;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ interface nsIDocShell;
[scriptable, uuid(d8c4d9e0-9462-445e-9e43-68d3872ad1de)]
interface nsIScreencastService : nsISupports
{
long startVideoRecording(in nsIDocShell docShell, in ACString fileName);
long startVideoRecording(in nsIDocShell docShell, in ACString fileName, in uint32_t width, in uint32_t height, in double scale);
void stopVideoRecording(in long sessionId);
};
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ nsScreencastService::nsScreencastService() = default;
nsScreencastService::~nsScreencastService() {
}

nsresult nsScreencastService::StartVideoRecording(nsIDocShell* aDocShell, const nsACString& aFileName, int32_t* sessionId) {
nsresult nsScreencastService::StartVideoRecording(nsIDocShell* aDocShell, const nsACString& aFileName, uint32_t width, uint32_t height, double scale, int32_t* sessionId) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Screencast service must be started on the Main thread.");
*sessionId = -1;

Expand Down Expand Up @@ -121,7 +121,10 @@ nsresult nsScreencastService::StartVideoRecording(nsIDocShell* aDocShell, const
# endif
*sessionId = ++mLastSessionId;
nsCString error;
RefPtr<ScreencastEncoder> encoder = ScreencastEncoder::create(error, PromiseFlatCString(aFileName), 1280, 960, Nothing());
Maybe<double> maybeScale;
if (scale)
maybeScale = Some(scale);
RefPtr<ScreencastEncoder> encoder = ScreencastEncoder::create(error, PromiseFlatCString(aFileName), width, height, maybeScale);
if (!encoder) {
fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get());
return NS_ERROR_FAILURE;
Expand Down

0 comments on commit fc18f2f

Please sign in to comment.