package com.onionnetworks.fec; import com.onionnetworks.util.Util; import com.onionnetworks.util.Buffer; /** * This class, along with FECMath, provides the implementation of the pure * Java 16 bit FEC codes. This is heavily dervied from Luigi Rizzos original * C implementation. See the file "LICENSE" along with this distribution for * additional copyright information. * * (c) Copyright 2001 Onion Networks * (c) Copyright 2000 OpenCola * * @author Justin F. Chapweske (justin@chapweske.com) */ public class Pure16Code extends PureCode { protected static final FECMath fecMath = new FECMath(16); /** Notes about large N support: you can just generate the top k*k vandermonde matrix, call it V, then invert it, then when you have k blocks generate a matrix M with the k rows you need <r_i> and E = M* V^{-1} is the encoding matrix for the systematic code which you then need to invert to perform the decoding. Probably there is a fast way to invert E given that M is also a vandermonde matrix so it is "easy" to compute M^{-1} */ public Pure16Code(int k, int n) { super(k,n,fecMath.createEncodeMatrix(k,n)); } /** * encode accepts as input pointers to n data packets of size sz, * and produces as output a packet pointed to by fec, computed * with index "index". */ protected void encode(byte[][] src, int[] srcOff, byte[][] repair, int[] repairOff, int[] index, int packetLength) { if (packetLength % 2 != 0) { throw new IllegalArgumentException("For 16 bit codes, buffers "+ "must be 16 bit aligned."); } char[][] srcChars = new char[src.length][]; int[] srcCharsOff = new int[src.length]; int numChars = packetLength/2; char[] repairChars = new char[numChars]; for (int i=0;i<srcChars.length;i++) { srcChars[i] = new char[numChars]; Util.arraycopy(src[i], srcOff[i], srcChars[i], 0, packetLength); srcCharsOff[i] = 0; } for (int i=0;i<repair.length;i++) { if (index[i] < k) { // < k, systematic so direct copy. System.arraycopy(src[index[i]],srcOff[index[i]],repair[i], repairOff[i], packetLength); } else { encode(srcChars,srcCharsOff,repairChars,0,index[i],numChars); Util.arraycopy(repairChars,0,repair[i],repairOff[i], packetLength); } } } /** * ASSERT: index >= k && index < n */ protected void encode(char[][] src, int[] srcOff, char[] repair, int repairOff, int index, int numChars) { int pos = index*k; Util.bzero(repair,repairOff,numChars); for (int i=0; i<k ; i++) { fecMath.addMul(repair,repairOff,src[i],srcOff[i], encMatrix[pos+i],numChars); } } protected void decode(byte[][] pkts, int[] pktsOff, int[] index, int packetLength, boolean inOrder) { if (packetLength % 2 != 0) { throw new IllegalArgumentException("For 16 bit codes, buffers "+ "must be 16 bit aligned."); } if (!inOrder) { shuffle(pkts, pktsOff, index, k); } char[][] pktsChars = new char[pkts.length][]; int[] pktsCharsOff = new int[pkts.length]; int numChars = packetLength/2; for (int i=0;i<pktsChars.length;i++) { pktsChars[i] = new char[numChars]; Util.arraycopy(pkts[i], pktsOff[i], pktsChars[i], 0, packetLength); pktsCharsOff[i] = 0; } char[][] result = decode(pktsChars, pktsCharsOff, index, numChars); for (int i=0;i<result.length;i++) { if (result[i] != null) { Util.arraycopy(result[i], 0, pkts[i], pktsOff[i], packetLength); index[i] = i; } } } protected char[][] decode(char[][] pkts, int[] pktsOff, int[] index, int numChars) { char[] decMatrix = fecMath.createDecodeMatrix(encMatrix,index,k,n); // do the actual decoding char[][] tmpPkts = new char[k][]; for (int row=0; row<k; row++) { if (index[row] >= k) { tmpPkts[row] = new char[numChars]; for (int col=0 ; col<k ; col++) { fecMath.addMul(tmpPkts[row],0,pkts[col],pktsOff[col], decMatrix[row*k + col], numChars); } } } return tmpPkts; } public String toString() { return new String("Pure16Code[k="+k+",n="+n+"]"); } }