32
32
#include "libav_deps.h"
33
33
#include "video_scaler.h"
36
38
namespace sfl_video {
38
VideoScaler::VideoScaler() : ctx_(0), mode_(SWS_FAST_BILINEAR) {}
40
VideoScaler::VideoScaler() : ctx_(0), mode_(SWS_FAST_BILINEAR), tmp_data_() {}
40
42
VideoScaler::~VideoScaler() { sws_freeContext(ctx_); }
42
void VideoScaler::scale(VideoFrame &input, VideoFrame &output)
44
void VideoScaler::scale(const VideoFrame &input, VideoFrame &output)
44
AVFrame *input_frame = input.get();
46
const AVFrame *input_frame = input.get();
45
47
AVFrame *output_frame = output.get();
47
49
ctx_ = sws_getCachedContext(ctx_,
61
63
sws_scale(ctx_, input_frame->data, input_frame->linesize, 0,
62
input_frame->height, output_frame->data, output_frame->linesize);
65
void VideoScaler::scale_and_pad(VideoFrame &input, VideoFrame &output,
64
input_frame->height, output_frame->data,
65
output_frame->linesize);
68
void VideoScaler::scale_with_aspect(const VideoFrame &input, VideoFrame &output)
70
AVFrame *output_frame = output.get();
71
scale_and_pad(input, output, 0, 0, output_frame->width,
72
output_frame->height, true);
75
static inline bool is_yuv_planar(const AVPixFmtDescriptor *desc)
77
unsigned used_bit_mask = (1u << desc->nb_components) - 1;
79
if (not (desc->flags & PIX_FMT_PLANAR)
80
or desc->flags & PIX_FMT_RGB)
83
/* handle formats that do not use all planes */
84
for (unsigned i = 0; i < desc->nb_components; ++i)
85
used_bit_mask &= ~(1u << desc->comp[i].plane);
87
return not used_bit_mask;
90
void VideoScaler::scale_and_pad(const VideoFrame &input, VideoFrame &output,
66
91
unsigned xoff, unsigned yoff,
67
unsigned dest_width, unsigned dest_height)
92
unsigned dest_width, unsigned dest_height,
69
AVFrame *input_frame = input.get();
95
const AVFrame *input_frame = input.get();
70
96
AVFrame *output_frame = output.get();
71
uint8_t *data[AV_NUM_DATA_POINTERS];
73
for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) {
74
if (output_frame->data[i]) {
75
const unsigned divisor = i == 0 ? 1 : 2;
76
unsigned offset = (yoff * output_frame->linesize[i] + xoff) / divisor;
77
data[i] = output_frame->data[i] + offset;
98
/* Correct destination width/height and offset if we need to keep input
102
const float local_ratio = (float)dest_width / dest_height;
103
const float input_ratio = (float)input_frame->width / input_frame->height;
105
if (local_ratio > input_ratio) {
106
auto old_dest_width = dest_width;
107
dest_width = dest_height * input_ratio;
108
xoff += (old_dest_width - dest_width) / 2;
110
auto old_dest_heigth = dest_height;
111
dest_height = dest_width / input_ratio;
112
yoff += (old_dest_heigth - dest_height) / 2;
116
// buffer overflow checks
117
assert(xoff + dest_width <= (unsigned)output_frame->width);
118
assert(yoff + dest_height <= (unsigned)output_frame->height);
82
120
ctx_ = sws_getCachedContext(ctx_,
83
121
input_frame->width,
84
122
input_frame->height,
134
// Make an offset'ed copy of output data from xoff and yoff
135
const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get((AVPixelFormat)output_frame->format);
136
if (is_yuv_planar(out_desc)) {
137
unsigned x_shift = out_desc->log2_chroma_w;
138
unsigned y_shift = out_desc->log2_chroma_h;
140
tmp_data_[0] = output_frame->data[0] + yoff * output_frame->linesize[0] + xoff;
141
tmp_data_[1] = output_frame->data[1] + (yoff >> y_shift) * output_frame->linesize[1] + (xoff >> x_shift);
142
tmp_data_[2] = output_frame->data[2] + (yoff >> y_shift) * output_frame->linesize[2] + (xoff >> x_shift);
143
tmp_data_[3] = nullptr;
145
memcpy(tmp_data_, output_frame->data, sizeof(tmp_data_));
146
tmp_data_[0] += yoff * output_frame->linesize[0] + xoff;
96
149
sws_scale(ctx_, input_frame->data, input_frame->linesize, 0,
97
input_frame->height, data, output_frame->linesize);
150
input_frame->height, tmp_data_, output_frame->linesize);
100
153
void VideoScaler::reset()