/*
 * stats.c
 * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
 *
 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
 *
 * mpeg2dec is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * mpeg2dec is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Modifications for this RISCOS port, Copyright (c) 2002 P.Everett
 * <peter@everett9981.freeserve.co.uk>
 */

#include "inttypes.h"
#include "mpeg2_inte.h"
#include "ka_log.h"

static void stats_picture (const uint8_t * buffer)
{
    static char * picture_coding_type_str [8] = {
  "Invalid picture type",
  "I-type",
  "P-type",
  "B-type",
  "D (very bad)",
  "Invalid","Invalid","Invalid"
    };

    int f_code[2][2] = {{0, 0}, {0, 0}};
    int picture_coding_type;
    int temporal_reference;
    int vbv_delay;

    temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6);
    picture_coding_type = (buffer [1] >> 3) & 7;
    vbv_delay = ((buffer[1] << 13) | (buffer[2] << 5) |
     (buffer[3] >> 3)) & 0xffff;

    /* forward_f_code and backward_f_code - used in mpeg1 only */
    if ((picture_coding_type == P_TYPE) || (picture_coding_type == B_TYPE))
    {
        f_code[0][1] = (buffer[3] >> 2) & 1;
        f_code[0][0] = (((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1;
    }
    if (picture_coding_type == B_TYPE)
    {
        f_code[1][1] = (buffer[4] >> 6) & 1;
        f_code[1][0] = ((buffer[4] >> 3) & 7) - 1;
    }

    ka_log(ka_log_info, " (picture) %s temporal_reference %d, vbv_delay %d"
       , picture_coding_type_str [picture_coding_type]
       , temporal_reference, vbv_delay);
    ka_log(ka_log_info, " (picture) forward f_code % d, forward full_pel % d"
       , f_code[0][0], f_code[0][1]);
    ka_log(ka_log_info, " (picture) backward f_code % d, backward full_pel % d"
       , f_code[1][0], f_code[1][1]);
}

static void stats_user_data (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (user_data)");
}

static void stats_sequence (const uint8_t * buffer)
{
    static char * aspect_ratio_information_str[8] = {
  "Invalid Aspect Ratio",
  "1:1",
  "4:3",
  "16:9",
  "2.21:1",
  "Invalid Aspect Ratio",
  "Invalid Aspect Ratio",
  "Invalid Aspect Ratio"
    };
    static char * frame_rate_str[16] = {
  "Invalid frame_rate_code",
  "23.976", "24", "25" , "29.97",
  "30" , "50", "59.94", "60" ,
  "Invalid frame_rate_code", "Invalid frame_rate_code",
  "Invalid frame_rate_code", "Invalid frame_rate_code",
  "Invalid frame_rate_code", "Invalid frame_rate_code",
  "Invalid frame_rate_code"
    };

    int horizontal_size;
    int vertical_size;
    int aspect_ratio_information;
    int frame_rate_code;
    int bit_rate_value;
    int vbv_buffer_size_value;
    int constrained_parameters_flag;
    int load_intra_quantizer_matrix;
    int load_non_intra_quantizer_matrix;

    vertical_size = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
    horizontal_size = vertical_size >> 12;
    vertical_size &= 0xfff;
    aspect_ratio_information = (buffer[3] >> 4) & 7;
    frame_rate_code = buffer[3] & 15;
    bit_rate_value = (buffer[4] << 10) | (buffer[5] << 2) | (buffer[6] >> 6);
    vbv_buffer_size_value = ((buffer[6] << 5) | (buffer[7] >> 3)) & 0x3ff;
    constrained_parameters_flag = buffer[7] & 4;
    load_intra_quantizer_matrix = buffer[7] & 2;
    if (load_intra_quantizer_matrix)
  buffer += 64;
    load_non_intra_quantizer_matrix = buffer[7] & 1;

    ka_log(ka_log_info, " (seq) %dx%d %s, %s fps, %5.0f kbps, VBV %d kB%s%s%s"
       , horizontal_size, vertical_size
       , aspect_ratio_information_str [aspect_ratio_information]
       , frame_rate_str [frame_rate_code]
       , bit_rate_value * 400.0 / 1000.0
       , 2 * vbv_buffer_size_value
       , constrained_parameters_flag ? " , CP":""
       , load_intra_quantizer_matrix ? " , Custom Intra Matrix":""
       , load_non_intra_quantizer_matrix ? " , Custom Non-Intra Matrix":"");
}

static void stats_sequence_error (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (sequence_error)");
}

static void stats_sequence_end (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (sequence_end)");
}

static void stats_group (const uint8_t * buffer)
{
    ka_log(ka_log_info, " (group)%s%s",
       (buffer[4] & 0x40) ? " closed_gop" : "",
       (buffer[4] & 0x20) ? " broken_link" : "");
}

static void stats_slice (uint8_t code, const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (slice %02x)", code);
}

static void stats_sequence_extension (const uint8_t * buffer)
{
    static char * chroma_format_str[4] = {
  "Invalid Chroma Format",
  "4:2:0 Chroma",
  "4:2:2 Chroma",
  "4:4:4 Chroma"
    };

    int progressive_sequence;
    int chroma_format;

    progressive_sequence = (buffer[1] >> 3) & 1;
    chroma_format = (buffer[1] >> 1) & 3;

    ka_log(ka_log_info, " (seq_ext) progressive_sequence %d, %s",
       progressive_sequence, chroma_format_str [chroma_format]);
}

static void stats_sequence_display_extension (const uint8_t * buffer)
{
    buffer = buffer;
    int width, height;

    if (buffer[0] & 1) {
        buffer += 3;
    }
    width = (buffer[1] << 6) | (buffer[2] >> 2);
    height =
        ((buffer[2]& 1 ) << 13) | (buffer[3] << 5) | (buffer[4] >> 3);
    ka_log(ka_log_info, " (sequence_display_extension) display %dx%d", width, height);
}

static void stats_quant_matrix_extension (mpeg2dec_t* mpeg2dec, const uint8_t * buffer)
{
    const mpeg2_sequence_t* sequence = &mpeg2_info(mpeg2dec)->sequence;
    static char * matrix_str[4] = {
    "Custom Intra Matrix",
    "Custom Non-Intra Matrix",
    "Chrominance Intra Matrix",
    "Chrominance Non-Intra Matrix"
    };
    int map = 0;

    if (buffer[0] & 8)
    {
        map |= 1;
        buffer += 64;
    }
    if (buffer[0] & 4)
    {
        map |= 2;
        buffer += 64;
    }
    if (sequence->chroma_type != SEQ_CHROMA_420)
    {
        if (buffer[0] & 2)
        {
            map |= 4;
            buffer += 64;
        }
        if (buffer[0] & 1)
            map |= 8;
    }

    if (map & 3)
    {
        ka_logs(ka_log_info, " (quant_ext) ");
        if (map & 1)
            ka_logn(matrix_str[0]);
        if ((map & 3) == 3)
            ka_logn(", ");
        if (map & 2)
           ka_logn(matrix_str[1]);
        ka_logn("\n");
    }
    if (map & 0xc)
    {
        ka_logs(ka_log_info, " (quant_ext) ");
        if (map & 4)
            ka_logn(matrix_str[2]);
        if ((map & 0xc) == 0xc)
            ka_logn(", ");
        if (map & 8)
           ka_logn(matrix_str[3]);
        ka_logn("\n");
    }
   if (!map)
        ka_log(ka_log_info, " (quant_ext)");
}

static void stats_copyright_extension (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (copyright_extension)");
}


static void stats_sequence_scalable_extension (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (sequence_scalable_extension)");
}

static void stats_picture_display_extension (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (picture_display_extension)");
}

static void stats_picture_spatial_scalable_extension (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (picture_spatial_scalable_extension)");
}

static void stats_picture_temporal_scalable_extension (const uint8_t * buffer)
{
    buffer = buffer;
    ka_log(ka_log_info, " (picture_temporal_scalable_extension)");
}

static void stats_picture_coding_extension (const uint8_t * buffer)
{
    static char * picture_structure_str[4] = {
  "Invalid Picture Structure",
  "Top field",
  "Bottom field",
  "Frame Picture"
    };

    int f_code[2][2];
    int intra_dc_precision;
    int picture_structure;
    int top_field_first;
    int frame_pred_frame_dct;
    int concealment_motion_vectors;
    int q_scale_type;
    int intra_vlc_format;
    int alternate_scan;
    int repeat_first_field;
    int progressive_frame;

    f_code[0][0] = buffer[0] & 15;
    f_code[0][1] = buffer[1] >> 4;
    f_code[1][0] = buffer[1] & 15;
    f_code[1][1] = buffer[2] >> 4;
    intra_dc_precision = (buffer[2] >> 2) & 3;
    picture_structure = buffer[2] & 3;
    top_field_first = buffer[3] >> 7;
    frame_pred_frame_dct = (buffer[3] >> 6) & 1;
    concealment_motion_vectors = (buffer[3] >> 5) & 1;
    q_scale_type = (buffer[3] >> 4) & 1;
    intra_vlc_format = (buffer[3] >> 3) & 1;
    alternate_scan = (buffer[3] >> 2) & 1;
    repeat_first_field = (buffer[3] >> 1) & 1;
    progressive_frame = buffer[4] >> 7;

    ka_log(ka_log_info, " (pic_ext) %s", picture_structure_str [picture_structure]);
    ka_log(ka_log_info, " (pic_ext) forward horizontal f_code % d, forward vertical f_code % d"
       , f_code[0][0], f_code[0][1]);
    ka_log(ka_log_info, " (pic_ext) backward horizontal f_code % d, backward vertical f_code % d"
       , f_code[1][0], f_code[1][1]);
    ka_log(ka_log_info, " (pic_ext) intra_dc_precision %d, top_field_first %d, frame_pred_frame_dct %d"
       , intra_dc_precision, top_field_first, frame_pred_frame_dct);
    ka_log(ka_log_info, " (pic_ext) concealment_motion_vectors %d, q_scale_type %d, intra_vlc_format %d"
       , concealment_motion_vectors, q_scale_type, intra_vlc_format);
    ka_log(ka_log_info, " (pic_ext) alternate_scan %d, repeat_first_field %d, progressive_frame %d"
       , alternate_scan, repeat_first_field, progressive_frame);
}

void stats_header (mpeg2dec_t* mpeg2dec, uint8_t code, const uint8_t * buffer)
{
    switch (code) {
    case 0x00:
  stats_picture (buffer);
  break;
    case 0xb2:
  stats_user_data (buffer);
  break;
    case 0xb3:
  stats_sequence (buffer);
  break;
    case 0xb4:
  stats_sequence_error (buffer);
  break;
    case 0xb5:
  switch (buffer[0] >> 4) {
  case 1:
      stats_sequence_extension (buffer);
      break;
  case 2:
      stats_sequence_display_extension (buffer);
      break;
  case 3:
      stats_quant_matrix_extension (mpeg2dec, buffer);
      break;
  case 4:
      stats_copyright_extension (buffer);
      break;
  case 5:
      stats_sequence_scalable_extension (buffer);
      break;
  case 7:
      stats_picture_display_extension (buffer);
      break;
  case 8:
      stats_picture_coding_extension (buffer);
      break;
  case 9:
      stats_picture_spatial_scalable_extension (buffer);
      break;
  case 10:
      stats_picture_temporal_scalable_extension (buffer);
      break;
  default:
      ka_log(ka_log_info, " (unknown extension %#x)", buffer[0] >> 4);
  }
  break;
    case 0xb7:
  stats_sequence_end (buffer);
  break;
    case 0xb8:
  stats_group (buffer);
  break;
    default:
  if (code < 0xb0)
      stats_slice (code, buffer);
  else
      ka_log(ka_log_info, " (unknown start code %#02x)", code);
    }
}
