/*
 * mpeg2_internal.h
 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
 * Copyright (C) 1999-2001 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>
 */

#ifndef mpeg2_internal_h
#define mpeg2_internal_h

#include "mpeg2.h"

#define CHUNK_VALID     0
#define CHUNK_FORBIDDEN 1
#define CHUNK_CORRUPTED 2

#define STATE_WAIT_SEQUENCE 0
#define STATE_WAIT_HEADER   1
#define STATE_SEQUENCE      2
#define STATE_GOP           3
#define STATE_PICTURE       4
#define STATE_SLICE         5

// chunks start codes
#define STARTCODE_PICTURE         0x00
#define STARTCODE_SLICE_MIN       0x01
#define STARTCODE_SLICE_MAX       0xaf
#define STARTCODE_USERDATA        0xb2
#define STARTCODE_SEQUENCE_HEADER 0xb3
#define STARTCODE_SEQUENCE_ERROR  0xb4
#define STARTCODE_EXTENSION       0xb5
#define STARTCODE_SEQUENCE_END    0xb7
#define STARTCODE_GROUP           0xb8
#define STARTCODE_SYSTEM_MIN      0xb9
#define STARTCODE_SYSTEM_MAX      0xff

// macroblock modes
#define MACROBLOCK_INTRA            1
#define MACROBLOCK_PATTERN          2
#define MACROBLOCK_MOTION_BACKWARD  4
#define MACROBLOCK_MOTION_FORWARD   8
#define MACROBLOCK_QUANT           16
#define DCT_TYPE_INTERLACED        32
// motion_type
#define MOTION_TYPE_MASK (3*64)
#define MOTION_TYPE_SHIFT 6
#define MC_FIELD (1*64)
#define MC_FRAME (2*64)
#define MC_16X8  (2*64)
#define MC_DMV   (3*64)

// picture structure
#define TOP_FIELD     1
#define BOTTOM_FIELD  2
#define FRAME_PICTURE 3

// picture coding type
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
#define D_TYPE 4

typedef struct
{
    yuv_bufs ref[2];
    int pmv[2][2];
    int f_code[2];
} motion_t;

typedef struct mpeg2_decoder_s
{
    int32_t options;
    // first, state that carries information from one macroblock to the
    // next inside a slice, and is never used outside of slice_process()

    // DCT coefficients - should be kept aligned !
    int32_t DCTblock[64];

    // bit parsing stuff
    uint32_t bitstream_buf;         // current 32 bit working set of buffer
    int bitstream_bits;             // used bits in working set
    const uint8_t * bitstream_ptr;  // buffer with stream data

    // Motion vectors
    // The f_ and b_ correspond to the forward and backward motion predictors
    motion_t b_motion;
    motion_t f_motion;

    // predictor for DC coefficients in intra blocks
    int32_t dc_dct_pred[3];

    int quantizer_scale;
    int macroblock_modes;

    // destination yuv buffers management
    yuv_bufs dest;

    int stride;
    int uvstride;
    int cur_offset;
    int cur_uvoffset;
    int cur_x;
    int cur_y;
    int max_y;
    int max_offset;

    // now non-slice-specific information

    // sequence header stuff
    uint8_t lumi_intra_quantizer_matrix [64];
    uint8_t lumi_non_intra_quantizer_matrix [64];
    uint8_t chroma_intra_quantizer_matrix [64];
    uint8_t chroma_non_intra_quantizer_matrix [64];

    // The width and height of the picture snapped to macroblock units
    int lumi_width;
    int lumi_height;
    int chroma_wshift;
    int chroma_hshift;

    int chroma_type;
    int blockmask;
    int vertical_position_extension;

    // picture header stuff

    int temporal_reference;
    // what type of picture this is (I, P, B, D)
    int coding_type;

    // picture coding extension stuff

    // quantization factor for intra dc coefficients
    int intra_dc_precision;
    // top/bottom/both fields
    int picture_structure;
    // bool to indicate progressive or interlaced PICTURE_TYPE
    int progressive_frame;
    // bool to indicate all predictions are frame based
    int frame_pred_frame_dct;
    // bool to indicate whether intra blocks have motion vectors
    // (for concealment)
    int concealment_motion_vectors;
    // bit to indicate which quantization table to use
    int q_scale_type;
    // bool to use different vlc tables
    int intra_vlc_format;
    // used for DMV MC
    int top_field_first;

    // stuff derived from bitstream

    // pointer to the zigzag scan we're supposed to be using
    const uint8_t * scan;

    int second_field; // 0 first field of picture in decoding order, 1 second
    int field_nr;     // 0 top field of picture, 1 bottom one
    int mpeg1;
} mpeg2_decoder_t;

// Structure for the mpeg2dec decoder

// 1 BACK REF, 1 FORWARD REF, 1 CUR, 1 PREV (Blendx2 deinterlacing)
#define MPEG2DEC_MAXFRAMES 4

struct mpeg2dec_s
{
    mpeg2_decoder_t  decoder;
    mpeg2_info_t info;

    mpeg2_frame_t frames[MPEG2DEC_MAXFRAMES];

    mpeg2_frame_t * current_frame;
    mpeg2_frame_t * display_frame;
    mpeg2_frame_t * forward_reference_frame;
    mpeg2_frame_t * backward_reference_frame;

    int state;
    uint32_t ext_state;

    // chunk extraction
    struct
    {
      uint8_t * buffer; // pointer to save buffer for chunk parts
      uint8_t * ptr;    // pointer to end of filled part of save buffer
      const uint8_t * start;  // pointer to start of ready chunk or NULL if none ready
      const uint8_t * end;    // pointer to end of ready chunk
      uint32_t pts;     // picture time stamp for the chunk
      uint8_t code;     // start code of the chunk
      uint32_t blockid; // id of videoblock from which chunk DATA was started
    } chunk;

    // video packet
    struct
    {
      const uint8_t * start;  // pointer to start of current packet
      uint32_t shift;   // current shift in start code lookup
      uint32_t pts;     // picture time stamp, reset to zero once used
      uint32_t blockid; // id of videoblock
      uint32_t nextpts; // picture time stamp for next chunk, reset once used
      uint8_t nextcode; // start code of next chunk
      uint8_t ptsset;   // 1 if already set for this packet, 0 otherwise
    } vbv;

    mpeg2_sequence_t sequence;

    int32_t display_offset_x, display_offset_y;

    // frame duration multiplier in 1/2 of a frame
    int nb_fields;

    // temporary work data used during header decoding
    mpeg2_sequence_t new_sequence;
    int copy_matrix;
    uint8_t lumi_intra_quantizer_matrix [64];
    uint8_t lumi_non_intra_quantizer_matrix [64];
    uint8_t chroma_intra_quantizer_matrix [64];
    uint8_t chroma_non_intra_quantizer_matrix [64];
};

// header.c
void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec);
int  mpeg2_header_sequence (mpeg2dec_t * mpeg2dec, const uint8_t * buffer);
int  mpeg2_header_picture (mpeg2dec_t * mpeg2dec, const uint8_t * buffer);
int  mpeg2_header_extension (mpeg2dec_t * mpeg2dec, const uint8_t * buffer);
void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec);
void mpeg2_header_matrix_finalize(mpeg2dec_t * mpeg2dec);

// motion_comp.c
typedef void mpeg2_mc_fct (uint8_t *, const uint8_t *, int, int);

typedef struct
{
    mpeg2_mc_fct * put [8];
    mpeg2_mc_fct * avg [8];
    mpeg2_mc_fct * test [8];
} mpeg2_mc_t;
extern mpeg2_mc_t mc_functions;

typedef struct mc_functions_s
{
    void (* put [8]) (uint8_t *dst, uint8_t *, int32_t, int32_t);
    void (* avg [8]) (uint8_t *dst, uint8_t *, int32_t, int32_t);
} mc_functions_t;

// slice.c
void mpeg2_slices_init(mpeg2_decoder_t* picture
                     , const yuv_bufs * forward_ref
                     , const yuv_bufs * current_ref
                     , const yuv_bufs * backward_ref);
int  mpeg2_slice(mpeg2_decoder_t* picture, uint8_t code, const uint8_t* buffer, const uint8_t* buffer_end);
void mpeg2_slices_complete(mpeg2_decoder_t* picture);

// stats.c
void stats_header(mpeg2dec_t* mpeg2dec, uint8_t code, const uint8_t * buffer);

#endif
