24bit.c 444 5104 267 12314 5333605246 5273 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "dither.h" #include "proto.h" /* * We'll define the "ConvertColor" macro here to do fixed point arithmetic * that'll convert from YCrCb to RGB using: * R = L + 1.40200*Cr; * G = L - 0.34414*Cb - 0.71414*Cr * B = L + 1.77200*Cb; * * We'll use fixed point by adding two extra bits after the decimal. */ #define BITS 8 #define ONE ((int) 1) #define CONST_SCALE (ONE << BITS) #define ROUND_FACTOR (ONE << (BITS-1)) /* Macro to convert integer to fixed. */ #define UP(x) (((int)(x)) << BITS) /* Macro to convert fixed to integer (with rounding). */ #define DOWN(x) (((x) + ROUND_FACTOR) >> BITS) /* Macro to convert a float to a fixed */ #define FIX(x) ((int) ((x)*CONST_SCALE + 0.5)) #define CLAMP(ll,x,ul) ( ((x)<(ll)) ?(ll):( ((x)>(ul)) ?(ul):(x))) static int *Cb_r_tab, *Cr_g_tab, *Cb_g_tab, *Cr_b_tab; /* *-------------------------------------------------------------- * * InitColorDither -- * * To get rid of the multiply and other conversions in color * dither, we use a lookup table. * * Results: * None. * * Side effects: * The lookup tables are initialized. * *-------------------------------------------------------------- */ void InitColorDither() { int CR, CB, i; Cr_b_tab = (int *)malloc(256*sizeof(int)); Cr_g_tab = (int *)malloc(256*sizeof(int)); Cb_g_tab = (int *)malloc(256*sizeof(int)); Cb_r_tab = (int *)malloc(256*sizeof(int)); for (i=0; i<256; i++) { CB = CR = i; CB -= 128; CR -= 128; Cb_r_tab[i] = FIX(1.40200) * CB; Cr_g_tab[i] = -FIX(0.34414) * CR; Cb_g_tab[i] = -FIX(0.71414) * CB; Cr_b_tab[i] = FIX(1.77200) * CR; } } /* *-------------------------------------------------------------- * * ColorDitherImage -- * * Converts image into 24 bit color. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void ColorDitherImage(lum, cr, cb, out, rows, cols) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int cols, rows; { int L, CR, CB; unsigned int *row1, *row2; unsigned char *lum2; int x, y; unsigned int r, b, g; int cb_r; int cr_g; int cb_g; int cr_b; row1 = (unsigned int *)out; row2 = row1 + cols; lum2 = lum + cols; for (y=0; y> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS; #else b = CLAMP(0,B,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS; #endif *row1++ = r | g | b; L = *lum++; L = UP(L); R = L + cb_r; G = L + cr_g + cb_g; B = L + cr_b; #ifndef RS6000 r = CLAMP(0,R,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS; #else b = CLAMP(0,B,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS; #endif *row1++ = r | g | b; /* * Now, do second row. */ L = *lum2++; L = UP(L); R = L + cb_r; G = L + cr_g + cb_g; B = L + cr_b; #ifndef RS6000 r = CLAMP(0,R,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS; #else b = CLAMP(0,B,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS; #endif *row2++ = r | g | b; L = *lum2++; L = UP(L); R = L + cb_r; G = L + cr_g + cb_g; B = L + cr_b; #ifndef RS6000 r = CLAMP(0,R,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; b = (CLAMP(0,B,UP(255)) & 0xff00) << BITS; #else b = CLAMP(0,B,UP(255)) >> BITS; g = CLAMP(0,G,UP(255)) & 0xff00; r = (CLAMP(0,R,UP(255)) & 0xff00) << BITS; #endif *row2++ = r | g | b; } lum += cols; lum2 += cols; row1 += cols; row2 += cols; } } 2x2.c 444 5104 267 21211 5333605247 4757 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "dither.h" #include "proto.h" #define RAND_ERR_RANGE 7 #define RAND_ERR_SUBVAL 3 /* Array containing actual pixel values for each possible 2x2 dither pattern. */ static unsigned char *dith_a; /* Arrays mapping lum, cr, and cb values to portions of dither pattern code. The addtion of one value from each array yields a valid dither pattern code. */ static int lval_a[256+RAND_ERR_RANGE-1]; static int rval_a[256+RAND_ERR_RANGE-1]; static int bval_a[256+RAND_ERR_RANGE-1]; /* Range of possible dither patterns in each channel. */ #define L_DITH_RANGE (((LUM_RANGE-1)*4)+1) #define CR_DITH_RANGE (((CR_RANGE-1)*4)+1) #define CB_DITH_RANGE (((CB_RANGE-1)*4)+1) /* Arrays of random error terms added to break up contours. */ static int *randval_a; static int **randptr_a; /* *-------------------------------------------------------------- * * Init2x2Dither-- * * Initializes structures used for 2x2 dithering. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Init2x2Dither() { unsigned char *dith_ca; int numcodes; int l_range, cr_range, cb_range; int p1, p2, p3, p4; int l_dith, cr_dith, cb_dith; int big_part, small_part; int i, j; l_range = L_DITH_RANGE; cr_range = CR_DITH_RANGE; cb_range = CB_DITH_RANGE; numcodes = l_range * cr_range * cb_range; dith_a = (unsigned char *) malloc(numcodes*4); dith_ca = dith_a; for (i=0; i 0) ? 1 : 0); p2 = big_part + ((small_part > 2) ? 1 : 0); p3 = big_part; p4 = big_part + ((small_part > 1) ? 1 : 0); p1 *= CR_RANGE * CB_RANGE; p2 *= CR_RANGE * CB_RANGE; p3 *= CR_RANGE * CB_RANGE; p4 *= CR_RANGE * CB_RANGE; cr_dith = (i/l_range) % cr_range; big_part = cr_dith / 4; small_part = cr_dith % 4; p1 += (big_part + ((small_part > 0) ? 1 : 0))*CB_RANGE; p2 += (big_part + ((small_part > 2) ? 1 : 0))*CB_RANGE; p3 += (big_part)*CB_RANGE; p4 += (big_part + ((small_part > 1) ? 1 : 0))*CB_RANGE; cb_dith = (i/(cr_range*l_range)) % cb_range; big_part = cb_dith / 4; small_part = cb_dith % 4; p1 += (big_part + ((small_part > 0) ? 1 : 0)); p2 += (big_part + ((small_part > 2) ? 1 : 0)); p3 += (big_part); p4 += (big_part + ((small_part > 1) ? 1 : 0)); *dith_ca++ = p1; *dith_ca++ = p2; *dith_ca++ = p3; *dith_ca++ = p4; } for (i=RAND_ERR_SUBVAL; i<256+RAND_ERR_SUBVAL; i++) { j = i-RAND_ERR_SUBVAL; lval_a[i] = (j * L_DITH_RANGE)/256; rval_a[i] = (j * CR_DITH_RANGE)/256; bval_a[i] = (j * CB_DITH_RANGE)/256; bval_a[i] *= CR_DITH_RANGE * L_DITH_RANGE * 4; rval_a[i] *= L_DITH_RANGE * 4; lval_a[i] *= 4; } for (i=0; i #include #include "decoders.h" #include "util.h" #include "video.h" #include "proto.h" /* Decoding table for macroblock_address_increment */ mb_addr_inc_entry mb_addr_inc[2048]; /* Decoding table for macroblock_type in predictive-coded pictures */ mb_type_entry mb_type_P[64]; /* Decoding table for macroblock_type in bidirectionally-coded pictures */ mb_type_entry mb_type_B[64]; /* Decoding table for motion vectors */ motion_vectors_entry motion_vectors[2048]; /* Decoding table for coded_block_pattern */ coded_block_pattern_entry coded_block_pattern[512] = { {(unsigned int)ERROR, 0}, {(unsigned int)ERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9}, {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8}, {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8}, {38, 8}, {38, 8}, {26, 8}, {26, 8}, {37, 8}, {37, 8}, {25, 8}, {25, 8}, {43, 8}, {43, 8}, {23, 8}, {23, 8}, {51, 8}, {51, 8}, {15, 8}, {15, 8}, {42, 8}, {42, 8}, {22, 8}, {22, 8}, {50, 8}, {50, 8}, {14, 8}, {14, 8}, {41, 8}, {41, 8}, {21, 8}, {21, 8}, {49, 8}, {49, 8}, {13, 8}, {13, 8}, {35, 8}, {35, 8}, {19, 8}, {19, 8}, {11, 8}, {11, 8}, {7, 8}, {7, 8}, {34, 7}, {34, 7}, {34, 7}, {34, 7}, {18, 7}, {18, 7}, {18, 7}, {18, 7}, {10, 7}, {10, 7}, {10, 7}, {10, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, {33, 7}, {33, 7}, {33, 7}, {33, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {9, 7}, {9, 7}, {9, 7}, {9, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3} }; /* Decoding table for dct_dc_size_luminance */ dct_dc_size_entry dct_dc_size_luminance[128] = { {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {7, 6}, {7, 6}, {8, 7}, {(unsigned int)ERROR, 0} }; /* Decoding table for dct_dc_size_chrominance */ dct_dc_size_entry dct_dc_size_chrominance[256] = { {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {7, 7}, {7, 7}, {8, 8}, {(unsigned int)ERROR, 0} }; /* DCT coeff tables. */ unsigned short int dct_coeff_tbl_0[256] = { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x052f, 0x051f, 0x050f, 0x04ff, 0x183f, 0x402f, 0x3c2f, 0x382f, 0x342f, 0x302f, 0x2c2f, 0x7c1f, 0x781f, 0x741f, 0x701f, 0x6c1f, 0x028e, 0x028e, 0x027e, 0x027e, 0x026e, 0x026e, 0x025e, 0x025e, 0x024e, 0x024e, 0x023e, 0x023e, 0x022e, 0x022e, 0x021e, 0x021e, 0x020e, 0x020e, 0x04ee, 0x04ee, 0x04de, 0x04de, 0x04ce, 0x04ce, 0x04be, 0x04be, 0x04ae, 0x04ae, 0x049e, 0x049e, 0x048e, 0x048e, 0x01fd, 0x01fd, 0x01fd, 0x01fd, 0x01ed, 0x01ed, 0x01ed, 0x01ed, 0x01dd, 0x01dd, 0x01dd, 0x01dd, 0x01cd, 0x01cd, 0x01cd, 0x01cd, 0x01bd, 0x01bd, 0x01bd, 0x01bd, 0x01ad, 0x01ad, 0x01ad, 0x01ad, 0x019d, 0x019d, 0x019d, 0x019d, 0x018d, 0x018d, 0x018d, 0x018d, 0x017d, 0x017d, 0x017d, 0x017d, 0x016d, 0x016d, 0x016d, 0x016d, 0x015d, 0x015d, 0x015d, 0x015d, 0x014d, 0x014d, 0x014d, 0x014d, 0x013d, 0x013d, 0x013d, 0x013d, 0x012d, 0x012d, 0x012d, 0x012d, 0x011d, 0x011d, 0x011d, 0x011d, 0x010d, 0x010d, 0x010d, 0x010d, 0x282c, 0x282c, 0x282c, 0x282c, 0x282c, 0x282c, 0x282c, 0x282c, 0x242c, 0x242c, 0x242c, 0x242c, 0x242c, 0x242c, 0x242c, 0x242c, 0x143c, 0x143c, 0x143c, 0x143c, 0x143c, 0x143c, 0x143c, 0x143c, 0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 0x085c, 0x085c, 0x085c, 0x085c, 0x085c, 0x085c, 0x085c, 0x085c, 0x047c, 0x047c, 0x047c, 0x047c, 0x047c, 0x047c, 0x047c, 0x047c, 0x046c, 0x046c, 0x046c, 0x046c, 0x046c, 0x046c, 0x046c, 0x046c, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00ec, 0x00ec, 0x00ec, 0x00ec, 0x00ec, 0x00ec, 0x00ec, 0x00ec, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00dc, 0x00cc, 0x00cc, 0x00cc, 0x00cc, 0x00cc, 0x00cc, 0x00cc, 0x00cc, 0x681c, 0x681c, 0x681c, 0x681c, 0x681c, 0x681c, 0x681c, 0x681c, 0x641c, 0x641c, 0x641c, 0x641c, 0x641c, 0x641c, 0x641c, 0x641c, 0x601c, 0x601c, 0x601c, 0x601c, 0x601c, 0x601c, 0x601c, 0x601c, 0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 0x581c, 0x581c, 0x581c, 0x581c, 0x581c, 0x581c, 0x581c, 0x581c, }; unsigned short int dct_coeff_tbl_1[16] = { 0x00bb, 0x202b, 0x103b, 0x00ab, 0x084b, 0x1c2b, 0x541b, 0x501b, 0x009b, 0x4c1b, 0x481b, 0x045b, 0x0c3b, 0x008b, 0x182b, 0x441b, }; unsigned short int dct_coeff_tbl_2[4] = { 0x4019, 0x1429, 0x0079, 0x0839, }; unsigned short int dct_coeff_tbl_3[4] = { 0x0449, 0x3c19, 0x3819, 0x1029, }; unsigned short int dct_coeff_next[256] = { 0xffff, 0xffff, 0xffff, 0xffff, 0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 0x0826, 0x0826, 0x2416, 0x2416, 0x0046, 0x0046, 0x2016, 0x2016, 0x1c15, 0x1c15, 0x1c15, 0x1c15, 0x1815, 0x1815, 0x1815, 0x1815, 0x0425, 0x0425, 0x0425, 0x0425, 0x1415, 0x1415, 0x1415, 0x1415, 0x3417, 0x0067, 0x3017, 0x2c17, 0x0c27, 0x0437, 0x0057, 0x2817, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, }; unsigned short int dct_coeff_first[256] = { 0xffff, 0xffff, 0xffff, 0xffff, 0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 0x0826, 0x0826, 0x2416, 0x2416, 0x0046, 0x0046, 0x2016, 0x2016, 0x1c15, 0x1c15, 0x1c15, 0x1c15, 0x1815, 0x1815, 0x1815, 0x1815, 0x0425, 0x0425, 0x0425, 0x0425, 0x1415, 0x1415, 0x1415, 0x1415, 0x3417, 0x0067, 0x3017, 0x2c17, 0x0c27, 0x0437, 0x0057, 0x2817, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x0034, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x1014, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0c14, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0023, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0813, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0412, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, }; /* Macro for filling up the decoding table for mb_addr_inc */ #define ASSIGN1(start, end, step, val, num) \ for (i = start; i < end; i+= step) { \ for (j = 0; j < step; j++) { \ mb_addr_inc[i+j].value = val; \ mb_addr_inc[i+j].num_bits = num; \ } \ val--; \ } /* *-------------------------------------------------------------- * * init_mb_addr_inc -- * * Initialize the VLC decoding table for macro_block_address_increment * * Results: * The decoding table for macro_block_address_increment will * be filled; illegal values will be filled as ERROR. * * Side effects: * The global array mb_addr_inc will be filled. * *-------------------------------------------------------------- */ static void init_mb_addr_inc() { int i, j, val; for (i = 0; i < 8; i++) { mb_addr_inc[i].value = ERROR; mb_addr_inc[i].num_bits = 0; } mb_addr_inc[8].value = MACRO_BLOCK_ESCAPE; mb_addr_inc[8].num_bits = 11; for (i = 9; i < 15; i++) { mb_addr_inc[i].value = ERROR; mb_addr_inc[i].num_bits = 0; } mb_addr_inc[15].value = MACRO_BLOCK_STUFFING; mb_addr_inc[15].num_bits = 11; for (i = 16; i < 24; i++) { mb_addr_inc[i].value = ERROR; mb_addr_inc[i].num_bits = 0; } val = 33; ASSIGN1(24, 36, 1, val, 11); ASSIGN1(36, 48, 2, val, 10); ASSIGN1(48, 96, 8, val, 8); ASSIGN1(96, 128, 16, val, 7); ASSIGN1(128, 256, 64, val, 5); ASSIGN1(256, 512, 128, val, 4); ASSIGN1(512, 1024, 256, val, 3); ASSIGN1(1024, 2048, 1024, val, 1); } /* Macro for filling up the decoding table for mb_type */ #define ASSIGN2(start, end, quant, motion_forward, motion_backward, pattern, intra, num, mb_type) \ for (i = start; i < end; i ++) { \ mb_type[i].mb_quant = quant; \ mb_type[i].mb_motion_forward = motion_forward; \ mb_type[i].mb_motion_backward = motion_backward; \ mb_type[i].mb_pattern = pattern; \ mb_type[i].mb_intra = intra; \ mb_type[i].num_bits = num; \ } /* *-------------------------------------------------------------- * * init_mb_type_P -- * * Initialize the VLC decoding table for macro_block_type in * predictive-coded pictures. * * Results: * The decoding table for macro_block_type in predictive-coded * pictures will be filled; illegal values will be filled as ERROR. * * Side effects: * The global array mb_type_P will be filled. * *-------------------------------------------------------------- */ static void init_mb_type_P() { int i; mb_type_P[0].mb_quant = mb_type_P[0].mb_motion_forward = mb_type_P[0].mb_motion_backward = mb_type_P[0].mb_pattern = mb_type_P[0].mb_intra = ERROR; mb_type_P[0].num_bits = 0; ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_P) ASSIGN2(2, 4, 1, 0, 0, 1, 0, 5, mb_type_P) ASSIGN2(4, 6, 1, 1, 0, 1, 0, 5, mb_type_P); ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_P); ASSIGN2(8, 16, 0, 1, 0, 0, 0, 3, mb_type_P); ASSIGN2(16, 32, 0, 0, 0, 1, 0, 2, mb_type_P); ASSIGN2(32, 64, 0, 1, 0, 1, 0, 1, mb_type_P); } /* *-------------------------------------------------------------- * * init_mb_type_B -- * * Initialize the VLC decoding table for macro_block_type in * bidirectionally-coded pictures. * * Results: * The decoding table for macro_block_type in bidirectionally-coded * pictures will be filled; illegal values will be filled as ERROR. * * Side effects: * The global array mb_type_B will be filled. * *-------------------------------------------------------------- */ static void init_mb_type_B() { int i; mb_type_B[0].mb_quant = mb_type_B[0].mb_motion_forward = mb_type_B[0].mb_motion_backward = mb_type_B[0].mb_pattern = mb_type_B[0].mb_intra = ERROR; mb_type_B[0].num_bits = 0; ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_B); ASSIGN2(2, 3, 1, 0, 1, 1, 0, 6, mb_type_B); ASSIGN2(3, 4, 1, 1, 0, 1, 0, 6, mb_type_B); ASSIGN2(4, 6, 1, 1, 1, 1, 0, 5, mb_type_B); ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_B); ASSIGN2(8, 12, 0, 1, 0, 0, 0, 4, mb_type_B); ASSIGN2(12, 16, 0, 1, 0, 1, 0, 4, mb_type_B); ASSIGN2(16, 24, 0, 0, 1, 0, 0, 3, mb_type_B); ASSIGN2(24, 32, 0, 0, 1, 1, 0, 3, mb_type_B); ASSIGN2(32, 48, 0, 1, 1, 0, 0, 2, mb_type_B); ASSIGN2(48, 64, 0, 1, 1, 1, 0, 2, mb_type_B); } /* Macro for filling up the decoding tables for motion_vectors */ #define ASSIGN3(start, end, step, val, num) \ for (i = start; i < end; i+= step) { \ for (j = 0; j < step / 2; j++) { \ motion_vectors[i+j].code = val; \ motion_vectors[i+j].num_bits = num; \ } \ for (j = step / 2; j < step; j++) { \ motion_vectors[i+j].code = -val; \ motion_vectors[i+j].num_bits = num; \ } \ val--; \ } /* *-------------------------------------------------------------- * * init_motion_vectors -- * * Initialize the VLC decoding table for the various motion * vectors, including motion_horizontal_forward_code, * motion_vertical_forward_code, motion_horizontal_backward_code, * and motion_vertical_backward_code. * * Results: * The decoding table for the motion vectors will be filled; * illegal values will be filled as ERROR. * * Side effects: * The global array motion_vector will be filled. * *-------------------------------------------------------------- */ static void init_motion_vectors() { int i, j, val = 16; for (i = 0; i < 24; i++) { motion_vectors[i].code = ERROR; motion_vectors[i].num_bits = 0; } ASSIGN3(24, 36, 2, val, 11); ASSIGN3(36, 48, 4, val, 10); ASSIGN3(48, 96, 16, val, 8); ASSIGN3(96, 128, 32, val, 7); ASSIGN3(128, 256, 128, val, 5); ASSIGN3(256, 512, 256, val, 4); ASSIGN3(512, 1024, 512, val, 3); ASSIGN3(1024, 2048, 1024, val, 1); } /* *-------------------------------------------------------------- * * init_tables -- * * Initialize all the tables for VLC decoding; this must be * called when the system is set up before any decoding can * take place. * * Results: * All the decoding tables will be filled accordingly. * * Side effects: * The corresponding global array for each decoding table * will be filled. * *-------------------------------------------------------------- */ void init_tables() { extern void init_pre_idct(); init_mb_addr_inc(); init_mb_type_P(); init_mb_type_B(); init_motion_vectors(); init_pre_idct(); #ifdef ANALYSIS { init_stats(); } #endif } /* *-------------------------------------------------------------- * * DecodeDCTDCSizeLum -- * * Huffman Decoder for dct_dc_size_luminance; location where * the result of decoding will be placed is passed as argument. * The decoded values are obtained by doing a table lookup on * dct_dc_size_luminance. * * Results: * The decoded value for dct_dc_size_luminance or ERROR for * unbound values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ void decodeDCTDCSizeLum(value) unsigned int *value; { unsigned int index; show_bits7(index); *value = dct_dc_size_luminance[index].value; flush_bits(dct_dc_size_luminance[index].num_bits); } /* *-------------------------------------------------------------- * * DecodeDCTDCSizeChrom -- * * Huffman Decoder for dct_dc_size_chrominance; location where * the result of decoding will be placed is passed as argument. * The decoded values are obtained by doing a table lookup on * dct_dc_size_chrominance. * * Results: * The decoded value for dct_dc_size_chrominance or ERROR for * unbound values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ void decodeDCTDCSizeChrom(value) unsigned int *value; { unsigned int index; show_bits8(index); *value = dct_dc_size_chrominance[index].value; flush_bits(dct_dc_size_chrominance[index].num_bits); } /* *-------------------------------------------------------------- * * decodeDCTCoeff -- * * Huffman Decoder for dct_coeff_first and dct_coeff_next; * locations where the results of decoding: run and level, are to * be placed and also the type of DCT coefficients, either * dct_coeff_first or dct_coeff_next, are being passed as argument. * * The decoder first examines the next 8 bits in the input stream, * and perform according to the following cases: * * '0000 0000' - examine 8 more bits (i.e. 16 bits total) and * perform a table lookup on dct_coeff_tbl_0. * One more bit is then examined to determine the sign * of level. * * '0000 0001' - examine 4 more bits (i.e. 12 bits total) and * perform a table lookup on dct_coeff_tbl_1. * One more bit is then examined to determine the sign * of level. * * '0000 0010' - examine 2 more bits (i.e. 10 bits total) and * perform a table lookup on dct_coeff_tbl_2. * One more bit is then examined to determine the sign * of level. * * '0000 0011' - examine 2 more bits (i.e. 10 bits total) and * perform a table lookup on dct_coeff_tbl_3. * One more bit is then examined to determine the sign * of level. * * otherwise - perform a table lookup on dct_coeff_tbl. If the * value of run is not ESCAPE, extract one more bit * to determine the sign of level; otherwise 6 more * bits will be extracted to obtain the actual value * of run , and then 8 or 16 bits to get the value of level. * * * * Results: * The decoded values of run and level or ERROR for unbound values * are placed in the locations specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ static void decodeDCTCoeff(dct_coeff_tbl, run, level) unsigned short int *dct_coeff_tbl; unsigned int *run; int *level; { unsigned int temp, index, num_bits; unsigned int value, next32bits, flushed; /* * Grab the next 32 bits and use it to improve performance of * getting the bits to parse. Thus, calls are translated as: * * show_bitsX <--> next32bits >> (32-X) * get_bitsX <--> val = next32bits >> (32-flushed-X); * flushed += X; * next32bits &= bitMask[flushed]; * flush_bitsX <--> flushed += X; * next32bits &= bitMask[flushed]; * */ show_bits32(next32bits); flushed = 0; /* show_bits8(index); */ index = next32bits >> 24; if (index > 3) { value = dct_coeff_tbl[index]; *run = (value & RUN_MASK) >> RUN_SHIFT; if (*run == END_OF_BLOCK) { *level = END_OF_BLOCK; } else { /* num_bits = (value & NUM_MASK) + 1; */ /* flush_bits(num_bits); */ flushed = (value & NUM_MASK) + 1; next32bits &= bitMask[flushed]; if (*run != ESCAPE) { *level = (value & LEVEL_MASK) >> LEVEL_SHIFT; /* get_bits1(value); */ /* if (value) *level = -*level; */ if (next32bits >> (31-flushed)) *level = -*level; flushed++; /* next32bits &= bitMask[flushed]; last op before update */ } else { /* *run == ESCAPE */ /* get_bits14(temp); */ temp = next32bits >> (18-flushed); flushed += 14; next32bits &= bitMask[flushed]; *run = temp >> 8; temp &= 0xff; if (temp == 0) { /* get_bits8(*level); */ *level = next32bits >> (24-flushed); flushed += 8; /* next32bits &= bitMask[flushed]; last op before update */ assert(*level >= 128); } else if (temp != 128) { /* Grab sign bit */ *level = ((int) (temp << 24)) >> 24; } else { /* get_bits8(*level); */ *level = next32bits >> (24-flushed); flushed += 8; /* next32bits &= bitMask[flushed]; last op before update */ *level = *level - 256; assert(*level <= -128 && *level >= -255); } } /* Update bitstream... */ flush_bits(flushed); } } else { if (index == 2) { /* show_bits10(index); */ index = next32bits >> 22; value = dct_coeff_tbl_2[index & 3]; } else if (index == 3) { /* show_bits10(index); */ index = next32bits >> 22; value = dct_coeff_tbl_3[index & 3]; } else if (index) { /* index == 1 */ /* show_bits12(index); */ index = next32bits >> 20; value = dct_coeff_tbl_1[index & 15]; } else { /* index == 0 */ /* show_bits16(index); */ index = next32bits >> 16; value = dct_coeff_tbl_0[index & 255]; } *run = (value & RUN_MASK) >> RUN_SHIFT; *level = (value & LEVEL_MASK) >> LEVEL_SHIFT; /* * Fold these operations together to make it fast... */ /* num_bits = (value & NUM_MASK) + 1; */ /* flush_bits(num_bits); */ /* get_bits1(value); */ /* if (value) *level = -*level; */ flushed = (value & NUM_MASK) + 2; if ((next32bits >> (32-flushed)) & 0x1) *level = -*level; /* Update bitstream ... */ flush_bits(flushed); } } /* *-------------------------------------------------------------- * * decodeDCTCoeffFirst -- * * Huffman Decoder for dct_coeff_first. Locations for the * decoded results: run and level, are being passed as * arguments. Actual work is being done by calling DecodeDCTCoeff, * with the table dct_coeff_first. * * Results: * The decoded values of run and level for dct_coeff_first or * ERROR for unbound values are placed in the locations given. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ void decodeDCTCoeffFirst(run, level) unsigned int *run; int *level; { decodeDCTCoeff(dct_coeff_first, run, level); } /* *-------------------------------------------------------------- * * decodeDCTCoeffNext -- * * Huffman Decoder for dct_coeff_first. Locations for the * decoded results: run and level, are being passed as * arguments. Actual work is being done by calling DecodeDCTCoeff, * with the table dct_coeff_next. * * Results: * The decoded values of run and level for dct_coeff_next or * ERROR for unbound values are placed in the locations given. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ void decodeDCTCoeffNext(run, level) unsigned int *run; int *level; { decodeDCTCoeff(dct_coeff_next, run, level); } dct_dc_size_luminance. * * Results: * The decoded value for dct_dc_size_luminance or ERROR for * unbound values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-----------------------------------------------------------decoders.h 444 5104 267 37377 5333605251 6160 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* * decoders.h * * This file contains the declarations of structures required for Huffman * decoding * */ /* Include util.h for bit i/o parsing macros. */ #include "util.h" /* Code for unbound values in decoding tables */ #define ERROR -1 #define DCT_ERROR 63 #define MACRO_BLOCK_STUFFING 34 #define MACRO_BLOCK_ESCAPE 35 /* Two types of DCT Coefficients */ #define DCT_COEFF_FIRST 0 #define DCT_COEFF_NEXT 1 /* Special values for DCT Coefficients */ #define END_OF_BLOCK 62 #define ESCAPE 61 /* Structure for an entry in the decoding table of * macroblock_address_increment */ typedef struct { unsigned int value; /* value for macroblock_address_increment */ int num_bits; /* length of the Huffman code */ } mb_addr_inc_entry; /* Decoding table for macroblock_address_increment */ extern mb_addr_inc_entry mb_addr_inc[2048]; /* Structure for an entry in the decoding table of macroblock_type */ typedef struct { unsigned int mb_quant; /* macroblock_quant */ unsigned int mb_motion_forward; /* macroblock_motion_forward */ unsigned int mb_motion_backward; /* macroblock_motion_backward */ unsigned int mb_pattern; /* macroblock_pattern */ unsigned int mb_intra; /* macroblock_intra */ int num_bits; /* length of the Huffman code */ } mb_type_entry; /* Decoding table for macroblock_type in predictive-coded pictures */ extern mb_type_entry mb_type_P[64]; /* Decoding table for macroblock_type in bidirectionally-coded pictures */ extern mb_type_entry mb_type_B[64]; /* Structures for an entry in the decoding table of coded_block_pattern */ typedef struct { unsigned int cbp; /* coded_block_pattern */ int num_bits; /* length of the Huffman code */ } coded_block_pattern_entry; /* External declaration of coded block pattern table. */ extern coded_block_pattern_entry coded_block_pattern[512]; /* Structure for an entry in the decoding table of motion vectors */ typedef struct { int code; /* value for motion_horizontal_forward_code, * motion_vertical_forward_code, * motion_horizontal_backward_code, or * motion_vertical_backward_code. */ int num_bits; /* length of the Huffman code */ } motion_vectors_entry; /* Decoding table for motion vectors */ extern motion_vectors_entry motion_vectors[2048]; /* Structure for an entry in the decoding table of dct_dc_size */ typedef struct { unsigned int value; /* value of dct_dc_size (luminance or chrominance) */ int num_bits; /* length of the Huffman code */ } dct_dc_size_entry; /* External declaration of dct dc size lumiance table. */ extern dct_dc_size_entry dct_dc_size_luminance[128]; /* External declaration of dct dc size chrom table. */ extern dct_dc_size_entry dct_dc_size_chrominance[256]; /* DCT coeff tables. */ #define RUN_MASK 0xfc00 #define LEVEL_MASK 0x03f0 #define NUM_MASK 0x000f #define RUN_SHIFT 10 #define LEVEL_SHIFT 4 /* External declaration of dct coeff tables. */ extern unsigned short int dct_coeff_tbl_0[256]; extern unsigned short int dct_coeff_tbl_1[16]; extern unsigned short int dct_coeff_tbl_2[4]; extern unsigned short int dct_coeff_tbl_3[4]; extern unsigned short int dct_coeff_next[256]; extern unsigned short int dct_coeff_first[256]; #define DecodeDCTDCSizeLum(macro_val) \ { \ unsigned int index; \ \ show_bits7(index); \ \ macro_val = dct_dc_size_luminance[index].value; \ \ flush_bits(dct_dc_size_luminance[index].num_bits); \ } #define DecodeDCTDCSizeChrom(macro_val) \ { \ unsigned int index; \ \ show_bits8(index); \ \ macro_val = dct_dc_size_chrominance[index].value; \ \ flush_bits(dct_dc_size_chrominance[index].num_bits); \ } #define DecodeDCTCoeff(dct_coeff_tbl, run, level) \ { \ unsigned int temp, index; \ unsigned int value, next32bits, flushed; \ \ /* \ * Grab the next 32 bits and use it to improve performance of \ * getting the bits to parse. Thus, calls are translated as: \ * \ * show_bitsX <--> next32bits >> (32-X) \ * get_bitsX <--> val = next32bits >> (32-flushed-X); \ * flushed += X; \ * next32bits &= bitMask[flushed]; \ * flush_bitsX <--> flushed += X; \ * next32bits &= bitMask[flushed]; \ * \ * I've streamlined the code a lot, so that we don't have to mask \ * out the low order bits and a few of the extra adds are removed. \ */ \ show_bits32(next32bits); \ \ /* show_bits8(index); */ \ index = next32bits >> 24; \ \ if (index > 3) { \ value = dct_coeff_tbl[index]; \ run = value >> RUN_SHIFT; \ if (run != END_OF_BLOCK) { \ /* num_bits = (value & NUM_MASK) + 1; */ \ /* flush_bits(num_bits); */ \ if (run != ESCAPE) { \ /* get_bits1(value); */ \ /* if (value) level = -level; */ \ flushed = (value & NUM_MASK) + 2; \ level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ value = next32bits >> (32-flushed); \ value &= 0x1; \ if (value) level = -level; \ /* next32bits &= ((~0) >> flushed); last op before update */ \ } \ else { /* run == ESCAPE */ \ /* Get the next six into run, and next 8 into temp */ \ /* get_bits14(temp); */ \ flushed = (value & NUM_MASK) + 1; \ temp = next32bits >> (18-flushed); \ /* Normally, we'd ad 14 to flushed, but I've saved a few \ * instr by moving the add below */ \ temp &= 0x3fff; \ run = temp >> 8; \ temp &= 0xff; \ if (temp == 0) { \ /* get_bits8(level); */ \ level = next32bits >> (10-flushed); \ level &= 0xff; \ flushed += 22; \ assert(level >= 128); \ } else if (temp != 128) { \ /* Grab sign bit */ \ flushed += 14; \ level = ((int) (temp << 24)) >> 24; \ } else { \ /* get_bits8(level); */ \ level = next32bits >> (10-flushed); \ level &= 0xff; \ flushed += 22; \ level = level - 256; \ assert(level <= -128 && level >= -255); \ } \ } \ /* Update bitstream... */ \ flush_bits(flushed); \ assert (flushed <= 32); \ } \ } \ else { \ if (index == 2) { \ /* show_bits10(index); */ \ index = next32bits >> 22; \ value = dct_coeff_tbl_2[index & 3]; \ } \ else if (index == 3) { \ /* show_bits10(index); */ \ index = next32bits >> 22; \ value = dct_coeff_tbl_3[index & 3]; \ } \ else if (index) { /* index == 1 */ \ /* show_bits12(index); */ \ index = next32bits >> 20; \ value = dct_coeff_tbl_1[index & 15]; \ } \ else { /* index == 0 */ \ /* show_bits16(index); */ \ index = next32bits >> 16; \ value = dct_coeff_tbl_0[index & 255]; \ } \ run = value >> RUN_SHIFT; \ level = (value & LEVEL_MASK) >> LEVEL_SHIFT; \ \ /* \ * Fold these operations together to make it fast... \ */ \ /* num_bits = (value & NUM_MASK) + 1; */ \ /* flush_bits(num_bits); */ \ /* get_bits1(value); */ \ /* if (value) level = -level; */ \ \ flushed = (value & NUM_MASK) + 2; \ value = next32bits >> (32-flushed); \ value &= 0x1; \ if (value) level = -level; \ \ /* Update bitstream ... */ \ flush_bits(flushed); \ assert (flushed <= 32); \ } \ } #define DecodeDCTCoeffFirst(runval, levelval) \ { \ DecodeDCTCoeff(dct_coeff_first, runval, levelval); \ } #define DecodeDCTCoeffNext(runval, levelval) \ { \ DecodeDCTCoeff(dct_coeff_next, runval, levelval); \ } /* *-------------------------------------------------------------- * * DecodeMBAddrInc -- * * Huffman Decoder for macro_block_address_increment; the location * in which the result will be placed is being passed as argument. * The decoded value is obtained by doing a table lookup on * mb_addr_inc. * * Results: * The decoded value for macro_block_address_increment or ERROR * for unbound values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeMBAddrInc(val) \ { \ unsigned int index; \ show_bits11(index); \ val = mb_addr_inc[index].value; \ flush_bits(mb_addr_inc[index].num_bits); \ } /* *-------------------------------------------------------------- * * DecodeMotionVectors -- * * Huffman Decoder for the various motion vectors, including * motion_horizontal_forward_code, motion_vertical_forward_code, * motion_horizontal_backward_code, motion_vertical_backward_code. * Location where the decoded result will be placed is being passed * as argument. The decoded values are obtained by doing a table * lookup on motion_vectors. * * Results: * The decoded value for the motion vector or ERROR for unbound * values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeMotionVectors(value) \ { \ unsigned int index; \ show_bits11(index); \ value = motion_vectors[index].code; \ flush_bits(motion_vectors[index].num_bits); \ } /* *-------------------------------------------------------------- * * DecodeMBTypeB -- * * Huffman Decoder for macro_block_type in bidirectionally-coded * pictures;locations in which the decoded results: macroblock_quant, * macroblock_motion_forward, macro_block_motion_backward, * macroblock_pattern, macro_block_intra, will be placed are * being passed as argument. The decoded values are obtained by * doing a table lookup on mb_type_B. * * Results: * The various decoded values for macro_block_type in * bidirectionally-coded pictures or ERROR for unbound values will * be placed in the locations specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeMBTypeB(quant, motion_fwd, motion_bwd, pat, intra) \ { \ unsigned int index; \ \ show_bits6(index); \ \ quant = mb_type_B[index].mb_quant; \ motion_fwd = mb_type_B[index].mb_motion_forward; \ motion_bwd = mb_type_B[index].mb_motion_backward; \ pat = mb_type_B[index].mb_pattern; \ intra = mb_type_B[index].mb_intra; \ flush_bits(mb_type_B[index].num_bits); \ } /* *-------------------------------------------------------------- * * DecodeMBTypeI -- * * Huffman Decoder for macro_block_type in intra-coded pictures; * locations in which the decoded results: macroblock_quant, * macroblock_motion_forward, macro_block_motion_backward, * macroblock_pattern, macro_block_intra, will be placed are * being passed as argument. * * Results: * The various decoded values for macro_block_type in intra-coded * pictures or ERROR for unbound values will be placed in the * locations specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeMBTypeI(quant, motion_fwd, motion_bwd, pat, intra) \ { \ unsigned int index; \ static int quantTbl[4] = {ERROR, 1, 0, 0}; \ \ show_bits2(index); \ \ motion_fwd = 0; \ motion_bwd = 0; \ pat = 0; \ intra = 1; \ quant = quantTbl[index]; \ if (index) { \ flush_bits (1 + quant); \ } \ } /* *-------------------------------------------------------------- * * DecodeMBTypeP -- * * Huffman Decoder for macro_block_type in predictive-coded pictures; * locations in which the decoded results: macroblock_quant, * macroblock_motion_forward, macro_block_motion_backward, * macroblock_pattern, macro_block_intra, will be placed are * being passed as argument. The decoded values are obtained by * doing a table lookup on mb_type_P. * * Results: * The various decoded values for macro_block_type in * predictive-coded pictures or ERROR for unbound values will be * placed in the locations specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeMBTypeP(quant, motion_fwd, motion_bwd, pat, intra) \ { \ unsigned int index; \ \ show_bits6(index); \ \ quant = mb_type_P[index].mb_quant; \ motion_fwd = mb_type_P[index].mb_motion_forward; \ motion_bwd = mb_type_P[index].mb_motion_backward; \ pat = mb_type_P[index].mb_pattern; \ intra = mb_type_P[index].mb_intra; \ \ flush_bits(mb_type_P[index].num_bits); \ } /* *-------------------------------------------------------------- * * DecodeCBP -- * * Huffman Decoder for coded_block_pattern; location in which the * decoded result will be placed is being passed as argument. The * decoded values are obtained by doing a table lookup on * coded_block_pattern. * * Results: * The decoded value for coded_block_pattern or ERROR for unbound * values will be placed in the location specified. * * Side effects: * Bit stream is irreversibly parsed. * *-------------------------------------------------------------- */ #define DecodeCBP(coded_bp) \ { \ unsigned int index; \ \ show_bits9(index); \ coded_bp = coded_block_pattern[index].cbp; \ flush_bits(coded_block_pattern[index].num_bits); \ } ert(level <= -128 && level >= -255); \ } \ } \ /* Update bitstream... */ \ flush_bits(flushed); \ assert (flushed <= 32); \ } \ } \ else { \ if (index == 2) { dither.h 444 5104 267 2471 5333605251 5612 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ extern int LUM_RANGE; extern int CR_RANGE; extern int CB_RANGE; #define CB_BASE 1 #define CR_BASE (CB_BASE*CB_RANGE) #define LUM_BASE (CR_BASE*CR_RANGE) extern unsigned char pixel[256]; extern int *lum_values; extern int *cr_values; extern int *cb_values; \ else if (index) { /* index == 1 */ \ /* show_bits12(index); */ \ index = next32bits >> 20; \ value = dct_coeff_tbl_1[index & 15]; \ } \ fs2.c 444 5104 267 22103 5333605251 5032 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "dither.h" #include "fs2.h" #include "proto.h" /* Structures for precomputed error propogation values. */ static FS2DithVal lum_index[256]; static FS2DithVal cr_index[256]; static FS2DithVal cb_index[256]; /* *-------------------------------------------------------------- * * InitFS2Dither -- * * Initializes structures for precomputed 2 error f-s dithering. * The value field of the structure contains the pixel component * of the particular channel in question. Thus the addition of * the value field of a structure in the luminance index, a * structure in the Cr index, and a structure in the Cb index will * yeild a color number. This color number can then be transformed * into a pixel value to be displayed. Each channel can then be * processed (i.e. dithered) separately, with the results being * added up and remapped to yield a final pixel value. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitFS2Dither() { int i; /* For each possible pixel value, precompute propogated error and store in array. */ for (i=0; i<256; i++) { lum_index[i].value = (i * LUM_RANGE) / 256; lum_index[i].e1 = (i-lum_values[lum_index[i].value]) / 2; lum_index[i].e3 = (i - lum_values[lum_index[i].value]) - lum_index[i].e1; lum_index[i].value *= LUM_BASE; cr_index[i].value = (i * CR_RANGE) / 256; cr_index[i].e1 = (i - cr_values[cr_index[i].value]) / 2; cr_index[i].e3 = (i - cr_values[cr_index[i].value]) - cr_index[i].e1 ; cr_index[i].value *= CR_BASE; cb_index[i].value = (i * CB_RANGE) / 256; cb_index[i].e1 = (i - cb_values[cb_index[i].value]) / 2; cb_index[i].e3 = (i - cb_values[cb_index[i].value]) - cb_index[i].e1; cb_index[i].value *= CB_BASE; } } /* *-------------------------------------------------------------- * * DitherImage -- * * Converts lum, cr, cb image planes into fixed colormap * space. * * Results: * the display plane is replaced by 8-bit colormap space * image. * * Side effects: * Hopefully, none. * *-------------------------------------------------------------- */ void FS2DitherImage(lum, cr, cb, disp, rows, cols) unsigned char *lum, *cr, *cb, *disp; int rows, cols; { static char *cur_row_error, *next_row_error; static int first = 1; char *cur_row_err_mark, *next_row_err_mark; char *temp; int i, j, pixsum, c_cols; unsigned char *cur_row, *channel, *dest_row; FS2DithVal *chan_index; /* Allocate error arrays. */ if (first) { cur_row_error = (char *) malloc(cols+2); next_row_error = (char *) malloc(cols+2); first = 0; } /* Initialize error arrays. */ memset(cur_row_error, 0, cols+2); memset(next_row_error, 0, cols+2); /* Use luminance values first. */ /* For each two rows, do... */ for(i=0; i 255) pixsum = 255; /* Establish dest value, propogate errors. */ *dest_row = lum_index[pixsum].value; *(cur_row_err_mark+1) += lum_index[pixsum].e1; *next_row_err_mark += lum_index[pixsum].e3; /* Advance pointers. */ cur_row++; dest_row++; cur_row_err_mark++; next_row_err_mark++; } /* Switch error arrays, so next row errors are now current row errors, and vice versa. */ temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; /* Reset next row errors. */ memset(next_row_error, 0, cols+2); /* Establish pointers for second row. This one will be processed right to left to establish serpantine motion. */ cur_row += cols-1; dest_row += cols-1; cur_row_err_mark = cur_row_error + cols; next_row_err_mark = next_row_error + cols; /* Process each column... */ for (j=0; j 255) pixsum = 255; *dest_row = lum_index[pixsum].value; *(cur_row_err_mark-1) += lum_index[pixsum].e1; *next_row_err_mark += lum_index[pixsum].e3; cur_row--; dest_row--; cur_row_err_mark--; next_row_err_mark--; } /* Switch error arrays. */ temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; /* Reset next row errors. */ memset(next_row_error, 0, cols+2); } /* Reset error arrays. */ memset(cur_row_error, 0, cols+2); /* Establish column length divided by two. */ c_cols = cols >> 1; /* Set channel to Cr. Use Cr index. */ channel = cr; chan_index = cr_index; repeat: /* Process each row of chrominance data... */ for (i=0; i < rows; i+=2) { /* Establish pointers. */ cur_row = channel + ((i>>1)*c_cols); dest_row = disp + (i*cols); cur_row_err_mark = cur_row_error+1; next_row_err_mark = next_row_error+1; /* For each column in row... */ for (j=0; j 255) pixsum = 255; /* Increment dest value. */ *dest_row += chan_index[pixsum].value; /* Propogate error values. */ *(cur_row_err_mark+1) += chan_index[pixsum].e1; *next_row_err_mark += chan_index[pixsum].e3; /* If count is odd, advance source pointer (Cr and Cb channels are 2:1 subsampled. */ if (j&1) cur_row++; /* Advance destination and error pointers. */ dest_row++; cur_row_err_mark++; next_row_err_mark++; } /* Switch error arrays. */ temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; /* Reset next row errors. */ memset(next_row_error, 0, cols+2); /* Re-establish pointers. */ cur_row += c_cols-1; dest_row += cols-1; cur_row_err_mark = cur_row_error+cols; next_row_err_mark = next_row_error+cols; /* Process second row right to left. */ for (j=0; j 255) pixsum = 255; /* Increment dest value. */ *dest_row += chan_index[pixsum].value; /* Propogate errors. */ *(cur_row_err_mark-1) += chan_index[pixsum].e1; *next_row_err_mark += chan_index[pixsum].e3; /* If column counters is odd, decrement source pointer. */ if (j&1) cur_row--; /* Decrement dest and error pointers. */ dest_row--; cur_row_err_mark--; next_row_err_mark--; } /* Switch error arrays. */ temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; /* Reinitialize next row errors. */ memset(next_row_error, 0, cols+2); } /* If Cr channel completed, set channel to Cb and Cb index and repeat. */ if (channel == cr) { channel = cb; chan_index = cb_index; memset(cur_row_error, 0, cols+2); goto repeat; } /* Establish pointer to start of display frame. */ dest_row = disp; /* Transform all display values to pixel values. */ for (i=0; i> (8-L_BITS)); cr_num = (i >> (8-CR_BITS)); cb_num = (i >> (8-CB_BITS)); /* These arrays contain the error values propogated for each pixel value for each channel. */ deltay[i] = (i - ((int) lum_values[lum_num])) / 2; deltau[i] = (i-((int) cr_values[cr_num])) / 2; deltav[i] = (i-((int) cb_values[cb_num])) / 2; deltay2[i] = (i - ((int) lum_values[lum_num])) - deltay[i]; deltau2[i] = (i - ((int) cr_values[cr_num])) - deltau[i]; deltav2[i] = (i - ((int) cb_values[cb_num])) - deltav[i]; } } /* *-------------------------------------------------------------- * * DitherImage -- * * Dithers an image using floyd-steinberg. * Assumptions made: * 1) The color space is allocated y:cr:cb = 8:4:4 * 2) The spatial resolution of y:cr:cb is 4:1:1 * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void FS2FastDitherImage (lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { int i, j, idx, idx2; int y, u, v; int dy, du, dv; int code; static int *yerr1; static int *yerr2; static int *uerr1; static int *uerr2; static int *verr1; static int *verr2; int *ye1, *ue1, *ve1; int *ye2, *ue2, *ve2; unsigned char *o, *l, *r, *b; static int first = 1; /* If first time called, allocate error arrays. */ if (first) { first = 0; yerr1 = (int *) malloc((w+5)*sizeof(int)); yerr2 = (int *) malloc((w+5)*sizeof(int)); uerr1 = (int *) malloc((w+5)*sizeof(int)); uerr2 = (int *) malloc((w+5)*sizeof(int)); verr1 = (int *) malloc((w+5)*sizeof(int)); verr2 = (int *) malloc((w+5)*sizeof(int)); } /* * Init error arrays and variables. */ memset ((char *)yerr1, 0, (w+5)*sizeof(int)); memset ((char *)yerr2, 0, (w+5)*sizeof(int)); memset ((char *)uerr1, 0, (w+5)*sizeof(int)); memset ((char *)uerr2, 0, (w+5)*sizeof(int)); memset ((char *)verr1, 0, (w+5)*sizeof(int)); memset ((char *)verr2, 0, (w+5)*sizeof(int)); du = dv = dy = 0; for (j=0; j 255) y = 255; if (u < 0) u = 0; else if (u > 255) u = 255; if (v < 0) v = 0; else if (v > 255) v = 255; /* * Construct a code using: * high order 3 bits of y, * high order 2 bits of u, * high order 2 bits of v */ code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) >> (8-(L_BITS+CR_BITS+CB_BITS))); *o++ = pixel[code]; *ye2++ = deltay[y]; *ue2++ = deltau[u]; *ve2++ = deltav[v]; dy = deltay2[y]; du = deltau2[u]; dv = deltav2[v]; /* Do right side of this pair... */ y = *l++ + dy + *ye1++; u = *r++ + du + *ue1++; v = *b++ + dv + *ve1++; if (y < 0) y = 0; else if (y > 255) y = 255; if (u < 0) u = 0; else if (u > 255) u = 255; if (v < 0) v = 0; else if (v > 255) v = 255; code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) >> (8-(L_BITS+CR_BITS+CB_BITS))); *o++ = pixel[code]; *ye2++ = deltay[y]; *ue2++ = deltau[u]; *ve2++ = deltav[v]; dy = deltay2[y]; du = deltau2[u]; dv = deltav2[v]; } ye1 = yerr1+w-1; ue1 = uerr1+w-1; ve1 = verr1+w-1; ye2 = yerr2+w-1; ue2 = uerr2+w-1; ve2 = verr2+w-1; l += w-1; o += w-1; r--; b--; dy = du = dv = 0; /* Do bottom part of row, in right to left order. */ for (i=w-1; i>0; i-=2) { /* Do right side of this pair... */ y = *l-- + dy + *ye2--; u = *r + du + *ue2--; v = *b + dv + *ve2--; if (y < 0) y = 0; else if (y > 255) y = 255; if (u < 0) u = 0; else if (u > 255) u = 255; if (v < 0) v = 0; else if (v > 255) v = 255; /* * Construct a code using: * high order 3 bits of y, * high order 2 bits of u, * high order 2 bits of v */ code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) >> (8-(L_BITS+CR_BITS+CB_BITS))); *o-- = pixel[code]; *ye1-- = deltay[y]; *ue1-- = deltau[u]; *ve1-- = deltav[v]; dy = deltay2[y]; du = deltau2[u]; dv = deltav2[v]; /* Do left side of this pair... */ y = *l-- + dy + *ye2--; u = *r-- + du + *ue2--; v = *b-- + dv + *ve2--; if (y < 0) y = 0; else if (y > 255) y = 255; if (u < 0) u = 0; else if (u > 255) u = 255; if (v < 0) v = 0; else if (v > 255) v = 255; code = (((y & L_MASK) | ((u & CR_MASK) >> L_BITS) | (v >> (L_BITS+CR_BITS))) >> (8-(L_BITS+CR_BITS+CB_BITS))); *o-- = pixel[code]; *ye1-- = deltay[y]; *ue1-- = deltau[u]; *ve1-- = deltav[v]; dy = deltay2[y]; du = deltau2[u]; dv = deltav2[v]; } } } ------------------------------------------------------------ * * DecodeMBTypeP -- * * Huffman Decoder for macro_block_type in predictive-coded pictures; * locations in which the decoded results: macroblock_quant, * macroblock_motion_forward, macro_block_motion_backfs4.c 444 5104 267 17031 5333605252 5041 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* This file contains C code to do YCrCb -> colormap space. */ #include "fs4.h" #include "video.h" #include "proto.h" #include "dither.h" /* Structures containing precomputed error terms. */ static FS4Dither lum_index[256]; static FS4Dither cr_index[256]; static FS4Dither cb_index[256]; /* *-------------------------------------------------------------- * * InitFS4Dither -- * * Initializes structures used for f-s dithering. Precomputes * error terms. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitFS4Dither() { int i; for (i=0; i<256; i++) { lum_index[i].value = (i * LUM_RANGE) / 256; lum_index[i].e1 = (7 * (i-lum_values[lum_index[i].value])) / 16; lum_index[i].e2 = (i-lum_values[lum_index[i].value])/16; lum_index[i].e3 = (5 * (i - lum_values[lum_index[i].value])) / 16; lum_index[i].e4 = (i-lum_values[lum_index[i].value]) - lum_index[i].e1 - lum_index[i].e2 - lum_index[i].e3; lum_index[i].value *= LUM_BASE; cr_index[i].value = (i * CR_RANGE) / 256; cr_index[i].e1 = (7 * (i-cr_values[cr_index[i].value])) / 16; cr_index[i].e2 = (i-cr_values[cr_index[i].value])/16; cr_index[i].e3 = (5 * (i - cr_values[cr_index[i].value])) / 16; cr_index[i].e4 = (i-cr_values[cr_index[i].value]) - cr_index[i].e1 - cr_index[i].e2 - cr_index[i].e3; cr_index[i].value *= CR_BASE; cb_index[i].value = (i * CB_RANGE) / 256; cb_index[i].e1 = (7 * (i-cb_values[cb_index[i].value])) / 16; cb_index[i].e2 = (i-cb_values[cb_index[i].value])/16; cb_index[i].e3 = (5 * (i - cb_values[cb_index[i].value])) / 16; cb_index[i].e4 = (i-cb_values[cb_index[i].value]) - cb_index[i].e1 - cb_index[i].e2 - cb_index[i].e3; cb_index[i].value *= CB_BASE; } } /* *-------------------------------------------------------------- * * DitherImage -- * * Converts lum, cr, cb image planes into fixed colormap * space. Uses Floyd-Steinberg dithering in serpentine * pattern with standard 4 errors propogated. * * Results: * The display plane is replaced by 8-bit colormap space * image. * * Side effects: * Hopefully, none. * *-------------------------------------------------------------- */ void FS4DitherImage(lum, cr, cb, disp, rows, cols) unsigned char *lum, *cr, *cb, *disp; int rows, cols; { static char *cur_row_error, *next_row_error; static int first = 1; char *cur_row_err_mark, *next_row_err_mark; char *temp; int i, j, pixsum, c_cols; unsigned char *cur_row, *channel, *dest_row; FS4Dither *chan_index; if (first) { cur_row_error = (char *) malloc(cols+2); next_row_error = (char *) malloc(cols+2); first = 0; } memset(cur_row_error, 0, cols+2); memset(next_row_error, 0, cols+2); for(i=0; i 255) pixsum = 255; *dest_row = lum_index[pixsum].value; *(cur_row_err_mark+1) += lum_index[pixsum].e1; *(next_row_err_mark+1) += lum_index[pixsum].e2; *next_row_err_mark += lum_index[pixsum].e3; *(next_row_err_mark-1) += lum_index[pixsum].e4; cur_row++; dest_row++; cur_row_err_mark++; next_row_err_mark++; } temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; memset(next_row_error, 0, cols+2); cur_row += cols-1; dest_row += cols-1; cur_row_err_mark = cur_row_error + cols; next_row_err_mark = next_row_error + cols; for (j=0; j 255) pixsum = 255; *dest_row = lum_index[pixsum].value; *(cur_row_err_mark-1) += lum_index[pixsum].e1; *(next_row_err_mark-1) += lum_index[pixsum].e2; *next_row_err_mark += lum_index[pixsum].e3; *(next_row_err_mark+1) += lum_index[pixsum].e4; cur_row--; dest_row--; cur_row_err_mark--; next_row_err_mark--; } temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; memset(next_row_error, 0, cols+2); } memset(cur_row_error, 0, cols+2); c_cols = cols >> 1; channel = cr; chan_index = cr_index; repeat: for (i=0; i < rows; i+=2) { cur_row = channel + ((i>>1)*c_cols); dest_row = disp + (i*cols); cur_row_err_mark = cur_row_error+1; next_row_err_mark = next_row_error+1; for (j=0; j 255) pixsum = 255; *dest_row += chan_index[pixsum].value; *(cur_row_err_mark+1) += chan_index[pixsum].e1; *(next_row_err_mark+1) += chan_index[pixsum].e2; *next_row_err_mark += chan_index[pixsum].e3; *(next_row_err_mark-1) += chan_index[pixsum].e4; if (j&1) cur_row++; dest_row++; cur_row_err_mark++; next_row_err_mark++; } temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; memset(next_row_error, 0, cols+2); cur_row += c_cols-1; dest_row += cols-1; cur_row_err_mark = cur_row_error+cols; next_row_err_mark = next_row_error+cols; for (j=0; j 255) pixsum = 255; *dest_row += chan_index[pixsum].value; *(cur_row_err_mark-1) += chan_index[pixsum].e1; *(next_row_err_mark-1) += chan_index[pixsum].e2; *next_row_err_mark += chan_index[pixsum].e3; *(next_row_err_mark+1) += chan_index[pixsum].e4; if (j&1) cur_row--; dest_row--; cur_row_err_mark--; next_row_err_mark--; } temp = cur_row_error; cur_row_error = next_row_error; next_row_error = temp; memset(next_row_error, 0, cols+2); } if (channel == cr) { channel = cb; chan_index = cb_index; memset(cur_row_error, 0, cols+2); goto repeat; } dest_row = disp; for (i=0; i #include "video.h" #include "proto.h" #include "dither.h" /* Range values for lum, cr, cb. */ int LUM_RANGE; int CR_RANGE; int CB_RANGE; /* Array that remaps color numbers to actual pixel values used by X server. */ unsigned char pixel[256]; /* Arrays holding quantized value ranged for lum, cr, and cb. */ int *lum_values; int *cr_values; int *cb_values; /* Declaration of global variable containing dither type. */ extern int ditherType; /* Structures used by the X server. */ Display *display; static XImage *ximage = NULL; static Colormap cmap; static Window window; static GC gc; /* *-------------------------------------------------------------- * * InitColor -- * * Initialized lum, cr, and cb quantized range value arrays. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitColor() { int i; for (i=0; i 255.0) fr = 255.0; if (fg < 0.0) fg = 0.0; else if (fg > 255.0) fg = 255.0; if (fb < 0.0) fb = 0.0; else if (fb > 255.0) fb = 255.0; *r = (unsigned char) fr; *g = (unsigned char) fg; *b = (unsigned char) fb; } #ifdef SH_MEM int gXErrorFlag = 0; int HandleXError(dpy, event) Display *dpy; XErrorEvent *event; { gXErrorFlag = 1; return 0; } void InstallXErrorHandler() { int HandleXError(); XSetErrorHandler(HandleXError); XFlush(display); } void DeInstallXErrorHandler() { XSetErrorHandler(NULL); XFlush(display); } #endif /* *-------------------------------------------------------------- * * ResizeDisplay -- * * Resizes display window. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void ResizeDisplay(w, h) int w, h; { if (ditherType == NO_DITHER) return; XResizeWindow(display, window, w, h); XFlush(display); } /* *-------------------------------------------------------------- * * MakeWindow -- * * Create X Window * * Results: * Read the code. * * Side effects: * None. * *-------------------------------------------------------------- */ #ifdef SH_MEM int CompletionType = -1; #endif static void MakeWindow(name) char *name; { XSizeHints hint; unsigned int fg, bg; char *hello = "MPEG Play"; int screen; Window CreateFullColorWindow(); if (ditherType == NO_DITHER) return; display = XOpenDisplay(name); if (display == NULL) { fprintf(stderr, "Can not open display\n"); exit(-2); } #ifdef SH_MEM if(shmemFlag) CompletionType = XShmGetEventBase(display) + ShmCompletion; #endif screen = DefaultScreen (display); /* Fill in hint structure */ hint.x = 200; hint.y = 300; hint.width = 150; hint.height = 150; hint.flags = PPosition | PSize; /* Get some colors */ bg = WhitePixel (display, screen); fg = BlackPixel (display, screen); /* Make the window */ if (ditherType == FULL_COLOR_DITHER) { window = CreateFullColorWindow (display, hint.x, hint.y, hint.width, hint.height); if (window == 0) { fprintf (stderr, "-color option only valid on full color display\n"); exit (-1); } } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) { window = XCreateSimpleWindow (display, DefaultRootWindow (display), hint.x, hint.y, hint.width, hint.height, 4, fg, bg); } else { XVisualInfo vinfo; if (!XMatchVisualInfo (display, screen, 8, PseudoColor, &vinfo)) { if (!XMatchVisualInfo(display, screen, 8, GrayScale, &vinfo)) { fprintf(stderr, "-requires 8 bit display\n"); exit(-1); } } window = XCreateSimpleWindow (display, DefaultRootWindow (display), hint.x, hint.y, hint.width, hint.height, 4, fg, bg); } XSelectInput(display, window, StructureNotifyMask); /* Tell other applications about this window */ XSetStandardProperties (display, window, hello, hello, None, NULL, 0, &hint); /* Map window. */ XMapWindow(display, window); /* Wait for map. */ while(1) { XEvent xev; XNextEvent(display, &xev); if(xev.type == MapNotify && xev.xmap.event == window) break; } XSelectInput(display, window, NoEventMask); } /* *-------------------------------------------------------------- * * InitDisplay -- * * Initialized display, sets up colormap, etc. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitDisplay(name) char *name; { int ncolors = LUM_RANGE*CB_RANGE*CR_RANGE; XColor xcolor; int i, lum_num, cr_num, cb_num; unsigned char r, g, b; Colormap dcmap; if (ditherType == NO_DITHER) return; MakeWindow(name); gc = XCreateGC(display, window, 0, 0); dcmap = cmap = XDefaultColormap(display, DefaultScreen(display)); xcolor.flags = DoRed | DoGreen | DoBlue; retry_alloc_colors: for (i=0; imb_width * 32, vid_stream->mb_height * 32, 8, 0); } else if (ditherType == FULL_COLOR_DITHER) { fc_visual = FindFullColorVisual(display, &depth); ximage = XCreateImage (display, fc_visual, depth, ZPixmap, 0, &dummy, vid_stream->mb_width * 16, vid_stream->mb_height * 16, 32, 0); } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) { ximage = XCreateImage (display, None, 1, XYBitmap, 0, &dummy, vid_stream->mb_width * 16, vid_stream->mb_height * 16, 8, 0); ximage->byte_order = MSBFirst; ximage->bitmap_bit_order = MSBFirst; } else { ximage = XCreateImage(display, None, 8, ZPixmap, 0, &dummy, vid_stream->mb_width * 16, vid_stream->mb_height * 16, 8, 0); } } if (!noDisplayFlag) { #ifdef SH_MEM if (shmemFlag) { XShmPutImage(display, window, gc, vid_stream->current->ximage, 0, 0, 0, 0, vid_stream->current->ximage->width, vid_stream->current->ximage->height, True); XFlush(display); while(1) { XEvent xev; XNextEvent(display, &xev); if(xev.type == CompletionType) break; } } else #endif { ximage->data = (char *) vid_stream->current->display; XPutImage(display, window, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); } } } if (pixsum < 0) pixsum = 0; else if (pixsum > 255) pixsum = 255; *dest_row += chan_index[pixsum].value; *(cur_row_err_mark-1) += chan_index[pixsum].e1; *(next_row_err_mark-1) += chan_index[pixsum].e2; *next_row_err_mark += chan_index[pixsum].e3; *(next_row_err_mark+1) += chan_index[pgray.c 444 5104 267 4235 5333605253 5272 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "proto.h" #include "dither.h" /* *-------------------------------------------------------------- * * GrayDitherImage -- * * Dithers image into 128 gray scales. Simply maps luminance * value into 1 of 128 gray scale colors (divide by two, essentially). * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void GrayDitherImage(lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { int i, max = w*h/16; for (i=0; i threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE)); else *lmark++ = (j * (CR_RANGE * CB_RANGE)); } } for (j=lum_values[LUM_RANGE-1]; j<256; j++) { *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE); } } { int cr1, cr2, cr3, cr4, err1, err2; int cb1, cb2, cb3, cb4, val, nval; for (i=0; i<256; i++) { val = i; cr1 = (val * CR_RANGE) / 256; err1 = (val - cr_values[cr1])/2; err2 = (val - cr_values[cr1]) - err1; nval = val+err1; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cr2 = (nval * CR_RANGE) / 256; err1 = (nval - cr_values[cr2])/2; nval = val+err2; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cr3 = (nval * CR_RANGE) / 256; err2 = (nval - cr_values[cr3])/2; nval = val+err1+err2; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cr4 = (nval * CR_RANGE) / 256; cr_fsarray[i][0] = cr1*CB_RANGE; cr_fsarray[i][1] = cr2*CB_RANGE; cr_fsarray[i][2] = cr3*CB_RANGE; cr_fsarray[i][3] = cr4*CB_RANGE; } for (i=0; i<256; i++) { val = i; cb1 = (val * CB_RANGE) / 256; err1 = (val - cb_values[cb1])/2; err2 = (val - cb_values[cb1]) - err1; nval = val+err1; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cb2 = (nval * CB_RANGE) / 256; err1 = (nval - cb_values[cb2])/2; nval = val+err2; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cb3 = (nval * CB_RANGE) / 256; err2 = (nval - cb_values[cb3])/2; nval = val+err1+err2; if (nval > 255) nval = 255; else if (nval < 0) nval = 0; cb4 = (nval * CB_RANGE) / 256; cb_fsarray[i][0] = cb1; cb_fsarray[i][1] = cb2; cb_fsarray[i][2] = cb3; cb_fsarray[i][3] = cb4; } } } /* *-------------------------------------------------------------- * * HybridDitherImage -- * * Dithers an image using an ordered dither. * Assumptions made: * 1) The color space is allocated y:cr:cb = 8:4:4 * 2) The spatial resolution of y:cr:cb is 4:1:1 * The luminance channel is dithered based on the standard * ordered dither pattern for a 4x4 area. The Chrominance * channels are dithered based on precomputed f-s errors. * Two errors are propogated per pixel. Errors are NOT propogated * beyond a 2x2 pixel area. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void HybridDitherImage (lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { unsigned char *l, *r, *b, *o1, *o2; unsigned char *l2; int i, j; l = lum; l2 = lum+w; r = cr; b = cb; o1 = out; o2 = out+w; for (i=0; i threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE)); else *lmark++ = (j * (CR_RANGE * CB_RANGE)); } } for (j=lum_values[LUM_RANGE-1]; j <256; j++) { *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE); } } l_darrays0 = l_darrays[0]; l_darrays8 = l_darrays[8]; l_darrays1 = l_darrays[1]; l_darrays9 = l_darrays[9]; l_darrays2 = l_darrays[2]; l_darrays10 = l_darrays[10]; l_darrays3 = l_darrays[3]; l_darrays11 = l_darrays[11]; l_darrays4 = l_darrays[4]; l_darrays12 = l_darrays[12]; l_darrays5 = l_darrays[5]; l_darrays13 = l_darrays[13]; l_darrays6 = l_darrays[6]; l_darrays14 = l_darrays[14]; l_darrays7 = l_darrays[7]; l_darrays15 = l_darrays[15]; { int cr1, cr2, cr3, cr4, err1, err2; int cb1, cb2, cb3, cb4, val, nval; int outerr1, outerr2, outerr3, outerr4; int inerr1, inerr2, inerr3, inerr4; unsigned short oe1, oe2, oe3, oe4; for (j=0; j<65536; j+= 256) { inerr1 = (((j & 0xc000) >> 14)*8) - 12; inerr2 = (((j & 0x3000) >> 12)*8) - 12; inerr3 = (((j & 0x0c00) >> 10)*8) - 12; inerr4 = (((j & 0x0300) >> 8) *8) - 12; for (i=0; i<256; i++) { val = i; nval = val+inerr1+inerr3; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cr1 = ((nval) * CR_RANGE) / 256; err1 = ((nval) - cr_values[cr1])/2; err2 = ((nval) - cr_values[cr1]) - err1; nval = val+err1+inerr2; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cr2 = ((nval) * CR_RANGE) / 256; err1 = ((nval) - cr_values[cr2])/2; outerr3 = ((nval) - cr_values[cr2])-err1; nval = val+err2+inerr4; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cr3 = ((nval) * CR_RANGE) / 256; err2 = ((nval) - cr_values[cr3])/2; outerr1 = ((nval) - cr_values[cr3]) - err2; nval = val+err1+err2; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cr4 = ((nval) * CR_RANGE) / 256; outerr2 = ((nval) - cr_values[cr4])/2; outerr4 = ((nval) - cr_values[cr4])-outerr2; cr_fsarray[i+j][0] = cr1*CB_RANGE; cr_fsarray[i+j][1] = cr2*CB_RANGE; cr_fsarray[i+j][2] = cr3*CB_RANGE; cr_fsarray[i+j][3] = cr4*CB_RANGE; if (outerr1 < -16) outerr1++; else if (outerr1 > 15) outerr1--; if (outerr2 < -16) outerr2++; else if (outerr2 > 15) outerr2--; if (outerr3 < -16) outerr3++; else if (outerr3 > 15) outerr3--; if (outerr4 < -16) outerr4++; else if (outerr4 > 15) outerr4--; oe1 = (outerr1 + 16) / 8; oe2 = (outerr2 + 16) / 8; oe3 = (outerr3 + 16) / 8; oe4 = (outerr4 + 16) / 8; /* This is a debugging check and should be removed if not needed. */ if ((oe1 > 3) || (oe2 > 3) || (oe3 > 3) || (oe4 > 3)) fprintf(stderr, "OE error!!!!\n"); c_fserr[i+j][0] = ((oe1 << 14) | (oe2 << 12)); c_fserr[i+j][1] = ((oe3 << 10) | (oe4 << 8)); } for (i=0; i<256; i++) { val = i; nval = val+inerr1+inerr3; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cb1 = ((nval) * CB_RANGE) / 256; err1 = ((nval) - cb_values[cb1])/2; err2 = ((nval) - cb_values[cb1]) - err1; nval = val+err1+inerr2; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cb2 = ((nval) * CB_RANGE) / 256; err1 = ((nval) - cb_values[cb2])/2; nval = val+err2+inerr4; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cb3 = ((nval) * CB_RANGE) / 256; err2 = ((nval) - cb_values[cb3])/2; nval = val+err1+err2; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cb4 = ((nval) * CB_RANGE) / 256; cb_fsarray[i+j][0] = cb1; cb_fsarray[i+j][1] = cb2; cb_fsarray[i+j][2] = cb3; cb_fsarray[i+j][3] = cb4; } } } } /* *-------------------------------------------------------------- * * HybridErrorDitherImage -- * * Dithers an image using a hybrid ordered/floyd-steinberg dither. * Assumptions made: * 1) The color space is allocated y:cr:cb = 8:4:4 * 2) The spatial resolution of y:cr:cb is 4:1:1 * This dither is almost exactly like the dither implemented in the * file odith.c (i.e. hybrid dithering) except a quantized amount of * error is propogated between 2x2 pixel areas in Cr and Cb. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void HybridErrorDitherImage (lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { unsigned char *l, *r, *b, *o1, *o2; unsigned char *l2; static int *cr_row_errs; static int *cb_row_errs; int *cr_r_err; int *cb_r_err; int cr_c_err; int cb_c_err; unsigned char *cr_fsptr; unsigned char *cb_fsptr; static int first = 1; int cr_code, cb_code; int i, j; int row_advance, row_advance2; int half_row_advance, half_row_advance2; /* If first time called, allocate error arrays. */ if (first) { cr_row_errs = (int *) malloc((w+5)*sizeof(int)); cb_row_errs = (int *) malloc((w+5)*sizeof(int)); first = 0; } row_advance = (w << 1) - 1; row_advance2 = row_advance+2; half_row_advance = (w>>1)-1; half_row_advance2 = half_row_advance+2; l = lum; l2 = lum+w; r = cr; b = cb; o1 = out; o2 = out+w; memset( (char *) cr_row_errs, 0, (w+5)*sizeof(int)); cr_r_err = cr_row_errs; cr_c_err = 0; memset( (char *) cb_row_errs, 0, (w+5)*sizeof(int)); cb_r_err = cb_row_errs; cb_c_err = 0; for (i=0; i0; j-=4) { cr_code = (*cr_r_err | cr_c_err | *r++); cb_code = (*cb_r_err | cb_c_err | *b++); cr_fsptr = cr_fsarray[cr_code]; cb_fsptr = cb_fsarray[cb_code]; *o1++ = pixel[(l_darrays0[*l++] | *cr_fsptr++ | *cb_fsptr++)]; *o1++ = pixel[(l_darrays8[*l++] | *cr_fsptr++ | *cb_fsptr++)]; *o2++ = pixel[(l_darrays12[*l2++] | *cr_fsptr++ | *cb_fsptr++)]; *o2++ = pixel[(l_darrays4[*l2++] | *cr_fsptr++ | *cb_fsptr++)]; cr_c_err = c_fserr[cr_code][1]; cb_c_err = c_fserr[cb_code][1]; *cr_r_err++ = c_fserr[cr_code][0]; *cb_r_err++ = c_fserr[cb_code][0]; cr_code = (*cr_r_err | cr_c_err | *r++); cb_code = (*cb_r_err | cb_c_err | *b++); cr_fsptr = cr_fsarray[cr_code]; cb_fsptr = cb_fsarray[cb_code]; *o1++ = pixel[(l_darrays2[*l++] | *cr_fsptr++ | *cb_fsptr++)]; *o1++ = pixel[(l_darrays10[*l++] | *cr_fsptr++ | *cb_fsptr++)]; *o2++ = pixel[(l_darrays14[*l2++] | *cr_fsptr++ | *cb_fsptr++)]; *o2++ = pixel[(l_darrays6[*l2++] | *cr_fsptr++ | *cb_fsptr++)]; cr_c_err = c_fserr[cr_code][1]; cb_c_err = c_fserr[cb_code][1]; *cr_r_err++ = c_fserr[cr_code][0]; *cb_r_err++ = c_fserr[cb_code][0]; } l += row_advance; l2 += row_advance; o1 += row_advance; o2 += row_advance; cr_c_err = 0; cb_c_err = 0; cr_r_err--; cb_r_err--; r += half_row_advance; b += half_row_advance; for (j=w; j>0; j-=4) { cr_code = (*cr_r_err | cr_c_err | *r--); cb_code = (*cb_r_err | cb_c_err | *b--); cr_fsptr = cr_fsarray[cr_code]; cb_fsptr = cb_fsarray[cb_code]; *o1-- = pixel[(l_darrays9[*l--] | *cr_fsptr++ | *cb_fsptr++)]; *o1-- = pixel[(l_darrays1[*l--] | *cr_fsptr++ | *cb_fsptr++)]; *o2-- = pixel[(l_darrays5[*l2--] | *cr_fsptr++ | *cb_fsptr++)]; *o2-- = pixel[(l_darrays13[*l2--] | *cr_fsptr++ | *cb_fsptr++)]; cr_c_err = c_fserr[cr_code][1]; cb_c_err = c_fserr[cb_code][1]; *cr_r_err-- = c_fserr[cr_code][0]; *cb_r_err-- = c_fserr[cb_code][0]; cr_code = (*cr_r_err | cr_c_err | *r--); cb_code = (*cb_r_err | cb_c_err | *b--); cr_fsptr = cr_fsarray[cr_code]; cb_fsptr = cb_fsarray[cb_code]; *o1-- = pixel[(l_darrays11[*l--] | *cr_fsptr++ | *cb_fsptr++)]; *o1-- = pixel[(l_darrays3[*l--] | *cr_fsptr++ | *cb_fsptr++)]; *o2-- = pixel[(l_darrays7[*l2--] | *cr_fsptr++ | *cb_fsptr++)]; *o2-- = pixel[(l_darrays15[*l2--] | *cr_fsptr++ | *cb_fsptr++)]; cr_c_err = c_fserr[cr_code][1]; cb_c_err = c_fserr[cb_code][1]; *cr_r_err-- = c_fserr[cr_code][0]; *cb_r_err-- = c_fserr[cb_code][0]; } l += row_advance2; l2 += row_advance2; o1 += row_advance2; o2 += row_advance2; cr_c_err = 0; cb_c_err = 0; cr_r_err++; cb_r_err++; r += half_row_advance2; b += half_row_advance2; } } 255) nval = 255; cr3 = ((nval) * CR_RANGE) / 256; err2 = ((nval) - cr_values[cr3])/2; outerr1 = ((nval) - cr_values[cr3]) - err2; nval = val+err1+err2; if (nval < 0) nval = 0; else if (nval > 255) nval = 255; cr4 = ((nval) * CR_RANGE) / 256; outerr2 = ((nval) - cr_values[cr4])/2; outerr4 = ((nval) - cr_values[cr4])-outerr2; cr_fsajrevdct.c 444 5104 267 126406 5333605254 6037 /* * jrevdct.c * * Copyright (C) 1991, 1992, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains the basic inverse-DCT transformation subroutine. * * This implementation is based on an algorithm described in * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. * The primary algorithm described there uses 11 multiplies and 29 adds. * We use their alternate method with 12 multiplies and 32 adds. * The advantage of this method is that no data path contains more than one * multiplication; this allows a very simple and accurate implementation in * scaled fixed-point arithmetic, with a minimal number of shifts. * * I've made lots of modifications to attempt to take advantage of the * sparse nature of the DCT matrices we're getting. Although the logic * is cumbersome, it's straightforward and the resulting code is much * faster. * * A better way to do this would be to pass in the DCT block as a sparse * matrix, perhaps with the difference cases encoded. */ #include #include "video.h" #include "proto.h" #define GLOBAL /* a function referenced thru EXTERNs */ /* We assume that right shift corresponds to signed division by 2 with * rounding towards minus infinity. This is correct for typical "arithmetic * shift" instructions that shift in copies of the sign bit. But some * C compilers implement >> with an unsigned shift. For these machines you * must define RIGHT_SHIFT_IS_UNSIGNED. * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. * It is only applied with constant shift counts. SHIFT_TEMPS must be * included in the variables of any routine using RIGHT_SHIFT. */ #ifdef RIGHT_SHIFT_IS_UNSIGNED #define SHIFT_TEMPS INT32 shift_temp; #define RIGHT_SHIFT(x,shft) \ ((shift_temp = (x)) < 0 ? \ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ (shift_temp >> (shft))) #else #define SHIFT_TEMPS #define RIGHT_SHIFT(x,shft) ((x) >> (shft)) #endif /* * This routine is specialized to the case DCTSIZE = 8. */ #if DCTSIZE != 8 Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ #endif /* * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT * on each column. Direct algorithms are also available, but they are * much more complex and seem not to be any faster when reduced to code. * * The poop on this scaling stuff is as follows: * * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) * larger than the true IDCT outputs. The final outputs are therefore * a factor of N larger than desired; since N=8 this can be cured by * a simple right shift at the end of the algorithm. The advantage of * this arrangement is that we save two multiplications per 1-D IDCT, * because the y0 and y4 inputs need not be divided by sqrt(N). * * We have to do addition and subtraction of the integer inputs, which * is no problem, and multiplication by fractional constants, which is * a problem to do in integer arithmetic. We multiply all the constants * by CONST_SCALE and convert them to integer constants (thus retaining * CONST_BITS bits of precision in the constants). After doing a * multiplication we have to divide the product by CONST_SCALE, with proper * rounding, to produce the correct output. This division can be done * cheaply as a right shift of CONST_BITS bits. We postpone shifting * as long as possible so that partial sums can be added together with * full fractional precision. * * The outputs of the first pass are scaled up by PASS1_BITS bits so that * they are represented to better-than-integral precision. These outputs * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word * with the recommended scaling. (To scale up 12-bit sample data further, an * intermediate INT32 array would be needed.) * * To avoid overflow of the 32-bit intermediate results in pass 2, we must * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis * shows that the values given below are the most effective. */ #ifdef EIGHT_BIT_SAMPLES #define PASS1_BITS 2 #else #define PASS1_BITS 1 /* lose a little precision to avoid overflow */ #endif #define ONE ((INT32) 1) #define CONST_SCALE (ONE << CONST_BITS) /* Convert a positive real constant to an integer scaled by CONST_SCALE. * IMPORTANT: if your compiler doesn't do this arithmetic at compile time, * you will pay a significant penalty in run time. In that case, figure * the correct integer constant values and insert them by hand. */ #define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) /* Descale and correctly round an INT32 value that's scaled by N bits. * We assume RIGHT_SHIFT rounds towards minus infinity, so adding * the fudge factor is correct for either sign of X. */ #define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) /* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. * For 8-bit samples with the recommended scaling, all the variable * and constant values involved are no more than 16 bits wide, so a * 16x16->32 bit multiply can be used instead of a full 32x32 multiply; * this provides a useful speedup on many machines. * There is no way to specify a 16x16->32 multiply in portable C, but * some C compilers will do the right thing if you provide the correct * combination of casts. * NB: for 12-bit samples, a full 32-bit multiplication will be needed. */ #ifdef EIGHT_BIT_SAMPLES #ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ #define MULTIPLY(var,const) (((INT16) (var)) * ((INT16) (const))) #endif #ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ #define MULTIPLY(var,const) (((INT16) (var)) * ((INT32) (const))) #endif #endif #ifndef MULTIPLY /* default definition */ #define MULTIPLY(var,const) ((var) * (const)) #endif /* Precomputed idct value arrays. */ static DCTELEM PreIDCT[64][64]; /* Pre compute singleton coefficient IDCT values. */ void init_pre_idct() { int i; void j_rev_dct(); for (i=0; i<64; i++) { memset((char *) PreIDCT[i], 0, 64*sizeof(DCTELEM)); PreIDCT[i][i] = 2048; j_rev_dct(PreIDCT[i]); } } #ifndef ORIG_DCT /* * Perform the inverse DCT on one block of coefficients. */ void j_rev_dct_sparse (data, pos) DCTBLOCK data; int pos; { register DCTELEM *dataptr; short int val; DCTELEM *ndataptr; int scale, coeff, rr; register int *dp; register int v; /* If DC Coefficient. */ if (pos == 0) { dp = (int *)data; v = *data; /* Compute 32 bit value to assign. This speeds things up a bit */ if (v < 0) val = (v-3)>>3; else val = (v+4)>>3; v = val | (val << 16); dp[0] = v; dp[1] = v; dp[2] = v; dp[3] = v; dp[4] = v; dp[5] = v; dp[6] = v; dp[7] = v; dp[8] = v; dp[9] = v; dp[10] = v; dp[11] = v; dp[12] = v; dp[13] = v; dp[14] = v; dp[15] = v; dp[16] = v; dp[17] = v; dp[18] = v; dp[19] = v; dp[20] = v; dp[21] = v; dp[22] = v; dp[23] = v; dp[24] = v; dp[25] = v; dp[26] = v; dp[27] = v; dp[28] = v; dp[29] = v; dp[30] = v; dp[31] = v; return; } /* Some other coefficient. */ dataptr = (DCTELEM *)data; coeff = dataptr[pos]; ndataptr = PreIDCT[pos]; for (rr=0; rr<4; rr++) { dataptr[0] = (ndataptr[0] * coeff) >> (CONST_BITS-2); dataptr[1] = (ndataptr[1] * coeff) >> (CONST_BITS-2); dataptr[2] = (ndataptr[2] * coeff) >> (CONST_BITS-2); dataptr[3] = (ndataptr[3] * coeff) >> (CONST_BITS-2); dataptr[4] = (ndataptr[4] * coeff) >> (CONST_BITS-2); dataptr[5] = (ndataptr[5] * coeff) >> (CONST_BITS-2); dataptr[6] = (ndataptr[6] * coeff) >> (CONST_BITS-2); dataptr[7] = (ndataptr[7] * coeff) >> (CONST_BITS-2); dataptr[8] = (ndataptr[8] * coeff) >> (CONST_BITS-2); dataptr[9] = (ndataptr[9] * coeff) >> (CONST_BITS-2); dataptr[10] = (ndataptr[10] * coeff) >> (CONST_BITS-2); dataptr[11] = (ndataptr[11] * coeff) >> (CONST_BITS-2); dataptr[12] = (ndataptr[12] * coeff) >> (CONST_BITS-2); dataptr[13] = (ndataptr[13] * coeff) >> (CONST_BITS-2); dataptr[14] = (ndataptr[14] * coeff) >> (CONST_BITS-2); dataptr[15] = (ndataptr[15] * coeff) >> (CONST_BITS-2); dataptr += 16; ndataptr += 16; } return; } void j_rev_dct (data) DCTBLOCK data; { INT32 tmp0, tmp1, tmp2, tmp3; INT32 tmp10, tmp11, tmp12, tmp13; INT32 z1, z2, z3, z4, z5; INT32 d0, d1, d2, d3, d4, d5, d6, d7; register DCTELEM *dataptr; int rowctr; SHIFT_TEMPS /* Pass 1: process rows. */ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ /* furthermore, we scale the results by 2**PASS1_BITS. */ dataptr = data; for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { /* Due to quantization, we will usually find that many of the input * coefficients are zero, especially the AC terms. We can exploit this * by short-circuiting the IDCT calculation for any row in which all * the AC terms are zero. In that case each output is equal to the * DC coefficient (with scale factor as needed). * With typical images and quantization tables, half or more of the * row DCT calculations can be simplified this way. */ register int *idataptr = (int*)dataptr; d0 = dataptr[0]; d1 = dataptr[1]; if ((d1 == 0) && (idataptr[1] | idataptr[2] | idataptr[3]) == 0) { /* AC terms all zero */ if (d0) { /* Compute a 32 bit value to assign. */ DCTELEM dcval = (DCTELEM) (d0 << PASS1_BITS); register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000); idataptr[0] = v; idataptr[1] = v; idataptr[2] = v; idataptr[3] = v; } dataptr += DCTSIZE; /* advance pointer to next row */ continue; } d2 = dataptr[2]; d3 = dataptr[3]; d4 = dataptr[4]; d5 = dataptr[5]; d6 = dataptr[6]; d7 = dataptr[7]; /* Even part: reverse the even part of the forward DCT. */ /* The rotator is sqrt(2)*c(-6). */ if (d6) { if (d4) { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } else { if (d0) { /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ tmp2 = MULTIPLY(d6, -FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } } else { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } else { if (d0) { /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } } } else { if (d4) { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } else { if (d0) { /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ tmp10 = tmp13 = (d0 + d4) << CONST_BITS; tmp11 = tmp12 = (d0 - d4) << CONST_BITS; } else { /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ tmp10 = tmp13 = d4 << CONST_BITS; tmp11 = tmp12 = -tmp10; } } } else { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } else { if (d0) { /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; } else { /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ tmp10 = tmp13 = tmp11 = tmp12 = 0; } } } } /* Odd part per figure 8; the matrix is unitary and hence its * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ if (d7) { if (d5) { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ z1 = d7 + d1; z2 = d5 + d3; z3 = d7 + d3; z4 = d5 + d1; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ z1 = d7; z2 = d5 + d3; z3 = d7 + d3; z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); z1 = MULTIPLY(d7, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 = z1 + z4; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ z1 = d7 + d1; z2 = d5; z3 = d7; z4 = d5 + d1; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z3 = MULTIPLY(d7, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 = z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ tmp0 = MULTIPLY(d7, - FIX(0.601344887)); z1 = MULTIPLY(d7, - FIX(0.899976223)); z3 = MULTIPLY(d7, - FIX(1.961570560)); tmp1 = MULTIPLY(d5, - FIX(0.509795578)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z5 = MULTIPLY(d5 + d7, FIX(1.175875602)); z3 += z5; z4 += z5; tmp0 += z3; tmp1 += z4; tmp2 = z2 + z3; tmp3 = z1 + z4; } } } else { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ z1 = d7 + d1; z3 = d7 + d3; z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(d3, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(d1, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 = z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ z3 = d7 + d3; tmp0 = MULTIPLY(d7, - FIX(0.601344887)); z1 = MULTIPLY(d7, - FIX(0.899976223)); tmp2 = MULTIPLY(d3, FIX(0.509795579)); z2 = MULTIPLY(d3, - FIX(2.562915447)); z5 = MULTIPLY(z3, FIX(1.175875602)); z3 = MULTIPLY(z3, - FIX(0.785694958)); tmp0 += z3; tmp1 = z2 + z5; tmp2 += z3; tmp3 = z1 + z5; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ z1 = d7 + d1; z5 = MULTIPLY(z1, FIX(1.175875602)); z1 = MULTIPLY(z1, FIX(0.275899379)); z3 = MULTIPLY(d7, - FIX(1.961570560)); tmp0 = MULTIPLY(d7, - FIX(1.662939224)); z4 = MULTIPLY(d1, - FIX(0.390180644)); tmp3 = MULTIPLY(d1, FIX(1.111140466)); tmp0 += z1; tmp1 = z4 + z5; tmp2 = z3 + z5; tmp3 += z1; } else { /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ tmp0 = MULTIPLY(d7, - FIX(1.387039845)); tmp1 = MULTIPLY(d7, FIX(1.175875602)); tmp2 = MULTIPLY(d7, - FIX(0.785694958)); tmp3 = MULTIPLY(d7, FIX(0.275899379)); } } } } else { if (d5) { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ z2 = d5 + d3; z4 = d5 + d1; z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(d1, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(d3, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 = z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ z2 = d5 + d3; z5 = MULTIPLY(z2, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(1.662939225)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z2 = MULTIPLY(z2, - FIX(1.387039845)); tmp2 = MULTIPLY(d3, FIX(1.111140466)); z3 = MULTIPLY(d3, - FIX(1.961570560)); tmp0 = z3 + z5; tmp1 += z2; tmp2 += z2; tmp3 = z4 + z5; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ z4 = d5 + d1; z5 = MULTIPLY(z4, FIX(1.175875602)); z1 = MULTIPLY(d1, - FIX(0.899976223)); tmp3 = MULTIPLY(d1, FIX(0.601344887)); tmp1 = MULTIPLY(d5, - FIX(0.509795578)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z4 = MULTIPLY(z4, FIX(0.785694958)); tmp0 = z1 + z5; tmp1 += z4; tmp2 = z2 + z5; tmp3 += z4; } else { /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ tmp0 = MULTIPLY(d5, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(0.275899380)); tmp2 = MULTIPLY(d5, - FIX(1.387039845)); tmp3 = MULTIPLY(d5, FIX(0.785694958)); } } } else { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ z5 = d1 + d3; tmp3 = MULTIPLY(d1, FIX(0.211164243)); tmp2 = MULTIPLY(d3, - FIX(1.451774981)); z1 = MULTIPLY(d1, FIX(1.061594337)); z2 = MULTIPLY(d3, - FIX(2.172734803)); z4 = MULTIPLY(z5, FIX(0.785694958)); z5 = MULTIPLY(z5, FIX(1.175875602)); tmp0 = z1 - z4; tmp1 = z2 + z4; tmp2 += z5; tmp3 += z5; } else { /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ tmp0 = MULTIPLY(d3, - FIX(0.785694958)); tmp1 = MULTIPLY(d3, - FIX(1.387039845)); tmp2 = MULTIPLY(d3, - FIX(0.275899379)); tmp3 = MULTIPLY(d3, FIX(1.175875602)); } } else { if (d1) { /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ tmp0 = MULTIPLY(d1, FIX(0.275899379)); tmp1 = MULTIPLY(d1, FIX(0.785694958)); tmp2 = MULTIPLY(d1, FIX(1.175875602)); tmp3 = MULTIPLY(d1, FIX(1.387039845)); } else { /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ tmp0 = tmp1 = tmp2 = tmp3 = 0; } } } } /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); dataptr += DCTSIZE; /* advance pointer to next row */ } /* Pass 2: process columns. */ /* Note that we must descale the results by a factor of 8 == 2**3, */ /* and also undo the PASS1_BITS scaling. */ dataptr = data; for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { /* Columns of zeroes can be exploited in the same way as we did with rows. * However, the row calculation has created many nonzero AC terms, so the * simplification applies less often (typically 5% to 10% of the time). * On machines with very fast multiplication, it's possible that the * test takes more time than it's worth. In that case this section * may be commented out. */ d0 = dataptr[DCTSIZE*0]; d1 = dataptr[DCTSIZE*1]; d2 = dataptr[DCTSIZE*2]; d3 = dataptr[DCTSIZE*3]; d4 = dataptr[DCTSIZE*4]; d5 = dataptr[DCTSIZE*5]; d6 = dataptr[DCTSIZE*6]; d7 = dataptr[DCTSIZE*7]; /* Even part: reverse the even part of the forward DCT. */ /* The rotator is sqrt(2)*c(-6). */ if (d6) { if (d4) { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } else { if (d0) { /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ tmp2 = MULTIPLY(d6, -FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } } else { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } else { if (d0) { /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ tmp2 = MULTIPLY(d6, - FIX(1.306562965)); tmp3 = MULTIPLY(d6, FIX(0.541196100)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } } } else { if (d4) { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = (d0 + d4) << CONST_BITS; tmp1 = (d0 - d4) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; } else { /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = d4 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp2 - tmp0; tmp12 = -(tmp0 + tmp2); } } else { if (d0) { /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ tmp10 = tmp13 = (d0 + d4) << CONST_BITS; tmp11 = tmp12 = (d0 - d4) << CONST_BITS; } else { /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ tmp10 = tmp13 = d4 << CONST_BITS; tmp11 = tmp12 = -tmp10; } } } else { if (d2) { if (d0) { /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp0 = d0 << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp0 + tmp2; tmp12 = tmp0 - tmp2; } else { /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ tmp2 = MULTIPLY(d2, FIX(0.541196100)); tmp3 = MULTIPLY(d2, FIX(1.306562965)); tmp10 = tmp3; tmp13 = -tmp3; tmp11 = tmp2; tmp12 = -tmp2; } } else { if (d0) { /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; } else { /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ tmp10 = tmp13 = tmp11 = tmp12 = 0; } } } } /* Odd part per figure 8; the matrix is unitary and hence its * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ if (d7) { if (d5) { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ z1 = d7 + d1; z2 = d5 + d3; z3 = d7 + d3; z4 = d5 + d1; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ z1 = d7; z2 = d5 + d3; z3 = d7 + d3; z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); z1 = MULTIPLY(d7, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 = z1 + z4; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ z1 = d7 + d1; z2 = d5; z3 = d7; z4 = d5 + d1; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z3 = MULTIPLY(d7, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 = z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ tmp0 = MULTIPLY(d7, - FIX(0.601344887)); z1 = MULTIPLY(d7, - FIX(0.899976223)); z3 = MULTIPLY(d7, - FIX(1.961570560)); tmp1 = MULTIPLY(d5, - FIX(0.509795578)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z5 = MULTIPLY(d5 + d7, FIX(1.175875602)); z3 += z5; z4 += z5; tmp0 += z3; tmp1 += z4; tmp2 = z2 + z3; tmp3 = z1 + z4; } } } else { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ z1 = d7 + d1; z3 = d7 + d3; z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); tmp0 = MULTIPLY(d7, FIX(0.298631336)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(z1, - FIX(0.899976223)); z2 = MULTIPLY(d3, - FIX(2.562915447)); z3 = MULTIPLY(z3, - FIX(1.961570560)); z4 = MULTIPLY(d1, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 = z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ z3 = d7 + d3; tmp0 = MULTIPLY(d7, - FIX(0.601344887)); z1 = MULTIPLY(d7, - FIX(0.899976223)); tmp2 = MULTIPLY(d3, FIX(0.509795579)); z2 = MULTIPLY(d3, - FIX(2.562915447)); z5 = MULTIPLY(z3, FIX(1.175875602)); z3 = MULTIPLY(z3, - FIX(0.785694958)); tmp0 += z3; tmp1 = z2 + z5; tmp2 += z3; tmp3 = z1 + z5; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ z1 = d7 + d1; z5 = MULTIPLY(z1, FIX(1.175875602)); z1 = MULTIPLY(z1, FIX(0.275899379)); z3 = MULTIPLY(d7, - FIX(1.961570560)); tmp0 = MULTIPLY(d7, - FIX(1.662939224)); z4 = MULTIPLY(d1, - FIX(0.390180644)); tmp3 = MULTIPLY(d1, FIX(1.111140466)); tmp0 += z1; tmp1 = z4 + z5; tmp2 = z3 + z5; tmp3 += z1; } else { /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ tmp0 = MULTIPLY(d7, - FIX(1.387039845)); tmp1 = MULTIPLY(d7, FIX(1.175875602)); tmp2 = MULTIPLY(d7, - FIX(0.785694958)); tmp3 = MULTIPLY(d7, FIX(0.275899379)); } } } } else { if (d5) { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ z2 = d5 + d3; z4 = d5 + d1; z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(2.053119869)); tmp2 = MULTIPLY(d3, FIX(3.072711026)); tmp3 = MULTIPLY(d1, FIX(1.501321110)); z1 = MULTIPLY(d1, - FIX(0.899976223)); z2 = MULTIPLY(z2, - FIX(2.562915447)); z3 = MULTIPLY(d3, - FIX(1.961570560)); z4 = MULTIPLY(z4, - FIX(0.390180644)); z3 += z5; z4 += z5; tmp0 = z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; } else { /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ z2 = d5 + d3; z5 = MULTIPLY(z2, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(1.662939225)); z4 = MULTIPLY(d5, - FIX(0.390180644)); z2 = MULTIPLY(z2, - FIX(1.387039845)); tmp2 = MULTIPLY(d3, FIX(1.111140466)); z3 = MULTIPLY(d3, - FIX(1.961570560)); tmp0 = z3 + z5; tmp1 += z2; tmp2 += z2; tmp3 = z4 + z5; } } else { if (d1) { /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ z4 = d5 + d1; z5 = MULTIPLY(z4, FIX(1.175875602)); z1 = MULTIPLY(d1, - FIX(0.899976223)); tmp3 = MULTIPLY(d1, FIX(0.601344887)); tmp1 = MULTIPLY(d5, - FIX(0.509795578)); z2 = MULTIPLY(d5, - FIX(2.562915447)); z4 = MULTIPLY(z4, FIX(0.785694958)); tmp0 = z1 + z5; tmp1 += z4; tmp2 = z2 + z5; tmp3 += z4; } else { /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ tmp0 = MULTIPLY(d5, FIX(1.175875602)); tmp1 = MULTIPLY(d5, FIX(0.275899380)); tmp2 = MULTIPLY(d5, - FIX(1.387039845)); tmp3 = MULTIPLY(d5, FIX(0.785694958)); } } } else { if (d3) { if (d1) { /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ z5 = d1 + d3; tmp3 = MULTIPLY(d1, FIX(0.211164243)); tmp2 = MULTIPLY(d3, - FIX(1.451774981)); z1 = MULTIPLY(d1, FIX(1.061594337)); z2 = MULTIPLY(d3, - FIX(2.172734803)); z4 = MULTIPLY(z5, FIX(0.785694958)); z5 = MULTIPLY(z5, FIX(1.175875602)); tmp0 = z1 - z4; tmp1 = z2 + z4; tmp2 += z5; tmp3 += z5; } else { /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ tmp0 = MULTIPLY(d3, - FIX(0.785694958)); tmp1 = MULTIPLY(d3, - FIX(1.387039845)); tmp2 = MULTIPLY(d3, - FIX(0.275899379)); tmp3 = MULTIPLY(d3, FIX(1.175875602)); } } else { if (d1) { /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ tmp0 = MULTIPLY(d1, FIX(0.275899379)); tmp1 = MULTIPLY(d1, FIX(0.785694958)); tmp2 = MULTIPLY(d1, FIX(1.175875602)); tmp3 = MULTIPLY(d1, FIX(1.387039845)); } else { /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ tmp0 = tmp1 = tmp2 = tmp3 = 0; } } } } /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS+PASS1_BITS+3); dataptr++; /* advance pointer to next column */ } } #else void j_rev_dct_sparse (data, pos) DCTBLOCK data; int pos; { j_rev_dct(data); } void j_rev_dct (data) DCTBLOCK data; { INT32 tmp0, tmp1, tmp2, tmp3; INT32 tmp10, tmp11, tmp12, tmp13; INT32 z1, z2, z3, z4, z5; register DCTELEM *dataptr; int rowctr; SHIFT_TEMPS /* Pass 1: process rows. */ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ /* furthermore, we scale the results by 2**PASS1_BITS. */ dataptr = data; for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { /* Due to quantization, we will usually find that many of the input * coefficients are zero, especially the AC terms. We can exploit this * by short-circuiting the IDCT calculation for any row in which all * the AC terms are zero. In that case each output is equal to the * DC coefficient (with scale factor as needed). * With typical images and quantization tables, half or more of the * row DCT calculations can be simplified this way. */ if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] | dataptr[5] | dataptr[6] | dataptr[7]) == 0) { /* AC terms all zero */ DCTELEM dcval = (DCTELEM) (dataptr[0] << PASS1_BITS); dataptr[0] = dcval; dataptr[1] = dcval; dataptr[2] = dcval; dataptr[3] = dcval; dataptr[4] = dcval; dataptr[5] = dcval; dataptr[6] = dcval; dataptr[7] = dcval; dataptr += DCTSIZE; /* advance pointer to next row */ continue; } /* Even part: reverse the even part of the forward DCT. */ /* The rotator is sqrt(2)*c(-6). */ z2 = (INT32) dataptr[2]; z3 = (INT32) dataptr[6]; z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); tmp0 = ((INT32) dataptr[0] + (INT32) dataptr[4]) << CONST_BITS; tmp1 = ((INT32) dataptr[0] - (INT32) dataptr[4]) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; /* Odd part per figure 8; the matrix is unitary and hence its * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ tmp0 = (INT32) dataptr[7]; tmp1 = (INT32) dataptr[5]; tmp2 = (INT32) dataptr[3]; tmp3 = (INT32) dataptr[1]; z1 = tmp0 + tmp3; z2 = tmp1 + tmp2; z3 = tmp0 + tmp2; z4 = tmp1 + tmp3; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); dataptr += DCTSIZE; /* advance pointer to next row */ } /* Pass 2: process columns. */ /* Note that we must descale the results by a factor of 8 == 2**3, */ /* and also undo the PASS1_BITS scaling. */ dataptr = data; for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { /* Columns of zeroes can be exploited in the same way as we did with rows. * However, the row calculation has created many nonzero AC terms, so the * simplification applies less often (typically 5% to 10% of the time). * On machines with very fast multiplication, it's possible that the * test takes more time than it's worth. In that case this section * may be commented out. */ #ifndef NO_ZERO_COLUMN_TEST if ((dataptr[DCTSIZE*1] | dataptr[DCTSIZE*2] | dataptr[DCTSIZE*3] | dataptr[DCTSIZE*4] | dataptr[DCTSIZE*5] | dataptr[DCTSIZE*6] | dataptr[DCTSIZE*7]) == 0) { /* AC terms all zero */ DCTELEM dcval = (DCTELEM) DESCALE((INT32) dataptr[0], PASS1_BITS+3); dataptr[DCTSIZE*0] = dcval; dataptr[DCTSIZE*1] = dcval; dataptr[DCTSIZE*2] = dcval; dataptr[DCTSIZE*3] = dcval; dataptr[DCTSIZE*4] = dcval; dataptr[DCTSIZE*5] = dcval; dataptr[DCTSIZE*6] = dcval; dataptr[DCTSIZE*7] = dcval; dataptr++; /* advance pointer to next column */ continue; } #endif /* Even part: reverse the even part of the forward DCT. */ /* The rotator is sqrt(2)*c(-6). */ z2 = (INT32) dataptr[DCTSIZE*2]; z3 = (INT32) dataptr[DCTSIZE*6]; z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); tmp0 = ((INT32) dataptr[DCTSIZE*0] + (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; tmp1 = ((INT32) dataptr[DCTSIZE*0] - (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; /* Odd part per figure 8; the matrix is unitary and hence its * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. */ tmp0 = (INT32) dataptr[DCTSIZE*7]; tmp1 = (INT32) dataptr[DCTSIZE*5]; tmp2 = (INT32) dataptr[DCTSIZE*3]; tmp3 = (INT32) dataptr[DCTSIZE*1]; z1 = tmp0 + tmp3; z2 = tmp1 + tmp2; z3 = tmp0 + tmp2; z4 = tmp1 + tmp3; z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ z3 += z5; z4 += z5; tmp0 += z1 + z3; tmp1 += z2 + z4; tmp2 += z2 + z3; tmp3 += z1 + z4; /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS+PASS1_BITS+3); dataptr++; /* advance pointer to next column */ } } #endif S1_BITS+3); dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS+PASS1_BITS+3); dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0,main.c 444 5104 267 32257 5333605254 5302 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "proto.h" #include #include #ifndef MIPS #include #else #include #endif #include "util.h" #include "dither.h" /* Define buffer length. */ #define BUF_LENGTH 80000 /* Function return type declarations */ void usage(); /* External declaration of main decoding call. */ extern VidStream *mpegVidRsrc(); extern VidStream *NewVidStream(); /* Declaration of global variable to hold dither info. */ int ditherType; /* Global file pointer to incoming data. */ FILE *input; /* End of File flag. */ static int EOF_flag = 0; /* Loop flag. */ int loopFlag = 0; /* Shared memory flag. */ int shmemFlag = 0; /* Quiet flag. */ int quietFlag = 0; /* Display image on screen? */ int noDisplayFlag = 0; /* Setjmp/Longjmp env. */ jmp_buf env; /* *-------------------------------------------------------------- * * get_more_data -- * * Called by correct_underflow in bit parsing utilities to * read in more data. * * Results: * Input buffer updated, buffer length updated. * Returns 1 if data read, 0 if EOF, -1 if error. * * Side effects: * None. * *-------------------------------------------------------------- */ int get_more_data(buf_start, max_length, length_ptr, buf_ptr) unsigned int *buf_start; int max_length; int *length_ptr; unsigned int **buf_ptr; { int length, num_read, i, request; unsigned char *buffer, *mark; unsigned int *lmark; if (EOF_flag) return 0; length = *length_ptr; buffer = (unsigned char *) *buf_ptr; if (length > 0) { memcpy((unsigned char *) buf_start, buffer, (length*4)); mark = ((unsigned char *) (buf_start + length)); } else { mark = (unsigned char *) buf_start; length = 0; } request = (max_length-length)*4; num_read = fread( mark, 1, request, input); /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */ { int num_read_rounded; unsigned char *index; num_read_rounded = 4*(num_read/4); /* this can happen only if num_readh_size*i, curVidStream->v_size*i); realTimeStart = ReadSysClock(); while (1) mpegVidRsrc(0, theStream); } /* *-------------------------------------------------------------- * * usage -- * * Print mpeg_play usage * * Results: * None. * * Side effects: * exits with a return value -1 * *-------------------------------------------------------------- */ void usage(s) char *s; /* program name */ { fprintf(stderr, "Usage:\n"); fprintf(stderr, "mpeg_play\n"); fprintf(stderr, " [-nob]\n"); fprintf(stderr, " [-nop]\n"); fprintf(stderr, " [-dither {ordered|ordered2|mbordered|fs4|fs2|fs2fast|hybrid|\n"); fprintf(stderr, " hybrid2|2x2|gray|color|none|mono|threshold}]\n"); fprintf(stderr, " [-loop]\n"); fprintf(stderr, " [-eachstat]\n"); fprintf(stderr, " [-no_display]\n"); fprintf(stderr, " [-quiet]\n"); fprintf(stderr, " file_name\n"); exit (-1); } /* *-------------------------------------------------------------- * * DoDitherImage -- * * Called when image needs to be dithered. Selects correct * dither routine based on info in ditherType. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DoDitherImage(l, Cr, Cb, disp, h, w) unsigned char *l, *Cr, *Cb, *disp; int h,w; { switch(ditherType) { case HYBRID_DITHER: HybridDitherImage(l, Cr, Cb, disp, h, w); break; case HYBRID2_DITHER: HybridErrorDitherImage(l, Cr, Cb, disp, h, w); break; case FS2FAST_DITHER: FS2FastDitherImage(l, Cr, Cb, disp, h, w); break; case FS2_DITHER: FS2DitherImage(l, Cr, Cb, disp, h, w); break; case FS4_DITHER: FS4DitherImage(l, Cr, Cb, disp, h, w); break; case Twox2_DITHER: Twox2DitherImage(l, Cr, Cb, disp, h, w); break; case FULL_COLOR_DITHER: ColorDitherImage(l, Cr, Cb, disp, h, w); break; case GRAY_DITHER: GrayDitherImage(l, Cr, Cb, disp, h, w); break; case NO_DITHER: break; case ORDERED_DITHER: OrderedDitherImage(l, Cr, Cb, disp, h, w); break; case MONO_DITHER: MonoDitherImage(l, Cr, Cb, disp, h, w); break; case MONO_THRESHOLD: MonoThresholdImage(l, Cr, Cb, disp, h, w); break; case ORDERED2_DITHER: Ordered2DitherImage(l, Cr, Cb, disp, h, w); break; case MBORDERED_DITHER: MBOrderedDitherImage(l, Cr, Cb, disp, h, w); break; } } = GRAY_DITHER; } else if (strcmp(argv[mark], "color") == 0) { argc--; mark++; ditherType = FULL_COLOR_DITHER; } else if (strcmp(argv[mark], "none") == 0) { argc--; mark++; ditherType = NO_DITHER; } else if (strcmp(argv[mark], "ordered") == 0) { argc--; mark++; ditherType = ORDERED_DITHER; } else if (strcmpmb_ordered.c 444 5104 267 27443 5333605254 6461 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* This file contains C code to implement an ordered dither. */ #include "video.h" #include "proto.h" #include "dither.h" #define DITH_SIZE 16 /* Structures used to implement macroblock ordered dither algorithm. */ static unsigned char ***ditherPtr[DITH_SIZE]; /* *-------------------------------------------------------------- * * InitMBOrderedDither-- * * Structures intialized for ordered dithering. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitMBOrderedDither() { unsigned char ****pos_2_cb; unsigned char ***cb_2_cr; unsigned char **cr_2_l; int cb_val, cb_rval, cr_val, cr_rval, l_val, l_rval; int i, j, pos; int err_range, threshval; pos_2_cb = (unsigned char ****) malloc (DITH_SIZE*sizeof(unsigned char ***)); cb_2_cr = (unsigned char ***) malloc(CB_RANGE*sizeof(unsigned char **)); cr_2_l = (unsigned char **) malloc(CR_RANGE*sizeof(unsigned char *)); for (pos=0; posthreshval) (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval+1]; else (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval]; } } for (cb_val=cb_values[CB_RANGE-1]; cb_val<256; cb_val++) { (pos_2_cb[pos])[cb_val] = cb_2_cr[CB_RANGE-1]; } for (cb_rval=0; cb_rvalthreshval) (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval+1]; else (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval]; } } for (cr_val=cr_values[CR_RANGE-1]; cr_val<256; cr_val++) { (cb_2_cr[cb_rval])[cr_val] = cr_2_l[CR_RANGE-1]; } for (cr_rval=0; cr_rvalthreshval) (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+((l_rval+1)*CR_RANGE*CB_RANGE)]; else (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+(l_rval*CR_RANGE*CB_RANGE)]; } } for (l_val = lum_values[LUM_RANGE-1]; l_val < 256; l_val++) { (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+((LUM_RANGE-1)*CR_RANGE*CB_RANGE)]; } } } } for (i=0; imb_width) << 4; col = (mb_addr % vid_stream->mb_width) << 4; row_size = vid_stream->mb_width << 4; dest = vid_stream->current->display + (row * row_size) + col; if (motion_forw) { right_forw = r_right_forw >> 1; down_forw = r_down_forw >> 1; src1 = past + ((row + down_forw) * row_size) + (col + right_forw); } if (motion_back) { right_back = r_right_back >> 1; down_back = r_down_back >> 1; src2 = future + ((row + down_back) * row_size) + (col + right_back); } if (motion_forw) { if (motion_back) { for (rr = 0; rr<16; rr++) { dest[0] = src1[0]; dest[1] = src2[1]; dest[2] = src1[2]; dest[3] = src2[3]; dest[4] = src1[4]; dest[5] = src2[5]; dest[6] = src1[6]; dest[7] = src2[7]; dest[8] = src1[8]; dest[9] = src2[9]; dest[10] = src1[10]; dest[11] = src2[11]; dest[12] = src1[12]; dest[13] = src2[13]; dest[14] = src1[14]; dest[15] = src2[15]; dest += row_size; src1 += row_size; src2 += row_size; } } else { mc = col & 0x3; mr = right_forw & 0x3; if (!mc && !mr) { /* Use 32 bit copy */ int *d, *s; d = (int *) dest; s = (int *) src1; row_size /= 4; for (rr = 0; rr < 16; rr++) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d += row_size; s += row_size; } } else if ((!mc || (mc == 2)) && (!mr || (mr == 2))) { /* Use 16 bit copy */ short int *d, * s; d = (short int *) dest; s = (short int *) src1; row_size /= 2; for (rr = 0; rr < 16; rr++) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = s[4]; d[5] = s[5]; d[6] = s[6]; d[7] = s[7]; d += row_size; s += row_size; } } else { for (rr = 0; rr < 16; rr++) { dest[0] = src1[0]; dest[1] = src1[1]; dest[2] = src1[2]; dest[3] = src1[3]; dest[4] = src1[4]; dest[5] = src1[5]; dest[6] = src1[6]; dest[7] = src1[7]; dest[8] = src1[8]; dest[9] = src1[9]; dest[10] = src1[10]; dest[11] = src1[11]; dest[12] = src1[12]; dest[13] = src1[13]; dest[14] = src1[14]; dest[15] = src1[15]; dest += row_size; src1 += row_size; } } } } else if (motion_back) { mc = col & 0x3; mr = right_back & 0x3; if (!mc && !mr) { /* Use 32 bit copy */ int *d, *s; d = (int *) dest; s = (int *) src2; row_size /= 4; for (rr = 0; rr < 16; rr++) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d += row_size; s += row_size; } } else if ((!mc || mc == 2) && (!mr || mr == 2)) { /* Use 8 bit copy */ short int *d, *s; d = (short int *) dest; s = (short int *) src2; row_size /= 2; for (rr = 0; rr < 16; rr++) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = s[4]; d[5] = s[5]; d[6] = s[6]; d[7] = s[7]; d += row_size; s += row_size; } } else { for (rr = 0; rr < 16; rr++) { /* Use 8 bit copy */ dest[0] = src2[0]; dest[1] = src2[1]; dest[2] = src2[2]; dest[3] = src2[3]; dest[4] = src2[4]; dest[5] = src2[5]; dest[6] = src2[6]; dest[7] = src2[7]; dest[8] = src2[8]; dest[9] = src2[9]; dest[10] = src2[10]; dest[11] = src2[11]; dest[12] = src2[12]; dest[13] = src2[13]; dest[14] = src2[14]; dest[15] = src2[15]; dest += row_size; src2 += row_size; } } } } el[cb_rval+(cr_rval*CB_RANGE)+ (0*CR_RANGE*CB_RANGE)]; } for (l_rval=0; l_rval<(LUM_RANGE-1); l_rval++) { err_range = lum_values[l_rval+1] - lum_values[l_rval]; threshval = ((pos*err_range) /DITH_SIZE) +mono.c 444 5104 267 11243 5333605255 5317 /* * Author: Yoichiro Ueno (ueno@cs.titech.ac.jp) * * Copyright (C) 1991, 1992, Yoichiro Ueno. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose is hereby granted by the Author without * fee, provided that the above copyright notice appear in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation, and that the name of the Author not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The Author makes no * representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. * * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ #include "video.h" #include "proto.h" #include "dither.h" /* *-------------------------------------------------------------- * * MonoDitherImage -- * * Dithers image into monochrome. * Dither algorithm is based on dither.c in xli.1.11. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ #define MaxGrey 65280 #define Threshold (MaxGrey/2) #define MinGrey 0 #if ultrix && mips # define SEED_BIT 0x01 # define OPP_SEED_BIT 0x80 # define SHIFT_SEED_BIT(b) (b <<= 1) # define OPP_SHIFT_SEED_BIT(b) (b >>= 1) #else # define SEED_BIT 0x80 # define OPP_SEED_BIT 0x01 # define SHIFT_SEED_BIT(b) (b >>= 1) # define OPP_SHIFT_SEED_BIT(b) (b <<= 1) #endif static int *curr = NULL; static int *next = NULL; void MonoDitherImage(lum, cr, cb, out, h, w) register unsigned char *lum; unsigned char *cr; unsigned char *cb; register unsigned char *out; int w, h; { int bit_r2l; register unsigned int bit; register unsigned int data; int i; register int j; int *swap; register int out_err; register int next1; register int next2; if(curr == NULL) { curr = (int *)malloc(sizeof(int) * (w + 2)); curr += 1; } if(next == NULL) { next = (int *)malloc(sizeof(int) * (w + 2)); next += 1; } bzero ((char *)curr, w * sizeof(*curr)); bit_r2l = SEED_BIT << (w - 1 & 7); for(i = 0; i < h; i ++) { if(i & 0x01) { /* Right to Left */ bit = bit_r2l; data = 0; out_err = curr[w-1]; next1 = 0; next2 = 0; for (j=(w-1); j>=0; j--) { out_err = (out_err >> 4) + (lum[j] << 8); if(out_err > Threshold) { data |= bit; out_err -= MaxGrey; } else out_err -= MinGrey; next[j+1] = next1 + (out_err * 3); next1 = next2 + (out_err * 5); next2 = (out_err * 1); out_err = curr[j-1] + (out_err * 7); OPP_SHIFT_SEED_BIT(bit); #if ultrix && mips if(bit == 0) { #else if(bit > 0x80) { #endif out[j >> 3] = data; bit = OPP_SEED_BIT; data = 0; } } next[0] = next1; } else { /* Left to Right */ bit = SEED_BIT; data = 0; out_err = curr[0]; next1 = 0; next2 = 0; for (j=0; j> 4) + (lum[j] << 8); if(out_err > Threshold) { data |= bit; out_err = out_err - MaxGrey; } else out_err = out_err - MinGrey; next[j-1] = next1 + (out_err * 3); next1 = next2 + (out_err * 5); next2 = (out_err * 1); out_err = curr[j+1] + (out_err * 7); SHIFT_SEED_BIT(bit); #if ultrix && mips if(bit > 0x80) { #else if(bit == 0) { #endif out[j >> 3] = data; bit = SEED_BIT; data = 0; } } next[w-1] = next1; } lum += w; out += w >> 3; swap = curr; curr = next; next = swap; } } /* *-------------------------------------------------------------- * * MonoThresholdImage -- * * convert image into monochrome with threshold. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void MonoThresholdImage(lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { unsigned char bit; unsigned char data; bit = SEED_BIT; data = 0; for (w*=h; w>0; w--) { if(*lum++>128) data |= bit; SHIFT_SEED_BIT(bit); if(bit == 0) { *out ++ = data; bit = SEED_BIT; data = 0; } } } re and * its documentation for any purpose is hereby granted by the Author without * fee, provided that the above copyright notice appear in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation, and that the name of the Author not be used * in advertising or publicity pertaining to dimotionvector.c 444 5104 267 13664 5333605255 7110 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "video.h" #include "proto.h" #include "util.h" /* *-------------------------------------------------------------- * * ComputeVector -- * * Computes motion vector given parameters previously parsed * and reconstructed. * * Results: * Reconstructed motion vector info is put into recon_* parameters * passed to this function. Also updated previous motion vector * information. * * Side effects: * None. * *-------------------------------------------------------------- */ #define ComputeVector(recon_right_ptr, recon_down_ptr, recon_right_prev, recon_down_prev, f, full_pel_vector, motion_h_code, motion_v_code, motion_h_r, motion_v_r) \ \ { \ int comp_h_r, comp_v_r; \ int right_little, right_big, down_little, down_big; \ int max, min, new_vector; \ \ /* The following procedure for the reconstruction of motion vectors \ is a direct and simple implementation of the instructions given \ in the mpeg December 1991 standard draft. \ */ \ \ if (f == 1 || motion_h_code == 0) \ comp_h_r = 0; \ else \ comp_h_r = f - 1 - motion_h_r; \ \ if (f == 1 || motion_v_code == 0) \ comp_v_r = 0; \ else \ comp_v_r = f - 1 - motion_v_r; \ \ right_little = motion_h_code * f; \ if (right_little == 0) \ right_big = 0; \ else { \ if (right_little > 0) { \ right_little = right_little - comp_h_r; \ right_big = right_little - 32 * f; \ } \ else { \ right_little = right_little + comp_h_r; \ right_big = right_little + 32 * f; \ } \ } \ \ down_little = motion_v_code * f; \ if (down_little == 0) \ down_big = 0; \ else { \ if (down_little > 0) { \ down_little = down_little - comp_v_r; \ down_big = down_little - 32 * f; \ } \ else { \ down_little = down_little + comp_v_r; \ down_big = down_little + 32 * f; \ } \ } \ \ max = 16 * f - 1; \ min = -16 * f; \ \ new_vector = recon_right_prev + right_little; \ \ if (new_vector <= max && new_vector >= min) \ *recon_right_ptr = recon_right_prev + right_little; \ /* just new_vector */ \ else \ *recon_right_ptr = recon_right_prev + right_big; \ recon_right_prev = *recon_right_ptr; \ if (full_pel_vector) \ *recon_right_ptr = *recon_right_ptr << 1; \ \ new_vector = recon_down_prev + down_little; \ if (new_vector <= max && new_vector >= min) \ *recon_down_ptr = recon_down_prev + down_little; \ /* just new_vector */ \ else \ *recon_down_ptr = recon_down_prev + down_big; \ recon_down_prev = *recon_down_ptr; \ if (full_pel_vector) \ *recon_down_ptr = *recon_down_ptr << 1; \ } /* *-------------------------------------------------------------- * * ComputeForwVector -- * * Computes forward motion vector by calling ComputeVector * with appropriate parameters. * * Results: * Reconstructed motion vector placed in recon_right_for_ptr and * recon_down_for_ptr. * * Side effects: * None. * *-------------------------------------------------------------- */ void ComputeForwVector(recon_right_for_ptr, recon_down_for_ptr) int *recon_right_for_ptr; int *recon_down_for_ptr; { Pict *picture; Macroblock *mblock; picture = &(curVidStream->picture); mblock = &(curVidStream->mblock); ComputeVector(recon_right_for_ptr, recon_down_for_ptr, mblock->recon_right_for_prev, mblock->recon_down_for_prev, picture->forw_f, picture->full_pel_forw_vector, mblock->motion_h_forw_code, mblock->motion_v_forw_code, mblock->motion_h_forw_r, mblock->motion_v_forw_r); } /* *-------------------------------------------------------------- * * ComputeBackVector -- * * Computes backward motion vector by calling ComputeVector * with appropriate parameters. * * Results: * Reconstructed motion vector placed in recon_right_back_ptr and * recon_down_back_ptr. * * Side effects: * None. * *-------------------------------------------------------------- */ void ComputeBackVector(recon_right_back_ptr, recon_down_back_ptr) int *recon_right_back_ptr; int *recon_down_back_ptr; { Pict *picture; Macroblock *mblock; picture = &(curVidStream->picture); mblock = &(curVidStream->mblock); ComputeVector(recon_right_back_ptr, recon_down_back_ptr, mblock->recon_right_back_prev, mblock->recon_down_back_prev, picture->back_f, picture->full_pel_back_vector, mblock->motion_h_back_code, mblock->motion_v_back_code, mblock->motion_h_back_r, mblock->motion_v_back_r); } l += 8; l2 += 8; r += 4; b += 4; o1 += 8; ompeg_play.1 644 5104 267 11401 5333610522 6231 .\" @(#)mpeg_play.1 2.0 93/01/27 SMI; .TH MPEG_PLAY 1 "27 January 1993" .SH NAME mpeg_play \- plays mpeg-1 encoded bitstreams using X11 .SH SYNOPSIS .B mpeg_play [ .B -nob ] [ .B -nop ] [ [ .B -display display_name ] [ .B -dither dither_option ] [ .B -loop ] [ .B -eachstat ] [ .B -no_display ] [ .B -shmem_off ] [ .B -l_range num ] [ .B -cr_range num ] [ .B -cb_range num ] [ .B -quiet ] .B file_name .SH DESCRIPTION .B mpeg_play decodes and displays mpeg-1 encoded bitstreams on systems running X11. The player will create a new window, display the bitstream, and exit. Any error messages or notices are sent to stderr. .SH OPTIONS .HP .B -nob : causes the player to ignore and not display any B frames. .HP .B -nop : causes the player to ignore and not display any P frames. .HP .B -display display_name : causes the player to open the window on the display \fIdisplay_name\fP. .HP .B -dither dither_option : selects from a variety of dither options. The possible values are: .RS .HP ordered - ordered dither. .HP ordered2 - a faster ordered dither. This is the default. .HP mbordered - ordered dithering at the macroblock level. Although there is a noticeable decrease in dither quality, this is the fastest dither available. .HP fs4 - Floyd-Steinberg dithering with 4 error values propogated. .HP fs2 - Floyd-Steinberg dithering with 2 error values propogated. .HP fs2fast - Fast Floyd-Steinberg dithering with 2 error values propogated. .HP hybrid - Hybrid dithering, a combination of ordered dithering for the luminance channel and Floyd-Steinberg 2 error dithering for the chrominance channels. Errors are NOT propogated properly and are dropped all togethor every two pixels in either direction. .HP hybrid2 - Hybrid dithering as above, but with error propogation among pixels. .HP 2x2 - A dithering technique using a 2x2 pixel area for each pixel. The image displayed is 4 times larger than the original image encoded. Random error terms are added to each pixel to break up contours and gradients. .HP gray - Grayscale dithering. The image is dithered into 128 grayscales. Chrominance information is thrown away. .HP color - Full color display (only available on 24 bit color displays). .HP none - no dithering is done, no image is displayed. Used to time decoding process. .HP mono - Floyd-Steinberg dithering for monochrome displays. .HP threshold - Floyd-simple dithering for monochrome displays. .RE .HP .B -loop : makes the player loop back to the beginning after reaching the end. .HP -quiet : supresses printing of frame numbers, timing information, and most error messages. .HP -eachstat : causes statistics to be displayed after each frame. Only valid when compiled with -DANALYSIS. .HP -shmem_off : turns shared memory off. .HP .B -l_range num_colors : sets the number of colors assigned to the luminance component when dithering the image. The product of l_range, cr_range and cb_range should be less than the number of colors on the display. .HP .B -cr_range num_colors : sets the number of colors assigned to the red component of the chrominace range when dithering the image. The product of l_range, cr_range and cb_range should be less than the number of colors on the display. .HP .B -cb_range num_colors : sets the number of colors assigned to the blue component of the chrominace range when dithering the image. The product of l_range, cr_range and cb_range should be less than the number of colors on the display. .HP -no_display : dithers, but does not display, usually used for testing and timing purposes. .SH NOTES The player expects MPEG-1 video streams only. It can not handle multiplexed MPEG streams or video+audio streams. The player uses the paris entropy coding table set (which we believe to be the MPEG-1 standard), but can not handle any bitstreams that use the "berlin" entropy coding table set. Berlin data is relatively rare so there shouldn't be too much to worry about here, but be aware of the difference when looking for streams to play. .LP Some streams do not end with the proper sequence end code and will probably generate an "Improper sequence end code." error when done playing. .LP This player can play XING data files. Be aware that XING makes no use of temporal redundancy or motion vector information. In other words, they do not use any P or B frames in their streams. Instead, XING data is simply a sequence of I frames. Since I frames take significantly longer to decode, performance of the player using XING data is not representative of the player's ability. .SH AUTHORS .HP Ketan Patel - University of California, Berkeley, kpatel@cs.berkeley.edu .HP Brian Smith - University of California, Berkeley, bsmith@cs.berkeley.edu .HP Henry Chi-To Ma - University of California, Berkeley, cma@cs.berkeley.edu .HP Kim Man Liu - University of California, Berkeley, kliu@cs.berkeley.edu priate parameters. * * Results: * Reconstructed motion vector placed in recon_right_for_ptr and * recon_down_for_ptr. * * Side effects: * None. * *-------------------------------------------------------------- */ void ComputeForwVectordered.c 444 5104 267 17461 5333605255 6003 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* This file contains C code to implement an ordered dither. */ #include "video.h" #include "proto.h" #include "dither.h" #define DITH_SIZE 16 /* Structures used to implement hybrid ordered dither/floyd-steinberg dither algorithm. */ static unsigned char *l_darrays[DITH_SIZE]; static unsigned char *cr_darrays[DITH_SIZE]; static unsigned char *cb_darrays[DITH_SIZE]; /* *-------------------------------------------------------------- * * InitOrderedDither-- * * Structures intialized for ordered dithering. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitOrderedDither() { int i, j, k, err_range, threshval; unsigned char *lmark, *cmark; for (i=0; i threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE)); else *lmark++ = (j * (CR_RANGE * CB_RANGE)); } } for (j=lum_values[LUM_RANGE-1]; j<256; j++) { *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE); } } for (i=0; i threshval) *cmark++ = ((j+1) * CB_RANGE); else *cmark++ = (j * CB_RANGE); } } for (j=cr_values[CR_RANGE-1]; j<256; j++) { *cmark++ = (CR_RANGE-1)*(CB_RANGE); } } for (i=0; i threshval) *cmark++ = j+1; else *cmark++ = j; } } for (j=cb_values[CB_RANGE-1]; j<256; j++) { *cmark++ = CB_RANGE-1; } } } /* *-------------------------------------------------------------- * * OrderedDitherImage -- * * Dithers an image using an ordered dither. * Assumptions made: * 1) The color space is allocated y:cr:cb = 8:4:4 * 2) The spatial resolution of y:cr:cb is 4:1:1 * The channels are dithered based on the standard * ordered dither pattern for a 4x4 area. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void OrderedDitherImage (lum, cr, cb, out, h, w) unsigned char *lum; unsigned char *cr; unsigned char *cb; unsigned char *out; int w, h; { unsigned char *l, *r, *b, *o1, *o2; unsigned char *l2; unsigned char L, R, B; int i, j; l = lum; l2 = lum+w; r = cr; b = cb; o1 = out; o2 = out+w; for (i=0; irecon_down_for_prev, picture->forw_f, picture->full_pel_forw_vector, mblock->motion_h_forw_code, mblock->motion_v_forw_code, mblock->motion_h_forw_r, mblock->motion_v_forw_r); } /ordered2.c 444 5104 267 20216 5333605256 6056 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* This file contains C code to implement an ordered dither. */ #include "video.h" #include "proto.h" #include "dither.h" #define DITH_SIZE 16 /* Structures used to implement hybrid ordered dither/floyd-steinberg dither algorithm. */ static unsigned char ***ditherPtr[DITH_SIZE]; /* *-------------------------------------------------------------- * * InitOrderedDither-- * * Structures intialized for ordered dithering. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void InitOrdered2Dither() { unsigned char ****pos_2_cb; unsigned char ***cb_2_cr; unsigned char **cr_2_l; int cb_val, cb_rval, cr_val, cr_rval, l_val, l_rval; int i, j, pos; int err_range, threshval; pos_2_cb = (unsigned char ****) malloc (DITH_SIZE*sizeof(unsigned char ***)); cb_2_cr = (unsigned char ***) malloc(CB_RANGE*sizeof(unsigned char **)); cr_2_l = (unsigned char **) malloc(CR_RANGE*sizeof(unsigned char *)); for (pos=0; posthreshval) (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval+1]; else (pos_2_cb[pos])[cb_val] = cb_2_cr[cb_rval]; } } for (cb_val=cb_values[CB_RANGE-1]; cb_val<256; cb_val++) { (pos_2_cb[pos])[cb_val] = cb_2_cr[CB_RANGE-1]; } for (cb_rval=0; cb_rvalthreshval) (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval+1]; else (cb_2_cr[cb_rval])[cr_val] = cr_2_l[cr_rval]; } } for (cr_val=cr_values[CR_RANGE-1]; cr_val<256; cr_val++) { (cb_2_cr[cb_rval])[cr_val] = cr_2_l[CR_RANGE-1]; } for (cr_rval=0; cr_rvalthreshval) (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+((l_rval+1)*CR_RANGE*CB_RANGE)]; else (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+(l_rval*CR_RANGE*CB_RANGE)]; } } for (l_val = lum_values[LUM_RANGE-1]; l_val < 256; l_val++) { (cr_2_l[cr_rval])[l_val] = pixel[cb_rval+(cr_rval*CB_RANGE)+((LUM_RANGE-1)*CR_RANGE*CB_RANGE)]; } } } } for (i=0; irecon_right_back_prev, mblock->recon_down_back_prev, picture->back_f, picture->full_pel_back_vector, mblock->motion_h_back_code, mblock->motion_v_back_code, mblock->motion_h_back_r, mblock->motion_v_back_r); } l += 8; l2 += 8; r += 4; b += 4; o1 += 8; oparseblock.c 444 5104 267 24156 5333605256 6504 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #define NO_SANITY_CHECKS #include #include "video.h" #include "proto.h" #include "decoders.h" /* External declarations. */ extern int zigzag_direct[]; /* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */ #define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1)) /* *-------------------------------------------------------------- * * ParseReconBlock -- * * Parse values for block structure from bitstream. * n is an indication of the position of the block within * the macroblock (i.e. 0-5) and indicates the type of * block (i.e. luminance or chrominance). Reconstructs * coefficients from values parsed and puts in * block.dct_recon array in vid stream structure. * sparseFlag is set when the block contains only one * coeffictient and is used by the IDCT. * * Results: * * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ #define DCT_recon blockPtr->dct_recon #define DCT_dc_y_past blockPtr->dct_dc_y_past #define DCT_dc_cr_past blockPtr->dct_dc_cr_past #define DCT_dc_cb_past blockPtr->dct_dc_cb_past #define DECODE_DCT_COEFF_FIRST DecodeDCTCoeffFirst #define DECODE_DCT_COEFF_NEXT DecodeDCTCoeffNext void ParseReconBlock(n) int n; { #ifdef RISC unsigned int temp_curBits; int temp_bitOffset; int temp_bufLength; unsigned int *temp_bitBuffer; #endif Block *blockPtr = &curVidStream->block; int coeffCount; if (bufLength < 100) correct_underflow(); #ifdef RISC temp_curBits = curBits; temp_bitOffset = bitOffset; temp_bufLength = bufLength; temp_bitBuffer = bitBuffer; #endif { /* * Copy the globals curBits, bitOffset, bufLength, and bitBuffer * into local variables with the same names, so the macros use the * local variables instead. This allows register allocation and * can provide 1-2 fps speedup. On machines with not so many registers, * don't do this. */ #ifdef RISC register unsigned int curBits = temp_curBits; register int bitOffset = temp_bitOffset; register int bufLength = temp_bufLength; register unsigned int *bitBuffer = temp_bitBuffer; #endif int diff; int size, level, i, run, pos, coeff; short int *reconptr; unsigned char *iqmatrixptr, *niqmatrixptr; int qscale; reconptr = DCT_recon[0]; /* * Hand coded version of memset that's a little faster... * Old call: * memset((char *) DCT_recon, 0, 64*sizeof(short int)); */ { INT32 *p; p = (INT32 *) reconptr; p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = p[8] = p[9] = p[10] = p[11] = p[12] = p[13] = p[14] = p[15] = p[16] = p[17] = p[18] = p[19] = p[20] = p[21] = p[22] = p[23] = p[24] = p[25] = p[26] = p[27] = p[28] = p[29] = p[30] = p[31] = 0; } if (curVidStream->mblock.mb_intra) { if (n < 4) { /* * Get the luminance bits. This code has been hand optimized to * get by the normal bit parsing routines. We get some speedup * by grabbing the next 16 bits and parsing things locally. * Thus, calls are translated as: * * show_bitsX <--> next16bits >> (16-X) * get_bitsX <--> val = next16bits >> (16-flushed-X); * flushed += X; * next16bits &= bitMask[flushed]; * flush_bitsX <--> flushed += X; * next16bits &= bitMask[flushed]; * * I've streamlined the code a lot, so that we don't have to mask * out the low order bits and a few of the extra adds are removed. * bsmith */ unsigned int next16bits, index, flushed; show_bits16(next16bits); index = next16bits >> (16-7); size = dct_dc_size_luminance[index].value; flushed = dct_dc_size_luminance[index].num_bits; next16bits &= bitMask[16+flushed]; if (size != 0) { flushed += size; diff = next16bits >> (16-flushed); if (!(diff & bitTest[32-size])) { diff = rBitMask[size] | (diff + 1); } } else { diff = 0; } flush_bits(flushed); if (n == 0) { coeff = diff << 3; if (curVidStream->mblock.mb_address - curVidStream->mblock.past_intra_addr > 1) coeff += 1024; else coeff += DCT_dc_y_past; DCT_dc_y_past = coeff; } else { coeff = DCT_dc_y_past + (diff << 3); DCT_dc_y_past = coeff; } } else { /* * Get the chrominance bits. This code has been hand optimized to * as described above */ unsigned int next16bits, index, flushed; show_bits16(next16bits); index = next16bits >> (16-8); size = dct_dc_size_chrominance[index].value; flushed = dct_dc_size_chrominance[index].num_bits; next16bits &= bitMask[16+flushed]; if (size != 0) { flushed += size; diff = next16bits >> (16-flushed); if (!(diff & bitTest[32-size])) { diff = rBitMask[size] | (diff + 1); } } else { diff = 0; } flush_bits(flushed); if (n == 4) { coeff = diff << 3; if (curVidStream->mblock.mb_address - curVidStream->mblock.past_intra_addr > 1) coeff += 1024; else coeff += DCT_dc_cr_past; DCT_dc_cr_past = coeff; } else { coeff = diff << 3; if (curVidStream->mblock.mb_address - curVidStream->mblock.past_intra_addr > 1) coeff += 1024; else coeff += DCT_dc_cb_past; DCT_dc_cb_past = coeff; } } *reconptr = coeff; i = 0; pos = 0; coeffCount = (coeff != 0); if (curVidStream->picture.code_type != 4) { qscale = curVidStream->slice.quant_scale; iqmatrixptr = curVidStream->intra_quant_matrix[0]; while(1) { DECODE_DCT_COEFF_NEXT(run, level); if (run == END_OF_BLOCK) break; i = i + run + 1; pos = zigzag_direct[i]; coeff = (level * qscale * ((int) iqmatrixptr[pos])) >> 3; if (level < 0) { coeff += (coeff & 1); } else { coeff -= (coeff & 1); } reconptr[pos] = coeff; if (coeff) { coeffCount++; } } #ifdef ANALYSIS { extern unsigned int *mbCoeffPtr; mbCoeffPtr[pos]++; } #endif flush_bits(2); goto end; } } else { niqmatrixptr = curVidStream->non_intra_quant_matrix[0]; qscale = curVidStream->slice.quant_scale; DECODE_DCT_COEFF_FIRST(run, level); i = run; pos = zigzag_direct[i]; if (level < 0) { coeff = (((level<<1) - 1) * qscale * ((int) (niqmatrixptr[pos]))) >> 4; coeff += (coeff & 1); } else { coeff = (((level<<1) + 1) * qscale * ((int) (*(niqmatrixptr+pos)))) >> 4; coeff -= (coeff & 1); } reconptr[pos] = coeff; if (coeff) { coeffCount = 1; } if (curVidStream->picture.code_type != 4) { while(1) { DECODE_DCT_COEFF_NEXT(run, level); if (run == END_OF_BLOCK) break; i = i+run+1; pos = zigzag_direct[i]; if (level < 0) { coeff = (((level<<1) - 1) * qscale * ((int) (niqmatrixptr[pos]))) >> 4; coeff += (coeff & 1); } else { coeff = (((level<<1) + 1) * qscale * ((int) (*(niqmatrixptr+pos)))) >> 4; coeff -= (coeff & 1); } reconptr[pos] = coeff; if (coeff) { coeffCount++; } } #ifdef ANALYSIS { extern unsigned int *mbCoeffPtr; mbCoeffPtr[pos]++; } #endif flush_bits(2); goto end; } } end: if (coeffCount == 1) j_rev_dct_sparse (reconptr, pos); else j_rev_dct(reconptr); #ifdef RISC temp_curBits = curBits; temp_bitOffset = bitOffset; temp_bufLength = bufLength; temp_bitBuffer = bitBuffer; #endif } #ifdef RISC curBits = temp_curBits; bitOffset = temp_bitOffset; bufLength = temp_bufLength; bitBuffer = temp_bitBuffer; #endif } #undef DCT_recon #undef DCT_dc_y_past #undef DCT_dc_cr_past #undef DCT_dc_cb_past /* *-------------------------------------------------------------- * * ParseAwayBlock -- * * Parses off block values, throwing them away. * Used with grayscale dithering. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void ParseAwayBlock(n) int n; { unsigned int diff; unsigned int size, run; int level; if (bufLength < 100) correct_underflow(); if (curVidStream->mblock.mb_intra) { /* If the block is a luminance block... */ if (n < 4) { /* Parse and decode size of first coefficient. */ DecodeDCTDCSizeLum(size); /* Parse first coefficient. */ if (size != 0) { get_bitsn(size, diff); } } /* Otherwise, block is chrominance block... */ else { /* Parse and decode size of first coefficient. */ DecodeDCTDCSizeChrom(size); /* Parse first coefficient. */ if (size != 0) { get_bitsn(size, diff); } } } /* Otherwise, block is not intracoded... */ else { /* Decode and set first coefficient. */ DECODE_DCT_COEFF_FIRST(run, level); } /* If picture is not D type (i.e. I, P, or B)... */ if (curVidStream->picture.code_type != 4) { /* While end of macroblock has not been reached... */ while (1) { /* Get the dct_coeff_next */ DECODE_DCT_COEFF_NEXT(run, level); if (run == END_OF_BLOCK) break; } /* End_of_block */ flush_bits(2); } } efine DCT_dc_cr_past blockPtr->dct_dc_cr_past #define DCT_dc_cb_past blockPtr->dct_dc_cb_past #define DECODE_DCT_COEFF_FIRST DecodeDCTCoeffFirst #define DECODE_DCT_COEFF_NEXT DecodeDCTCoeffNext void ParseReconBlock(n) int n; { #ifdef RISC unsigned int temp_curBits; int temp_bitOffset; int temp_bufLength; unsigned int *temp_bitBuffer; #endif Block *blockPtr = &curVidStream->block; proto.h 664 5104 267 11121 5333766263 5525 #ifdef __STDC__ # define P(s) s #else # define P(s) () #endif /* util.c */ void correct_underflow P((void )); int next_bits P((int num , unsigned int mask )); char *get_ext_data P((void )); int next_start_code P((void )); char *get_extra_bit_info P((void )); /* video.c */ void init_stats P((void )); void PrintAllStats P((void )); double ReadSysClock P((void )); void PrintTimeInfo P((void )); VidStream *NewVidStream P((int bufLength )); void DestroyVidStream P((VidStream *astream )); PictImage *NewPictImage P((unsigned int width , unsigned int height )); void DestroyPictImage P((PictImage *apictimage )); VidStream *mpegVidRsrc P((TimeStamp time_stamp , VidStream *vid_stream )); void ToggleBFlag P((void )); void TogglePFlag P((void )); /* parseblock.c */ void ParseReconBlock P((int n )); void ParseAwayBlock P((int n )); /* motionvector.c */ void ComputeForwVector P((int *recon_right_for_ptr , int *recon_down_for_ptr )); void ComputeBackVector P((int *recon_right_back_ptr , int *recon_down_back_ptr )); /* decoders.c */ void init_tables P((void )); void decodeDCTDCSizeLum P((unsigned int *value )); void decodeDCTDCSizeChrom P((unsigned int *value )); void decodeDCTCoeffFirst P((unsigned int *run , int *level )); void decodeDCTCoeffNext P((unsigned int *run , int *level )); /* main.c */ int get_more_data P((unsigned int *buf_start , int max_length , int *length_ptr , unsigned int **buf_ptr )); void int_handler P((void )); void main P((int argc , char **argv )); void usage P((char *s )); void DoDitherImage P((unsigned char *l , unsigned char *Cr , unsigned char *Cb , unsigned char *disp , int h , int w )); /* gdith.c */ void InitColor P((void )); int HandleXError P((Display *dpy , XErrorEvent *event )); void InstallXErrorHandler P((void )); void DeInstallXErrorHandler P((void )); void ResizeDisplay P((int w , int h )); void InitDisplay P((char *name )); void InitGrayDisplay P((char *name )); void InitMonoDisplay P((char *name )); void InitColorDisplay P((char *name )); void ExecuteDisplay P((VidStream *vid_stream )); /* fs2.c */ void InitFS2Dither P((void )); void FS2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols )); /* fs2fast.c */ void InitFS2FastDither P((void )); void FS2FastDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* fs4.c */ void InitFS4Dither P((void )); void FS4DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *disp , int rows , int cols )); /* hybrid.c */ void InitHybridDither P((void )); void HybridDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* hybriderr.c */ void InitHybridErrorDither P((void )); void HybridErrorDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* 2x2.c */ void Init2x2Dither P((void )); void RandInit P((int h , int w )); void PostInit2x2Dither P((void )); void Twox2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* gray.c */ void GrayDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* mono.c */ /* jrevdct.c */ void init_pre_idct P((void )); void j_rev_dct_sparse P((DCTBLOCK data , int pos )); void j_rev_dct P((DCTBLOCK data )); void j_rev_dct_sparse P((DCTBLOCK data , int pos )); void j_rev_dct P((DCTBLOCK data )); /* 24bit.c */ void InitColorDither P((void )); void ColorDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int rows , int cols )); /* util32.c */ Visual *FindFullColorVisual P((Display *dpy , int *depth )); Window CreateFullColorWindow P((Display *dpy , int x , int y , int w , int h )); /* ordered.c */ void InitOrderedDither P((void )); void OrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* ordered2.c */ void InitOrdered2Dither P((void )); void Ordered2DitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); /* mb_ordered.c */ void InitMBOrderedDither P((void )); void MBOrderedDitherImage P((unsigned char *lum , unsigned char *cr , unsigned char *cb , unsigned char *out , int h , int w )); void MBOrderedDitherDisplayCopy P((VidStream *vid_stream , int mb_addr , int motion_forw , int r_right_forw , int r_down_forw , int motion_back , int r_right_back , int r_down_back , unsigned char *past , unsigned char *future )); #undef P eam->mblock.mb_address - curVidStream->mblock.past_intra_addr > 1) coeff += 1024; else coeff += DCT_dc_cb_past; DCT_dc_cb_past = coeff; } } *reconptr = coeff; i = 0; pos = 0; coeffCount = (coeff != 0); if (curVidStream->picture.code_type != 4) { qscale = curVidStream->slice.quant_scale; iqmatrixptr = curVidStream->intra_quant_matrix[0]; while(1) { DECODutil.c 444 5104 267 24434 5333605256 5333 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include #include "video.h" #include "proto.h" #include "util.h" /* Declarations of global variables used. */ unsigned int curBits; int bitOffset; int bufLength; unsigned int *bitBuffer; /* Bit masks used by bit i/o operations. */ unsigned int nBitMask[] = { 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe}; unsigned int bitMask[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff, 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff, 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff, 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff, 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f, 0x0000000f, 0x00000007, 0x00000003, 0x00000001}; unsigned int rBitMask[] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000}; unsigned int bitTest[] = { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x04000000, 0x02000000, 0x01000000, 0x00800000, 0x00400000, 0x00200000, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000, 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001}; /* *-------------------------------------------------------------- * * correct_underflow -- * * Called when buffer does not have sufficient data to * satisfy request for bits. * Calls get_more_data, an application specific routine * required to fill the buffer with more data. * * Results: * None really. * * Side effects: * buf_length and buffer fields in curVidStream structure * may be changed. * *-------------------------------------------------------------- */ void correct_underflow() { int status; status = get_more_data(curVidStream->buf_start, curVidStream->max_buf_length, &bufLength, &bitBuffer); if (status < 0) { if (!quietFlag) { fprintf (stderr, "\n"); perror("Unexpected read error."); } exit(1); } else if ((status == 0) && (bufLength < 1)) { if (!quietFlag) { fprintf(stderr, "\nImproper or missing sequence end code.\n"); } #ifdef ANALYSIS PrintAllStats(); #endif if (!quietFlag) { PrintTimeInfo(); } if (loopFlag) longjmp(env, 1); DestroyVidStream(curVidStream); exit(0); } #ifdef UTIL2 curBits = *bitBuffer << bitOffset; #else curBits = *bitBuffer; #endif } /* *-------------------------------------------------------------- * * next_bits -- * * Compares next num bits to low order position in mask. * Buffer pointer is NOT advanced. * * Results: * TRUE, FALSE, or error code. * * Side effects: * None. * *-------------------------------------------------------------- */ int next_bits(num, mask) int num; unsigned int mask; { unsigned int stream; int ret_value; /* If no current stream, return error. */ if (curVidStream == NULL) return NO_VID_STREAM; /* Get next num bits, no buffer pointer advance. */ show_bitsn(num, stream); /* Compare bit stream and mask. Set return value toTRUE if equal, FALSE if differs. */ if (mask == stream) { ret_value = TRUE; } else ret_value = FALSE; /* Return return value. */ return ret_value; } /* *-------------------------------------------------------------- * * get_ext_data -- * * Assumes that bit stream is at begining of extension * data. Parses off extension data into dynamically * allocated space until start code is hit. * * Results: * Pointer to dynamically allocated memory containing * extension data. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ char *get_ext_data () { int size, marker; char *dataPtr; unsigned int data; /* Set initial ext data buffer size. */ size = EXT_BUF_SIZE; /* Allocate ext data buffer. */ dataPtr = (char *) malloc(size); /* Initialize marker to keep place in ext data buffer. */ marker = 0; /* While next data is not start code... */ while (!next_bits(24, 0x000001)) { /* Get next byte of ext data. */ get_bits8(data); /* Put ext data into ext data buffer. Advance marker. */ dataPtr[marker] = (char) data; marker++; /* If end of ext data buffer reached, resize data buffer. */ if (marker == size) { size += EXT_BUF_SIZE; dataPtr = (char *) realloc(dataPtr, size); } } /* Realloc data buffer to free any extra space. */ dataPtr = (char *) realloc(dataPtr, marker); /* Return pointer to ext data buffer. */ return dataPtr; } /* *-------------------------------------------------------------- * * next_start_code -- * * Parses off bitstream until start code reached. When done * next 4 bytes of bitstream will be start code. Bit offset * reset to 0. * * Results: * Status code. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ int next_start_code() { int state; int byteoff; unsigned int data; /* If no current stream, return error. */ if (curVidStream == NULL) return NO_VID_STREAM; /* If insufficient buffer length, correct underflow. */ if (bufLength < 2) { correct_underflow(); } /* If bit offset not zero, reset and advance buffer pointer. */ byteoff = bitOffset % 8; if (byteoff != 0) { flush_bits((8-byteoff)); } /* Set state = 0. */ state = 0; /* While buffer has data ... */ while(bufLength > 0) { /* If insufficient data exists, correct underflow. */ if (bufLength < 2) { correct_underflow(); } /* If next byte is zero... */ get_bits8(data); if (data == 0) { /* If state < 2, advance state. */ if (state < 2) state++; } /* If next byte is one... */ else if (data == 1) { /* If state == 2, advance state (i.e. start code found). */ if (state == 2) state++; /* Otherwise, reset state to zero. */ else state = 0; } /* Otherwise byte is neither 1 or 0, reset state to 0. */ else { state = 0; } /* If state == 3 (i.e. start code found)... */ if (state == 3) { /* Set buffer pointer back and reset length & bit offsets so next bytes will be beginning of start code. */ bitOffset = bitOffset - 24; #ifdef ANALYSIS bitCount -= 24; #endif if (bitOffset < 0) { bitOffset = 32 + bitOffset; bufLength++; bitBuffer--; #ifdef UTIL2 curBits = *bitBuffer << bitOffset; #else curBits = *bitBuffer; #endif } else { #ifdef UTIL2 curBits = *bitBuffer << bitOffset; #else curBits = *bitBuffer; #endif } /* Return success. */ return OK; } } /* Return underflow error. */ return UNDERFLOW; } /* *-------------------------------------------------------------- * * get_extra_bit_info -- * * Parses off extra bit info stream into dynamically * allocated memory. Extra bit info is indicated by * a flag bit set to 1, followed by 8 bits of data. * This continues until the flag bit is zero. Assumes * that bit stream set to first flag bit in extra * bit info stream. * * Results: * Pointer to dynamically allocated memory with extra * bit info in it. Flag bits are NOT included. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ char *get_extra_bit_info () { int size, marker; char *dataPtr; unsigned int data; /* Get first flag bit. */ get_bits1(data); /* If flag is false, return NULL pointer (i.e. no extra bit info). */ if (!data) return NULL; /* Initialize size of extra bit info buffer and allocate. */ size = EXT_BUF_SIZE; dataPtr = (char *) malloc(size); /* Reset marker to hold place in buffer. */ marker = 0; /* While flag bit is true. */ while (data) { /* Get next 8 bits of data. */ get_bits8(data); /* Place in extra bit info buffer. */ dataPtr[marker] = (char) data; marker++; /* If buffer is full, reallocate. */ if (marker == size) { size += EXT_BUF_SIZE; dataPtr = (char *) realloc(dataPtr, size); } /* Get next flag bit. */ get_bits1(data); } /* Reallocate buffer to free extra space. */ dataPtr = (char *) realloc(dataPtr, marker); /* Return pointer to extra bit info buffer. */ return dataPtr; } 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, util.h 444 5104 267 52057 5333605257 5343 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* Status codes for bit stream i/o operations. */ #define NO_VID_STREAM -1 #define UNDERFLOW -2 #define OK 1 /* Size increment of extension data buffers. */ #define EXT_BUF_SIZE 1024 /* External declarations for bitstream i/o operations. */ extern unsigned int bitMask[]; extern unsigned int nBitMask[]; extern unsigned int rBitMask[]; extern unsigned int bitTest[]; /* External declarations of bitstream global variables. */ extern unsigned int curBits; extern int bitOffset; extern int bufLength; extern unsigned int *bitBuffer; /* Macro for updating bit counter if analysis tool is on. */ #ifdef ANALYSIS #define UPDATE_COUNT(numbits) bitCount += numbits #else #define UPDATE_COUNT(numbits) #endif #ifdef NO_SANITY_CHECKS #define get_bits1(result) \ { \ UPDATE_COUNT(1); \ result = ((curBits & 0x80000000) != 0); \ curBits <<= 1; \ bitOffset++; \ \ if (bitOffset & 0x20) { \ bitOffset = 0; \ bitBuffer++; \ curBits = *bitBuffer; \ bufLength--; \ } \ } #define get_bits2(result) \ { \ UPDATE_COUNT(2); \ bitOffset += 2; \ \ if (bitOffset & 0x20) { \ bitOffset -= 32; \ bitBuffer++; \ bufLength--; \ if (bitOffset) { \ curBits |= (*bitBuffer >> (2 - bitOffset)); \ } \ result = ((curBits & 0xc0000000) >> 30); \ curBits = *bitBuffer << bitOffset; \ } \ \ result = ((curBits & 0xc0000000) >> 30); \ curBits <<= 2; \ } #define get_bitsX(num, mask, shift, result) \ { \ UPDATE_COUNT(num); \ bitOffset += num; \ \ if (bitOffset & 0x20) { \ bitOffset -= 32; \ bitBuffer++; \ bufLength--; \ if (bitOffset) { \ curBits |= (*bitBuffer >> (num - bitOffset)); \ } \ result = ((curBits & mask) >> shift); \ curBits = *bitBuffer << bitOffset; \ } \ else { \ result = ((curBits & mask) >> shift); \ curBits <<= num; \ } \ } #else #define get_bits1(result) \ { \ /* Check for underflow. */ \ \ if (bufLength < 2) { \ correct_underflow(); \ } \ UPDATE_COUNT(1); \ result = ((curBits & 0x80000000) != 0); \ curBits <<= 1; \ bitOffset++; \ \ if (bitOffset & 0x20) { \ bitOffset = 0; \ bitBuffer++; \ curBits = *bitBuffer; \ bufLength--; \ } \ } #define get_bits2(result) \ { \ /* Check for underflow. */ \ \ if (bufLength < 2) { \ correct_underflow(); \ } \ UPDATE_COUNT(2); \ bitOffset += 2; \ \ if (bitOffset & 0x20) { \ bitOffset -= 32; \ bitBuffer++; \ bufLength--; \ if (bitOffset) { \ curBits |= (*bitBuffer >> (2 - bitOffset)); \ } \ result = ((curBits & 0xc0000000) >> 30); \ curBits = *bitBuffer << bitOffset; \ } \ \ result = ((curBits & 0xc0000000) >> 30); \ curBits <<= 2; \ } #define get_bitsX(num, mask, shift, result) \ { \ /* Check for underflow. */ \ \ if (bufLength < 2) { \ correct_underflow(); \ } \ UPDATE_COUNT(num); \ bitOffset += num; \ \ if (bitOffset & 0x20) { \ bitOffset -= 32; \ bitBuffer++; \ bufLength--; \ if (bitOffset) { \ curBits |= (*bitBuffer >> (num - bitOffset)); \ } \ result = ((curBits & mask) >> shift); \ curBits = *bitBuffer << bitOffset; \ } \ else { \ result = ((curBits & mask) >> shift); \ curBits <<= num; \ } \ } #endif #define get_bits3(result) get_bitsX(3, 0xe0000000, 29, result) #define get_bits4(result) get_bitsX(4, 0xf0000000, 28, result) #define get_bits5(result) get_bitsX(5, 0xf8000000, 27, result) #define get_bits6(result) get_bitsX(6, 0xfc000000, 26, result) #define get_bits7(result) get_bitsX(7, 0xfe000000, 25, result) #define get_bits8(result) get_bitsX(8, 0xff000000, 24, result) #define get_bits9(result) get_bitsX(9, 0xff800000, 23, result) #define get_bits10(result) get_bitsX(10, 0xffc00000, 22, result) #define get_bits11(result) get_bitsX(11, 0xffe00000, 21, result) #define get_bits12(result) get_bitsX(12, 0xfff00000, 20, result) #define get_bits14(result) get_bitsX(14, 0xfffc0000, 18, result) #define get_bits16(result) get_bitsX(16, 0xffff0000, 16, result) #define get_bits18(result) get_bitsX(18, 0xffffc000, 14, result) #define get_bits32(result) get_bitsX(32, 0xffffffff, 0, result) #define get_bitsn(num, result) get_bitsX((num), nBitMask[num], (32-(num)), result) #ifdef NO_SANITY_CHECKS #define show_bits32(result) \ { \ if (bitOffset) { \ result = curBits | (*(bitBuffer+1) >> (32 - bitOffset)); \ } \ else { \ result = curBits; \ } \ } #define show_bitsX(num, mask, shift, result) \ { \ int bO; \ bO = bitOffset + num; \ if (bO > 32) { \ bO -= 32; \ result = ((curBits & mask) >> shift) | \ (*(bitBuffer+1) >> (shift + (num - bO))); \ } \ else { \ result = ((curBits & mask) >> shift); \ } \ } #else #define show_bits32(result) \ { \ /* Check for underflow. */ \ if (bufLength < 2) { \ correct_underflow(); \ } \ if (bitOffset) { \ result = curBits | (*(bitBuffer+1) >> (32 - bitOffset)); \ } \ else { \ result = curBits; \ } \ } #define show_bitsX(num, mask, shift, result) \ { \ int bO; \ \ /* Check for underflow. */ \ if (bufLength < 2) { \ correct_underflow(); \ } \ bO = bitOffset + num; \ if (bO > 32) { \ bO -= 32; \ result = ((curBits & mask) >> shift) | \ (*(bitBuffer+1) >> (shift + (num - bO))); \ } \ else { \ result = ((curBits & mask) >> shift); \ } \ } #endif #define show_bits1(result) show_bitsX(1, 0x80000000, 31, result) #define show_bits2(result) show_bitsX(2, 0xc0000000, 30, result) #define show_bits3(result) show_bitsX(3, 0xe0000000, 29, result) #define show_bits4(result) show_bitsX(4, 0xf0000000, 28, result) #define show_bits5(result) show_bitsX(5, 0xf8000000, 27, result) #define show_bits6(result) show_bitsX(6, 0xfc000000, 26, result) #define show_bits7(result) show_bitsX(7, 0xfe000000, 25, result) #define show_bits8(result) show_bitsX(8, 0xff000000, 24, result) #define show_bits9(result) show_bitsX(9, 0xff800000, 23, result) #define show_bits10(result) show_bitsX(10, 0xffc00000, 22, result) #define show_bits11(result) show_bitsX(11, 0xffe00000, 21, result) #define show_bits12(result) show_bitsX(12, 0xfff00000, 20, result) #define show_bits13(result) show_bitsX(13, 0xfff80000, 19, result) #define show_bits14(result) show_bitsX(14, 0xfffc0000, 18, result) #define show_bits15(result) show_bitsX(15, 0xfffe0000, 17, result) #define show_bits16(result) show_bitsX(16, 0xffff0000, 16, result) #define show_bits17(result) show_bitsX(17, 0xffff8000, 15, result) #define show_bits18(result) show_bitsX(18, 0xffffc000, 14, result) #define show_bits19(result) show_bitsX(19, 0xffffe000, 13, result) #define show_bits20(result) show_bitsX(20, 0xfffff000, 12, result) #define show_bits21(result) show_bitsX(21, 0xfffff800, 11, result) #define show_bits22(result) show_bitsX(22, 0xfffffc00, 10, result) #define show_bits23(result) show_bitsX(23, 0xfffffe00, 9, result) #define show_bits24(result) show_bitsX(24, 0xffffff00, 8, result) #define show_bits25(result) show_bitsX(25, 0xffffff80, 7, result) #define show_bits26(result) show_bitsX(26, 0xffffffc0, 6, result) #define show_bits27(result) show_bitsX(27, 0xffffffe0, 5, result) #define show_bits28(result) show_bitsX(28, 0xfffffff0, 4, result) #define show_bits29(result) show_bitsX(29, 0xfffffff8, 3, result) #define show_bits30(result) show_bitsX(30, 0xfffffffc, 2, result) #define show_bits31(result) show_bitsX(31, 0xfffffffe, 1, result) #define show_bitsn(num,result) show_bitsX((num), (0xffffffff << (32-(num))), (32-(num)), result) #ifdef NO_SANITY_CHECKS #define flush_bits32 \ { \ UPDATE_COUNT(32); \ \ bitBuffer++; \ bufLength--; \ curBits = *bitBuffer << bitOffset; \ } #define flush_bits(num) \ { \ bitOffset += num; \ \ UPDATE_COUNT(num); \ \ if (bitOffset & 0x20) { \ bitOffset -= 32; \ bitBuffer++; \ bufLength--; \ curBits = *bitBuffer << bitOffset; \ } \ else { \ curBits <<= num; \ } \ } #else #define flush_bits32 \ { \ if (curVidStream == NULL) { \ /* Deal with no vid stream here. */ \ } \ \ if (bufLength < 2) { \ correct_underflow(); \ } \ \ UPDATE_COUNT(32); \ \ bitBuffer++; \ bufLength--; \ curBits = *bitBuffer << bitOffset; \ } #define flush_bits(num) \ { \ if (curVidStream == NULL) { \ /* Deal with no vid stream here. */ \ } \ \ if (bufLength < 2) { \ correct_underflow(); \ } \ \ UPDATE_COUNT(num); \ \ bitOffset += num; \ \ if (bitOffset & 0x20) { \ bufLength--; \ bitOffset -= 32; \ bitBuffer++; \ curBits = *bitBuffer << bitOffset; \ } \ else { \ curBits <<= num; \ } \ } #endif #define UTIL2 \ if (bitOffset) { \ result = curBits | (*(bitBuffer+1) >> (32 - bitOffset)); \ } \ else { \ result = curBits; \ } \ } #define show_bitsX(num, mask, shift, result) \ { util32.c 444 5104 267 3121 5333605257 5447 #include #include #include #include "video.h" #include "proto.h" /* * Return a pointer to a full color bit visual on the dpy */ Visual * FindFullColorVisual (dpy, depth) Display *dpy; int *depth; { XVisualInfo vinfo; XVisualInfo *vinfo_ret; int numitems, maxdepth; vinfo.class = TrueColor; vinfo_ret = XGetVisualInfo(dpy, VisualClassMask, &vinfo, &numitems); if (numitems == 0) return NULL; maxdepth = 0; while(numitems > 0) { if (vinfo_ret[numitems-1].depth > maxdepth) { maxdepth = vinfo_ret[numitems-1 ].depth; } numitems--; } XFree(vinfo_ret); if (maxdepth < 24) return NULL; if (XMatchVisualInfo(dpy, DefaultScreen(dpy), maxdepth, TrueColor, &vinfo)) { *depth = maxdepth; return vinfo.visual; } return NULL; } Window CreateFullColorWindow (dpy, x, y, w, h) Display *dpy; int x, y, w, h; { int depth; Visual *visual; XSetWindowAttributes xswa; unsigned int mask; unsigned int class; int screen; screen = XDefaultScreen(dpy); class = InputOutput; /* Could be InputOnly */ visual = FindFullColorVisual (dpy, &depth); if (visual == NULL) { return 0; } mask = CWBackPixel | CWColormap | CWBorderPixel; xswa.colormap = XCreateColormap(dpy, XRootWindow(dpy, screen), visual, AllocNone); xswa.background_pixel = BlackPixel(dpy, DefaultScreen(dpy)); xswa.border_pixel = WhitePixel(dpy, DefaultScreen(dpy)); return XCreateWindow(dpy, RootWindow(dpy, screen), x, y, w, h, 1, depth, class, visual, mask, &xswa); } sult) show_bitsX(15, 0xfffe0000, 17, result) #define show_bits16(result) show_bitsX(16, 0xffff0000, 16, result) #define show_bits17(result) show_bitsX(17, 0xffff8000, 15, result) #define show_bits18(result) show_bitsX(18, 0xffffc000, 14, result) #define show_bits19(result) show_bitsX(19, 0xffffe000, 13, result) #define show_bits20(result) show_bitsX(20, 0xfffff000, 12, result) #define show_bits21(result) show_bitsX(21, 0xfffff8video.c 444 5104 267 325120 5333605261 5474 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /* This file contains C code that implements * the video decoder model. */ #include #include #include #ifndef MIPS #include #else #include #include #endif #include "decoders.h" #include "video.h" #include "util.h" #include "proto.h" /* Declarations of functions. */ static void ReconIMBlock(); static void ReconPMBlock(); static void ReconBMBlock(); static void ReconBiMBlock(); static void ReconSkippedBlock(); static void DoPictureDisplay(); static int ParseSeqHead(); static int ParseGOP(); static int ParsePicture(); static int ParseSlice(); static int ParseMacroBlock(); static void ProcessSkippedPFrameMBlocks(); static void ProcessSkippedBFrameMBlocks(); extern int ditherType; char *ditherFlags; /* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */ #define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1)) /* Declare global pointer to vid stream used for current decoding. */ VidStream *curVidStream = NULL; /* Set up array for fast conversion from zig zag order to row/column coordinates. */ int zigzag[64][2] = { 0, 0, 1, 0, 0, 1, 0, 2, 1, 1, 2, 0, 3, 0, 2, 1, 1, 2, 0, 3, 0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 5, 0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 5, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7, 1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6, 2, 7, 1, 7, 2, 6, 3, 5, 4, 4, 5, 3, 6, 2, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 3, 7, 4, 6, 5, 5, 6, 4, 7, 5, 7, 6, 6, 7, 5, 7, 6, 6, 7, 7, 7}; /* Array mapping zigzag to array pointer offset. */ int zigzag_direct[64] = { 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}; /* Set up array for fast conversion from row/column coordinates to zig zag order. */ int scan[8][8] = { {0, 1, 5, 6, 14, 15, 27, 28}, {2, 4, 7, 13, 16, 26, 29, 42}, {3, 8, 12, 17, 25, 30, 41, 43}, {9, 11, 18, 24, 31, 40, 44, 53}, {10, 19, 23, 32, 39, 45, 52, 54}, {20, 22, 33, 38, 46, 51, 55, 60}, {21, 34, 37, 47, 50, 56, 59, 61}, {35, 36, 48, 49, 57, 58, 62, 63}}; /* Initialize P and B skip flags. */ static int No_P_Flag = 0; static int No_B_Flag = 0; /* Max lum, chrom indices for illegal block checking. */ static int lmaxx; static int lmaxy; static int cmaxx; static int cmaxy; /* * We use a lookup table to make sure values stay in the 0..255 range. * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this * table the "crop table". * MAX_NEG_CROP is the maximum neg/pos value we can handle. */ #define MAX_NEG_CROP 384 #define NUM_CROP_ENTRIES (256+2*MAX_NEG_CROP) #define assertCrop(x) assert(((x) >= -MAX_NEG_CROP) && \ ((x) <= 256+MAX_NEG_CROP)) static unsigned char cropTbl[NUM_CROP_ENTRIES]; /* The following accounts for time and size spent in various parsing acitivites if ANALYSIS has been defined. */ #ifdef ANALYSIS 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]; unsigned int cacheMiss[8][8]; static void init_stat_struct(astat) 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() { 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() { 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() { 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() { 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() { return bitCount; } static void StartTime() { stat_a[0].tottime = ReadSysClock(); } static void EndTime() { stat_a[0].tottime = ReadSysClock() - stat_a[0].tottime; } #endif double realTimeStart; int totNumFrames = 0; double ReadSysClock() { struct timeval tv; (void) gettimeofday(&tv, (struct timezone *)NULL); return (tv.tv_sec + tv.tv_usec / 1000000.0); } void PrintTimeInfo() { double spent; spent = ReadSysClock() - realTimeStart; if (!quietFlag) { printf("\nReal Time Spent (After Initializations): %f secs.\n", spent); printf("Avg. Frames/Sec: %f\n", ((double) totNumFrames) / spent); } } /* *-------------------------------------------------------------- * * NewVidStream -- * * Allocates and initializes a VidStream structure. Takes * as parameter requested size for buffer length. * * Results: * A pointer to the new VidStream structure. * * Side effects: * None. * *-------------------------------------------------------------- */ VidStream * NewVidStream(bufLength) int bufLength; { int i, j; VidStream *new; static unsigned char default_intra_matrix[64] = { 8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37, 19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40, 22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58, 26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83}; /* Check for legal buffer length. */ if (bufLength < 4) return NULL; /* Make buffer length multiple of 4. */ bufLength = (bufLength + 3) >> 2; /* Allocate memory for new structure. */ new = (VidStream *) malloc(sizeof(VidStream)); /* Initialize pointers to extension and user data. */ new->group.ext_data = new->group.user_data = new->picture.extra_info = new->picture.user_data = new->picture.ext_data = new->slice.extra_info = new->ext_data = new->user_data = NULL; /* Copy default intra matrix. */ for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { new->intra_quant_matrix[j][i] = default_intra_matrix[i * 8 + j]; } } /* Initialize crop table. */ for (i = (-MAX_NEG_CROP); i < NUM_CROP_ENTRIES - MAX_NEG_CROP; i++) { if (i <= 0) { cropTbl[i + MAX_NEG_CROP] = 0; } else if (i >= 255) { cropTbl[i + MAX_NEG_CROP] = 255; } else { cropTbl[i + MAX_NEG_CROP] = i; } } /* Initialize non intra quantization matrix. */ for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { new->non_intra_quant_matrix[j][i] = 16; } } /* Initialize pointers to image spaces. */ new->current = new->past = new->future = NULL; for (i = 0; i < RING_BUF_SIZE; i++) { new->ring[i] = NULL; } /* Create buffer. */ new->buf_start = (unsigned int *) malloc(bufLength * 4); /* * Set max_buf_length to one less than actual length to deal with messy * data without proper seq. end codes. */ new->max_buf_length = bufLength - 1; /* Initialize bitstream i/o fields. */ new->bit_offset = 0; new->buf_length = 0; new->buffer = new->buf_start; /* Return structure. */ return new; } /* *-------------------------------------------------------------- * * DestroyVidStream -- * * Deallocates a VidStream structure. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DestroyVidStream(astream) VidStream *astream; { int i; if (astream->ext_data != NULL) free(astream->ext_data); if (astream->user_data != NULL) free(astream->user_data); if (astream->group.ext_data != NULL) free(astream->group.ext_data); if (astream->group.user_data != NULL) free(astream->group.user_data); if (astream->picture.extra_info != NULL) free(astream->picture.extra_info); if (astream->picture.ext_data != NULL) free(astream->picture.ext_data); if (astream->picture.user_data != NULL) free(astream->picture.user_data); if (astream->slice.extra_info != NULL) free(astream->slice.extra_info); if (astream->buf_start != NULL) free(astream->buf_start); for (i = 0; i < RING_BUF_SIZE; i++) { if (astream->ring[i] != NULL) { DestroyPictImage(astream->ring[i]); astream->ring[i] = NULL; } } free((char *) astream); } /* *-------------------------------------------------------------- * * NewPictImage -- * * Allocates and initializes a PictImage structure. * The width and height of the image space are passed in * as parameters. * * Results: * A pointer to the new PictImage structure. * * Side effects: * None. * *-------------------------------------------------------------- */ PictImage * NewPictImage(width, height) unsigned int width, height; { PictImage *new; /* Allocate memory space for new structure. */ new = (PictImage *) malloc(sizeof(PictImage)); /* Allocate memory for image spaces. */ #ifdef SH_MEM new->ximage = NULL; if (shmemFlag) { Visual *fc_visual; int depth; Visual *FindFullColorVisual(); if (ditherType == Twox2_DITHER) { new->ximage = XShmCreateImage(display, None, 8, ZPixmap, NULL, &(new->shminfo), width * 2, height * 2); } else if (ditherType == FULL_COLOR_DITHER) { fc_visual = FindFullColorVisual(display, &depth); new->ximage = XShmCreateImage(display, fc_visual, depth, ZPixmap, NULL, &(new->shminfo), width, height); } else if (ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) { new->ximage = XShmCreateImage(display, None, 1, XYBitmap, NULL, &(new->shminfo), width, height); } else { new->ximage = XShmCreateImage(display, None, 8, ZPixmap, NULL, &(new->shminfo), width, height); } /* If no go, then revert to normal Xlib calls. */ if (new->ximage == NULL) { shmemFlag = 0; if (!quietFlag) { fprintf(stderr, "Shared memory error, disabling.\n"); fprintf(stderr, "Ximage error.\n"); } goto shmemerror; } /* Success here, continue. */ new->shminfo.shmid = shmget(IPC_PRIVATE, (new->ximage->bytes_per_line * new->ximage->height), IPC_CREAT | 0777); if (new->shminfo.shmid < 0) { XDestroyImage(new->ximage); new->ximage = NULL; shmemFlag = 0; if (!quietFlag) { fprintf(stderr, "Shared memory error, disabling.\n"); fprintf(stderr, "Seg. id. error.\n"); } goto shmemerror; } new->shminfo.shmaddr = (char *) shmat(new->shminfo.shmid, 0, 0); if (new->shminfo.shmaddr == ((char *) -1)) { XDestroyImage(new->ximage); new->ximage = NULL; shmemFlag = 0; if (!quietFlag) { fprintf(stderr, "Shared memory error, disabling.\n"); fprintf(stderr, "Address error.\n"); } goto shmemerror; } new->ximage->data = new->shminfo.shmaddr; new->display = (unsigned char *) new->ximage->data; new->shminfo.readOnly = False; XShmAttach(display, &(new->shminfo)); XSync(display, False); if (gXErrorFlag) { /* Ultimate failure here. */ XDestroyImage(new->ximage); new->ximage = NULL; shmemFlag = 0; if (!quietFlag) { fprintf(stderr, "Shared memory error, disabling.\n"); } gXErrorFlag = 0; goto shmemerror; } else { shmctl(new->shminfo.shmid, IPC_RMID, 0); } if (!quietFlag) { fprintf(stderr, "Sharing memory.\n"); } } else #endif { shmemerror: if ((ditherType == Twox2_DITHER) || (ditherType == FULL_COLOR_DITHER)) { new->display = (unsigned char *) malloc(width * height * 4); } else { new->display = (unsigned char *) malloc(width * height); } } new->luminance = (unsigned char *) malloc(width * height); new->Cr = (unsigned char *) malloc(width * height / 4); new->Cb = (unsigned char *) malloc(width * height / 4); /* Reset locked flag. */ new->locked = 0; /* Return pointer to new structure. */ return new; } /* *-------------------------------------------------------------- * * DestroyPictImage -- * * Deallocates a PictImage structure. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void DestroyPictImage(apictimage) PictImage *apictimage; { if (apictimage->luminance != NULL) { free(apictimage->luminance); } if (apictimage->Cr != NULL) { free(apictimage->Cr); } if (apictimage->Cb != NULL) { free(apictimage->Cb); } #ifdef SH_MEM if (apictimage->ximage != NULL) { XShmDetach(display, &(apictimage->shminfo)); XDestroyImage(apictimage->ximage); shmdt(apictimage->shminfo.shmaddr); apictimage->ximage = NULL; apictimage->display = NULL; } #endif if (apictimage->display != NULL) { free(apictimage->display); } free(apictimage); } /* *-------------------------------------------------------------- * * mpegVidRsrc -- * * Parses bit stream until MB_QUANTUM number of * macroblocks have been decoded or current slice or * picture ends, whichever comes first. If the start * of a frame is encountered, the frame is time stamped * with the value passed in time_stamp. If the value * passed in buffer is not null, the video stream buffer * is set to buffer and the length of the buffer is * expected in value passed in through length. The current * video stream is set to vid_stream. If vid_stream * is passed as NULL, a new VidStream structure is created * and initialized and used as the current video stream. * * Results: * A pointer to the video stream structure used. * * Side effects: * Bit stream is irreversibly parsed. If a picture is completed, * a function is called to display the frame at the correct time. * *-------------------------------------------------------------- */ VidStream * mpegVidRsrc(time_stamp, vid_stream) TimeStamp time_stamp; VidStream *vid_stream; { static int first = 1; unsigned int data; int i, status; /* If vid_stream is null, create new VidStream structure. */ if (vid_stream == NULL) { return NULL; } /* * Set global curVidStream to vid_stream. Necessary because bit i/o use * curVidStream and are not passed vid_stream. Also set global bitstream * parameters. */ curVidStream = vid_stream; bitOffset = curVidStream->bit_offset; #ifdef UTIL2 curBits = *curVidStream->buffer << bitOffset; #else curBits = *curVidStream->buffer; #endif bufLength = curVidStream->buf_length; bitBuffer = curVidStream->buffer; /* * If called for the first time, find start code, make sure it is a * sequence start code. */ if (first) { next_start_code(); show_bits32(data); if (data != SEQ_START_CODE) { fprintf(stderr, "This is not an MPEG stream."); DestroyVidStream(curVidStream); exit(1); } first = 0; } /* Get next 32 bits (size of start codes). */ show_bits32(data); /* * Process according to start code (or parse macroblock if not a start code * at all. */ switch (data) { case SEQ_END_CODE: /* Display last frame. */ if (vid_stream->future != NULL) { vid_stream->current = vid_stream->future; ExecuteDisplay(vid_stream); } /* Sequence done. Do the right thing. For right now, exit. */ if (!quietFlag) { fprintf(stderr, "\nDone!\n"); } #ifdef ANALYSIS PrintAllStats(); #endif PrintTimeInfo(); if (loopFlag) longjmp(env, 1); DestroyVidStream(curVidStream); exit(0); break; case SEQ_START_CODE: /* Sequence start code. Parse sequence header. */ if (ParseSeqHead(vid_stream) != PARSE_OK) goto error; /* * Return after sequence start code so that application above can use * info in header. */ goto done; case GOP_START_CODE: /* Group of Pictures start code. Parse gop header. */ if (ParseGOP(vid_stream) != PARSE_OK) goto error; case PICTURE_START_CODE: /* Picture start code. Parse picture header and first slice header. */ status = ParsePicture(vid_stream, time_stamp); if (status == SKIP_PICTURE) { next_start_code(); fprintf(stderr, "Skipping picture..."); while (!next_bits(32, PICTURE_START_CODE)) { if (next_bits(32, GOP_START_CODE)) break; else if (next_bits(32, SEQ_END_CODE)) break; flush_bits(24); next_start_code(); } fprintf(stderr, "Done.\n"); goto done; } else if (status != PARSE_OK) goto error; if (ParseSlice(vid_stream) != PARSE_OK) goto error; break; default: /* Check for slice start code. */ if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) { /* Slice start code. Parse slice header. */ if (ParseSlice(vid_stream) != PARSE_OK) goto error; } break; } /* Parse next MB_QUANTUM macroblocks. */ for (i = 0; i < MB_QUANTUM; i++) { /* Check to see if actually a startcode and not a macroblock. */ if (!next_bits(23, 0x00000000)) { /* Not start code. Parse Macroblock. */ if (ParseMacroBlock(vid_stream) != PARSE_OK) goto error; #ifdef ANALYSIS if (showmb_flag) { DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr, vid_stream->current->Cb, vid_stream->current->display, vid_stream->mb_height * 16, vid_stream->mb_width * 16); ExecuteDisplay(vid_stream); } #endif } else { /* Not macroblock, actually start code. Get start code. */ next_start_code(); show_bits32(data); /* * If start code is outside range of slice start codes, frame is * complete, display frame. */ if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) { #ifdef ANALYSIS EndTime(); stat_a[0].totsize += bitCountRead() - pictureSizeCount; if (showEachFlag) { PrintOneStat(); }; CollectStats(); #endif DoPictureDisplay(vid_stream); } break; } } /* Return pointer to video stream structure. */ goto done; error: fprintf(stderr, "Error!!!!\n"); next_start_code(); goto done; done: /* Copy global bit i/o variables back into vid_stream. */ vid_stream->buffer = bitBuffer; vid_stream->buf_length = bufLength; vid_stream->bit_offset = bitOffset; return vid_stream; } /* *-------------------------------------------------------------- * * ParseSeqHead -- * * Assumes bit stream is at the begining of the sequence * header start code. Parses off the sequence header. * * Results: * Fills the vid_stream structure with values derived and * decoded from the sequence header. Allocates the pict image * structures based on the dimensions of the image space * found in the sequence header. * * Side effects: * Bit stream irreversibly parsed off. * *-------------------------------------------------------------- */ static int ParseSeqHead(vid_stream) VidStream *vid_stream; { unsigned int data; int i; /* Flush off sequence start code. */ flush_bits32; /* Get horizontal size of image space. */ get_bits12(data); vid_stream->h_size = data; /* Get vertical size of image space. */ get_bits12(data); vid_stream->v_size = data; /* Calculate macroblock width and height of image space. */ vid_stream->mb_width = (vid_stream->h_size + 15) / 16; vid_stream->mb_height = (vid_stream->v_size + 15) / 16; /* If dither type is MBORDERED allocate ditherFlags. */ if (ditherType == MBORDERED_DITHER) { ditherFlags = (char *) malloc(vid_stream->mb_width*vid_stream->mb_height); } /* Initialize lmaxx, lmaxy, cmaxx, cmaxy. */ lmaxx = vid_stream->mb_width*16-1; lmaxy = vid_stream->mb_height*16-1; cmaxx = vid_stream->mb_width*8-1; cmaxy = vid_stream->mb_height*8-1; /* * Initialize ring buffer of pict images now that dimensions of image space * are known. */ #ifdef SH_MEM if (display != NULL) { InstallXErrorHandler(); } #endif if (vid_stream->ring[0] == NULL) { for (i = 0; i < RING_BUF_SIZE; i++) { vid_stream->ring[i] = NewPictImage(vid_stream->mb_width * 16, vid_stream->mb_height * 16); } } #ifdef SH_MEM if (display != NULL) { DeInstallXErrorHandler(); } #endif /* Parse of aspect ratio code. */ get_bits4(data); vid_stream->aspect_ratio = (unsigned char) data; /* Parse off picture rate code. */ get_bits4(data); vid_stream->picture_rate = (unsigned char) data; /* Parse off bit rate. */ get_bits18(data); vid_stream->bit_rate = data; /* Flush marker bit. */ flush_bits(1); /* Parse off vbv buffer size. */ get_bits10(data); vid_stream->vbv_buffer_size = data; /* Parse off contrained parameter flag. */ get_bits1(data); if (data) { vid_stream->const_param_flag = TRUE; } else vid_stream->const_param_flag = FALSE; /* * If intra_quant_matrix_flag set, parse off intra quant matrix values. */ get_bits1(data); if (data) { for (i = 0; i < 64; i++) { get_bits8(data); vid_stream->intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = (unsigned char) data; } } /* * If non intra quant matrix flag set, parse off non intra quant matrix * values. */ get_bits1(data); if (data) { for (i = 0; i < 64; i++) { get_bits8(data); vid_stream->non_intra_quant_matrix[zigzag[i][1]][zigzag[i][0]] = (unsigned char) data; } } /* Go to next start code. */ next_start_code(); /* * If next start code is extension start code, parse off extension data. */ if (next_bits(32, EXT_START_CODE)) { flush_bits32; if (vid_stream->ext_data != NULL) { free(vid_stream->ext_data); vid_stream->ext_data = NULL; } vid_stream->ext_data = get_ext_data(); } /* If next start code is user start code, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits32; if (vid_stream->user_data != NULL) { free(vid_stream->user_data); vid_stream->user_data = NULL; } vid_stream->user_data = get_ext_data(); } return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseGOP -- * * Parses of group of pictures header from bit stream * associated with vid_stream. * * Results: * Values in gop header placed into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParseGOP(vid_stream) VidStream *vid_stream; { unsigned int data; /* Flush group of pictures start code. WWWWWWOOOOOOOSSSSSSHHHHH!!! */ flush_bits32; /* Parse off drop frame flag. */ get_bits1(data); if (data) { vid_stream->group.drop_flag = TRUE; } else vid_stream->group.drop_flag = FALSE; /* Parse off hour component of time code. */ get_bits5(data); vid_stream->group.tc_hours = data; /* Parse off minute component of time code. */ get_bits6(data); vid_stream->group.tc_minutes = data; /* Flush marker bit. */ flush_bits(1); /* Parse off second component of time code. */ get_bits6(data); vid_stream->group.tc_seconds = data; /* Parse off picture count component of time code. */ get_bits6(data); vid_stream->group.tc_pictures = data; /* Parse off closed gop and broken link flags. */ get_bits2(data); if (data > 1) { vid_stream->group.closed_gop = TRUE; if (data > 2) { vid_stream->group.broken_link = TRUE; } else vid_stream->group.broken_link = FALSE; } else { vid_stream->group.closed_gop = FALSE; if (data) { vid_stream->group.broken_link = TRUE; } else vid_stream->group.broken_link = FALSE; } /* Goto next start code. */ next_start_code(); /* If next start code is extension data, parse off extension data. */ if (next_bits(32, EXT_START_CODE)) { flush_bits32; if (vid_stream->group.ext_data != NULL) { free(vid_stream->group.ext_data); vid_stream->group.ext_data = NULL; } vid_stream->group.ext_data = get_ext_data(); } /* If next start code is user data, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits32; if (vid_stream->group.user_data != NULL) { free(vid_stream->group.user_data); vid_stream->group.user_data = NULL; } vid_stream->group.user_data = get_ext_data(); } return PARSE_OK; } /* *-------------------------------------------------------------- * * ParsePicture -- * * Parses picture header. Marks picture to be presented * at particular time given a time stamp. * * Results: * Values from picture header put into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParsePicture(vid_stream, time_stamp) VidStream *vid_stream; TimeStamp time_stamp; { unsigned int data; int i; /* Flush header start code. */ flush_bits32; /* Parse off temporal reference. */ get_bits10(data); vid_stream->picture.temp_ref = data; /* Parse of picture type. */ get_bits3(data); vid_stream->picture.code_type = data; if ((vid_stream->picture.code_type == B_TYPE) && (No_B_Flag || (vid_stream->past == NULL) || (vid_stream->future == NULL))) return SKIP_PICTURE; if ((vid_stream->picture.code_type == P_TYPE) && (No_P_Flag || (vid_stream->future == NULL))) return SKIP_PICTURE; #ifdef ANALYSIS StartTime(); stat_a[0].frametype = vid_stream->picture.code_type; stat_a[0].number = 1; stat_a[0].totsize = 45; pictureSizeCount = bitCountRead(); #endif /* Parse off vbv buffer delay value. */ get_bits16(data); vid_stream->picture.vbv_delay = data; /* If P or B type frame... */ if ((vid_stream->picture.code_type == 2) || (vid_stream->picture.code_type == 3)) { /* Parse off forward vector full pixel flag. */ get_bits1(data); if (data) vid_stream->picture.full_pel_forw_vector = TRUE; else vid_stream->picture.full_pel_forw_vector = FALSE; /* Parse of forw_r_code. */ get_bits3(data); /* Decode forw_r_code into forw_r_size and forw_f. */ vid_stream->picture.forw_r_size = data - 1; vid_stream->picture.forw_f = (1 << vid_stream->picture.forw_r_size); } /* If B type frame... */ if (vid_stream->picture.code_type == 3) { /* Parse off back vector full pixel flag. */ get_bits1(data); if (data) vid_stream->picture.full_pel_back_vector = TRUE; else vid_stream->picture.full_pel_back_vector = FALSE; /* Parse off back_r_code. */ get_bits3(data); /* Decode back_r_code into back_r_size and back_f. */ vid_stream->picture.back_r_size = data - 1; vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size); } /* Get extra bit picture info. */ if (vid_stream->picture.extra_info != NULL) { free(vid_stream->picture.extra_info); vid_stream->picture.extra_info = NULL; } vid_stream->picture.extra_info = get_extra_bit_info(); /* Goto next start code. */ next_start_code(); /* If start code is extension start code, parse off extension data. */ if (next_bits(32, EXT_START_CODE)) { flush_bits32; if (vid_stream->picture.ext_data != NULL) { free(vid_stream->picture.ext_data); vid_stream->picture.ext_data = NULL; } vid_stream->picture.ext_data = get_ext_data(); } /* If start code is user start code, parse off user data. */ if (next_bits(32, USER_START_CODE)) { flush_bits32; if (vid_stream->picture.user_data != NULL) { free(vid_stream->picture.user_data); vid_stream->picture.user_data = NULL; } vid_stream->picture.user_data = get_ext_data(); } /* Find a pict image structure in ring buffer not currently locked. */ i = 0; while (vid_stream->ring[i]->locked != 0) { if (++i >= RING_BUF_SIZE) { perror("Fatal error. Ring buffer full."); exit(1); } } /* Set current pict image structure to the one just found in ring. */ vid_stream->current = vid_stream->ring[i]; /* Set time stamp. */ vid_stream->current->show_time = time_stamp; /* Reset past macroblock address field. */ vid_stream->mblock.past_mb_addr = -1; return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseSlice -- * * Parses off slice header. * * Results: * Values found in slice header put into video stream structure. * * Side effects: * Bit stream irreversibly parsed. * *-------------------------------------------------------------- */ static int ParseSlice(vid_stream) VidStream *vid_stream; { unsigned int data; /* Flush slice start code. */ flush_bits(24); /* Parse off slice vertical position. */ get_bits8(data); vid_stream->slice.vert_pos = data; /* Parse off quantization scale. */ get_bits5(data); vid_stream->slice.quant_scale = data; /* Parse off extra bit slice info. */ if (vid_stream->slice.extra_info != NULL) { free(vid_stream->slice.extra_info); vid_stream->slice.extra_info = NULL; } vid_stream->slice.extra_info = get_extra_bit_info(); /* Reset past intrablock address. */ vid_stream->mblock.past_intra_addr = -2; /* Reset previous recon motion vectors. */ vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; vid_stream->mblock.recon_right_back_prev = 0; vid_stream->mblock.recon_down_back_prev = 0; /* Reset macroblock address. */ vid_stream->mblock.mb_address = ((vid_stream->slice.vert_pos - 1) * vid_stream->mb_width) - 1; /* Reset past dct dc y, cr, and cb values. */ vid_stream->block.dct_dc_y_past = 1024; vid_stream->block.dct_dc_cr_past = 1024; vid_stream->block.dct_dc_cb_past = 1024; return PARSE_OK; } /* *-------------------------------------------------------------- * * ParseMacroBlock -- * * Parseoff macroblock. Reconstructs DCT values. Applies * inverse DCT, reconstructs motion vectors, calculates and * set pixel values for macroblock in current pict image * structure. * * Results: * Here's where everything really happens. Welcome to the * heart of darkness. * * Side effects: * Bit stream irreversibly parsed off. * *-------------------------------------------------------------- */ static int ParseMacroBlock(vid_stream) VidStream *vid_stream; { int addr_incr; unsigned int data; int mask, i, recon_right_for, recon_down_for, recon_right_back, recon_down_back; int zero_block_flag; BOOLEAN mb_quant, mb_motion_forw, mb_motion_back, mb_pattern; int no_dith_flag = 0; #ifdef ANALYSIS mbSizeCount = bitCountRead(); #endif /* * Parse off macroblock address increment and add to macroblock address. */ do { DecodeMBAddrInc(addr_incr); if (addr_incr == MB_ESCAPE) { vid_stream->mblock.mb_address += 33; addr_incr = MB_STUFFING; } } while (addr_incr == MB_STUFFING); vid_stream->mblock.mb_address += addr_incr; if (vid_stream->mblock.mb_address > (vid_stream->mb_height * vid_stream->mb_width - 1)) return SKIP_TO_START_CODE; /* * If macroblocks have been skipped, process skipped macroblocks. */ if (vid_stream->mblock.mb_address - vid_stream->mblock.past_mb_addr > 1) { if (vid_stream->picture.code_type == P_TYPE) ProcessSkippedPFrameMBlocks(vid_stream); else if (vid_stream->picture.code_type == B_TYPE) ProcessSkippedBFrameMBlocks(vid_stream); } /* Set past macroblock address to current macroblock address. */ vid_stream->mblock.past_mb_addr = vid_stream->mblock.mb_address; /* Based on picture type decode macroblock type. */ switch (vid_stream->picture.code_type) { case I_TYPE: DecodeMBTypeI(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, vid_stream->mblock.mb_intra); break; case P_TYPE: DecodeMBTypeP(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, vid_stream->mblock.mb_intra); break; case B_TYPE: DecodeMBTypeB(mb_quant, mb_motion_forw, mb_motion_back, mb_pattern, vid_stream->mblock.mb_intra); break; } /* If quantization flag set, parse off new quantization scale. */ if (mb_quant == TRUE) { get_bits5(data); vid_stream->slice.quant_scale = data; } /* If forward motion vectors exist... */ if (mb_motion_forw == TRUE) { /* Parse off and decode horizontal forward motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_h_forw_code); /* If horiz. forward r data exists, parse off. */ if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_h_forw_code != 0)) { get_bitsn(vid_stream->picture.forw_r_size, data); vid_stream->mblock.motion_h_forw_r = data; } /* Parse off and decode vertical forward motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_v_forw_code); /* If vert. forw. r data exists, parse off. */ if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_v_forw_code != 0)) { get_bitsn(vid_stream->picture.forw_r_size, data); vid_stream->mblock.motion_v_forw_r = data; } } /* If back motion vectors exist... */ if (mb_motion_back == TRUE) { /* Parse off and decode horiz. back motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_h_back_code); /* If horiz. back r data exists, parse off. */ if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_h_back_code != 0)) { get_bitsn(vid_stream->picture.back_r_size, data); vid_stream->mblock.motion_h_back_r = data; } /* Parse off and decode vert. back motion vector. */ DecodeMotionVectors(vid_stream->mblock.motion_v_back_code); /* If vert. back r data exists, parse off. */ if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_v_back_code != 0)) { get_bitsn(vid_stream->picture.back_r_size, data); vid_stream->mblock.motion_v_back_r = data; } } #ifdef ANALYSIS if (vid_stream->mblock.mb_intra) { stat_a[0].i_mbnum++; mbCBPPtr = stat_a[0].i_mbcbp; mbCoeffPtr = stat_a[0].i_mbcoeff; mbSizePtr = &(stat_a[0].i_mbsize); } else if (mb_motion_back && mb_motion_forw) { stat_a[0].bi_mbnum++; mbCBPPtr = stat_a[0].bi_mbcbp; mbCoeffPtr = stat_a[0].bi_mbcoeff; mbSizePtr = &(stat_a[0].bi_mbsize); } else if (mb_motion_back) { stat_a[0].b_mbnum++; mbCBPPtr = stat_a[0].b_mbcbp; mbCoeffPtr = stat_a[0].b_mbcoeff; mbSizePtr = &(stat_a[0].b_mbsize); } else { stat_a[0].p_mbnum++; mbCBPPtr = stat_a[0].p_mbcbp; mbCoeffPtr = stat_a[0].p_mbcoeff; mbSizePtr = &(stat_a[0].p_mbsize); } #endif /* If mblock pattern flag set, parse and decode CBP (code block pattern). */ if (mb_pattern == TRUE) { DecodeCBP(vid_stream->mblock.cbp); } /* Otherwise, set CBP to zero. */ else vid_stream->mblock.cbp = 0; #ifdef ANALYSIS mbCBPPtr[vid_stream->mblock.cbp]++; #endif /* Reconstruct motion vectors depending on picture type. */ if (vid_stream->picture.code_type == P_TYPE) { /* * If no forw motion vectors, reset previous and current vectors to 0. */ if (!mb_motion_forw) { recon_right_for = 0; recon_down_for = 0; vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; } /* * Otherwise, compute new forw motion vectors. Reset previous vectors to * current vectors. */ else { ComputeForwVector(&recon_right_for, &recon_down_for); } } if (vid_stream->picture.code_type == B_TYPE) { /* Reset prev. and current vectors to zero if mblock is intracoded. */ if (vid_stream->mblock.mb_intra) { vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; vid_stream->mblock.recon_right_back_prev = 0; vid_stream->mblock.recon_down_back_prev = 0; } else { /* If no forw vectors, current vectors equal prev. vectors. */ if (!mb_motion_forw) { recon_right_for = vid_stream->mblock.recon_right_for_prev; recon_down_for = vid_stream->mblock.recon_down_for_prev; } /* * Otherwise compute forw. vectors. Reset prev vectors to new values. */ else { ComputeForwVector(&recon_right_for, &recon_down_for); } /* If no back vectors, set back vectors to prev back vectors. */ if (!mb_motion_back) { recon_right_back = vid_stream->mblock.recon_right_back_prev; recon_down_back = vid_stream->mblock.recon_down_back_prev; } /* Otherwise compute new vectors and reset prev. back vectors. */ else { ComputeBackVector(&recon_right_back, &recon_down_back); } /* * Store vector existance flags in structure for possible skipped * macroblocks to follow. */ vid_stream->mblock.bpict_past_forw = mb_motion_forw; vid_stream->mblock.bpict_past_back = mb_motion_back; } } /* For each possible block in macroblock. */ if (ditherType == GRAY_DITHER || ditherType == MONO_DITHER || ditherType == MONO_THRESHOLD) { for (mask = 32, i = 0; i < 4; mask >>= 1, i++) { /* If block exists... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { zero_block_flag = 0; ParseReconBlock(i); } else { zero_block_flag = 1; } /* If macroblock is intra coded... */ if (vid_stream->mblock.mb_intra) { ReconIMBlock(vid_stream, i); } else if (mb_motion_forw && mb_motion_back) { ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag); } else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) { ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, zero_block_flag); } else if (mb_motion_back) { ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, zero_block_flag); } } /* Kill the Chrominace blocks... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x2)) { ParseAwayBlock(4); } if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x1)) { ParseAwayBlock(5); } } else { if ((ditherType == MBORDERED_DITHER) && (vid_stream->mblock.cbp == 0) && (vid_stream->picture.code_type == 3) && (!vid_stream->mblock.mb_intra) && (!(mb_motion_forw && mb_motion_back))) { MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address, mb_motion_forw, recon_right_for, recon_down_for, mb_motion_back, recon_right_back, recon_down_back, vid_stream->past->display, vid_stream->future->display); ditherFlags[vid_stream->mblock.mb_address] = 0; no_dith_flag = 1; } else { for (mask = 32, i = 0; i < 6; mask >>= 1, i++) { /* If block exists... */ if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) { zero_block_flag = 0; ParseReconBlock(i); } else { zero_block_flag = 1; } /* If macroblock is intra coded... */ if (vid_stream->mblock.mb_intra) { ReconIMBlock(vid_stream, i); } else if (mb_motion_forw && mb_motion_back) { ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag); } else if (mb_motion_forw || (vid_stream->picture.code_type == P_TYPE)) { ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for, zero_block_flag); } else if (mb_motion_back) { ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back, zero_block_flag); } } } } if ((ditherType == MBORDERED_DITHER) && (!no_dith_flag)) { if ((vid_stream->picture.code_type == 2) && (vid_stream->mblock.cbp == 0) && (!vid_stream->mblock.mb_intra)) { MBOrderedDitherDisplayCopy(vid_stream, vid_stream->mblock.mb_address, 1, recon_right_for, recon_down_for, 0, 0, 0, vid_stream->future->display, (unsigned char *) NULL); ditherFlags[vid_stream->mblock.mb_address] = 0; } else { ditherFlags[vid_stream->mblock.mb_address] = 1; } } /* If D Type picture, flush marker bit. */ if (vid_stream->picture.code_type == 4) flush_bits(1); /* If macroblock was intracoded, set macroblock past intra address. */ if (vid_stream->mblock.mb_intra) vid_stream->mblock.past_intra_addr = vid_stream->mblock.mb_address; #ifdef ANALYSIS *mbSizePtr += bitCountRead() - mbSizeCount; #endif return PARSE_OK; } /* *-------------------------------------------------------------- * * ReconIMBlock -- * * Reconstructs intra coded macroblock. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconIMBlock(vid_stream, bnum) VidStream *vid_stream; int bnum; { int mb_row, mb_col, row, col, row_size, rr; unsigned char *dest; /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum < 4) { /* Calculate row and col values for upper left pixel of block. */ row = mb_row * 16; col = mb_col * 16; if (bnum > 1) row += 8; if (bnum % 2) col += 8; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* Establish row size. */ row_size = vid_stream->mb_width * 16; } /* Otherwise if block is Cr block... */ else if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* Establish row size. */ row_size = vid_stream->mb_width * 8; /* Calculate row,col for upper left pixel of block. */ row = mb_row * 8; col = mb_col * 8; } /* Otherwise block is Cb block, and ... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* Establish row size. */ row_size = vid_stream->mb_width * 8; /* Calculate row,col for upper left pixel value of block. */ row = mb_row * 8; col = mb_col * 8; } /* * For each pixel in block, set to cropped reconstructed value from inverse * dct. */ { short *sp = &vid_stream->block.dct_recon[0][0]; unsigned char *cm = cropTbl + MAX_NEG_CROP; dest += row * row_size + col; for (rr = 0; rr < 4; rr++, sp += 16, dest += row_size) { dest[0] = cm[sp[0]]; assertCrop(sp[0]); dest[1] = cm[sp[1]]; assertCrop(sp[1]); dest[2] = cm[sp[2]]; assertCrop(sp[2]); dest[3] = cm[sp[3]]; assertCrop(sp[3]); dest[4] = cm[sp[4]]; assertCrop(sp[4]); dest[5] = cm[sp[5]]; assertCrop(sp[5]); dest[6] = cm[sp[6]]; assertCrop(sp[6]); dest[7] = cm[sp[7]]; assertCrop(sp[7]); dest += row_size; dest[0] = cm[sp[8]]; assertCrop(sp[8]); dest[1] = cm[sp[9]]; assertCrop(sp[9]); dest[2] = cm[sp[10]]; assertCrop(sp[10]); dest[3] = cm[sp[11]]; assertCrop(sp[11]); dest[4] = cm[sp[12]]; assertCrop(sp[12]); dest[5] = cm[sp[13]]; assertCrop(sp[13]); dest[6] = cm[sp[14]]; assertCrop(sp[14]); dest[7] = cm[sp[15]]; assertCrop(sp[15]); } } } /* *-------------------------------------------------------------- * * ReconPMBlock -- * * Reconstructs forward predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconPMBlock(vid_stream, bnum, recon_right_for, recon_down_for, zflag) VidStream *vid_stream; int bnum, recon_right_for, recon_down_for, zflag; { int mb_row, mb_col, row, col, row_size, rr; unsigned char *dest, *past; static int right_for, down_for, right_half_for, down_half_for; unsigned char *rindex1, *rindex2; unsigned char *index; short int *blockvals; #ifdef LOOSE_MPEG int maxx, maxy; int illegalBlock = 0; int row_start, row_end, rfirst, rlast, col_start, col_end, cfirst, clast; #endif /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; if (bnum < 4) { /* Calculate right_for, down_for motion vectors. */ right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past != NULL) past = vid_stream->past->luminance; } else { /* Set predicitive frame to current future frame. */ if (vid_stream->future != NULL) past = vid_stream->future->luminance; } /* Establish row size. */ row_size = vid_stream->mb_width << 4; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 4; col = mb_col << 4; if (bnum > 1) row += 8; if (bnum % 2) col += 8; #ifdef LOOSE_MPEG /* Check for block illegality. */ maxx = lmaxx; maxy = lmaxy; if (row + down_for + 7 > maxy) illegalBlock |= 0x4; else if (row + down_for < 0) illegalBlock |= 0x1; if (col + right_for + 7 > maxx) illegalBlock |= 0x2; else if (col + right_for < 0) illegalBlock |= 0x8; #endif } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ recon_right_for /= 2; recon_down_for /= 2; right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; /* Establish row size. */ row_size = vid_stream->mb_width << 3; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 3; col = mb_col << 3; #ifdef LOOSE_MPEG /* Check for block illegality. */ maxx = cmaxx; maxy = cmaxy; if (row + down_for + 7 > maxy) illegalBlock |= 0x4; else if (row + down_for < 0) illegalBlock |= 0x1; if (col + right_for + 7 > maxx) illegalBlock |= 0x2; else if (col + right_for < 0) illegalBlock |= 0x8; #endif /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past != NULL) past = vid_stream->past->Cr; } else { if (vid_stream->future != NULL) past = vid_stream->future->Cr; } } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; if (vid_stream->picture.code_type == B_TYPE) { if (vid_stream->past != NULL) past = vid_stream->past->Cb; } else { if (vid_stream->future != NULL) past = vid_stream->future->Cb; } } } /* For each pixel in block... */ #ifdef LOOSE_MPEG if (illegalBlock) { if (illegalBlock & 0x1) { row_start = 0; row_end = row+down_for+8; rfirst = rlast = 8 - row_end; } else if (illegalBlock & 0x4) { row_start = row + down_for; row_end = maxy+1; rlast = row_end - row_start - 1; rfirst = 0; } else { row_start = row+down_for; row_end = row_start+8; rfirst = 0; } if (illegalBlock & 0x8) { col_start = 0; col_end = col + right_for + 8; cfirst = clast = 8 - col_end; } else if (illegalBlock & 0x2) { col_start = col + right_for; col_end = maxx + 1; clast = col_end - col_start - 1; cfirst = 0; } else { col_start = col + right_for; col_end = col_start + 8; cfirst = 0; } for (rr = row_start; rr < row_end; rr++) { rindex1 = past + (rr * row_size) + col_start; index = dest + ((row + rfirst) * row_size) + col + cfirst; for (cc = col_start; cc < col_end; cc++) { *index++ = *rindex1++; } } if (illegalBlock & 0x1) { for (rr = rlast -1; rr >=0; rr--) { index = dest + ((row + rr) * row_size) + col; rindex1 = dest + ((row + rlast) * row_size) + col; for (cc = 0; cc < 8; cc ++) { *index++ = *rindex1++; } } } else if (illegalBlock & 0x4) { for (rr = rlast+1; rr < 8; rr++) { index = dest + ((row + rr) * row_size) + col; rindex1 = dest + ((row + rlast) * row_size) + col; for (cc = 0; cc < 8; cc ++) { *index++ = *rindex1++; } } } if (illegalBlock & 0x2) { for (cc = clast+1; cc < 8; cc++) { index = dest + (row * row_size) + (col + cc); rindex1 = dest + (row * row_size) + (col + clast); for (rr = 0; rr < 8; rr++) { *index = *rindex1; index += row_size; rindex1 += row_size; } } } else if (illegalBlock & 0x8) { for (cc = clast-1; cc >= 0; cc--) { index = dest + (row * row_size) + (col + cc); rindex1 = dest + (row * row_size) + (col + clast); for (rr = 0; rr < 8; rr++) { *index = *rindex1; index += row_size; rindex1 += row_size; } } } if (!zflag) { for (rr = 0; rr < 8; rr++) { index = dest + (row*row_size) + col; blockvals = &(vid_stream->block.dct_recon[rr][0]); index[0] += blockvals[0]; index[1] += blockvals[1]; index[2] += blockvals[2]; index[3] += blockvals[3]; index[4] += blockvals[4]; index[5] += blockvals[5]; index[6] += blockvals[6]; index[7] += blockvals[7]; } } } else { #endif index = dest + (row * row_size) + col; rindex1 = past + (row + down_for) * row_size + col + right_for; blockvals = &(vid_stream->block.dct_recon[0][0]); /* * Calculate predictive pixel value based on motion vectors and copy to * dest plane. */ if ((!down_half_for) && (!right_half_for)) { unsigned char *cm = cropTbl + MAX_NEG_CROP; if (!zflag) for (rr = 0; rr < 4; rr++) { index[0] = cm[(int) rindex1[0] + (int) blockvals[0]]; index[1] = cm[(int) rindex1[1] + (int) blockvals[1]]; index[2] = cm[(int) rindex1[2] + (int) blockvals[2]]; index[3] = cm[(int) rindex1[3] + (int) blockvals[3]]; index[4] = cm[(int) rindex1[4] + (int) blockvals[4]]; index[5] = cm[(int) rindex1[5] + (int) blockvals[5]]; index[6] = cm[(int) rindex1[6] + (int) blockvals[6]]; index[7] = cm[(int) rindex1[7] + (int) blockvals[7]]; index += row_size; rindex1 += row_size; index[0] = cm[(int) rindex1[0] + (int) blockvals[8]]; index[1] = cm[(int) rindex1[1] + (int) blockvals[9]]; index[2] = cm[(int) rindex1[2] + (int) blockvals[10]]; index[3] = cm[(int) rindex1[3] + (int) blockvals[11]]; index[4] = cm[(int) rindex1[4] + (int) blockvals[12]]; index[5] = cm[(int) rindex1[5] + (int) blockvals[13]]; index[6] = cm[(int) rindex1[6] + (int) blockvals[14]]; index[7] = cm[(int) rindex1[7] + (int) blockvals[15]]; blockvals += 16; index += row_size; rindex1 += row_size; } else { if (right_for & 0x1) { /* No alignment, use bye copy */ for (rr = 0; rr < 4; rr++) { index[0] = rindex1[0]; index[1] = rindex1[1]; index[2] = rindex1[2]; index[3] = rindex1[3]; index[4] = rindex1[4]; index[5] = rindex1[5]; index[6] = rindex1[6]; index[7] = rindex1[7]; index += row_size; rindex1 += row_size; index[0] = rindex1[0]; index[1] = rindex1[1]; index[2] = rindex1[2]; index[3] = rindex1[3]; index[4] = rindex1[4]; index[5] = rindex1[5]; index[6] = rindex1[6]; index[7] = rindex1[7]; index += row_size; rindex1 += row_size; } } else if (right_for & 0x2) { /* Half-word bit aligned, use 16 bit copy */ short *src = (short *)rindex1; short *dest = (short *)index; row_size >>= 1; for (rr = 0; rr < 4; rr++) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_size; src += row_size; dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_size; src += row_size; } } else { /* Word aligned, use 32 bit copy */ int *src = (int *)rindex1; int *dest = (int *)index; row_size >>= 2; for (rr = 0; rr < 4; rr++) { dest[0] = src[0]; dest[1] = src[1]; dest += row_size; src += row_size; dest[0] = src[0]; dest[1] = src[1]; dest += row_size; src += row_size; } } } } else { unsigned char *cm = cropTbl + MAX_NEG_CROP; rindex2 = rindex1 + right_half_for + (down_half_for * row_size); if (!zflag) for (rr = 0; rr < 4; rr++) { index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[0]]; index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[1]]; index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[2]]; index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[3]]; index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[4]]; index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[5]]; index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[6]]; index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[7]]; index += row_size; rindex1 += row_size; rindex2 += row_size; index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[8]]; index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[9]]; index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[10]]; index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[11]]; index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[12]]; index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[13]]; index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[14]]; index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[15]]; blockvals += 16; index += row_size; rindex1 += row_size; rindex2 += row_size; } else for (rr = 0; rr < 4; rr++) { index[0] = (int) (rindex1[0] + rindex2[0]) >> 1; index[1] = (int) (rindex1[1] + rindex2[1]) >> 1; index[2] = (int) (rindex1[2] + rindex2[2]) >> 1; index[3] = (int) (rindex1[3] + rindex2[3]) >> 1; index[4] = (int) (rindex1[4] + rindex2[4]) >> 1; index[5] = (int) (rindex1[5] + rindex2[5]) >> 1; index[6] = (int) (rindex1[6] + rindex2[6]) >> 1; index[7] = (int) (rindex1[7] + rindex2[7]) >> 1; index += row_size; rindex1 += row_size; rindex2 += row_size; index[0] = (int) (rindex1[0] + rindex2[0]) >> 1; index[1] = (int) (rindex1[1] + rindex2[1]) >> 1; index[2] = (int) (rindex1[2] + rindex2[2]) >> 1; index[3] = (int) (rindex1[3] + rindex2[3]) >> 1; index[4] = (int) (rindex1[4] + rindex2[4]) >> 1; index[5] = (int) (rindex1[5] + rindex2[5]) >> 1; index[6] = (int) (rindex1[6] + rindex2[6]) >> 1; index[7] = (int) (rindex1[7] + rindex2[7]) >> 1; index += row_size; rindex1 += row_size; rindex2 += row_size; } } #ifdef LOOSE_MPEG } #endif } /* *-------------------------------------------------------------- * * ReconBMBlock -- * * Reconstructs back predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBMBlock(vid_stream, bnum, recon_right_back, recon_down_back, zflag) VidStream *vid_stream; int bnum, recon_right_back, recon_down_back, zflag; { int mb_row, mb_col, row, col, row_size, rr; unsigned char *dest, *future; int right_back, down_back, right_half_back, down_half_back; unsigned char *rindex1, *rindex2; unsigned char *index; short int *blockvals; #ifdef LOOSE_MPEG int illegalBlock = 0; int maxx, maxy; int row_start, row_end, rlast, rfirst, col_start, col_end, clast, cfirst; #endif /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum < 4) { /* Calculate right_back, down_bakc motion vectors. */ right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* * If future frame exists, set future to luminance plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->luminance; /* Establish row size. */ row_size = vid_stream->mb_width << 4; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 4; col = mb_col << 4; if (bnum > 1) row += 8; if (bnum % 2) col += 8; #ifdef LOOSE_MPEG /* Check for block illegality. */ maxx = lmaxx; maxy = lmaxy; if (row + down_back + 7 > maxy) illegalBlock |= 0x4; else if (row + down_back < 0) illegalBlock |= 0x1; if (col + right_back + 7 > maxx) illegalBlock |= 0x2; else if (col + right_back < 0) illegalBlock |= 0x8; #endif } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ recon_right_back /= 2; recon_down_back /= 2; right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* Establish row size. */ row_size = vid_stream->mb_width << 3; /* Calculate row,col of upper left pixel in block. */ row = mb_row << 3; col = mb_col << 3; #ifdef LOOSE_MPEG /* Check for block illegality. */ maxx = cmaxx; maxy = cmaxy; if (row + down_back + 7 > maxy) illegalBlock |= 0x4; else if (row + down_back < 0) illegalBlock |= 0x1; if (col + right_back + 7 > maxx) illegalBlock |= 0x2; else if (col + right_back < 0) illegalBlock |= 0x8; #endif /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* * If future frame exists, set future to Cr plane of future image. */ if (vid_stream->future != NULL) future = vid_stream->future->Cr; } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* * If future frame exists, set future to Cb plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->Cb; } } /* For each pixel in block do... */ #ifdef LOOSE_MPEG if (illegalBlock) { if (illegalBlock & 0x1) { row_start = 0; row_end = row+down_back+8; rfirst = rlast = 8 - row_end; } else if (illegalBlock & 0x4) { row_start = row + down_back; row_end = maxy+1; rlast = row_end - row_start - 1; rfirst = 0; } else { row_start = row+down_back; row_end = row_start+8; rfirst = 0; } if (illegalBlock & 0x8) { col_start = 0; col_end = col + right_back + 8; cfirst = clast = 8 - col_end; } else if (illegalBlock & 0x2) { col_start = col + right_back; col_end = maxx + 1; clast = col_end - col_start - 1; cfirst = 0; } else { col_start = col + right_back; col_end = col_start + 8; cfirst = 0; } for (rr = row_start; rr < row_end; rr++) { rindex1 = future + (rr * row_size) + col_start; index = dest + ((row + rfirst) * row_size) + col + cfirst; for (cc = col_start; cc < col_end; cc++) { *index++ = *rindex1++; } } if (illegalBlock & 0x1) { for (rr = rlast -1; rr >=0; rr--) { index = dest + ((row + rr) * row_size) + col; rindex1 = dest + ((row + rlast) * row_size) + col; for (cc = 0; cc < 8; cc ++) { *index++ = *rindex1++; } } } else if (illegalBlock & 0x4) { for (rr = rlast+1; rr < 8; rr++) { index = dest + ((row + rr) * row_size) + col; rindex1 = dest + ((row + rlast) * row_size) + col; for (cc = 0; cc < 8; cc ++) { *index++ = *rindex1++; } } } if (illegalBlock & 0x2) { for (cc = clast+1; cc < 8; cc++) { index = dest + (row * row_size) + (col + cc); rindex1 = dest + (row * row_size) + (col + clast); for (rr = 0; rr < 8; rr++) { *index = *rindex1; index += row_size; rindex1 += row_size; } } } else if (illegalBlock & 0x8) { for (cc = clast-1; cc >= 0; cc--) { index = dest + (row * row_size) + (col + cc); rindex1 = dest + (row * row_size) + (col + clast); for (rr = 0; rr < 8; rr++) { *index = *rindex1; index += row_size; rindex1 += row_size; } } } if (!zflag) { for (rr = 0; rr < 8; rr++) { index = dest + (row*row_size) + col; blockvals = &(vid_stream->block.dct_recon[rr][0]); index[0] += blockvals[0]; index[1] += blockvals[1]; index[2] += blockvals[2]; index[3] += blockvals[3]; index[4] += blockvals[4]; index[5] += blockvals[5]; index[6] += blockvals[6]; index[7] += blockvals[7]; } } } else { #endif index = dest + (row * row_size) + col; rindex1 = future + (row + down_back) * row_size + col + right_back; blockvals = &(vid_stream->block.dct_recon[0][0]); if ((!right_half_back) && (!down_half_back)) { unsigned char *cm = cropTbl + MAX_NEG_CROP; if (!zflag) for (rr = 0; rr < 4; rr++) { index[0] = cm[(int) rindex1[0] + (int) blockvals[0]]; index[1] = cm[(int) rindex1[1] + (int) blockvals[1]]; index[2] = cm[(int) rindex1[2] + (int) blockvals[2]]; index[3] = cm[(int) rindex1[3] + (int) blockvals[3]]; index[4] = cm[(int) rindex1[4] + (int) blockvals[4]]; index[5] = cm[(int) rindex1[5] + (int) blockvals[5]]; index[6] = cm[(int) rindex1[6] + (int) blockvals[6]]; index[7] = cm[(int) rindex1[7] + (int) blockvals[7]]; index += row_size; rindex1 += row_size; index[0] = cm[(int) rindex1[0] + (int) blockvals[8]]; index[1] = cm[(int) rindex1[1] + (int) blockvals[9]]; index[2] = cm[(int) rindex1[2] + (int) blockvals[10]]; index[3] = cm[(int) rindex1[3] + (int) blockvals[11]]; index[4] = cm[(int) rindex1[4] + (int) blockvals[12]]; index[5] = cm[(int) rindex1[5] + (int) blockvals[13]]; index[6] = cm[(int) rindex1[6] + (int) blockvals[14]]; index[7] = cm[(int) rindex1[7] + (int) blockvals[15]]; blockvals += 16; index += row_size; rindex1 += row_size; } else { if (right_back & 0x1) { /* No alignment, use bye copy */ for (rr = 0; rr < 4; rr++) { index[0] = rindex1[0]; index[1] = rindex1[1]; index[2] = rindex1[2]; index[3] = rindex1[3]; index[4] = rindex1[4]; index[5] = rindex1[5]; index[6] = rindex1[6]; index[7] = rindex1[7]; index += row_size; rindex1 += row_size; index[0] = rindex1[0]; index[1] = rindex1[1]; index[2] = rindex1[2]; index[3] = rindex1[3]; index[4] = rindex1[4]; index[5] = rindex1[5]; index[6] = rindex1[6]; index[7] = rindex1[7]; index += row_size; rindex1 += row_size; } } else if (right_back & 0x2) { /* Half-word bit aligned, use 16 bit copy */ short *src = (short *)rindex1; short *dest = (short *)index; row_size >>= 1; for (rr = 0; rr < 4; rr++) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_size; src += row_size; dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_size; src += row_size; } } else { /* Word aligned, use 32 bit copy */ int *src = (int *)rindex1; int *dest = (int *)index; row_size >>= 2; for (rr = 0; rr < 4; rr++) { dest[0] = src[0]; dest[1] = src[1]; dest += row_size; src += row_size; dest[0] = src[0]; dest[1] = src[1]; dest += row_size; src += row_size; } } } } else { unsigned char *cm = cropTbl + MAX_NEG_CROP; rindex2 = rindex1 + right_half_back + (down_half_back * row_size); if (!zflag) for (rr = 0; rr < 4; rr++) { index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[0]]; index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[1]]; index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[2]]; index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[3]]; index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[4]]; index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[5]]; index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[6]]; index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[7]]; index += row_size; rindex1 += row_size; rindex2 += row_size; index[0] = cm[((int) (rindex1[0] + rindex2[0]) >> 1) + blockvals[8]]; index[1] = cm[((int) (rindex1[1] + rindex2[1]) >> 1) + blockvals[9]]; index[2] = cm[((int) (rindex1[2] + rindex2[2]) >> 1) + blockvals[10]]; index[3] = cm[((int) (rindex1[3] + rindex2[3]) >> 1) + blockvals[11]]; index[4] = cm[((int) (rindex1[4] + rindex2[4]) >> 1) + blockvals[12]]; index[5] = cm[((int) (rindex1[5] + rindex2[5]) >> 1) + blockvals[13]]; index[6] = cm[((int) (rindex1[6] + rindex2[6]) >> 1) + blockvals[14]]; index[7] = cm[((int) (rindex1[7] + rindex2[7]) >> 1) + blockvals[15]]; blockvals += 16; index += row_size; rindex1 += row_size; rindex2 += row_size; } else for (rr = 0; rr < 4; rr++) { index[0] = (int) (rindex1[0] + rindex2[0]) >> 1; index[1] = (int) (rindex1[1] + rindex2[1]) >> 1; index[2] = (int) (rindex1[2] + rindex2[2]) >> 1; index[3] = (int) (rindex1[3] + rindex2[3]) >> 1; index[4] = (int) (rindex1[4] + rindex2[4]) >> 1; index[5] = (int) (rindex1[5] + rindex2[5]) >> 1; index[6] = (int) (rindex1[6] + rindex2[6]) >> 1; index[7] = (int) (rindex1[7] + rindex2[7]) >> 1; index += row_size; rindex1 += row_size; rindex2 += row_size; index[0] = (int) (rindex1[0] + rindex2[0]) >> 1; index[1] = (int) (rindex1[1] + rindex2[1]) >> 1; index[2] = (int) (rindex1[2] + rindex2[2]) >> 1; index[3] = (int) (rindex1[3] + rindex2[3]) >> 1; index[4] = (int) (rindex1[4] + rindex2[4]) >> 1; index[5] = (int) (rindex1[5] + rindex2[5]) >> 1; index[6] = (int) (rindex1[6] + rindex2[6]) >> 1; index[7] = (int) (rindex1[7] + rindex2[7]) >> 1; index += row_size; rindex1 += row_size; rindex2 += row_size; } } #ifdef LOOSE_MPEG } #endif } /* *-------------------------------------------------------------- * * ReconBiMBlock -- * * Reconstructs bidirectionally predicted macroblocks. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconBiMBlock(vid_stream, bnum, recon_right_for, recon_down_for, recon_right_back, recon_down_back, zflag) VidStream *vid_stream; int bnum, recon_right_for, recon_down_for, recon_right_back, recon_down_back; int zflag; { int mb_row, mb_col, row, col, row_size, rr; unsigned char *dest, *past, *future; int right_for, down_for, right_half_for, down_half_for; int right_back, down_back, right_half_back, down_half_back; unsigned char *index, *rindex1, *bindex1; short int *blockvals; int forw_row_start, back_row_start, forw_col_start, back_col_start; #ifdef LOOSE_MPEG int illegal_forw = 0; int illegal_back = 0; #endif /* Calculate macroblock row and column from address. */ mb_row = vid_stream->mblock.mb_address / vid_stream->mb_width; mb_col = vid_stream->mblock.mb_address % vid_stream->mb_width; /* If block is luminance block... */ if (bnum < 4) { /* * Calculate right_for, down_for, right_half_for, down_half_for, * right_back, down_bakc, right_half_back, and down_half_back, motion * vectors. */ right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* Set dest to luminance plane of current pict image. */ dest = vid_stream->current->luminance; /* If past frame exists, set past to luminance plane of past frame. */ if (vid_stream->past != NULL) past = vid_stream->past->luminance; /* * If future frame exists, set future to luminance plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->luminance; /* Establish row size. */ row_size = (vid_stream->mb_width << 4); /* Calculate row,col of upper left pixel in block. */ row = (mb_row << 4); col = (mb_col << 4); if (bnum > 1) row += 8; if (bnum & 0x01) col += 8; forw_col_start = col + right_for; forw_row_start = row + down_for; back_col_start = col + right_back; back_row_start = row + down_back; #ifdef LOOSE_MPEG /* Check for illegal pred. blocks. */ if (forw_col_start+8 > lmaxx) illegal_forw = 1; else if (forw_col_start < 0) illegal_forw = 1; if (forw_row_start+8 > lmaxy) illegal_forw = 1; else if (forw_row_start < 0) illegal_forw = 1; if (back_col_start+8 > lmaxx) illegal_back = 1; else if (back_col_start < 0) illegal_back = 1; if (back_row_start+8 > lmaxy) illegal_back = 1; else if (back_row_start < 0) illegal_back = 1; #endif } /* Otherwise, block is NOT luminance block, ... */ else { /* Construct motion vectors. */ recon_right_for /= 2; recon_down_for /= 2; right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; recon_right_back /= 2; recon_down_back /= 2; right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; /* Establish row size. */ row_size = (vid_stream->mb_width << 3); /* Calculate row,col of upper left pixel in block. */ row = (mb_row << 3); col = (mb_col << 3); forw_col_start = col + right_for; forw_row_start = row + down_for; back_col_start = col + right_back; back_row_start = row + down_back; #ifdef LOOSE_MPEG /* Check for illegal pred. blocks. */ if (forw_col_start+8 > cmaxx) illegal_forw = 1; else if (forw_col_start < 0) illegal_forw = 1; if (forw_row_start+8 > cmaxy) illegal_forw = 1; else if (forw_row_start < 0) illegal_forw = 1; if (back_col_start+8 > cmaxx) illegal_back = 1; else if (back_col_start < 0) illegal_back = 1; if (back_row_start+8 > cmaxy) illegal_back = 1; else if (back_row_start < 0) illegal_back = 1; #endif /* If block is Cr block... */ if (bnum == 4) { /* Set dest to Cr plane of current pict image. */ dest = vid_stream->current->Cr; /* If past frame exists, set past to Cr plane of past image. */ if (vid_stream->past != NULL) past = vid_stream->past->Cr; /* * If future frame exists, set future to Cr plane of future image. */ if (vid_stream->future != NULL) future = vid_stream->future->Cr; } /* Otherwise, block is Cb block... */ else { /* Set dest to Cb plane of current pict image. */ dest = vid_stream->current->Cb; /* If past frame exists, set past to Cb plane of past frame. */ if (vid_stream->past != NULL) past = vid_stream->past->Cb; /* * If future frame exists, set future to Cb plane of future frame. */ if (vid_stream->future != NULL) future = vid_stream->future->Cb; } } /* For each pixel in block... */ index = dest + (row * row_size) + col; #ifdef LOOSE_MPEG if (illegal_forw) rindex1 = future + back_row_start * row_size + back_col_start; else #endif rindex1 = past + forw_row_start * row_size + forw_col_start; #ifdef LOOSE_MPEG if (illegal_back) bindex1 = past + forw_row_start * row_size + forw_col_start; else #endif bindex1 = future + back_row_start * row_size + back_col_start; blockvals = (short int *) &(vid_stream->block.dct_recon[0][0]); { unsigned char *cm = cropTbl + MAX_NEG_CROP; if (!zflag) for (rr = 0; rr < 4; rr++) { index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[0]]; index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[1]]; index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[2]]; index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[3]]; index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[4]]; index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[5]]; index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[6]]; index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[7]]; index += row_size; rindex1 += row_size; bindex1 += row_size; index[0] = cm[((int) (rindex1[0] + bindex1[0]) >> 1) + blockvals[8]]; index[1] = cm[((int) (rindex1[1] + bindex1[1]) >> 1) + blockvals[9]]; index[2] = cm[((int) (rindex1[2] + bindex1[2]) >> 1) + blockvals[10]]; index[3] = cm[((int) (rindex1[3] + bindex1[3]) >> 1) + blockvals[11]]; index[4] = cm[((int) (rindex1[4] + bindex1[4]) >> 1) + blockvals[12]]; index[5] = cm[((int) (rindex1[5] + bindex1[5]) >> 1) + blockvals[13]]; index[6] = cm[((int) (rindex1[6] + bindex1[6]) >> 1) + blockvals[14]]; index[7] = cm[((int) (rindex1[7] + bindex1[7]) >> 1) + blockvals[15]]; blockvals += 16; index += row_size; rindex1 += row_size; bindex1 += row_size; } else for (rr = 0; rr < 4; rr++) { index[0] = (int) (rindex1[0] + bindex1[0]) >> 1; index[1] = (int) (rindex1[1] + bindex1[1]) >> 1; index[2] = (int) (rindex1[2] + bindex1[2]) >> 1; index[3] = (int) (rindex1[3] + bindex1[3]) >> 1; index[4] = (int) (rindex1[4] + bindex1[4]) >> 1; index[5] = (int) (rindex1[5] + bindex1[5]) >> 1; index[6] = (int) (rindex1[6] + bindex1[6]) >> 1; index[7] = (int) (rindex1[7] + bindex1[7]) >> 1; index += row_size; rindex1 += row_size; bindex1 += row_size; index[0] = (int) (rindex1[0] + bindex1[0]) >> 1; index[1] = (int) (rindex1[1] + bindex1[1]) >> 1; index[2] = (int) (rindex1[2] + bindex1[2]) >> 1; index[3] = (int) (rindex1[3] + bindex1[3]) >> 1; index[4] = (int) (rindex1[4] + bindex1[4]) >> 1; index[5] = (int) (rindex1[5] + bindex1[5]) >> 1; index[6] = (int) (rindex1[6] + bindex1[6]) >> 1; index[7] = (int) (rindex1[7] + bindex1[7]) >> 1; index += row_size; rindex1 += row_size; bindex1 += row_size; } } } /* *-------------------------------------------------------------- * * ProcessSkippedPFrameMBlocks -- * * Processes skipped macroblocks in P frames. * * Results: * Calculates pixel values for luminance, Cr, and Cb planes * in current pict image for skipped macroblocks. * * Side effects: * Pixel values in pict image changed. * *-------------------------------------------------------------- */ static void ProcessSkippedPFrameMBlocks(vid_stream) VidStream *vid_stream; { int row_size, half_row, mb_row, mb_col, row, col, rr; int addr, row_incr, half_row_incr, crow, ccol; int *dest, *src, *dest1, *src1; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; half_row = (row_size >> 1); row_incr = row_size >> 2; half_row_incr = half_row >> 2; /* For each skipped macroblock, do... */ for (addr = vid_stream->mblock.past_mb_addr + 1; addr < vid_stream->mblock.mb_address; addr++) { /* Calculate macroblock row and col. */ mb_row = addr / vid_stream->mb_width; mb_col = addr % vid_stream->mb_width; /* Calculate upper left pixel row,col for luminance plane. */ row = mb_row << 4; col = mb_col << 4; /* For each row in macroblock luminance plane... */ dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); src = (int *)(vid_stream->future->luminance + (row * row_size) + col); for (rr = 0; rr < 8; rr++) { /* Copy pixel values from last I or P picture. */ dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_incr; src += row_incr; dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_incr; src += row_incr; } /* * Divide row,col to get upper left pixel of macroblock in Cr and Cb * planes. */ crow = row >> 1; ccol = col >> 1; /* For each row in Cr, and Cb planes... */ dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); src = (int *)(vid_stream->future->Cr + (crow * half_row) + ccol); dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); src1 = (int *)(vid_stream->future->Cb + (crow * half_row) + ccol); for (rr = 0; rr < 4; rr++) { /* Copy pixel values from last I or P picture. */ dest[0] = src[0]; dest[1] = src[1]; dest1[0] = src1[0]; dest1[1] = src1[1]; dest += half_row_incr; src += half_row_incr; dest1 += half_row_incr; src1 += half_row_incr; dest[0] = src[0]; dest[1] = src[1]; dest1[0] = src1[0]; dest1[1] = src1[1]; dest += half_row_incr; src += half_row_incr; dest1 += half_row_incr; src1 += half_row_incr; } if (ditherType == MBORDERED_DITHER) { MBOrderedDitherDisplayCopy(vid_stream, addr, 1, 0, 0, 0, 0, 0, vid_stream->future->display, (unsigned char *) NULL); ditherFlags[addr] = 0; } } vid_stream->mblock.recon_right_for_prev = 0; vid_stream->mblock.recon_down_for_prev = 0; } /* *-------------------------------------------------------------- * * ProcessSkippedBFrameMBlocks -- * * Processes skipped macroblocks in B frames. * * Results: * Calculates pixel values for luminance, Cr, and Cb planes * in current pict image for skipped macroblocks. * * Side effects: * Pixel values in pict image changed. * *-------------------------------------------------------------- */ static void ProcessSkippedBFrameMBlocks(vid_stream) VidStream *vid_stream; { int row_size, half_row, mb_row, mb_col, row, col, rr; int right_half_for, down_half_for, c_right_half_for, c_down_half_for; int right_half_back, down_half_back, c_right_half_back, c_down_half_back; int addr, right_for, down_for; int recon_right_for, recon_down_for; int recon_right_back, recon_down_back; int right_back, down_back; int c_right_for, c_down_for; int c_right_back, c_down_back; unsigned char forw_lum[256]; unsigned char forw_cr[64], forw_cb[64]; unsigned char back_lum[256], back_cr[64], back_cb[64]; int row_incr, half_row_incr; int ccol, crow; /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ row_size = vid_stream->mb_width << 4; half_row = (row_size >> 1); row_incr = row_size >> 2; half_row_incr = half_row >> 2; /* Establish motion vector codes based on full pixel flag. */ if (vid_stream->picture.full_pel_forw_vector) { recon_right_for = vid_stream->mblock.recon_right_for_prev << 1; recon_down_for = vid_stream->mblock.recon_down_for_prev << 1; } else { recon_right_for = vid_stream->mblock.recon_right_for_prev; recon_down_for = vid_stream->mblock.recon_down_for_prev; } if (vid_stream->picture.full_pel_back_vector) { recon_right_back = vid_stream->mblock.recon_right_back_prev << 1; recon_down_back = vid_stream->mblock.recon_down_back_prev << 1; } else { recon_right_back = vid_stream->mblock.recon_right_back_prev; recon_down_back = vid_stream->mblock.recon_down_back_prev; } /* If only one motion vector, do display copy, else do full calculation. */ if (ditherType == MBORDERED_DITHER) { if (vid_stream->mblock.bpict_past_forw && !vid_stream->mblock.bpict_past_back) { for (addr = vid_stream->mblock.past_mb_addr+1; addr < vid_stream->mblock.mb_address; addr++) { MBOrderedDitherDisplayCopy(vid_stream, addr, 1, recon_right_for, recon_down_for, 0, 0, 0, vid_stream->past->display, vid_stream->future->display); ditherFlags[addr] = 0; } return; } if (vid_stream->mblock.bpict_past_back && !vid_stream->mblock.bpict_past_forw) { for (addr = vid_stream->mblock.past_mb_addr+1; addr < vid_stream->mblock.mb_address; addr++) { MBOrderedDitherDisplayCopy(vid_stream, addr, 0, 0, 0, 1, recon_right_back, recon_down_back, vid_stream->past->display, vid_stream->future->display); ditherFlags[addr] = 0; } return; } } /* Calculate motion vectors. */ if (vid_stream->mblock.bpict_past_forw) { right_for = recon_right_for >> 1; down_for = recon_down_for >> 1; right_half_for = recon_right_for & 0x1; down_half_for = recon_down_for & 0x1; recon_right_for /= 2; recon_down_for /= 2; c_right_for = recon_right_for >> 1; c_down_for = recon_down_for >> 1; c_right_half_for = recon_right_for & 0x1; c_down_half_for = recon_down_for & 0x1; } if (vid_stream->mblock.bpict_past_back) { right_back = recon_right_back >> 1; down_back = recon_down_back >> 1; right_half_back = recon_right_back & 0x1; down_half_back = recon_down_back & 0x1; recon_right_back /= 2; recon_down_back /= 2; c_right_back = recon_right_back >> 1; c_down_back = recon_down_back >> 1; c_right_half_back = recon_right_back & 0x1; c_down_half_back = recon_down_back & 0x1; } /* For each skipped macroblock, do... */ for (addr = vid_stream->mblock.past_mb_addr + 1; addr < vid_stream->mblock.mb_address; addr++) { /* Calculate macroblock row and col. */ mb_row = addr / vid_stream->mb_width; mb_col = addr % vid_stream->mb_width; /* Calculate upper left pixel row,col for luminance plane. */ row = mb_row << 4; col = mb_col << 4; crow = row / 2; ccol = col / 2; /* If forward predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_forw) { ReconSkippedBlock(vid_stream->past->luminance, forw_lum, row, col, row_size, right_for, down_for, right_half_for, down_half_for, 16); ReconSkippedBlock(vid_stream->past->Cr, forw_cr, crow, ccol, half_row, c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); ReconSkippedBlock(vid_stream->past->Cb, forw_cb, crow, ccol, half_row, c_right_for, c_down_for, c_right_half_for, c_down_half_for, 8); } /* If back predicted, calculate prediction values. */ if (vid_stream->mblock.bpict_past_back) { ReconSkippedBlock(vid_stream->future->luminance, back_lum, row, col, row_size, right_back, down_back, right_half_back, down_half_back, 16); ReconSkippedBlock(vid_stream->future->Cr, back_cr, crow, ccol, half_row, c_right_back, c_down_back, c_right_half_back, c_down_half_back, 8); ReconSkippedBlock(vid_stream->future->Cb, back_cb, crow, ccol, half_row, c_right_back, c_down_back, c_right_half_back, c_down_half_back, 8); } if (vid_stream->mblock.bpict_past_forw && !vid_stream->mblock.bpict_past_back) { int *dest, *dest1; int *src, *src1; dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); src = (int *)forw_lum; for (rr = 0; rr < 16; rr++) { /* memcpy(dest, forw_lum+(rr<<4), 16); */ dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_incr; src += 4; } dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); src = (int *)forw_cr; src1 = (int *)forw_cb; for (rr = 0; rr < 8; rr++) { /* * memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3), * 8); */ dest[0] = src[0]; dest[1] = src[1]; dest1[0] = src1[0]; dest1[1] = src1[1]; dest += half_row_incr; dest1 += half_row_incr; src += 2; src1 += 2; } } else if (vid_stream->mblock.bpict_past_back && !vid_stream->mblock.bpict_past_forw) { int *src, *src1; int *dest, *dest1; dest = (int *)(vid_stream->current->luminance + (row * row_size) + col); src = (int *)back_lum; for (rr = 0; rr < 16; rr++) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest += row_incr; src += 4; } dest = (int *)(vid_stream->current->Cr + (crow * half_row) + ccol); dest1 = (int *)(vid_stream->current->Cb + (crow * half_row) + ccol); src = (int *)back_cr; src1 = (int *)back_cb; for (rr = 0; rr < 8; rr++) { /* * memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3), * 8); */ dest[0] = src[0]; dest[1] = src[1]; dest1[0] = src1[0]; dest1[1] = src1[1]; dest += half_row_incr; dest1 += half_row_incr; src += 2; src1 += 2; } } else { unsigned char *src1, *src2, *src1a, *src2a; unsigned char *dest, *dest1; dest = vid_stream->current->luminance + (row * row_size) + col; src1 = forw_lum; src2 = back_lum; for (rr = 0; rr < 16; rr++) { dest[0] = (int) (src1[0] + src2[0]) >> 1; dest[1] = (int) (src1[1] + src2[1]) >> 1; dest[2] = (int) (src1[2] + src2[2]) >> 1; dest[3] = (int) (src1[3] + src2[3]) >> 1; dest[4] = (int) (src1[4] + src2[4]) >> 1; dest[5] = (int) (src1[5] + src2[5]) >> 1; dest[6] = (int) (src1[6] + src2[6]) >> 1; dest[7] = (int) (src1[7] + src2[7]) >> 1; dest[8] = (int) (src1[8] + src2[8]) >> 1; dest[9] = (int) (src1[9] + src2[9]) >> 1; dest[10] = (int) (src1[10] + src2[10]) >> 1; dest[11] = (int) (src1[11] + src2[11]) >> 1; dest[12] = (int) (src1[12] + src2[12]) >> 1; dest[13] = (int) (src1[13] + src2[13]) >> 1; dest[14] = (int) (src1[14] + src2[14]) >> 1; dest[15] = (int) (src1[15] + src2[15]) >> 1; dest += row_size; src1 += 16; src2 += 16; } dest = vid_stream->current->Cr + (crow * half_row) + ccol; dest1 = vid_stream->current->Cb + (crow * half_row) + ccol; src1 = forw_cr; src2 = back_cr; src1a = forw_cb; src2a = back_cb; for (rr = 0; rr < 8; rr++) { dest[0] = (int) (src1[0] + src2[0]) >> 1; dest[1] = (int) (src1[1] + src2[1]) >> 1; dest[2] = (int) (src1[2] + src2[2]) >> 1; dest[3] = (int) (src1[3] + src2[3]) >> 1; dest[4] = (int) (src1[4] + src2[4]) >> 1; dest[5] = (int) (src1[5] + src2[5]) >> 1; dest[6] = (int) (src1[6] + src2[6]) >> 1; dest[7] = (int) (src1[7] + src2[7]) >> 1; dest += half_row; src1 += 8; src2 += 8; dest1[0] = (int) (src1a[0] + src2a[0]) >> 1; dest1[1] = (int) (src1a[1] + src2a[1]) >> 1; dest1[2] = (int) (src1a[2] + src2a[2]) >> 1; dest1[3] = (int) (src1a[3] + src2a[3]) >> 1; dest1[4] = (int) (src1a[4] + src2a[4]) >> 1; dest1[5] = (int) (src1a[5] + src2a[5]) >> 1; dest1[6] = (int) (src1a[6] + src2a[6]) >> 1; dest1[7] = (int) (src1a[7] + src2a[7]) >> 1; dest1 += half_row; src1a += 8; src2a += 8; } } if (ditherType == MBORDERED_DITHER) { ditherFlags[addr] = 1; } } } /* *-------------------------------------------------------------- * * ReconSkippedBlock -- * * Reconstructs predictive block for skipped macroblocks * in B Frames. * * Results: * No return values. * * Side effects: * None. * *-------------------------------------------------------------- */ static void ReconSkippedBlock(source, dest, row, col, row_size, right, down, right_half, down_half, width) unsigned char *source; unsigned char *dest; int row, col, row_size, right, down, right_half, down_half, width; { int rr; unsigned char *source2; source += ((row + down) * row_size) + col + right; if (width == 16) { if ((!right_half) && (!down_half)) { if (right & 0x1) { /* No alignment, use bye copy */ for (rr = 0; rr < 16; rr++) { dest[0] = source[0]; dest[1] = source[1]; dest[2] = source[2]; dest[3] = source[3]; dest[4] = source[4]; dest[5] = source[5]; dest[6] = source[6]; dest[7] = source[7]; dest[8] = source[8]; dest[9] = source[9]; dest[10] = source[10]; dest[11] = source[11]; dest[12] = source[12]; dest[13] = source[13]; dest[14] = source[14]; dest[15] = source[15]; dest += 16; source += row_size; } } else if (right & 0x2) { /* Half-word bit aligned, use 16 bit copy */ short *src = (short *)source; short *d = (short *)dest; row_size >>= 1; for (rr = 0; rr < 16; rr++) { d[0] = src[0]; d[1] = src[1]; d[2] = src[2]; d[3] = src[3]; d[4] = src[4]; d[5] = src[5]; d[6] = src[6]; d[7] = src[7]; d += 8; src += row_size; } } else { /* Word aligned, use 32 bit copy */ int *src = (int *)source; int *d = (int *)dest; row_size >>= 2; for (rr = 0; rr < 16; rr++) { d[0] = src[0]; d[1] = src[1]; d[2] = src[2]; d[3] = src[3]; d += 4; src += row_size; } } } else { source2 = source + right_half + (row_size * down_half); for (rr = 0; rr < width; rr++) { dest[0] = (int) (source[0] + source2[0]) >> 1; dest[1] = (int) (source[1] + source2[1]) >> 1; dest[2] = (int) (source[2] + source2[2]) >> 1; dest[3] = (int) (source[3] + source2[3]) >> 1; dest[4] = (int) (source[4] + source2[4]) >> 1; dest[5] = (int) (source[5] + source2[5]) >> 1; dest[6] = (int) (source[6] + source2[6]) >> 1; dest[7] = (int) (source[7] + source2[7]) >> 1; dest[8] = (int) (source[8] + source2[8]) >> 1; dest[9] = (int) (source[9] + source2[9]) >> 1; dest[10] = (int) (source[10] + source2[10]) >> 1; dest[11] = (int) (source[11] + source2[11]) >> 1; dest[12] = (int) (source[12] + source2[12]) >> 1; dest[13] = (int) (source[13] + source2[13]) >> 1; dest[14] = (int) (source[14] + source2[14]) >> 1; dest[15] = (int) (source[15] + source2[15]) >> 1; dest += width; source += row_size; source2 += row_size; } } } else { /* (width == 8) */ assert(width == 8); if ((!right_half) && (!down_half)) { if (right & 0x1) { for (rr = 0; rr < width; rr++) { dest[0] = source[0]; dest[1] = source[1]; dest[2] = source[2]; dest[3] = source[3]; dest[4] = source[4]; dest[5] = source[5]; dest[6] = source[6]; dest[7] = source[7]; dest += 8; source += row_size; } } else if (right & 0x02) { short *d = (short *)dest; short *src = (short *)source; row_size >>= 1; for (rr = 0; rr < width; rr++) { d[0] = src[0]; d[1] = src[1]; d[2] = src[2]; d[3] = src[3]; d += 4; src += row_size; } } else { int *d = (int *)dest; int *src = (int *)source; row_size >>= 2; for (rr = 0; rr < width; rr++) { d[0] = src[0]; d[1] = src[1]; d += 2; src += row_size; } } } else { source2 = source + right_half + (row_size * down_half); for (rr = 0; rr < width; rr++) { dest[0] = (int) (source[0] + source2[0]) >> 1; dest[1] = (int) (source[1] + source2[1]) >> 1; dest[2] = (int) (source[2] + source2[2]) >> 1; dest[3] = (int) (source[3] + source2[3]) >> 1; dest[4] = (int) (source[4] + source2[4]) >> 1; dest[5] = (int) (source[5] + source2[5]) >> 1; dest[6] = (int) (source[6] + source2[6]) >> 1; dest[7] = (int) (source[7] + source2[7]) >> 1; dest += width; source += row_size; source2 += row_size; } } } } /* *-------------------------------------------------------------- * * DoPictureDisplay -- * * Converts image from Lum, Cr, Cb to colormap space. Puts * image in lum plane. Updates past and future frame * pointers. Dithers image. Sends to display mechanism. * * Results: * Pict image structure locked if displaying or if frame * is needed as past or future reference. * * Side effects: * Lum plane pummelled. * *-------------------------------------------------------------- */ static void DoPictureDisplay(vid_stream) VidStream *vid_stream; { /* Convert to colormap space and dither. */ DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr, vid_stream->current->Cb, vid_stream->current->display, vid_stream->mb_height * 16, vid_stream->mb_width * 16); /* Update past and future references if needed. */ if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) { if (vid_stream->future == NULL) { vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; } else { if (vid_stream->past != NULL) { vid_stream->past->locked &= ~PAST_LOCK; } vid_stream->past = vid_stream->future; vid_stream->past->locked &= ~FUTURE_LOCK; vid_stream->past->locked |= PAST_LOCK; vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; vid_stream->current = vid_stream->past; ExecuteDisplay(vid_stream); } } else ExecuteDisplay(vid_stream); } /* *-------------------------------------------------------------- * * ToggleBFlag -- * * Called to set no b frame processing flag. * * Results: * No_B_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void ToggleBFlag() { if (No_B_Flag) { No_B_Flag = 0; } else No_B_Flag = 1; } /* *-------------------------------------------------------------- * * TogglePFlag -- * * Called to set no p frame processing flag. * * Results: * No_P_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void TogglePFlag() { if (No_P_Flag) { No_P_Flag = 0; } else No_P_Flag = 1; } dest[11] = (int) (src1[11] + src2[11]) >> 1; dest[12] = (int) (src1[12] + src2[12]) >> 1; dest[13] = (int) (src1[13] + src2[13]) >> 1; dest[14] = (int) (src1[14] + src2[14]) >> 1; dest[15] = (int) (src1[15] + src2[15]) >> 1; dest += row_size; src1 += 16; src2 += 16; } dest = vid_stream->current->Cr + (crow * half_row) + ccol; dest1 = vid_stream->current->Cb + (crow * half_row) + ccol; video.h 444 5104 267 25570 5333605261 5467 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include #include #include #include #ifdef SH_MEM #include #include #include #endif /* X11/xmd.h correctly defines INT32, etc */ #ifndef XMD_H typedef int INT32; typedef short INT16; typedef char INT8; #endif typedef unsigned int UINT32; typedef unsigned short UINT16; typedef unsigned char UINT8; /* Define Parsing error codes. */ #define SKIP_PICTURE -10 #define SKIP_TO_START_CODE -1 #define PARSE_OK 1 /* Define BOOLEAN, TRUE, and FALSE. */ #define BOOLEAN int #define TRUE 1 #define FALSE 0 /* Set ring buffer size. */ #define RING_BUF_SIZE 5 /* Macros for picture code type. */ #define I_TYPE 1 #define P_TYPE 2 #define B_TYPE 3 /* Start codes. */ #define SEQ_END_CODE 0x000001b7 #define SEQ_START_CODE 0x000001b3 #define GOP_START_CODE 0x000001b8 #define PICTURE_START_CODE 0x00000100 #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0x000001af #define EXT_START_CODE 0x000001b5 #define USER_START_CODE 0x000001b2 /* Number of macroblocks to process in one call to mpegVidRsrc. */ #define MB_QUANTUM 100 /* Macros used with macroblock address decoding. */ #define MB_STUFFING 34 #define MB_ESCAPE 35 /* Lock flags for pict images. */ #define DISPLAY_LOCK 0x01 #define PAST_LOCK 0x02 #define FUTURE_LOCK 0x04 #define HYBRID_DITHER 0 #define HYBRID2_DITHER 1 #define FS4_DITHER 2 #define FS2_DITHER 3 #define FS2FAST_DITHER 4 #define Twox2_DITHER 5 #define GRAY_DITHER 6 #define FULL_COLOR_DITHER 7 #define NO_DITHER 8 #define ORDERED_DITHER 9 #define MONO_DITHER 10 #define MONO_THRESHOLD 11 #define ORDERED2_DITHER 12 #define MBORDERED_DITHER 13 /* External declaration of row,col to zig zag conversion matrix. */ extern int scan[][8]; /* Temporary definition of time stamp structure. */ typedef int TimeStamp; /* Structure with reconstructed pixel values. */ typedef struct pict_image { unsigned char *luminance; /* Luminance plane. */ unsigned char *Cr; /* Cr plane. */ unsigned char *Cb; /* Cb plane. */ unsigned char *display; /* Display plane. */ int locked; /* Lock flag. */ TimeStamp show_time; /* Presentation time. */ #ifdef SH_MEM XShmSegmentInfo shminfo; /* Segment info. */ XImage *ximage; /* Ximage struct. */ #endif } PictImage; /* Group of pictures structure. */ typedef struct GoP { BOOLEAN drop_flag; /* Flag indicating dropped frame. */ unsigned int tc_hours; /* Hour component of time code. */ unsigned int tc_minutes; /* Minute component of time code. */ unsigned int tc_seconds; /* Second component of time code. */ unsigned int tc_pictures; /* Picture counter of time code. */ BOOLEAN closed_gop; /* Indicates no pred. vectors to previous group of pictures. */ BOOLEAN broken_link; /* B frame unable to be decoded. */ char *ext_data; /* Extension data. */ char *user_data; /* User data. */ } GoP; /* Picture structure. */ typedef struct pict { unsigned int temp_ref; /* Temporal reference. */ unsigned int code_type; /* Frame type: P, B, I */ unsigned int vbv_delay; /* Buffer delay. */ BOOLEAN full_pel_forw_vector; /* Forw. vectors specified in full pixel values flag. */ unsigned int forw_r_size; /* Used for vector decoding. */ unsigned int forw_f; /* Used for vector decoding. */ BOOLEAN full_pel_back_vector; /* Back vectors specified in full pixel values flag. */ unsigned int back_r_size; /* Used in decoding. */ unsigned int back_f; /* Used in decoding. */ char *extra_info; /* Extra bit picture info. */ char *ext_data; /* Extension data. */ char *user_data; /* User data. */ } Pict; /* Slice structure. */ typedef struct slice { unsigned int vert_pos; /* Vertical position of slice. */ unsigned int quant_scale; /* Quantization scale. */ char *extra_info; /* Extra bit slice info. */ } Slice; /* Macroblock structure. */ typedef struct macroblock { int mb_address; /* Macroblock address. */ int past_mb_addr; /* Previous mblock address. */ int motion_h_forw_code; /* Forw. horiz. motion vector code. */ unsigned int motion_h_forw_r; /* Used in decoding vectors. */ int motion_v_forw_code; /* Forw. vert. motion vector code. */ unsigned int motion_v_forw_r; /* Used in decdoinge vectors. */ int motion_h_back_code; /* Back horiz. motion vector code. */ unsigned int motion_h_back_r; /* Used in decoding vectors. */ int motion_v_back_code; /* Back vert. motion vector code. */ unsigned int motion_v_back_r; /* Used in decoding vectors. */ unsigned int cbp; /* Coded block pattern. */ BOOLEAN mb_intra; /* Intracoded mblock flag. */ BOOLEAN bpict_past_forw; /* Past B frame forw. vector flag. */ BOOLEAN bpict_past_back; /* Past B frame back vector flag. */ int past_intra_addr; /* Addr of last intracoded mblock. */ int recon_right_for_prev; /* Past right forw. vector. */ int recon_down_for_prev; /* Past down forw. vector. */ int recon_right_back_prev; /* Past right back vector. */ int recon_down_back_prev; /* Past down back vector. */ } Macroblock; /* Block structure. */ typedef struct block { short int dct_recon[8][8]; /* Reconstructed dct coeff matrix. */ short int dct_dc_y_past; /* Past lum. dc dct coefficient. */ short int dct_dc_cr_past; /* Past cr dc dct coefficient. */ short int dct_dc_cb_past; /* Past cb dc dct coefficient. */ } Block; /* Video stream structure. */ typedef struct vid_stream { unsigned int h_size; /* Horiz. size in pixels. */ unsigned int v_size; /* Vert. size in pixels. */ unsigned int mb_height; /* Vert. size in mblocks. */ unsigned int mb_width; /* Horiz. size in mblocks. */ unsigned char aspect_ratio; /* Code for aspect ratio. */ unsigned char picture_rate; /* Code for picture rate. */ unsigned int bit_rate; /* Bit rate. */ unsigned int vbv_buffer_size; /* Minimum buffer size. */ BOOLEAN const_param_flag; /* Contrained parameter flag. */ unsigned char intra_quant_matrix[8][8]; /* Quantization matrix for intracoded frames. */ unsigned char non_intra_quant_matrix[8][8]; /* Quanitization matrix for non intracoded frames. */ char *ext_data; /* Extension data. */ char *user_data; /* User data. */ GoP group; /* Current group of pict. */ Pict picture; /* Current picture. */ Slice slice; /* Current slice. */ Macroblock mblock; /* Current macroblock. */ Block block; /* Current block. */ int state; /* State of decoding. */ int bit_offset; /* Bit offset in stream. */ unsigned int *buffer; /* Pointer to next byte in buffer. */ int buf_length; /* Length of remaining buffer.*/ unsigned int *buf_start; /* Pointer to buffer start. */ int max_buf_length; /* Max lenght of buffer. */ PictImage *past; /* Past predictive frame. */ PictImage *future; /* Future predictive frame. */ PictImage *current; /* Current frame. */ PictImage *ring[RING_BUF_SIZE]; /* Ring buffer of frames. */ } VidStream; /* Declaration of global pointer to current video stream. */ extern VidStream *curVidStream; /* Declarataion of global display pointer. */ extern Display *display; /* Shared memory flag. */ extern int shmemFlag; /* Quiet mode flag. */ extern int quietFlag; /* Dither flags external declaration. */ extern char *ditherFlags; /* Definition of Contant integer scale factor. */ #define CONST_BITS 13 /* Misc DCT definitions */ #define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define GLOBAL /* a function referenced thru EXTERNs */ typedef short DCTELEM; typedef DCTELEM DCTBLOCK[DCTSIZE2]; #ifdef SH_MEM extern int gXErrorFlag; #endif extern double realTimeStart; extern int totNumFrames; extern int loopFlag; extern int noDisplayFlag; extern jmp_buf env; #ifdef ANALYSIS extern unsigned int bitCount; extern int showEachFlag; extern unsigned int cacheHit[8][8]; extern unsigned int cacheMiss[8][8]; #endif /* Structure with reconstructed pixel values. */ typedef struct pict_image { unsigned char *luminance; /* Luminance plant; int *src = (int *)source; row_size >>= 2; for (rr = 0; rr < width; rr++) { d[0] = src[0]; d[1] = src[1]; d += 2; src += row_size; } } } else { source2 = source + right_half + (row_size * down_half); for (rr = 0; rr < width; rr++) { dest[0] = (int) (source[0] + source2[0]) >> 1; dest[1] = (int) (source[1] + source2[1]) >> 1; dest[2] = (int) (source[2] + source2[2]) >> 1; dest[3] = (int) (source[3] + source2[3]) >> 1; dest[4] = (int) (source[4] + source2[4]) >> 1; dest[5] = (int) (source[5] + source2[5]) >> 1; dest[6] = (int) (source[6] + source2[6]) >> 1; dest[7] = (int) (source[7] + source2[7]) >> 1; dest += width; source += row_size; source2 += row_size; } } } } /* *-------------------------------------------------------------- * * DoPictureDisplay -- * * Converts image from Lum, Cr, Cb to colormap space. Puts * image in lum plane. Updates past and future frame * pointers. Dithers image. Sends to display mechanism. * * Results: * Pict image structure locked if displaying or if frame * is needed as past or future reference. * * Side effects: * Lum plane pummelled. * *-------------------------------------------------------------- */ static void DoPictureDisplay(vid_stream) VidStream *vid_stream; { /* Convert to colormap space and dither. */ DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr, vid_stream->current->Cb, vid_stream->current->display, vid_stream->mb_height * 16, vid_stream->mb_width * 16); /* Update past and future references if needed. */ if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) { if (vid_stream->future == NULL) { vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; } else { if (vid_stream->past != NULL) { vid_stream->past->locked &= ~PAST_LOCK; } vid_stream->past = vid_stream->future; vid_stream->past->locked &= ~FUTURE_LOCK; vid_stream->past->locked |= PAST_LOCK; vid_stream->future = vid_stream->current; vid_stream->future->locked |= FUTURE_LOCK; vid_stream->current = vid_stream->past; ExecuteDisplay(vid_stream); } } else ExecuteDisplay(vid_stream); } /* *-------------------------------------------------------------- * * ToggleBFlag -- * * Called to set no b frame processing flag. * * Results: * No_B_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void ToggleBFlag() { if (No_B_Flag) { No_B_Flag = 0; } else No_B_Flag = 1; } /* *-------------------------------------------------------------- * * TogglePFlag -- * * Called to set no p frame processing flag. * * Results: * No_P_Flag flag is toggled from present value to opposite value. * * Side effects: * None. * *-------------------------------------------------------------- */ void TogglePFlag() { if (No_P_Flag) { No_P_Flag = 0; } else No_P_Flag = 1; } dest[11] = (int) (src1[11] + src2[11]) >> 1; dest[12] = (int) (src1[12] + src2[12]) >> 1; dest[13] = (int) (src1[13] + src2[13]) >> 1; dest[14] = (int) (src1[14] + src2[14]) >> 1; dest[15] = (int) (src1[15] + src2[15]) >> 1; dest += row_size; src1 += 16; src2 += 16; } dest = vid_stream->current->Cr + (crow * half_row) + ccol; dest1 = vid_stream->current->Cb + (crow * half_row) + ccol; video.h 444 5104 267 25570 5333605261 5467 /* * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include #include #include #include #ifdef SH_MEM #include #include #include #endif /* X11/xmd.h correctly defines INT32, etc */ #ifndef XMD_H typedef int INT32; typedef short INT16; typedef char INT8; #endif typedef unsigned int UINT32; typedef unsigned short UINT16; typedef unsigned char UINT8; /* Define Parsing error codes. */ #define SKIP_PICTURE -10 #define SKIP_TO_START_CODE -1 #define PARSE_OK 1 /* Define BOOLEAN, TRUE, and FALSE. */ #define BOOLEAN int #define TRUE 1 #define FALSE 0 /* Set ring buffer size. */ #define RING_BUF_SIZE 5 /* Macros for picture code type. */ #define I_TYPE 1 #define P_TYPE 2 #define B_TYPE 3 /* Start codes. */ #define SEQ_END_CODE 0x000001b7 #define SEQ_START_CODE 0x000001b3 #define GOP_START_CODE 0x000001b8 #define PICTURE_START_CODE 0x00000100 #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0