1 /*
2 * Copyright (c) 2012 Stefano Sabatini
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * send commands filter
24 */
25
26 #include "config_components.h"
27
39
40 #define COMMAND_FLAG_ENTER 1
41 #define COMMAND_FLAG_LEAVE 2
42 #define COMMAND_FLAG_EXPR 4
43
45 "N", /* frame number */
46 "T", /* frame time in seconds */
47 #if FF_API_FRAME_PKT
48 "POS", /* original position in the file of the frame */
49 #endif
50 "PTS", /* frame pts */
51 "TS", /* interval start time in seconds */
52 "TE", /* interval end time in seconds */
53 "TI", /* interval interpolated value: TI = (T - TS) / (TE - TS) */
54 "W", /* width for video frames */
55 "H", /* height for video frames */
57 };
58
62 #if FF_API_FRAME_PKT
64 #endif
72 };
73
75 {
76 static const char * const flag_strings[] = { "enter", "leave", "expr" };
78
82 if (!is_first)
85 is_first = 0;
86 }
87 }
88
89 return pbuf->str;
90 }
91
97
101 int index;
///< unique index for these interval commands
104 int enabled;
///< current time detected inside this interval
106
111
115
116 #define OFFSET(x) offsetof(SendCmdContext, x)
117 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
124 };
125
126 #define SPACES " \f\t\n\r"
127
129 {
130 while (**buf) {
131 /* skip leading spaces */
132 *buf += strspn(*buf,
SPACES);
133 if (**buf != '#')
134 break;
135
136 (*buf)++;
137
138 /* skip comment until the end of line */
139 *buf += strcspn(*buf, "\n");
140 if (**buf)
141 (*buf)++;
142 }
143 }
144
145 #define COMMAND_DELIMS " \f\t\n\r,;"
146
148 const char **buf, void *log_ctx)
149 {
151
152 memset(cmd, 0,
sizeof(
Command));
153 cmd->
index = cmd_count;
154
155 /* format: [FLAGS] target command arg */
156 *buf += strspn(*buf,
SPACES);
157
158 /* parse flags */
159 if (**buf == '[') {
160 (*buf)++; /* skip "[" */
161
162 while (**buf) {
163 int len = strcspn(*buf,
"|+]");
164
168 else {
169 char flag_buf[64];
172 "Unknown flag '%s' in interval #%d, command #%d\n",
173 flag_buf, interval_count, cmd_count);
175 }
177 if (**buf == ']')
178 break;
179 if (!strspn(*buf, "+|")) {
181 "Invalid flags char '%c' in interval #%d, command #%d\n",
182 **buf, interval_count, cmd_count);
184 }
185 if (**buf)
186 (*buf)++;
187 }
188
189 if (**buf != ']') {
191 "Missing flag terminator or extraneous data found at the end of flags "
192 "in interval #%d, command #%d\n", interval_count, cmd_count);
194 }
195 (*buf)++; /* skip "]" */
196 } else {
198 }
199
200 *buf += strspn(*buf,
SPACES);
204 "No target specified in interval #%d, command #%d\n",
205 interval_count, cmd_count);
208 }
209
210 *buf += strspn(*buf,
SPACES);
214 "No command specified in interval #%d, command #%d\n",
215 interval_count, cmd_count);
218 }
219
220 *buf += strspn(*buf,
SPACES);
222
223 return 1;
224
230 }
231
233 const char **buf, void *log_ctx)
234 {
235 int cmd_count = 0;
237 AVBPrint pbuf;
238
240 *nb_cmds = 0;
241
242 while (**buf) {
244
245 if ((
ret =
parse_command(&cmd, cmd_count, interval_count, buf, log_ctx)) < 0)
247 cmd_count++;
248
249 /* (re)allocate commands array if required */
250 if (*nb_cmds == n) {
251 n =
FFMAX(16, 2*n);
/* first allocation = 16, or double the number */
255 "Could not (re)allocate command array\n");
257 }
258 }
259
260 (*cmds)[(*nb_cmds)++] = cmd;
261
262 *buf += strspn(*buf,
SPACES);
263 if (**buf && **buf != ';' && **buf != ',') {
265 "Missing separator or extraneous data found at the end of "
266 "interval #%d, in command #%d\n",
267 interval_count, cmd_count);
269 "Command was parsed as: flags:[%s] target:%s command:%s arg:%s\n",
272 }
273 if (**buf == ';')
274 break;
275 if (**buf == ',')
276 (*buf)++;
277 }
278
279 return 0;
280 }
281
282 #define DELIMS " \f\t\n\r,;"
283
285 const char **buf, void *log_ctx)
286 {
287 char *intervalstr;
289
290 *buf += strspn(*buf,
SPACES);
291 if (!**buf)
292 return 0;
293
294 /* reset data */
295 memset(interval, 0,
sizeof(
Interval));
296 interval->
index = interval_count;
297
298 /* format: INTERVAL COMMANDS */
299
300 /* parse interval */
302 if (intervalstr && intervalstr[0]) {
303 char *start, *end;
304
305 start =
av_strtok(intervalstr,
"-", &end);
306 if (!start) {
309 "Invalid interval specification '%s' in interval #%d\n",
310 intervalstr, interval_count);
311 goto end;
312 }
315 "Invalid start time specification '%s' in interval #%d\n",
316 start, interval_count);
317 goto end;
318 }
319
320 if (end) {
323 "Invalid end time specification '%s' in interval #%d\n",
324 end, interval_count);
325 goto end;
326 }
327 } else {
328 interval->
end_ts = INT64_MAX;
329 }
332 "Invalid end time '%s' in interval #%d: "
333 "cannot be lesser than start time '%s'\n",
334 end, interval_count, start);
336 goto end;
337 }
338 } else {
340 "No interval specified for interval #%d\n", interval_count);
342 goto end;
343 }
344
345 /* parse commands */
347 interval_count, buf, log_ctx);
348
349 end:
352 }
353
355 const char *buf, void *log_ctx)
356 {
357 int interval_count = 0;
359
361 *nb_intervals = 0;
362
363 if (!buf)
364 return 0;
365
366 while (1) {
368
370 if (!(*buf))
371 break;
372
375
376 buf += strspn(buf,
SPACES);
377 if (*buf) {
378 if (*buf != ';') {
380 "Missing terminator or extraneous data found at the end of interval #%d\n",
381 interval_count);
383 }
384 buf++; /* skip ';' */
385 }
386 interval_count++;
387
388 /* (re)allocate commands array if required */
389 if (*nb_intervals == n) {
390 n =
FFMAX(16, 2*n);
/* first allocation = 16, or double the number */
392 if (!*intervals) {
394 "Could not (re)allocate intervals array\n");
396 }
397 }
398
399 (*intervals)[(*nb_intervals)++] = interval;
400 }
401
402 return 0;
403 }
404
406 {
410 }
411
413 {
416
417 if ((!!
s->commands_filename + !!
s->commands_str) != 1) {
419 "One and only one of the filename or commands options must be specified\n");
421 }
422
423 if (
s->commands_filename) {
424 uint8_t *file_buf, *buf;
425 size_t file_bufsize;
427 &file_buf, &file_bufsize, 0,
ctx);
430
431 /* create a 0-terminated string based on the read file */
433 if (!buf) {
436 }
437 memcpy(buf, file_buf, file_bufsize);
438 buf[file_bufsize] = 0;
440 s->commands_str = buf;
441 }
442
444 s->commands_str,
ctx)) < 0)
446
447 if (
s->nb_intervals == 0) {
450 }
451
453
455 for (
i = 0;
i <
s->nb_intervals;
i++) {
456 AVBPrint pbuf;
463 " [%s] target:%s command:%s arg:%s index:%d\n",
465 }
466 }
467
468 return 0;
469 }
470
472 {
475
476 for (
i = 0;
i <
s->nb_intervals;
i++) {
483 }
485 }
487 }
488
490 {
496
498 goto end;
499
501
502 #define WITHIN_INTERVAL(ts, start_ts, end_ts) ((ts) >= (start_ts) && (ts) < (end_ts))
503
504 for (
i = 0;
i <
s->nb_intervals;
i++) {
507
511 }
515 }
518
520 AVBPrint pbuf;
522 "[%s] interval #%d start_ts:%f end_ts:%f ts:%f\n",
524 (
double)interval->
start_ts/1000000, (
double)interval->
end_ts/1000000,
525 (double)ts/1000000);
526
529 char *cmd_arg = cmd->
arg;
530 char buf[1024];
531
538
540 #if FF_API_FRAME_PKT
544 #endif
546 var_values[
VAR_T] = current;
547 var_values[
VAR_TS] = start;
549 var_values[
VAR_TI] = (current - start) / (end - start);
552
558 }
559
561 if (!cmd_arg) {
564 }
565 }
567 "Processing command #%d target:%s command:%s arg:%s\n",
571 buf, sizeof(buf),
574 "Command reply for command #%d: ret:%s res:%s\n",
578 }
579 }
580 }
581 }
582
583 end:
588 }
589
591 }
592
594
595 #if CONFIG_SENDCMD_FILTER
596
598 {
602 },
603 };
604
614 .priv_class = &sendcmd_class,
615 };
616
617 #endif
618
619 #if CONFIG_ASENDCMD_FILTER
620
622 {
626 },
627 };
628
632 .priv_class = &sendcmd_class,
639 };
640
641 #endif