unsigned int bitCount = 0;

int showmb_flag = 0;
int showEachFlag = 0;

typedef struct {
  int frametype;
  unsigned int totsize;
  unsigned int number;
  unsigned int i_mbsize;
  unsigned int p_mbsize;
  unsigned int b_mbsize;
  unsigned int bi_mbsize;
  unsigned int i_mbnum;
  unsigned int p_mbnum;
  unsigned int b_mbnum;
  unsigned int bi_mbnum;
  unsigned int i_mbcbp[64];
  unsigned int p_mbcbp[64];
  unsigned int b_mbcbp[64];
  unsigned int bi_mbcbp[64];
  unsigned int i_mbcoeff[64];
  unsigned int p_mbcoeff[64];
  unsigned int b_mbcoeff[64];
  unsigned int bi_mbcoeff[64];
  double tottime;
} Statval;

Statval stat_a[4];
unsigned int pictureSizeCount;
unsigned int mbSizeCount;
unsigned int *mbCBPPtr, *mbCoeffPtr, *mbSizePtr;
unsigned int cacheHit[8][8], cacheMiss[8][8];



static void init_stat_struct(Statval *astat)
{
  int j;

  astat->frametype = 0;
  astat->totsize = 0;
  astat->number = 0;
  astat->i_mbsize = 0;
  astat->p_mbsize = 0;
  astat->b_mbsize = 0;
  astat->bi_mbsize = 0;
  astat->i_mbnum = 0;
  astat->p_mbnum = 0;
  astat->b_mbnum = 0;
  astat->bi_mbnum = 0;

  for (j = 0; j < 64; j++) {

    astat->i_mbcbp[j] = 0;
    astat->p_mbcbp[j] = 0;
    astat->b_mbcbp[j] = 0;
    astat->bi_mbcbp[j] = 0;
    astat->i_mbcoeff[j] = 0;
    astat->p_mbcoeff[j] = 0;
    astat->b_mbcoeff[j] = 0;
    astat->bi_mbcoeff[j] = 0;
  }
  astat->tottime = 0.0;
}

void init_stats(void)
{
  int i, j;

  for (i = 0; i < 4; i++) {
    init_stat_struct(&(stat_a[i]));
    stat_a[i].frametype = i;
  }

  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      cacheHit[i][j] = 0;
      cacheMiss[i][j] = 0;
    }
  }

  bitCount = 0;
}

static void PrintOneStat(void)
{
  int i;

  printf("\n");
  switch (stat_a[0].frametype) {
  case I_TYPE:
    printf("I FRAME\n");
    break;
  case P_TYPE:
    printf("P FRAME\n");
    break;
  case B_TYPE:
    printf("B FRAME\n");
    break;
  }

  printf("Size: %d bytes + %d bits\n", stat_a[0].totsize / 8, stat_a[0].totsize % 8);
  if (stat_a[0].i_mbnum > 0) {
    printf("\tI Macro Block Stats:\n");
    printf("\t%d I Macroblocks\n", stat_a[0].i_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].i_mbsize / (8 * stat_a[0].i_mbnum),
	   (stat_a[0].i_mbsize * stat_a[0].i_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcbp[i],
	     stat_a[0].i_mbcbp[i + 1], stat_a[0].i_mbcbp[i + 2], stat_a[0].i_mbcbp[i + 3],
	     stat_a[0].i_mbcbp[i + 4], stat_a[0].i_mbcbp[i + 5], stat_a[0].i_mbcbp[i + 6],
	     stat_a[0].i_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].i_mbcoeff[i],
	     stat_a[0].i_mbcoeff[i + 1], stat_a[0].i_mbcoeff[i + 2],
	     stat_a[0].i_mbcoeff[i + 3], stat_a[0].i_mbcoeff[i + 4],
	     stat_a[0].i_mbcoeff[i + 5], stat_a[0].i_mbcoeff[i + 6],
	     stat_a[0].i_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].p_mbnum > 0) {
    printf("\tP Macro Block Stats:\n");
    printf("\t%d P Macroblocks\n", stat_a[0].p_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].p_mbsize / (8 * stat_a[0].p_mbnum),
	   (stat_a[0].p_mbsize / stat_a[0].p_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcbp[i],
	     stat_a[0].p_mbcbp[i + 1], stat_a[0].p_mbcbp[i + 2], stat_a[0].p_mbcbp[i + 3],
	     stat_a[0].p_mbcbp[i + 4], stat_a[0].p_mbcbp[i + 5], stat_a[0].p_mbcbp[i + 6],
	     stat_a[0].p_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].p_mbcoeff[i],
	     stat_a[0].p_mbcoeff[i + 1], stat_a[0].p_mbcoeff[i + 2],
	     stat_a[0].p_mbcoeff[i + 3], stat_a[0].p_mbcoeff[i + 4],
	     stat_a[0].p_mbcoeff[i + 5], stat_a[0].p_mbcoeff[i + 6],
	     stat_a[0].p_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].b_mbnum > 0) {
    printf("\tB Macro Block Stats:\n");
    printf("\t%d B Macroblocks\n", stat_a[0].b_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].b_mbsize / (8 * stat_a[0].b_mbnum),
	   (stat_a[0].b_mbsize / stat_a[0].b_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcbp[i],
	     stat_a[0].b_mbcbp[i + 1], stat_a[0].b_mbcbp[i + 2], stat_a[0].b_mbcbp[i + 3],
	     stat_a[0].b_mbcbp[i + 4], stat_a[0].b_mbcbp[i + 5], stat_a[0].b_mbcbp[i + 6],
	     stat_a[0].b_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].b_mbcoeff[i],
	     stat_a[0].b_mbcoeff[i + 1], stat_a[0].b_mbcoeff[i + 2],
	     stat_a[0].b_mbcoeff[i + 3], stat_a[0].b_mbcoeff[i + 4],
	     stat_a[0].b_mbcoeff[i + 5], stat_a[0].b_mbcoeff[i + 6],
	     stat_a[0].b_mbcoeff[i + 7]);
    }
  }
  if (stat_a[0].bi_mbnum > 0) {
    printf("\tBi Macro Block Stats:\n");
    printf("\t%d Bi Macroblocks\n", stat_a[0].bi_mbnum);
    printf("\tAvg. Size: %d bytes + %d bits\n",
	   stat_a[0].bi_mbsize / (8 * stat_a[0].bi_mbnum),
	   (stat_a[0].bi_mbsize * stat_a[0].bi_mbnum) % 8);
    printf("\t\tCoded Block Pattern Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcbp[i],
	     stat_a[0].bi_mbcbp[i + 1], stat_a[0].bi_mbcbp[i + 2], stat_a[0].bi_mbcbp[i + 3],
	     stat_a[0].bi_mbcbp[i + 4], stat_a[0].bi_mbcbp[i + 5], stat_a[0].bi_mbcbp[i + 6],
	     stat_a[0].bi_mbcbp[i + 7]);
    }
    printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
    for (i = 0; i < 64; i += 8) {
      printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[0].bi_mbcoeff[i],
	     stat_a[0].bi_mbcoeff[i + 1], stat_a[0].bi_mbcoeff[i + 2],
	     stat_a[0].bi_mbcoeff[i + 3], stat_a[0].bi_mbcoeff[i + 4],
	     stat_a[0].bi_mbcoeff[i + 5], stat_a[0].bi_mbcoeff[i + 6],
	     stat_a[0].bi_mbcoeff[i + 7]);
    }
  }
  printf("\nTime to Decode: %g secs.\n", stat_a[0].tottime);
  printf("****************\n");
}

void PrintAllStats(void)
{
  int i, j;
  unsigned int supertot, supernum;
  double supertime;

  printf("\n");
  printf("General Info: \n");
  printf("Width: %d\nHeight: %d\n", curVidStream->mb_width * 16, curVidStream->mb_height * 16);

  for (i = 1; i < 4; i++) {

    if (stat_a[i].number == 0)
      continue;

    switch (i) {
    case 1:
      printf("I FRAMES\n");
      break;
    case 2:
      printf("P FRAMES\n");
      break;
    case 3:
      printf("B FRAMES\n");
      break;
    }

    printf("Number: %d\n", stat_a[i].number);
    printf("Avg. Size: %d bytes + %d bits\n",
	   stat_a[i].totsize / (8 * stat_a[i].number), (stat_a[i].totsize / stat_a[i].number) % 8);
    if (stat_a[i].i_mbnum > 0) {
      printf("\tI Macro Block Stats:\n");
      printf("\t%d I Macroblocks\n", stat_a[i].i_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].i_mbsize / (8 * stat_a[i].i_mbnum),
	     (stat_a[i].i_mbsize / stat_a[i].i_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcbp[j],
	       stat_a[i].i_mbcbp[j + 1], stat_a[i].i_mbcbp[j + 2], stat_a[i].i_mbcbp[j + 3],
	       stat_a[i].i_mbcbp[j + 4], stat_a[i].i_mbcbp[j + 5], stat_a[i].i_mbcbp[j + 6],
	       stat_a[i].i_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].i_mbcoeff[j],
	       stat_a[i].i_mbcoeff[j + 1], stat_a[i].i_mbcoeff[j + 2],
	       stat_a[i].i_mbcoeff[j + 3], stat_a[i].i_mbcoeff[j + 4],
	       stat_a[i].i_mbcoeff[j + 5], stat_a[i].i_mbcoeff[j + 6],
	       stat_a[i].i_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].p_mbnum > 0) {
      printf("\tP Macro Block Stats:\n");
      printf("\t%d P Macroblocks\n", stat_a[i].p_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].p_mbsize / (8 * stat_a[i].p_mbnum),
	     (stat_a[i].p_mbsize / stat_a[i].p_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcbp[j],
	       stat_a[i].p_mbcbp[j + 1], stat_a[i].p_mbcbp[j + 2], stat_a[i].p_mbcbp[j + 3],
	       stat_a[i].p_mbcbp[j + 4], stat_a[i].p_mbcbp[j + 5], stat_a[i].p_mbcbp[j + 6],
	       stat_a[i].p_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].p_mbcoeff[j],
	       stat_a[i].p_mbcoeff[j + 1], stat_a[i].p_mbcoeff[j + 2],
	       stat_a[i].p_mbcoeff[j + 3], stat_a[i].p_mbcoeff[j + 4],
	       stat_a[i].p_mbcoeff[j + 5], stat_a[i].p_mbcoeff[j + 6],
	       stat_a[i].p_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].b_mbnum > 0) {
      printf("\tB Macro Block Stats:\n");
      printf("\t%d B Macroblocks\n", stat_a[i].b_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].b_mbsize / (8 * stat_a[i].b_mbnum),
	     (stat_a[i].b_mbsize * stat_a[i].b_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcbp[j],
	       stat_a[i].b_mbcbp[j + 1], stat_a[i].b_mbcbp[j + 2], stat_a[i].b_mbcbp[j + 3],
	       stat_a[i].b_mbcbp[j + 4], stat_a[i].b_mbcbp[j + 5], stat_a[i].b_mbcbp[j + 6],
	       stat_a[i].b_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].b_mbcoeff[j],
	       stat_a[i].b_mbcoeff[j + 1], stat_a[i].b_mbcoeff[j + 2],
	       stat_a[i].b_mbcoeff[j + 3], stat_a[i].b_mbcoeff[j + 4],
	       stat_a[i].b_mbcoeff[j + 5], stat_a[i].b_mbcoeff[j + 6],
	       stat_a[i].b_mbcoeff[j + 7]);
      }
    }
    if (stat_a[i].bi_mbnum > 0) {
      printf("\tBi Macro Block Stats:\n");
      printf("\t%d Bi Macroblocks\n", stat_a[i].bi_mbnum);
      printf("\tAvg. Size: %d bytes + %d bits\n",
	     stat_a[i].bi_mbsize / (8 * stat_a[i].bi_mbnum),
	     (stat_a[i].bi_mbsize * stat_a[i].bi_mbnum) % 8);
      printf("\t\tCoded Block Pattern Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcbp[j],
	       stat_a[i].bi_mbcbp[j + 1], stat_a[i].bi_mbcbp[j + 2], stat_a[i].bi_mbcbp[j + 3],
	       stat_a[i].bi_mbcbp[j + 4], stat_a[i].bi_mbcbp[j + 5], stat_a[i].bi_mbcbp[j + 6],
	       stat_a[i].bi_mbcbp[j + 7]);
      }
      printf("\n\t\tNumber of Coefficients/Block Histogram:\n");
      for (j = 0; j < 64; j += 8) {
	printf("\t%.6d %.6d %.6d %.6d %.6d %.6d %.6d %.6d\n", stat_a[i].bi_mbcoeff[j],
	       stat_a[i].bi_mbcoeff[j + 1], stat_a[i].bi_mbcoeff[j + 2],
	       stat_a[i].bi_mbcoeff[j + 3], stat_a[i].bi_mbcoeff[j + 4],
	       stat_a[i].bi_mbcoeff[j + 5], stat_a[i].bi_mbcoeff[j + 6],
	       stat_a[i].bi_mbcoeff[j + 7]);
      }
    }
    printf("\nAvg. Time to Decode: %f secs.\n",
	   (stat_a[i].tottime / ((double) stat_a[i].number)));
    printf("\n");
    printf("*************************\n\n");
  }

  supertot = stat_a[1].totsize + stat_a[2].totsize + stat_a[3].totsize;
  supernum = stat_a[1].number + stat_a[2].number + stat_a[3].number;
  supertime = stat_a[1].tottime + stat_a[2].tottime + stat_a[3].tottime;

  printf("Total Number of Frames: %d\n", supernum);
  printf("Avg Frame Size: %d bytes %d bits\n",
	 supertot / (8 * supernum), (supertot / supernum) % 8);
  printf("Total Time Decoding: %g secs.\n", supertime);
  printf("Avg Decoding Time/Frame: %g secs.\n", supertime / ((double) supernum));
  printf("Avg Decoding Frames/Sec: %g secs.\n", ((double) supernum) / supertime);
  printf("\n");

  printf("Cache Hits/Miss\n");
  for (i = 0; i < 8; i++) {
    printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n",
	   cacheHit[i][0], cacheMiss[i][0], cacheHit[i][1], cacheMiss[i][1],
	   cacheHit[i][2], cacheMiss[i][2], cacheHit[i][3], cacheMiss[i][3]);
    printf("%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\t%.6d/%.6d\n",
	   cacheHit[i][4], cacheMiss[i][4], cacheHit[i][5], cacheMiss[i][5],
	   cacheHit[i][6], cacheMiss[i][6], cacheHit[i][7], cacheMiss[i][7]);
  }
}

static void CollectStats(void)
{
  int i, j;

  i = stat_a[0].frametype;

  stat_a[i].totsize += stat_a[0].totsize;
  stat_a[i].number += stat_a[0].number;
  stat_a[i].i_mbsize += stat_a[0].i_mbsize;
  stat_a[i].p_mbsize += stat_a[0].p_mbsize;
  stat_a[i].b_mbsize += stat_a[0].b_mbsize;
  stat_a[i].bi_mbsize += stat_a[0].bi_mbsize;
  stat_a[i].i_mbnum += stat_a[0].i_mbnum;
  stat_a[i].p_mbnum += stat_a[0].p_mbnum;
  stat_a[i].b_mbnum += stat_a[0].b_mbnum;
  stat_a[i].bi_mbnum += stat_a[0].bi_mbnum;

  for (j = 0; j < 64; j++) {

    stat_a[i].i_mbcbp[j] += stat_a[0].i_mbcbp[j];
    stat_a[i].p_mbcbp[j] += stat_a[0].p_mbcbp[j];
    stat_a[i].b_mbcbp[j] += stat_a[0].b_mbcbp[j];
    stat_a[i].bi_mbcbp[j] += stat_a[0].bi_mbcbp[j];
    stat_a[i].i_mbcoeff[j] += stat_a[0].i_mbcoeff[j];
    stat_a[i].p_mbcoeff[j] += stat_a[0].p_mbcoeff[j];
    stat_a[i].b_mbcoeff[j] += stat_a[0].b_mbcoeff[j];
    stat_a[i].bi_mbcoeff[j] += stat_a[0].bi_mbcoeff[j];
  }

  stat_a[i].tottime += stat_a[0].tottime;

  init_stat_struct(&(stat_a[0]));
}

static unsigned int bitCountRead(void)
{
  return bitCount;
}

static void StartTime(void)
{
  stat_a[0].tottime = ReadSysClock();
}

static void EndTime(void)
{
  stat_a[0].tottime = ReadSysClock() - stat_a[0].tottime;
}
