MODULE MPEGUtilities;
IMPORT
SYSTEM, Machine, MPEGTables, Streams, KernelLog, Raster, Codecs;
CONST
W1 = 2841;
W2 = 2676;
W3 = 2408;
W5 = 1609;
W6 = 1108;
W7 = 565;
EnableMMX = TRUE;
VAR
IdctBorder*: POINTER TO ARRAY OF LONGINT;
ii: LONGINT;
TYPE
PointerToArrayOfCHAR* = POINTER TO ARRAY OF CHAR;
PointerToArrayOfLONGINT* = POINTER TO ARRAY OF LONGINT;
Dequantizer* = OBJECT
PROCEDURE DequantizeNonintraCoeffs*(
coeffs: PointerToArrayOfLONGINT;
nonintraQM: PointerToArrayOfLONGINT;
qScale: LONGINT): BOOLEAN;
VAR
i: LONGINT;
sign: LONGINT;
BEGIN
FOR i := 0 TO 63 DO
IF coeffs[i] > 0 THEN
sign := 1;
ELSIF coeffs[i] = 0 THEN
sign := 0;
ELSE
sign := -1;
END;
coeffs[i] := ((2*coeffs[i] + sign) * qScale * nonintraQM[i]) DIV 16;
IF (coeffs[i] MOD 2) = 0 THEN
coeffs[i] := coeffs[i] - sign;
END;
IF coeffs[i] > 2047 THEN
coeffs[i] := 2047;
END;
IF coeffs[i] < -2048 THEN
coeffs[i] := -2048;
END;
END;
RETURN TRUE;
END DequantizeNonintraCoeffs;
PROCEDURE DequantizeIntraCoeffs*(
coeffs: PointerToArrayOfLONGINT;
intraQM: PointerToArrayOfLONGINT;
qScale: LONGINT;
VAR prediction: LONGINT;
first: BOOLEAN;
mbSkipped: BOOLEAN): BOOLEAN;
VAR
i: LONGINT;
BEGIN
FOR i := 1 TO 63 DO
coeffs[i] := (2*coeffs[i]*qScale*intraQM[i]) DIV 16;
IF ((coeffs[i] MOD 2) = 0) & (coeffs[i] # 0) THEN
IF coeffs[i] > 0 THEN
DEC(coeffs[i]);
ELSE
INC(coeffs[i]);
END;
END;
IF coeffs[i] > 2047 THEN
coeffs[i] := 2047;
END;
IF coeffs[i] < -2048 THEN
coeffs[i] := -2048;
END;
END;
coeffs[0] := coeffs[0] * 8;
IF first & mbSkipped THEN
prediction := 8*128;
END;
INC(prediction, coeffs[0]);
coeffs[0] := prediction;
RETURN TRUE;
END DequantizeIntraCoeffs;
PROCEDURE DequantizeNonintraCoeffs2*(
coeffs: PointerToArrayOfLONGINT;
nonintraQM: PointerToArrayOfLONGINT;
qScale: LONGINT);
VAR
i: LONGINT;
sum: LONGINT;
BEGIN
FOR i := 0 TO 63 DO
IF coeffs[i] # 0 THEN
IF coeffs[i] > 0 THEN
coeffs[i] := ((2 * coeffs[i] + 1) * nonintraQM[i] * qScale) DIV 32;
ELSE
coeffs[i] := ((2 * coeffs[i] - 1) * nonintraQM[i] * qScale) DIV 32;
END;
IF coeffs[i] > 2047 THEN
coeffs[i] := 2047;
ELSIF coeffs[i] < -2048 THEN
coeffs[i] := -2048;
END;
INC(sum, coeffs[i]);
END;
END;
MismatchControl(coeffs[63], sum);
END DequantizeNonintraCoeffs2;
PROCEDURE DequantizeIntraCoeffs2*(
coeffs: PointerToArrayOfLONGINT;
intraQM: PointerToArrayOfLONGINT;
qScale: LONGINT;
dcPrecision: LONGINT);
VAR
i: LONGINT;
sum: LONGINT;
BEGIN
coeffs[0] := MPEGTables.DCM[dcPrecision] * coeffs[0];
sum := coeffs[0];
FOR i := 1 TO 63 DO
coeffs[i] := ((2 * coeffs[i]) * intraQM[i] * qScale) DIV 32;
IF coeffs[i] > 2047 THEN
coeffs[i] := 2047;
END;
IF coeffs[i] < -2048 THEN
coeffs[i] := -2048;
END;
INC(sum, coeffs[i]);
END;
MismatchControl(coeffs[63], sum);
END DequantizeIntraCoeffs2;
PROCEDURE MismatchControl(VAR coeffs63: LONGINT; sum: LONGINT);
BEGIN
IF (sum MOD 2) = 0 THEN
IF (coeffs63 MOD 2) = 1 THEN
DEC(coeffs63);
ELSE
INC(coeffs63);
END;
END;
END MismatchControl;
END Dequantizer;
Frame* = OBJECT
VAR
buffer*: PointerToArrayOfCHAR;
cbOffset*, crOffset*: LONGINT;
frameNr*: LONGINT;
picType*: LONGINT;
END Frame;
PicCodingExt* = OBJECT
VAR
dcPrecision*: LONGINT;
picStructure*: LONGINT;
topFieldFirst*: BOOLEAN;
framePredFrameDct*: BOOLEAN;
concealmentMV*: BOOLEAN;
qScaleType*: BOOLEAN;
intraVlcFormat*: BOOLEAN;
alternateScan*: BOOLEAN;
repeatFirstField*: BOOLEAN;
chroma420Type*: BOOLEAN;
progressiveFrame*: BOOLEAN;
PROCEDURE Dump*;
BEGIN
KernelLog.String("dc Precision: "); KernelLog.Int(dcPrecision, 0); KernelLog.Ln;
KernelLog.String("picture structure: ");
CASE picStructure OF
0: KernelLog.String("Reserved");
| 1: KernelLog.String("Top Field");
| 2: KernelLog.String("Bottom Field");
| 3: KernelLog.String("Frame");
END;
KernelLog.Ln;
KernelLog.String("top field first: "); IF topFieldFirst THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("frame pred frame dct: "); IF framePredFrameDct THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("concealment MV: "); IF concealmentMV THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("qScaleType: "); IF qScaleType THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("intraVlcFormat: "); IF intraVlcFormat THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("alternate scan: "); IF alternateScan THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("repeat first field: "); IF repeatFirstField THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("chroma 4:2:0 type: "); IF chroma420Type THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
KernelLog.String("progressiveFrame: "); IF progressiveFrame THEN KernelLog.String("TRUE") ELSE KernelLog.String("FALSE") END; KernelLog.Ln;
END Dump;
END PicCodingExt;
MotionVectorInfos* = OBJECT
VAR
fullPel*: ARRAY 2 OF ARRAY 2 OF BOOLEAN;
fCode*: ARRAY 2 OF ARRAY 2 OF LONGINT;
f*: ARRAY 2 OF ARRAY 2 OF LONGINT;
rSize*: ARRAY 2 OF ARRAY 2 OF LONGINT;
motionVerticalFieldSelect*: ARRAY 2 OF ARRAY 2 OF BOOLEAN;
motionCode*: ARRAY 2 OF ARRAY 2 OF ARRAY 2 OF LONGINT;
motionResidual*: ARRAY 2 OF ARRAY 2 OF ARRAY 2 OF LONGINT;
dmVector*: ARRAY 2 OF LONGINT;
mv*: ARRAY 2 OF ARRAY 2 OF ARRAY 2 OF LONGINT;
pmv*: ARRAY 2 OF ARRAY 2 OF ARRAY 2 OF LONGINT;
PROCEDURE Dump*(r, s, t: LONGINT);
BEGIN
KernelLog.String("Motion Vector Type: ");
IF s = 0 THEN
KernelLog.String("Forward ");
ELSE
KernelLog.String("Backward ");
END;
IF t = 0 THEN
KernelLog.String("Horizontal");
ELSE
KernelLog.String("Vertical");
END;
KernelLog.Ln;
KernelLog.String("fCode: "); KernelLog.Int(fCode[s][t], 0); KernelLog.Ln;
KernelLog.String("fullPel: "); IF fullPel[r][s] THEN KernelLog.String("TRUE"); ELSE KernelLog.String("FALSE"); END; KernelLog.Ln;
KernelLog.String("f: "); KernelLog.Int(f[r][s], 0); KernelLog.Ln;
KernelLog.String("rSize: "); KernelLog.Int(rSize[r][s], 0); KernelLog.Ln;
KernelLog.String("motionVerticalFieldSelect: "); IF motionVerticalFieldSelect[r][s] THEN KernelLog.String("TRUE"); ELSE KernelLog.String("FALSE"); END; KernelLog.Ln;
KernelLog.String("motionCode: "); KernelLog.Int(motionCode[r][s][t], 0); KernelLog.Ln;
KernelLog.String("motionResidual: "); KernelLog.Int(motionResidual[r][s][t], 0); KernelLog.Ln;
KernelLog.String("dmVector: "); KernelLog.Int(dmVector[t], 0); KernelLog.Ln;
END Dump;
END MotionVectorInfos;
IDCT* = OBJECT
PROCEDURE PerformIDCT*(block: PointerToArrayOfLONGINT );
VAR
i: LONGINT;
BEGIN
FOR i:= 0 TO 7 DO
IDCTRow( block, i * 8)
END;
FOR i:= 0 TO 7 DO
IDCTCol( block, i )
END;
END PerformIDCT;
PROCEDURE IDCTRow( blk: PointerToArrayOfLONGINT; baseIndex: LONGINT);
VAR
x0, x1, x2, x3, x4, x5, x6, x7, x8: LONGINT;
adr, tempAdr: LONGINT;
BEGIN
adr := SYSTEM.ADR( blk[baseIndex] );
x1 := SYSTEM.GET32( adr + 4*SYSTEM.SIZEOF(LONGINT) ) * 2048;
x2 := SYSTEM.GET32( adr + 6*SYSTEM.SIZEOF(LONGINT) );
x3 := SYSTEM.GET32( adr + 2*SYSTEM.SIZEOF(LONGINT) );
x4 := SYSTEM.GET32( adr + SYSTEM.SIZEOF(LONGINT) );
x5 := SYSTEM.GET32( adr + 7*SYSTEM.SIZEOF(LONGINT) );
x6 := SYSTEM.GET32( adr + 5*SYSTEM.SIZEOF(LONGINT) );
x7 := SYSTEM.GET32( adr + 3*SYSTEM.SIZEOF(LONGINT) );
IF ( x1 = 0 ) & ( x2 = 0 ) & ( x3 = 0 ) & ( x4 = 0 ) & ( x5 = 0 ) & ( x6 = 0 ) & ( x7 = 0 ) THEN
x0 := SYSTEM.GET32( adr ) * 8;
SYSTEM.PUT32( adr , x0 );
tempAdr := adr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
RETURN
END;
x0 := ( SYSTEM.GET32( adr ) * 2048 ) + 128;
x8 := W7 * ( x4 + x5 );
x4 := x8 + ( W1 - W7 ) * x4;
x5 := x8 - ( W1 + W7 ) * x5;
x8 := W3 * ( x6 + x7 );
x6 := x8 - ( W3 - W5 ) * x6;
x7 := x8 - ( W3 + W5 ) * x7;
x8 := x0 + x1;
x0 := x0 - x1;
x1 := W6 * ( x3 + x2 );
x2 := x1 - ( W2 + W6 ) * x2;
x3 := x1 + ( W2 - W6 ) * x3;
x1 := x4 + x6;
x4 := x4 - x6;
x6 := x5 + x7;
x5 := x5 - x7;
x7 := x8 + x3;
x8 := x8 - x3;
x3 := x0 + x2;
x0 := x0 - x2;
x2 := ( 181 * ( x4 + x5 ) + 128 ) DIV 256;
x4 := ( 181 * ( x4 - x5 ) + 128 ) DIV 256;
SYSTEM.PUT32( adr, ( x7 + x1 ) DIV 256 );
tempAdr := adr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x3 + x2 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x0 + x4 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x8 + x6 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x8 - x6 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x0 - x4 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x3 - x2 ) DIV 256 );
tempAdr := tempAdr + SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, ( x7 - x1 ) DIV 256 )
END IDCTRow;
PROCEDURE IDCTCol( blk: PointerToArrayOfLONGINT; baseIndex: LONGINT );
VAR
x0, x1, x2, x3, x4, x5, x6, x7, x8: LONGINT;
adr, tempAdr, sourceAdr: LONGINT;
BEGIN
adr := SYSTEM.ADR( blk[baseIndex] );
x1 := SYSTEM.GET32( adr + 32*SYSTEM.SIZEOF(LONGINT) ) * 256;
x2 := SYSTEM.GET32( adr + 48*SYSTEM.SIZEOF(LONGINT) );
x3 := SYSTEM.GET32( adr + 16*SYSTEM.SIZEOF(LONGINT) );
x4 := SYSTEM.GET32( adr + 8*SYSTEM.SIZEOF(LONGINT) );
x5 := SYSTEM.GET32( adr + 56*SYSTEM.SIZEOF(LONGINT) );
x6 := SYSTEM.GET32( adr + 40*SYSTEM.SIZEOF(LONGINT) );
x7 := SYSTEM.GET32( adr + 24*SYSTEM.SIZEOF(LONGINT) );
IF ( x1 = 0 ) & ( x2 = 0 ) & ( x3 = 0 ) & ( x4 = 0 ) & ( x5 = 0 ) & ( x6 = 0 ) & ( x7 = 0 ) THEN
x0 := IdctBorder[( ( SYSTEM.GET32( adr ) + 32 ) DIV 64 ) + 512];
SYSTEM.PUT32( adr , x0 );
tempAdr := adr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, x0 );
RETURN
END;
x0 := (SYSTEM.GET32( adr )* 256) + 8192;
x8 := W7 * ( x4 + x5 ) + 4;
x4 := ( x8 + ( W1 - W7 ) * x4 ) DIV 8;
x5 := ( x8 - ( W1 + W7) * x5 ) DIV 8;
x8 := W3 * ( x6 + x7 ) + 4;
x6 := ( x8 - ( W3 - W5 ) * x6 )DIV 8;
x7 := ( x8 - ( W3 + W5 ) * x7 ) DIV 8;
x8 := x0 + x1;
x0 := x0 - x1;
x1 := W6 * ( x3 + x2 ) + 4;
x2 := ( x1 - ( W2 + W6 ) * x2 ) DIV 8;
x3 := ( x1 + ( W2 - W6 ) * x3 ) DIV 8;
x1 := x4 + x6;
x4 := x4 - x6;
x6 := x5 + x7;
x5 := x5 - x7;
x7 := x8 + x3;
x8 := x8 - x3;
x3 := x0 + x2;
x0 := x0 - x2;
x2 := ( 181 * ( x4 + x5 ) + 128 ) DIV 256;
x4 := ( 181 * ( x4 - x5 ) + 128 ) DIV 256;
tempAdr := adr;
sourceAdr := SYSTEM.ADR(IdctBorder[512] );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x7 + x1 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x3 + x2 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x0 + x4 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x8 + x6 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x8 - x6 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x0 - x4 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x3 - x2 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) );
tempAdr := tempAdr + 8*SYSTEM.SIZEOF( LONGINT );
SYSTEM.PUT32( tempAdr, SYSTEM.GET32( ( ( ( x7 - x1 ) DIV 16384 )*SYSTEM.SIZEOF(LONGINT) ) + sourceAdr ) )
END IDCTCol;
END IDCT;
BitStream* = OBJECT
VAR
first: LONGINT;
last: LONGINT;
bitIndex: LONGINT;
buffer: ARRAY 8 OF CHAR;
bufAdr: LONGINT;
input: Codecs.DemuxStream;
eof: BOOLEAN;
bitsLeft: LONGINT;
len: LONGINT;
i: LONGINT;
PROCEDURE & Init*( r: Codecs.DemuxStream );
BEGIN
ASSERT(r # NIL);
first := 0;
last := -1;
bitIndex := 0;
bufAdr := SYSTEM.ADR(buffer[0]);
input := r;
eof := FALSE;
ReadLongintFromStream();
ReadLongintFromStream();
END Init;
PROCEDURE Reset*;
VAR
dummy, result: LONGINT;
BEGIN
input.SetPosX(Codecs.SeekByte, 0, dummy, result);
first := 0;
last := -1;
bitIndex := 0;
bufAdr := SYSTEM.ADR(buffer[0]);
eof := FALSE;
ReadLongintFromStream();
ReadLongintFromStream();
END Reset;
PROCEDURE ReadLongintFromStream;
VAR
read: LONGINT;
BEGIN
IF eof THEN RETURN END;
input.Bytes(buffer, first, 4, read);
IF (input.res = Streams.EOF) OR (read < 4) THEN
eof := TRUE;
bitsLeft := 32 + read*8;
END;
first := 4 - first;
END ReadLongintFromStream;
PROCEDURE ByteAlign*;
BEGIN
IF (bitIndex MOD 8) # 0 THEN
SkipBits(8 - (bitIndex MOD 8));
END;
END ByteAlign;
PROCEDURE IsAligned*(): BOOLEAN;
BEGIN
RETURN ((bitIndex MOD 8) = 0);
END IsAligned;
PROCEDURE ShowBits*(n: LONGINT): LONGINT;
VAR
nbit: LONGINT;
bufa, bufb: LONGINT;
temp: LONGINT;
BEGIN
IF eof & (bitsLeft < n) THEN
RETURN -1;
END;
nbit := (bitIndex + n) - 32;
IF nbit > 0 THEN
bufa := Machine.ChangeByteOrder(SYSTEM.GET32(bufAdr + first));
bufb := Machine.ChangeByteOrder(SYSTEM.GET32(bufAdr + 4 - first));
temp := SYSTEM.LSH(SYSTEM.LSH(bufa, bitIndex), nbit - bitIndex );
RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.LSH(bufb, nbit - 32)) + SYSTEM.VAL(SET, temp));
ELSE
bufa := Machine.ChangeByteOrder(SYSTEM.GET32(bufAdr + first));
RETURN SYSTEM.LSH(SYSTEM.LSH(bufa, bitIndex), n - 32);
END;
END ShowBits;
PROCEDURE ShowBuffer*;
BEGIN
KernelLog.Hex(ORD(buffer[0]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[1]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[2]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[3]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[4]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[5]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[6]), -1); KernelLog.String(" ");
KernelLog.Hex(ORD(buffer[7]), -1); KernelLog.String(" ");
KernelLog.String("first = "); KernelLog.Int(first, 0);
END ShowBuffer;
PROCEDURE GetBits*( n: LONGINT): LONGINT;
VAR
ret: LONGINT;
BEGIN
ret := ShowBits( n );
SkipBits( n );
RETURN ret
END GetBits;
PROCEDURE SkipBits*(n: LONGINT);
BEGIN
IF eof & (bitsLeft <= 0) THEN
RETURN;
END;
IF eof THEN
DEC(bitsLeft, n);
END;
INC(bitIndex, n);
IF bitIndex > 31 THEN
ReadLongintFromStream();
DEC(bitIndex, 32);
END;
END SkipBits;
PROCEDURE Pos*(): LONGINT;
BEGIN
RETURN input.Pos() - 8;
END Pos;
PROCEDURE SetPos*(pos: LONGINT);
VAR
dummy, result: LONGINT;
BEGIN
input.SetPosX(Codecs.SeekByte, pos, dummy, result);
first := 0;
last := -1;
bitIndex := 0;
bufAdr := SYSTEM.ADR(buffer[0]);
eof := FALSE;
ReadLongintFromStream();
ReadLongintFromStream();
END SetPos;
PROCEDURE HasMoreData*(): BOOLEAN;
BEGIN
RETURN ~(eof & (bitsLeft <= 0));
END HasMoreData;
END BitStream;
StreamReader* = OBJECT
VAR
stream: BitStream;
eof*: BOOLEAN;
PROCEDURE &init*(s: BitStream);
BEGIN
stream := s;
eof := FALSE;
END init;
PROCEDURE ReadMotionCode*(): LONGINT;
VAR
bits: LONGINT;
res: LONGINT;
BEGIN
IF eof THEN RETURN 0 END;
bits := stream.GetBits(1);
IF bits = 1 THEN
RETURN 0;
ELSIF bits < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
bits := stream.ShowBits(3);
IF bits < 0 THEN eof := TRUE; RETURN 0 END;
IF bits # 0 THEN
res := MPEGTables.MC4[bits][0];
stream.SkipBits(MPEGTables.MC4[bits][1]);
bits := stream.GetBits(1);
IF bits = 1 THEN
RETURN -res;
ELSIF bits < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
RETURN res;
END;
ELSE
stream.SkipBits(3);
bits := stream.ShowBits(3);
IF bits < 0 THEN eof := TRUE; RETURN 0 END;
IF bits >= 3 THEN
res := MPEGTables.MC7[bits][0];
stream.SkipBits(MPEGTables.MC7[bits][1]);
bits := stream.GetBits(1);
IF bits = 1 THEN
RETURN -res;
ELSIF bits < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
RETURN res;
END;
ELSE
stream.SkipBits(1);
bits := stream.ShowBits(5) - 12;
IF bits <= -12 THEN eof := TRUE; RETURN 0 END;
res := MPEGTables.MC10[bits][0];
stream.SkipBits(MPEGTables.MC10[bits][1]);
bits := stream.GetBits(1);
IF bits = 1 THEN
RETURN -res;
ELSIF bits < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
RETURN res;
END;
END;
END;
END;
END ReadMotionCode;
PROCEDURE ReadRunLevelCode*(c: PointerToArrayOfLONGINT; VAR cur: LONGINT; MPEG2: BOOLEAN): BOOLEAN;
VAR
run, length: LONGINT;
level: LONGINT;
index: LONGINT;
BEGIN
IF eof THEN RETURN TRUE END;
length := 0;
CASE stream.ShowBits(6) OF
0:
CASE stream.ShowBits(12) OF
1:
stream.SkipBits(12);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC17[index][0];
level := MPEGTables.RLC17[index][1];
length := 4;
| 2..3:
stream.SkipBits(11);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC16[index][0];
level := MPEGTables.RLC16[index][1];
length := 4;
| 4..7:
stream.SkipBits(10);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := 0;
level := 31-index;
length := 4;
| 8..15:
stream.SkipBits(9);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC14[index][0];
level := MPEGTables.RLC14[index][1];
length := 4;
| 16..31:
stream.SkipBits(8);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC13[index][0];
level := MPEGTables.RLC13[index][1];
length := 4;
| 32..63:
stream.SkipBits(7);
index := stream.ShowBits(3);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC11[index][0];
level := MPEGTables.RLC11[index][1];
length := 3;
ELSE
eof := TRUE;
RETURN TRUE;
END;
| 1:
stream.SkipBits(6);
run := stream.GetBits(6);
IF run < 0 THEN eof := TRUE; RETURN TRUE END;
IF ~MPEG2 THEN
index := stream.GetBits(8);
IF index = 0 THEN
level := stream.GetBits(8);
IF level < 0 THEN eof := TRUE; RETURN TRUE END;
ELSIF index = 128 THEN
level := -stream.GetBits(8);
IF level > 0 THEN eof := TRUE; RETURN TRUE END;
ELSIF index < 0 THEN
eof := TRUE;
RETURN TRUE;
ELSE
IF index > 127 THEN
level := -256+index;
ELSE
level := index;
END;
END;
ELSE
level := stream.GetBits(12);
ASSERT(level # 0);
IF level > 2047 THEN
level := level - 4095;
ELSIF level < 0 THEN
eof := TRUE;
RETURN TRUE;
END;
END;
INC(cur, run);
c[MPEGTables.ZZN[cur]] := level;
INC(cur);
RETURN FALSE;
| 2..7:
index := stream.ShowBits(7) - 4;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC8[index][0];
level := MPEGTables.RLC8[index][1];
length := MPEGTables.RLC8[index][2];
| 8..9:
index := stream.ShowBits(8) - 32;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC9[index][0];
level := MPEGTables.RLC9[index][1];
length := 8;
| 10..31:
index := stream.ShowBits(5) - 5;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC6[index][0];
level := MPEGTables.RLC6[index][1];
length := MPEGTables.RLC6[index][2];
| 32..47:
stream.SkipBits(2);
RETURN TRUE;
| 48..63:
run := 0;
level := 1;
length := 2;
ELSE
eof := TRUE;
RETURN TRUE;
END;
stream.SkipBits(length);
index := stream.GetBits(1);
IF index = 1 THEN
level := -level;
ELSIF index < 0 THEN
eof := TRUE;
RETURN TRUE;
END;
INC(cur, run);
c[MPEGTables.ZZN[cur]] := level;
INC(cur);
RETURN FALSE;
END ReadRunLevelCode;
PROCEDURE ReadRunLevelCode2*(c: PointerToArrayOfLONGINT; VAR cur: LONGINT): BOOLEAN;
VAR
run, length: LONGINT;
level: LONGINT;
index: LONGINT;
BEGIN
IF eof THEN RETURN TRUE END;
length := 0;
CASE stream.ShowBits(6) OF
0:
CASE stream.ShowBits(12) OF
1:
stream.SkipBits(12);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC17[index][0];
level := MPEGTables.RLC17[index][1];
length := 4;
| 2..3:
stream.SkipBits(11);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC16[index][0];
level := MPEGTables.RLC16[index][1];
length := 4;
| 4..7:
stream.SkipBits(10);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := 0;
level := 31-index;
length := 4;
| 8..15:
stream.SkipBits(9);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC14[index][0];
level := MPEGTables.RLC14[index][1];
length := 4;
| 16..31:
stream.SkipBits(8);
index := stream.ShowBits(4);
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC13[index][0];
level := MPEGTables.RLC13[index][1];
length := 4;
| 32..39:
run := 5;
level := 2;
length := 9;
| 40..47:
run := 14;
level := 1;
length := 9;
| 48..51:
run := 2;
level := 4;
length := 10;
| 52..55:
run := 16;
level := 1;
length := 10;
| 56..63:
run := 15;
level := 1;
length := 9;
ELSE
eof := TRUE;
RETURN TRUE;
END;
| 1:
stream.SkipBits(6);
run := stream.GetBits(6);
IF run < 0 THEN eof := TRUE; RETURN TRUE END;
level := stream.GetBits(12);
ASSERT(level # 0);
IF level > 2047 THEN
level := level - 4095;
ELSIF level < 0 THEN
eof := TRUE;
RETURN TRUE;
END;
INC(cur, run);
c[MPEGTables.ZZN[cur]] := level;
INC(cur);
RETURN FALSE;
| 2..7:
index := stream.ShowBits(7) - 4;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC8_2[index][0];
level := MPEGTables.RLC8_2[index][1];
length := MPEGTables.RLC8_2[index][2];
| 8..9:
index := stream.ShowBits(8) - 32;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC9_2[index][0];
level := MPEGTables.RLC9_2[index][1];
length := 8;
| 10..11:
run := 2;
level := 1;
length := 5;
| 12..13:
run := 1;
level := 2;
length := 5;
| 14..15:
run := 3;
level := 1;
length := 5;
| 16..23:
run := 1;
level := 1;
length := 3;
| 24..27:
stream.SkipBits(4);
RETURN TRUE;
| 28..31:
run := 0;
level := 3;
length := 4;
| 32..47:
run := 0;
level := 1;
length := 2;
| 48..55:
run := 0;
level := 2;
length := 3;
| 56..57:
run := 0;
level := 4;
length := 5;
| 58..59:
run := 0;
level := 6;
length := 5;
| 60..63:
index := stream.ShowBits(8) - 240;
IF index < 0 THEN eof := TRUE; RETURN TRUE END;
run := MPEGTables.RLC9_2_2[index][0];
level := MPEGTables.RLC9_2_2[index][1];
length := MPEGTables.RLC9_2_2[index][2];
ELSE
eof := TRUE;
RETURN TRUE;
END;
stream.SkipBits(length);
index := stream.GetBits(1);
IF index = 1 THEN
level := -level;
ELSIF index < 0 THEN
eof := TRUE;
RETURN TRUE;
END;
INC(cur, run);
c[MPEGTables.ZZN[cur]] := level;
INC(cur);
RETURN FALSE;
END ReadRunLevelCode2;
PROCEDURE ReadAddressIncrement*():LONGINT;
VAR
tmp: LONGINT;
BEGIN
IF eof THEN RETURN 0 END;
CASE stream.ShowBits(4) OF
0:
stream.SkipBits(4);
CASE stream.ShowBits(4) OF
0:
RETURN -1;
| 1:
stream.SkipBits(4);
tmp := stream.GetBits(3);
IF tmp = 0 THEN
RETURN -2;
ELSIF tmp = 7 THEN
RETURN -3;
ELSIF tmp < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
RETURN -1;
END;
| 2:
RETURN -1;
| 3..5:
IF stream.ShowBits(6) >= 18 THEN
tmp := stream.GetBits(6);
RETURN (39-tmp);
ELSIF stream.ShowBits(6) < 0 THEN
eof := TRUE;
RETURN 0;
ELSE
tmp := stream.GetBits(7);
RETURN (57-tmp);
END;
| 6..11:
tmp := stream.GetBits(4);
IF tmp < 0 THEN eof := TRUE; RETURN 0 END;
RETURN (21-tmp);
| 12..15:
tmp := stream.GetBits(3);
IF tmp < 0 THEN eof := TRUE; RETURN 0 END;
RETURN (15-tmp);
ELSE
eof := TRUE;
RETURN 0;
END;
| 1:
tmp := stream.GetBits(5);
IF tmp < 0 THEN eof := TRUE; RETURN 0 END;
RETURN (9-tmp);
| 2:
stream.SkipBits(4);
RETURN 5;
| 3:
stream.SkipBits(4);
RETURN 4;
| 4,5:
stream.SkipBits(3);
RETURN 3;
| 6,7:
stream.SkipBits(3);
RETURN 2;
| 8..15:
stream.SkipBits(1);
RETURN 1;
ELSE
eof := TRUE;
RETURN 0;
END;
END ReadAddressIncrement;
PROCEDURE ReadMacroBlockType*(type: LONGINT; VAR intra, pattern, back, forw, quant: BOOLEAN): BOOLEAN;
VAR
tmp: LONGINT;
BEGIN
IF eof THEN RETURN FALSE END;
intra := FALSE;
pattern := FALSE;
back := FALSE;
forw := FALSE;
quant := FALSE;
CASE type OF
1:
intra := TRUE;
tmp := stream.GetBits(1);
IF tmp = 1 THEN
RETURN TRUE;
ELSIF tmp < 0 THEN
eof := TRUE;
RETURN FALSE;
ELSE
tmp := stream.GetBits(1);
IF tmp = 1 THEN
quant := TRUE;
RETURN TRUE;
ELSIF tmp < 0 THEN
eof := TRUE;
RETURN FALSE;
ELSE
RETURN FALSE;
END;
END;
| 2:
CASE stream.ShowBits(3) OF
0:
stream.SkipBits(3);
CASE stream.ShowBits(3) OF
0:
RETURN FALSE;
| 1:
stream.SkipBits(3);
intra := TRUE;
quant := TRUE;
RETURN TRUE;
| 2,3:
stream.SkipBits(2);
pattern := TRUE;
quant := TRUE;
RETURN TRUE;
| 4,5:
stream.SkipBits(2);
pattern := TRUE;
forw := TRUE;
quant := TRUE;
RETURN TRUE;
| 6,7:
stream.SkipBits(2);
intra := TRUE;
RETURN TRUE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
| 1:
stream.SkipBits(3);
forw := TRUE;
RETURN TRUE;
| 2,3:
stream.SkipBits(2);
pattern := TRUE;
RETURN TRUE;
| 4..7:
stream.SkipBits(1);
pattern := TRUE;
forw := TRUE;
RETURN TRUE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
| 3:
CASE stream.ShowBits(4) OF
0:
stream.SkipBits(4);
tmp := stream.GetBits(2);
CASE tmp OF
0:
RETURN FALSE;
| 1:
intra := TRUE;
quant := TRUE;
RETURN TRUE;
| 2:
pattern := TRUE;
back := TRUE;
quant := TRUE;
RETURN TRUE;
| 3:
pattern := TRUE;
forw := TRUE;
quant := TRUE;
RETURN TRUE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
| 1:
stream.SkipBits(4);
tmp := stream.GetBits(1);
IF tmp = 0 THEN
pattern := TRUE;
forw := TRUE;
back := TRUE;
quant := TRUE;
RETURN TRUE;
ELSIF tmp < 0 THEN
eof := TRUE;
RETURN FALSE;
ELSE
intra := TRUE;
RETURN TRUE;
END;
| 2:
stream.SkipBits(4);
forw := TRUE;
RETURN TRUE;
| 3:
stream.SkipBits(4);
pattern := TRUE;
forw := TRUE;
RETURN TRUE;
| 4,5:
stream.SkipBits(3);
back := TRUE;
RETURN TRUE;
| 6,7:
stream.SkipBits(3);
pattern := TRUE;
back := TRUE;
RETURN TRUE;
| 8..11:
stream.SkipBits(2);
forw := TRUE;
back := TRUE;
RETURN TRUE;
| 12..15:
stream.SkipBits(2);
pattern := TRUE;
forw := TRUE;
back := TRUE;
RETURN TRUE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
| 4:
tmp := stream.GetBits(1);
IF tmp = 1 THEN
intra := TRUE;
RETURN TRUE;
ELSIF tmp < 0 THEN
eof := TRUE;
RETURN FALSE;
ELSE
RETURN FALSE;
END;
ELSE
RETURN FALSE;
END;
END ReadMacroBlockType;
PROCEDURE ReadSequenceExtension*(
VAR MainProfile: BOOLEAN;
VAR LevelID: LONGINT;
VAR ChromaFormat: LONGINT;
VAR videoWidth, videoHeight: LONGINT): BOOLEAN;
VAR
tmp: LONGINT;
BEGIN
IF eof THEN RETURN FALSE END;
IF stream.ShowBits(1) # 0 THEN
IF stream.ShowBits(1) < 0 THEN
eof := TRUE;
RETURN FALSE;
ELSE
KernelLog.String("Profile/Level not supported"); KernelLog.Ln;
RETURN FALSE;
END;
ELSE
stream.SkipBits(1);
END;
CASE stream.ShowBits(3) OF
0..3, 6, 7:
KernelLog.String("Profile not supported"); KernelLog.Ln;
RETURN FALSE;
| 4:
MainProfile := TRUE;
| 5:
MainProfile := FALSE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
stream.SkipBits(3);
CASE stream.ShowBits(4) OF
0..3, 5, 7, 9, 11..16:
KernelLog.String("Level not supported"); KernelLog.Ln;
RETURN FALSE;
| 4:
IF MainProfile THEN
LevelID := 4;
ELSE
KernelLog.String("Level not supported"); KernelLog.Ln;
RETURN FALSE;
END;
| 6:
IF MainProfile THEN
LevelID := 3;
ELSE
KernelLog.String("Level not supported"); KernelLog.Ln;
RETURN FALSE;
END;
| 8:
LevelID := 2;
| 10:
LevelID := 1;
ELSE
eof := TRUE;
RETURN FALSE;
END;
stream.SkipBits(4);
stream.SkipBits(1);
CASE stream.ShowBits(2) OF
0:
KernelLog.String("Illegal chroma format"); KernelLog.Ln;
| 1:
ChromaFormat := 1;
| 2:
KernelLog.String("4:2:2 chroma format is not supported"); KernelLog.Ln;
RETURN FALSE;
| 3:
KernelLog.String("4:4:4: chroma format is not supported"); KernelLog.Ln;
RETURN FALSE;
ELSE
eof := TRUE;
RETURN FALSE;
END;
stream.SkipBits(2);
tmp := stream.GetBits(2);
IF tmp < 0 THEN RETURN FALSE END;
videoWidth := tmp * 4096 + videoWidth;
tmp := stream.GetBits(2);
IF tmp < 0 THEN RETURN FALSE END;
videoHeight := tmp * 4096 + videoHeight;
stream.SkipBits(29);
RETURN TRUE;
END ReadSequenceExtension;
PROCEDURE ReadSequenceDisplayExtension*(): BOOLEAN;
BEGIN
IF eof THEN RETURN FALSE END;
stream.SkipBits(7);
IF stream.ShowBits(1) = 1 THEN
stream.SkipBits(24);
END;
stream.SkipBits(30);
RETURN TRUE;
END ReadSequenceDisplayExtension;
PROCEDURE ReadQuantMatrixExtension*(): BOOLEAN;
BEGIN
IF eof THEN RETURN FALSE END;
END ReadQuantMatrixExtension;
PROCEDURE ReadCopyrightExtension*(): BOOLEAN;
BEGIN
IF eof THEN RETURN FALSE END;
END ReadCopyrightExtension;
PROCEDURE ReadPictureDisplayExtension*(): BOOLEAN;
BEGIN
IF eof THEN RETURN FALSE END;
END ReadPictureDisplayExtension;
PROCEDURE ReadPictureCodingExtension*(VAR pce: PicCodingExt; VAR mvi: MotionVectorInfos): BOOLEAN;
BEGIN
IF eof THEN RETURN FALSE END;
mvi.fCode[0][0] := stream.GetBits(4);
mvi.fCode[0][1] := stream.GetBits(4);
mvi.fCode[1][0] := stream.GetBits(4);
mvi.fCode[1][1] := stream.GetBits(4);
pce.dcPrecision := stream.GetBits(2);
pce.picStructure := stream.GetBits(2);
pce.topFieldFirst := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.framePredFrameDct := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.concealmentMV := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.qScaleType := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.intraVlcFormat := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.alternateScan := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.repeatFirstField := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.chroma420Type := stream.ShowBits(1) = 1; stream.SkipBits(1);
pce.progressiveFrame := stream.ShowBits(1) = 1; stream.SkipBits(1);
IF stream.ShowBits(1) = 1 THEN
stream.SkipBits(21);
ELSE
stream.SkipBits(1);
END;
IF stream.ShowBits(1) < 0 THEN
eof := TRUE;
RETURN FALSE;
END;
RETURN TRUE;
END ReadPictureCodingExtension;
PROCEDURE ReadQuantizerMatrix*(matrix: PointerToArrayOfLONGINT);
VAR
i, j: LONGINT;
tmp: LONGINT;
zzQM: ARRAY 64 OF LONGINT;
BEGIN
IF eof THEN RETURN END;
FOR i := 0 TO 63 DO
tmp := stream.GetBits(8);
IF tmp < 0 THEN
eof := TRUE;
RETURN;
ELSE
zzQM[i] := tmp;
END;
END;
FOR i := 0 TO 7 DO
FOR j := 0 TO 7 DO
matrix[i*8+j] := zzQM[MPEGTables.ZZ[i][j]];
END;
END;
END ReadQuantizerMatrix;
PROCEDURE ReadMotionVectors*(s: LONGINT; VAR mvi: MotionVectorInfos; frameMotionType: LONGINT);
BEGIN
IF eof THEN RETURN END;
IF frameMotionType # 1 THEN
IF frameMotionType # 2 THEN
mvi.motionVerticalFieldSelect[0][s] := (stream.GetBits(1) = 1);
END;
ReadMotionVectorsHelper(0, s, mvi);
ELSE
mvi.motionVerticalFieldSelect[0][s] := (stream.GetBits(1) = 1);
ReadMotionVectorsHelper(0, s, mvi);
mvi.motionVerticalFieldSelect[1][s] := (stream.GetBits(1) = 1);
ReadMotionVectorsHelper(1, s, mvi);
END;
IF stream.ShowBits(1) < 0 THEN
eof := TRUE;
END;
END ReadMotionVectors;
PROCEDURE ReadMotionVectorsHelper(r, s: LONGINT; VAR mvi: MotionVectorInfos);
BEGIN
IF eof THEN RETURN END;
mvi.motionCode[r][s][0] := ReadMotionCode();
IF (mvi.fCode[s][0] # 1) & (mvi.motionCode[r][s][0] # 0) THEN
mvi.motionResidual[r][s][0] := stream.GetBits(mvi.fCode[s][0] - 1);
END;
IF FALSE THEN
CASE stream.ShowBits(2) OF
0,1: mvi.dmVector[0] := 0;
stream.SkipBits(1);
| 2: mvi.dmVector[0] := 1;
stream.SkipBits(2);
| 3: mvi.dmVector[0] := -1;
stream.SkipBits(2);
END;
END;
mvi.motionCode[r][s][1] := ReadMotionCode();
IF (mvi.fCode[s][1] # 1) & (mvi.motionCode[r][s][1] # 0) THEN
mvi.motionResidual[r][s][1] := stream.GetBits(mvi.fCode[s][1] - 1);
END;
IF FALSE THEN
CASE stream.ShowBits(2) OF
0,1: mvi.dmVector[1] := 0;
stream.SkipBits(1);
| 2: mvi.dmVector[1] := 1;
stream.SkipBits(2);
| 3: mvi.dmVector[1] := -1;
stream.SkipBits(2);
END;
END;
IF stream.ShowBits(1) < 0 THEN
eof := TRUE;
END;
END ReadMotionVectorsHelper;
END StreamReader;
TYPE MMXConsts = POINTER TO MMXConstsDesc;
TYPE MMXConstsDesc = RECORD
mmwMultY, mmwMultUG, mmwMultUB, mmwMultVR, mmwMultVG: HUGEINT;
mmb10, mmw0080, mmw00ff, mmwCutRed, mmwCutGreen, mmwCutBlue: HUGEINT;
mask5, mask6, maskBlue: HUGEINT;
END;
TYPE ColorSpace* = OBJECT
VAR
mmxConsts: MMXConsts;
PROCEDURE &Init*;
BEGIN
NEW( mmxConsts );
mmxConsts.mmwMultY := 2568256825682568H;
mmxConsts.mmwMultUG := 0F36EF36EF36EF36EH;
mmxConsts.mmwMultUB := 40CF40CF40CF40CFH;
mmxConsts.mmwMultVR := 3343334333433343H;
mmxConsts.mmwMultVG := 0E5E2E5E2E5E2E5E2H;
mmxConsts.mmb10 := 1010101010101010H;
mmxConsts.mmw0080 := 0080008000800080H;
mmxConsts.mmw00ff := 00FF00FF00FF00FFH;
mmxConsts.mmwCutRed := 7C007C007C007C00H;
mmxConsts.mmwCutGreen := 03E003E003E003E0H;
mmxConsts.mmwCutBlue := 001F001F001F001FH;
mmxConsts.mask5 := 0F8F8F8F8F8F8F8F8H;
mmxConsts.mask6 := 0FCFCFCFCFCFCFCFCH;
mmxConsts.maskBlue := 1F1F1F1F1F1F1F1FH;
END Init;
PROCEDURE Convert*(
src: PointerToArrayOfCHAR;
srcYBaseOffset: LONGINT;
yStride: LONGINT;
srcUBaseOffset, srcVBaseOffset,uvStride: LONGINT;
img: Raster.Image;
width, height, dstStride: LONGINT );
BEGIN
IF img.fmt.code = Raster.BGR888.code THEN
ConvertYUVToRGB888( src, srcYBaseOffset, yStride, srcUBaseOffset, srcVBaseOffset, uvStride, img, width, height,
dstStride );
ELSIF img.fmt.code = Raster.BGR565.code THEN
IF EnableMMX THEN
ConvertYUVToRGB565MMX( src, srcYBaseOffset, yStride, srcUBaseOffset, srcVBaseOffset, uvStride, img, width, height,
dstStride );
ELSE
ConvertYUVToRGB565( src, srcYBaseOffset, yStride, srcUBaseOffset, srcVBaseOffset, uvStride, img, width, height,
dstStride );
END;
END;
END Convert;
PROCEDURE ConvertYUVToRGB565MMX(
puc: PointerToArrayOfCHAR;
pucYBaseOffset: LONGINT;
strideY: LONGINT;
pucUBaseOffset, pucVBaseOffset, strideUV: LONGINT;
pucOut: Raster.Image;
widthY, heightY, strideOut: LONGINT );
VAR
y, horizCount: LONGINT;
pusOut: LONGINT;
BEGIN
strideOut := widthY*2;
IF heightY < 0 THEN
heightY := -heightY;
pucYBaseOffset := pucYBaseOffset + ( heightY - 1 ) * strideY ;
pucUBaseOffset := pucUBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
pucVBaseOffset := pucVBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
strideY := -strideY;
strideUV := -strideUV;
END;
pusOut := pucOut.adr;
pucYBaseOffset := SYSTEM.ADR( puc[0] )+ pucYBaseOffset;
pucUBaseOffset := SYSTEM.ADR ( puc[0] ) + pucUBaseOffset;
pucVBaseOffset := SYSTEM.ADR( puc[0] ) + pucVBaseOffset;
horizCount := -(widthY DIV 8);
FOR y := 0 TO heightY-1 DO
ScanLine565MMX(horizCount, pucVBaseOffset, pucUBaseOffset, pucYBaseOffset, pusOut,
SYSTEM.ADR( mmxConsts.mmwMultY ) );
pucYBaseOffset := pucYBaseOffset + strideY;
IF ( y MOD 2 ) > 0 THEN
pucUBaseOffset := pucUBaseOffset + strideUV;
pucVBaseOffset := pucVBaseOffset + strideUV
END;
pusOut := pusOut + strideOut;
END;
END ConvertYUVToRGB565MMX;
PROCEDURE ScanLine565MMX(horizCount, pucV, pucU, pucY, pucOut: LONGINT; mmxConsts: LONGINT);
CODE { SYSTEM.MMX, SYSTEM.PentiumPro }
MOV EAX, [EBP+pucOut]
MOV EBX, [EBP+pucY]
MOV ECX, [EBP+pucU]
MOV EDX, [EBP+pucV]
MOV EDI, [EBP+horizCount]
MOV ESI, [EBP+mmxConsts]
horizLoop:
; load data
MOVD MMX2, [ECX] ; mm2 = ________u3u2u1u0
MOVD MMX3, [EDX] ; mm3 = ________v3v2v1v0
MOVQ MMX0, [EBX] ; mm0 = y7y6y5y4y3y2y1y0
PXOR MMX7, MMX7 ; zero mm7
; convert chroma part
PUNPCKLBW MMX2, MMX7 ; MMX2 = __U3__U2__U1__U0
PUNPCKLBW MMX3, MMX7 ; MMX3 = __V3__V2__V1__V0
; PSUBW MMX2, mmw0080 ; MMX2 -= 128
PSUBW MMX2, [ESI+48] ; MMX2 -= 128
; PSUBW MMX3, mmw0080 ; MMX3 -= 128
PSUBW MMX3, [ESI+48] ; MMX3 -= 128
PSLLW MMX2, 3 ; MMX2 *= 8
PSLLW MMX3, 3 ; MMX3 *= 8
MOVQ MMX4, MMX2 ; MMX4 = MMX2 = U
MOVQ MMX5, MMX3 ; MMX5 = MMX3 = V
; PMULHW MMX2, mmwMultUG ; MMX2 *= U GREEN COEFF
; PMULHW MMX3, mmwMultVG ; MMX3 *= V GREEN COEFF
; PMULHW MMX4, mmwMultUB ; MMX4 = BLUE CHROMA
; PMULHW MMX5, mmwMultVR ; MMX5 = RED CHROMA
PMULHW MMX2, [ESI+8] ; MMX2 *= U GREEN COEFF
PMULHW MMX3, [ESI+32] ; MMX3 *= V GREEN COEFF
PMULHW MMX4, [ESI+16] ; MMX4 = BLUE CHROMA
PMULHW MMX5, [ESI+24] ; MMX5 = RED CHROMA
PADDSW MMX2, MMX3 ; MMX2 = GREEN CHROMA
; convert luma part
; PSUBUSB MMX0, mmb10 ; MMX0 -= 16
; MOVQ MMX1, mmw00ff
PSUBUSB MMX0, [ESI+40] ; MMX0 -= 16
MOVQ MMX6, [ESI+56] ;
MOVQ MMX1, MMX0
PSRLW MMX0, 8 ; MMX0 = __Y7__Y5__Y3__Y1 LUMA ODD
PAND MMX1, MMX6 ; MMX1 = __Y6__Y4__Y2__Y0 LUMA EVEN
PSLLW MMX0, 3 ; MMX0 *= 8
PSLLW MMX1, 3 ; MMX1 *= 8
; PMULHW MMX0, mmwMultY ; MMX0 LUMA ODD *= LUMA COEFF
; PMULHW MMX1, mmwMultY ; MMX1 LUMA EVEN *= LUMA COEFF
PMULHW MMX0, [ESI] ; MMX0 LUMA ODD *= LUMA COEFF
PMULHW MMX1, [ESI] ; MMX1 LUMA EVEN *= LUMA COEFF
; complete the matrix calc with the additions
MOVQ MMX3, MMX4 ; COPY BLUE CHROMA
MOVQ MMX6, MMX5 ; COPY RED CHROMA
MOVQ MMX7, MMX2 ; COPY GREEN CHROMA
PADDSW MMX3, MMX0 ; MMX3 = LUMA ODD + BLUE CHROMA
PADDSW MMX4, MMX1 ; MMX4 = LUMA EVEN + BLUE CHROMA
PADDSW MMX6, MMX0 ; MMX6 = LUMA ODD + RED CHROMA
PADDSW MMX5, MMX1 ; MMX5 = LUMA EVEN + RED CHROMA
PADDSW MMX7, MMX0 ; MMX7 = LUMA ODD + GREEN CHROMA
PADDSW MMX2, MMX1 ; MMX2 = LUMA EVEN + GREEN CHROMA
; clipping
PACKUSWB MMX3, MMX3
PACKUSWB MMX4, MMX4
PACKUSWB MMX6, MMX6
PACKUSWB MMX5, MMX5
PACKUSWB MMX7, MMX7
PACKUSWB MMX2, MMX2
; interleave odd and even parts
PUNPCKLBW MMX4, MMX3 ; MMX4 = B7B6B5B4B3B2B1B0 BLUE
PUNPCKLBW MMX5, MMX6 ; MMX5 = R7R6R5R4R3R2R1R0 RED
PUNPCKLBW MMX2, MMX7 ; MMX2 = G7G6G5G4G3G2G1G0 GREEN
; mask not needed bits (using 555)
; PAND MMX4, mask5
; PAND MMX5, mask5
; PAND MMX2, mask5
PAND MMX4, [ESI+88]
PAND MMX5, [ESI+88]
PAND MMX2, [ESI+96]
; mix colors and write
PSRLW MMX4, 3 ; MMX4 = RED SHIFTED
; PAND MMX4, maskBlue ; MASK THE BLUE AGAIN
PAND MMX4, [ESI+104] ; MASK THE BLUE AGAIN
PXOR MMX7, MMX7 ; ZERO MMX7
MOVQ MMX1, MMX5 ; MMX1 = COPY BLUE
MOVQ MMX3, MMX4 ; MMX3 = COPY RED
MOVQ MMX6, MMX2 ; MMX6 = COPY GREEN
PUNPCKHBW MMX1, MMX7
PUNPCKHBW MMX3, MMX7
PUNPCKHBW MMX6, MMX7
PSLLW MMX6, 3 ; SHIFT GREEN
PSLLW MMX1, 8 ; SHIFT BLUE
POR MMX6, MMX3
POR MMX6, MMX1
MOVQ [EAX+8], MMX6
PUNPCKLBW MMX2, MMX7 ; MMX2 = __G3__G2__G1__G0 ALREADY MASKED
PUNPCKLBW MMX4, MMX7
PUNPCKLBW MMX5, MMX7
PSLLW MMX2, 3 ; SHIFT GREEN
PSLLW MMX5, 8 ; SHIFT BLUE
POR MMX2, MMX4
POR MMX2, MMX5
MOVQ [EAX], MMX2
ADD EBX, 8 ; PUCY += 8;
ADD ECX, 4 ; PUCU += 4;
ADD EDX, 4 ; PUCV += 4;
ADD EAX, 16 ; PUCOUT += 16 // WROTE 16 BYTES
INC EDI
JNE horizLoop
EMMS
END ScanLine565MMX;
PROCEDURE ConvertYUVToRGB565(
puc: PointerToArrayOfCHAR;
pucYBaseOffset: LONGINT;
strideY: LONGINT;
pucUBaseOffset, pucVBaseOffset, strideUV: LONGINT;
pucOut: Raster.Image;
widthY, heightY, strideOut: LONGINT );
VAR
xCount, yCount, strideDiff: LONGINT;
pusOut: LONGINT;
r, g, b: LONGINT;
y, u, v: LONGINT;
BEGIN
strideDiff := (strideOut - widthY)*SYSTEM.SIZEOF(INTEGER);
IF heightY < 0 THEN
heightY := -heightY;
pucYBaseOffset := pucYBaseOffset + ( heightY - 1 ) * strideY ;
pucUBaseOffset := pucUBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
pucVBaseOffset := pucVBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
strideY := -strideY;
strideUV := -strideUV;
END;
pusOut := pucOut.adr;
pucYBaseOffset := SYSTEM.ADR( puc[0] )+ pucYBaseOffset;
pucUBaseOffset := SYSTEM.ADR ( puc[0] ) + pucUBaseOffset;
pucVBaseOffset := SYSTEM.ADR( puc[0] ) + pucVBaseOffset;
FOR yCount := 0 TO heightY - 1 DO
FOR xCount := 0 TO widthY - 1 DO
y := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucYBaseOffset + xCount ) ) ) - 16;
u := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucUBaseOffset + ( xCount DIV 2 ) ) ) ) - 128;
v := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucVBaseOffset + ( xCount DIV 2 ) ) ) ) - 128;
r := ( 2568H*y + 3343H*u ) DIV 2000H;
g := ( 2568H*y - 0C92H*v - 1A1EH*u ) DIV 2000H;
b := ( 2568H*y + 40CFH*v ) DIV 2000H;
IF r > 255 THEN r := 255; ELSIF r < 0 THEN r := 0 END;
IF g > 255 THEN g := 255; ELSIF g < 0 THEN g := 0 END;
IF b > 255 THEN b := 255; ELSIF b < 0 THEN b := 0 END;
SYSTEM.PUT16( pusOut, SYSTEM.VAL( INTEGER, SYSTEM.VAL( SET, r DIV 8 ) + SYSTEM.VAL( SET, ( g DIV 4 ) * 32 ) +
SYSTEM.VAL( SET, (b DIV 8 ) * 2048 ) ) );
pusOut := pusOut + SYSTEM.SIZEOF( INTEGER );
END;
pucYBaseOffset := pucYBaseOffset + strideY;
IF yCount MOD 2 > 0 THEN
pucUBaseOffset := pucUBaseOffset + strideUV;
pucVBaseOffset := pucVBaseOffset + strideUV
END;
pusOut := pusOut + strideDiff;
END;
END ConvertYUVToRGB565;
PROCEDURE ConvertYUVToRGB888(
puc: PointerToArrayOfCHAR;
pucYBaseOffset: LONGINT;
strideY: LONGINT;
pucUBaseOffset, pucVBaseOffset, strideUV: LONGINT;
pucOut: Raster.Image;
widthY, heightY, strideOut: LONGINT );
VAR
xCount, yCount, strideDiff: LONGINT;
pusOut: LONGINT;
r, g, b: LONGINT;
y, u, v: LONGINT;
BEGIN
strideDiff := (strideOut - widthY)*3;
IF heightY < 0 THEN
heightY := -heightY;
pucYBaseOffset := pucYBaseOffset + ( heightY - 1 ) * strideY ;
pucUBaseOffset := pucUBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
pucVBaseOffset := pucVBaseOffset + ( heightY DIV 2 - 1 ) * strideUV;
strideY := -strideY;
strideUV := -strideUV;
END;
pusOut := pucOut.adr;
pucYBaseOffset := SYSTEM.ADR( puc[0] )+ pucYBaseOffset;
pucUBaseOffset := SYSTEM.ADR ( puc[0] ) + pucUBaseOffset;
pucVBaseOffset := SYSTEM.ADR( puc[0] ) + pucVBaseOffset;
FOR yCount := 0 TO heightY - 1 DO
FOR xCount := 0 TO widthY - 1 DO
y := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucYBaseOffset + xCount ) ) ) - 16;
u := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucUBaseOffset + ( xCount DIV 2 ) ) ) ) - 128;
v := ORD( SYSTEM.VAL( CHAR, SYSTEM.GET8( pucVBaseOffset + ( xCount DIV 2 ) ) ) ) - 128;
r := ( 2568H*y + 3343H*u ) DIV 2000H;
g := ( 2568H*y - 0C92H*v - 1A1EH*u ) DIV 2000H;
b := ( 2568H*y + 40CFH*v ) DIV 2000H;
IF r > 255 THEN r := 255; ELSIF r < 0 THEN r := 0 END;
IF g > 255 THEN g := 255; ELSIF g < 0 THEN g := 0 END;
IF b > 255 THEN b := 255; ELSIF b < 0 THEN b := 0 END;
SYSTEM.PUT8( pusOut, r );
INC( pusOut );
SYSTEM.PUT8( pusOut, g );
INC( pusOut );
SYSTEM.PUT8( pusOut, b );
INC( pusOut );
END;
pucYBaseOffset := pucYBaseOffset + strideY;
IF yCount MOD 2 > 0 THEN
pucUBaseOffset := pucUBaseOffset + strideUV;
pucVBaseOffset := pucVBaseOffset + strideUV;
END;
pusOut := pusOut + strideDiff;
END;
END ConvertYUVToRGB888;
END ColorSpace;
BlockActions* = OBJECT
PROCEDURE ClearBlock*(dest: PointerToArrayOfCHAR; destOffs, incr: LONGINT);
VAR
d: LONGINT;
i: LONGINT;
BEGIN
d := SYSTEM.ADR(dest[destOffs]);
FOR i := 0 TO 7 DO
SYSTEM.PUT32(d, 0);
SYSTEM.PUT32(d + 4, 0);
INC(d, incr);
END;
END ClearBlock;
PROCEDURE ClearBlockLongint*(block: PointerToArrayOfLONGINT);
BEGIN
IF EnableMMX THEN
ClearBlockMMX(SYSTEM.ADR(block[0]));
ELSE
ClearBlockGeneric(block);
END;
END ClearBlockLongint;
PROCEDURE ClearBlockGeneric(block: PointerToArrayOfLONGINT );
VAR
i: LONGINT;
adr: LONGINT;
BEGIN
adr := SYSTEM.ADR( block[0] );
FOR i := 0 TO 63 DO
SYSTEM.PUT32( adr, 0 );
INC(adr, SYSTEM.SIZEOF(LONGINT));
END;
END ClearBlockGeneric;
PROCEDURE ClearBlockMMX(dst: LONGINT);
CODE{ SYSTEM.MMX, SYSTEM.PentiumPro }
MOV EDX, -32 ; clear loop counter
MOV ESI, [EBP+dst] ; capture block address
PXOR MMX0, MMX0 ; mm0 = 0
loop:
MOVQ [ESI], MMX0 ; clear memory location
ADD ESI, 8
INC EDX
JNZ loop
EMMS
END ClearBlockMMX;
PROCEDURE CopyBlock*(src, dest: PointerToArrayOfCHAR; srcOffs, destOffs, srcIncr, destIncr, lines: LONGINT);
VAR
s, d: LONGINT;
i: LONGINT;
BEGIN
s := SYSTEM.ADR(src[srcOffs]);
d := SYSTEM.ADR(dest[destOffs]);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s, d, 8);
INC(s, srcIncr);
INC(d, destIncr);
END;
END CopyBlock;
PROCEDURE MoveBlockOverwrite*(src, dest: PointerToArrayOfCHAR; destOffs, mvX, mvY, srcIncr, destIncr, lines: LONGINT);
VAR
buffer: ARRAY 16 OF CHAR;
bufadr: LONGINT;
index: LONGINT;
i, j: LONGINT;
s, d: LONGINT;
tmp1, tmp2: LONGINT;
BEGIN
s := SYSTEM.ADR(src[destOffs])+ (mvY DIV 2)*destIncr + (mvX DIV 2);
d := SYSTEM.ADR(dest[destOffs]);
IF (mvX MOD 2) = 0 THEN
IF (mvY MOD 2) = 0 THEN
CopyBlock(src, dest, destOffs + (mvY DIV 2)*destIncr + (mvX DIV 2), destOffs, srcIncr, destIncr, lines);
ELSE
bufadr := SYSTEM.ADR(buffer[0]);
SYSTEM.MOVE(s, bufadr, 8);
INC(s, srcIncr);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s, bufadr+8-index, 8);
FOR j := 0 TO 7 DO
SYSTEM.PUT8(d+j,
(ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + index + j))) +
ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + 8 - index + j)))) DIV 2);
END;
index := 8 - index;
INC(s, srcIncr);
INC(d, destIncr);
END;
END;
ELSE
IF (mvY MOD 2) = 0 THEN
bufadr := SYSTEM.ADR(buffer[0]);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s+1, bufadr, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+j)));
SYSTEM.PUT8(d+j, (tmp1 + tmp2) DIV 2);
END;
INC(s, srcIncr);
INC(d, destIncr);
END;
ELSE
bufadr := SYSTEM.ADR(buffer[0]);
SYSTEM.MOVE(s+1, bufadr, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+j)));
SYSTEM.PUT8(bufadr+j, (tmp1 + tmp2) DIV 2);
END;
INC(s, srcIncr);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s+1, bufadr+8-index, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+8-index+j)));
SYSTEM.PUT8(bufadr+8-index+j, (tmp1 + tmp2) DIV 2);
END;
FOR j := 0 TO 7 DO
SYSTEM.PUT8(bufadr+index+j,
(ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + index + j))) +
ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + 8 - index + j)))) DIV 2);
END;
SYSTEM.MOVE(bufadr+index, d, 8);
index := 8 - index;
INC(s, srcIncr);
INC(d, destIncr);
END;
END;
END;
END MoveBlockOverwrite;
PROCEDURE MoveBlockInterp*(src, dest: PointerToArrayOfCHAR; destOffs, mvX, mvY, srcIncr, destIncr, lines: LONGINT);
VAR
buffer: ARRAY 16 OF CHAR;
bufadr: LONGINT;
index: LONGINT;
i, j: LONGINT;
s, d: LONGINT;
tmp1, tmp2: LONGINT;
BEGIN
s := SYSTEM.ADR(src[destOffs])+ (mvY DIV 2)*destIncr + (mvX DIV 2);
d := SYSTEM.ADR(dest[destOffs]);
IF (mvX MOD 2) = 0 THEN
IF (mvY MOD 2) = 0 THEN
FOR i := 0 TO (lines-1) DO
FOR j := 0 TO 7 DO
SYSTEM.PUT8(d+j,
(ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s+j))) +
ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(d+j)))) DIV 2);
END;
INC(s, srcIncr);
INC(d, destIncr);
END;
ELSE
bufadr := SYSTEM.ADR(buffer[0]);
SYSTEM.MOVE(s, bufadr, 8);
INC(s, srcIncr);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s, bufadr+8-index, 8);
FOR j := 0 TO 7 DO
tmp1 :=
(ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + index + j))) +
ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + 8 - index + j)))) DIV 2;
SYSTEM.PUT8(d+j, (tmp1 + ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(d + j)))) DIV 2);
END;
index := 8 - index;
INC(s, srcIncr);
INC(d, destIncr);
END;
END;
ELSE
IF (mvY MOD 2) = 0 THEN
bufadr := SYSTEM.ADR(buffer[0]);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s+1, bufadr, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+j)));
tmp1 := (tmp1 + tmp2) DIV 2;
SYSTEM.PUT8(d+j, (tmp1 + ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(d+j)))) DIV 2);
END;
INC(s, srcIncr);
INC(d, destIncr);
END;
ELSE
bufadr := SYSTEM.ADR(buffer[0]);
SYSTEM.MOVE(s+1, bufadr, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+j)));
SYSTEM.PUT8(bufadr+j, (tmp1 + tmp2) DIV 2);
END;
INC(s, srcIncr);
FOR i := 0 TO (lines-1) DO
SYSTEM.MOVE(s+1, bufadr+8-index, 8);
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(s)));
FOR j := 0 TO 7 DO
tmp1 := tmp2;
tmp2 := ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr+8-index+j)));
SYSTEM.PUT8(bufadr+8-index+j, (tmp1 + tmp2) DIV 2);
END;
FOR j := 0 TO 7 DO
tmp1 :=
(ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + index + j))) +
ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(bufadr + 8 - index + j)))) DIV 2;
SYSTEM.PUT8(d+j, (tmp1 + ORD(SYSTEM.VAL(CHAR, SYSTEM.GET8(d + j)))) DIV 2);
END;
index := 8 - index;
INC(s, srcIncr);
INC(d, destIncr);
END;
END;
END;
END MoveBlockInterp;
PROCEDURE TransferIDCTAdd*( source: PointerToArrayOfLONGINT; dest: PointerToArrayOfCHAR; destOffset, stride: LONGINT );
BEGIN
IF EnableMMX THEN
TransferIDCTAddMMX( SYSTEM.ADR( source[0] ), SYSTEM.ADR( dest[destOffset] ), stride );
ELSE
TransferIDCTAddGeneric( source, dest, destOffset, stride );
END;
END TransferIDCTAdd;
PROCEDURE TransferIDCTCopy*( source: PointerToArrayOfLONGINT; dest: PointerToArrayOfCHAR; destOffset, stride: LONGINT );
BEGIN
IF EnableMMX THEN
TransferIDCTCopyMMX( SYSTEM.ADR( source[0] ), SYSTEM.ADR( dest[destOffset] ), stride );
ELSE
TransferIDCTCopyGeneric( source, dest, destOffset, stride );
END;
END TransferIDCTCopy;
PROCEDURE TransferIDCTAddGeneric( source: PointerToArrayOfLONGINT; dest: PointerToArrayOfCHAR; destOffset, stride: LONGINT );
VAR
x, y, s, d, sum: LONGINT;
BEGIN
stride := stride - 8;
s := SYSTEM.ADR( source[0] );
d := SYSTEM.ADR( dest[destOffset] );
FOR y := 0 TO 7 DO
FOR x := 0 TO 7 DO
sum := ORD( SYSTEM.VAL(CHAR, SYSTEM.GET8( d ) ) ) + SYSTEM.GET32( s );
IF sum > 255 THEN
SYSTEM.PUT8( d, 255 )
ELSIF sum < 0 THEN
SYSTEM.PUT8( d, 0 )
ELSE
SYSTEM.PUT8( d, sum )
END;
s := s + SYSTEM.SIZEOF( LONGINT );
d := d + SYSTEM.SIZEOF( CHAR );
END;
d := d + stride
END;
END TransferIDCTAddGeneric;
PROCEDURE TransferIDCTAddMMX( source, dest, stride: LONGINT );
CODE{ SYSTEM.MMX, SYSTEM.PentiumPro }
MOV EAX, [EBP+source] ; PARAMETER 1, *SOURCES32
MOV EBX, [EBP+dest] ; PARAMETER 2, *DESTU8
MOV EDI, [EBP+stride] ; PARAMETER 3, STRIDE
MOV EDX, -8 ; loop counter
PXOR MMX7, MMX7 ; SET MMX7 = 0
loop:
MOVQ MMX0, [EBX] ; eight bytes of destination into mm0
MOVQ MMX1, MMX0 ; eight bytes of destination into mm1
PUNPCKLBW MMX0, MMX7 ; unpack first 4 bytes from dest into mm0, no saturation
PUNPCKHBW MMX1, MMX7 ; unpack next 4 bytes from dest into mm1, no saturation
MOVQ MMX2, [EAX] ; two source Doublewords into mm2
PACKSSDW MMX2, [EAX+8] ; pack mm2 with next two source double words into mm2
MOVQ MMX3, [EAX+16]
PACKSSDW MMX3, [EAX+24]
PADDSW MMX0, MMX2 ; add source and destination
PADDSW MMX1, MMX3 ; add source and destination
PACKUSWB MMX0, MMX1 ; pack mm0 and mm1 into mm0
MOVQ [EBX], MMX0 ; copy output to destination
ADD EBX, EDI ; add +stride to dest ptr
ADD EAX, 32
INC EDX
JNZ loop
EMMS
END TransferIDCTAddMMX;
PROCEDURE TransferIDCTCopyGeneric( source: PointerToArrayOfLONGINT; dest: PointerToArrayOfCHAR; destOffset, stride: LONGINT );
VAR
x, y, s, d, val: LONGINT;
BEGIN
stride := stride - 8;
s := SYSTEM.ADR( source[0] );
d := SYSTEM.ADR( dest[destOffset] );
FOR y := 0 TO 7 DO
FOR x:= 0 TO 7 DO
val := SYSTEM.GET32( s );
IF val > 255 THEN
SYSTEM.PUT8( d, 255 )
ELSIF val < 0 THEN
SYSTEM.PUT8( d, 0 )
ELSE
SYSTEM.PUT8( d, val )
END;
s := s + SYSTEM.SIZEOF(LONGINT);
d := d + SYSTEM.SIZEOF( CHAR );
END;
d := d + stride
END;
END TransferIDCTCopyGeneric;
PROCEDURE TransferIDCTCopyMMX( source, dest, stride: LONGINT );
CODE{ SYSTEM.MMX, SYSTEM.PentiumPro }
MOV EAX, [EBP+source] ; PARAMETER 1, *SOURCES32
MOV EBX, [EBP+dest] ; PARAMETER 2, *DESTU8
MOV EDI, [EBP+stride] ; PARAMETER 3, STRIDE
MOV EDX, -8
loop:
MOVQ MMX0, [EAX] ; eight bytes (two LONGINT) of source into mm0
PACKSSDW MMX0, [EAX+8] ; Pack next 8 bytes (two LONGINT) together with mm0
MOVQ MMX1, [EAX+16]
PACKSSDW MMX1, [EAX+24]
PACKUSWB MMX0, MMX1 ; Pack 4 INTEGER with another 4 INTEGER into mm0
MOVQ [EBX], MMX0 ; Write mm0 to dest
ADD EBX, EDI ; Add stride to dest
ADD EAX, 32 ; next source
INC EDX
JNZ loop
EMMS
END TransferIDCTCopyMMX;
END BlockActions;
BEGIN
NEW(IdctBorder, 1024 );
FOR ii := -512 TO 511 DO
IF ii < -256 THEN
IdctBorder[ii + 512] := -256
ELSIF ii > 255 THEN
IdctBorder[ii + 512] := 255
ELSE
IdctBorder[ii + 512] := ii;
END;
END;
END MPEGUtilities.