libavfilter/vf_separatefields.c
d0073c7a
 /*
  * Copyright (c) 2013 Paul B Mahol
  *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * FFmpeg 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
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "internal.h"
 
 typedef struct {
     int nb_planes;
1d8ce109
     AVFrame *second;
d0073c7a
 } SeparateFieldsContext;
 
 static int config_props_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     SeparateFieldsContext *sf = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
 
74561680
     sf->nb_planes = av_pix_fmt_count_planes(inlink->format);
d0073c7a
 
     if (inlink->h & 1) {
         av_log(ctx, AV_LOG_ERROR, "height must be even\n");
         return AVERROR_INVALIDDATA;
     }
 
d2e051e3
     outlink->time_base.num = inlink->time_base.num;
     outlink->time_base.den = inlink->time_base.den * 2;
d0073c7a
     outlink->frame_rate.num = inlink->frame_rate.num * 2;
     outlink->frame_rate.den = inlink->frame_rate.den;
     outlink->w = inlink->w;
     outlink->h = inlink->h / 2;
 
     return 0;
 }
 
1d8ce109
 static void extract_field(AVFrame *frame, int nb_planes, int type)
 {
     int i;
 
     for (i = 0; i < nb_planes; i++) {
         if (type)
             frame->data[i] = frame->data[i] + frame->linesize[i];
         frame->linesize[i] *= 2;
     }
 }
 
d0073c7a
 static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx = inlink->dst;
     SeparateFieldsContext *sf = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
1d8ce109
     int ret;
d0073c7a
 
     inpicref->height = outlink->h;
     inpicref->interlaced_frame = 0;
 
1d8ce109
     if (!sf->second) {
         goto clone;
     } else {
         AVFrame *second = sf->second;
d0073c7a
 
1d8ce109
         extract_field(second, sf->nb_planes, second->top_field_first);
 
         if (second->pts != AV_NOPTS_VALUE &&
             inpicref->pts != AV_NOPTS_VALUE)
             second->pts += inpicref->pts;
d0073c7a
         else
1d8ce109
             second->pts = AV_NOPTS_VALUE;
 
         ret = ff_filter_frame(outlink, second);
         if (ret < 0)
             return ret;
 clone:
         sf->second = av_frame_clone(inpicref);
         if (!sf->second)
             return AVERROR(ENOMEM);
d0073c7a
     }
 
1d8ce109
     extract_field(inpicref, sf->nb_planes, !inpicref->top_field_first);
 
     if (inpicref->pts != AV_NOPTS_VALUE)
         inpicref->pts *= 2;
 
     return ff_filter_frame(outlink, inpicref);
 }
 
 static int request_frame(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     SeparateFieldsContext *sf = ctx->priv;
     int ret;
 
     ret = ff_request_frame(ctx->inputs[0]);
     if (ret == AVERROR_EOF && sf->second) {
         sf->second->pts *= 2;
         extract_field(sf->second, sf->nb_planes, sf->second->top_field_first);
         ret = ff_filter_frame(outlink, sf->second);
         sf->second = 0;
e7834d29
     }
b8a5c761
 
1d8ce109
     return ret;
d0073c7a
 }
 
 static const AVFilterPad separatefields_inputs[] = {
     {
b211607b
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
d0073c7a
     },
     { NULL }
 };
 
 static const AVFilterPad separatefields_outputs[] = {
     {
1d8ce109
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props_output,
         .request_frame = request_frame,
d0073c7a
     },
     { NULL }
 };
 
325f6e0a
 AVFilter ff_vf_separatefields = {
b211607b
     .name        = "separatefields",
     .description = NULL_IF_CONFIG_SMALL("Split input video frames into fields."),
     .priv_size   = sizeof(SeparateFieldsContext),
     .inputs      = separatefields_inputs,
     .outputs     = separatefields_outputs,
d0073c7a
 };