UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
resize.c
Go to the documentation of this file.
1
7/*
8 * Copyright (c) 2014 Fundació i2CAT, Internet I Innovació Digital a Catalunya
9 * Copyright (c) 2014-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#include <errno.h>
49#include <stdlib.h>
50#include <string.h>
51
52#include "capture_filter.h"
54#include "debug.h"
55#include "lib_common.h"
56#include "utils/color_out.h"
57#include "utils/macros.h"
58#include "utils/parallel_conv.h"
59#include "video.h"
60#include "video_codec.h"
62
63#define MOD_NAME "[resize filter] "
64
65struct module;
66
67static int init(struct module *parent, const char *cfg, void **state);
68static void done(void *state);
69static struct video_frame *filter(void *state, struct video_frame *in);
70
79
80static void usage() {
81 printf("Scaling by scale factor:\n\n");
82 printf("resize usage:\n");
83 color_printf("\t" TBOLD(TRED("resize") ":numerator[/denominator][algo=<a>]") "\n");
84 printf("or\n");
85 printf("\t" TBOLD(TRED("resize") ":<width>x<height>[algo=<a>]") "\n\n");
86 color_printf("Scaling examples:\n"
87 "\t" TBOLD("resize:1/2") " | " TBOLD("resize:0.5")
88 " - downscale input frame size by scale factor of 2\n"
89 "\t" TBOLD("resize:1280x720")
90 " - scales input to 1280x720\n"
91 "\t" TBOLD("resize:720x576")
92 " - scales input to PAL\n");
94 "\nOptions:\n"
95 "\t" TBOLD(
96 "algo") " - scaling algorithm to use (list with `algo:help`)\n");
97 color_printf("\n");
98}
99
100static int
101parse_fmt(char *cfg, struct resize_param *param)
102{
103 char *save_ptr = NULL;
104 char *item = NULL;
105 while ((item = strtok_r(cfg, ":", &save_ptr))) {
106 cfg = NULL;
107 if (IS_KEY_PREFIX(item, "algorithm")) {
108 param->algo = resize_algo_from_string(strchr(item, '=') + 1);
109 if (param->algo < 0) {
110 return param->algo == RESIZE_ALGO_HELP_SHOWN ? 1 : -1;
111 }
112 continue;
113 }
114 if (!isdigit(item[0]) && item[0] != '.') {
116 "[RESIZE ERROR] Unrecognized part of config "
117 "string: %s\n",
118 item);
119 return -1;
120 }
121 if (strchr(item, 'x')) {
122 param->mode = USE_DIMENSIONS;
123 param->target_width = strtol(item, NULL, 10);
124 param->target_height = strtol(strchr(item, 'x') + 1, NULL, 10);
125 } else {
126 param->mode = USE_FRACTION;
127 param->factor = strtod(item, NULL);
128 if (strchr(item, '/')) {
129 const long den = strtol(strchr(item, '/') + 1, NULL, 10);
130 param->factor = den <= 0 ? .0 : param->factor / den;
131 }
132 }
133 }
134
135 if (param->mode == USE_DIMENSIONS && param->target_width > 0 &&
136 param->target_height > 0) {
137 return 0;
138 }
139 if (param->mode == USE_FRACTION && param->factor > 0) {
140 return 0;
141 }
142
143 MSG(ERROR, "No or incorrect resize size!\n");
144 return -1;
145}
146
147static int init(struct module * parent, const char *cfg, void **state)
148{
149 UNUSED(parent);
150 struct resize_param param = { .algo = RESIZE_ALGO_DFL };
151
152 if(strcasecmp(cfg, "help") == 0) {
153 usage();
154 return 1;
155 }
156
157 char *fmt = strdup(cfg);
158 const int rc = parse_fmt(fmt, &param);
159 free(fmt);
160 if (rc != 0) {
161 return rc;
162 }
163
164 struct state_resize *s = calloc(1, sizeof(struct state_resize));
165 s->param = param;
166
167 *state = s;
168 return 0;
169}
170
171static void
173{
174 vf_free(s->dec_frame);
175 s->dec_frame = NULL;
176}
177
178static void
180{
182 free(state);
183}
184
185static bool
187{
189 return true;
190 }
191 struct video_desc dec_desc = video_desc_from_frame(in);
193 const codec_t supp_in_codecs[] = { RESIZE_SUPPORTED_PIXFMT_INIT,
195 if (codec_is_in_set(in->color_spec, supp_in_codecs)) {
196 dec_desc.color_spec = in->color_spec;
197 s->decoder = vc_memcpy;
198 } else {
199 s->decoder = get_best_decoder_from(in->color_spec, supp_in_codecs,
200 &dec_desc.color_spec);
201 if (s->decoder == NULL) {
202 MSG(ERROR,
203 "Cannot decode %s to neither of supported input formats!\n",
205 return false;
206 }
207 }
210 MSG(INFO, "Decoding through %s to output pixfmt %s.\n",
211 get_codec_name(dec_desc.color_spec),
213
214 if (s->param.mode == USE_DIMENSIONS) {
217 } else {
218 s->out_desc.width = in->tiles[0].width * s->param.factor;
219 s->out_desc.height = in->tiles[0].height * s->param.factor;
220 }
223 if (s->decoder != vc_memcpy) {
224 s->dec_frame = vf_alloc_desc_data(dec_desc);
225 }
226 MSG(NOTICE, "resizing from %dx%d to %dx%d\n", s->saved_desc.width,
228 return true;
229}
230
231static struct video_frame *filter(void *state, struct video_frame *in)
232{
233 struct state_resize *s = state;
234
235 if (!reconfigure_if_needed(s, in)) {
237 return NULL;
238 }
239
240 struct video_frame *out_frame = vf_alloc_desc(s->out_desc);
241 if (s->vo_pp_out_buffer) {
242 out_frame->tiles[0].data = s->vo_pp_out_buffer;
243 } else {
244 out_frame->tiles[0].data = (char *) malloc(out_frame->tiles[0].data_len);
246 }
247
248 for (unsigned int i = 0; i < out_frame->tile_count; i++) {
249 if (s->decoder != vc_memcpy) {
251 (int) in->tiles[i].height, s->dec_frame->tiles[i].data,
253 in->tiles[i].data,
255 0);
256 }
257 struct video_frame *const in_frame =
258 s->decoder == vc_memcpy ? in : s->dec_frame;
259
260 resize_frame(in_frame->tiles[i].data, in_frame->color_spec,
261 out_frame->tiles[i].data, (int) in_frame->tiles[i].width,
262 (int) in_frame->tiles[i].height, &s->param);
263 }
264
266
267 out_frame->callbacks.dispose = vf_free;
268
269 return out_frame;
270}
271
272static void vo_pp_set_out_buffer(void *state, char *buffer)
273{
274 struct state_resize *s = state;
275 s->vo_pp_out_buffer = buffer;
276}
277
279 init,
280 done,
281 filter,
282};
283
285// coverity[leaked_storage:SUPPRESS]
287
288/* vim: set expandtab sw=4: */
#define UNUSED(x)
void ** state
const char * fmt
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
void vf_data_deleter(struct video_frame *buf)
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
const char * get_codec_name(codec_t codec)
#define CAPTURE_FILTER_ABI_VERSION
#define ADD_VO_PP_CAPTURE_FILTER_WRAPPER(name, init, filter, done, set_out_buf, get_prop_callb)
int color_printf(const char *format,...)
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
@ LIBRARY_CLASS_CAPTURE_FILTER
Definition lib_common.h:75
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
void parallel_pix_conv(int height, char *out, int out_linesize, const char *in, int in_linesize, decoder_t decode, int threads)
decoder_t get_best_decoder_from(codec_t in, const codec_t *out_candidates, codec_t *out)
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
decoder_func_t vc_memcpy
dummy conversion - ptr to it returned if no conversion needed
static const struct capture_filter_info capture_filter_resize
Definition resize.c:278
static struct video_frame * filter(void *state, struct video_frame *in)
Definition resize.c:231
static int parse_fmt(char *cfg, struct resize_param *param)
Definition resize.c:101
static void cleanup_common(struct state_resize *s)
Definition resize.c:172
static void usage()
Definition resize.c:80
static void vo_pp_set_out_buffer(void *state, char *buffer)
Definition resize.c:272
static bool reconfigure_if_needed(struct state_resize *s, const struct video_frame *in)
Definition resize.c:186
static void done(void *state)
Definition resize.c:179
static int init(struct module *parent, const char *cfg, void **state)
Definition resize.c:147
int resize_algo_from_string(const char *str)
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_HELP_SHOWN
#define RESIZE_SUPPORTED_PIXFMT_INIT
const char * parent
Definition settings.cpp:198
const char * param
Definition settings.cpp:195
Definition hd-rum.c:27
enum resize_param::resize_mode mode
decoder_t decoder
Definition resize.c:76
struct resize_param param
Definition resize.c:72
char * vo_pp_out_buffer
buffer to write to if we use vo_pp wrapper (otherwise unused)
Definition resize.c:75
struct video_frame * dec_frame
Definition resize.c:77
struct video_desc saved_desc
Definition resize.c:73
struct video_desc out_desc
Definition resize.c:74
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
codec_t color_spec
Definition types.h:182
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* data_deleter)(struct video_frame *)
Definition types.h:256
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
unsigned int tile_count
Definition types.h:344
struct video_frame_callbacks callbacks
Definition types.h:324
codec_t color_spec
Definition types.h:306
@ DEPTH8
Definition types.h:126
codec_t
Definition types.h:65
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ RG48
16-bit RGB little-endian (RlRhGl...)
Definition types.h:95
This is an umbrella header for video functions.
bool codec_is_in_set(codec_t codec, const codec_t *set)
int get_bits_per_component(codec_t codec)
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.
#define VIDEO_FRAME_DISPOSE(frame)
Definition video_frame.h:76