1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /**
20 * @file
21 * text expansion utilities
22 */
23
24 #include <fenv.h>
25 #include <math.h>
26 #include <string.h>
27
34
36 char *
name,
unsigned argc,
char **argv)
37 {
38 void *log_ctx = expand_text->
log_ctx;
41
44 continue;
45 if (argc < functions[
i].argc_min) {
47 name, functions[
i].argc_min);
49 }
50 if (argc > functions[
i].argc_max) {
52 name, functions[
i].argc_max);
54 }
55 break;
56 }
60 }
61
62 return functions[
i].
func(log_ctx, bp,
name, argc, argv);
63 }
64
65 /**
66 * Expand text template pointed to by *rtext.
67 *
68 * Expand text template defined in text using the logic defined in a text
69 * expander object.
70 *
71 * This function expects the text to be in the format %{FUNCTION_NAME[:PARAMS]},
72 * where PARAMS is a sequence of strings separated by : and represents the function
73 * arguments to use for the function evaluation.
74 *
75 * @param text_expander TextExpander object used to expand the text
76 * @param bp BPrint object where the expanded text is written to
77 * @param rtext pointer to pointer to the text to expand, it is updated to point
78 * to the next part of the template to process
79 * @return negative value corresponding to an AVERROR error code in case of
80 * errors, a non-negative value otherwise
81 */
83 {
84 void *log_ctx = expand_text->
log_ctx;
85 const char *text = *rtext;
86 char *argv[16] = {
NULL };
89
90 if (*text != '{') {
93 }
94 text++;
95 while (1) {
98 goto end;
99 }
100 if (!*text) {
103 goto end;
104 }
106 av_freep(&argv[--argc]);
/* error will be caught later */
107 if (*text == '}')
108 break;
109 text++;
110 }
111
113 goto end;
115 *rtext = text + 1;
116
117 end:
118 for (
i = 0;
i < argc;
i++)
121 }
122
124 {
126
128 if (!text)
129 return 0;
130
131 while (*text) {
132 if (*text == '\\' && text[1]) {
134 text += 2;
135 } else if (*text == '%') {
136 text++;
139 } else {
141 text++;
142 }
143 }
146 return 0;
147 }
148
150 const char *fmt, const char *strftime_fmt)
151 {
153
159 }
161 }
162
163 if (!strcmp(fmt, "flt")) {
165 } else if (!strcmp(fmt, "hms") ||
166 !strcmp(fmt, "hms24hh")) {
169 } else {
171 char sign = ' ';
172 if (ms < 0) {
173 sign = '-';
174 ms = -ms;
175 }
176 if (!strcmp(fmt, "hms24hh")) {
177 /* wrap around 24 hours */
178 ms %= 24 * 60 * 60 * 1000;
179 }
181 (int)(ms / (60 * 60 * 1000)),
182 (int)(ms / (60 * 1000)) % 60,
183 (int)(ms / 1000) % 60,
184 (int)(ms % 1000));
185 }
186 } else if (!strcmp(fmt, "localtime") ||
187 !strcmp(fmt, "gmtime")) {
188 struct tm tm;
189 time_t ms = (time_t)
pts;
190 if (!strcmp(fmt, "localtime"))
192 else
195 } else {
198 }
199 return 0;
200 }
201
203 const char *strftime_fmt, char localtime)
204 {
205 const char *fmt =
av_x_if_null(strftime_fmt,
"%Y-%m-%d %H:%M:%S");
206 const char *fmt_begin = fmt;
208 time_t now;
209 struct tm tm;
210 const char *begin;
213 int div;
214 AVBPrint fmt_bp;
215
217
219 now = unow / 1000000;
220 if (localtime)
222 else
224
225 // manually parse format for %N (fractional seconds)
226 begin = fmt;
227 while ((begin = strchr(begin, '%'))) {
230
231 // skip escaped "%%"
234 continue;
235 }
236
237 // count digits between % and possible N
241 }
242
243 // N encountered, insert time
245 int num_digits = 3; // default show millisecond [1,6]
246
247 // if digit given, expect [1,6], warn & clamp otherwise
249 num_digits =
av_clip(*(begin + 1) -
'0', 1, 6);
250 }
else if (
len > 1) {
251 av_log(log_ctx,
AV_LOG_WARNING,
"Invalid number of decimals for %%N, using default of %i\n", num_digits);
252 }
253
254 len += 2;
// add % and N to get length of string part
255
256 div = pow(10, 6 - num_digits);
257
258 av_bprintf(&fmt_bp,
"%.*s%0*d", (
int)(begin - fmt_begin), fmt_begin, num_digits, (
int)(unow % 1000000) / div);
259
261 fmt_begin = begin;
262
263 continue;
264 }
265
267 }
268
272 }
273
275
277
278 return 0;
279 }
280
282 const char *expr,
283 const char * const *fun_names, const ff_eval_func2 *fun_values,
284 const char *
const *
var_names,
const double *var_values,
285 void *eval_ctx)
286 {
287 double res;
289
292 eval_ctx, 0, log_ctx);
295 "Text expansion expression '%s' is not valid\n",
296 expr);
297 else
299
301 }
302
304 const char *expr,
305 const char * const *fun_names, const ff_eval_func2 *fun_values,
306 const char *
const *
var_names,
const double *var_values,
307 void *eval_ctx,
309 {
310 double res;
311 int intval;
313 char fmt_str[30] = "%";
314
317 eval_ctx, 0, log_ctx);
320 "Text expansion expression '%s' is not valid\n",
321 expr);
323 }
324
325 if (!strchr(
"xXdu",
format)) {
327 " allowed values: 'x', 'X', 'd', 'u'\n",
format);
329 }
330
331 feclearexcept(FE_ALL_EXCEPT);
332 intval = res;
333 #if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
334 if ((
ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
335 av_log(log_ctx,
AV_LOG_ERROR,
"Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n",
ret, intval);
337 }
338 #endif
339
343
345 res, expr, fmt_str);
346
348
349 return 0;
350 }
351
352
354 unsigned char **text, size_t *text_size)
355 {
356 int err;
357 uint8_t *textbuf;
359 size_t textbuf_size;
360
361 if ((err =
av_file_map(textfile, &textbuf, &textbuf_size, 0, log_ctx)) < 0) {
363 "The text file '%s' could not be read or is empty\n",
364 textfile);
365 return err;
366 }
367
368 if (textbuf_size > 0 && ff_is_newline(textbuf[textbuf_size - 1]))
369 textbuf_size--;
370 if (textbuf_size > SIZE_MAX - 1 || !(
tmp =
av_realloc(*text, textbuf_size + 1))) {
373 }
375 memcpy(*text, textbuf, textbuf_size);
376 (*text)[textbuf_size] = 0;
377 if (text_size)
378 *text_size = textbuf_size;
380
381 return 0;
382 }
383