Ejemplo n.º 1
0
int main(int argc, char **argv)
{
  FILE *infile, *strfile, *reconfile;

  uint32_t input_file_size; //TODO: Support file size values larger than 32 bits 
  yuv_frame_t orig,ref[MAX_REF_FRAMES];
  yuv_frame_t rec[MAX_REORDER_BUFFER];
  int rec_available[MAX_REORDER_BUFFER] = {0};
  int last_frame_output=-1;
  int num_encoded_frames,num_bits,start_bits,end_bits;
  int sub_gop=1;
  int rec_buffer_idx;
  int frame_num,frame_num0,k,r;
  int frame_offset;
  int ysize,csize,frame_size;
  int width,height,input_stride_y,input_stride_c;
  uint32_t acc_num_bits;
  snrvals psnr;
  snrvals accsnr;
  double bit_rate_in_kbps;
  enc_params *params;
  encoder_info_t encoder_info;

  init_use_simd();

  /* Read commands from command line and from configuration file(s) */
  if (argc < 3)
  {
    fprintf(stdout,"usage: %s <parameters>\n",argv[0]);
    fatalerror("");
  }
  params = parse_config_params(argc, argv);
  if (params == NULL)
  {
    fatalerror("Error while reading encoder paramaters.");
  }
  check_parameters(params);

  /* Open files */
  if (!(infile = fopen(params->infilestr,"rb")))
  {
    fatalerror("Could not open in-file for reading.");
  }
  if (!(strfile = fopen(params->outfilestr,"wb")))
  {
    fatalerror("Could not open out-file for writing.");
  }
  reconfile = NULL;
  if (params->reconfilestr && !(reconfile = fopen(params->reconfilestr,"wb")))
  {
    fatalerror("Could not open recon-file for reading.");
  }

  fseek(infile, 0, SEEK_END);
  input_file_size = ftell(infile);
  fseek(infile, 0, SEEK_SET);

  accsnr.y = 0;
  accsnr.u = 0;
  accsnr.v = 0;
  acc_num_bits = 0;

  height = params->height;
  width = params->width;
  input_stride_y = width;
  input_stride_c = width/2;
  ysize = height * width;
  csize = ysize / 4;
  frame_size = ysize + 2*csize;

  /* Create frames*/
  create_yuv_frame(&orig,width,height,0,0,0,0);
  for (r=0;r<MAX_REORDER_BUFFER;r++){
    create_yuv_frame(&rec[r],width,height,0,0,0,0);
  }
  for (r=0;r<MAX_REF_FRAMES;r++){ //TODO: Use Long-term frame instead of a large sliding window
    create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2);
  }

  /* Initialize main bit stream */
  stream_t stream;
  stream.bitstream = (uint8_t *)malloc(MAX_BUFFER_SIZE * sizeof(uint8_t));
  stream.bitbuf = 0;
  stream.bitrest = 32;
  stream.bytepos = 0;
  stream.bytesize = MAX_BUFFER_SIZE;

  /* Configure encoder */
  encoder_info.params = params;
  encoder_info.orig = &orig;
  for (r=0;r<MAX_REF_FRAMES;r++){
    encoder_info.ref[r] = &ref[r];
  }
  encoder_info.stream = &stream;
  encoder_info.width = width;
  encoder_info.height = height;

  encoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t));


  /* Write sequence header */ //TODO: Separate function for sequence header
  start_bits = get_bit_pos(&stream);
  putbits(16,width,&stream);
  putbits(16,height,&stream);
  putbits(1,params->enable_pb_split,&stream);
  putbits(1,params->enable_tb_split,&stream);
  putbits(2,params->max_num_ref-1,&stream); //TODO: Support more than 4 reference frames
  putbits(4,params->num_reorder_pics,&stream);// Max 15 reordered pictures
  putbits(2,params->max_delta_qp,&stream);
  putbits(1,params->deblocking,&stream);
  putbits(1,params->clpf,&stream);
  putbits(1,params->use_block_contexts,&stream);
  putbits(1,params->enable_bipred,&stream);

  end_bits = get_bit_pos(&stream);
  num_bits = end_bits-start_bits;
  acc_num_bits += num_bits;
  printf("SH:  %4d bits\n",num_bits);

  /* Start encoding sequence */
  num_encoded_frames = 0;
  sub_gop = max(1,params->num_reorder_pics+1);
  for (frame_num0 = params->skip; frame_num0 < (params->skip + params->num_frames) && (frame_num0+sub_gop)*frame_size <= input_file_size; frame_num0+=sub_gop)
  {
    for (k=0; k<sub_gop; k++) {
      int r,r0,r1,r2,r3;
      /* Initialize frame info */
      frame_offset = reorder_frame_offset(k,sub_gop);
      frame_num = frame_num0 + frame_offset;
      // If there is an initial I frame and reordering need to jump to the next P frame
      if (frame_num<params->skip) continue;

      encoder_info.frame_info.frame_num = frame_num - params->skip;
      rec_buffer_idx = encoder_info.frame_info.frame_num%MAX_REORDER_BUFFER;
      encoder_info.rec = &rec[rec_buffer_idx];
      encoder_info.rec->frame_num = encoder_info.frame_info.frame_num;
      if (params->num_reorder_pics==0) {
        if (params->intra_period > 0)
          encoder_info.frame_info.frame_type = ((num_encoded_frames%params->intra_period) == 0 ? I_FRAME : P_FRAME);
        else
          encoder_info.frame_info.frame_type = (num_encoded_frames == 0 ? I_FRAME : P_FRAME);
      } else {
        if (params->intra_period > 0)
          encoder_info.frame_info.frame_type = ((encoder_info.frame_info.frame_num%params->intra_period) == 0 ? I_FRAME :
              ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME));
        else
          encoder_info.frame_info.frame_type = (encoder_info.frame_info.frame_num == 0 ? I_FRAME :
              ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME));
      }

      int coded_phase = (num_encoded_frames + sub_gop - 2) % sub_gop + 1;
      int b_level = log2i(coded_phase);

      if (encoder_info.frame_info.frame_type == I_FRAME){
        encoder_info.frame_info.qp = params->qp + params->dqpI;
      }
      else if (params->num_reorder_pics==0) {
        if (num_encoded_frames % params->HQperiod)
          encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP;
        else
          encoder_info.frame_info.qp = params->qp;
      } else {
        if (encoder_info.frame_info.frame_num % sub_gop){
          float mqpB = params->mqpB;
#if DYADIC_CODING
          mqpB = 1.0+(b_level+1)*((mqpB-1.0)/2.0);
#endif
          encoder_info.frame_info.qp = (int)(mqpB*(float)params->qp) + params->dqpB;
        }  else
          encoder_info.frame_info.qp = params->qp;
      }

      encoder_info.frame_info.num_ref = min(num_encoded_frames,params->max_num_ref);
      if (params->num_reorder_pics > 0) {
#if DYADIC_CODING
        /* if we have a P frame then use the previous P frame as a reference */
        if ((num_encoded_frames-1) % sub_gop == 0) {
          if (num_encoded_frames==1)
            encoder_info.frame_info.ref_array[0] = 0;
          else
            encoder_info.frame_info.ref_array[0] = sub_gop-1;
          if (encoder_info.frame_info.num_ref>1 )
            encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1));

          for (r=2;r<encoder_info.frame_info.num_ref;r++){
            encoder_info.frame_info.ref_array[r] = r-1;
          }

        } else {
          int display_phase =  (encoder_info.frame_info.frame_num-1) % sub_gop;
          int ref_offset=sub_gop>>(b_level+1);

           encoder_info.frame_info.ref_array[0]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1);
           encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1);
          /* use most recent frames for the last ref(s)*/
          for (r=2;r<encoder_info.frame_info.num_ref;r++){
            encoder_info.frame_info.ref_array[r] = r-2;
          }
        }
#else
        /* if we have a P frame then use the previous P frame as a reference */
        if ((num_encoded_frames-1) % sub_gop == 0) {
          if (num_encoded_frames==1)
            encoder_info.frame_info.ref_array[0] = 0;
          else
            encoder_info.frame_info.ref_array[0] = sub_gop-1;
          if (encoder_info.frame_info.num_ref>1 )
            encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1));

          for (r=2;r<encoder_info.frame_info.num_ref;r++){
            encoder_info.frame_info.ref_array[r] = r-1;
          }

        } else {
          // Use the last encoded frame as the first ref
          if (encoder_info.frame_info.num_ref>0) {
            encoder_info.frame_info.ref_array[0] = 0;
          }
          /* Use the subsequent P frame as the 2nd ref */
          int phase = (num_encoded_frames + sub_gop - 2) % sub_gop;
          if (encoder_info.frame_info.num_ref>1) {
            if (phase==0)
              encoder_info.frame_info.ref_array[1] = min(sub_gop, num_encoded_frames-1);
            else
              encoder_info.frame_info.ref_array[1] = min(phase, num_encoded_frames-1);
          }
          /* Use the prior P frame as the 3rd ref */
          if (encoder_info.frame_info.num_ref>2) {
            encoder_info.frame_info.ref_array[2] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1);
          }
          /* use most recent frames for the last ref(s)*/
          for (r=3;r<encoder_info.frame_info.num_ref;r++){
            encoder_info.frame_info.ref_array[r] = r-3+1;
          }
        }

#endif
      } else {
        if (encoder_info.frame_info.num_ref==1){
          /* If num_ref==1 always use most recent frame */
          encoder_info.frame_info.ref_array[0] = 0;
        }
        else if (encoder_info.frame_info.num_ref==2){
          /* If num_ref==2 use most recent LQ frame and most recent HQ frame */
          r0 = 0;
          r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
          encoder_info.frame_info.ref_array[0] = r0;
          encoder_info.frame_info.ref_array[1] = r1;
        }
        else if (encoder_info.frame_info.num_ref==3){
          r0 = 0;
          r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
          r2 = r1==1 ? 2 : 1;
          encoder_info.frame_info.ref_array[0] = r0;
          encoder_info.frame_info.ref_array[1] = r1;
          encoder_info.frame_info.ref_array[2] = r2;
        }
        else if (encoder_info.frame_info.num_ref==4){
          r0 = 0;
          r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
          r2 = r1==1 ? 2 : 1;
          r3 = r2+1;
          if (r3==r1) r3 += 1;
          encoder_info.frame_info.ref_array[0] = r0;
          encoder_info.frame_info.ref_array[1] = r1;
          encoder_info.frame_info.ref_array[2] = r2;
          encoder_info.frame_info.ref_array[3] = r3;
        }
        else{
          for (r=0;r<encoder_info.frame_info.num_ref;r++){
            encoder_info.frame_info.ref_array[r] = r;
          }
        }
      }

      if (params->intra_rdo){
        if (encoder_info.frame_info.frame_type == I_FRAME){
          encoder_info.frame_info.num_intra_modes = 10;
        }
        else{
          encoder_info.frame_info.num_intra_modes = params->encoder_speed > 0 ? 4 : 10;
        }
      }
      else{
        encoder_info.frame_info.num_intra_modes = 4;
      }

#if 0
      /* To test sliding window operation */
      int offsetx = 500;
      int offsety = 200;
      int offset_rec = encoder_info.rec->offset_y + offsety * encoder_info.rec->stride_y +  offsetx;
      int offset_ref = encoder_info.ref[0]->offset_y + offsety * encoder_info.ref[0]->stride_y +  offsetx;
      if (encoder_info.frame_info.num_ref==2){
        int r0 = encoder_info.frame_info.ref_array[0];
        int r1 = encoder_info.frame_info.ref_array[1];
        printf("ref0=%3d ref1=%3d ",encoder_info.ref[r0]->y[offset_ref],encoder_info.ref[r1]->y[offset_ref]);
      }
      else{
        printf("ref0=XXX ref1=XXX ");
      }
#endif

      /* Read input frame */
      fseek(infile, frame_num*(frame_size+params->frame_headerlen)+params->file_headerlen+params->frame_headerlen, SEEK_SET);
      read_yuv_frame(&orig,width,height,infile);
      orig.frame_num = encoder_info.frame_info.frame_num;

      /* Encode frame */
      start_bits = get_bit_pos(&stream);
      encode_frame(&encoder_info);
      rec_available[rec_buffer_idx]=1;
      end_bits =  get_bit_pos(&stream);
      num_bits = end_bits-start_bits;
      num_encoded_frames++;

      /* Compute SNR */
      if (params->snrcalc){
        snr_yuv(&psnr,&orig,&rec[rec_buffer_idx],height,width,input_stride_y,input_stride_c);
      }
      else{
        psnr.y =  psnr.u = psnr.v = 0.0;
      }
      accsnr.y += psnr.y;
      accsnr.u += psnr.u;
      accsnr.v += psnr.v;

      acc_num_bits += num_bits;

      if (encoder_info.frame_info.frame_type==I_FRAME)
        fprintf(stdout,"%4d I %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v);
      else if (encoder_info.frame_info.frame_type==P_FRAME)
        fprintf(stdout,"%4d P %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v);
      else 
        fprintf(stdout,"%4d B %4d %10d %10.4f %8.4f %8.4f ",frame_num,encoder_info.frame_info.qp,num_bits,psnr.y,psnr.u,psnr.v);

      for (r=0;r<encoder_info.frame_info.num_ref;r++){
        fprintf(stdout,"%3d",encoder_info.frame_info.ref_array[r]);
      }
      fprintf(stdout,"\n");
      fflush(stdout);

      /* Write compressed bits for this frame to file */
      flush_bytebuf(&stream, strfile);

      if (reconfile){
        /* Write output frame */
        rec_buffer_idx = (last_frame_output+1) % MAX_REORDER_BUFFER;
        if (rec_available[rec_buffer_idx]) {
          last_frame_output++;
          write_yuv_frame(&rec[rec_buffer_idx],width,height,reconfile);
          rec_available[rec_buffer_idx]=0;
        }
      }
    }
  }
Ejemplo n.º 2
0
int main(int argc, char** argv)
{
    FILE *infile,*outfile;
    decoder_info_t decoder_info;
    stream_t stream;
    yuv_frame_t rec[MAX_REORDER_BUFFER];
    yuv_frame_t ref[MAX_REF_FRAMES];
    int rec_available[MAX_REORDER_BUFFER]={0};
    int rec_buffer_idx;
    int op_rec_buffer_idx;
    int decode_frame_num = 0;
    int last_frame_output = -1;
    int done = 0;
    int width;
    int height;
    int r;

    init_use_simd();

    parse_arg(argc, argv, &infile, &outfile);
    
	  fseek(infile, 0, SEEK_END);
	  int input_file_size = ftell(infile);
	  fseek(infile, 0, SEEK_SET);
    
    initbits_dec(infile, &stream);

    decoder_info.stream = &stream;

    memset(&decoder_info.bit_count,0,sizeof(bit_count_t));

    int bit_start = stream.bitcnt;
    /* Read sequence header */
    width = getbits(&stream,16);
    height = getbits(&stream,16);

    decoder_info.width = width;
    decoder_info.height = height;
    printf("width=%4d height=%4d\n",width,height);

    decoder_info.pb_split = getbits(&stream,1);
    printf("pb_split_enable=%1d\n",decoder_info.pb_split); //TODO: Rename variable to pb_split_enable

    decoder_info.tb_split_enable = getbits(&stream,1);
    printf("tb_split_enable=%1d\n",decoder_info.tb_split_enable);

    decoder_info.max_num_ref = getbits(&stream,2) + 1;
    fprintf(stderr,"num refs is %d\n",decoder_info.max_num_ref);

    decoder_info.interp_ref = getbits(&stream,1);
    decoder_info.max_delta_qp = getbits(&stream, 1);
    decoder_info.deblocking = getbits(&stream,1);
    decoder_info.clpf = getbits(&stream,1);
    decoder_info.use_block_contexts = getbits(&stream,1);
    decoder_info.bipred = getbits(&stream,1);

    decoder_info.bit_count.sequence_header += (stream.bitcnt - bit_start);

    for (r=0;r<MAX_REORDER_BUFFER;r++){
      create_yuv_frame(&rec[r],width,height,0,0,0,0);
    }
    for (r=0;r<MAX_REF_FRAMES;r++){
      create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2);
      decoder_info.ref[r] = &ref[r];
    }
    if (decoder_info.interp_ref) {
      for (r=0;r<MAX_SKIP_FRAMES;r++){
        decoder_info.interp_frames[r] = malloc(sizeof(yuv_frame_t));
        create_yuv_frame(decoder_info.interp_frames[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2);
      }
    }

    decoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t));

    do
    {
      decoder_info.frame_info.decode_order_frame_num = decode_frame_num;
      decode_frame(&decoder_info,rec);
      rec_buffer_idx = decoder_info.frame_info.display_frame_num%MAX_REORDER_BUFFER;
      rec_available[rec_buffer_idx]=1;

      done = initbits_dec(infile, &stream);

      op_rec_buffer_idx = (last_frame_output+1)%MAX_REORDER_BUFFER;
      if (rec_available[op_rec_buffer_idx]) {
        last_frame_output++;
        write_yuv_frame(&rec[op_rec_buffer_idx],width,height,outfile);
        rec_available[op_rec_buffer_idx] = 0;
      }
      printf("decode_frame_num=%4d display_frame_num=%4d input_file_size=%12d bitcnt=%12d\n",
          decode_frame_num,decoder_info.frame_info.display_frame_num,input_file_size,stream.bitcnt);
      decode_frame_num++;
    }
    while (!done);
    // Output the tail
    int i,j;
    for (i=1; i<=MAX_REORDER_BUFFER; ++i) {
      op_rec_buffer_idx=(last_frame_output+i) % MAX_REORDER_BUFFER;
      if (rec_available[op_rec_buffer_idx])
        write_yuv_frame(&rec[op_rec_buffer_idx],width,height,outfile);
      else
        break;
    }

    bit_count_t bit_count = decoder_info.bit_count;
    uint32_t tot_bits[NUM_FRAME_TYPES] = {0};

    for (i=0;i<NUM_FRAME_TYPES;i++){
      tot_bits[i] = bit_count.frame_header[i] +
                    bit_count.super_mode[i] +
                    bit_count.intra_mode[i] +
                    bit_count.mv[i] +
                    bit_count.skip_idx[i] +
                    bit_count.coeff_y[i] +
                    bit_count.coeff_u[i] +
                    bit_count.coeff_v[i] +
                    bit_count.cbp[i] +
                    bit_count.clpf[i];
    }
    tot_bits[0] += bit_count.sequence_header;
    int ni = bit_count.frame_type[0];
    int np = bit_count.frame_type[1];
    int nb = bit_count.frame_type[2];
    if (np==0) np = (1<<30); //Hack to avoid division by zero if there are no P frames
    if (nb==0) nb = (1<<30); //Hack to avoid division by zero if there are no B frames

    printf("\n\nBIT STATISTICS:\n");
    printf("Sequence header: %4d\n",bit_count.sequence_header);
    printf("                           I pictures:           P pictures:           B pictures:\n");
    printf("                           total    average      total    average      total    average\n");
    printf("Frame header:          %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.frame_header[0],bit_count.frame_header[0]/ni,bit_count.frame_header[1],bit_count.frame_header[1]/np,bit_count.frame_header[2],bit_count.frame_header[2]/nb);
    printf("Super mode:            %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.super_mode[0],bit_count.super_mode[0]/ni,bit_count.super_mode[1],bit_count.super_mode[1]/np,bit_count.super_mode[2],bit_count.super_mode[2]/nb);
    printf("Intra mode:            %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.intra_mode[0],bit_count.intra_mode[0]/ni,bit_count.intra_mode[1],bit_count.intra_mode[1]/np, bit_count.intra_mode[2],bit_count.intra_mode[2]/nb);
    printf("MV:                    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mv[0],bit_count.mv[0],bit_count.mv[1],bit_count.mv[1]/np, bit_count.mv[2],bit_count.mv[2]/nb);
    printf("Skip idx:              %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.skip_idx[0],bit_count.skip_idx[0],bit_count.skip_idx[1],bit_count.skip_idx[1]/np,bit_count.skip_idx[2],bit_count.skip_idx[2]/nb);
    printf("Coeff_y:               %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.coeff_y[0],bit_count.coeff_y[0]/ni,bit_count.coeff_y[1],bit_count.coeff_y[1]/np,bit_count.coeff_y[2],bit_count.coeff_y[2]/nb);
    printf("Coeff_u:               %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.coeff_u[0],bit_count.coeff_u[0]/ni,bit_count.coeff_u[1],bit_count.coeff_u[1]/np,bit_count.coeff_u[2],bit_count.coeff_u[2]/nb);
    printf("Coeff_v:               %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.coeff_v[0],bit_count.coeff_v[0]/ni,bit_count.coeff_v[1],bit_count.coeff_v[1]/np,bit_count.coeff_v[2],bit_count.coeff_v[2]/nb);
    printf("CBP (TU-split):        %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.cbp[0],bit_count.cbp[0]/ni,bit_count.cbp[1],bit_count.cbp[1]/np,bit_count.cbp[2],bit_count.cbp[2]/nb);
    printf("CLPF:                  %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.clpf[0],bit_count.clpf[0]/ni,bit_count.clpf[1],bit_count.clpf[1]/np,bit_count.clpf[2],bit_count.clpf[2]/nb);
    printf("Total:                 %9d  %9d  %9d  %9d  %9d  %9d\n",tot_bits[0],tot_bits[0],tot_bits[1],tot_bits[1]/np,tot_bits[2],tot_bits[2]/nb);
    printf("---------------------------------------------------------------------------------------\n\n");

    printf("PARAMETER STATISTICS:\n");
    printf("                           I pictures:           P pictures:           B pictures:\n");
    printf("                           total    average      total    average      total    average\n");
    printf("Skip-blocks (8x8):     %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mode[0][0],bit_count.mode[0][0]/ni,bit_count.mode[1][0],bit_count.mode[1][0]/np,bit_count.mode[2][0],bit_count.mode[2][0]/nb);
    printf("Intra-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mode[0][1],bit_count.mode[0][1]/ni,bit_count.mode[1][1],bit_count.mode[1][1]/np,bit_count.mode[2][1],bit_count.mode[2][1]/nb);
    printf("Inter-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mode[0][2],bit_count.mode[0][2]/ni,bit_count.mode[1][2],bit_count.mode[1][2]/np,bit_count.mode[2][2],bit_count.mode[2][2]/nb);
    printf("Bipred-blocks (8x8):   %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mode[0][3],bit_count.mode[0][3]/ni,bit_count.mode[1][3],bit_count.mode[1][3]/np,bit_count.mode[2][3],bit_count.mode[2][3]/nb);
    printf("Merge-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.mode[0][4],bit_count.mode[0][4]/ni,bit_count.mode[1][4],bit_count.mode[1][4]/np,bit_count.mode[2][4],bit_count.mode[2][4]/nb);

    printf("\n");
    printf("8x8-blocks (8x8):      %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.size[0][0],bit_count.size[0][0]/ni,bit_count.size[1][0],bit_count.size[1][0]/np,bit_count.size[2][0],bit_count.size[2][0]/nb);
    printf("16x16-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.size[0][1],bit_count.size[0][1]/ni,bit_count.size[1][1],bit_count.size[1][1]/np,bit_count.size[2][1],bit_count.size[2][1]/nb);
    printf("32x32-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.size[0][2],bit_count.size[0][2]/ni,bit_count.size[1][2],bit_count.size[1][2]/np,bit_count.size[2][2],bit_count.size[2][2]/nb);
    printf("64x64-blocks (8x8):    %9d  %9d  %9d  %9d  %9d  %9d\n",bit_count.size[0][3],bit_count.size[0][3]/ni,bit_count.size[1][3],bit_count.size[1][3]/np,bit_count.size[2][3],bit_count.size[2][3]/nb);

    printf("\n");
    printf("Mode and size distribution for P pictures:\n");
    printf("                            SKIP      INTRA      INTER     BIPRED      MERGE\n");
    printf("8x8-blocks (8x8):      %9d  %9d  %9d  %9d  %9d\n",bit_count.size_and_mode[P_FRAME][0][0],bit_count.size_and_mode[P_FRAME][0][1],bit_count.size_and_mode[P_FRAME][0][2],bit_count.size_and_mode[P_FRAME][0][3],bit_count.size_and_mode[P_FRAME][0][4]);
    printf("16x16-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n",bit_count.size_and_mode[P_FRAME][1][0],bit_count.size_and_mode[P_FRAME][1][1],bit_count.size_and_mode[P_FRAME][1][2],bit_count.size_and_mode[P_FRAME][1][3],bit_count.size_and_mode[P_FRAME][1][4]);
    printf("32x32-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n",bit_count.size_and_mode[P_FRAME][2][0],bit_count.size_and_mode[P_FRAME][2][1],bit_count.size_and_mode[P_FRAME][2][2],bit_count.size_and_mode[P_FRAME][2][3],bit_count.size_and_mode[P_FRAME][2][4]);
    printf("64x64-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n",bit_count.size_and_mode[P_FRAME][3][0],bit_count.size_and_mode[P_FRAME][3][1],bit_count.size_and_mode[P_FRAME][3][2],bit_count.size_and_mode[P_FRAME][3][3],bit_count.size_and_mode[P_FRAME][3][4]);

    printf("\n");
    printf("Mode and size distribution for B pictures:\n");
    printf("                            SKIP      INTRA      INTER     BIPRED      MERGE\n");
    printf("8x8-blocks (8x8):      %9d  %9d  %9d  %9d  %9d\n", bit_count.size_and_mode[B_FRAME][0][0], bit_count.size_and_mode[B_FRAME][0][1], bit_count.size_and_mode[B_FRAME][0][2], bit_count.size_and_mode[B_FRAME][0][3], bit_count.size_and_mode[B_FRAME][0][4]);
    printf("16x16-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n", bit_count.size_and_mode[B_FRAME][1][0], bit_count.size_and_mode[B_FRAME][1][1], bit_count.size_and_mode[B_FRAME][1][2], bit_count.size_and_mode[B_FRAME][1][3], bit_count.size_and_mode[B_FRAME][1][4]);
    printf("32x32-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n", bit_count.size_and_mode[B_FRAME][2][0], bit_count.size_and_mode[B_FRAME][2][1], bit_count.size_and_mode[B_FRAME][2][2], bit_count.size_and_mode[B_FRAME][2][3], bit_count.size_and_mode[B_FRAME][2][4]);
    printf("64x64-blocks (8x8):    %9d  %9d  %9d  %9d  %9d\n", bit_count.size_and_mode[B_FRAME][3][0], bit_count.size_and_mode[B_FRAME][3][1], bit_count.size_and_mode[B_FRAME][3][2], bit_count.size_and_mode[B_FRAME][3][3], bit_count.size_and_mode[B_FRAME][3][4]);

    int idx;
    int num = 5 + decoder_info.max_num_ref;
    printf("\nSuper-mode distribution for P pictures:\n");
    printf("                    SKIP   SPLIT INTERr0   MERGE   BIPRED  INTRA ");
    for (i = 1; i < decoder_info.max_num_ref; i++) printf("INTERr%1d ", i);
    printf("\n");
    for (idx=0;idx<NUM_BLOCK_SIZES;idx++){
      int size = 8<<idx;
      printf("%2d x %2d-blocks: ",size,size);
      for (i=0;i<num;i++){
        printf("%8d",bit_count.super_mode_stat[P_FRAME][idx][i]);
      }
      printf("\n");
    }
   
    printf("\nSuper-mode distribution for B pictures:\n");
    printf("                    SKIP   SPLIT INTERr0   MERGE   BIPRED  INTRA ");
    for (i = 1; i < decoder_info.max_num_ref; i++) printf("INTERr%1d ", i);
    printf("\n");
    for (idx = 0; idx<NUM_BLOCK_SIZES; idx++) {
      int size = 8 << idx;
      printf("%2d x %2d-blocks: ", size, size);
      for (i = 0; i<num; i++) {
        printf("%8d", bit_count.super_mode_stat[B_FRAME][idx][i]);
      }
      printf("\n");
    }

    int size;
    int max_num_ref = 4;
    printf("\n");
    printf("Ref_idx and size distribution for P pictures:\n");
    for (i=0;i<NUM_BLOCK_SIZES;i++){
      size = 1<<(i+3);
      printf("%2d x %2d-blocks: ",size,size);
      for (j=0;j<decoder_info.max_num_ref;j++){
        printf("%6d",bit_count.size_and_ref_idx[P_FRAME][i][j]);
      }
      printf("\n");
    }

    printf("\n");
    printf("Ref_idx and size distribution for B pictures:\n");
    for (i = 0; i<NUM_BLOCK_SIZES; i++) {
      size = 1 << (i + 3);
      printf("%2d x %2d-blocks: ", size, size);
      for (j = 0; j<decoder_info.max_num_ref; j++) {
        printf("%6d", bit_count.size_and_ref_idx[B_FRAME][i][j]);
      }
      printf("\n");
    }
    printf("\n");
    printf("bi-ref-P:  ");
    for (j=0;j<max_num_ref*max_num_ref;j++){
      printf("%7d",bit_count.bi_ref[P_FRAME][j]);
    }
    printf("\n");
    printf("bi-ref-B:  ");
    for (j = 0; j<max_num_ref*max_num_ref; j++) {
      printf("%7d", bit_count.bi_ref[B_FRAME][j]);
    }
    printf("\n");
    printf("-----------------------------------------------------------------\n");
    for (r=0;r<MAX_REORDER_BUFFER;r++){
      close_yuv_frame(&rec[r]);
    }
    for (r=0;r<MAX_REF_FRAMES;r++){
      close_yuv_frame(&ref[r]);
    }
    if (decoder_info.interp_ref) {
      for (r=0;r<MAX_SKIP_FRAMES;r++){
        close_yuv_frame(decoder_info.interp_frames[r]);
        free(decoder_info.interp_frames[r]);
      }
    }

    free(decoder_info.deblock_data);

    return 0;
}
Ejemplo n.º 3
0
int main(int argc, char **argv)
{
  FILE *infile, *strfile, *reconfile;

  uint32_t input_file_size; //TODO: Support file size values larger than 32 bits 
  yuv_frame_t orig,ref[MAX_REF_FRAMES];
  yuv_frame_t rec[MAX_REORDER_BUFFER];
  int rec_available[MAX_REORDER_BUFFER] = {0};
  int last_frame_output=-1;
  int num_encoded_frames,num_bits,start_bits,end_bits;
  int sub_gop=1;
  int rec_buffer_idx;
  int frame_num,frame_num0,k,r;
  int frame_offset;
  int ysize,csize,frame_size;
  int width,height;
  int min_interp_depth;
  int last_intra_frame_num = 0;
  uint32_t acc_num_bits;
  snrvals psnr;
  snrvals accsnr;
  double bit_rate_in_kbps;
  enc_params *params;
  encoder_info_t encoder_info;
  int y4m_output;
  // Keep track of last P frame for using the right references for the tail of a sequence in re-ordered modes
  int last_PorI_frame;

  init_use_simd();

  /* Read commands from command line and from configuration file(s) */
  if (argc < 3)
  {
    fprintf(stdout,"usage: %s <parameters>\n",argv[0]);
    fatalerror("");
  }
  params = parse_config_params(argc, argv);
  if (params == NULL)
  {
    fatalerror("Error while reading encoder paramaters.");
  }
  check_parameters(params);

  /* Open files */
  if (!(infile = fopen(params->infilestr,"rb")))
  {
    fatalerror("Could not open in-file for reading.");
  }
  if (!(strfile = fopen(params->outfilestr,"wb")))
  {
    fatalerror("Could not open out-file for writing.");
  }
  reconfile = NULL;
  y4m_output = 0;
  if (params->reconfilestr) {
    char *p;
    if (!(reconfile = fopen(params->reconfilestr,"wb")))
    {
      fatalerror("Could not open recon-file for reading.");
    }
    p = strrchr(params->reconfilestr,'.');
    y4m_output = p != NULL && strcmp(p,".y4m") == 0;
  }
  
  fseek(infile, 0, SEEK_END);
  input_file_size = ftell(infile);
  fseek(infile, 0, SEEK_SET);


  if (y4m_output) {
    fprintf(reconfile,
     "YUV4MPEG2 W%d H%d F%d:1 Ip A0:0 C420jpeg XYSCSS=420JPEG\x0a",
     params->width, params->height, (int)params->frame_rate);
  }

  accsnr.y = 0;
  accsnr.u = 0;
  accsnr.v = 0;
  acc_num_bits = 0;

  height = params->height;
  width = params->width;
  ysize = height * width;
  csize = ysize / 4;
  frame_size = ysize + 2*csize;

  /* Create frames*/
  create_yuv_frame(&orig,width,height,0,0,0,0);
  for (r=0;r<MAX_REORDER_BUFFER;r++){
    create_yuv_frame(&rec[r],width,height,0,0,0,0);
  }
  for (r=0;r<MAX_REF_FRAMES;r++){ //TODO: Use Long-term frame instead of a large sliding window
    create_yuv_frame(&ref[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2);
  }
  if (params->interp_ref) {
    for (r=0;r<MAX_SKIP_FRAMES;r++){
      encoder_info.interp_frames[r] = malloc(sizeof(yuv_frame_t));
      create_yuv_frame(encoder_info.interp_frames[r],width,height,PADDING_Y,PADDING_Y,PADDING_Y/2,PADDING_Y/2);
    }
  }

  /* Initialize main bit stream */
  stream_t stream;
  stream.bitstream = (uint8_t *)malloc(MAX_BUFFER_SIZE * sizeof(uint8_t));
  stream.bitbuf = 0;
  stream.bitrest = 32;
  stream.bytepos = 0;
  stream.bytesize = MAX_BUFFER_SIZE;

  /* Configure encoder */
  encoder_info.params = params;
  encoder_info.orig = &orig;
  for (r=0;r<MAX_REF_FRAMES;r++){
    encoder_info.ref[r] = &ref[r];
  }
  encoder_info.stream = &stream;
  encoder_info.width = width;
  encoder_info.height = height;

  encoder_info.deblock_data = (deblock_data_t *)malloc((height/MIN_PB_SIZE) * (width/MIN_PB_SIZE) * sizeof(deblock_data_t));


  /* Write sequence header */ //TODO: Separate function for sequence header
  start_bits = get_bit_pos(&stream);
  putbits(16,width,&stream);
  putbits(16,height,&stream);
  putbits(1,params->enable_pb_split,&stream);
  putbits(1,params->enable_tb_split,&stream);
  putbits(2,params->max_num_ref-1,&stream); //TODO: Support more than 4 reference frames
  putbits(1,params->interp_ref,&stream);// Use an interpolated reference frame
  putbits(1, (params->max_delta_qp || params->bitrate), &stream);
  putbits(1,params->deblocking,&stream);
  putbits(1,params->clpf,&stream);
  putbits(1,params->use_block_contexts,&stream);
  putbits(1,params->enable_bipred,&stream);

  end_bits = get_bit_pos(&stream);
  num_bits = end_bits-start_bits;
  acc_num_bits += num_bits;
  printf("SH:  %4d bits\n",num_bits);

  /* Start encoding sequence */
  num_encoded_frames = 0;
  sub_gop = max(1,params->num_reorder_pics+1);

  min_interp_depth = log2i(params->num_reorder_pics+1)-3;
  if (params->frame_rate > 30) min_interp_depth--;

  last_PorI_frame = -1;

  rate_control_t rc;
  encoder_info.rc = &rc;
  if (params->bitrate > 0) {
    int target_bits = params->bitrate / params->frame_rate;
    int num_sb = ((width + MAX_BLOCK_SIZE - 1) / MAX_BLOCK_SIZE) * ((height + MAX_BLOCK_SIZE - 1) / MAX_BLOCK_SIZE);
    init_rate_control_per_sequence(&rc, target_bits, num_sb);
  }

  for (frame_num0 = params->skip; frame_num0 < (params->skip + params->num_frames) && (frame_num0+1)*frame_size <= input_file_size; frame_num0+=sub_gop)
  {
    for (k=0; k<sub_gop; k++) {
      int r,r1,r2,r3;
      /* Initialize frame info */
      frame_offset = reorder_frame_offset(k,sub_gop,params->dyadic_coding);
      frame_num = frame_num0 + frame_offset;
      // If there is an initial I frame and reordering need to jump to the next P frame
      if (frame_num<params->skip) continue;

      encoder_info.frame_info.frame_num = frame_num - params->skip;
      rec_buffer_idx = encoder_info.frame_info.frame_num%MAX_REORDER_BUFFER;
      encoder_info.rec = &rec[rec_buffer_idx];
      encoder_info.rec->frame_num = encoder_info.frame_info.frame_num;
      if (params->num_reorder_pics==0) {
        if (params->intra_period > 0)
          encoder_info.frame_info.frame_type = ((num_encoded_frames%params->intra_period) == 0 ? I_FRAME : P_FRAME);
        else
          encoder_info.frame_info.frame_type = (num_encoded_frames == 0 ? I_FRAME : P_FRAME);
      } else {
        if (params->intra_period > 0)
          encoder_info.frame_info.frame_type = ((encoder_info.frame_info.frame_num%params->intra_period) == 0 ? I_FRAME :
              ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME));
        else
          encoder_info.frame_info.frame_type = (encoder_info.frame_info.frame_num == 0 ? I_FRAME :
              ((encoder_info.frame_info.frame_num%sub_gop)==0 ? P_FRAME : B_FRAME));
      }

      int coded_phase = (num_encoded_frames + sub_gop - 2) % sub_gop + 1;
      int b_level = log2i(coded_phase);
      encoder_info.frame_info.b_level = b_level;

      if (encoder_info.frame_info.frame_type == I_FRAME){
        encoder_info.frame_info.qp = params->qp + params->dqpI;
        last_intra_frame_num = encoder_info.frame_info.frame_num;
      }
      else if (params->num_reorder_pics==0) {
        if (num_encoded_frames % params->HQperiod)
          encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP;
        else
          encoder_info.frame_info.qp = params->qp;
      } else {
        if (encoder_info.frame_info.frame_num % sub_gop) {
          if (params->dyadic_coding){
            if (b_level == 0)
              encoder_info.frame_info.qp = (int)(params->mqpB0*(float)params->qp) + params->dqpB0;
            else if (b_level == 1)
              encoder_info.frame_info.qp = (int)(params->mqpB1*(float)params->qp) + params->dqpB1;
            else if (b_level == 2)
              encoder_info.frame_info.qp = (int)(params->mqpB2*(float)params->qp) + params->dqpB2;
            else if (b_level == 3)
              encoder_info.frame_info.qp = (int)(params->mqpB3*(float)params->qp) + params->dqpB3;
            else
              encoder_info.frame_info.qp = (int)(params->mqpB*(float)params->qp) + params->dqpB;
          }
          else {
            encoder_info.frame_info.qp = (int)(params->mqpB*(float)params->qp) + params->dqpB;
          }
        }  else {
          if (encoder_info.frame_info.frame_num % params->HQperiod) {
            encoder_info.frame_info.qp = (int)(params->mqpP*(float)params->qp) + params->dqpP;
          } else
            encoder_info.frame_info.qp = params->qp;
        }
      }
      encoder_info.frame_info.qp = clip(encoder_info.frame_info.qp, 0, MAX_QP);

      encoder_info.frame_info.num_ref = encoder_info.frame_info.frame_type == I_FRAME ? 0 : min(num_encoded_frames,params->max_num_ref);
      encoder_info.frame_info.interp_ref = 0;

      if (encoder_info.frame_info.num_ref > 0) {
        if (params->num_reorder_pics > 0) {
          if (params->dyadic_coding) {
            /* if we have a P frame then use the previous P frame as a reference */
            if ((num_encoded_frames-1) % sub_gop == 0) {
              if (num_encoded_frames==1)
                encoder_info.frame_info.ref_array[0] = 0;
              else
                encoder_info.frame_info.ref_array[0] = sub_gop-1;
              if (encoder_info.frame_info.num_ref>1 )
                encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1));

              for (r=2;r<encoder_info.frame_info.num_ref;r++){
                encoder_info.frame_info.ref_array[r] = r-2;
              }

            } else if (encoder_info.frame_info.num_ref>0){

              int display_phase =  (encoder_info.frame_info.frame_num-1) % sub_gop;
              int ref_offset=sub_gop>>(b_level+1);

              if (b_level >= min_interp_depth && params->interp_ref) {

                // Need to add another reference if we are at the beginning
                if (encoder_info.frame_info.num_ref==2) encoder_info.frame_info.num_ref++;

                encoder_info.frame_info.interp_ref = 1;

                encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1);
                encoder_info.frame_info.ref_array[2]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1);

                // Interpolate these two reference frames to make a new frame
                encoder_info.frame_info.ref_array[0]=-1;
                // Add this interpolated frame to the reference buffer and use it as the first reference
                yuv_frame_t* ref1=encoder_info.ref[encoder_info.frame_info.ref_array[1]];
                yuv_frame_t* ref2=encoder_info.ref[encoder_info.frame_info.ref_array[2]];
                interpolate_frames(encoder_info.interp_frames[0], ref1, ref2, 2, 1);
                pad_yuv_frame(encoder_info.interp_frames[0]);
                encoder_info.interp_frames[0]->frame_num = encoder_info.frame_info.frame_num;
                /* use most recent frames for the last ref(s)*/
                for (r=3;r<encoder_info.frame_info.num_ref;r++){
                  encoder_info.frame_info.ref_array[r] = r-3;
                }
              } else {
                encoder_info.frame_info.ref_array[0]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase-ref_offset+1]-1);
                encoder_info.frame_info.ref_array[1]=min(num_encoded_frames-1,coded_phase-dyadic_reorder_display_to_code[log2i(sub_gop)][display_phase+ref_offset+1]-1);

                /* use most recent frames for the last ref(s)*/
                for (r=2;r<encoder_info.frame_info.num_ref;r++){
                  encoder_info.frame_info.ref_array[r] = r-2;
                }

              }
            }
          } else {
            /* if we have a P frame then use the previous P frame as a reference */
            if ((num_encoded_frames-1) % sub_gop == 0) {
              if (num_encoded_frames==1)
                encoder_info.frame_info.ref_array[0] = 0;
              else
                encoder_info.frame_info.ref_array[0] = sub_gop-1;
              if (encoder_info.frame_info.num_ref>1 )
                encoder_info.frame_info.ref_array[1] = min(MAX_REF_FRAMES-1,min(num_encoded_frames-1,2*sub_gop-1));

              for (r=2;r<encoder_info.frame_info.num_ref;r++){
                encoder_info.frame_info.ref_array[r] = r-1;
              }

            } else {
              if (params->interp_ref && encoder_info.frame_info.num_ref>0) {

                // Need to add another reference if we are at the beginning
                if (encoder_info.frame_info.num_ref==2) encoder_info.frame_info.num_ref++;

                encoder_info.frame_info.interp_ref = 1;

                // Use the last encoded frame as the first true ref
                if (encoder_info.frame_info.num_ref>0) {
                  encoder_info.frame_info.ref_array[1] = 0;
                }
                /* Use the subsequent P frame as the 2nd ref */
                int phase = (num_encoded_frames + sub_gop - 2) % sub_gop;
                if (encoder_info.frame_info.num_ref>1) {
                  if (phase==0)
                    encoder_info.frame_info.ref_array[2] = min(sub_gop, num_encoded_frames-1);
                  else
                    encoder_info.frame_info.ref_array[2] = min(phase, num_encoded_frames-1);
                }
                // Interpolate these two reference frames to make a new frame
                encoder_info.frame_info.ref_array[0]=-1;
                // Add this interpolated frame to the reference buffer and use it as the first reference
                yuv_frame_t* ref1=encoder_info.ref[encoder_info.frame_info.ref_array[1]];
                yuv_frame_t* ref2=encoder_info.ref[encoder_info.frame_info.ref_array[2]];
                interpolate_frames(encoder_info.interp_frames[0], ref1, ref2, sub_gop-phase,phase!=0 ? 1 : sub_gop-phase-1);
                pad_yuv_frame(encoder_info.interp_frames[0]);
                encoder_info.interp_frames[0]->frame_num = encoder_info.frame_info.frame_num;

                /* Use the prior P frame as the 4th ref */
                if (encoder_info.frame_info.num_ref>2) {
                  encoder_info.frame_info.ref_array[3] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1);
                }
                /* use most recent frames for the last ref(s)*/
                for (r=4;r<encoder_info.frame_info.num_ref;r++){
                  encoder_info.frame_info.ref_array[r] = r-4+1;
                }


              } else {
                // Use the last encoded frame as the first ref
                if (encoder_info.frame_info.num_ref>0) {
                  encoder_info.frame_info.ref_array[0] = 0;
                }
                /* Use the subsequent P frame as the 2nd ref */
                int phase = (num_encoded_frames + sub_gop - 2) % sub_gop;
                if (encoder_info.frame_info.num_ref>1) {
                  if (phase==0)
                    encoder_info.frame_info.ref_array[1] = min(sub_gop, num_encoded_frames-1);
                  else
                    encoder_info.frame_info.ref_array[1] = min(phase, num_encoded_frames-1);
                }
                /* Use the prior P frame as the 3rd ref */
                if (encoder_info.frame_info.num_ref>2) {
                  encoder_info.frame_info.ref_array[2] = min(phase ? phase + sub_gop : 2*sub_gop, num_encoded_frames-1);
                }
                /* use most recent frames for the last ref(s)*/
                for (r=3;r<encoder_info.frame_info.num_ref;r++){
                  encoder_info.frame_info.ref_array[r] = r-3+1;
                }
              }
            }
          }
        } else {
          if (encoder_info.frame_info.num_ref>=1){
            /* If num_ref==1 always use most recent frame */
            encoder_info.frame_info.ref_array[0] = last_PorI_frame;
          }

          if (encoder_info.frame_info.num_ref==2){
            /* If num_ref==2 use most recent LQ frame and most recent HQ frame */
            r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
            encoder_info.frame_info.ref_array[1] = r1;
          }
          else if (encoder_info.frame_info.num_ref==3){
            r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
            r2 = r1==1 ? 2 : 1;
            encoder_info.frame_info.ref_array[1] = r1;
            encoder_info.frame_info.ref_array[2] = r2;
          }
          else if (encoder_info.frame_info.num_ref==4){
            r1 = ((num_encoded_frames + params->HQperiod - 2) % params->HQperiod) + 1;
            r2 = r1==1 ? 2 : 1;
            r3 = r2+1;
            if (r3==r1) r3 += 1;
            encoder_info.frame_info.ref_array[1] = r1;
            encoder_info.frame_info.ref_array[2] = r2;
            encoder_info.frame_info.ref_array[3] = r3;
          }
          else{
            for (r=1;r<encoder_info.frame_info.num_ref;r++){
              encoder_info.frame_info.ref_array[r] = r;
            }
          }
        }
      }