📄 lavpipe.c
字号:
/* * lavpipe - combines several input streams and pipes them trough * arbitrary filters in order to finally output a resulting * video stream based on a given "recipe" (pipe list) * * Copyright (C) 2001, pHilipp Zabel <pzabel@gmx.de> * Copyright (C) 2001, Matthew Marjanovic <maddog@mir.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <ctype.h>#include <string.h>#include <sys/types.h>#include <signal.h>#include "mjpeg_logging.h"#include "pipelist.h"#include "yuv4mpeg.h"static void usage(void){ fprintf( stderr, "Usage: lavpipe [options] <pipe list>\n" "Options: -o num Frame offset - skip num frames in the beginning\n" " if num is negative, all but the last num frames are skipped\n" " -n num Only num frames are processed (0 means all frames)\n" " -v num Verbosity of output [0..2]\n" );}staticchar **parse_spawn_command(char *cmdline){ char **argv; char *p = cmdline; int i, argc = 0; if (p == NULL) return NULL; if (*p == '\0') return NULL; argc = 0; while (*p != '\0') { while (!isspace(*p)) { p++; if (*p == '\0') { argc++; goto END_OF_LINE; } } argc++; while (isspace(*p)) { p++; if (*p == '\0') goto END_OF_LINE; } } END_OF_LINE: argv = malloc(argc+1 * sizeof(argv[0])); for (p = cmdline, i=0; i < argc; i++) { argv[i] = p; while (!isspace(*(++p))); p[0] = '\0'; while (isspace(*(++p))) if (p[0] == '\0') break; } argv[argc] = NULL; return argv;}static pid_t fork_child_sub(char *command, int *fd_in, int *fd_out){ int n; int pipe_in[2]; int pipe_out[2]; char **myargv; pid_t pid; if (fd_in) { if (pipe(pipe_in)) { mjpeg_error_exit1( "Couldn't create input pipe from %s", command); } } if (fd_out) { if (pipe(pipe_out)) { mjpeg_error_exit1( "Couldn't create output pipe to %s", command); } } if ((pid = fork ()) < 0) { mjpeg_error_exit1("Couldn't fork %s", command); } if (pid == 0) { /* child redirects stdout to pipe_in */ if (fd_in) { close(pipe_in[0]); close(1); n = dup(pipe_in[1]); if (n != 1) exit (1); } /* child redirects stdin to pipe_out */ if (fd_out) { close(pipe_out[1]); close(0); n = dup(pipe_out[0]); if (n != 0) exit(1); } myargv = parse_spawn_command(command); execvp(myargv[0], myargv); return -1; } else { /* parent */ if (fd_in != NULL) { close(pipe_in[1]); *fd_in = pipe_in[0]; } if (fd_out != NULL) { close(pipe_out[0]); *fd_out = pipe_out[1]; } return pid; }}static pid_t fork_child(const char *command, int offset, int num, int *fd_in, int *fd_out){ char tmp1[1024], tmp2[1024]; char *current = tmp1; char *next = tmp2; char *p; strncpy(current, command, 1024); /* replace $o by offset */ p = strstr(current, "$o"); if (p) { p[0] = '\0'; p += 2; snprintf(next, 1024, "%s%d%s", current, offset, p); p = current; current = next; next = p; } /* replace $n by number of frames */ p = strstr(current, "$n"); if (p) { p[0] = '\0'; p += 2; snprintf(next, 1024, "%s%d%s", current, num, p); p = current; current = next; next = p; } mjpeg_debug( "Executing: '%s'", current); return fork_child_sub(current, fd_in, fd_out);}static void alloc_yuv_buffers(unsigned char *yuv[3], int w, int h){ yuv[0] = malloc (w * h * sizeof(yuv[0][0])); yuv[1] = malloc (w * h / 4 * sizeof(yuv[1][0])); yuv[2] = malloc (w * h / 4 * sizeof(yuv[2][0]));}static void free_yuv_buffers(unsigned char *yuv[3]){ free(yuv[0]); free(yuv[1]); free(yuv[2]); yuv[0] = yuv[1] = yuv[2] = NULL;}static void init_pipe_source(pipe_source_t *ps, char *command){ ps->command = strdup(command); y4m_init_stream_info(&(ps->streaminfo)); y4m_init_frame_info(&(ps->frameinfo)); ps->pid = -1; ps->fd = -1; ps->frame_num = 0;}static void fini_pipe_source(pipe_source_t *ps){ free(ps->command); y4m_fini_stream_info(&(ps->streaminfo)); y4m_fini_frame_info(&(ps->frameinfo));}static void spawn_pipe_source(pipe_source_t *ps, int offset, int count){ ps->pid = fork_child(ps->command, offset, count, &(ps->fd), NULL); ps->frame_num = offset; mjpeg_debug("spawned source '%s'", ps->command);}static void decommission_pipe_source(pipe_source_t *source){ if (source->fd >= 0) { close(source->fd); source->fd = -1; } if (source->pid > 0) { mjpeg_debug("DIE DIE DIE pid %d", source->pid); kill(source->pid, SIGINT); source->pid = -1; }}static void init_pipe_filter(pipe_filter_t *pf, const char *command){ pf->command = strdup(command); y4m_init_stream_info(&(pf->out_streaminfo)); y4m_init_stream_info(&(pf->in_streaminfo)); y4m_init_frame_info(&(pf->frameinfo)); pf->yuv[0] = pf->yuv[1] = pf->yuv[2] = NULL; pf->pid = -1; pf->out_fd = -1; pf->in_fd = -1;}static void fini_pipe_filter(pipe_filter_t *pf){ free(pf->command); free_yuv_buffers(pf->yuv); y4m_fini_stream_info(&(pf->out_streaminfo)); y4m_fini_stream_info(&(pf->in_streaminfo)); y4m_fini_frame_info(&(pf->frameinfo));}static void spawn_pipe_filter(pipe_filter_t *pf, int offset, int count){ pf->pid = fork_child(pf->command, offset, count, &(pf->in_fd), &(pf->out_fd)); mjpeg_debug("spawned filter '%s'", pf->command);}static void decommission_pipe_filter(pipe_filter_t *filt){ if (filt->in_fd >= 0) { close(filt->in_fd); filt->in_fd = -1; } if (filt->out_fd >= 0) { close(filt->out_fd); filt->out_fd = -1; } if (filt->pid > 0) { mjpeg_debug("DIE DIE DIE pid %d", filt->pid); kill(filt->pid, SIGINT); filt->pid = -1; } free_yuv_buffers(filt->yuv);} /* * make sure all the sources needed for this segment are cued up * and ready to produce frames * */staticvoid 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) { int i, j, k; for (i = 0; i < seg->input_count; i++) { int in_index = seg->input_index[i]; int in_offset = seg->input_offset[i]; pipe_source_t *source = &(sources[in_index]); mjpeg_debug("OSI: input %d == source %d: '%s'", i, in_index, source->command); /* spawn the source if not already running */ if (source->fd < 0) { /* calculate # of frames we want to get from this stream */ /* need to look if we can use this in successive sequences and what param_frames is */ int offset = in_offset + frame; int count = seg->frame_count - frame; /* until end of sequence */ for (j = segnum + 1; j < pl->segment_count; j++) { PipeSegment *other = pl->segments[j]; /* mjpeg_debug("checking i %d j %d", i, j); */ for (k = 0; k < other->input_count; k++) { /* mjpeg_debug("checking i %d j %d k %d", i, j, k); */ if (in_index == other->input_index[k]) { if ((offset + count) == other->input_offset[k]) { count += other->frame_count; /* add another sequence */ } else goto FINISH_CHECK; /* need to reopen with other offset */ } else goto FINISH_CHECK; /* stream will not be used in segment j anymore */ } } FINISH_CHECK: /* mjpeg_debug("finish-check i %d j %d k %d", i, j, k); */ if (count > cl->frames - total_frames) { count = cl->frames - total_frames; } /******** why have 'count'? let the source keep making frames... ...we'll just kill it when we are done anyway! *********/ /* spawn_pipe_source(source, offset, count);*/ spawn_pipe_source(source, offset, 0); if (y4m_read_stream_header(source->fd, &(source->streaminfo)) != Y4M_OK) mjpeg_error_exit1("Bad source header!"); mjpeg_debug("read header"); y4m_log_stream_info(LOG_DEBUG, "src: ", &(source->streaminfo)); } else { mjpeg_debug("...source %d is still alive.", in_index); } if (i == 0) { /* first time: copy stream info to filter */ y4m_copy_stream_info(&(filt->out_streaminfo), &(source->streaminfo)); mjpeg_debug("copied info"); } else { /* n-th time: make sure source streams match */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -