UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
vo_postprocess.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2011-2024 CESNET
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
50#include "vo_postprocess.h"
51
52#include <assert.h> // for assert
53#include <stdint.h> // for uint32_t
54#include <stdio.h> // for NULL, printf, size_t
55#include <stdlib.h> // for free, malloc
56#include <string.h> // for strchr, strcmp, strdup, strtok_r
57
58#include "debug.h" // for log_msg, LOG_LEVEL_ERROR
59#include "lib_common.h" // for library_class, list_modules, load_library
60#include "utils/color_out.h" // for color_printf, TERM_BOLD, TERM_RESET
61#include "utils/list.h" // for simple_linked_list_it_init, simple_link...
62#include "utils/macros.h" // for to_fourcc
63#include "video_codec.h" // for vc_get_linesize
64#include "video_display.h" // for display_prop_vid_mode
65
66#define MAGIC to_fourcc('V', 'P', 'S', 'T')
67#define MAGIC_SINGLE to_fourcc('V', 'P', 'S', 'S')
68#define MOD_NAME "[vo_postprocess] "
69
71 uint32_t magic;
73 void *state;
74 struct video_frame *f;
75};
76
81
83{
84 printf("Usage:\n");
85 color_printf(TERM_BOLD "\t-p <postprocess_module>[:<args>] | help\n" TERM_RESET);
86 printf("\n");
87 printf("Possible postprocess modules:\n");
89}
90
91static _Bool init(struct vo_postprocess_state *s, const char *config_string) {
92 char *cpy = strdup(config_string);
93 char *tmp = cpy;
94 char *save_ptr = NULL;
95 char *item = NULL;
96
97 while ((item = strtok_r(tmp, ",", &save_ptr)) != NULL) {
98 const char *vo_postprocess_options = "";
99 char *lib_name = item;
100 if (strchr(lib_name, ':')) {
101 vo_postprocess_options = strchr(lib_name, ':') + 1;
102 *strchr(lib_name, ':') = '\0';
103 }
105 if (!funcs) {
106 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown postprocess module: %s\n", lib_name);
107 free(cpy);
108 return 0;
109 }
110 struct vo_postprocess_state_single *state = malloc(sizeof(struct vo_postprocess_state_single));
111 state->magic = MAGIC_SINGLE;
112 state->funcs = funcs;
113 state->state = state->funcs->init(vo_postprocess_options);
114 if (!state->state) {
115 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Postprocessing initialization failed: %s\n", config_string);
116 free(cpy);
117 free(state);
118 return 0;
119 }
121
122 tmp = NULL;
123 }
124 free(cpy);
125 return 1;
126}
127
128struct vo_postprocess_state *vo_postprocess_init(const char *config_string)
129{
130 if (!config_string) {
131 return NULL;
132 }
133
134 if (strcmp(config_string, "help") == 0 || strcmp(config_string, "fullhelp") == 0) {
135 show_vo_postprocess_help(strcmp(config_string, "fullhelp") == 0);
136 return NULL;
137 }
138
139 struct vo_postprocess_state *s = (struct vo_postprocess_state *) malloc(sizeof(struct vo_postprocess_state));
140 s->magic = MAGIC;
142
143 if (!init(s, config_string)) {
145 return NULL;
146 }
147
148 return s;
149}
150
151bool
153 struct video_desc desc)
154{
155 if (s == NULL) {
156 return false;
157 }
158
159 bool filter_complex = false;
160
161 for(void *it = simple_linked_list_it_init(s->postprocessors); it != NULL; ) {
163 const bool ret = state->funcs->reconfigure(state->state, desc);
164 if (!ret) {
166 return false;
167 }
168 // get desc for next iteration
169 int display_mode = 0;
170 int out_frames_count = 0;
171 state->funcs->get_out_desc(state->state, &desc, &display_mode, &out_frames_count);
172
173 // check if convert is simple (doesn't change display mode and out_fr_count == 1); if not, only one filter allowed
174 if (display_mode != DISPLAY_PROPERTY_VIDEO_MERGED || out_frames_count != 1) {
175 filter_complex = true;
176 }
177 }
178
179 if (filter_complex && simple_linked_list_size(s->postprocessors) > 1) {
180 log_msg(LOG_LEVEL_ERROR, MOD_NAME "One of postprocessors is complex (changing properties) and "
181 "cannot be used in filter chain (more postprocessors)!\n");
182 return false;
183 }
184
185 return true;
186}
187
189{
190 if (s == NULL) {
191 return NULL;
192 }
193
194 struct video_frame *out = NULL;
195
196 for(void *it = simple_linked_list_it_init(s->postprocessors); it != NULL; ) {
198 state->f = state->funcs->getf(state->state);
199 if (state->f == NULL) {
201 return NULL;
202 }
203 if (out == NULL) {
204 out = state->f;
205 }
206 }
207
208 return out;
209}
210
216 struct video_frame *out, int req_pitch)
217{
218 if (s == NULL) {
219 return false;
220 }
221 assert(in == ((struct vo_postprocess_state_single *) simple_linked_list_first(s->postprocessors))->f || in == NULL);
222
223 for(void *it = simple_linked_list_it_init(s->postprocessors); it != NULL; ) {
225 struct video_frame *next = out;
226 if (it != NULL) {
228 next = state_next->f;
229 }
230
231 int pitch = vc_get_linesize(next->tiles[0].width, next->color_spec);
232 if (it == NULL) {
233 pitch = req_pitch;
234 }
235 bool ret = state->funcs->vo_postprocess(state->state, in, next, pitch);
236 if (!ret) {
237 return false;
238 }
239 in = next;
240 }
241
242 return true;
243}
244
246{
247 if (s == NULL) {
248 return;
249 }
250 for(void *it = simple_linked_list_it_init(s->postprocessors); it != NULL; ) {
252 state->funcs->done(state->state);
253 free(state);
254 }
256 free(s);
257}
258
259void vo_postprocess_get_out_desc(struct vo_postprocess_state *s, struct video_desc *out, int *display_mode, int *out_frames_count)
260{
261 if (s == NULL) {
262 return;
263 }
265 state->funcs->get_out_desc(state->state, out, display_mode, out_frames_count);
266}
267
269{
270 if (s == NULL) {
271 return false;
272 }
273 assert(s->magic == MAGIC);
274
277 assert(state->magic == MAGIC_SINGLE);
278 return state->funcs->get_property(state->state, property, val, len);
279 }
280
287 assert(state->magic == MAGIC_SINGLE);
288 return state->funcs->get_property(state->state, property, val, len);
289 }
290
291 return false;
292}
293
void ** state
int void * val
struct video_desc desc
int void size_t * len
int property
int vc_get_linesize(unsigned int width, codec_t codec)
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
@ DISPLAY_PROPERTY_VIDEO_MERGED
monolithic framebuffer
void list_modules(enum library_class cls, int abi_version, bool full)
const void * load_library(const char *name, enum library_class cls, int abi_version)
@ LIBRARY_CLASS_VIDEO_POSTPROCESS
Definition lib_common.h:83
void simple_linked_list_append(struct simple_linked_list *l, void *data)
Definition list.cpp:68
void * simple_linked_list_it_peek_next(const void *it)
Definition list.cpp:132
void * simple_linked_list_it_next(void **i)
Definition list.cpp:119
int simple_linked_list_size(struct simple_linked_list *l)
Definition list.cpp:93
void * simple_linked_list_last(struct simple_linked_list *l)
returns last element of list, UB if empty
Definition list.cpp:103
struct simple_linked_list * simple_linked_list_init(void)
Definition list.cpp:53
void simple_linked_list_destroy(struct simple_linked_list *l)
Definition list.cpp:58
void * simple_linked_list_first(struct simple_linked_list *l)
returns first element of list, UB if empty
Definition list.cpp:98
void simple_linked_list_it_destroy(void *i)
Should be used when it != NULL, eg. when leaving the loop before the end.
Definition list.cpp:139
void * simple_linked_list_it_init(struct simple_linked_list *l)
Definition list.cpp:108
Definition hd-rum.c:27
unsigned int width
Definition types.h:280
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
codec_t color_spec
Definition types.h:306
vo_postprocess_init_t init
struct video_frame * f
const struct vo_postprocess_info * funcs
struct simple_linked_list * postprocessors
void show_vo_postprocess_help(bool full)
struct vo_postprocess_state * vo_postprocess_init(const char *config_string)
bool vo_postprocess_get_property(struct vo_postprocess_state *s, int property, void *val, size_t *len)
bool vo_postprocess_reconfigure(struct vo_postprocess_state *s, struct video_desc desc)
void vo_postprocess_get_out_desc(struct vo_postprocess_state *s, struct video_desc *out, int *display_mode, int *out_frames_count)
void vo_postprocess_done(struct vo_postprocess_state *s)
#define MAGIC
bool vo_postprocess(struct vo_postprocess_state *s, struct video_frame *in, struct video_frame *out, int req_pitch)
#define MOD_NAME
static _Bool init(struct vo_postprocess_state *s, const char *config_string)
#define MAGIC_SINGLE
struct video_frame * vo_postprocess_getf(struct vo_postprocess_state *s)
#define VO_PP_DOES_CHANGE_TILING_MODE
#define VO_PP_PROPERTY_CODECS
#define VO_PP_ABI_VERSION