browser(firefox): do not leak vpx codec (#16034)

This commit is contained in:
Yury Semikhatsky 2022-07-28 13:39:34 -07:00 committed by GitHub
parent dcbcb93c26
commit b479869ddc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 28 deletions

View file

@ -1,2 +1,2 @@
1336 1337
Changed: lushnikov@chromium.org Tue Jul 26 17:42:25 MSK 2022 Changed: yurys@chromium.org Thu Jul 28 13:35:27 PDT 2022

View file

@ -45,6 +45,18 @@ namespace mozilla {
namespace { namespace {
struct VpxCodecDeleter {
void operator()(vpx_codec_ctx_t* codec) {
if (codec) {
vpx_codec_err_t ret = vpx_codec_destroy(codec);
if (ret != VPX_CODEC_OK)
fprintf(stderr, "Failed to destroy codec: %s\n", vpx_codec_error(codec));
}
}
};
using ScopedVpxCodec = std::unique_ptr<vpx_codec_ctx_t, VpxCodecDeleter>;
// Number of timebase unints per one frame. // Number of timebase unints per one frame.
constexpr int timeScale = 1000; constexpr int timeScale = 1000;
@ -183,8 +195,8 @@ private:
class ScreencastEncoder::VPXCodec { class ScreencastEncoder::VPXCodec {
public: public:
VPXCodec(vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file) VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file)
: m_codec(codec) : m_codec(std::move(codec))
, m_cfg(cfg) , m_cfg(cfg)
, m_file(file) , m_file(file)
, m_writer(new WebMFileWriter(file, &m_cfg)) , m_writer(new WebMFileWriter(file, &m_cfg))
@ -233,14 +245,14 @@ private:
vpx_codec_iter_t iter = nullptr; vpx_codec_iter_t iter = nullptr;
const vpx_codec_cx_pkt_t *pkt = nullptr; const vpx_codec_cx_pkt_t *pkt = nullptr;
int flags = 0; int flags = 0;
const vpx_codec_err_t res = vpx_codec_encode(&m_codec, img, m_pts, duration, flags, VPX_DL_REALTIME); const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME);
if (res != VPX_CODEC_OK) { if (res != VPX_CODEC_OK) {
fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(&m_codec)); fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get()));
return false; return false;
} }
bool gotPkts = false; bool gotPkts = false;
while ((pkt = vpx_codec_get_cx_data(&m_codec, &iter)) != nullptr) { while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) {
gotPkts = true; gotPkts = true;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
@ -266,7 +278,7 @@ private:
} }
RefPtr<nsIThread> m_encoderQueue; RefPtr<nsIThread> m_encoderQueue;
vpx_codec_ctx_t m_codec; ScopedVpxCodec m_codec;
vpx_codec_enc_cfg_t m_cfg; vpx_codec_enc_cfg_t m_cfg;
FILE* m_file { nullptr }; FILE* m_file { nullptr };
std::unique_ptr<WebMFileWriter> m_writer; std::unique_ptr<WebMFileWriter> m_writer;
@ -277,7 +289,7 @@ private:
std::unique_ptr<vpx_image_t> m_image; std::unique_ptr<vpx_image_t> m_image;
}; };
ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec, const gfx::IntMargin& margin) ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec> vpxCodec, const gfx::IntMargin& margin)
: m_vpxCodec(std::move(vpxCodec)) : m_vpxCodec(std::move(vpxCodec))
, m_margin(margin) , m_margin(margin)
{ {
@ -314,9 +326,9 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
cfg.g_timebase.den = fps * timeScale; cfg.g_timebase.den = fps * timeScale;
cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
vpx_codec_ctx_t codec; ScopedVpxCodec codec(new vpx_codec_ctx_t);
if (vpx_codec_enc_init(&codec, codec_interface, &cfg, 0)) { if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) {
errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(&codec)); errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(codec.get()));
return nullptr; return nullptr;
} }
@ -326,7 +338,7 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
return nullptr; return nullptr;
} }
std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(codec, cfg, file)); std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(std::move(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), margin); return new ScreencastEncoder(std::move(vpxCodec), margin);
} }

View file

@ -26,7 +26,7 @@ public:
static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin); static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin);
class VPXCodec; class VPXCodec;
ScreencastEncoder(std::unique_ptr<VPXCodec>&&, const gfx::IntMargin& margin); ScreencastEncoder(std::unique_ptr<VPXCodec>, const gfx::IntMargin& margin);
void encodeFrame(const webrtc::VideoFrame& videoFrame); void encodeFrame(const webrtc::VideoFrame& videoFrame);

View file

@ -1,2 +1,2 @@
1336 1337
Changed: lushnikov@chromium.org Tue Jul 26 17:42:25 MSK 2022 Changed: yurys@chromium.org Thu Jul 28 13:34:25 PDT 2022

View file

@ -45,6 +45,18 @@ namespace mozilla {
namespace { namespace {
struct VpxCodecDeleter {
void operator()(vpx_codec_ctx_t* codec) {
if (codec) {
vpx_codec_err_t ret = vpx_codec_destroy(codec);
if (ret != VPX_CODEC_OK)
fprintf(stderr, "Failed to destroy codec: %s\n", vpx_codec_error(codec));
}
}
};
using ScopedVpxCodec = std::unique_ptr<vpx_codec_ctx_t, VpxCodecDeleter>;
// Number of timebase unints per one frame. // Number of timebase unints per one frame.
constexpr int timeScale = 1000; constexpr int timeScale = 1000;
@ -183,8 +195,8 @@ private:
class ScreencastEncoder::VPXCodec { class ScreencastEncoder::VPXCodec {
public: public:
VPXCodec(vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file) VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file)
: m_codec(codec) : m_codec(std::move(codec))
, m_cfg(cfg) , m_cfg(cfg)
, m_file(file) , m_file(file)
, m_writer(new WebMFileWriter(file, &m_cfg)) , m_writer(new WebMFileWriter(file, &m_cfg))
@ -233,14 +245,14 @@ private:
vpx_codec_iter_t iter = nullptr; vpx_codec_iter_t iter = nullptr;
const vpx_codec_cx_pkt_t *pkt = nullptr; const vpx_codec_cx_pkt_t *pkt = nullptr;
int flags = 0; int flags = 0;
const vpx_codec_err_t res = vpx_codec_encode(&m_codec, img, m_pts, duration, flags, VPX_DL_REALTIME); const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME);
if (res != VPX_CODEC_OK) { if (res != VPX_CODEC_OK) {
fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(&m_codec)); fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get()));
return false; return false;
} }
bool gotPkts = false; bool gotPkts = false;
while ((pkt = vpx_codec_get_cx_data(&m_codec, &iter)) != nullptr) { while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) {
gotPkts = true; gotPkts = true;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
@ -266,7 +278,7 @@ private:
} }
RefPtr<nsIThread> m_encoderQueue; RefPtr<nsIThread> m_encoderQueue;
vpx_codec_ctx_t m_codec; ScopedVpxCodec m_codec;
vpx_codec_enc_cfg_t m_cfg; vpx_codec_enc_cfg_t m_cfg;
FILE* m_file { nullptr }; FILE* m_file { nullptr };
std::unique_ptr<WebMFileWriter> m_writer; std::unique_ptr<WebMFileWriter> m_writer;
@ -277,7 +289,7 @@ private:
std::unique_ptr<vpx_image_t> m_image; std::unique_ptr<vpx_image_t> m_image;
}; };
ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec, const gfx::IntMargin& margin) ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec> vpxCodec, const gfx::IntMargin& margin)
: m_vpxCodec(std::move(vpxCodec)) : m_vpxCodec(std::move(vpxCodec))
, m_margin(margin) , m_margin(margin)
{ {
@ -314,9 +326,9 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
cfg.g_timebase.den = fps * timeScale; cfg.g_timebase.den = fps * timeScale;
cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
vpx_codec_ctx_t codec; ScopedVpxCodec codec(new vpx_codec_ctx_t);
if (vpx_codec_enc_init(&codec, codec_interface, &cfg, 0)) { if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) {
errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(&codec)); errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(codec.get()));
return nullptr; return nullptr;
} }
@ -326,7 +338,7 @@ RefPtr<ScreencastEncoder> ScreencastEncoder::create(nsCString& errorString, cons
return nullptr; return nullptr;
} }
std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(codec, cfg, file)); std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(std::move(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), margin); return new ScreencastEncoder(std::move(vpxCodec), margin);
} }

View file

@ -26,7 +26,7 @@ public:
static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin); static RefPtr<ScreencastEncoder> create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin);
class VPXCodec; class VPXCodec;
ScreencastEncoder(std::unique_ptr<VPXCodec>&&, const gfx::IntMargin& margin); ScreencastEncoder(std::unique_ptr<VPXCodec>, const gfx::IntMargin& margin);
void encodeFrame(const webrtc::VideoFrame& videoFrame); void encodeFrame(const webrtc::VideoFrame& videoFrame);