/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            mov_encoder.cc
 *
 *  Sat Feb 19 14:13:19 CET 2005
 *  Copyright  2005 Bent Bisballe
 *  deva@aasimon.org
 ****************************************************************************/

/*
 * Originally from:
 * RTVideoRec Realtime video recoder and encoder for Linux
 *
 * Copyright (C) 2004  B. Stultiens
 * Copyright (C) 2004  Koen Otter and Glenn van der Meyden
 */

/*
 *    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.
 */

/*
 * $Id$
 */

/*
 * $Log$
 * Revision 1.36  2005/07/22 15:59:39  deva
 * *** empty log message ***
 *
 * Revision 1.35  2005/07/07 12:42:19  deva
 * *** empty log message ***
 *
 * Revision 1.34  2005/07/05 23:15:16  deva
 * *** empty log message ***
 *
 * Revision 1.33  2005/07/02 11:39:52  deva
 * Added some audiocode.
 * Moved libfame code out of mov_encoder
 *
 * Revision 1.32  2005/06/19 20:04:43  deva
 * ImgEncoder now uses the file class for output, through jpeg_mem_dest.
 *
 * Revision 1.31  2005/06/19 11:44:14  deva
 * Cleaned up a log of logging.
 * Fixed server queue (shouldn't happen).
 * Added user and group lookup.
 *
 * Revision 1.30  2005/06/16 21:28:57  deva
 * Rewrote thread object
 * Fixed bug in mov_encoder (pushed read_sem too many times, whihc lead to
 * growing server queue)
 *
 * Revision 1.29  2005/06/14 18:58:35  deva
 * *** empty log message ***
 *
 * Revision 1.28  2005/06/14 12:29:40  deva
 * Incorporated the use of the Info object everywhere... also using the log functionality.
 *
 * Revision 1.27  2005/06/09 11:00:03  deva
 * Added daemon code, and cleaned up using -Wall and -Werror
 *
 * Revision 1.26  2005/05/26 12:48:36  deva
 * *** empty log message ***
 *
 * Revision 1.25  2005/05/25 15:36:05  deva
 * Added mpeg4 encoding to the encoders, controllable by the config file.
 *
 * Revision 1.24  2005/05/22 15:49:22  deva
 * Added multithreaded encoding support.
 *
 * Revision 1.23  2005/05/19 14:10:22  deva
 * Multithreading rulez?
 *
 * Revision 1.22  2005/05/17 19:16:26  deva
 * Made new mpeg writer work, with proper file permissions.
 *
 * Revision 1.21  2005/05/17 14:30:56  deva
 * Added code, preparing threaded encoding.
 *
 * Revision 1.20  2005/05/16 16:00:57  deva
 * Lots of stuff!
 *
 * Revision 1.19  2005/05/16 13:25:52  deva
 * Moved video setting to configuration file.
 * Fine tuned setting for 2.4ghz server
 *
 * Revision 1.18  2005/05/16 11:13:24  deva
 * Optimized some encoding parameters.
 *
 * Revision 1.17  2005/05/16 10:45:10  deva
 * Added new entries to fame parameter struct (bitrate omongst other things)
 *
 * Revision 1.16  2005/05/09 19:54:15  deva
 * *** empty log message ***
 *
 * Revision 1.15  2005/05/09 16:40:20  deva
 * Added optimize yuv conversion code
 *
 * Revision 1.14  2005/05/07 10:56:18  deva
 * Changed print outs
 *
 * Revision 1.13  2005/05/07 10:25:34  deva
 * Removed ffmpeg code from img_encoder and corrected decoding errors in mov_encoder
 *
 * Revision 1.12  2005/05/05 20:41:38  deva
 * Removed the last pieces of ffmpeg... replaced it with libfame...
 * Not quite working yet, but all the major code is in place!
 *
 * Revision 1.11  2005/05/03 17:12:53  deva
 * Fixed a bug (forgot to set the frametime).
 *
 * Revision 1.10  2005/05/03 08:31:59  deva
 * Removed the error object, and replaced it with a more generic info object.
 *
 * Revision 1.9  2005/05/02 10:59:44  deva
 * Reverted to mpg file format (accidentally used avi with mpeg2)
 *
 * Revision 1.8  2005/05/01 09:56:26  deva
 * Added Id and Log tags to all files
 */

#include "mov_encoder.h"

#include <errno.h>

// For nice
#include <unistd.h>

#include "miav_config.h"

#include "debug.h"

MovEncoder::MovEncoder(sem_t *r_sem,
                       FrameVectorQueue *in, sem_t *in_sem, pthread_mutex_t *in_mutex,
                       FramePriorityQueue *out, sem_t *out_sem, pthread_mutex_t *out_mutex,
                       Info *i)
{
  info = i;
  info->info("MovEncoder");

  running = true;

  inputqueue = in;
  outputqueue = out;

  input_sem = in_sem;
  output_sem = out_sem;
  
  read_sem = r_sem;

  input_mutex = in_mutex;
  output_mutex = out_mutex;
}

MovEncoder::~MovEncoder()
{
  info->info("~MovEncoder");
}


//#define COPY_DV 1

// this runs in a thread
void MovEncoder::thread_main()
{
  info->info("MovEncoder thread is running.");
  static volatile int test = 0;
  int outsize = 0;
  int insize = 0;

  // Run with slightly lower priority than MovEncoderWriter
  nice(1);

  FrameVector *item;
  Frame *in_frame;
  Frame *out_v_frame;
  Frame *out_a_frame;

  LibFAMEWrapper fame(info);
  //  LibLAMEWrapper lame(info);

  while(running) {
    sem_wait(input_sem);

    // Make a new instance for every frame sequence (usually 5) to ensure no
    // frame dependencies are broken when running multithreaded.
    LibLAMEWrapper lame(info);

    // Lock inout mutex
    pthread_mutex_lock(input_mutex);
    item = inputqueue->front();
    inputqueue->pop();

    insize = inputqueue->size();

    pthread_mutex_unlock(input_mutex);
    // Unlock input mutex

    if(item) {
      for(unsigned int cnt = 0; cnt < item->size(); cnt++) {
        in_frame = item->at(cnt);

#ifdef COPY_DV

        // Encode video
        out_v_frame = new Frame(in_frame->data, in_frame->size);
        out_v_frame->number = in_frame->number;

        // Encode audio
        out_a_frame = new Frame(in_frame->data, in_frame->size);
        out_a_frame->number = in_frame->number + 1;
       
#else /*COPY_DV*/

        // Encode video
        out_v_frame = fame.encode(in_frame);
        out_v_frame->number = in_frame->number;

        // Encode audio
        out_a_frame = lame.encode(in_frame);
        out_a_frame->number = in_frame->number + 1;
        
#endif /*COPY_DV*/
        delete in_frame;
        
        // Lock output mutex
        pthread_mutex_lock(output_mutex);

        outputqueue->push(out_v_frame);

        outputqueue->push(out_a_frame);

        outsize = outputqueue->size();

        pthread_mutex_unlock(output_mutex);
        // Unlock output mutex
      }

      delete item;

      test++;
      if(test % (25 * 24) == 0) info->info("Input pool size: %d, output pool size: %d", insize, outsize);

      // Kick frame writer
      sem_post(output_sem);

      // Kick reader
      sem_post(read_sem);
    }
  }

  info->info("MovEncoder thread has stopped.");
}