/*
 * video.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: video.c,v 1.10 2004/07/19 21:48:02 stefan Exp $
 */

#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <vdr/plugin.h>
#include "video.h"
#include "utils.h"
#include "setup-softdevice2net.h"



cVideoOut::~cVideoOut()
{
  dsyslog("[VideoOut]: Good bye");
}

/* ---------------------------------------------------------------------------
 */
void cVideoOut::CheckAspect(int new_afd, float new_asp)
{
    int           new_aspect;
    double        d_asp, afd_asp;

  /* -------------------------------------------------------------------------
   * check if there are some aspect ratio constraints
   * flags & XV_FORMAT_.. check if our ouput aspect is
   *                        NORMAL 4:3 or WIDE 16:9
   *
   */
  new_aspect = (new_asp > 1.4) ? DV_FORMAT_WIDE : DV_FORMAT_NORMAL;
  new_afd &= 0x07;
  /* -------------------------------------------------------------------------
   * override afd value with crop value from setup
   */
  new_afd = (setupStore.cropMode) ? setupStore.cropMode : new_afd;

  if (new_aspect == current_aspect && new_afd == current_afd)
  {
    aspect_changed = 0;
    return;
  }
  aspect_changed = 1;

  d_asp = (double) dwidth / (double) dheight;
  switch (new_afd) {
  /* --------------------------------------------------------------------------
   * these are still TODOs. in general I focus on 2 cases where there
   * is a mismatch (4:3 frame encoded as 16:9, and 16:9 enc as 4:3
   */
    case 0: afd_asp = new_asp; break;
    case 1: afd_asp = 4.0 / 3.0; break;
    case 2: afd_asp = 16.0 / 9.0; break;
    case 3: afd_asp = 14.0 / 9.0; break;
    case 4: afd_asp = new_asp; break;
    case 5: afd_asp = 4.0 / 3.0; break;
    case 6: afd_asp = 16.0 / 9.0; break;
    case 7: afd_asp = 16.0 / 9.0; break;
    default: afd_asp = new_asp; break;
  }

  sheight = fheight;
  swidth = fwidth;
  if (afd_asp <= new_asp) {
    swidth = (int) (0.5 + ((double) fwidth * afd_asp / new_asp));
  } else {
    sheight = (int) (0.5 + ((double) fheight * new_asp / afd_asp));
  }
  sxoff = (fwidth - swidth) / 2;
  syoff = (fheight - sheight) / 2;

  if (d_asp > afd_asp) {
    /* ------------------------------------------------------------------------
     * display aspect is wider than frame aspect
     * so we have to pillar-box
     */
    lheight = dheight;
    lwidth = (int) (0.5 + ((double) dheight * afd_asp));
    lxoff = (dwidth - lwidth) / 2;
    lyoff = 0;
  } else {
    /* ------------------------------------------------------------------------
     * display aspect is taller or equal than frame aspect
     * so we have to letter-box
     */
    lwidth = dwidth;
    lheight = (int) (0.5 + ((double) dwidth / afd_asp));
    lyoff = (dheight - lheight) / 2;
    lxoff = 0;
  }

  current_aspect = new_aspect;
  current_afd = new_afd;
}

/* ---------------------------------------------------------------------------
 */
void cVideoOut::CheckAspectDimensions(AVFrame *picture,
                                        AVCodecContext *context)
{
    static float  new_asp, aspect_F = -100.0;
    static int    aspect_I = -100;

  /* --------------------------------------------------------------------------
   * check and handle changes of dimensions first
   */
  if (fwidth != context->width || fheight != context->height)
  {
    dsyslog("[VideoOut]: resolution changed: W(%d -> %d); H(%d ->%d)\n",
             fwidth, context->width, fheight, context->height);
    fwidth = context->width; fheight = context->height;
    current_aspect = -1;
  }

#if LIBAVCODEC_BUILD > 4686
  if (picture->pan_scan->width) {
    new_asp = (float) (picture->pan_scan->width *
                       context->sample_aspect_ratio.num) /
               (float) (picture->pan_scan->height *
                        context->sample_aspect_ratio.den);
  } else {
    new_asp = (float) (context->width *
                       context->sample_aspect_ratio.num) /
               (float) (context->height *
                        context->sample_aspect_ratio.den);
  }
#else
  new_asp = context->aspect_ratio;
#endif


  if (aspect_I != context->dtg_active_format ||
      aspect_F != new_asp)
  {
    dsyslog("[VideoOut]: aspect changed (%d -> %d ; %f -> %f)",
             aspect_I,context->dtg_active_format,
             aspect_F,new_asp);
#if LIBAVCODEC_BUILD > 4686
    if (picture->pan_scan->width) {
      dsyslog("[VideoOut]: PAN/SCAN info present ([%d] %d - %d, %d %d)",
               picture->pan_scan->id,
               picture->pan_scan->width,
               picture->pan_scan->height,
               context->sample_aspect_ratio.num,
               context->sample_aspect_ratio.den);
      for (int i = 0; i < 3; i++) {
        dsyslog("[VideoOut]: PAN/SCAN  position  %d (%d %d)",
                 i,
                 picture->pan_scan->position[i] [0],
                 picture->pan_scan->position[i] [1]);
      }
    }
#endif

    aspect_I = context->dtg_active_format;
    aspect_F = new_asp;
  }

  CheckAspect (aspect_I, aspect_F);
}

void cVideoOut::OpenOSD(int X, int Y)
{
  OSDxOfs = X;
  OSDyOfs = Y;
  OSDpresent=true;
}

void cVideoOut::CloseOSD()
{
  OSDpresent=false;
}

void cVideoOut::Draw(cBitmap *Bitmap, unsigned char *osd_buf, int linelen)
{
    int           depth = (Bpp + 7) / 8;
    int           a, r, g, b, xr, xg, xb;
    tColor        c;
    tIndex        *buf;
    const tIndex  *adr;

  for (int y = 0; y < Bitmap->Height(); y+=2)
  {
    buf = (tIndex *) osd_buf +
            (linelen) * ( OSDyOfs/2 + (y/2) ) +
            OSDxOfs/2 * depth;

    for (int x = 0; x < Bitmap->Width(); x+=2)
    {
      adr = Bitmap->Data(x, y);
      c = Bitmap->Color(*adr);

      a = (c >> 24) & 255; //Alpha
      r = (c >> 16) & 255; //Red
      g = (c >> 8) & 255;  //Green
      b = c & 255;         //Blue


      switch (depth) {

	// alpha blending: displayColor = sourceColor x alpha / 255 + backgroundColor x (255 - alpha) / 255
        
        case 4:   //Bpp 32

	      buf[0] = (b*a/255)+(buf[0]*(255-a)/255);
	      buf[1] = (g*a/255)+(buf[1]*(255-a)/255);
	      buf[2] = (r*a/255)+(buf[2]*(255-a)/255);
	      buf[3] = a;
          buf += 4;
          break;
        case 2:   // Bpp 16 

#if 0                  
                 // get background color
                 xb = buf[0]&0x1f;
                 xg = (buf[0]&0xE0)>>2 | buf[1]&0x07;
                 xr = (buf[1]&0xf8)>>3;
                 

#define ALPHA 128
                 // alpha-blending
                 b = (b*ALPHA/255)+(xb*(255-ALPHA)/255);
                 g = (g*ALPHA/255)+(xg*(255-ALPHA)/255);
                 r = (r*ALPHA/255)+(xr*(255-ALPHA)/255);
#endif
                 
                 buf[0] = ((b >> 3)& 0x1F) | ((g & 0x1C) << 3);
                 buf[1] = (r & 0xF8) | (g >> 5);
              buf += 2;
              break;
        default:
            dsyslog("[VideoOut] OSD: unsupported depth %d exiting",depth);
            exit(1);
          break;
      }
    }
  }
}

