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
38
39 #define COMMAND_FLAG_ENTER 1
40 #define COMMAND_FLAG_LEAVE 2
41 #define COMMAND_FLAG_EXPR 4
42
44 "N", /* frame number */
45 "T", /* frame time in seconds */
46 #if FF_API_FRAME_PKT
47 "POS", /* original position in the file of the frame */
48 #endif
49 "PTS", /* frame pts */
50 "TS", /* interval start time in seconds */
51 "TE", /* interval end time in seconds */
52 "TI", /* interval interpolated value: TI = (T - TS) / (TE - TS) */
53 "W", /* width for video frames */
54 "H", /* height for video frames */
56 };
57
61 #if FF_API_FRAME_PKT
63 #endif
71 };
72
74 {
75 static const char * const flag_strings[] = { "enter", "leave", "expr" };
77
81 if (!is_first)
84 is_first = 0;
85 }
86 }
87
88 return pbuf->str;
89 }
90
96
100 int index;
///< unique index for these interval commands
103 int enabled;
///< current time detected inside this interval
105
110
114
115 #define OFFSET(x) offsetof(SendCmdContext, x)
116 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
123 };
124
125 #define SPACES " \f\t\n\r"
126
128 {
129 while (**buf) {
130 /* skip leading spaces */
131 *buf += strspn(*buf,
SPACES);
132 if (**buf != '#')
133 break;
134
135 (*buf)++;
136
137 /* skip comment until the end of line */
138 *buf += strcspn(*buf, "\n");
139 if (**buf)
140 (*buf)++;
141 }
142 }
143
144 #define COMMAND_DELIMS " \f\t\n\r,;"
145
147 const char **buf, void *log_ctx)
148 {
150
151 memset(cmd, 0,
sizeof(
Command));
152 cmd->
index = cmd_count;
153
154 /* format: [FLAGS] target command arg */
155 *buf += strspn(*buf,
SPACES);
156
157 /* parse flags */
158 if (**buf == '[') {
159 (*buf)++; /* skip "[" */
160
161 while (**buf) {
162 int len = strcspn(*buf,
"|+]");
163
167 else {
168 char flag_buf[64];
171 "Unknown flag '%s' in interval #%d, command #%d\n",
172 flag_buf, interval_count, cmd_count);
174 }
176 if (**buf == ']')
177 break;
178 if (!strspn(*buf, "+|")) {
180 "Invalid flags char '%c' in interval #%d, command #%d\n",
181 **buf, interval_count, cmd_count);
183 }
184 if (**buf)
185 (*buf)++;
186 }
187
188 if (**buf != ']') {
190 "Missing flag terminator or extraneous data found at the end of flags "
191 "in interval #%d, command #%d\n", interval_count, cmd_count);
193 }
194 (*buf)++; /* skip "]" */
195 } else {
197 }
198
199 *buf += strspn(*buf,
SPACES);
203 "No target specified in interval #%d, command #%d\n",
204 interval_count, cmd_count);
207 }
208
209 *buf += strspn(*buf,
SPACES);
213 "No command specified in interval #%d, command #%d\n",
214 interval_count, cmd_count);
217 }
218
219 *buf += strspn(*buf,
SPACES);
221
222 return 1;
223
229 }
230
232 const char **buf, void *log_ctx)
233 {
234 int cmd_count = 0;
236 AVBPrint pbuf;
237
239 *nb_cmds = 0;
240
241 while (**buf) {
243
244 if ((
ret =
parse_command(&cmd, cmd_count, interval_count, buf, log_ctx)) < 0)
246 cmd_count++;
247
248 /* (re)allocate commands array if required */
249 if (*nb_cmds == n) {
250 n =
FFMAX(16, 2*n);
/* first allocation = 16, or double the number */
254 "Could not (re)allocate command array\n");
256 }
257 }
258
259 (*cmds)[(*nb_cmds)++] = cmd;
260
261 *buf += strspn(*buf,
SPACES);
262 if (**buf && **buf != ';' && **buf != ',') {
264 "Missing separator or extraneous data found at the end of "
265 "interval #%d, in command #%d\n",
266 interval_count, cmd_count);
268 "Command was parsed as: flags:[%s] target:%s command:%s arg:%s\n",
271 }
272 if (**buf == ';')
273 break;
274 if (**buf == ',')
275 (*buf)++;
276 }
277
278 return 0;
279 }
280
281 #define DELIMS " \f\t\n\r,;"
282
284 const char **buf, void *log_ctx)
285 {
286 char *intervalstr;
288
289 *buf += strspn(*buf,
SPACES);
290 if (!**buf)
291 return 0;
292
293 /* reset data */
294 memset(interval, 0,
sizeof(
Interval));
295 interval->
index = interval_count;
296
297 /* format: INTERVAL COMMANDS */
298
299 /* parse interval */
301 if (intervalstr && intervalstr[0]) {
302 char *start, *end;
303
304 start =
av_strtok(intervalstr,
"-", &end);
305 if (!start) {
308 "Invalid interval specification '%s' in interval #%d\n",
309 intervalstr, interval_count);
310 goto end;
311 }
314 "Invalid start time specification '%s' in interval #%d\n",
315 start, interval_count);
316 goto end;
317 }
318
319 if (end) {
322 "Invalid end time specification '%s' in interval #%d\n",
323 end, interval_count);
324 goto end;
325 }
326 } else {
327 interval->
end_ts = INT64_MAX;
328 }
331 "Invalid end time '%s' in interval #%d: "
332 "cannot be lesser than start time '%s'\n",
333 end, interval_count, start);
335 goto end;
336 }
337 } else {
339 "No interval specified for interval #%d\n", interval_count);
341 goto end;
342 }
343
344 /* parse commands */
346 interval_count, buf, log_ctx);
347
348 end:
351 }
352
354 const char *buf, void *log_ctx)
355 {
356 int interval_count = 0;
358
360 *nb_intervals = 0;
361
362 if (!buf)
363 return 0;
364
365 while (1) {
367
369 if (!(*buf))
370 break;
371
374
375 buf += strspn(buf,
SPACES);
376 if (*buf) {
377 if (*buf != ';') {
379 "Missing terminator or extraneous data found at the end of interval #%d\n",
380 interval_count);
382 }
383 buf++; /* skip ';' */
384 }
385 interval_count++;
386
387 /* (re)allocate commands array if required */
388 if (*nb_intervals == n) {
389 n =
FFMAX(16, 2*n);
/* first allocation = 16, or double the number */
391 if (!*intervals) {
393 "Could not (re)allocate intervals array\n");
395 }
396 }
397
398 (*intervals)[(*nb_intervals)++] = interval;
399 }
400
401 return 0;
402 }
403
405 {
409 }
410
412 {
415
416 if ((!!
s->commands_filename + !!
s->commands_str) != 1) {
418 "One and only one of the filename or commands options must be specified\n");
420 }
421
422 if (
s->commands_filename) {
423 uint8_t *file_buf, *buf;
424 size_t file_bufsize;
426 &file_buf, &file_bufsize, 0,
ctx);
429
430 /* create a 0-terminated string based on the read file */
432 if (!buf) {
435 }
436 memcpy(buf, file_buf, file_bufsize);
437 buf[file_bufsize] = 0;
439 s->commands_str = buf;
440 }
441
443 s->commands_str,
ctx)) < 0)
445
446 if (
s->nb_intervals == 0) {
449 }
450
452
454 for (
i = 0;
i <
s->nb_intervals;
i++) {
455 AVBPrint pbuf;
462 " [%s] target:%s command:%s arg:%s index:%d\n",
464 }
465 }
466
467 return 0;
468 }
469
471 {
474
475 for (
i = 0;
i <
s->nb_intervals;
i++) {
482 }
484 }
486 }
487
489 {
494
496 goto end;
497
499
500 #define WITHIN_INTERVAL(ts, start_ts, end_ts) ((ts) >= (start_ts) && (ts) < (end_ts))
501
502 for (
i = 0;
i <
s->nb_intervals;
i++) {
505
509 }
513 }
516
518 AVBPrint pbuf;
520 "[%s] interval #%d start_ts:%f end_ts:%f ts:%f\n",
522 (
double)interval->
start_ts/1000000, (
double)interval->
end_ts/1000000,
523 (double)ts/1000000);
524
527 char *cmd_arg = cmd->
arg;
528 char buf[1024];
529
536
538 #if FF_API_FRAME_PKT
542 #endif
544 var_values[
VAR_T] = current;
545 var_values[
VAR_TS] = start;
547 var_values[
VAR_TI] = (current - start) / (end - start);
550
556 }
557
559 if (!cmd_arg) {
562 }
563 }
565 "Processing command #%d target:%s command:%s arg:%s\n",
569 buf, sizeof(buf),
572 "Command reply for command #%d: ret:%s res:%s\n",
576 }
577 }
578 }
579 }
580
581 end:
586 }
587
589 }
590
592
593 #if CONFIG_SENDCMD_FILTER
594
596 {
600 },
601 };
602
612 .priv_class = &sendcmd_class,
613 };
614
615 #endif
616
617 #if CONFIG_ASENDCMD_FILTER
618
620 {
624 },
625 };
626
630 .priv_class = &sendcmd_class,
637 };
638
639 #endif