1 /*
2 * lavpipe - combines several input streams and pipes them trough
3 * arbitrary filters in order to finally output a resulting
4 * video stream based on a given "recipe" (pipe list)
5 *
6 * Copyright (C) 2001, pHilipp Zabel <pzabel@gmx.de>
7 * Copyright (C) 2001, Matthew Marjanovic <maddog@mir.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <signal.h>
37
38 #include "mjpeg_logging.h"
39 #include "pipelist.h"
40 #include "yuv4mpeg.h"
41
usage(void)42 static void usage(void)
43 {
44 fprintf(
45 stderr,
46 "Usage: lavpipe [options] <pipe list>\n"
47 "Options: -o num Frame offset - skip num frames in the beginning\n"
48 " if num is negative, all but the last num frames are skipped\n"
49 " -n num Only num frames are processed (0 means all frames)\n"
50 " -v num Verbosity of output [0..2]\n"
51 );
52 }
53
54 static
parse_spawn_command(char * cmdline)55 char **parse_spawn_command(char *cmdline)
56 {
57 char **argv;
58 char *p = cmdline;
59 int i, argc = 0;
60
61 if (p == NULL) return NULL;
62 if (*p == '\0') return NULL;
63
64 argc = 0;
65 while (*p != '\0') {
66 while (!isspace(*p)) {
67 p++;
68 if (*p == '\0') {
69 argc++;
70 goto END_OF_LINE;
71 }
72 }
73 argc++;
74 while (isspace(*p)) {
75 p++;
76 if (*p == '\0') goto END_OF_LINE;
77 }
78 }
79
80 END_OF_LINE:
81 argv = malloc(argc+1 * sizeof(argv[0]));
82
83 for (p = cmdline, i=0; i < argc; i++) {
84 argv[i] = p;
85 while (!isspace(*(++p)));
86 p[0] = '\0';
87 while (isspace(*(++p)))
88 if (p[0] == '\0') break;
89 }
90
91 argv[argc] = NULL;
92 return argv;
93 }
94
95 static
fork_child_sub(char * command,int * fd_in,int * fd_out)96 pid_t fork_child_sub(char *command, int *fd_in, int *fd_out)
97 {
98 int n;
99 int pipe_in[2];
100 int pipe_out[2];
101 char **myargv;
102 pid_t pid;
103
104 if (fd_in) {
105 if (pipe(pipe_in)) {
106 mjpeg_error_exit1( "Couldn't create input pipe from %s", command);
107 }
108 }
109 if (fd_out) {
110 if (pipe(pipe_out)) {
111 mjpeg_error_exit1( "Couldn't create output pipe to %s", command);
112 }
113 }
114 if ((pid = fork ()) < 0) {
115 mjpeg_error_exit1("Couldn't fork %s", command);
116 }
117
118 if (pid == 0) {
119 /* child redirects stdout to pipe_in */
120 if (fd_in) {
121 close(pipe_in[0]);
122 close(1);
123 n = dup(pipe_in[1]);
124 if (n != 1) exit (1);
125 }
126 /* child redirects stdin to pipe_out */
127 if (fd_out) {
128 close(pipe_out[1]);
129 close(0);
130 n = dup(pipe_out[0]);
131 if (n != 0) exit(1);
132 }
133 myargv = parse_spawn_command(command);
134 execvp(myargv[0], myargv);
135 return -1;
136 } else {
137 /* parent */
138 if (fd_in != NULL) {
139 close(pipe_in[1]);
140 *fd_in = pipe_in[0];
141 }
142 if (fd_out != NULL) {
143 close(pipe_out[0]);
144 *fd_out = pipe_out[1];
145 }
146 return pid;
147 }
148 }
149
150
fork_child(const char * command,int offset,int num,int * fd_in,int * fd_out)151 static pid_t fork_child(const char *command,
152 int offset, int num,
153 int *fd_in, int *fd_out)
154 {
155 char tmp1[1024], tmp2[1024];
156 char *current = tmp1;
157 char *next = tmp2;
158 char *p;
159
160 strncpy(current, command, 1024);
161
162 /* replace $o by offset */
163 p = strstr(current, "$o");
164 if (p) {
165 p[0] = '\0';
166 p += 2;
167 snprintf(next, 1024, "%s%d%s", current, offset, p);
168 p = current;
169 current = next;
170 next = p;
171 }
172
173 /* replace $n by number of frames */
174 p = strstr(current, "$n");
175 if (p) {
176 p[0] = '\0';
177 p += 2;
178 snprintf(next, 1024, "%s%d%s", current, num, p);
179 p = current;
180 current = next;
181 next = p;
182 }
183
184 mjpeg_debug( "Executing: '%s'", current);
185 return fork_child_sub(current, fd_in, fd_out);
186 }
187
alloc_yuv_buffers(unsigned char * yuv[3],y4m_stream_info_t * si)188 static void alloc_yuv_buffers(unsigned char *yuv[3], y4m_stream_info_t *si)
189 {
190 int chroma_ss, ss_v, ss_h, w, h;
191
192 w = y4m_si_get_width(si);
193 h = y4m_si_get_height(si);
194
195 chroma_ss = y4m_si_get_chroma(si);
196 ss_h = y4m_chroma_ss_x_ratio(chroma_ss).d;
197 ss_v = y4m_chroma_ss_y_ratio(chroma_ss).d;
198
199 yuv[0] = malloc (w * h * sizeof(yuv[0][0]));
200 yuv[1] = malloc ((w / ss_h) * (h / ss_v) * sizeof(yuv[1][0]));
201 yuv[2] = malloc ((w / ss_h) * (h / ss_v) * sizeof(yuv[2][0]));
202 }
203
free_yuv_buffers(unsigned char * yuv[3])204 static void free_yuv_buffers(unsigned char *yuv[3])
205 {
206 free(yuv[0]);
207 free(yuv[1]);
208 free(yuv[2]);
209 yuv[0] = yuv[1] = yuv[2] = NULL;
210 }
211
init_pipe_source(pipe_source_t * ps,char * command)212 static void init_pipe_source(pipe_source_t *ps, char *command)
213 {
214 ps->command = strdup(command);
215 y4m_init_stream_info(&(ps->streaminfo));
216 y4m_init_frame_info(&(ps->frameinfo));
217 ps->pid = -1;
218 ps->fd = -1;
219 ps->frame_num = 0;
220 }
221
fini_pipe_source(pipe_source_t * ps)222 static void fini_pipe_source(pipe_source_t *ps)
223 {
224 free(ps->command);
225 y4m_fini_stream_info(&(ps->streaminfo));
226 y4m_fini_frame_info(&(ps->frameinfo));
227 }
228
spawn_pipe_source(pipe_source_t * ps,int offset,int count)229 static void spawn_pipe_source(pipe_source_t *ps, int offset, int count)
230 {
231 ps->pid = fork_child(ps->command,
232 offset, count,
233 &(ps->fd), NULL);
234 ps->frame_num = offset;
235 mjpeg_debug("spawned source '%s'", ps->command);
236 }
237
decommission_pipe_source(pipe_source_t * source)238 static void decommission_pipe_source(pipe_source_t *source)
239 {
240 if (source->fd >= 0) {
241 close(source->fd);
242 source->fd = -1;
243 }
244 if (source->pid > 0) {
245 mjpeg_debug("DIE DIE DIE pid %d", source->pid);
246 kill(source->pid, SIGINT);
247 source->pid = -1;
248 }
249 }
250
init_pipe_filter(pipe_filter_t * pf,const char * command)251 static void init_pipe_filter(pipe_filter_t *pf, const char *command)
252 {
253 pf->command = strdup(command);
254 y4m_init_stream_info(&(pf->out_streaminfo));
255 y4m_init_stream_info(&(pf->in_streaminfo));
256 y4m_init_frame_info(&(pf->frameinfo));
257 pf->yuv[0] = pf->yuv[1] = pf->yuv[2] = NULL;
258 pf->pid = -1;
259 pf->out_fd = -1;
260 pf->in_fd = -1;
261 }
262
fini_pipe_filter(pipe_filter_t * pf)263 static void fini_pipe_filter(pipe_filter_t *pf)
264 {
265 free(pf->command);
266 free_yuv_buffers(pf->yuv);
267 y4m_fini_stream_info(&(pf->out_streaminfo));
268 y4m_fini_stream_info(&(pf->in_streaminfo));
269 y4m_fini_frame_info(&(pf->frameinfo));
270 }
271
spawn_pipe_filter(pipe_filter_t * pf,int offset,int count)272 static void spawn_pipe_filter(pipe_filter_t *pf, int offset, int count)
273 {
274 pf->pid = fork_child(pf->command,
275 offset, count,
276 &(pf->in_fd), &(pf->out_fd));
277 mjpeg_debug("spawned filter '%s'", pf->command);
278 }
279
decommission_pipe_filter(pipe_filter_t * filt)280 static void decommission_pipe_filter(pipe_filter_t *filt)
281 {
282 if (filt->in_fd >= 0) {
283 close(filt->in_fd);
284 filt->in_fd = -1;
285 }
286 if (filt->out_fd >= 0) {
287 close(filt->out_fd);
288 filt->out_fd = -1;
289 }
290 if (filt->pid > 0) {
291 mjpeg_debug("DIE DIE DIE pid %d", filt->pid);
292 kill(filt->pid, SIGINT);
293 filt->pid = -1;
294 }
295 free_yuv_buffers(filt->yuv);
296 }
297
298 /*
299 * make sure all the sources needed for this segment are cued up
300 * and ready to produce frames
301 *
302 */
303
304 static
open_segment_inputs(PipeSegment * seg,pipe_filter_t * filt,int frame,int segnum,int total_frames,PipeList * pl,commandline_params_t * cl,pipe_source_t * sources)305 void open_segment_inputs(PipeSegment *seg, pipe_filter_t *filt,
306 int frame, int segnum, int total_frames,
307 PipeList *pl, commandline_params_t *cl,
308 pipe_source_t *sources)
309 {
310 int i, j, k;
311
312 for (i = 0; i < seg->input_count; i++) {
313 int in_index = seg->input_index[i];
314 int in_offset = seg->input_offset[i];
315 pipe_source_t *source = &(sources[in_index]);
316
317 mjpeg_debug("OSI: input %d == source %d: '%s'",
318 i, in_index, source->command);
319
320 /* spawn the source if not already running */
321 if (source->fd < 0) {
322
323 /* calculate # of frames we want to get from this stream */
324 /* need to look if we can use this in successive sequences and
325 what param_frames is */
326
327 int offset = in_offset + frame;
328 int count = seg->frame_count - frame; /* until end of sequence */
329
330 for (j = segnum + 1; j < pl->segment_count; j++) {
331 PipeSegment *other = pl->segments[j];
332 /* mjpeg_debug("checking i %d j %d", i, j); */
333 for (k = 0; k < other->input_count; k++) {
334 /* mjpeg_debug("checking i %d j %d k %d", i, j, k); */
335 if (in_index == other->input_index[k]) {
336 if ((offset + count) == other->input_offset[k]) {
337 count += other->frame_count; /* add another sequence */
338 } else
339 goto FINISH_CHECK; /* need to reopen with other offset */
340 } else
341 goto FINISH_CHECK; /* stream will not be used in
342 segment j anymore */
343 }
344 }
345 FINISH_CHECK:
346 /* mjpeg_debug("finish-check i %d j %d k %d", i, j, k); */
347 if (count > cl->frames - total_frames) {
348 count = cl->frames - total_frames;
349 }
350
351 /******** why have 'count'? let the source keep making frames...
352 ...we'll just kill it when we are done anyway! *********/
353 /* spawn_pipe_source(source, offset, count);*/
354 spawn_pipe_source(source, offset, 0);
355
356 if (y4m_read_stream_header(source->fd, &(source->streaminfo)) != Y4M_OK)
357 mjpeg_error_exit1("Bad source header!");
358
359 mjpeg_debug("read header");
360 y4m_log_stream_info(mjpeg_loglev_t("debug"), "src: ", &(source->streaminfo));
361 } else {
362 mjpeg_debug("...source %d is still alive.", in_index);
363 }
364
365 if (i == 0) {
366 /* first time: copy stream info to filter */
367 y4m_copy_stream_info(&(filt->out_streaminfo), &(source->streaminfo));
368 mjpeg_debug("copied info");
369 } else {
370 /* n-th time: make sure source streams match */
371 if (y4m_si_get_width(&(filt->out_streaminfo)) !=
372 y4m_si_get_width(&(source->streaminfo)))
373 mjpeg_error_exit1("Stream mismatch: frame width");
374 if (y4m_si_get_height(&(filt->out_streaminfo)) !=
375 y4m_si_get_height(&(source->streaminfo)))
376 mjpeg_error_exit1("Stream mismatch: frame height");
377 if (y4m_si_get_interlace(&(filt->out_streaminfo)) !=
378 y4m_si_get_interlace(&(source->streaminfo)))
379 mjpeg_error_exit1("Stream mismatch: interlace");
380 mjpeg_debug("verified info");
381 }
382 }
383
384 }
385
386 static
setup_segment_filter(PipeSegment * seg,pipe_filter_t * filt,int frame)387 void setup_segment_filter(PipeSegment *seg, pipe_filter_t *filt, int frame)
388 {
389 mjpeg_debug("OSO: '%s'", filt->command);
390 if (strcmp(filt->command, "-")) {
391 /* ...via a filter command:
392 * o spawn filter process
393 * o write source stream info to filter
394 * o read filter's result stream info
395 * o alloc yuv buffers for source->filter transfers
396 */
397 /* ... why does the 'count' matter, if lavpipe controls the frame
398 * flow anyway???????? */
399 spawn_pipe_filter(filt, frame, (seg->frame_count - frame));
400 y4m_write_stream_header(filt->out_fd, &(filt->out_streaminfo));
401 y4m_read_stream_header(filt->in_fd, &(filt->in_streaminfo));
402 mjpeg_debug("SSF: read filter result stream header");
403 y4m_log_stream_info(mjpeg_loglev_t("debug"), "result: ", &(filt->in_streaminfo));
404 alloc_yuv_buffers(filt->yuv, &(filt->out_streaminfo));
405 } else {
406 /* ...no filter; direct output:
407 * o result stream info is just a copy of the source stream info
408 */
409 filt->out_fd = filt->in_fd = -1;
410 y4m_copy_stream_info(&(filt->in_streaminfo), &(filt->out_streaminfo));
411 mjpeg_debug("SSF: copied source header");
412 }
413 }
414
415
416 static
process_segment_frames(pipe_sequence_t * ps,int segnum,int * frame,int * total_frames)417 void process_segment_frames(pipe_sequence_t *ps, int segnum,
418 int *frame, int *total_frames)
419 {
420 pipe_source_t *sources = ps->sources;
421 pipe_filter_t *the_output = &(ps->output);
422 PipeList *pl = &(ps->pl);
423 commandline_params_t *cl = &(ps->cl);
424
425 PipeSegment *seg = ps->pl.segments[segnum];
426 pipe_filter_t *filt = &(ps->filters[segnum]);
427
428
429 mjpeg_debug("PSF: segment %d, initial frame = %d", segnum, *frame);
430 while (*frame < seg->frame_count) {
431 int i;
432
433 for (i = 0; i < seg->input_count; i++) {
434 int in_index = seg->input_index[i];
435 pipe_source_t *source = &(sources[in_index]);
436 unsigned char **yuv;
437
438 if (filt->out_fd >= 0)
439 /* filter present; write/read through filter's buffer first */
440 yuv = filt->yuv;
441 else
442 /* no filter present; source -> direct to output buffer */
443 yuv = the_output->yuv;
444
445 mjpeg_debug("read frame %03d > input %d, src %d fd = %d",
446 *frame, i, in_index, source->fd);
447 if (y4m_read_frame(source->fd,
448 &(source->streaminfo), &(source->frameinfo),
449 yuv) != Y4M_OK) {
450 int err = errno;
451 mjpeg_error("ERRNO says: %s", strerror(err));
452 mjpeg_error_exit1("lavpipe: input stream error in stream %d,"
453 "sequence %d, frame %d",
454 i, segnum, *frame);
455 }
456 source->frame_num += 1;
457
458 if (filt->out_fd >= 0)
459 y4m_write_frame(filt->out_fd,
460 &(filt->out_streaminfo), &(filt->frameinfo),
461 yuv);
462 }
463
464 if (filt->in_fd >= 0) {
465 if (y4m_read_frame(filt->in_fd,
466 &(filt->in_streaminfo), &(filt->frameinfo),
467 the_output->yuv) != Y4M_OK) {
468 mjpeg_error_exit1( "lavpipe: filter stream error in sequence %d,"
469 "frame %d",
470 segnum, *frame);
471 }
472 }
473
474 /* output result */
475 y4m_write_frame(the_output->out_fd,
476 &(the_output->out_streaminfo),
477 &(the_output->frameinfo),
478 the_output->yuv);
479
480 (*frame)++;
481 if (++(*total_frames) == cl->frames) {
482 segnum = pl->segment_count - 1; /* = close all input files below */
483 break;
484 }
485 }
486 }
487
488 /*
489 * this is just being picky, but...
490 *
491 * Close all sources used by current segment, but only if they will
492 * cannot be used in current state by upcoming segments.
493 *
494 */
495
496 static
close_segment_inputs(pipe_sequence_t * ps,int segnum,int frame)497 void close_segment_inputs(pipe_sequence_t *ps, int segnum, int frame)
498 {
499 PipeList *pl = &(ps->pl);
500 pipe_source_t *sources = ps->sources;
501 PipeSegment *seg = pl->segments[segnum];
502 int i;
503
504 for (i = 0; i < seg->input_count; i++) {
505 int current_index = seg->input_index[i];
506 pipe_source_t *source = &(sources[current_index]);
507
508 if (source->fd >= 0) {
509 /* if it's still alive...
510 * ...iterate over remaining segments, and see if they can
511 * use this source.
512 */
513 int s;
514 for (s = segnum + 1; s < pl->segment_count; s++) {
515 int j;
516 PipeSegment *next_seg = pl->segments[s];
517
518 for (j = 0; j < next_seg->input_count; j++) {
519 int index = next_seg->input_index[j];
520 int offset = next_seg->input_offset[j];
521
522 if ( (index == current_index) &&
523 (offset == source->frame_num) ) {
524 /* A segment input offset matches the current frame...
525 * ...this source can still be used.
526 */
527 mjpeg_info("allowing input %d (source %d) to live",
528 i, current_index);
529 goto KEEP_SOURCE;
530 }
531 }
532 }
533 mjpeg_info( "closing input %d (source %d)", i, current_index);
534 decommission_pipe_source(source);
535 KEEP_SOURCE: ;
536 }
537 }
538 }
539
540 static
parse_command_line(int argc,char * argv[],commandline_params_t * cl)541 void parse_command_line(int argc, char *argv[], commandline_params_t *cl)
542 {
543 char c;
544 int err;
545
546 cl->verbose = 1;
547 cl->offset = 0;
548 cl->frames = 0;
549 cl->listfile = NULL;
550
551 err = 0;
552 while ((c = getopt(argc, argv, "o:n:v:")) != EOF) {
553 switch (c) {
554 case 'o':
555 cl->offset = atoi(optarg);
556 break;
557 case 'n':
558 cl->frames = atoi(optarg);
559 break;
560 case 'v':
561 cl->verbose = atoi(optarg);
562 if ( (cl->verbose < 0) || (cl->verbose > 2) ) {
563 usage();
564 exit(1);
565 }
566 break;
567 default:
568 err++;
569 }
570 }
571 if ((optind >= argc) || (err)) {
572 usage();
573 exit(1);
574 }
575 cl->listfile = strdup(argv[optind]);
576 }
577
578 static
initialize_pipe_sequence(pipe_sequence_t * ps,int argc,char ** argv)579 void initialize_pipe_sequence(pipe_sequence_t *ps, int argc, char **argv)
580 {
581 int i;
582 commandline_params_t *cl = &(ps->cl);
583 PipeList *pl = &(ps->pl);
584
585 init_pipe_filter(&(ps->output), "");
586 ps->output.out_fd = 1;
587
588 /* parse command-line arguments */
589 parse_command_line(argc, argv, cl);
590
591 /* set-up logging */
592 (void)mjpeg_default_handler_verbosity(cl->verbose);
593
594 /* read pipe 'recipe' */
595 if (read_pipe_list(cl->listfile, pl) < 0) {
596 mjpeg_error_exit1( "lavpipe: couldn't open \"%s\"", cl->listfile);
597 }
598
599 /* a negative offset means "from the end" */
600 if (cl->offset < 0) {
601 cl->offset = pl->frame_count + cl->offset;
602 }
603 if ((cl->offset >= pl->frame_count) ||
604 (cl->offset < 0)) {
605 mjpeg_error_exit1( "error: offset greater than # of frames in input");
606 }
607
608 /* zero frame count means "all frames" */
609 if (cl->frames == 0) {
610 cl->frames = pl->frame_count - cl->offset;
611 }
612 if ((cl->offset + cl->frames) > pl->frame_count) {
613 mjpeg_warn( "input too short for -n %d", cl->frames);
614 cl->frames = pl->frame_count - cl->offset;
615 }
616
617 /* initialize pipe sources */
618 ps->sources = malloc(pl->source_count * sizeof(ps->sources[0]));
619 for (i = 0; i < pl->source_count; i++)
620 init_pipe_source(&(ps->sources[i]), pl->source_cmd[i]);
621
622 /* initialize pipe filters */
623 ps->filters = malloc(pl->segment_count * sizeof(ps->filters[0]));
624 for (i = 0; i < pl->segment_count; i++)
625 init_pipe_filter(&(ps->filters[i]), pl->segments[i]->output_cmd);
626
627 }
628
629 static
process_pipe_sequence(pipe_sequence_t * ps)630 void process_pipe_sequence(pipe_sequence_t *ps)
631 {
632 int segm_num; /* current segment number */
633 int segm_frame; /* frame number, within a segment */
634 int sequ_frame; /* cumulative/total frame number */
635 int first_iteration;
636
637 /* find start segment/frame, given overall lavpipe offset ("-o") */
638 segm_frame = ps->cl.offset;
639 for (segm_num = 0;
640 segm_frame >= ps->pl.segments[segm_num]->frame_count;
641 segm_num++) {
642 segm_frame -= ps->pl.segments[segm_num]->frame_count;
643 }
644
645 /* process the segments */
646 first_iteration = 1;
647 sequ_frame = 0;
648 while ( (segm_num < ps->pl.segment_count) &&
649 (sequ_frame < ps->cl.frames) ) {
650 PipeSegment *seg = ps->pl.segments[segm_num];
651 pipe_filter_t *filt = &(ps->filters[segm_num]);
652
653 mjpeg_debug("starting segment %d, frame %d", segm_num, segm_frame);
654
655 open_segment_inputs(seg, filt, segm_frame, segm_num, sequ_frame,
656 &ps->pl, &ps->cl, ps->sources);
657 setup_segment_filter(seg, filt, segm_frame);
658
659 if (first_iteration) {
660 /* Initialize the final output stream, just once */
661
662 /* The final output stream parameters are taken from the output
663 * parameters of the first segment's output filter.
664 * (If there is no filter (i.e. "-", direct output), then the
665 * parameters will end up coming from the first segment's source
666 * stream.)
667 */
668 y4m_copy_stream_info(&(ps->output.out_streaminfo),
669 &(filt->in_streaminfo));
670 y4m_write_stream_header(ps->output.out_fd, &(ps->output.out_streaminfo));
671 alloc_yuv_buffers(ps->output.yuv, &(ps->output.out_streaminfo));
672 mjpeg_debug("output stream initialized");
673 first_iteration = 0;
674 } else {
675 /* For succeeding segments, make sure that the new filter's stream is
676 * consistent with the final output stream.
677 */
678 if (y4m_si_get_width(&(filt->in_streaminfo)) !=
679 y4m_si_get_width(&(ps->output.out_streaminfo)))
680 mjpeg_error_exit1("Stream mismatch: frame width");
681 if (y4m_si_get_height(&(filt->in_streaminfo)) !=
682 y4m_si_get_height(&(ps->output.out_streaminfo)))
683 mjpeg_error_exit1("Stream mismatch: frame height");
684 if (y4m_si_get_interlace(&(filt->in_streaminfo)) !=
685 y4m_si_get_interlace(&(ps->output.out_streaminfo)))
686 mjpeg_error_exit1("Stream mismatch: interlace");
687 mjpeg_debug("filter stream verified");
688 }
689
690 process_segment_frames(ps, segm_num, &segm_frame, &sequ_frame);
691 decommission_pipe_filter(filt);
692 close_segment_inputs(ps, segm_num, segm_frame);
693
694 /* prepare for next sequence */
695 segm_num++;
696 segm_frame = 0;
697 }
698 }
699
700 static
cleanup_pipe_sequence(pipe_sequence_t * ps)701 void cleanup_pipe_sequence(pipe_sequence_t *ps)
702 {
703 int i;
704 PipeList *pl = &(ps->pl);
705
706 /* free/fini everything */
707 fini_pipe_filter(&ps->output);
708 for (i = 0; i < pl->source_count; i++)
709 fini_pipe_source(&(ps->sources[i]));
710 free(ps->sources);
711 for (i = 0; i < pl->segment_count; i++)
712 fini_pipe_filter(&(ps->filters[i]));
713 free(ps->filters);
714 }
715
716
main(int argc,char * argv[])717 int main (int argc, char *argv[])
718 {
719 pipe_sequence_t ps;
720
721 initialize_pipe_sequence(&ps, argc, argv);
722 process_pipe_sequence(&ps);
723 cleanup_pipe_sequence(&ps);
724 return 0;
725 }
726