/*
* Copyright 2005 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/**
* @description
* This file contains functions that allow one to decode MPEG-2 compliant video.
* The code is based on the MPEG-2 specification (ISO/IEC 13818-2). The MPEG-2 decoding
* is a work in progress, although it works within a limited test range. Throughout the
* source code, citations are made in cases where an understanding of the code would be
* helped by looking at an outside source. The format I have chosen is
* (cite NUM#, LOOKUP_INFO). NUM=1 refers to ISO/IEC: 13818-2, and NUM=2 refers to the reference
* MPEG implementation written in C, available at [www.mpeg.org].
*
* @author Matthew Drake
* @file InverseQuantization.str.pre
* @version 1.0
*/
// FEATURETODO: This should really just be another constructor to the next filter somehow
int->int pipeline InverseQuantization_NoDefaultValues(portal UpdatePortal_quantiser_data_ac,
portal UpdatePortal_quantiser_data_dc,
portal UpdatePortal_macroblock_intra) {
int[64] empty_matrix;
add InverseQuantization(UpdatePortal_quantiser_data_ac,
UpdatePortal_quantiser_data_dc,
UpdatePortal_macroblock_intra,
-1,
empty_matrix,
empty_matrix,
-1);
}
/**
* @internal
*/
int->int pipeline InverseQuantization(portal UpdatePortal_quantiser_data_ac,
portal UpdatePortal_quantiser_data_dc,
portal UpdatePortal_macroblock_intra,
int default_intra_dc_precision,
int[64] default_intra_quantiser_matrix,
int[64] default_non_intra_quantiser_matrix,
int default_q_scale_type) {
// The handling of the intra DC coefficient is described on (cite 1, P.69)
add int->int splitjoin {
split duplicate;
// Intra Coded Macroblocks
add int->int splitjoin {
split roundrobin(1, 63);
add InverseQuantization_DC_Intra_Coeff(default_intra_dc_precision) to UpdatePortal_quantiser_data_dc; // (cite 1, P.69)
add InverseQuantization_AC_Coeff(1, default_intra_quantiser_matrix, default_non_intra_quantiser_matrix, default_q_scale_type) to UpdatePortal_quantiser_data_ac;
join roundrobin(1, 63);
}
// Non Intra Coded Macroblocks
add InverseQuantization_AC_Coeff(0, default_intra_quantiser_matrix, default_non_intra_quantiser_matrix, default_q_scale_type) to UpdatePortal_quantiser_data_ac;
join roundrobin(64, 64);
}
// Selects which stream - FEATURETODO eventually programmable splitjoin and only one of the two
// above branches gets taken instead of both.
add InverseQuantizationJoinerSubstitute() to UpdatePortal_macroblock_intra;
}
/**
* @internal
*/
int->int filter InverseQuantizationJoinerSubstitute {
int macroblock_intra;
init {
macroblock_intra = -1;
}
handler setMacroblockIntra(int new_macroblock_intra) {
macroblock_intra = new_macroblock_intra;
}
work pop (128) push 64 {
if (macroblock_intra == -1) {
println(" Error: macroblock_intra should not be -1, should have recieved update message");
} else if (macroblock_intra == 1) {
// It was Intra Coded
for (int i = 0; i < 64; i++) {
push(pop());
}
for (int i = 0; i < 64; i++) {
pop();
}
} else {
// It was Non Intra Coded
for (int i = 0; i < 64; i++) {
pop();
}
for (int i = 0; i < 64; i++) {
push(pop());
}
}
}
}
/**
* @internal
*/
int->int filter InverseQuantization_DC_Intra_Coeff(int default_intra_dc_precision) {
// (cite 1, P.69)
int[4] intra_dc_mult;
int intra_dc_precision;
init {
intra_dc_mult[0] = 8;
intra_dc_mult[1] = 4;
intra_dc_mult[2] = 2;
intra_dc_mult[3] = 1;
intra_dc_precision = default_intra_dc_precision;
}
work pop 1 push 1 {
push(intra_dc_mult[intra_dc_precision] * pop());
}
handler setIntraDCPrecision(int new_intra_dc_precision) {
intra_dc_precision = new_intra_dc_precision;
}
}
/**
* @internal
*/
int->int filter InverseQuantization_AC_Coeff(int macroblock_intra,
int[64] default_intra_quantiser_matrix,
int[64] default_non_intra_quantiser_matrix,
int default_q_scale_type) {
// Assumes 4:2:0 data
// (cite 1, P.69)
// intra = 1: This is dequantizing the non-DC part of an intra coded block
// intra = 0: This is dequantizing the DC and AC part of a non-intra coded block
// These are all assigned by messages and MUST be assigned before the first
// call to work()
int quantiser_scale_code;
int q_scale_type;
int[64] intra_quantiser_matrix;
int[64] non_intra_quantiser_matrix;
// (cite 1, P.70 Table 7-6)
int[2][32] quantiser_scale =
// Note that quantiser_scale[x][0] is a Forbidden Value
{{ 0, 2, 4, 6, 8, 10, 12, 14,
16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46,
48, 50, 52, 54, 56, 58, 60, 62},
{ 0, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 14, 16, 18, 20, 22,
24, 28, 32, 36, 40, 44, 48, 52,
56, 64, 72, 80, 88, 96, 104, 112}};
init {
quantiser_scale_code = 0; // Guarantees that this throws an error
// if it doesn't get a quantiser message
// before getting some data.
intra_quantiser_matrix = default_intra_quantiser_matrix;
non_intra_quantiser_matrix = default_non_intra_quantiser_matrix;
q_scale_type = default_q_scale_type;
}
work pop (64-macroblock_intra) push (64-macroblock_intra) {
if (quantiser_scale_code == 0)
println("Error - quantiser_scale_code not allowed to be 0 " + macroblock_intra);
for (int i = macroblock_intra; i < 64; i++) {
int QF = pop();
// (cite 1, P.71)
int k = 0;
if (macroblock_intra == 1) {
k = 0;
} else {
// TODO - I think I'm interpreting this part of the spec correctly, check though.
if (QF > 0) {
k = 1;
} else if (QF < 0) {
k = -1;
} else {
k = 0;
}
}
int W = 0;
if (macroblock_intra == 1) {
W = intra_quantiser_matrix[i];
} else {
W = non_intra_quantiser_matrix[i];
}
int F = (2 * QF + k) * W *
quantiser_scale[q_scale_type][quantiser_scale_code] / 32;
push(F);
}
}
handler setQuantiserScaleCode(int new_quantiser_scale_code) {
quantiser_scale_code = new_quantiser_scale_code;
}
handler setQuantiserMatrices(int[64] new_intra_quantiser_matrix,
int[64] new_non_intra_quantiser_matrix) {
intra_quantiser_matrix = new_intra_quantiser_matrix;
non_intra_quantiser_matrix = new_non_intra_quantiser_matrix;
}
handler setQScaleType(int new_q_scale_type) {
q_scale_type = new_q_scale_type;
}
}