0

media: Manually scale frames for OpenH264 encoder when needed

OpenH264 can resize frames automatically only if
 - the input and output aspect ratios are the same and
 - the input is larger than the output in both dimensions.

This CL does manual scaling when these conditions are not met.
Bug: 404887295

Change-Id: I9ba4fb55231abc157b359108673d62a558b8babf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6410892
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1439813}
This commit is contained in:
Eugene Zemtsov 2025-03-28 17:56:51 -07:00 committed by Chromium LUCI CQ
parent 40edbf5379
commit 30951827e2
5 changed files with 27 additions and 53 deletions

@ -15,6 +15,7 @@
#include "base/trace_event/trace_event.h"
#include "media/base/media_switches.h"
#include "media/base/svc_scalability_mode.h"
#include "media/base/video_aspect_ratio.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "media/video/video_encoder_info.h"
@ -147,6 +148,22 @@ void SetUpOpenH264Params(VideoCodecProfile profile,
}
}
// OpenH264 can resize frames automatically as long as
// - the input and output aspect ratios are the same and
// - the input is larger than the output in both dimensions.
bool NeedsManualResizing(const gfx::Size& src, const gfx::Size& dst) {
if (src.IsEmpty() || dst.IsEmpty()) {
return true;
}
if (dst.width() > src.width() || dst.height() > src.height()) {
return true;
}
return VideoAspectRatio::PAR(src.width(), src.height()) !=
VideoAspectRatio::PAR(dst.width(), dst.height());
}
} // namespace
OpenH264VideoEncoder::ISVCEncoderDeleter::ISVCEncoderDeleter() = default;
@ -380,6 +397,9 @@ void OpenH264VideoEncoder::Encode(scoped_refptr<VideoFrame> frame,
"No frame provided for encoding."));
return;
}
TRACE_EVENT1("media", "OpenH264::EncodeFrame", "timestamp",
frame->timestamp());
const bool supported_format = frame->format() == PIXEL_FORMAT_NV12 ||
frame->format() == PIXEL_FORMAT_I420 ||
frame->format() == PIXEL_FORMAT_XBGR ||
@ -407,9 +427,13 @@ void OpenH264VideoEncoder::Encode(scoped_refptr<VideoFrame> frame,
}
}
if (frame->format() != PIXEL_FORMAT_I420) {
// OpenH264 can resize frame automatically, but since we're converting
// pixel format anyway we can do resize as well.
if (frame->format() != PIXEL_FORMAT_I420 ||
NeedsManualResizing(frame->visible_rect().size(), options_.frame_size)) {
// In cases where we need to
// - enlarge the frame
// - change the pixel format or
// - change the aspect ratio
// we are forced to convert and rescale manually.
auto i420_frame = frame_pool_.CreateFrame(
PIXEL_FORMAT_I420, options_.frame_size, gfx::Rect(options_.frame_size),
options_.frame_size, frame->timestamp());
@ -462,8 +486,6 @@ void OpenH264VideoEncoder::Encode(scoped_refptr<VideoFrame> frame,
}
SFrameBSInfo frame_info = {};
TRACE_EVENT1("media", "OpenH264::EncodeFrame", "timestamp",
frame->timestamp());
if (int err = codec_->EncodeFrame(&picture, &frame_info)) {
std::move(done_cb).Run(
EncoderStatus(EncoderStatus::Codes::kEncoderFailedEncode,

@ -1,12 +0,0 @@
This is a testharness.js-based test.
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 128 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 128 Format:I420 expected 0 +/- 0.05 but got 0.35520482281454246
[FAIL] Scaling Image in Encoding from 32 x 32 to 96 x 96 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 32 x 32 to 96 x 96 Format:I420 expected 0 +/- 0.05 but got 0.3893183778140886
[FAIL] Scaling Image in Encoding from 64 x 32 to 128 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 32 to 128 x 64 Format:I420 expected 0 +/- 0.05 but got 0.3551470588235294
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 192 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 192 Format:I420 expected 0 +/- 0.05 but got 0.37569210409858395
[FAIL] Scaling Image in Encoding from 128 x 192 to 64 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 128 x 192 to 64 x 64 Format:I420 expected 0 +/- 0.05 but got 0.20954765369689543
Harness: the test ran to completion.

@ -1,12 +0,0 @@
This is a testharness.js-based test.
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 128 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 128 Format:I420 expected 0 +/- 0.05 but got 0.35520482281454246
[FAIL] Scaling Image in Encoding from 32 x 32 to 96 x 96 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 32 x 32 to 96 x 96 Format:I420 expected 0 +/- 0.05 but got 0.3893183778140886
[FAIL] Scaling Image in Encoding from 64 x 32 to 128 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 32 to 128 x 64 Format:I420 expected 0 +/- 0.05 but got 0.3551470588235294
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 192 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 192 Format:I420 expected 0 +/- 0.05 but got 0.37569210409858395
[FAIL] Scaling Image in Encoding from 128 x 192 to 64 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 128 x 192 to 64 x 64 Format:I420 expected 0 +/- 0.05 but got 0.20954765369689543
Harness: the test ran to completion.

@ -1,12 +0,0 @@
This is a testharness.js-based test.
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 128 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 128 Format:I420 expected 0 +/- 0.05 but got 0.35520482281454246
[FAIL] Scaling Image in Encoding from 32 x 32 to 96 x 96 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 32 x 32 to 96 x 96 Format:I420 expected 0 +/- 0.05 but got 0.3893183778140886
[FAIL] Scaling Image in Encoding from 64 x 32 to 128 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 32 to 128 x 64 Format:I420 expected 0 +/- 0.05 but got 0.3551470588235294
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 192 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 192 Format:I420 expected 0 +/- 0.05 but got 0.37569210409858395
[FAIL] Scaling Image in Encoding from 128 x 192 to 64 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 128 x 192 to 64 x 64 Format:I420 expected 0 +/- 0.05 but got 0.20954765369689543
Harness: the test ran to completion.

@ -1,12 +0,0 @@
This is a testharness.js-based test.
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 128 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 128 Format:I420 expected 0 +/- 0.05 but got 0.35520482281454246
[FAIL] Scaling Image in Encoding from 32 x 32 to 96 x 96 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 32 x 32 to 96 x 96 Format:I420 expected 0 +/- 0.05 but got 0.3893183778140886
[FAIL] Scaling Image in Encoding from 64 x 32 to 128 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 32 to 128 x 64 Format:I420 expected 0 +/- 0.05 but got 0.3551470588235294
[FAIL] Scaling Image in Encoding from 64 x 64 to 128 x 192 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 64 x 64 to 128 x 192 Format:I420 expected 0 +/- 0.05 but got 0.37569210409858395
[FAIL] Scaling Image in Encoding from 128 x 192 to 64 x 64 Format: I420
assert_approx_equals: Scaled Image differs too much! Scaling from 128 x 192 to 64 x 64 Format:I420 expected 0 +/- 0.05 but got 0.20954765369689543
Harness: the test ran to completion.