/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            libdv_wrapper.cc
 *
 *  Mon Apr 10 11:20:18 CEST 2006
 *  Copyright  2006 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  This file is part of MIaV.
 *
 *  MIaV 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.
 *
 *  MIaV 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 MIaV; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include "libdv_wrapper.h"

#include "format.h"

//#define COLORSPACE_YV12

LibDVWrapper::LibDVWrapper(DV::Quality quality,
                           DV::System system,
                           DV::Sampling sampling)
{
	decoder = dv_decoder_new(FALSE, // int ignored
                           FALSE, // int clamp_luma
                           FALSE);// int clamp_chroma
  setQuality(quality);
  setSystem(system);
  setSampling(sampling);

  yuv[0] = yuv[1] = yuv[2] = NULL;
  pitches[0] = pitches[1] = pitches[2] = 0;

  width = 720;
  height = 576;
  //  first = true;


  // TESTING
  //  decoder->std = e_dv_std_smpte_314m;//e_dv_std_iec_61834;
  decoder->num_dif_seqs = 12; // DIF sequences per frame (12 does the trick)

}


LibDVWrapper::~LibDVWrapper()
{
  dv_decoder_free(decoder);
}

void LibDVWrapper::setQuality(DV::Quality quality)
{
  dv_set_quality(decoder, quality);
}

void LibDVWrapper::setSystem(DV::System system)
{
  decoder->system = (dv_system_t)system;
}

void LibDVWrapper::setSampling(DV::Sampling sampling)
{
  decoder->sampling = (dv_sample_t)sampling;
}

Frame *LibDVWrapper::decode(Frame *input, DV::ColorSpace c)
{
  if(input->vformat != VF_DV) {
    fprintf(stderr, "Wrong format in LibDVWrapper, expected VF_DV, got: %i\n", input->vformat);
    return NULL;
  }

  /*
  if(first) {
    dv_parse_header(decoder, (const uint8_t*)input);
    //dv_parse_packs(decoder, frame->data); // Not needed anyway!
    decoder->std = e_dv_std_iec_61834;
    decoder->num_dif_seqs = 12;
    first = false;
  }
  */


  int size = 0;
  char* buf = NULL;
  video_format_t type = VF_NONE;
  DV::ColorSpace colorspace = c;
  switch(colorspace) {
  case DV::YUV:
#ifdef COLORSPACE_YV12
    size = width*height*2;
    buf = new char[size];
    type = VF_YV12;
    yuv[0] = (unsigned char*)buf;
    yuv[1] = (unsigned char*)yuv[0] + (width * height);
    yuv[2] = (unsigned char*)yuv[1] + (width * height / 4);
    pitches[0] = width;
    pitches[1] = width / 2;
    pitches[2] = width / 2;
#else
    size = width*height*2;
    buf = new char[size];
    type = VF_YUV422;
    yuv[0] = (unsigned char*)buf;
    yuv[1] = yuv[2] = NULL;
    pitches[0] = width * 2;
    pitches[1] = pitches[2] = 0;
#endif
    break;

  case DV::RGB:
    size = width*height*3;
    buf = new char[size];
    type = VF_RGB;
    yuv[0] = (unsigned char*)buf;
    yuv[1] = yuv[2] = NULL;
    pitches[0] = width * 3;
    pitches[1] = pitches[2] = 0;
    break;

  case DV::BGR0:
    size = width*height*4;
    buf = new char[size];
    type = VF_BRG0;
    yuv[0] = (unsigned char*)buf;
    yuv[1] = yuv[2] = NULL;
    pitches[0] = width * 4;
    pitches[1] = pitches[2] = 0;
    break;
  }

  dv_decode_full_frame(decoder,
                       (const uint8_t*)input->vframe,
                       (dv_color_space_t)colorspace,
                       yuv,
                       pitches);

  Frame *frame = new Frame(buf, size, type, NULL, 0, AF_NONE);

  frame->timecode = getTimeCode();

  return frame;
}

TimeCode LibDVWrapper::getTimeCode()
{
  TimeCode timecode;
  int timestamp[4];

  dv_get_timestamp_int(decoder, timestamp);

  timecode.hour = timestamp[0];
  timecode.min = timestamp[1];
  timecode.sec = timestamp[2];
  timecode.frame = timestamp[3];
  /*
  fprintf(stderr, "%d %d %d %d\n",
          timecode.hour,
          timecode.min,
          timecode.sec,
          timecode.frame);
  */
  return timecode;
}