/*
 * header.c
 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
 * Copyright (C) 2003      Regis Duchesne <hpreg@zoy.org>
 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
 *
 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
 * See http://libmpeg2.sourceforge.net/ for updates.
 *
 * 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 <string.h>
#include "inttypes.h"
#include "mpeg2_inte.h"
#include "config.h"
#include "ka_log.h"

#define SEQ_EXT          0x002
#define SEQ_DISPLAY_EXT  0x004
#define QUANT_MATRIX_EXT 0x008
#define COPYRIGHT_EXT    0x010
#define SEQ_SCALABLE_EXT 0x020
#define PIC_DISPLAY_EXT  0x080
#define PIC_CODING_EXT   0x100
#define PIC_SPATIAL_EXT  0x200
#define PIC_TEMPORAL_EXT 0x400

/* default intra quant matrix, in zig-zag order */
static const uint8_t default_intra_quantizer_matrix[64] = {
    8,
    16, 16,
    19, 16, 19,
    22, 22, 22, 22,
    22, 22, 26, 24, 26,
    27, 27, 27, 26, 26, 26,
    26, 27, 27, 27, 29, 29, 29,
    34, 34, 34, 29, 29, 29, 27, 27,
    29, 29, 32, 32, 34, 34, 37,
    38, 37, 35, 35, 34, 35,
    38, 38, 40, 40, 40,
    48, 48, 46, 46,
    56, 56, 58,
    69, 69,
    83
};

static const uint8_t mpeg2_scan_norm[64] = {
    /* Zig-Zag scan pattern */
     0,  1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
    12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};

static const uint8_t mpeg2_scan_alt[64] = {
    /* Alternate scan pattern */
     0,  8, 16, 24,  1,  9,  2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
    41, 33, 26, 18,  3, 11,  4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
    51, 59, 20, 28,  5, 13,  6, 14, 21, 29, 36, 44, 52, 60, 37, 45,
    53, 61, 22, 30,  7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63
};

int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
  /* Video frame rate table in units of 1/90KHz. */
  static const unsigned int frame_period[16] = {
    0,  3754,  3750,  3600,  3003,  3000,  1800,  1502, 1500,
    /*   -    23.976 24     25     29.97  30     50     59.94 60    fps */
    /* unofficial: xing 15 fps */
    6000,
    /* unofficial: libmpeg3 "Unofficial economy rates" 5/10/12/15 fps */
    18000, 9000, 7500, 6000, 0, 0
  };
  int i;

  if ((buffer[6] & 0x20) != 0x20) /* missing marker_bit */
    return CHUNK_CORRUPTED;

  i = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
  sequence->display_width = sequence->picture_width = i >> 12;
  sequence->display_height = sequence->picture_height = i & 0xfff;
  if (!sequence->display_width
  ||  !sequence->display_height)
    return CHUNK_CORRUPTED;
  sequence->width = (sequence->picture_width + 15) & ~15;
  sequence->height = (sequence->picture_height + 15) & ~15;
  sequence->chroma_type = SEQ_CHROMA_420;

  sequence->flags = SEQ_FLAG_PROGRESSIVE_SEQUENCE;

  sequence->pixel_width = buffer[3] >> 4; /* aspect ratio */
  sequence->frame_period = frame_period[buffer[3] & 15];
  if (!sequence->frame_period) sequence->frame_period = 3600;

  sequence->byte_rate = (buffer[4]<<10) | (buffer[5]<<2) | (buffer[6]>>6);

  sequence->vbv_buffer_size = ((buffer[6]<<16)|(buffer[7]<<8))&0x1ff800;

  if (buffer[7] & 4)
    sequence->flags |= SEQ_FLAG_CONSTRAINED_PARAMETERS;

  mpeg2dec->copy_matrix = 0x33; /* intra & non-intra, copies to chroma */
  if (buffer[7] & 2)
  {
    for (i = 0; i < 64; i++)
      mpeg2dec->lumi_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
        (buffer[i+7] << 7) | (buffer[i+8] >> 1);
      buffer += 64;
  }
  else
  {
    for (i = 0; i < 64; i++)
      mpeg2dec->lumi_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
        default_intra_quantizer_matrix [i];
  }

  if (buffer[7] & 1)
  {
    for (i = 0; i < 64; i++)
      mpeg2dec->lumi_non_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
         buffer[i+8];
  }
  else
  {
    for (i = 0; i < 64; i++)
      mpeg2dec->lumi_non_intra_quantizer_matrix[i] = 16;
  }

  sequence->profile_level_id = 0x80;
  sequence->colour_primaries = 0;
  sequence->transfer_characteristics = 0;
  sequence->matrix_coefficients = 0;

  mpeg2dec->ext_state = SEQ_EXT;
  mpeg2dec->display_offset_x = mpeg2dec->display_offset_y = 0;

  return CHUNK_VALID;
}

static int sequence_ext(mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
  uint32_t flags;

  /* check chroma format, size extensions, marker bit */
  if (!(buffer[3] & 1))
    return CHUNK_CORRUPTED;

  sequence->profile_level_id = ((buffer[0] << 4) | (buffer[1] >> 4)) & 0xff;

  sequence->display_width = sequence->picture_width +=
    ((buffer[1] << 13) | (buffer[2] << 5)) & 0x3000;
  sequence->display_height = sequence->picture_height +=
    (buffer[2] << 7) & 0x3000;
  sequence->width = (sequence->picture_width + 15) & ~15;
  sequence->height = (sequence->picture_height + 15) & ~15;
  flags = sequence->flags | SEQ_FLAG_MPEG2;
  if (!(buffer[1] & 8))
  {
    flags &= ~SEQ_FLAG_PROGRESSIVE_SEQUENCE;
    sequence->height = (sequence->height + 31) & ~31;
  }

  sequence->chroma_type = (buffer[1] >> 1) & 3;
  if (!sequence->chroma_type)
  {
    if (config.debug & cfg_printwarnings)
      ka_log(ka_log_error | ka_log_video, "Invalid Chroma Type");
    return CHUNK_CORRUPTED;
  }

  if (buffer[5] & 0x80)
    flags |= SEQ_FLAG_LOW_DELAY;
  sequence->flags = flags;

  sequence->byte_rate += ((buffer[2]<<25) | (buffer[3]<<17)) & 0x3ffc0000;

  sequence->vbv_buffer_size |= buffer[4] << 21;

  sequence->frame_period =
  sequence->frame_period * ((buffer[5]&31)+1) / (((buffer[5]>>5)&3)+1);

  mpeg2dec->ext_state = SEQ_DISPLAY_EXT | COPYRIGHT_EXT | SEQ_SCALABLE_EXT;

  return CHUNK_VALID;
}

static int sequence_display_ext (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);

  sequence->flags = ((sequence->flags & ~SEQ_MASK_VIDEO_FORMAT) |
    ((buffer[0]<<4) & SEQ_MASK_VIDEO_FORMAT));
  if (buffer[0] & 1)
  {
    sequence->flags |= SEQ_FLAG_COLOUR_DESCRIPTION;
    sequence->colour_primaries = buffer[1];
    sequence->transfer_characteristics = buffer[2];
    sequence->matrix_coefficients = buffer[3];
    buffer += 3;
  }

  if (!(buffer[2] & 2))    /* missing marker_bit */
    return CHUNK_CORRUPTED;

  if( (buffer[1] << 6) | (buffer[2] >> 2) )
    sequence->display_width = (buffer[1] << 6) | (buffer[2] >> 2);
  if( ((buffer[2]& 1 ) << 13) | (buffer[3] << 5) | (buffer[4] >> 3) )
    sequence->display_height =
      ((buffer[2]& 1 ) << 13) | (buffer[3] << 5) | (buffer[4] >> 3);

  return CHUNK_VALID;
}

static int sequence_scalable_ext(mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2dec = mpeg2dec; // unused
  buffer = buffer;     // unused
  return CHUNK_VALID;
}

static inline void reduce(int* pwidth, int* pheight)
{
  int width = *pwidth;
  int height = *pheight;

  while (width)
  {    /* find greatest common divisor */
    int tmp = width;
    width = height % tmp;
    height = tmp;
  }

  *pwidth /= height;
  *pheight /= height;
}

static inline void finalize_sequence (mpeg2_sequence_t * sequence)
{
  int width;
  int height;

  if (sequence->flags & SEQ_FLAG_MPEG2)
  {
    int cwidth, cheight;

    switch (sequence->pixel_width)
    {
      case 1:        /* square pixels */
        sequence->pixel_width = sequence->pixel_height = 1;    return;
      case 2:        /* 4:3 aspect ratio */
        cwidth = 4; cheight = 3;    break;
      case 3:        /* 16:9 aspect ratio */
        cwidth = 16; cheight = 9;    break;
      case 4:        /* 2.21:1 aspect ratio */
        cwidth = 221; cheight = 100;    break;
      default:    /* illegal */
        sequence->pixel_width = sequence->pixel_height = 0;    return;
    }

    // Specs unclear, should say:
    //  show all: SAR = DAR * picture h/w
    //  pan/scan: SAR = DAR * display h/w
//    width = cwidth * sequence->display_height;
//    height = cheight * sequence->display_width;
//    reduce(&width, &height);
    width = cwidth * sequence->picture_height;
    height = cheight * sequence->picture_width;
    reduce(&width, &height);
  }
  else
  {
    if (sequence->byte_rate == 0x3ffff)
      sequence->byte_rate = 0;        /* mpeg-1 VBR */

    switch (sequence->pixel_width)
    {
      case 0:
      case 15:    /* illegal */
        sequence->pixel_width = sequence->pixel_height = 0;        return;
      case 1:    /* square pixels */
        sequence->pixel_width = sequence->pixel_height = 1;        return;
      case 3:    /* 720x576 16:9 */
        sequence->pixel_width = 64;    sequence->pixel_height = 45;    return;
      case 6:    /* 720x480 16:9 */
        sequence->pixel_width = 32;    sequence->pixel_height = 27;    return;
      case 8: /* BT.601 625 lines 4:3 */
        sequence->pixel_width = 59;    sequence->pixel_height = 54;    return;
      case 12: /* BT.601 525 lines 4:3 */
        sequence->pixel_width = 10;    sequence->pixel_height = 11;    return;
      default:
        height = 88 * sequence->pixel_width + 1171;
        width = 2000;
    }

    reduce(&width, &height);
  }

  sequence->pixel_width = width;
  sequence->pixel_height = height;
}

void mpeg2_header_matrix_finalize (mpeg2dec_t * mpeg2dec)
{
  mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);

  if (mpeg2dec->copy_matrix & 0x01)
    memcpy(decoder->lumi_intra_quantizer_matrix
        , mpeg2dec->lumi_intra_quantizer_matrix, 64);
  if (mpeg2dec->copy_matrix & 0x02)
    memcpy(decoder->lumi_non_intra_quantizer_matrix
        , mpeg2dec->lumi_non_intra_quantizer_matrix, 64);

  if (mpeg2dec->copy_matrix & 0x04)
    memcpy(decoder->chroma_intra_quantizer_matrix
        , mpeg2dec->chroma_intra_quantizer_matrix, 64);
  else if (mpeg2dec->copy_matrix & 0x10)
    memcpy(decoder->chroma_intra_quantizer_matrix
        , mpeg2dec->lumi_intra_quantizer_matrix, 64);

  if (mpeg2dec->copy_matrix & 0x08)
    memcpy(decoder->chroma_non_intra_quantizer_matrix
        , mpeg2dec->chroma_non_intra_quantizer_matrix, 64);
  else if (mpeg2dec->copy_matrix & 0x20)
    memcpy(decoder->chroma_non_intra_quantizer_matrix
        , mpeg2dec->lumi_non_intra_quantizer_matrix, 64);
}

void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec)
{
  mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
  mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);

  finalize_sequence (sequence);

  mpeg2_header_matrix_finalize (mpeg2dec);
  decoder->mpeg1 = !(sequence->flags & SEQ_FLAG_MPEG2);
  decoder->lumi_width = sequence->width;
  decoder->lumi_height = sequence->height;
  decoder->vertical_position_extension = (sequence->picture_height > 2800);

  decoder->chroma_type = sequence->chroma_type;
  switch(decoder->chroma_type)
  {
    case SEQ_CHROMA_444:
    {
      decoder->blockmask = 0xfff;
      decoder->chroma_wshift = 0;
      decoder->chroma_hshift = 0;
    }
    break;
    case SEQ_CHROMA_422:
    {
      decoder->blockmask = 0xff0;
      decoder->chroma_wshift = 1;
      decoder->chroma_hshift = 0;
    }
    break;
    default:
    {
      decoder->blockmask = 0xfc0;
      decoder->chroma_wshift = 1;
      decoder->chroma_hshift = 1;
    }
  }

  sequence->chroma_wshift = decoder->chroma_wshift;
  sequence->chroma_hshift = decoder->chroma_hshift;
  sequence->chroma_width = sequence->width >> decoder->chroma_wshift;
  sequence->chroma_height = sequence->height >> decoder->chroma_hshift;

  /*
   * According to 6.1.1.6, repeat sequence headers should be
   * identical to the original. However some encoders do not
   * respect that and change various fields (including bitrate
   * and aspect ratio) in the repeat sequence headers. So
   * we'll ignore that in the comparison and still consider these as
   * repeat sequence headers.
   */
  mpeg2dec->sequence.byte_rate = sequence->byte_rate;
  mpeg2dec->sequence = *sequence;
}

/*

int mpeg2_header_gop (mpeg2dec_t * mpeg2dec)
{
  uint8_t * buffer = mpeg2dec->chunk_start;
  mpeg2_gop_t * gop = &(mpeg2dec->new_gop);

  if (! (buffer[1] & 8))
    return 1;
  gop->hours = (buffer[0] >> 2) & 31;
  gop->minutes = ((buffer[0] << 4) | (buffer[1] >> 4)) & 63;
  gop->seconds = ((buffer[1] << 3) | (buffer[2] >> 5)) & 63;
  gop->pictures = ((buffer[2] << 1) | (buffer[3] >> 7)) & 63;
  gop->flags = (buffer[0] >> 7) | ((buffer[3] >> 4) & 6);
  mpeg2dec->state = STATE_GOP;
  return 0;
}

void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec)
{
  mpeg2dec->gop = mpeg2dec->new_gop;
  mpeg2_reset_info (&(mpeg2dec->info));
  mpeg2dec->info.gop = &(mpeg2dec->gop);
  info_user_data (mpeg2dec);
}

void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type)
{
  int i;

  for (i = 0; i < 3; i++)
    if (mpeg2dec->fbuf[1] != &mpeg2dec->fbuf_alloc[i].fbuf &&
        mpeg2dec->fbuf[2] != &mpeg2dec->fbuf_alloc[i].fbuf) {
      mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[i].fbuf;
      mpeg2dec->info.current_fbuf = mpeg2dec->fbuf[0];
      if (b_type || (mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY)) {
        if (b_type || mpeg2dec->convert)
           mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[0];
        mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[0];
      }
      break;
    }
}
*/

int mpeg2_header_picture (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);

  decoder->coding_type = (buffer [1] >> 3) & 7;
  if ((decoder->coding_type < I_TYPE)
  ||  (decoder->coding_type > D_TYPE))
    return CHUNK_CORRUPTED;

  decoder->temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6);
//  decoder->vbv_delay = ((buffer[1] << 11) | buffer[2] << 3) | buffer[3] >> 5) & 0xffff;

  /* forward_f_code and backward_f_code - used in mpeg1 only */
  /* pre subtract 1 to f_code[0] for use later in compute_motion_vector */
  if ((decoder->coding_type == P_TYPE) || (decoder->coding_type == B_TYPE))
  {
    decoder->f_motion.f_code[1] = (buffer[3] >> 2) & 1;
    decoder->f_motion.f_code[0] =
        (((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1;
  }
  if (decoder->coding_type == B_TYPE)
  {
    decoder->b_motion.f_code[1] = (buffer[4] >> 6) & 1;
    decoder->b_motion.f_code[0] = ((buffer[4] >> 3) & 7) - 1;
  }

  decoder->intra_dc_precision = 0;
  decoder->picture_structure = FRAME_PICTURE;
  decoder->field_nr = 0;
  decoder->progressive_frame = 1;
  mpeg2dec->nb_fields = 2;
  decoder->top_field_first = 0;
  decoder->frame_pred_frame_dct = 1;
  decoder->concealment_motion_vectors = 0;
  decoder->q_scale_type = 0;
  decoder->intra_vlc_format = 0;
  decoder->scan = mpeg2_scan_norm;
  mpeg2dec->copy_matrix = 0;

  mpeg2dec->ext_state = PIC_CODING_EXT;

  return CHUNK_VALID;
}

static int picture_coding_ext (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);

  /* pre subtract 1 for use later in compute_motion_vector */
  /* values -1 are forbidden */
  decoder->f_motion.f_code[0] = (buffer[0] & 15) - 1;
  decoder->f_motion.f_code[1] = (buffer[1] >> 4) - 1;
  decoder->b_motion.f_code[0] = (buffer[1] & 15) - 1;
  decoder->b_motion.f_code[1] = (buffer[2] >> 4) - 1;

  decoder->intra_dc_precision = (buffer[2] >> 2) & 3;
  /* value 0 is forbidden */
  /* progressive sequence may contain only frame pictures */
  /* The 2 fields  of a frame must have same coding_type */
  /* except if 1st is I, second may be P */
  /* 2d field must be of opposite parity */
  decoder->picture_structure = buffer[2] & 3;
  decoder->field_nr = (decoder->picture_structure == BOTTOM_FIELD);

  /* chroma_420_type, historical flag */

  decoder->progressive_frame = buffer[4] >> 7;
//    if (buffer[4] & 0x40)
//    flags |= (((buffer[4]<<26) | (buffer[5]<<18) | (buffer[6]<<10)) &
//          PIC_MASK_COMPOSITE_DISPLAY) | PIC_FLAG_COMPOSITE_DISPLAY;
//    picture->flags = flags;
  if (decoder->picture_structure == FRAME_PICTURE)
  {
    if (mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)
      mpeg2dec->nb_fields = (buffer[3] & 2) ? ((buffer[3] & 0x80) ? 6 : 4) : 2;
    else
      mpeg2dec->nb_fields = (buffer[3] & 2) ? 3 : 2;
  }
  decoder->top_field_first = buffer[3] >> 7;
  decoder->frame_pred_frame_dct = (buffer[3] >> 6) & 1;
  decoder->concealment_motion_vectors = (buffer[3] >> 5) & 1;
  decoder->q_scale_type = (buffer[3] >> 4) & 1;
  decoder->intra_vlc_format = (buffer[3] >> 3) & 1;
  decoder->scan = (buffer[3] & 4) ? mpeg2_scan_alt : mpeg2_scan_norm;

  mpeg2dec->ext_state = PIC_DISPLAY_EXT | COPYRIGHT_EXT | QUANT_MATRIX_EXT
          | PIC_SPATIAL_EXT | PIC_TEMPORAL_EXT;

  return CHUNK_VALID;
}

static int picture_display_ext (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2dec = mpeg2dec; // unused
  buffer = buffer;     // unused
  return CHUNK_VALID;
}

static int copyright_ext (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2dec = mpeg2dec; // unused
  buffer = buffer;     // unused
  return CHUNK_VALID;
}

static int picture_spatial_scalable_ext(mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2dec = mpeg2dec; // unused
  buffer = buffer;     // unused
  return CHUNK_VALID;
}

static int picture_temporal_scalable_ext(mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2dec = mpeg2dec; // unused
  buffer = buffer;     // unused
  return CHUNK_VALID;
}

static int quant_matrix_ext (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
  int i;

  if (buffer[0] & 8)
  {
    for (i = 0; i < 64; i++)
        mpeg2dec->lumi_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
        (buffer[i] << 5) | (buffer[i+1] >> 3);
    mpeg2dec->copy_matrix |= 0x11;
    buffer += 64;
  }

  if (buffer[0] & 4)
  {
    for (i = 0; i < 64; i++)
        mpeg2dec->lumi_non_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
        (buffer[i] << 6) | (buffer[i+1] >> 2);
    mpeg2dec->copy_matrix |= 0x22;
    buffer += 64;
  }

  if (decoder->chroma_type != SEQ_CHROMA_420)
  {
    if (buffer[0] & 2)
    {
      for (i = 0; i < 64; i++)
        mpeg2dec->chroma_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
            (buffer[i] << 7) | (buffer[i+1] >> 1);
      mpeg2dec->copy_matrix |= 4;
      buffer += 64;
    }

    if (buffer[0] & 1)
    {
      for (i = 0; i < 64; i++)
        mpeg2dec->chroma_non_intra_quantizer_matrix[mpeg2_scan_norm[i]] =
            buffer[i+1];
      mpeg2dec->copy_matrix |= 8;
    }
  }

  return CHUNK_VALID;
}

int mpeg2_header_extension (mpeg2dec_t * mpeg2dec, const uint8_t * buffer)
{
  static int (* parser[]) (mpeg2dec_t *, const uint8_t *) = {
    0, sequence_ext, sequence_display_ext, quant_matrix_ext,
    copyright_ext, sequence_scalable_ext,
    0, picture_display_ext, picture_coding_ext,
    picture_spatial_scalable_ext, picture_temporal_scalable_ext
    };
  int ext, ext_bit;

  ext = buffer[0] >> 4;
  ext_bit = 1 << ext;

  if (!(mpeg2dec->ext_state & ext_bit))
  {
    if (config.debug & cfg_printwarnings)
      ka_log(ka_log_error | ka_log_video, "Invalid extension %d", ext);
    return CHUNK_CORRUPTED;
  }

  mpeg2dec->ext_state &= ~ext_bit;
  return parser[ext](mpeg2dec, buffer);
}
