/*
 * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/*
 * This file is a utilities file which supports JPEG Encode process
 */

#include <sys/types.h>
#include <stdio.h>

#define MAX_JPEG_COMPONENTS 3 //only for Y, U and V
#define JPEG_Y 0
#define JPEG_U 1
#define JPEG_V 2
#define NUM_QUANT_ELEMENTS 64
#define NUM_MAX_HUFFTABLE 2
#define NUM_AC_RUN_SIZE_BITS 16
#define NUM_AC_CODE_WORDS_HUFFVAL 162
#define NUM_DC_RUN_SIZE_BITS 16
#define NUM_DC_CODE_WORDS_HUFFVAL 12

#define BITSTREAM_ALLOCATE_STEPPING     4096

struct __bitstream {
    unsigned int *buffer;
    int bit_offset;
    int max_size_in_dword;
};

typedef struct __bitstream bitstream;

static unsigned int
swap32(unsigned int val)
{
    unsigned char *pval = (unsigned char *)&val;

    return ((pval[0] << 24)     |
            (pval[1] << 16)     |
            (pval[2] << 8)      |
            (pval[3] << 0));
}

static void
bitstream_start(bitstream *bs)
{
    bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
    bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
    assert(bs->buffer);
    bs->bit_offset = 0;
}

static void
bitstream_end(bitstream *bs)
{
    int pos = (bs->bit_offset >> 5);
    int bit_offset = (bs->bit_offset & 0x1f);
    int bit_left = 32 - bit_offset;

    if (bit_offset) {
        bs->buffer[pos] = swap32((bs->buffer[pos] << bit_left));
    }
}

static void
bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
{
    int pos = (bs->bit_offset >> 5);
    int bit_offset = (bs->bit_offset & 0x1f);
    int bit_left = 32 - bit_offset;

    if (!size_in_bits)
        return;

    if (size_in_bits < 32)
        val &= ((1 << size_in_bits) - 1);

    bs->bit_offset += size_in_bits;

    if (bit_left > size_in_bits) {
        bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
    } else {
        size_in_bits -= bit_left;
        bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
        bs->buffer[pos] = swap32(bs->buffer[pos]);

        if (pos + 1 == bs->max_size_in_dword) {
            bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
            bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
            assert(bs->buffer);
        }

        bs->buffer[pos + 1] = val;
    }
}

//As per Jpeg Spec ISO/IEC 10918-1, below values are assigned
enum jpeg_markers {

//Define JPEG markers as 0xFFXX if you are adding the value directly to the buffer
//Else define marker as 0xXXFF if you are assigning the marker to a structure variable.
//This is needed because of the little-endedness of the IA

    SOI  = 0xFFD8, //Start of Image
    EOI  = 0xFFD9, //End of Image
    SOS  = 0xFFDA, //Start of Scan
    DQT  = 0xFFDB, //Define Quantization Table
    DRI  = 0xFFDD, //Define restart interval
    RST0 = 0xFFD0, //Restart interval termination
    DHT  = 0xFFC4, //Huffman table
    SOF0 = 0xFFC0, //Baseline DCT
    APP0 = 0xFFE0, //Application Segment
    COM  = 0xFFFE  //Comment segment
};

typedef struct _JPEGFrameHeader {

    uint16_t SOF;    //Start of Frame Header
    uint16_t Lf;     //Length of Frame Header
    uint8_t  P;      //Sample precision
    uint16_t Y;      //Number of lines
    uint16_t X;      //Number of samples per line
    uint8_t  Nf;     //Number of image components in frame

    struct _JPEGComponent {
        uint8_t Ci;    //Component identifier
        uint8_t Hi: 4; //Horizontal sampling factor
        uint8_t Vi: 4; //Vertical sampling factor
        uint8_t Tqi;   //Quantization table destination selector
    } JPEGComponent[MAX_JPEG_COMPONENTS];

} JPEGFrameHeader;


typedef struct _JPEGScanHeader {

    uint16_t SOS;  //Start of Scan
    uint16_t Ls;   //Length of Scan
    uint8_t  Ns;   //Number of image components in the scan

    struct _ScanComponent {
        uint8_t Csj;   //Scan component selector
        uint8_t Tdj: 4; //DC Entropy coding table destination selector(Tdj:4 bits)
        uint8_t Taj: 4; //AC Entropy coding table destination selector(Taj:4 bits)
    } ScanComponent[MAX_JPEG_COMPONENTS];

    uint8_t Ss;    //Start of spectral or predictor selection, 0 for Baseline
    uint8_t Se;    //End of spectral or predictor selection, 63 for Baseline
    uint8_t Ah: 4; //Successive approximation bit position high, 0 for Baseline
    uint8_t Al: 4; //Successive approximation bit position low, 0 for Baseline

} JPEGScanHeader;


typedef struct _JPEGQuantSection {

    uint16_t DQT;    //Quantization table marker
    uint16_t Lq;     //Length of Quantization table definition
    uint8_t  Tq: 4;  //Quantization table destination identifier
    uint8_t  Pq: 4;  //Quatization table precision. Should be 0 for 8-bit samples
    uint8_t  Qk[NUM_QUANT_ELEMENTS]; //Quantization table elements

} JPEGQuantSection;

typedef struct _JPEGHuffSection {

    uint16_t DHT;                            //Huffman table marker
    uint16_t Lh;                             //Huffman table definition length
    uint8_t  Tc: 4;                          //Table class- 0:DC, 1:AC
    uint8_t  Th: 4;                          //Huffman table destination identifier
    uint8_t  Li[NUM_AC_RUN_SIZE_BITS];       //Number of Huffman codes of length i
    uint8_t  Vij[NUM_AC_CODE_WORDS_HUFFVAL]; //Value associated with each Huffman code

} JPEGHuffSection;


typedef struct _JPEGRestartSection {

    uint16_t DRI;  //Restart interval marker
    uint16_t Lr;   //Legth of restart interval segment
    uint16_t Ri;   //Restart interval

} JPEGRestartSection;


typedef struct _JPEGCommentSection {

    uint16_t COM;  //Comment marker
    uint16_t Lc;   //Comment segment length
    uint8_t  Cmi;  //Comment byte

} JPEGCommentSection;


typedef struct _JPEGAppSection {

    uint16_t APPn;  //Application data marker
    uint16_t Lp;    //Application data segment length
    uint8_t  Api;   //Application data byte

} JPEGAppSection;

//Luminance quantization table
//Source: Jpeg Spec ISO/IEC 10918-1, Annex K, Table K.1
uint8_t jpeg_luma_quant[NUM_QUANT_ELEMENTS] = {
    16, 11, 10, 16, 24,  40,  51,  61,
    12, 12, 14, 19, 26,  58,  60,  55,
    14, 13, 16, 24, 40,  57,  69,  56,
    14, 17, 22, 29, 51,  87,  80,  62,
    18, 22, 37, 56, 68,  109, 103, 77,
    24, 35, 55, 64, 81,  104, 113, 92,
    49, 64, 78, 87, 103, 121, 120, 101,
    72, 92, 95, 98, 112, 100, 103, 99
};

//Luminance quantization table
//Source: Jpeg Spec ISO/IEC 10918-1, Annex K, Table K.2
uint8_t jpeg_chroma_quant[NUM_QUANT_ELEMENTS] = {
    17, 18, 24, 47, 99, 99, 99, 99,
    18, 21, 26, 66, 99, 99, 99, 99,
    24, 26, 56, 99, 99, 99, 99, 99,
    47, 66, 99, 99, 99, 99, 99, 99,
    99, 99, 99, 99, 99, 99, 99, 99,
    99, 99, 99, 99, 99, 99, 99, 99,
    99, 99, 99, 99, 99, 99, 99, 99,
    99, 99, 99, 99, 99, 99, 99, 99
};


//Zigzag scan order of the the Luma and Chroma components
//Note: Jpeg Spec ISO/IEC 10918-1, Figure A.6 shows the zigzag order differently.
//The Spec is trying to show the zigzag pattern with number positions. The below
//table will use the patter shown by A.6 and map the postion of the elements in the array
uint8_t jpeg_zigzag[] = {
    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
};


//Huffman table for Luminance DC Coefficients
//Reference Jpeg Spec ISO/IEC 10918-1, K.3.3.1
//K.3.3.1 is the summarized version of Table K.3
uint8_t jpeg_hufftable_luma_dc[] = {
    //TcTh (Tc=0 since 0:DC, 1:AC; Th=0)
    0x00,
    //Li
    0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //Vi
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
};

//Huffman table for Chrominance DC Coefficients
//Reference Jpeg Spec ISO/IEC 10918-1, K.3.3.1
//K.3.3.1 is the summarized version of Table K.4
uint8_t jpeg_hufftable_chroma_dc[] = {
    //TcTh (Tc=0 since 0:DC, 1:AC; Th=1)
    0x01,
    //Li
    0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    //Vi
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
};


//Huffman table for Luminance AC Coefficients
//Reference Jpeg Spec ISO/IEC 10918-1, K.3.3.2
//K.3.3.2 is the summarized version of Table K.5
uint8_t jpeg_hufftable_luma_ac[] = {
    //TcTh (Tc=1 since 0:DC, 1:AC; Th=0)
    0x10,
    //Li
    0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D,
    //Vi
    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
    0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
    0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
    0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
    0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
    0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
    0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    0xF9, 0xFA
};

//Huffman table for Chrominance AC Coefficients
//Reference Jpeg Spec ISO/IEC 10918-1, K.3.3.2
//K.3.3.2 is the summarized version of Table K.6
uint8_t jpeg_hufftable_chroma_ac[] = {
    //TcTh (Tc=1 since 0:DC, 1:AC; Th=1)
    0x11,
    //Li
    0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
    //Vi
    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
    0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
    0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
    0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
    0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    0xF9, 0xFA
};

typedef struct _YUVComponentSpecs {
    //One of 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGBA)>
    unsigned int yuv_type;
    // One of VA_RT_FORMAT_YUV420, VA_RT_FORMAT_YUV422, VA_RT_FORMAT_YUV400, VA_RT_FORMAT_YUV444, VA_RT_FORMAT_RGB32
    unsigned int va_surface_format;
    //One of VA_FOURCC_I420, VA_FOURCC_NV12, VA_FOURCC_UYVY, VA_FOURCC_YUY2, VA_FOURCC_Y800, VA_FOURCC_444P, VA_FOURCC_RGBA
    unsigned int fourcc_val; //Using this field to evaluate the input file type.
    //no.of. components
    unsigned int num_components;
    //Y horizontal subsample
    unsigned int y_h_subsample;
    //Y vertical subsample
    unsigned int y_v_subsample;
    //U horizontal subsample
    unsigned int u_h_subsample;
    //U vertical subsample
    unsigned int u_v_subsample;
    //V horizontal subsample
    unsigned int v_h_subsample;
    //V vertical subsample
    unsigned int v_v_subsample;
} YUVComponentSpecs;
