/*
 * Copyright 1993 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any expressed or implied warranty.
 */

/************************************************************
  This file contains mpeg parameter related functions, which
  are used in MPEGTool Encoder dialog. Since mpeg ecoder 
  function in MPEGTool doesn't check parameter by itself, 
  parameter check function also included in this file and
  parameter must use this function before calling encoder.
**************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <memory.h>
#include <signal.h>
#include "global.h"
#include "errorhandle.h"

#define CONFIGURATION_FILE "MPEGTool.cfg"
/*************************************************************
  Get parameters from MPEGTool Encoder dialog and define
  file names and call encoder (mpeg_encode)
 *************************************************************/
int
  mpeg_encoder_param_set(P)
MPEG_param *P;
{
  char in_fname[256],
      out_fname[256],
     stat_fname[256];

  int rcode=0,status;

  sprintf(in_fname,"\0"); sprintf(out_fname,"\0"); sprintf(stat_fname,"\0");
#ifdef DEBUG
  disp_param(P);
#endif
  if(eval_mpeg_param(P)) return -1;
  /*------ input file name selection ------*/
  if(P->in_dev==1) { /* disk */
    if(strlen(P->in_file_name)==0) {
      if(P->CCIR)
        sprintf(in_fname,"%s.CCIR",P->data_name);
      else
        sprintf(in_fname,"%s.rgb",P->data_name);
    }
    else
      strcpy(in_fname, P->in_file_name);
  }
  else { /* tape device */
    strcpy(in_fname, P->in_dev_name);
  }
  /*------ output file name selection ------*/
  if(P->out_dev==1) { /* disk */
    if(strlen(P->out_file_name)==0) {
      sprintf(out_fname,"%sN%dM%dQ%dB%d.mpg",
                        P->data_name,P->N, P->M, P->quant, P->Beta);
    }
    else
      strcpy(out_fname, P->out_file_name);
  }
  else if(P->out_dev == 1) { /* tape device */
    strcpy(out_fname, P->out_dev_name);
  }
  /*------ stat file name selection ------*/
  if(P->stat_out) {
    sprintf(stat_fname,"%sN%dM%dQ%dB%d.stat",
                        P->data_name, P->N, P->M, P->quant, P->Beta);
  }
  
  return(mpeg_encode(P->N, P->M, P->quant, P->Beta, 
			P->CCIR, P->width, P->height, 
			P->start_frame, P->num_of_frame,
			in_fname, P->in_dev, out_fname, stat_fname));
}
/******************** Set initial value for parameter ******************
  Init param set several initial parameter used in MPEG encoder
  If "MPEGTOOL.cfg" exist, the value is used as initial value.
************************************************************************/
void
  init_mpeg_param(P,config_file_name)
MPEG_param *P;
char *config_file_name;
{
  FILE *fdcfg;     /* File pointer of configuration file */
  char buf[256];   /* line read buffer */
  int  i = 0;      /* counter */
  char init_value[18][256];

  /* N,M,Q,B */
  sprintf(init_value[0],"1"); sprintf(init_value[1],"1"); 
  sprintf(init_value[2],"4"); sprintf(init_value[3],"64");
  /*start,# of frame*/
  sprintf(init_value[4],"1"); sprintf(init_value[5],"3"); 
  /*CCIR,height,width*/
  sprintf(init_value[6],"1"); sprintf(init_value[7],"480"); 
  sprintf(init_value[8],"512"); sprintf(init_value[9],"1");
  sprintf(init_value[10],"1"); sprintf(init_value[11],"0"); 
  /*data name */
  sprintf(init_value[12],"videodata"); sprintf(init_value[13],"\0");
  /* infile, indev */
  sprintf(init_value[14],"/dev/rst1"); sprintf(init_value[15],"\0");
  /* outfile,outdev */
  sprintf(init_value[16],"/dev/rst2"); sprintf(init_value[17],"\0");

/*------------- get initial values from MPEGTOOL.cfg file -----------*/
  if (config_file_name == NULL) 
    fdcfg = fopen(CONFIGURATION_FILE,"r");
  else 
    fdcfg = fopen(config_file_name,"r");
  if (fdcfg == NULL) {
#ifdef DEBUG
    fprintf(stderr,"%s not found. use default value\n",CONFIGURATION_FILE);
#endif
  }
  else {
    i = 0;
    while ((fgets(buf,256,fdcfg)!=NULL)&&(i<17)) {
      if(buf[0] != '#') { 
	/* Comment line if the first letter is '#' */    
	if((buf[0] == '=')||(strlen(buf)==1)) {
	  i++;   /* if the first letter is '=' or blank line, use default */  
	}
	else {
	  strcpy(init_value[i],buf);
	  init_value[i++][strlen(buf)-1] = '\000';
	}
      }
    }
    close(fdcfg);
  }
/*------------- parameter assignment --------------------------------*/
  P->N     =  atoi(init_value[0]);
  P->M     =  atoi(init_value[1]);
  P->quant =  atoi(init_value[2]);
  P->Beta  =  atoi(init_value[3]);

  P->start_frame  = atoi(init_value[4]);
  P->num_of_frame = atoi(init_value[5]);
 
  P->CCIR   = atoi(init_value[6]); /* set RGB data */
  P->height = atoi(init_value[7]);
  P->width  = atoi(init_value[8]);
 
  P->in_dev   = atoi(init_value[ 9]);
  P->out_dev  = atoi(init_value[10]);
  P->stat_out = atoi(init_value[11]);
 
  sprintf(P->data_name,     init_value[12]);
  sprintf(P->in_file_name,  init_value[13]);
  sprintf(P->in_dev_name,   init_value[14]);
  sprintf(P->out_file_name, init_value[15]);
  sprintf(P->out_dev_name,  init_value[16]);
  sprintf(P->stat_file_name,  init_value[17]);

  P->Psave = NULL;
}

/********************* DISPLAY paramter ******************/
int
  disp_param(P)
MPEG_param *P;
{
  char *menu ="\n\
*********************************************\n\
*  N, M, B, Q : (%3d,%3d %3d,%3d)           *\n\
*  from %4d,%4d frames                    *\n\
*  height, width : (%3d, %3d), CCIR :%3d    *\n\
*  dev (in,out,stat) = (%2d,%2d,%2d)           *\n\
*  data name     : %-23s  *\n\
*  in dev name   : %-23s  *\n\
*  in filename   : %-23s  *\n\
*  out dev name  : %-23s  *\n\
*  out filename  : %-23s  *\n\
*  stat filename : %-23s  *\n\
*********************************************\n"; 
  if(P == NULL) {
    fprintf(stderr,"MPEG parameter is NULL\n");
    return(-1);
  }
  printf(menu,P->N,P->M,P->Beta,P->quant,P->start_frame,
              P->num_of_frame,P->height,P->width,P->CCIR,
              P->in_dev, P->out_dev, P->stat_out,P->data_name,
              P->in_dev_name, P->in_file_name, P->out_dev_name, 
              P->out_file_name, P->stat_file_name);
  return(0);
}
/*****************************************************************
  mpeg parameter undate functions for MOTIF parameter setting.
  store_mpeg_parameter stores data into the Psave.
  restore_mpeg_parameter restores data from the Psave.
 *****************************************************************/
/*int
  store_mpeg_parameter(P)
MPEG_param *P;
{
  if(P == NULL) return -1;
  if ((P->Psave == NULL)||(P == P->Psave)) {
     P->Psave = (MPEG_param *)malloc(sizeof(MPEG_param));
  }
  P->Psave = P;
  return 0;
}

int
  restore_mpeg_parameter(P)
MPEG_param *P;
{
  if(P == NULL) return -1;
  if(P->Psave  == NULL) {
    fprintf(stderr,"No data has been stored\n"); 
    return -1;
  }
  P = P->Psave;
  memcpy(P,P->Psave,sizeof(MPEG_param)-sizeof(P->Psave));

  P->Psave = NULL;

  return(0);
}
*/
/****************************************************************
  eval_param.c - evaluate the parameter and if it is acceptable,
                 retuen 0, otherwise, -1 with the errnum, which
                 contains the reason of unacceptable.
                 Only ONE error is detected in each evaluation
 ****************************************************************/
int
  eval_mpeg_param(P)
MPEG_param *P;
{
  int mode = 0; /* mode of picture coding */
/* M, N evaluation */
/*************************************************************************/
/*    Evaluate N (intra_num ) and N (pred_num) value and choose mode     */
/*        N = 1              : I mode                                    */
/*        N > 1 && M = 1     : P mode                                    */
/*        M > 1 && N % M = 0 : B mode                                    */
/*        Otherwise          : Error                                     */
/*    In the case of B,P mode, the number of frames should be [M * int]. */
/*************************************************************************/
/* check M, N value */
/*------ check parameter ranges ------*/
  if ((P->N < 0)||(P->M < 0)) {
    errnum = 18; /* N or M must be positive */
    return -1;
  }
  if (P->N < P->M) {
    errnum = 16; /*  M must be smaller than or equal to N */
    return -1;
  }
  if(P->N%P->M != 0) {
    errnum = 11; /*  N must be M multiply by interger */
    return -1;
  }
  /*--- Beta value evaluation ---*/
  if((P->Beta < 1)||(P->Beta > 64)) {
    errnum = 12;
    return -1;
  }
  /*--- quantization scale ---*/
  if((P->quant <1 )||(P->quant > 32)) {
    errnum = 15;
    return -1;
  }
  /*------ mode selection ------*/
  if      (P->N == 1) mode = 0;  /* intra frame coding */
  else if (P->M == 1) mode = 1;  /* fwd prediction mode coding */
  else                mode = 3;  /* interpolate prediction mode coding */
  /*------ frame number evaluation ------*/
  /*--- if pred or bi-pred mode, number of frame should be M * int ---*/
  if (((mode==1)||(mode==3))&&((P->num_of_frame-1)%P->M != 0)) {
     errnum = 14; /* num_of_frame must be M multiply by interger */
     return -1;
   }
  /*------ evaluate frame number and set tape_number ------*/
  if(P->start_frame < 1) {
    errnum = 17;
    return -1;
  }
  else if((P->height < 0)||(P->width < 0)) {
    errnum = 13;
    return -1;
  }
  /*--------------------------------------------------------*/
  /*                 other parameters                       */
  /*--------------------------------------------------------*/
  /*--- data name set ---*/
  if(strlen(P->data_name)==0) {
    errnum = 19; return -1;
  }
  /*------ input file/device name evaluation ------*/
  if(P->in_dev == 1) { /* disk */
    if(P->in_file_name[strlen(P->in_file_name)-1] == '/') 
      {errnum = 21; return -1;} /* when directory */
  } 
  else { /* device */
    if(strlen(P->in_dev_name)==0) 
      {errnum = 22;return -1;}
    if(P->in_file_name[strlen(P->in_dev_name)-1] == '/') 
      {errnum = 22;return -1;} /* when directory */
  } 
  /*------ output file/device name evaluation ------*/
  if(P->out_dev == 1) { /* disk */
    if(P->out_file_name[strlen(P->out_file_name)-1] == '/') 
      {errnum = 21;return -1;} /* when directory */
  } 
  else {
    if(strlen(P->out_dev_name)==0) 
      {errnum = 23;return -1;}
    if(P->out_dev_name[strlen(P->out_dev_name)-1] == '/') 
      {errnum = 23;return -1;} /* when directory */
  } 
  return 0;
}
