Ring Daemon 16.0.0
Loading...
Searching...
No Matches
video_scaler.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "libav_deps.h" // MUST BE INCLUDED FIRST
19#include "libav_utils.h"
20#include "video_scaler.h"
21#include "media_buffer.h"
22#include "logger.h"
23
24#include <cassert>
25
26namespace jami {
27namespace video {
28
30 : ctx_(0)
31 , mode_(SWS_FAST_BILINEAR)
32 , tmp_data_()
33{}
34
39
40void
42 scale(input.pointer(), output.pointer());
43}
44
45void
47{
48 ctx_ = sws_getCachedContext(ctx_,
49 input_frame->width,
50 input_frame->height,
51 (AVPixelFormat) input_frame->format,
52 output_frame->width,
53 output_frame->height,
55 mode_,
56 NULL,
57 NULL,
58 NULL);
59 if (!ctx_) {
60 JAMI_ERR("Unable to create a scaler context");
61 return;
62 }
63
64 sws_scale(ctx_,
65 input_frame->data,
66 input_frame->linesize,
67 0,
68 input_frame->height,
69 output_frame->data,
70 output_frame->linesize);
71}
72
73void
75{
76 if (input.width() == output.width() && input.height() == output.height()) {
77 if (input.format() != output.format()) {
79 output.copyFrom(*outPtr);
80 } else {
81 output.copyFrom(input);
82 }
83 } else {
84 auto output_frame = output.pointer();
85 scale_and_pad(input, output, 0, 0, output_frame->width, output_frame->height, true);
86 }
87}
88
89void
92 unsigned xoff,
93 unsigned yoff,
94 unsigned dest_width,
95 unsigned dest_height,
96 bool keep_aspect)
97{
98 const auto input_frame = input.pointer();
99 auto output_frame = output.pointer();
100
101 /* Correct destination width/height and offset if we need to keep input
102 * frame aspect.
103 */
104 if (keep_aspect) {
105 const float local_ratio = (float) dest_width / dest_height;
106 const float input_ratio = (float) input_frame->width / input_frame->height;
107
108 if (local_ratio > input_ratio) {
111 xoff += (old_dest_width - dest_width) / 2;
112 } else {
116 }
117 }
118
119 // buffer overflow checks
120 if ((xoff + dest_width > (unsigned) output_frame->width)
121 || (yoff + dest_height > (unsigned) output_frame->height)) {
122 JAMI_ERR("Unable to scale video");
123 return;
124 }
125
126 ctx_ = sws_getCachedContext(ctx_,
127 input_frame->width,
128 input_frame->height,
129 (AVPixelFormat) input_frame->format,
132 (AVPixelFormat) output_frame->format,
133 mode_,
134 NULL,
135 NULL,
136 NULL);
137 if (!ctx_) {
138 JAMI_ERR("Unable to create a scaler context");
139 return;
140 }
141
142 // Make an offset'ed copy of output data from xoff and yoff
144 memset(tmp_data_, 0, sizeof(tmp_data_));
145 for (int i = 0; i < 4 && output_frame->linesize[i]; i++) {
146 signed x_shift = xoff, y_shift = yoff;
147 if (i == 1 || i == 2) {
148 x_shift = -((-x_shift) >> out_desc->log2_chroma_w);
149 y_shift = -((-y_shift) >> out_desc->log2_chroma_h);
150 }
151 auto x_step = out_desc->comp[i].step;
152 tmp_data_[i] = output_frame->data[i] + y_shift * output_frame->linesize[i]
153 + x_shift * x_step;
154 }
155
156 sws_scale(ctx_,
157 input_frame->data,
158 input_frame->linesize,
159 0,
160 input_frame->height,
161 tmp_data_,
162 output_frame->linesize);
163}
164
165std::unique_ptr<VideoFrame>
167{
168 auto output = std::make_unique<VideoFrame>();
169 output->reserve(pix, input.width(), input.height());
170 scale(input, *output);
171 av_frame_copy_props(output->pointer(), input.pointer());
172 return output;
173}
174
175void
177{
178 if (ctx_) {
179 sws_freeContext(ctx_);
180 ctx_ = nullptr;
181 }
182}
183
184} // namespace video
185} // namespace jami
void scale(const AVFrame *input, AVFrame *output)
void scale_with_aspect(const VideoFrame &input, VideoFrame &output)
void scale_and_pad(const VideoFrame &input, VideoFrame &output, unsigned xoff, unsigned yoff, unsigned dest_width, unsigned dest_height, bool keep_aspect)
std::unique_ptr< VideoFrame > convertFormat(const VideoFrame &input, AVPixelFormat pix)
const AVFrame * pointer() const noexcept
int format() const noexcept
int height() const noexcept
int width() const noexcept
#define JAMI_ERR(...)
Definition logger.h:218
void emitSignal(Args... args)
Definition ring_signal.h:64