/* * 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 MotionPrediction.str.pre * @version 1.0 */ int->int pipeline MotionPrediction_wrapper(int width, int height, portal UpdatePortal_picture_type, portal UpdatePortal_picture_type3) { add MotionPrediction(width, height) to UpdatePortal_picture_type; } /** * @internal */ int->int filter MotionPrediction(int width, int height) { int count; int lastSeenFrame; int datarate = (width*height/64*(64+8+1+1+1)); int pushrate = width*height; int[width][height] prev_picture; int[width][height] next_picture; int next_picture_type; init { next_picture_type = -1; count = 0; } work pop datarate push pushrate { if (next_picture_type == -1) { println("Error - Should have received a picture type message before motion prediction can process"); } if (next_picture_type == 1 || next_picture_type == 2) { prev_picture = next_picture; if (next_picture_type == 1) { readIPicture(); } else { readPPicture(); } } else { readBPicture(); } count++; } void readIPicture() pop datarate push pushrate { lastSeenFrame = 1; int[width][height] temp_picture; for (int blocky = 0; blocky < (height/8); blocky++) { for (int blockx = 0; blockx < (width/8); blockx++) { for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { temp_picture[x+blockx*8][y+blocky*8] = pop(); } } for (int i = 0; i < 8; i++) { pop(); } pop(); pop(); pop(); } } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { next_picture[x][y] = temp_picture[x][y]; push(temp_picture[x][y]); } } } void readPPicture() pop datarate push pushrate { lastSeenFrame = 2; int[width][height] temp_picture; int[width/8][height/8][2][2][2] vector; int[width/8][height/8] macroblock_intra; for (int blocky = 0; blocky < height/8; blocky++) { for (int blockx = 0; blockx < width/8; blockx++) { for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { temp_picture[x+blockx*8][y+blocky*8] = pop(); } } for (int r = 0; r < 2; r++) { for (int s = 0; s < 2; s++) { for (int t = 0; t < 2; t++) { vector[blockx][blocky][r][s][t] = pop(); } } } macroblock_intra[blockx][blocky] = pop(); pop(); pop(); } } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel; if (macroblock_intra[x/8][y/8] == 0) { int sample_data; sample_data = predictMotionPixel(prev_picture, vector, 0, x, y); pixel = sample_data; } else { pixel = 0; } next_picture[x][y] = temp_picture[x][y] + pixel; push(next_picture[x][y]); if (next_picture[x][y] > 127) { next_picture[x][y] = 127; } else if (next_picture[x][y] < -128) { next_picture[x][y] = -128; } } } } void readBPicture() pop datarate push pushrate { lastSeenFrame = 3; int[width][height] temp_picture; int[width/8][height/8][2][2][2] vector; int[width/8][height/8] macroblock_intra; int[width/8][height/8] macroblock_motion_forward; int[width/8][height/8] macroblock_motion_backward; for (int blocky = 0; blocky < height/8; blocky++) { for (int blockx = 0; blockx < width/8; blockx++) { for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { temp_picture[x+blockx*8][y+blocky*8] = pop(); } } for (int r = 0; r < 2; r++) { for (int s = 0; s < 2; s++) { for (int t = 0; t < 2; t++) { vector[blockx][blocky][r][s][t] = pop(); } } } macroblock_intra[blockx][blocky] = pop(); macroblock_motion_forward[blockx][blocky] = pop(); macroblock_motion_backward[blockx][blocky] = pop(); } } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pushval; int permsample = 0; if (macroblock_intra[x/8][y/8] == 0) { int[2] sample_data; if (macroblock_motion_forward[x/8][y/8] == 1) { sample_data[0] = predictMotionPixel(prev_picture, vector, 0, x, y); } if (macroblock_motion_backward[x/8][y/8] == 1) { sample_data[1] = predictMotionPixel(next_picture, vector, 1, x, y); } if (macroblock_motion_forward[x/8][y/8] == 1) { if (macroblock_motion_backward[x/8][y/8] == 1) { permsample = (1+sample_data[0]+sample_data[1]+256)/2-128; } else { permsample = sample_data[0]; } } else { if (macroblock_motion_backward[x/8][y/8] == 1) { permsample = sample_data[1]; } else { // TODO - this should be the previous frame's macroblock, not the previous reference frame's macroblock permsample = prev_picture[x][y]; } } } else { permsample = 0; } pushval = temp_picture[x][y] + permsample; push(pushval); } } } handler setPictureType(int picture_coding_type) { next_picture_type = picture_coding_type; } int predictPixelHorizHalfPelVertHalfPel(int[width][height] predict_pic, int horiz_vector, int vert_vector) { int sample_data; sample_data = (predict_pic[(horiz_vector-1)/2][(vert_vector-1)/2] + predict_pic[(horiz_vector-1)/2][(vert_vector+1)/2] + predict_pic[(horiz_vector+1)/2][(vert_vector-1)/2] + predict_pic[(horiz_vector+1)/2][(vert_vector+1)/2]); sample_data += 128*4; if (sample_data > 0) { sample_data += 2; } else if (sample_data < 0) { // println("Error - Shouldn't be less than zero " + sample_data); } sample_data = sample_data / 4; sample_data -= 128; return sample_data; } int predictPixelHorizHalfPelVertFullPel(int[width][height] predict_pic, int horiz_vector, int vert_vector) { int sample_data; sample_data = (predict_pic[(horiz_vector-1)/2][vert_vector/2] + predict_pic[(horiz_vector+1)/2][vert_vector/2]); sample_data += 128*2; if (sample_data > 0) { sample_data += 1; } else if (sample_data < 0) { // println("Error - Shouldn't be less than zero " + sample_data); } sample_data = sample_data / 2; sample_data -= 128; return sample_data; } int predictPixelHorizFullPelVertHalfPel(int[width][height] predict_pic, int horiz_vector, int vert_vector) { int sample_data; sample_data = (predict_pic[horiz_vector/2][(vert_vector-1)/2] + predict_pic[horiz_vector/2][(vert_vector+1)/2]); sample_data += 128*2; if (sample_data > 0) { sample_data += 1; } else if (sample_data < 0) { // println("Error - Shouldn't be less than zero " + sample_data); } sample_data = sample_data / 2; sample_data -= 128; return sample_data; } int predictPixelHorizFullPelVertFullPel(int[width][height] predict_pic, int horiz_vector, int vert_vector) { int sample_data; sample_data = predict_pic[horiz_vector/2][vert_vector/2]; return sample_data; } int predictMotionPixel(int[width][height] predict_pic, int[width/8][height/8][2][2][2] vector, int whichvect, int x, int y) { // whichvect = 0 for forward motion prediction // whichvect = 1 for backward motion prediction int horiz_vector = vector[x/8][y/8][0][whichvect][0] + (x*2); int vert_vector = vector[x/8][y/8][0][whichvect][1] + (y*2); int sample_data; if (vert_vector < 0 || vert_vector >= (height*2-1) || horiz_vector < 0 || horiz_vector >= (width*2-1)) { sample_data = 0; } else if ((horiz_vector & 0x1) == 1) { if ((vert_vector & 0x1) == 1) { sample_data = predictPixelHorizHalfPelVertHalfPel(predict_pic, horiz_vector, vert_vector); } else { sample_data = predictPixelHorizHalfPelVertFullPel(predict_pic, horiz_vector, vert_vector); } } else { if ((vert_vector & 0x1) == 1) { sample_data = predictPixelHorizFullPelVertHalfPel(predict_pic, horiz_vector, vert_vector); } else { sample_data = predictPixelHorizFullPelVertFullPel(predict_pic, horiz_vector, vert_vector); } } if (sample_data > 127) sample_data = 127; else if (sample_data < -128) sample_data = -128; return sample_data; } } // TODO - hack, because we need this filter for one of the optimized versions // so we need a dummy defined somewhere so that we can have the rest of the files // reference this portal. (FEATURETODO - this will not be needed once hierarchical // messaging works int->int filter SendBackReferenceFrame() { handler setPictureType(int picture_type) {} work pop 1 push 1 { push(pop()); } }