/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  mpeg2encoder.c - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt  
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: mpeg2encoder.c,v 1.5 2007/12/03 19:57:53 root Exp $
 *
 **/

//The most part of this Code is from the MMS V.2 Project:

#include <mpeg2encoder.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

extern "C" 
{
#include <avcodec.h>

#ifdef HAVE_SWSCALE
#  include <swscale.h>
#endif
}

#include "common.h"
   
//***************************************************************************
// 
//***************************************************************************

AVCodecContext* codec_context;
UINT8 *mpg_buf, *pic_dat;
AVFrame yuv_buf;
AVPicture pic;

//***************************************************************************
// 
//***************************************************************************

void mpeg_init(int video_width, int video_height, int fps)
{
   AVCodec* codec;
   int i = 0;
   int status;

   avcodec_init();
   avcodec_register_all();
    
   codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);

   if (!codec) 
   {
      tell(0, "Error: mpeg2encoder.c: codec not found\n");
      exit(0);
   }

   codec_context = avcodec_alloc_context();

   /* encoder parameters */

   avcodec_get_context_defaults(codec_context);

   codec_context->bit_rate   = 0;
   codec_context->width      = video_width;
   codec_context->height     = video_height;

#if LIBAVCODEC_BUILD >= 4754
   codec_context->time_base = (AVRational) { 1, fps };
#else
   codec_context->frame_rate = fps;
   codec_context->frame_rate_base = 1;
#endif

   codec_context->gop_size = 1; /* with a gop (keyframe interval) length of <= 1 
                                   avcodec enters 'I-Frame only' mode :-) */

   codec_context->flags = CODEC_FLAG_QSCALE;
   codec_context->pix_fmt = PIX_FMT_YUV420P;

   if ((status = avcodec_open(codec_context, codec)) < 0) 
   {
      tell(0, "Error: mpeg2encoder.c: codec could not be opened, status was (%d)\n", status);
      exit(0);
   }

   /* prepare necessary buffers */

   pic_dat = (UINT8 *) malloc( avpicture_get_size(PIX_FMT_YUV420P, video_width, video_height) );
   memset(pic_dat, 0, avpicture_get_size(PIX_FMT_YUV420P, video_width, video_height)); 
   mpg_buf = (UINT8 *) malloc(1000000); /* if segfaults are generated in encode_video, raise this size */
   avpicture_fill(&pic, pic_dat, PIX_FMT_YUV420P, video_width, video_height);

   /* prepare an AVPicture out of our buffers */

   yuv_buf = *avcodec_alloc_frame();

   /* the lower the better quality, but also larger images => slower to transfer */

   yuv_buf.quality = 2;

   /* copy the data from avpicture to avframe */

   for (i = 0; i < 4; ++i)
   {
      yuv_buf.data[i]= pic.data[i];
      yuv_buf.linesize[i]= pic.linesize[i];
   }
}

//***************************************************************************
// 
//***************************************************************************

mpeg_frame mpeg_draw(UINT8* buf)
{
   mpeg_frame new_frame;
   const int width = 720, height = 576;
   int i;
   AVPicture avpsrc;

   avpicture_fill(&avpsrc, buf, PIX_FMT_RGBA32, width, height);

#ifndef HAVE_SWSCALE

   img_convert(&pic, PIX_FMT_YUV420P, &avpsrc, PIX_FMT_RGBA32, width, height);

#else

   SwsContext* convert_ctx = sws_getContext(width, height, PIX_FMT_RGB24, width, height, 
                                            PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
   sws_scale(convert_ctx, avpsrc.data, avpsrc.linesize, 
             0, height, pic.data, pic.linesize);
   sws_freeContext(convert_ctx);

#endif

   /* copy the data from avpicture to avframe */
    
   for (i=0; i<4; ++i)
   {
      yuv_buf.data[i]= pic.data[i];
      yuv_buf.linesize[i]= pic.linesize[i];
   }
  
   new_frame.data = mpg_buf; /* mpg_buf just gives us a pointer to mpeg data
                                and tells us how large it is */

   /* raise 100000 if this segfaults */

   new_frame.size = avcodec_encode_video(codec_context, mpg_buf, 1000000, &yuv_buf);

   return new_frame;
}

//***************************************************************************
// 
//***************************************************************************

void mpeg_deinit()
{
   avcodec_close(codec_context);
   av_free(codec_context);
   free(pic_dat);
   free(mpg_buf);
}
