/*
 * Implementation of class AviReader
 *
 * $Date$
 * $Revision$
 *
 */

#include "WImage/VideoArray.hh"
#include "WImage/AviReader.hh"
#include "WImage/debug.h"
#include <cstdio>

extern "C" {
#include "avilib.h"
}

#if !(defined __WATCOMC__ && __WATCOMC__ < 1230)
using namespace std;
#endif

AviReader::AviReader (char const *name, VideoArray < coeff > *arrays[],
                      int rawy, int rawx, int from, int to)
  : VideoReader (name, arrays, 3, from, to) 
{ 
  
    m_ysize = rawy;
    m_xsize = rawx;
    
    if (m_to - m_from <= 0)
      { 
        m_frames = framesInFile (name);
        m_to = m_frames;
        m_frames -= m_from;
      }
}

double
AviReader::frameRate (const char *fname)
{
  avi_t *avi = AVI_open_input_file ((char*)fname, 1);
  if (avi == NULL)
    {
      throw invalid_argument ("framesInFile: Could not open file.");
    }
  double rc = (int)AVI_frame_rate (avi);
  AVI_close (avi);
  return rc;
}

int 
AviReader::framesInFile (const char *fname)
{
  avi_t *avi = AVI_open_input_file ((char*)fname, 0);
  if (avi == NULL)
    {
      throw invalid_argument ("framesInFile: Could not open file.");
    }
  int rc = (int)AVI_video_frames (avi);
  AVI_close (avi);
  return rc;
}

void 
AviReader::fileDimensions (const char *fname, int &y, int &x)
{
  avi_t *avi = AVI_open_input_file ((char*)fname, 0);
  if (avi == NULL)
    {
      throw invalid_argument ("framesInFile: Could not open file.");
    }
  x = AVI_video_width(avi);
  y = AVI_video_height(avi);
  AVI_close (avi);
}


int 
AviReader::readfmt (void)
{
  int rc = 0;
  pixel *oneFrame = NULL;
  avi_t *avi = AVI_open_input_file ((char*)m_fname, 1);
  if (avi == NULL)
    {
      return -2;
    }
  char *compression = AVI_video_compressor (avi);

  if (strlen (compression) == 0)
    {
      int frameSize = AVI_frame_size (avi, m_from);
      int xysize = m_ysize * m_xsize;
      int keyframe = 0;
      oneFrame = NEW (pixel [frameSize]);

      if (frameSize != xysize * m_channels)
        {
          rc = -2;
          goto finish;
        }

      if (AVI_set_video_position (avi, m_from) != 0)
        {
          rc = -2;
          goto finish;
        }
  
      for (int f = m_from; f < m_to; f++)
        {
          // only allow same frame size over the whole video
          if (AVI_frame_size (avi, f) != frameSize)
            {
              rc = -2;
              goto finish;
            }
          if (AVI_read_frame (avi, (char*)oneFrame, &keyframe) < 0)
            {
              rc = -2;
              goto finish;
            }
          for (int c = 0; c < m_channels; c++)
            {
              m_arrays[c]->current (f - m_from);
            }
          for (int i = 0; i < xysize; i++)
            {
              for (int c = 0; c < m_channels; c++)
                {
                  assert (m_channels * i + c < frameSize);
                  assert (i < m_arrays[c]->size ());
                  m_arrays[c]->to (i, (coeff)oneFrame[m_channels * i + c]);
                }
            }
        }
    }
  else
    {
      rc = -2;
      goto finish;
    }

 finish:
  if (oneFrame != NULL)
    {
      DELETEAR (oneFrame);
    }
  AVI_close (avi);
  return rc;
}
  
