browser(firefox): write video to .webm instead of .ivf (#3062)

This commit is contained in:
Yury Semikhatsky 2020-07-21 09:26:59 -07:00 committed by GitHub
parent 2d59a8f9c2
commit a5cb983768
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 73 deletions

View file

@ -1,2 +1,2 @@
1134
Changed: pavel.feldman@gmail.com Mon Jul 20 15:11:16 PDT 2020
1135
Changed: yurys@chromium.org Tue Jul 21 09:15:13 PDT 2020

View file

@ -37,6 +37,7 @@
#include <vpx/vp8cx.h>
#include <vpx/vpx_encoder.h>
#include "nsThreadUtils.h"
#include "WebMFileWriter.h"
#include "webrtc/api/video/video_frame.h"
namespace mozilla {
@ -100,60 +101,6 @@ void createImage(unsigned int width, unsigned int height,
out_image_buffer = std::move(image_buffer);
}
void mem_put_le16(void *vmem, int val) {
unsigned char *mem = (unsigned char *)vmem;
mem[0] = (unsigned char)((val >> 0) & 0xff);
mem[1] = (unsigned char)((val >> 8) & 0xff);
}
void mem_put_le32(void *vmem, int val) {
unsigned char *mem = (unsigned char *)vmem;
mem[0] = (unsigned char)((val >> 0) & 0xff);
mem[1] = (unsigned char)((val >> 8) & 0xff);
mem[2] = (unsigned char)((val >> 16) & 0xff);
mem[3] = (unsigned char)((val >> 24) & 0xff);
}
void ivf_write_file_header_with_video_info(FILE *outfile, uint32_t fourcc,
int frame_cnt, int frame_width,
int frame_height,
vpx_rational_t timebase) {
char header[32];
header[0] = 'D';
header[1] = 'K';
header[2] = 'I';
header[3] = 'F';
mem_put_le16(header + 4, 0); // version
mem_put_le16(header + 6, 32); // header size
mem_put_le32(header + 8, fourcc); // fourcc
mem_put_le16(header + 12, frame_width); // width
mem_put_le16(header + 14, frame_height); // height
mem_put_le32(header + 16, timebase.den); // rate
mem_put_le32(header + 20, timebase.num); // scale
mem_put_le32(header + 24, frame_cnt); // length
mem_put_le32(header + 28, 0); // unused
fwrite(header, 1, 32, outfile);
}
void ivf_write_file_header(FILE *outfile, const struct vpx_codec_enc_cfg *cfg,
uint32_t fourcc, int frame_cnt) {
ivf_write_file_header_with_video_info(outfile, fourcc, frame_cnt, cfg->g_w,
cfg->g_h, cfg->g_timebase);
}
void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size) {
char header[12];
mem_put_le32(header, (int)frame_size);
mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF));
mem_put_le32(header + 8, (int)(pts >> 32));
fwrite(header, 1, 12, outfile);
}
} // namespace
class ScreencastEncoder::VPXFrame {
@ -229,11 +176,11 @@ private:
class ScreencastEncoder::VPXCodec {
public:
VPXCodec(uint32_t fourcc, vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file)
: m_fourcc(fourcc)
, m_codec(codec)
VPXCodec(vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file)
: m_codec(codec)
, m_cfg(cfg)
, m_file(file)
, m_writer(new WebMFileWriter(file, &m_cfg))
{
nsresult rv = NS_NewNamedThread("Screencast enc", getter_AddRefs(m_encoderQueue));
if (rv != NS_OK) {
@ -241,8 +188,6 @@ public:
return;
}
ivf_write_file_header(m_file, &m_cfg, m_fourcc, 0);
createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer, m_imageBufferSize);
}
@ -288,11 +233,7 @@ private:
gotPkts = true;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
ivf_write_frame_header(m_file, m_pts, pkt->data.frame.sz);
if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, m_file) != pkt->data.frame.sz) {
fprintf(stderr, "Failed to write compressed frame\n");
return 0;
}
m_writer->writeFrame(pkt);
bool keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
++m_frameCount;
fprintf(stderr, " #%03d %spts=%" PRId64 " sz=%zd\n", m_frameCount, keyframe ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz);
@ -309,18 +250,16 @@ private:
while (encodeFrame(nullptr, 1))
++m_frameCount;
rewind(m_file);
// Update total frame count.
ivf_write_file_header(m_file, &m_cfg, m_fourcc, m_frameCount);
m_writer->finish();
fclose(m_file);
fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount);
}
RefPtr<nsIThread> m_encoderQueue;
uint32_t m_fourcc { 0 };
vpx_codec_ctx_t m_codec;
vpx_codec_enc_cfg_t m_cfg;
FILE* m_file { nullptr };
std::unique_ptr<WebMFileWriter> m_writer;
int m_frameCount { 0 };
int64_t m_pts { 0 };
std::unique_ptr<uint8_t[]> m_imageBuffer;
@ -339,12 +278,10 @@ ScreencastEncoder::~ScreencastEncoder()
{
}
static constexpr uint32_t vp8fourcc = 0x30385056;
static constexpr int fps = 24;
RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, const nsCString& filePath, int width, int height, Maybe<double> scale, int offsetTop)
{
const uint32_t fourcc = vp8fourcc;
vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx();
if (!codec_interface) {
errorString = "Codec not found.";
@ -382,7 +319,7 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
return nullptr;
}
std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(fourcc, 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));
return new ScreencastEncoder(std::move(vpxCodec), scale, offsetTop);
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebMFileWriter.h"
#include "mkvmuxer/mkvmuxerutil.h"
namespace mozilla {
WebMFileWriter::WebMFileWriter(FILE* file, vpx_codec_enc_cfg_t* cfg)
: m_cfg(cfg)
, m_writer(new mkvmuxer::MkvWriter(file))
, m_segment(new mkvmuxer::Segment()) {
m_segment->Init(m_writer.get());
m_segment->set_mode(mkvmuxer::Segment::kFile);
m_segment->OutputCues(true);
mkvmuxer::SegmentInfo* info = m_segment->GetSegmentInfo();
std::string version = "Playwright " + std::string(vpx_codec_version_str());
info->set_writing_app(version.c_str());
// Add vp8 track.
m_videoTrackId = m_segment->AddVideoTrack(
static_cast<int>(m_cfg->g_w), static_cast<int>(m_cfg->g_h), 0);
if (!m_videoTrackId) {
fprintf(stderr, "Failed to add video track\n");
}
}
WebMFileWriter::~WebMFileWriter() {}
void WebMFileWriter::writeFrame(const vpx_codec_cx_pkt_t* pkt) {
int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * m_cfg->g_timebase.num /
m_cfg->g_timebase.den;
m_segment->AddFrame(static_cast<uint8_t*>(pkt->data.frame.buf),
pkt->data.frame.sz, m_videoTrackId, pts_ns,
pkt->data.frame.flags & VPX_FRAME_IS_KEY);
}
void WebMFileWriter::finish() {
m_segment->Finalize();
}
} // namespace mozilla

View file

@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include "vpx/vpx_encoder.h"
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvwriter.h"
namespace mozilla {
class WebMFileWriter {
public:
WebMFileWriter(FILE*, vpx_codec_enc_cfg_t* cfg);
~WebMFileWriter();
void writeFrame(const vpx_codec_cx_pkt_t* pkt);
void finish();
private:
vpx_codec_enc_cfg_t* m_cfg = nullptr;
std::unique_ptr<mkvmuxer::MkvWriter> m_writer;
std::unique_ptr<mkvmuxer::Segment> m_segment;
uint64_t m_videoTrackId = 0;
};
} // namespace mozilla

View file

@ -32,6 +32,17 @@ LOCAL_INCLUDES += [
'/widget/headless',
]
LOCAL_INCLUDES += [
'/third_party/aom/third_party/libwebm',
]
SOURCES += [
'/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc',
'/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc',
'/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc',
'WebMFileWriter.cpp',
]
include('/media/webrtc/webrtc.mozbuild')
include('/ipc/chromium/chromium-config.mozbuild')