/*
  File: gethdr.cc

*/

#pragma implementation

#include <stdio.h>
#include <fstream.h>
#include <sys/time.h>

#include "athread.hh"

#include "error.hh"
#include "debug.hh"
#include "util.hh"

#include "sync.hh"
#include "mpeg2const.hh"
#include "mpeg2buff.hh"

#include "videoconst.hh"
#include "display.hh"
#include "idct.hh"
#include "vstream.hh"
#include "layerdata.hh"
#include "global.hh"

/* decode headers from one input stream
 * until an End of Sequence or picture start code
 * is found
 */

int LayerData::getheader(){
  unsigned int code;
  static int found_seqhdr=False; 
  // a sequence header should be found before returning from `getheader' the
  // first time (this is to set horizontal/vertical size properly)

  while (1){
    // look for startcode
    code=input->startcode();
    input->flushbits(32);
    switch (code){
    case Sequence_start_code: 
      TRACER("sequence start code");
      found_seqhdr=True;
      getseqhdr();  
      ext_user_data();
      break;
    case Gop_start_code:
      TRACER("gop start code"); 
      getgophdr();
      ext_user_data();
      break;
    case Picture_start_code:
      TRACER("picture start code");
      getpicturehdr();
      ext_user_data();
      if (found_seqhdr) return 1;
      break;
    case Sequence_end_code:
      TRACER("sequence end code");
      return 0;
    default:
      if (!quiet && framerate==0)
        fprintf(stderr,"Unexpected startcode %08x (ignored)\n", code);
      break;
    }
  }
  return 0;
}

// decode sequence header

void LayerData::getseqhdr(){
  TRACER("void LayerData::getseqhdr()");
  int i;
  int aspect_ratio, picture_rate, vbv_buffer_size;
  int constrained_parameters_flag;
  int load_intra_quantizer_matrix, load_non_intra_quantizer_matrix;
  int bit_rate;
  int pos=0;
  if (verbose>0)
    pos = input->getposition();

  horizontal_size = input->getbits(12);
  vertical_size = input->getbits(12);
  aspect_ratio = input->getbits(4);
  picture_rate = input->getbits(4);
  bit_rate = input->getbits(18);
  input->flushbits(1); /* marker bit (=1) */
  vbv_buffer_size = input->getbits(10);
  constrained_parameters_flag = input->getbits(1);

  if ((load_intra_quantizer_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++)
      intra_quantizer_matrix[zig_zag_scan[i]] = input->getbits(8);
  }
  else {
    for (i=0; i<64; i++)
      intra_quantizer_matrix[i] = default_intra_quantizer_matrix[i];
  }

  if ((load_non_intra_quantizer_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++)
      non_intra_quantizer_matrix[zig_zag_scan[i]] = input->getbits(8);
  }
  else {
    for (i=0; i<64; i++)
      non_intra_quantizer_matrix[i] = 16;
  }

  /* copy luminance to chrominance matrices */
  for (i=0; i<64; i++){
    chroma_intra_quantizer_matrix[i] =
      intra_quantizer_matrix[i];

    chroma_non_intra_quantizer_matrix[i] =
      non_intra_quantizer_matrix[i];
  }
  if (verbose>0){
    printf("sequence header (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  horizontal_size=%d\n",horizontal_size);
      printf("  vertical_size=%d\n",vertical_size);
      printf("  aspect_ratio=%d\n",aspect_ratio);
      printf("  picture_rate=%d\n",picture_rate);
      printf("  bit_rate=%d\n",bit_rate);
      printf("  vbv_buffer_size=%d\n",vbv_buffer_size);
      printf("  constrained_parameters_flag=%d\n",constrained_parameters_flag);
      printf("  load_intra_quantizer_matrix=%d\n",load_intra_quantizer_matrix);
      printf("  load_non_intra_quantizer_matrix=%d\n",load_non_intra_quantizer_matrix);
    }
  }
}


/* decode group of pictures header */

void LayerData::getgophdr(){
  int drop_flag, hour, minute, sec, frame, closed_gop, broken_link;
  int pos=0;
  if (verbose>0)
    pos = input->getposition();

  drop_flag = input->getbits(1);
  hour = input->getbits(5);
  minute = input->getbits(6);
  input->flushbits(1);
  sec = input->getbits(6);
  frame = input->getbits(6);
  closed_gop = input->getbits(1);
  broken_link = input->getbits(1);

  if (verbose>0){
    printf("group of pictures (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  drop_flag=%d\n",drop_flag);
      printf("  timecode %d:%02d:%02d:%02d\n",hour,minute,sec,frame);
      printf("  closed_gop=%d\n",closed_gop);
      printf("  broken_link=%d\n",broken_link);
    }
  }
}


/* decode picture header */

void LayerData::getpicturehdr(){
  int temp_ref, vbv_delay;
  int pos=0;
  if (verbose>0)
    pos = input->getposition();

  pict_scal = 0; /* unless overwritten by pict. spat. scal. ext. */

  temp_ref = input->getbits(10);
  pict_type = input->getbits(3);
  vbv_delay = input->getbits(16);
  if (pict_type==P_TYPE || pict_type==B_TYPE){
    full_forw = input->getbits(1);
    forw_r_size = input->getbits(3) - 1;
  }
  if (pict_type==B_TYPE){
    full_back = input->getbits(1);
    back_r_size = input->getbits(3) - 1;
  }

  if (verbose>0){
    printf("picture header (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  temp_ref=%d\n",temp_ref);
      printf("  pict_type=%d\n",pict_type);
      printf("  vbv_delay=%d\n",vbv_delay);
      if (pict_type==P_TYPE || pict_type==B_TYPE){
        printf("  full_forw=%d\n",full_forw);
        printf("  forw_r_size=%d\n",forw_r_size);
      }
      if (pict_type==B_TYPE){
        printf("  full_back=%d\n",full_back);
        printf("  back_r_size=%d\n",back_r_size);
      }
    }
  }

  // get extra bit picture
  while (input->getbits(1)) input->flushbits(8);
}

/* decode slice header */

int LayerData::getslicehdr(){
  int slice_vertical_position_extension, intra_slice;
  int pos=0;
  if (verbose>0)
    pos = input->getposition();

  slice_vertical_position_extension=(mpeg2 && vertical_size>2800) ? input->getbits(3) : 0;

  if (scalable_mode==SC_DP) pri_brk = input->getbits(7);

  int qs = input->getbits(5);
  quant_scale= mpeg2 ? (qscale_type ? non_linear_mquant_table[qs] : qs<<1) : qs;

  if (input->getbits(1)){
    intra_slice = input->getbits(1);
    input->flushbits(7);
    ext_bit_info();
  }
  else intra_slice = 0;

  if (verbose>2){
    printf("slice header (byte %d)\n",(pos>>3)-4);
    if (verbose>3){
      if (mpeg2 && vertical_size>2800)
        printf("  slice_vertical_position_extension=%d\n",slice_vertical_position_extension);
      if (scalable_mode==SC_DP)
        printf("  priority_breakpoint=%d\n",pri_brk);
      printf("  quantizer_scale_code=%d\n",qs);
    }
  }
  return slice_vertical_position_extension;
}


/* decode extension and user data */

void LayerData::ext_user_data(){
  int code=input->startcode();
  while (code==Ext_start_code || code==User_start_code){
    input->flushbits(32);  
    if (code==Ext_start_code){
      int ext_ID = input->getbits(4);
      switch (ext_ID){
      case SEQ_ID:
        sequence_extension();
        break;
      case DISP_ID:
        sequence_display_extension();
        break;
      case QUANT_ID:
        quant_matrix_extension();
        break;
      case SEQSCAL_ID:
        sequence_scalable_extension();
        break;
      case PANSCAN_ID:
        picture_display_extension();
        break;
      case CODING_ID:
        picture_coding_extension();
        break;
      case SPATSCAL_ID:
        picture_spatial_scalable_extension();
        break;
      case TEMPSCAL_ID:
        picture_temporal_scalable_extension();
        break;
      default:
        fprintf(stderr,"reserved extension start code ID %d\n",ext_ID);
        break;
      }
    }
    else {
      if (verbose) printf("user data\n");
    }
    code=input->startcode();
  }
}


/* decode sequence extension */

void LayerData::sequence_extension(){
  int prof_lev;
  int horizontal_size_extension, vertical_size_extension;
  int bit_rate_extension, vbv_buffer_size_extension, low_delay;
  int frame_rate_extension_n, frame_rate_extension_d;

  int pos=0;
  if (verbose>0)
    pos = input->getposition();
  mpeg2 = 1;
  scalable_mode = SC_NONE; /* unless overwritten by seq. scal. ext. */
  prof_lev = input->getbits(8);
  prog_seq = input->getbits(1);
  chroma_format = input->getbits(2);
  horizontal_size_extension = input->getbits(2);
  vertical_size_extension = input->getbits(2);
  bit_rate_extension = input->getbits(12);
  input->flushbits(1);
  vbv_buffer_size_extension = input->getbits(8);
  low_delay = input->getbits(1);
  frame_rate_extension_n = input->getbits(2);
  frame_rate_extension_d = input->getbits(5);

  horizontal_size = (horizontal_size_extension<<12) | (horizontal_size&0x0fff);
  vertical_size = (vertical_size_extension<<12) | (vertical_size&0x0fff);

  if (verbose>0){
    printf("sequence extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  profile_and_level_indication=%d\n",prof_lev);
      if (prof_lev<128){
        printf("    profile=%d, level=%d\n",prof_lev>>4,prof_lev&15);
      }
      printf("  progressive_sequence=%d\n",prog_seq);
      printf("  chroma_format=%d\n",chroma_format);
      printf("  horizontal_size_extension=%d\n",horizontal_size_extension);
      printf("  vertical_size_extension=%d\n",vertical_size_extension);
      printf("  bit_rate_extension=%d\n",bit_rate_extension);
      printf("  vbv_buffer_size_extension=%d\n",vbv_buffer_size_extension);
      printf("  low_delay=%d\n",low_delay);
      printf("  frame_rate_extension_n=%d\n",frame_rate_extension_n);
      printf("  frame_rate_extension_d=%d\n",frame_rate_extension_d);
    }
  }
}


/* decode sequence display extension */

void LayerData::sequence_display_extension(){
  int colour_primaries(0), transfer_characteristics(0);
  int display_horizontal_size, display_vertical_size;
  int pos=0;
  if (verbose>0)
     pos = input->getposition();
  
  int video_format = input->getbits(3);
  int colour_description = input->getbits(1);

  if (colour_description){
    colour_primaries = input->getbits(8);
    transfer_characteristics = input->getbits(8);
    matrix_coefficients = input->getbits(8);
  }

  display_horizontal_size = input->getbits(14);
  input->flushbits(1);
  display_vertical_size = input->getbits(14);

  if (verbose>0){
    printf("sequence display extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  video_format=%d\n",video_format);
      printf("  colour_description=%d\n",colour_description);
      if (colour_description){
        printf("    colour_primaries=%d\n",colour_primaries);
        printf("    transfer_characteristics=%d\n",transfer_characteristics);
        printf("    matrix_coefficients=%d\n",matrix_coefficients);
      }
      printf("  display_horizontal_size=%d\n",display_horizontal_size);
      printf("  display_vertical_size=%d\n",display_vertical_size);
    }
  }
}


/* decode quant matrix entension */

void LayerData::quant_matrix_extension(){
  int i;
  int load_intra_quantiser_matrix, load_non_intra_quantiser_matrix;
  int load_chroma_intra_quantiser_matrix;
  int load_chroma_non_intra_quantiser_matrix;
  int pos=0;
  if (verbose>0)
      pos=input->getposition();

  if ((load_intra_quantiser_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++){
      chroma_intra_quantizer_matrix[zig_zag_scan[i]]
      = intra_quantizer_matrix[zig_zag_scan[i]]
      = input->getbits(8);
    }
  }

  if ((load_non_intra_quantiser_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++){
      chroma_non_intra_quantizer_matrix[zig_zag_scan[i]]
      = non_intra_quantizer_matrix[zig_zag_scan[i]]
      = input->getbits(8);
    }
  }

  if ((load_chroma_intra_quantiser_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++)
      chroma_intra_quantizer_matrix[zig_zag_scan[i]] = input->getbits(8);
  }

  if ((load_chroma_non_intra_quantiser_matrix=input->getbits(1))!=0){
    for (i=0; i<64; i++)
      chroma_non_intra_quantizer_matrix[zig_zag_scan[i]] = input->getbits(8);
  }

  if (verbose>0){
    printf("quant matrix extension (byte %d)\n",(pos>>3)-4);
    printf("  load_intra_quantiser_matrix=%d\n", load_intra_quantiser_matrix);
    printf("  load_non_intra_quantiser_matrix=%d\n", load_non_intra_quantiser_matrix);
    printf("  load_chroma_intra_quantiser_matrix=%d\n", load_chroma_intra_quantiser_matrix);
    printf("  load_chroma_non_intra_quantiser_matrix=%d\n", load_chroma_non_intra_quantiser_matrix);
  }
}


/* decode sequence scalable extension */

void LayerData::sequence_scalable_extension(){
  int pos=0;
  if (verbose>0)
     pos = input->getposition();
  scalable_mode = input->getbits(2) + 1; /* add 1 to make SC_DP != SC_NONE */
  int layer_id = input->getbits(4);

  if (scalable_mode==SC_SPAT){
    llw = input->getbits(14); /* lower_layer_prediction_horizontal_size */
    input->flushbits(1);
    llh = input->getbits(14); /* lower_layer_prediction_vertical_size */
    hm = input->getbits(5);
    hn = input->getbits(5);
    vm = input->getbits(5);
    vn = input->getbits(5);
  }

  if (scalable_mode==SC_TEMP)
    error("temporal scalability not implemented\n");

  if (verbose>0){
    printf("sequence scalable extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  scalable_mode=%d\n",scalable_mode-1);
      printf("  layer_id=%d\n",layer_id);
      if (scalable_mode==SC_SPAT){
        printf("    lower_layer_prediction_horiontal_size=%d\n",llw);
        printf("    lower_layer_prediction_vertical_size=%d\n",llh);
        printf("    horizontal_subsampling_factor_m=%d\n",hm);
        printf("    horizontal_subsampling_factor_n=%d\n",hn);
        printf("    vertical_subsampling_factor_m=%d\n",vm);
        printf("    vertical_subsampling_factor_n=%d\n",vn);
      }
    }
  }
}


/* decode picture display extension */

void LayerData::picture_display_extension(){
  int n;
  short frame_centre_horizontal_offset[3];
  short frame_centre_vertical_offset[3];

  int pos=0;
  if (verbose>0)
    pos=input->getposition();

  if (prog_seq || pict_struct!=FRAME_PICTURE) n = 1;
  else n=repeatfirst ? 3 : 2;

  int i;
  for (i=0; i<n; i++){
    frame_centre_horizontal_offset[i] = (short)input->getbits(16);
    input->flushbits(1);
    frame_centre_vertical_offset[i] = (short)input->getbits(16);
    input->flushbits(1);
  }

  if (verbose>0){
    printf("picture display extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      for (i=0; i<n; i++){
        printf("  frame_centre_horizontal_offset[%d]=%d\n",i,
          frame_centre_horizontal_offset[i]);
        printf("  frame_centre_vertical_offset[%d]=%d\n",i,
          frame_centre_vertical_offset[i]);
      }
    }
  }
}


/* decode picture coding extension */

void LayerData::picture_coding_extension(){
  int chroma_420_type, composite_display_flag;
  int v_axis(0), field_sequence(0), sub_carrier(0), burst_amplitude(0), sub_carrier_phase(0);
  int pos=0;
  if (verbose>0)
    pos=input->getposition();

  h_forw_r_size = input->getbits(4) - 1;
  v_forw_r_size = input->getbits(4) - 1;
  h_back_r_size = input->getbits(4) - 1;
  v_back_r_size = input->getbits(4) - 1;
  dc_prec = input->getbits(2);
  pict_struct = input->getbits(2);
  topfirst = input->getbits(1);
  frame_pred_dct = input->getbits(1);
  conceal_mv = input->getbits(1);
  qscale_type = input->getbits(1);
  intravlc = input->getbits(1);
  altscan = input->getbits(1);
  repeatfirst = input->getbits(1);
  chroma_420_type = input->getbits(1);
  prog_frame = input->getbits(1);
  composite_display_flag = input->getbits(1);
  if (composite_display_flag){
    v_axis = input->getbits(1);
    field_sequence = input->getbits(3);
    sub_carrier = input->getbits(1);
    burst_amplitude = input->getbits(7);
    sub_carrier_phase = input->getbits(8);
  }

  if (verbose>0){
    printf("picture coding extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  forward_horizontal_f_code=%d\n",h_forw_r_size+1);
      printf("  forward_vertical_f_code=%d\n",v_forw_r_size+1);
      printf("  backward_horizontal_f_code=%d\n",h_back_r_size+1);
      printf("  backward_vertical_f_code=%d\n",v_back_r_size+1);
      printf("  intra_dc_precision=%d\n",dc_prec);
      printf("  picture_structure=%d\n",pict_struct);
      printf("  top_field_first=%d\n",topfirst);
      printf("  frame_pred_frame_dct=%d\n",frame_pred_dct);
      printf("  concealment_motion_vectors=%d\n",conceal_mv);
      printf("  q_scale_type=%d\n",qscale_type);
      printf("  intra_vlc_format=%d\n",intravlc);
      printf("  alternate_scan=%d\n",altscan);
      printf("  repeat_first_field=%d\n",repeatfirst);
      printf("  chroma_420_type=%d\n",chroma_420_type);
      printf("  progressive_frame=%d\n",prog_frame);
      printf("  composite_display_flag=%d\n",composite_display_flag);
      if (composite_display_flag){
        printf("    v_axis=%d\n",v_axis);
        printf("    field_sequence=%d\n",field_sequence);
        printf("    sub_carrier=%d\n",sub_carrier);
        printf("    burst_amplitude=%d\n",burst_amplitude);
        printf("    sub_carrier_phase=%d\n",sub_carrier_phase);
      }
    }
  }
}


/* decode picture spatial scalable extension */

void LayerData::picture_spatial_scalable_extension(){
  int pos=0;
  if (verbose>0)
    pos = input->getposition();

  pict_scal = 1; /* use spatial scalability in this picture */

  lltempref = input->getbits(10);
  input->flushbits(1);
  llx0 = input->getbits(15);
  if (llx0>=16384) llx0-= 32768;
  input->flushbits(1);
  lly0 = input->getbits(15);
  if (lly0>=16384) lly0-= 32768;
  stwc_table_index = input->getbits(2);
  llprog_frame = input->getbits(1);
  llfieldsel = input->getbits(1);
  if (verbose>0){
    printf("picture spatial scalable extension (byte %d)\n",(pos>>3)-4);
    if (verbose>1){
      printf("  lower_layer_temporal_reference=%d\n",lltempref);
      printf("  lower_layer_horizontal_offset=%d\n",llx0);
      printf("  lower_layer_vertical_offset=%d\n",lly0);
      printf("  spatial_temporal_weight_code_table_index=%d\n",
        stwc_table_index);
      printf("  lower_layer_progressive_frame=%d\n",llprog_frame);
      printf("  lower_layer_deinterlaced_field_select=%d\n",llfieldsel);
    }
  }
}


/* decode picture temporal scalable extension
 *
 * not implemented
 */

void LayerData::picture_temporal_scalable_extension(){
  error("temporal scalability not supported\n");
}

