UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
resize_utils.cpp
Go to the documentation of this file.
1
7/*
8 * Copyright (c) 2014 Fundació i2CAT, Internet I Innovació Digital a Catalunya
9 * Copyright (c) 2015-2023 CESNET, z. s. p. o.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, is permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 *
25 * This product includes software developed by the Fundació i2CAT,
26 * Internet I Innovació Digital a Catalunya. This product also includes
27 * software developed by CESNET z.s.p.o.
28 *
29 * 4. Neither the name of the University nor of the Institute may be used
30 * to endorse or promote products derived from this software without
31 * specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
34 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
35 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
37 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
43 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
44 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 *
46 */
47
48#ifdef HAVE_CONFIG_H
49#include "config.h"
50#endif
51
52#include <cstdlib>
53#pragma GCC diagnostic push
54#pragma GCC diagnostic ignored "-Wcast-align"
55#pragma GCC diagnostic ignored "-Wcast-qual"
56#ifdef HAVE_OPENCV2_OPENCV_HPP
57#include <opencv2/opencv.hpp>
58#else
59#include <opencv2/imgproc.hpp>
60#include <opencv2/imgproc/types_c.h>
61#endif
62#pragma GCC diagnostic pop
63
65#include "debug.h"
66#include "utils/color_out.h"
67#include "video.h"
68
69#define DEFAULT_ALGO INTER_LINEAR
70#define MOD_NAME "[resize] "
71
72using cv::INTER_AREA;
73using cv::INTER_CUBIC;
74using cv::INTER_LANCZOS4;
75using cv::INTER_LINEAR;
76// using cv::INTER_LINEAR_EXACT;
77using cv::INTER_NEAREST;
78// using cv::INTER_NEAREST_EXACT;
79using cv::Mat;
80using cv::Rect;
81using cv::Size;
82
83static const char *resize_algo_to_string(int algo);
84
85static Mat ug_to_rgb_mat(codec_t codec, int width, int height, char *indata) {
86 Mat yuv;
87 Mat rgb;
88 int pix_fmt = CV_8UC2;
89 int cv_color = 0;
90 int num = 1;
91 int den = 1;
92
93 switch (codec) {
94 case RG48:
95 rgb.create(height, width, CV_16UC3);
96 rgb.data = (uchar*)indata;
97 return rgb;
98 case RGB:
99 rgb.create(height, width, CV_8UC3);
100 rgb.data = (uchar*)indata;
101 return rgb;
102 case RGBA:
103 cv_color = CV_RGBA2RGB;
104 pix_fmt = CV_8UC4;
105 break;
106 case I420:
107 pix_fmt = CV_8U;
108 num = 3;
109 den = 2;
110 cv_color = CV_YUV2RGB_I420;
111 break;
112 case UYVY:
113 cv_color = CV_YUV2RGB_UYVY;
114 break;
115 case YUYV:
116 cv_color = CV_YUV2RGB_YUYV;
117 break;
118 default:
119 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Unsupported codec: " << codec << "\n";
120 abort();
121 }
122 yuv.create(height * num / den, width, pix_fmt);
123 yuv.data = (uchar*)indata;
124 cvtColor(yuv, rgb, cv_color);
125
126 return rgb;
127}
128
129static int
131{
132 return get_bits_per_component(pixfmt) == DEPTH16 ? CV_16UC3 : CV_8UC3;
133}
134
135static void
136resize_frame_dimensions(char *indata, codec_t in_color, char *outdata, int width,
137 int height, int target_width,
138 int target_height, int algo)
139{
140 const codec_t out_color =
141 get_bits_per_component(in_color) == 16 ? RG48 : RGB;
142 Mat rgb = ug_to_rgb_mat(in_color, (int) width, (int) height, indata);
143
144 double in_aspect = (double) width / height;
145 double out_aspect = (double) target_width / target_height;
146 Rect r;
147 if (in_aspect == out_aspect) {
148 r.x = 0;
149 r.y = 0;
150 r.width = target_width;
151 r.height = target_height;
152 } else if (in_aspect > out_aspect) {
153 r.x = 0;
154 r.width = target_width;
155 r.height = (int) (target_width / in_aspect);
156 r.y = (target_height - r.height) / 2;
157 // clear top and bottom margin
158 size_t linesize = vc_get_linesize(target_width, out_color);
159 size_t top_margin_size = r.y * linesize;
160 size_t bottom_margin_size = (target_height - r.y - r.height) * linesize;
161 memset(outdata, 0, top_margin_size);
162 memset(outdata + linesize * target_height - bottom_margin_size, 0, bottom_margin_size);
163 } else {
164 r.y = 0;
165 r.height = target_height;
166 r.width = (int) (target_height * in_aspect);
167 r.x = (target_width - r.width) / 2;
168 // clear left and right margins
169 size_t linesize = vc_get_linesize(target_width, out_color);
170 size_t left_margin_size = vc_get_linesize(r.x, out_color);
171 size_t right_margin_size = vc_get_linesize(target_width - r.x - r.width, out_color);
172 for (int i = 0; i < target_height; ++i) {
173 memset(outdata + i * linesize, 0, left_margin_size);
174 memset(outdata + (i + 1) * linesize - right_margin_size, 0, right_margin_size);
175 }
176 }
177
178 Mat out((int) target_height, (int) target_width,
179 get_out_cv_data_type(in_color), outdata);
180 resize(rgb, out(r), r.size(), 0, 0, algo);
181}
182
183void
184resize_frame(char *indata, codec_t in_color, char *outdata, int width,
185 int height, struct resize_param *resize_spec)
186{
187 if (resize_spec->algo == RESIZE_ALGO_DFL) {
188 resize_spec->algo = DEFAULT_ALGO;
189 MSG(NOTICE, "using resize algorithm: %s\n",
191 }
192
193 DEBUG_TIMER_START(resize);
194 if (resize_spec->mode == resize_param::USE_FRACTION) {
195 const double factor = resize_spec->factor;
196 Mat rgb = ug_to_rgb_mat(in_color, (int) width, (int) height, indata);
197 Mat out((int) (height * factor), (int) (width * factor),
198 get_out_cv_data_type(in_color), outdata);
199 resize(rgb, out, Size(0, 0), factor, factor, resize_spec->algo);
200 } else if (resize_spec->mode == resize_param::USE_DIMENSIONS) {
201 resize_frame_dimensions(indata, in_color, outdata, width, height,
202 resize_spec->target_width,
203 resize_spec->target_height, resize_spec->algo);
204 } else {
205 abort();
206 }
207 DEBUG_TIMER_STOP(resize);
208}
209
210static const struct {
211 int val;
212 const char *name;
213} interp_map[] = {
214 {INTER_NEAREST, "nearest" },
215 { INTER_LINEAR, "linear" },
216 { INTER_CUBIC, "cubic" },
217 { INTER_AREA, "area" },
218 { INTER_LANCZOS4, "lanczos4" },
219 // { INTER_LINEAR_EXACT, "linear_exact" },
220 // { INTER_NEAREST_EXACT, "nearest_exact"},
222
223int
225{
226 if (strcmp(str, "help") == 0) {
227 color_printf("Available resize algorithms:\n");
228 for (auto const &i : interp_map) {
229 color_printf("\t" TBOLD("%s") "%s\n", i.name,
230 i.val == DEFAULT_ALGO ? " (default)" : "");
231 }
233 }
234 for (auto const &i : interp_map) {
235 if (strcmp(i.name, str) == 0) {
236 return i.val;
237 }
238 }
239 return RESIZE_ALGO_UNKN;
240}
241
242static const char *
244{
245 for (auto const &i : interp_map) {
246 if (i.val == algo) {
247 return i.name;
248 }
249 }
250 return "(unknown algo!)";
251}
252
253/* vim: set expandtab sw=4: */
int vc_get_linesize(unsigned int width, codec_t codec)
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
#define DEBUG_TIMER_START(name)
Definition debug.h:324
#define DEBUG_TIMER_STOP(name)
Definition debug.h:325
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG(level)
Definition debug.h:313
static const char * resize_algo_to_string(int algo)
#define DEFAULT_ALGO
static Mat ug_to_rgb_mat(codec_t codec, int width, int height, char *indata)
static void resize_frame_dimensions(char *indata, codec_t in_color, char *outdata, int width, int height, int target_width, int target_height, int algo)
static int get_out_cv_data_type(codec_t pixfmt)
const char * name
int val
int resize_algo_from_string(const char *str)
#define MOD_NAME
static const struct @12 interp_map[]
void resize_frame(char *indata, codec_t in_color, char *outdata, int width, int height, struct resize_param *resize_spec)
#define RESIZE_ALGO_DFL
#define RESIZE_ALGO_UNKN
#define RESIZE_ALGO_HELP_SHOWN
enum resize_param::resize_mode mode
@ DEPTH16
Definition types.h:129
codec_t
Definition types.h:65
@ YUYV
YCbCr 422 8-bit - Y0 Cb Y1 Cr.
Definition types.h:72
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ RG48
16-bit RGB little-endian (RlRhGl...)
Definition types.h:95
@ I420
planar YCbCr 4:2:0
Definition types.h:97
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
This is an umbrella header for video functions.
int get_bits_per_component(codec_t codec)