yading@10: /* yading@10: * Copyright (c) 2007 Bobby Bingham yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * audio and video splitter yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "libavutil/internal.h" yading@10: #include "libavutil/mem.h" yading@10: #include "libavutil/opt.h" yading@10: yading@10: #include "avfilter.h" yading@10: #include "audio.h" yading@10: #include "internal.h" yading@10: #include "video.h" yading@10: yading@10: typedef struct SplitContext { yading@10: const AVClass *class; yading@10: int nb_outputs; yading@10: } SplitContext; yading@10: yading@10: static int split_init(AVFilterContext *ctx) yading@10: { yading@10: SplitContext *s = ctx->priv; yading@10: int i; yading@10: yading@10: for (i = 0; i < s->nb_outputs; i++) { yading@10: char name[32]; yading@10: AVFilterPad pad = { 0 }; yading@10: yading@10: snprintf(name, sizeof(name), "output%d", i); yading@10: pad.type = ctx->filter->inputs[0].type; yading@10: pad.name = av_strdup(name); yading@10: yading@10: ff_insert_outpad(ctx, i, &pad); yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static void split_uninit(AVFilterContext *ctx) yading@10: { yading@10: int i; yading@10: yading@10: for (i = 0; i < ctx->nb_outputs; i++) yading@10: av_freep(&ctx->output_pads[i].name); yading@10: } yading@10: yading@10: static int filter_frame(AVFilterLink *inlink, AVFrame *frame) yading@10: { yading@10: AVFilterContext *ctx = inlink->dst; yading@10: int i, ret = AVERROR_EOF; yading@10: yading@10: for (i = 0; i < ctx->nb_outputs; i++) { yading@10: AVFrame *buf_out; yading@10: yading@10: if (ctx->outputs[i]->closed) yading@10: continue; yading@10: buf_out = av_frame_clone(frame); yading@10: if (!buf_out) { yading@10: ret = AVERROR(ENOMEM); yading@10: break; yading@10: } yading@10: yading@10: ret = ff_filter_frame(ctx->outputs[i], buf_out); yading@10: if (ret < 0) yading@10: break; yading@10: } yading@10: av_frame_free(&frame); yading@10: return ret; yading@10: } yading@10: yading@10: #define OFFSET(x) offsetof(SplitContext, x) yading@10: #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM yading@10: static const AVOption options[] = { yading@10: { "outputs", "set number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS }, yading@10: { NULL }, yading@10: }; yading@10: yading@10: #define split_options options yading@10: AVFILTER_DEFINE_CLASS(split); yading@10: yading@10: #define asplit_options options yading@10: AVFILTER_DEFINE_CLASS(asplit); yading@10: yading@10: static const AVFilterPad avfilter_vf_split_inputs[] = { yading@10: { yading@10: .name = "default", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .get_video_buffer = ff_null_get_video_buffer, yading@10: .filter_frame = filter_frame, yading@10: }, yading@10: { NULL } yading@10: }; yading@10: yading@10: AVFilter avfilter_vf_split = { yading@10: .name = "split", yading@10: .description = NULL_IF_CONFIG_SMALL("Pass on the input video to N outputs."), yading@10: yading@10: .priv_size = sizeof(SplitContext), yading@10: .priv_class = &split_class, yading@10: yading@10: .init = split_init, yading@10: .uninit = split_uninit, yading@10: yading@10: .inputs = avfilter_vf_split_inputs, yading@10: .outputs = NULL, yading@10: yading@10: .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, yading@10: }; yading@10: yading@10: static const AVFilterPad avfilter_af_asplit_inputs[] = { yading@10: { yading@10: .name = "default", yading@10: .type = AVMEDIA_TYPE_AUDIO, yading@10: .get_audio_buffer = ff_null_get_audio_buffer, yading@10: .filter_frame = filter_frame, yading@10: }, yading@10: { NULL } yading@10: }; yading@10: yading@10: AVFilter avfilter_af_asplit = { yading@10: .name = "asplit", yading@10: .description = NULL_IF_CONFIG_SMALL("Pass on the audio input to N audio outputs."), yading@10: yading@10: .priv_size = sizeof(SplitContext), yading@10: .priv_class = &asplit_class, yading@10: yading@10: .init = split_init, yading@10: .uninit = split_uninit, yading@10: yading@10: .inputs = avfilter_af_asplit_inputs, yading@10: .outputs = NULL, yading@10: yading@10: .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, yading@10: };