maintain aspect ratio when using software encoder
This commit is contained in:
+70
-4
@@ -81,9 +81,16 @@ public:
|
|||||||
img.row_pitch, 0
|
img.row_pitch, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
int ret = sws_scale(sws.get(), (std::uint8_t *const *)&img.data, linesizes, 0, img.height, frame->data, frame->linesize);
|
std::uint8_t *const data[] {
|
||||||
|
frame->data[0] + offset,
|
||||||
|
frame->data[1] + offset / 2,
|
||||||
|
frame->data[2] + offset / 2,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = sws_scale(sws.get(), (std::uint8_t *const *)&img.data, linesizes, 0, img.height, data, frame->linesize);
|
||||||
if(ret <= 0) {
|
if(ret <= 0) {
|
||||||
BOOST_LOG(fatal) << "Couldn't convert image to required format and/or size"sv;
|
BOOST_LOG(error) << "Couldn't convert image to required format and/or size"sv;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -98,7 +105,63 @@ public:
|
|||||||
0, 1 << 16, 1 << 16);
|
0, 1 << 16, 1 << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(int in_width, int in_height, int out_width, int out_height, AVFrame *frame, AVPixelFormat format) {
|
/**
|
||||||
|
* When preserving aspect ratio, ensure that padding is black
|
||||||
|
*/
|
||||||
|
int prefill(AVFrame *frame, AVPixelFormat format) {
|
||||||
|
auto width = frame->width;
|
||||||
|
auto height = frame->height;
|
||||||
|
|
||||||
|
sws_t sws {
|
||||||
|
sws_getContext(
|
||||||
|
width, height, AV_PIX_FMT_BGR0,
|
||||||
|
width, height, format,
|
||||||
|
SWS_LANCZOS | SWS_ACCURATE_RND,
|
||||||
|
nullptr, nullptr, nullptr)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!sws) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::buffer_t<std::uint32_t> img { (std::size_t)(width * height) };
|
||||||
|
std::fill(std::begin(img), std::end(img), 0);
|
||||||
|
|
||||||
|
const int linesizes[2] {
|
||||||
|
width, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
av_frame_make_writable(frame);
|
||||||
|
|
||||||
|
auto data = img.begin();
|
||||||
|
int ret = sws_scale(sws.get(), (std::uint8_t *const *)&data, linesizes, 0, height, frame->data, frame->linesize);
|
||||||
|
if(ret <= 0) {
|
||||||
|
BOOST_LOG(error) << "Couldn't convert image to required format and/or size"sv;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init(int in_width, int in_height, AVFrame *frame, AVPixelFormat format) {
|
||||||
|
if(prefill(frame, format)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto out_width = frame->width;
|
||||||
|
auto out_height = frame->height;
|
||||||
|
|
||||||
|
// Ensure aspect ratio is maintained
|
||||||
|
auto scalar = std::fminf((float)out_width / in_width, (float)out_height / in_height);
|
||||||
|
out_width = in_width * scalar;
|
||||||
|
out_height = in_height * scalar;
|
||||||
|
|
||||||
|
// result is always positive
|
||||||
|
auto offsetX = (frame->width - out_width) / 2;
|
||||||
|
auto offsetY = (frame->height - out_height) / 2;
|
||||||
|
offset = offsetX + offsetY * frame->width;
|
||||||
|
|
||||||
sws.reset(sws_getContext(
|
sws.reset(sws_getContext(
|
||||||
in_width, in_height, AV_PIX_FMT_BGR0,
|
in_width, in_height, AV_PIX_FMT_BGR0,
|
||||||
out_width, out_height, format,
|
out_width, out_height, format,
|
||||||
@@ -112,6 +175,9 @@ public:
|
|||||||
~swdevice_t() override {}
|
~swdevice_t() override {}
|
||||||
|
|
||||||
sws_t sws;
|
sws_t sws;
|
||||||
|
|
||||||
|
// offset of input image to output frame in pixels
|
||||||
|
int offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct encoder_t {
|
struct encoder_t {
|
||||||
@@ -698,7 +764,7 @@ std::optional<session_t> make_session(const encoder_t &encoder, const config_t &
|
|||||||
if(!hwdevice->data) {
|
if(!hwdevice->data) {
|
||||||
auto device_tmp = std::make_unique<swdevice_t>();
|
auto device_tmp = std::make_unique<swdevice_t>();
|
||||||
|
|
||||||
if(device_tmp->init(width, height, config.width, config.height, frame.get(), sw_fmt)) {
|
if(device_tmp->init(width, height, frame.get(), sw_fmt)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user