/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            decoder.cc
 *
 *  Mon Mar  6 20:14:30 CET 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 "decoder.h"

#include "info.h"

#include "transcoder.h"

#define READ_DV_FROM_FILE

#include "dv.h"
#ifdef READ_DV_FROM_FILE
#include "dvfile.h"
#else/* READ_DV_FROM_FILE*/
#include "dv1394.h"
#endif/* READ_DV_FROM_FILE*/

#include <QEvent>
#include <QApplication>

#include "control.h"

#include "libdv_wrapper.h"

Decoder::Decoder()
{
  running = true;
  pframe = NULL;
  qApp->installEventFilter(this);
}

Decoder::~Decoder()
{
}

void Decoder::run()
{
  bool newconnection = true;

  //  closesem.acquire(); // Lock the shutdown process

#ifdef READ_DV_FROM_FILE
  dvfile reader;
#else/* READ_DV_FROM_FILE*/
  dv1394 reader;
  reader.connect();
#endif/* READ_DV_FROM_FILE*/
 
  LibDVWrapper dvdecoder(DV::ColorBest, DV::PAL, DV::YUV_422);

  while(running) {
    Frame *dvframe = reader.readFrame();
    if(!dvframe) continue; // An empty frame

    Frame *yuvframe = dvdecoder.decode(dvframe); // Decode the DV frame to YUV422 and PCM audio

    if(dvframe->vframe) delete dvframe->vframe;
    if(dvframe->aframe) delete dvframe->aframe;
    delete dvframe;

    if(!yuvframe) continue; // An error ocurred

    if(MIaV::control.isFrozen() == false) {
      if(yuvframe->vformat != VF_YUV422) {
        fprintf(stderr, "Wrong videoformat in Decoder, expected VF_YUV422, got %i\n", yuvframe->vformat);
      } else {
        if(!pframe) {
          fprintf(stderr, "PFrame data not set!\n");
        } else {
          pmutex.lock();
          memcpy(pframe, yuvframe->vframe, yuvframe->vframesize);
          pmutex.unlock();
        }
      }
    }
    
    if(MIaV::control.isRecording()) {
      if(newconnection) {
        NetworkSender *sender = new NetworkSender(MIaV::control.getCpr());

        sendersmutex.lock();
        senders.push_back(sender);
        sendersmutex.unlock();

        sender->start();
        newconnection = false;
      }

      sendersmutex.lock();
      if(senders.isEmpty() == false) 
        senders.back()->pushFrame(yuvframe,
                                  MIaV::control.getShot(),
                                  MIaV::control.getFreeze());
      sendersmutex.unlock();

    } else {

      sendersmutex.lock();
      // Remove idle senders
      QLinkedList<NetworkSender*>::iterator i;
      for (i = senders.begin(); i != senders.end(); i++) {
        NetworkSender *ns = *i;
        if(ns->queueSize() == 0) {
          i = senders.erase(i);
          ns->stop();
          delete ns;
        }
      }
      sendersmutex.unlock();


      if(yuvframe->vframe) delete yuvframe->vframe;
      if(yuvframe->aframe) delete yuvframe->aframe;
      delete yuvframe;

      newconnection = true;
    
    }
  }
  //  closesem.release(); // Unlock the shutdown process
}

void Decoder::setPFrameData(char *pframe)
{
  pmutex.lock();
  this->pframe = pframe;
  pmutex.unlock();
}

void Decoder::pframeAcquire()
{
  pmutex.lock();;
}

void Decoder::pframeRelease()
{
  pmutex.unlock();
}

void Decoder::snapshot(unsigned char *rgb)
{

  pmutex.lock();

  Frame frame(pframe, 720*576*2, VF_YUV422);

  Frame *brg0 = transcode(&frame, VF_BRG0, (char*)rgb, 720*576*4);
  if(brg0) delete brg0; // We don't need the actual frameobject
  else {
    // Some error occurred!
  }
  pmutex.unlock();
}

bool Decoder::eventFilter(QObject *o, QEvent *e)
{
  if (e->type() == QEvent::Close) {
    //    printf("QUIT from: %p, this: %p, testing: %p\n", o, this, qApp->activeWindow());
    if(qApp->activeWindow() == (QWidget*)o) { // Ignore close events from non top level widgets
      running = false; // Tell the thread to stop.
      sleep(1);// Wait for the thread to stop. (The ugly way!)
      //      closesem.acquire(); // Wait for the thread to stop.
    }
  }

  // standard event processing
  return false;
}

Status Decoder::status()
{
  Status s;

  s.server_diskspace = 0xffffffff;
  s.server_diskspace_max = 0xffffffff;
  s.server_load = 0xffffffff;
  s.server_load_max = 0xffffffff;
  s.server_ping_ms = 0xffffffff;
  s.server_fps = -1.0;

  sendersmutex.lock();
  // Get the server disk status etc.
  if(senders.isEmpty() == false) senders.back()->getServerStatus(&s);

  //  fprintf(stderr, "Load: %d of %d - ", s.server_load, s.server_load_max);
  //  fprintf(stderr, "Space: %d of %d\n", s.server_diskspace, s.server_diskspace_max);

  // Read out the queue sizes
  QLinkedList<NetworkSender*>::iterator i;
  for(i = senders.begin(); i != senders.end(); i++) {
    NetworkSender *ns = *i;
    s.queue_sizes.push_back(ns->queueSize());
  }
  sendersmutex.unlock();
  
  return s;
}