/*
* Java port of ffmpeg mpeg1/2 decoder.
* Copyright (c) 2003 Jonathan Hueber.
*
* Copyright (c) 2000,2001 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* See Credits file and Readme for details
*/
package net.sourceforge.jffmpeg.codecs.video.mpeg;
import net.sourceforge.jffmpeg.codecs.video.mpeg12.MpegVideo;
import java.awt.Frame;
import java.awt.Image;
import java.awt.image.MemoryImageSource;
import java.awt.image.ColorModel;
import java.awt.Graphics;
import javax.media.Buffer;
import java.io.PrintWriter;
/**
* This class manages three display buffers.
* Last frame I/P
* Current frame I/P/B
* Next P frame P
*/
public class DisplayOutput {
private static final boolean motionDebug = false;
private static final boolean debugFT = false;
private static final boolean debugOutput = false;
public static PrintWriter debug = null;
/*
* This is the next I or P frame
*/
private int[] luminance;
private int[] red;
private int[] blue;
/*
* This is the current B frame
*/
private int[] nextPLuminance;
private int[] nextPRed;
private int[] nextPBlue;
/*
* This is the last I or P frame
*/
private int[] oldLuminance;
private int[] oldRed;
private int[] oldBlue;
/**
* Width and height of the Luminance and Chrominance outputs
*/
private int screenX;
private int screenY;
private int chromX;
private int chromY;
/**
* Actual RGB output sizes
*/
private int displayX;
private int displayY;
private int[] displayArray;
/**
* Construct Display (width/height in macroblocks)
* Internally a frame of width 1 macroblock is placed around the
* the display region
*/
public DisplayOutput( int mbWidth, int mbHeight ) {
/**
* Width and height in pixels
*/
displayX = mbWidth * 16;
displayY = mbHeight * 16;
screenX = displayX + 32;
screenY = displayY + 32;
chromX = screenX / 2;
chromY = screenY / 2;
/**
* Allocate display and boarders
*/
mbWidth += 2;
mbHeight += 2;
luminance = new int[ screenX * screenY ];
red = new int[ chromX * chromY ];
blue = new int[ chromX * chromY ];
nextPLuminance = new int[ screenX * screenY ];
nextPRed = new int[ chromX * chromY ];
nextPBlue = new int[ chromX * chromY ];
oldLuminance = new int[ screenX * screenY ];
oldRed = new int[ chromX * chromY ];
oldBlue = new int[ chromX * chromY ];
/* Initialise I frame to 0x80 */
for ( int i = 0; i < blue.length; i++ ) {
blue[i] = 0x400;
}
System.arraycopy( blue, 0, red, 0, blue.length );
System.arraycopy( blue, 0, luminance, 0, blue.length );
System.arraycopy( blue, 0, luminance, blue.length, blue.length );
System.arraycopy( blue, 0, luminance, blue.length * 2, blue.length );
System.arraycopy( blue, 0, luminance, blue.length * 3, blue.length );
}
/** Optimized DCT add and put follows */
private static final int W1 = 22725; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W2 = 21407; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W3 = 19266; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W4 = 16383; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W5 = 12873; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W6 = 8867; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int W7 = 4520; //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5
private static final int ROW_SHIFT = 11;
private static final int COL_SHIFT = 20;
private int block0, block1, block2, block3, block4, block5, block6, block7;
private int a0, a1, a2, a3;
private int b0, b1, b2, b3;
private final void idctRowCondDC( int[] block, int offset ) {
block0 = block[ offset ];
block1 = block[ offset + 1 ];
block2 = block[ offset + 2 ];
block3 = block[ offset + 3 ];
block4 = block[ offset + 4 ];
block5 = block[ offset + 5 ];
block6 = block[ offset + 6 ];
block7 = block[ offset + 7 ];
if ( (block1|block2|block3|block4|block5|block6|block7) == 0 ) {
block0 <<= 3;
block[ offset ] = block0;
block[ offset + 1 ] = block0;
block[ offset + 2 ] = block0;
block[ offset + 3 ] = block0;
block[ offset + 4 ] = block0;
block[ offset + 5 ] = block0;
block[ offset + 6 ] = block0;
block[ offset + 7 ] = block0;
return;
}
a0 = W4 * block0 + (1 << (ROW_SHIFT - 1));
a1 = a0 + W6 * block2 - W4 * block4 - W2 * block6;
a2 = a0 - W6 * block2 - W4 * block4 + W2 * block6;
a3 = a0 - W2 * block2 + W4 * block4 - W6 * block6;
a0 += W2 * block2 + W4 * block4 + W6 * block6;
b0 = W1 * block1 + W3 * block3 + W5 * block5 + W7 * block7;
b1 = W3 * block1 - W7 * block3 - W1 * block5 - W5 * block7;
b2 = W5 * block1 - W1 * block3 + W7 * block5 + W3 * block7;
b3 = W7 * block1 - W5 * block3 + W3 * block5 - W1 * block7;
block[ offset + 0 ] = (a0 + b0) >> ROW_SHIFT;
block[ offset + 7 ] = (a0 - b0) >> ROW_SHIFT;
block[ offset + 1 ] = (a1 + b1) >> ROW_SHIFT;
block[ offset + 6 ] = (a1 - b1) >> ROW_SHIFT;
block[ offset + 2 ] = (a2 + b2) >> ROW_SHIFT;
block[ offset + 5 ] = (a2 - b2) >> ROW_SHIFT;
block[ offset + 3 ] = (a3 + b3) >> ROW_SHIFT;
block[ offset + 4 ] = (a3 - b3) >> ROW_SHIFT;
}
private final void idctSparseColAdd( int[] block, int offset, int[] destination, int destinationOffset, int destinationWidth ) {
block0 = block[ offset ];
block1 = block[ offset + 1 * 8 ];
block2 = block[ offset + 2 * 8 ];
block3 = block[ offset + 3 * 8 ];
block4 = block[ offset + 4 * 8 ];
block5 = block[ offset + 5 * 8 ];
block6 = block[ offset + 6 * 8 ];
block7 = block[ offset + 7 * 8 ];
a0 = W4 * block0 + (1 << (COL_SHIFT - 1));
a1 = a0 + W6 * block2 - W4 * block4 - W2 * block6;
a2 = a0 - W6 * block2 - W4 * block4 + W2 * block6;
a3 = a0 - W2 * block2 + W4 * block4 - W6 * block6;
a0 += W2 * block2 + W4 * block4 + W6 * block6;
b0 = W1 * block1 + W3 * block3 + W5 * block5 + W7 * block7;
b1 = W3 * block1 - W7 * block3 - W1 * block5 - W5 * block7;
b2 = W5 * block1 - W1 * block3 + W7 * block5 + W3 * block7;
b3 = W7 * block1 - W5 * block3 + W3 * block5 - W1 * block7;
destinationOffset += offset;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a0 + b0) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a1 + b1) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a2 + b2) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a3 + b3) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a3 - b3) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a2 - b2) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a1 - b1) >> COL_SHIFT)); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop(destination[ destinationOffset ] + ((a0 - b0) >> COL_SHIFT));
}
private final void idctAdd( int[] block, int[] destination, int destinationOffset, int destinationWidth ) {
if ( debugFT ) {
boolean t = false;
for ( int i = 0; i < block.length; i++ ) {
if ( block[i] != 0 ) t = true;
}
if ( t ) {
debug.print( "Add " );
for ( int i = 0; i < block.length; i++ ) {
debug.print( Integer.toHexString(block[i]) + " " );
}
debug.println();
}
}
idctRowCondDC( block, 0 );
idctRowCondDC( block, 8 );
idctRowCondDC( block, 16 );
idctRowCondDC( block, 24 );
idctRowCondDC( block, 32 );
idctRowCondDC( block, 40 );
idctRowCondDC( block, 48 );
idctRowCondDC( block, 56 );
idctSparseColAdd( block, 0, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 1, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 2, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 3, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 4, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 5, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 6, destination, destinationOffset, destinationWidth );
idctSparseColAdd( block, 7, destination, destinationOffset, destinationWidth );
}
private final void idctSparseColPut( int[] block, int offset, int[] destination, int destinationOffset, int destinationWidth ) {
block0 = block[ offset ];
block1 = block[ offset + 1 * 8 ];
block2 = block[ offset + 2 * 8 ];
block3 = block[ offset + 3 * 8 ];
block4 = block[ offset + 4 * 8 ];
block5 = block[ offset + 5 * 8 ];
block6 = block[ offset + 6 * 8 ];
block7 = block[ offset + 7 * 8 ];
a0 = W4 * block0 + (1 << (COL_SHIFT - 1));
a1 = a0 + W6 * block2 - W4 * block4 - W2 * block6;
a2 = a0 - W6 * block2 - W4 * block4 + W2 * block6;
a3 = a0 - W2 * block2 + W4 * block4 - W6 * block6;
a0 += W2 * block2 + W4 * block4 + W6 * block6;
b0 = W1 * block1 + W3 * block3 + W5 * block5 + W7 * block7;
b1 = W3 * block1 - W7 * block3 - W1 * block5 - W5 * block7;
b2 = W5 * block1 - W1 * block3 + W7 * block5 + W3 * block7;
b3 = W7 * block1 - W5 * block3 + W3 * block5 - W1 * block7;
destinationOffset += offset;
destination[ destinationOffset ] = crop((a0 + b0) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a1 + b1) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a2 + b2) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a3 + b3) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a3 - b3) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a2 - b2) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a1 - b1) >> COL_SHIFT); destinationOffset += destinationWidth;
destination[ destinationOffset ] = crop((a0 - b0) >> COL_SHIFT);
}
private final void idctPut( int[] block, int[] destination, int destinationOffset, int destinationWidth ) {
if ( debugFT ) {
int count = 0;
debug.print( "dct " );
for ( int i = 0; i < block.length; i++ ) {
debug.print( Integer.toHexString( block[i] ) + " " );
}
debug.println();
}
idctRowCondDC( block, 0 );
idctRowCondDC( block, 8 );
idctRowCondDC( block, 16 );
idctRowCondDC( block, 24 );
idctRowCondDC( block, 32 );
idctRowCondDC( block, 40 );
idctRowCondDC( block, 48 );
idctRowCondDC( block, 56 );
idctSparseColPut( block, 0, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 1, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 2, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 3, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 4, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 5, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 6, destination, destinationOffset, destinationWidth );
idctSparseColPut( block, 7, destination, destinationOffset, destinationWidth );
if ( debugOutput ) {
debug.print( "Out " );
for ( int y = 0; y < 8; y++ ) {
for ( int x = 0; x < 8; x++ ) {
debug.print( Integer.toHexString(destination[ destinationOffset + x + (y * destinationWidth)]) + " " );
}
}
debug.println();
}
}
/**
* Move into range 0-ff
*/
private static final int crop( int x ) {
if ( (x & 0xff) == x ) return x;
if ( x < 0 ) {
x = 0;
} else if ( x > 0xff ) {
x = 0xff;
}
return x;
}
/**
* Put luminance IDCT at (mbX, mbY)
*
* @param interlaced Set to true for draw to single field (mbY LSB --> field number)
*/
public final void putLuminanceIdct( int mbX, int mbY, int[] block, boolean interlaced ) {
int offset = interlaced ? (mbX * 8 + 16 + ((mbY&~1) * 8 + 16 + (mbY&1)) *screenX)
: (mbX * 8 + 16 + (mbY * 8 + 16) *screenX);
idctPut( block, luminance, offset, interlaced ? screenX*2 : screenX );
}
/**
* Put R Chrominance IDCT at (mbX, mbY)
*/
public final void putRedIdct( int mbX, int mbY, int[] block ) {
idctPut( block, red, (mbX * 8 + 8 + (mbY * 8 + 8) *chromX), chromX );
}
/**
* Put B Chrominance IDCT at (mbX, mbY)
*/
public final void putBlueIdct( int mbX, int mbY, int[] block ) {
idctPut( block, blue, (mbX * 8 + 8 + (mbY * 8 + 8) *chromX), chromX );
}
/**
* Non-interlaced Luminance
*/
public final void putLuminanceIdct( int mbX, int mbY, int[] block ) {
idctPut( block, luminance, mbX * 8 + 16 + (mbY * 8 + 16) *screenX, screenX );
}
/**
* Add luminance IDCT at (mbX, mbY)
*
* @param interlaced Set to true for draw to single field (mbY LSB --> field number)
*/
public final void addLuminanceIdct( int mbX, int mbY, int[] block, boolean interlaced ) {
int offset = interlaced ? (mbX * 8 + 16 + ((mbY&~1) * 8 + 16 + (mbY&1)) *screenX)
: (mbX * 8 + 16 + (mbY * 8 + 16) *screenX);
idctAdd( block, luminance, offset, interlaced ? screenX*2 : screenX );
}
/**
* Add R Chrominance IDCT at (mbX, mbY)
*/
public final void addRedIdct( int mbX, int mbY, int[] block ) {
idctAdd( block, red, (mbX * 8 + 8 + (mbY * 8 + 8) *chromX), chromX );
}
/**
* Add B Chrominance IDCT at (mbX, mbY)
*/
public final void addBlueIdct( int mbX, int mbY, int[] block ) {
idctAdd( block, blue, (mbX * 8 + 8 + (mbY * 8 + 8) *chromX), chromX );
}
/**
* Non-interlaced Luminance
*/
public final void addLuminanceIdct( int mbX, int mbY, int[] block ) {
idctAdd( block, luminance, mbX * 8 + 16 + (mbY * 8 + 16)*screenX, screenX );
}
/** The following code performs the MPEG motion bit blitting */
/**
* On pixel with rounding
*/
private final void blitBlock0Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
dy += top;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
for ( x = left; x < right; x++ ) {
destination[ x + y ] = source[ x + dx + dy ];
}
}
}
/**
* Horizontal pair pixel merge with rounding
*/
private final void blitBlock1Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int leftPixel, rightPixel;
dy += top;
int leftPlusDx = left + dx;
int dxPlus1 = dx + 1;
int dxPlus1PlusDy;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
rightPixel = source[ leftPlusDx + dy ];
dxPlus1PlusDy = dxPlus1 + dy;
for ( x = left; x < right; x++ ) {
leftPixel = rightPixel;
rightPixel = source[ x + dxPlus1PlusDy ];
destination[ x + y ] =
(leftPixel|rightPixel) - ((leftPixel^rightPixel) >>1);
}
}
}
/**
* Vertical pair pixel merge with rounding
*/
private final void blitBlock2Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int topPixel, bottomPixel;
int dxPlusDyPlusTop = dx + dy + top;
int dxPlusDestWidth = dx + destinationWidth;
int xPlusDxPlusDestWidth;
for ( x = left; x < right; x++ ) {
bottomPixel = source[ x + dxPlusDyPlusTop ];
xPlusDxPlusDestWidth = x + dxPlusDestWidth + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
topPixel = bottomPixel;
bottomPixel = source[ xPlusDxPlusDestWidth + y ];
destination[ x + y ] =
(topPixel|bottomPixel) - ((topPixel^bottomPixel) >>1);
}
}
}
/**
* Horizontal and vertical pair pixel merge with rounding
*/
private final void blitBlock3Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int a,b;
int dxPlusDyPlusTop = dx + dy + top;
int xPlusDxPlusDy;
dy += destinationWidth;
for ( x = left; x < right; x++ ) {
b = source[ x + dxPlusDyPlusTop ] + source[ x + dxPlusDyPlusTop + 1 ];
xPlusDxPlusDy = x + dx + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
a = b;
b = source[ xPlusDxPlusDy + y ] + source[ xPlusDxPlusDy + 1 + y ];
destination[ x + y ] = (a + b + 2) >>2;
}
}
}
/**
* On pixel with no rounding
*/
private final void blitBlock0NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
dy += top;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
for ( x = left; x < right; x++ ) {
destination[ x + y ] = source[ x + dx + dy ];
}
}
}
/**
* Horizontal pair pixel merge with no rounding
*/
private final void blitBlock1NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int leftPixel, rightPixel;
dy += top;
int leftPlusDx = left + dx;
int dxPlus1 = dx + 1;
int dxPlus1PlusDy;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
rightPixel = source[ leftPlusDx + dy ];
dxPlus1PlusDy = dxPlus1 + dy;
for ( x = left; x < right; x++ ) {
leftPixel = rightPixel;
rightPixel = source[ x + dxPlus1PlusDy ];
destination[ x + y ] =
(leftPixel&rightPixel) + ((leftPixel^rightPixel) >>1);
}
}
}
/**
* Vertical pair pixel merge with no rounding
*/
private final void blitBlock2NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int topPixel, bottomPixel;
int dxPlusDyPlusTop = dx + dy + top;
int dxPlusDestWidth = dx + destinationWidth;
int xPlusDxPlusDestWidth;
for ( x = left; x < right; x++ ) {
bottomPixel = source[ x + dxPlusDyPlusTop ];
xPlusDxPlusDestWidth = x + dxPlusDestWidth + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
topPixel = bottomPixel;
bottomPixel = source[ xPlusDxPlusDestWidth + y ];
destination[ x + y ] =
(topPixel&bottomPixel) + ((topPixel^bottomPixel) >>1);
}
}
}
/**
* Horizontal and vertical pair pixel merge with no rounding
*/
private final void blitBlock3NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int a,b;
int dxPlusDyPlusTop = dx + dy + top;
int xPlusDxPlusDy;
dy += destinationWidth;
for ( x = left; x < right; x++ ) {
b = source[ x + dxPlusDyPlusTop ] + source[ x + dxPlusDyPlusTop + 1 ];
xPlusDxPlusDy = x + dx + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
a = b;
b = source[ xPlusDxPlusDy + y ] + source[ xPlusDxPlusDy + 1 + y ];
destination[ x + y ] = (a + b + 1) >>2;
}
}
}
/**
* Perform motion blit Source->Destination (blit area) + (dx/dy - halfPixels)
* Boolean rounding
*/
private final void blitBlock( int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right,
int dx, int dy, int halfPixels, boolean rounding ) {
int x,y;
top *= destinationWidth;
bottom *= destinationWidth;
dy *= destinationWidth;
if ( rounding ) {
/* Rounding On */
switch ( halfPixels ) {
case 0: {
/**
* This is a straight copy
*/
blitBlock0Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 1: {
/**
* Half a pixel offset
*/
blitBlock1Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 2: {
/**
* Half a pixel offset
*/
blitBlock2Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 3:
default: {
/**
* Half a pixel offset
*/
blitBlock3Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
}
} else {
switch ( halfPixels ) {
case 0: {
/**
* This is a straight copy
*/
blitBlock0NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 1: {
/**
* Half a pixel offset
*/
blitBlock1NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 2: {
/**
* Half a pixel offset
*/
blitBlock2NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 3:
default: {
/**
* Half a pixel offset
*/
blitBlock3NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
}
}
}
/** The following code performs the MPEG motion bit merging (B frames only) */
/**
* On pixel with rounding addition (B frames only)
*/
private final void mergeBlock0Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
dy += top;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
for ( x = left; x < right; x++ ) {
destination[ x + y ] = (destination[ x + y ] + source[ x + dx + dy ]) >> 1;
}
}
}
/**
* Horizontal pair pixel merge with rounding addition (B frames only)
*/
private final void mergeBlock1Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int leftPixel, rightPixel;
dy += top;
int leftPlusDx = left + dx;
int dxPlus1 = dx + 1;
int dxPlus1PlusDy;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
rightPixel = source[ leftPlusDx + dy ];
dxPlus1PlusDy = dxPlus1 + dy;
for ( x = left; x < right; x++ ) {
leftPixel = rightPixel;
rightPixel = source[ x + dxPlus1PlusDy ];
destination[ x + y ] =
(destination[ x + y ] + (leftPixel|rightPixel) - ((leftPixel^rightPixel) >>1))>>1;
}
}
}
/**
* Vertical pair pixel merge with rounding addition (B frames only)
*/
private final void mergeBlock2Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int topPixel, bottomPixel;
int dxPlusDyPlusTop = dx + dy + top;
int dxPlusDestWidth = dx + destinationWidth;
int xPlusDxPlusDestWidth;
for ( x = left; x < right; x++ ) {
bottomPixel = source[ x + dxPlusDyPlusTop ];
xPlusDxPlusDestWidth = x + dxPlusDestWidth + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
topPixel = bottomPixel;
bottomPixel = source[ xPlusDxPlusDestWidth + y ];
destination[ x + y ] =
(destination[ x + y ] + (topPixel|bottomPixel) - ((topPixel^bottomPixel) >>1))>>1;
}
}
}
/**
* Horizontal and vertical pair pixel merge with rounding addition (B frames only)
*/
private final void mergeBlock3Round(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int a,b;
int dxPlusDyPlusTop = dx + dy + top;
int xPlusDxPlusDy;
dy += destinationWidth;
for ( x = left; x < right; x++ ) {
b = source[ x + dxPlusDyPlusTop ] + source[ x + dxPlusDyPlusTop + 1 ];
xPlusDxPlusDy = x + dx + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
a = b;
b = source[ xPlusDxPlusDy + y ] + source[ xPlusDxPlusDy + 1 + y ];
destination[ x + y ] = (destination[ x + y ] + ((a + b + 2) >>2))>>1;
}
}
}
/**
* On pixel with no rounding addition (B frames only)
*/
private final void mergeBlock0NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
dy += top;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
for ( x = left; x < right; x++ ) {
destination[ x + y ] = (destination[ x + y ] + source[ x + dx + dy ]) >> 1;
}
}
}
/**
* Horizontal pair pixel merge with no rounding addition (B frames only)
*/
private final void mergeBlock1NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int leftPixel, rightPixel;
dy += top;
int leftPlusDx = left + dx;
int dxPlus1 = dx + 1;
int dxPlus1PlusDy;
for ( y = top; y < bottom; y += destinationWidth, dy += destinationWidth ) {
rightPixel = source[ leftPlusDx + dy ];
dxPlus1PlusDy = dxPlus1 + dy;
for ( x = left; x < right; x++ ) {
leftPixel = rightPixel;
rightPixel = source[ x + dxPlus1PlusDy ];
destination[ x + y ] =
(destination[ x + y ] + (leftPixel&rightPixel) + ((leftPixel^rightPixel) >>1)) >> 1;
}
}
}
/**
* Vertical pair pixel merge with no rounding addition (B frames only)
*/
private final void mergeBlock2NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int topPixel, bottomPixel;
int dxPlusDyPlusTop = dx + dy + top;
int dxPlusDestWidth = dx + destinationWidth;
int xPlusDxPlusDestWidth;
for ( x = left; x < right; x++ ) {
bottomPixel = source[ x + dxPlusDyPlusTop ];
xPlusDxPlusDestWidth = x + dxPlusDestWidth + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
topPixel = bottomPixel;
bottomPixel = source[ xPlusDxPlusDestWidth + y ];
destination[ x + y ] =
(destination[ x + y ] + (topPixel&bottomPixel) + ((topPixel^bottomPixel) >>1)) >> 1;
}
}
}
/**
* Horizontal and vertical pair pixel merge with no rounding addition (B frames only)
*/
private final void mergeBlock3NoRound(
int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right, int dx, int dy ) {
int x,y;
int a,b;
int dxPlusDyPlusTop = dx + dy + top;
int xPlusDxPlusDy;
dy += destinationWidth;
for ( x = left; x < right; x++ ) {
b = source[ x + dxPlusDyPlusTop ] + source[ x + dxPlusDyPlusTop + 1 ];
xPlusDxPlusDy = x + dx + dy;
for ( y = top; y < bottom; y += destinationWidth ) {
a = b;
b = source[ xPlusDxPlusDy + y ] + source[ xPlusDxPlusDy + 1 + y ];
destination[ x + y ] = (destination[ x + y ] + ((a + b + 1) >>2)) >> 1;
}
}
}
/**
* Perform motion addition (B frames) Source->Destination (blit area) + (dx/dy - halfPixels)
* Boolean rounding
*/
private final void mergeBlock( int[] source, int[] destination, int destinationWidth,
int top, int bottom, int left, int right,
int dx, int dy, int halfPixels, boolean rounding ) {
int x,y;
top *= destinationWidth;
bottom *= destinationWidth;
dy *= destinationWidth;
if ( rounding ) {
/* Rounding On */
switch ( halfPixels ) {
case 0: {
/**
* This is a straight copy
*/
mergeBlock0Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 1: {
/**
* Half a pixel offset
*/
mergeBlock1Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 2: {
/**
* Half a pixel offset
*/
mergeBlock2Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 3:
default: {
/**
* Half a pixel offset
*/
mergeBlock3Round( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
}
} else {
switch ( halfPixels ) {
case 0: {
/**
* This is a straight copy
*/
mergeBlock0NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 1: {
/**
* Half a pixel offset
*/
mergeBlock1NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 2: {
/**
* Half a pixel offset
*/
mergeBlock2NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
case 3:
default: {
/**
* Half a pixel offset
*/
mergeBlock3NoRound( source, destination, destinationWidth,
top, bottom, left, right, dx, dy );
break;
}
}
}
}
/** Clip value */
private final int clip( int position, int offset, int maximum ) {
if ( position + offset < 0 ) {
position = - offset;
}
if ( position + offset > maximum ) {
position = maximum - offset;
}
return position;
}
/**
* This method is the main entry point to perform a variety of pel motion schemes
* Source YUV maps are passed in (last I/P or next I/P), the destination is always the current frame.
*
* Destination offset is supplied, as is the source and destination field numbers
* Rounding is a boolean. Average triggers the merge used for B frames only.
*/
public void mpeg_motion( int[] sourceLuminance, int[] sourceRed, int[] sourceBlue,
int mbX, int mbY,
int dest_offset, boolean fieldBased, int sourceFieldNumber, int destFieldNumber,
boolean rounding, boolean average,
int motion_x, int motion_y,
int leftOffset, int topOffset,
int width, int height ) {
if ( motionDebug && (motion_x != 0||motion_y != 0) )
{
debug.println( "mpeg_motion pos:(" + Integer.toHexString(mbX) + "," + Integer.toHexString(mbY) +
") size:(" + Integer.toHexString(width) + "," + Integer.toHexString(height) +
") motion:(" + Integer.toHexString(motion_x) + "," + Integer.toHexString(motion_y) +
")" );
}
/* field based operations work on alternate lines */
int lineLength = fieldBased ? screenX * 2 : screenX;
/**
* Manage clipping
*/
int top = mbY * 16 + 16 + topOffset;
int left = mbX * 16 + 16 + leftOffset;
/*
* Field based lines are twice the length
*/
if ( fieldBased ) top = (top / 2);
/**
* Manage half pixel motion
*/
int halfPixels = (motion_x & 1)|((motion_y & 1)<<1);
int dx = motion_x / 2;
int dy = motion_y / 2;
if ( motion_x < 0 && ((halfPixels & 1) == 1)) {
dx--;
}
if ( motion_y < 0 && ((halfPixels & 2) == 2)) {
dy--;
}
/**
* Clipped region from the edge previous buffer
*/
left = clip( left, dx, screenX - 16 );
top = clip( top, dy, (fieldBased ? (screenY / 2 - 8) : screenY - 16 ) );
int right = left + width;
int bottom = top + height;
if ( right + dx == screenX ) halfPixels &= ~1;
if ( bottom + dy == (fieldBased ? (screenY / 2) : screenY ) ) halfPixels &= ~2;
/*
* Field based lines are twice the length
*/
if ( fieldBased && destFieldNumber == 1 ) {
left += screenX;
right += screenX;
}
if ( fieldBased && sourceFieldNumber != destFieldNumber ) {
/* Copy Field 0 <==> Field 1 */
dx += screenX * (sourceFieldNumber - destFieldNumber);
}
/*
System.out.println( "From" );
for ( int n = top; n < bottom; n++ ) {
for ( int m = left; m < right; m++ ) {
System.out.print( (oldLuminance[ m + n * lineLength ] + " ") );
}
}
System.out.println();
*/
/**
* Luminance
*/
if ( average ) {
mergeBlock( sourceLuminance, luminance, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
} else {
blitBlock( sourceLuminance, luminance, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
}
/*
if ( left + dx< 16 || top +dy< 16 || right + dx + (halfPixels&1) > displayX + 16
|| bottom + dy + ((halfPixels&2)>>1) > displayY + 16 ) {
System.out.println( "motion(" + motion_x + " " + motion_y + ")" );
System.out.println( "move(" + (left+dx-16) +" " + (top+dy-16) + " " + halfPixels + ")" );
for (int y = top; y < bottom; y++ ) {
for ( int x = left; x < right; x++) {
System.out.print( Integer.toHexString( luminance[ x ][ y ] ) + " " );
}
System.out.println();
}
}
*/
/**
* Chrominance
*/
/* field based operations work on alternate luminance lines */
lineLength = fieldBased ? chromX * 2 : chromX;
top = mbY * 8 + 8 + (topOffset/2);
left = mbX * 8 + 8 + (leftOffset/2);
/*
* Field based lines are twice the length
*/
if ( fieldBased ) top = (top / 2);
/* Round up */
if ( (motion_x & 1) != 0 ) { if (motion_x < 0) {motion_x--; } else { motion_x++; } }
if ( (motion_y & 1) != 0 ) { if (motion_y < 0) {motion_y--; } else { motion_y++; } }
halfPixels = (motion_y & 2)|((motion_x & 2)>>1);
dx = motion_x / 4;
dy = motion_y / 4;
if ( motion_x < 0 && ((halfPixels & 1) == 1)) {
dx--;
}
if ( motion_y < 0 && ((halfPixels & 2) == 2)) {
dy--;
}
/**
* Clipped region is a straight copy from previous buffer
*/
left = clip( left, dx, chromX - 8 );
top = clip( top, dy, (fieldBased ? (chromY / 2 - 4) : chromY - 8) );
right = left + width/2;
bottom = top + height/2;
if ( right + dx == chromX ) halfPixels &= ~1;
if ( bottom + dy == (fieldBased ? (chromY / 2) : chromY ) ) halfPixels &= ~2;
/*
* Field based lines are twice the length
*/
if ( fieldBased && destFieldNumber == 1 ) {
left += chromX;
right += chromX;
}
if ( fieldBased && sourceFieldNumber != destFieldNumber ) {
/* Copy Field 0 <==> Field 1 */
dx += chromX * (sourceFieldNumber - destFieldNumber);
}
if ( average ) {
mergeBlock( sourceBlue, blue, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
mergeBlock( sourceRed, red, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
} else {
blitBlock( sourceBlue, blue, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
blitBlock( sourceRed, red, lineLength,
top, bottom, left, right,
dx, dy, halfPixels, rounding );
}
}
/**
* This is the main move block function, controlling a large number of different
* MV types
*/
public void move( int[] sourceLuminance, int[] sourceRed, int[] sourceBlue,
int mbX, int mbY, int[] motion, int motionOffset,
boolean rounding, boolean average, int mv_type, boolean[] fieldSelect, int fieldSelectOffset ) {
switch ( mv_type ) {
case MpegVideo.MV_TYPE_16X16: {
// System.out.println( "MV_TYPE_16X16" );
mpeg_motion( sourceLuminance, sourceRed, sourceBlue,
mbX, mbY,
0, false, 0, 0,
rounding, average,
motion[motionOffset], motion[motionOffset + 1],
0, 0, 16, 16 );
break;
}
case MpegVideo.MV_TYPE_FIELD: {
/* mpeg_motion( sourceLuminance, sourceRed, sourceBlue,
mbX, mbY,
0, false, 0, 0,
rounding, average, (motion[0][0]+motion[1][0])/2, (motion[0][1]+motion[1][1])/2, 16 );
/* System.out.println( "MV_TYPE_FIELD" ); */
mpeg_motion( sourceLuminance, sourceRed, sourceBlue,
mbX, mbY,
0, true, fieldSelect[fieldSelectOffset]?1:0, 0, // Field based, source field, destination field ID
rounding, average, motion[motionOffset], (motion[motionOffset + 1]),
0, 0, 16, 8 );
mpeg_motion( sourceLuminance, sourceRed, sourceBlue,
mbX, mbY,
0, true, fieldSelect[fieldSelectOffset + 1]?1:0, 1,
rounding, average, motion[motionOffset + 2], motion[motionOffset + 3],
0, 0, 16, 8 );
break;
}
default: {
throw new Error ( "Unrecognised " + mv_type );
}
}
}
private final static int divide2( int a ) {
if ( a < 0 ) { return a/2 - (a & 1); } else { return a/2 + (a & 1); }
}
public final void moveFromLast( int mbX, int mbY, int[] motion, int motionOffset, boolean rounding, boolean average, int mv_type, boolean[] fieldSelect, int fieldSelectOffset ) {
move( oldLuminance, oldRed, oldBlue, mbX, mbY, motion, motionOffset, rounding, average, mv_type, fieldSelect, fieldSelectOffset );
}
public final void moveFromNext( int mbX, int mbY, int[] motion, int motionOffset, boolean rounding, boolean average, int mv_type, boolean[] fieldSelect, int fieldSelectOffset ) {
move( nextPLuminance, nextPRed, nextPBlue, mbX, mbY, motion, motionOffset, rounding, average, mv_type, fieldSelect, fieldSelectOffset );
}
/**
* Copy this macroblock from the previous frame (MPEG4)
*/
public void move( int mbX, int mbY, int motion_x, int motion_y, boolean rounding ) {
mpeg_motion( oldLuminance, oldRed, oldBlue, mbX, mbY,
0, false, 0, 0,
rounding, false,
motion_x, motion_y,
0, 0, 16, 16 );
}
/**
* Merge this macroblock with the next frame (MPEG4)
*/
public void moveFromNext( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, boolean merge ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue, mbX, mbY,
0, false, 0, 0,
rounding, merge,
motion_x, motion_y,
0, 0, 16, 16 );
}
/**
* Merge this macroblock with the next frame (MPEG4)
*/
public void moveFromIPFrame( int mbX, int mbY, int motion_x, int motion_y, boolean rounding ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue, mbX, mbY,
0, false, 0, 0,
rounding, false,
motion_x, motion_y,
0, 0, 16, 16 );
}
/**
* Copy a field block from the previous frame (MPEG4)
* //TODO Checkme
*/
public void moveField( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, boolean field ) {
mpeg_motion( oldLuminance, oldRed, oldBlue,
mbX, mbY,
0, true, field?1:0, 0, // Field based, source field, destination field ID
rounding, false, motion_x, motion_y,
0, 0, 16, 8 );
}
/**
* Merge a field block from the next frame (MPEG4)
* //TODO Checkme
*/
public void moveFieldFromNext( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, boolean field, boolean merge ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue,
mbX, mbY,
0, true, field?1:0, 0, // Field based, source field, destination field ID
rounding, merge, motion_x, motion_y,
0, 0, 16, 8 );
}
/**
* Merge a field block from the next frame (MPEG4)
* //TODO Checkme
*/
public void moveFieldFromIPFrame( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, boolean field ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue,
mbX, mbY,
0, true, field?1:0, 0, // Field based, source field, destination field ID
rounding, false, motion_x, motion_y,
0, 0, 16, 8 );
}
/**
* Copy an 8x8 block from the previous frame (MPEG4)
*/
public void move8x8( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, int leftOffset, int topOffset ) {
mpeg_motion( oldLuminance, oldRed, oldBlue, mbX, mbY,
0, false, 0, 0,
rounding, false,
motion_x, motion_y,
leftOffset, topOffset, 8, 8 );
}
/**
* Copy an 8x8 block from the previous frame (MPEG4)
*/
public void move8x8FromNext( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, int leftOffset, int topOffset, boolean merge ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue, mbX, mbY,
0, false, 0, 0,
rounding, merge,
motion_x, motion_y,
leftOffset, topOffset, 8, 8 );
}
/**
* Copy an 8x8 block from the previous frame (MPEG4)
*/
public void move8x8FromIPFrame( int mbX, int mbY, int motion_x, int motion_y, boolean rounding, int leftOffset, int topOffset ) {
mpeg_motion( nextPLuminance, nextPRed, nextPBlue, mbX, mbY,
0, false, 0, 0,
rounding, false,
motion_x, motion_y,
leftOffset, topOffset, 8, 8 );
}
/* public static final void clear( int[] a ) {
for ( int y = a.length - 1; y >= 0; y-- ) a[y] = 0;
}
*/
/**
* This is an I or P frame - (current -> next -> last)
*/
public final void endIPFrame() {
// clear( oldLuminance ); clear( oldRed ); clear( oldBlue );
/** Set current as next, next as previous, etc */
int[] t;
t = oldLuminance; oldLuminance = nextPLuminance; nextPLuminance = luminance; luminance = t;
t = oldRed; oldRed = nextPRed; nextPRed = red; red = t;
t = oldBlue; oldBlue = nextPBlue; nextPBlue = blue; blue = t;
/**
* Expand next frame into Boarders
*
for ( int x = 0; x < 16; x++ ) {
for ( int y = 16; y < displayY + 16; y++ ) {
nextPLuminance[ x + y * screenX ] = nextPLuminance[ 16 + y * screenX ];
nextPLuminance[ displayX + 32 - x - 1 + y * screenX ] = nextPLuminance[ displayX + 15 + y * screenX ];
nextPBlue[ x/2 + (y/2)*chromX ] = nextPBlue[ 16 /2 + (y/2)*chromX ];
nextPBlue[ (displayX + 32 - x)/2 - 1 + (y/2)*chromX ] = nextPBlue[ (displayX + 16)/2 - 1 + (y/2)*chromX ];
nextPRed[ x/2 + (y/2) * chromX ] = nextPRed[ 16 /2 + (y/2)*chromX ];
nextPRed[ (displayX + 32 - x)/2 - 1 + (y/2)*chromX ] = nextPRed[ (displayX + 16)/2 - 1 + (y/2)*chromX ];
}
}
for ( int y = 0; y < 16; y++ ) {
for ( int x = 0; x < displayX + 32; x++ ) {
nextPLuminance[ x + y * screenX ] = nextPLuminance[ x + 16 * screenX ];
nextPLuminance[ x + (displayY + 32 - y - 1) * screenX ] = nextPLuminance[ x + (displayY + 15) * screenX ];
nextPBlue[ x/2 + (y/2)*chromX ] = nextPBlue[ x/2 + (16/2)*chromX ];
nextPBlue[ x /2 + ((displayY + 32 - y )/2 - 1)*chromX ] = nextPBlue[ x/2 + ((displayY + 16)/2 - 1)*chromX];
nextPRed[ x/2 + (y/2)*chromX ] = nextPRed[ x/2 + (16/2)*chromX ];
nextPRed[ x /2 + ((displayY + 32 - y)/2 - 1)*chromX ] = nextPRed[ x/2 + ((displayY + 16)/2 - 1)*chromX ];
}
}
*/
}
/**
* End B frame - this gets discarded so does nothing :)
*/
public final void endBFrame() {
}
public final void endFrame() {
expandIntoBoarder();
/** Set current as previous, etc */
int[] t;
t = oldLuminance; oldLuminance = luminance; luminance = t;
t = oldRed; oldRed = red; red = t;
t = oldBlue; oldBlue = blue; blue = t;
}
public final void expandIntoBoarder() {
/**
* Expand into Boarders
*/
int x,y,y1,l1,l2,xoff,r1,r2,b1,b2,yoff;
int screenX16 = 16 * screenX;
for ( y = displayY * screenX ; y > 0; ) {
y -= screenX;
y1 = y + screenX16; /* Start at bottom-left of display */
xoff = displayX + 16 + y1; /* First pixel in RH border */
l1 = luminance[ 16 + y1 ]; /* Pixel at left edge of display */
l2 = luminance[ xoff - 1 ]; /* Pixel at right edge of display */
for ( x = 16; x > 0; ) {
x--;
luminance[ x + y1 ] = l1; /* Left border */
luminance[ xoff + x ] = l2; /* Right border */
}
}
int chromXX8 = 8 * chromX;
int dxtemp = displayX/2 + 8;
for ( y = displayY/2 * chromX; y > 0; ) {
y -= chromX;
y1 = y + chromXX8; /* Start at bottom-left of chroma */
xoff = dxtemp + y1; /* First pixel in RH border */
b1 = blue[ 8 + y1 ]; /* Pixel at left edge of display */
b2 = blue[ xoff - 1 ]; /* Pixel at RH edge of display */
r1 = red[ 8 + y1 ];
r2 = red[ xoff - 1];
for ( x = 8; x > 0; ) {
x--;
blue[ x + y1 ] = b1; /* Left boarder */
blue[ xoff + x ] = b2; /* Right border */
red[ x + y1 ] = r1;
red[ xoff + x ] = r2;
}
}
int dtemp = (displayY + 16) * screenX;
for ( x = screenX; x > 0; ) { /* Full screen width */
x--;
yoff = x + dtemp; /* First pixel in bottom border */
l1 = luminance[ x + screenX16 ]; /* Pixel at top of screen */
l2 = luminance[ yoff - screenX ]; /* Pixel at bottom of screen */
for ( y = screenX16; y > 0; ) {
y -= screenX;
luminance[ x + y ] = l1; /* Top boarder */
luminance[ yoff + y] = l2; /* Bottom boarder */
}
}
int btemp = (displayY/2 + 8)*chromX;
for ( x = chromX; x > 0; ) { /* Full Chroma screen Width */
x--;
yoff = x + btemp; /* First pixel in bottom border */
b1 = blue[ x + chromXX8 ]; /* Pixel at top of screen */
b2 = blue[ yoff - chromX]; /* Pixel at bottom of screen */
r1 = red[ x + chromXX8 ];
r2 = red[ yoff - chromX];
for ( y = chromXX8; y > 0; ) {
y -= chromX;
blue[ x + y ] = b1; /* Top border */
blue[ yoff + y ] = b2; /* Bottom border */
red[ x + y ] = r1;
red[ yoff + y ] = r2;
}
}
}
/**
* Show next I/P frame (will then become old frame)
*/
public void showNextScreen( Buffer buffer ) {
int[] data = (int[])buffer.getData();
if ( data == null || data.length < displayX * displayY ) {
data = new int[ displayX * displayY ];
buffer.setData( data );
}
buffer.setLength( data.length );
int h = 0;
int yCount = displayY/2;
int xCount = displayX/2;
int l1,l2,l3,l4,r,b,g,rshift,yoff,yoff1,chromoff,x2,x,xo,scale;
int y = 14;
for (int yo = yCount; yo > 0; yo-- ) {
y += 2;
x2 = 8 + y/2 * chromX;
x = 14 + screenX * y;
for ( xo = xCount; xo > 0; xo-- ) {
x += 2;
r = crop( nextPRed[ x2 ] ) - 128;
b = crop( nextPBlue[ x2++ ] ) - 128;
g = (b * 13954 + r * 34903)>>16;
r = (r * 117504)>>16;
b = (b * 138452)>>16;
// l = 0.3 red + 0.59 green + 0.11 blue
l1 = ((nextPLuminance[ x ]-16)*76309)>>16;
l3 = ((nextPLuminance[ x + screenX ]-16)*76309)>>16;
l2 = ((nextPLuminance[ x + 1 ]-16)*76309)>>16;
l4 = ((nextPLuminance[ x + 1 + screenX ]-16)*76309)>>16;
data[h ] = (crop(l1+r)<<16)|(crop(l1-g)<<8)|crop(l1+b);
data[h + 1 ] = (crop(l2+r)<<16)|(crop(l2-g)<<8)|crop(l2+b);
data[h + displayX] = (crop(l3+r)<<16)|(crop(l3-g)<<8)|crop(l3+b);
data[h + 1 + displayX] = (crop(l4+r)<<16)|(crop(l4-g)<<8)|crop(l4+b);
h += 2;
}
h += displayX;
}
}
/**
* Show current B frame
*/
public void showScreen( Buffer buffer ) {
int[] data = (int[])buffer.getData();
if ( data == null || data.length < displayX * displayY ) {
data = new int[ displayX * displayY ];
buffer.setData( data );
}
buffer.setLength( data.length );
int h = 0;
int yCount = displayY/2;
int xCount = displayX/2;
int l1,l2,l3,l4,r,b,g,rshift,yoff,yoff1,chromoff,x2,x,xo,scale;
int y = 14;
for (int yo = yCount; yo > 0; yo-- ) {
y += 2;
x2 = 8 + y/2 * chromX;
x = 14 + screenX * y;
for ( xo = xCount; xo > 0; xo-- ) {
x += 2;
r = crop( red[ x2 ] ) - 128;
b = crop( blue[ x2++ ] ) - 128;
g = (b * 13954 + r * 34903)>>16;
r = (r * 117504)>>16;
b = (b * 138452)>>16;
// l = 0.3 red + 0.59 green + 0.11 blue
l1 = ((luminance[ x ]-16)*76309)>>16;
l3 = ((luminance[ x + screenX ]-16)*76309)>>16;
l2 = ((luminance[ x + 1 ]-16)*76309)>>16;
l4 = ((luminance[ x + 1 + screenX ]-16)*76309)>>16;
data[h ] = (crop(l1+r)<<16)|(crop(l1-g)<<8)|crop(l1+b);
data[h + 1 ] = (crop(l2+r)<<16)|(crop(l2-g)<<8)|crop(l2+b);
data[h + displayX] = (crop(l3+r)<<16)|(crop(l3-g)<<8)|crop(l3+b);
data[h + 1 + displayX] = (crop(l4+r)<<16)|(crop(l4-g)<<8)|crop(l4+b);
h += 2;
}
h += displayX;
}
}
public void dumpMB( int x, int y ) {
System.out.println( "x " + (x++) + ", y "+ (y++) );
for ( int n = y * 16; n < y * 16 + 16; n++ ) {
for ( int m = x * 16; m < x * 16 + 16; m++ ) {
System.out.print( luminance[ m + n * screenX ] + " " );
}
System.out.println();
}
System.out.println();
for ( int n = y * 8; n < y * 8 + 8; n+=2 ) {
for ( int m = x * 8; m < x * 8 + 8; m++ ) {
System.out.print( blue[ m + n * chromX ] + " " );
}
System.out.println();
}
System.out.println();
for ( int n = y * 8; n < y * 8 + 8; n+=2 ) {
for ( int m = x * 8; m < x * 8 + 8; m++ ) {
System.out.print( red[ m + n * chromX ] + " " );
}
System.out.println();
}
System.out.println();
}
}