/*
 * This file is part of MPlayer.
 *
 * MPlayer 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.
 *
 * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include "config.h"
#include "mp_msg.h"
#include "help_mp.h"

#include "img_format.h"
#include "mp_image.h"
#include "vf.h"
#include "libavcodec/avcodec.h"

extern int avcodec_initialized;

struct vf_priv_s
{
  int       width, height;
  int       pix_fmt;
};

/* Support for avcodec's built-in deinterlacer.
 * Based on vf_lavc.c
 */

//===========================================================================//


/* Convert mplayer's IMGFMT_* to avcodec's PIX_FMT_* for the supported
 * IMGFMT's, and return -1 if the deinterlacer doesn't support
 * that format (-1 because 0 is a valid PIX_FMT).
 */
/* The deinterlacer supports planer 4:2:0, 4:2:2, and 4:4:4 YUV */
static int
imgfmt_to_pixfmt (int imgfmt)
{
  switch(imgfmt)
    {
      /* I hope I got all the supported formats */

      /* 4:2:0 */
    case IMGFMT_YV12:
    case IMGFMT_I420:
    case IMGFMT_IYUV:
      return PIX_FMT_YUV420P;
      break;

#if 0
      /* 4:2:2 */
    case IMGFMT_UYVY:
    case IMGFMT_UYNV:
    case IMGFMT_Y422:
    case IMGFMT_YUY2:
    case IMGFMT_YUNV:
    case IMGFMT_YVYU:
    case IMGFMT_Y42T:
    case IMGFMT_V422:
    case IMGFMT_V655:
      return PIX_FMT_YUV422P;
      break;
#endif

      /* Are there any _planar_ YUV 4:4:4 formats? */

    default:
      return -1;
    }
}


static int
config (struct vf_instance *vf,
        int width, int height, int d_width, int d_height,
        unsigned int flags, unsigned int outfmt)
{
  struct vf_priv_s *priv = vf->priv;

  priv->pix_fmt = imgfmt_to_pixfmt(outfmt);
  if(priv->pix_fmt == -1)
    return 0;

  /* The deinterlacer will fail if this is false */
  if ((width & 3) != 0 || (height & 3) != 0)
    return 0;

  /* If we get here, the deinterlacer is guaranteed not to fail */

  priv->width  = width;
  priv->height = height;

  return vf_next_config(vf,
			width, height,
			d_width, d_height,
			flags, outfmt);
}

static int
put_image (struct vf_instance *vf, mp_image_t *mpi, double pts)
{
  struct vf_priv_s *priv = vf->priv;
  mp_image_t* dmpi;
  AVPicture pic;
  AVPicture lavc_picture;

  lavc_picture.data[0]     = mpi->planes[0];
  lavc_picture.data[1]     = mpi->planes[1];
  lavc_picture.data[2]     = mpi->planes[2];
  lavc_picture.linesize[0] = mpi->stride[0];
  lavc_picture.linesize[1] = mpi->stride[1];
  lavc_picture.linesize[2] = mpi->stride[2];

  dmpi = vf_get_image(vf->next, mpi->imgfmt,
		      MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
		      priv->width, priv->height);

  pic.data[0]     = dmpi->planes[0];
  pic.data[1]     = dmpi->planes[1];
  pic.data[2]     = dmpi->planes[2];
  pic.linesize[0] = dmpi->stride[0];
  pic.linesize[1] = dmpi->stride[1];
  pic.linesize[2] = dmpi->stride[2];

  if (avpicture_deinterlace(&pic, &lavc_picture,
			    priv->pix_fmt, priv->width, priv->height) < 0)
    {
      /* This should not happen -- see config() */
      return 0;
    }

  return vf_next_put_image(vf, dmpi, pts);
}


static int
query_format (struct vf_instance *vf, unsigned int fmt)
{
  if(imgfmt_to_pixfmt(fmt) == -1)
    return 0;

  return vf_next_query_format(vf,fmt);
}


static int
vf_open(vf_instance_t *vf, char *args)
{
  /* We don't have any args */
  (void) args;

  vf->config       = config;
  vf->put_image    = put_image;
  vf->query_format = query_format;
  vf->priv         = malloc(sizeof(struct vf_priv_s));
  memset(vf->priv,0,sizeof(struct vf_priv_s));

  /* This may not technically be necessary just for a deinterlace,
   * but it seems like a good idea.
   */
  if(!avcodec_initialized)
    {
      avcodec_init();
      avcodec_register_all();
      avcodec_initialized=1;
    }

  return 1;
}


const vf_info_t vf_info_lavcdeint = {
    "libavcodec's deinterlacing filter",
    "lavcdeint",
    "Joe Rabinoff",
    "libavcodec's internal deinterlacer, in case you don't like "
      "the builtin ones (invoked with -pp or -npp)",
    vf_open,
    NULL
};


//===========================================================================//
