public virtual BitOutputBuffer encodePacket(int ly, int c, int r, int t, CBlkRateDistStats[][] cbs, int[][] tIndx, BitOutputBuffer hbuf, byte[] bbuf, int pIdx)
{
int b, i, maxi;
int ncb;
int thmax;
int newtp;
int cblen;
int prednbits, nbits; // deltabits removed
TagTreeEncoder cur_ttIncl, cur_ttMaxBP; // inclusion and bit-depth tag
// trees
int[] cur_prevtIdxs; // last encoded truncation points
CBlkRateDistStats[] cur_cbs;
int[] cur_tIndx; // truncation points to encode
int minsb = (r == 0)?0:1;
int maxsb = (r == 0)?1:4;
Coord cbCoord = null;
SubbandAn root = infoSrc.getAnSubbandTree(t, c);
SubbandAn sb;
roiInPkt = false;
roiLen = 0;
int mend, nend;
// Checks if a precinct with such an index exists in this resolution
// level
if (pIdx >= ppinfo[t][c][r].Length)
{
packetWritable = false;
return hbuf;
}
PrecInfo prec = ppinfo[t][c][r][pIdx];
// First, we check if packet is empty (i.e precinct 'pIdx' has no
// code-block in any of the subbands)
bool isPrecVoid = true;
for (int s = minsb; s < maxsb; s++)
{
if (prec.nblk[s] == 0)
{
// The precinct has no code-block in this subband.
continue;
}
else
{
// The precinct is not empty in at least one subband ->
// stop
isPrecVoid = false;
break;
}
}
if (isPrecVoid)
{
packetWritable = true;
if (hbuf == null)
{
hbuf = new BitOutputBuffer();
}
else
{
hbuf.reset();
}
if (bbuf == null)
{
lbbuf = bbuf = new byte[1];
}
hbuf.writeBit(0);
lblen = 0;
return hbuf;
}
if (hbuf == null)
{
hbuf = new BitOutputBuffer();
}
else
{
hbuf.reset();
}
// Invalidate last body buffer
lbbuf = null;
lblen = 0;
// Signal that packet is present
hbuf.writeBit(1);
for (int s = minsb; s < maxsb; s++)
{
// Loop on subbands
sb = (SubbandAn) root.getSubbandByIdx(r, s);
// Go directly to next subband if the precinct has no code-block
// in the current one.
if (prec.nblk[s] == 0)
{
continue;
}
cur_ttIncl = ttIncl[t][c][r][pIdx][s];
cur_ttMaxBP = ttMaxBP[t][c][r][pIdx][s];
cur_prevtIdxs = prevtIdxs[t][c][r][s];
cur_cbs = cbs[s];
cur_tIndx = tIndx[s];
// Set tag tree values for code-blocks in this precinct
mend = (prec.cblk[s] == null)?0:prec.cblk[s].Length;
for (int m = 0; m < mend; m++)
{
nend = (prec.cblk[s][m] == null)?0:prec.cblk[s][m].Length;
for (int n = 0; n < nend; n++)
{
cbCoord = prec.cblk[s][m][n].idx;
b = cbCoord.x + cbCoord.y * sb.numCb.x;
if (cur_tIndx[b] > cur_prevtIdxs[b] && cur_prevtIdxs[b] < 0)
{
// First inclusion
cur_ttIncl.setValue(m, n, ly - 1);
}
if (ly == 1)
{
// First layer, need to set the skip of MSBP
cur_ttMaxBP.setValue(m, n, cur_cbs[b].skipMSBP);
}
}
}
// Now encode the information
for (int m = 0; m < prec.cblk[s].Length; m++)
{
// Vertical code-blocks
for (int n = 0; n < prec.cblk[s][m].Length; n++)
{
// Horiz. cblks
cbCoord = prec.cblk[s][m][n].idx;
b = cbCoord.x + cbCoord.y * sb.numCb.x;
// 1) Inclusion information
if (cur_tIndx[b] > cur_prevtIdxs[b])
{
// Code-block included in this layer
if (cur_prevtIdxs[b] < 0)
{
// First inclusion
// Encode layer info
cur_ttIncl.encode(m, n, ly, hbuf);
// 2) Max bitdepth info. Encode value
thmax = cur_cbs[b].skipMSBP + 1;
for (i = 1; i <= thmax; i++)
{
cur_ttMaxBP.encode(m, n, i, hbuf);
}
// Count body size for packet
lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
}
else
{
// Already in previous layer
// Send "1" bit
hbuf.writeBit(1);
// Count body size for packet
lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]] - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
}
// 3) Truncation point information
if (cur_prevtIdxs[b] < 0)
{
newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]];
}
else
{
newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]] - cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] - 1;
}
// Mix of switch and if is faster
switch (newtp)
{
case 0:
hbuf.writeBit(0); // Send one "0" bit
break;
case 1:
hbuf.writeBits(2, 2); // Send one "1" and one "0"
break;
case 2:
case 3:
case 4:
// Send two "1" bits followed by 2 bits
// representation of newtp-2
hbuf.writeBits((3 << 2) | (newtp - 2), 4);
break;
default:
if (newtp <= 35)
{
// Send four "1" bits followed by a five bits
// representation of newtp-5
hbuf.writeBits((15 << 5) | (newtp - 5), 9);
}
else if (newtp <= 163)
{
// Send nine "1" bits followed by a seven bits
// representation of newtp-36
hbuf.writeBits((511 << 7) | (newtp - 36), 16);
}
else
{
throw new System.ArithmeticException("Maximum number " + "of truncation " + "points exceeded");
}
break;
}
}
else
{
// Block not included in this layer
if (cur_prevtIdxs[b] >= 0)
{
// Already in previous layer. Send "0" bit
hbuf.writeBit(0);
}
else
{
// Not in any previous layers
cur_ttIncl.encode(m, n, ly, hbuf);
}
// Go to the next one.
continue;
}
// Code-block length
// We need to compute the maximum number of bits needed to
// signal the length of each terminated segment and the
// final truncation point.
newtp = 1;
maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
cblen = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
// Loop on truncation points
i = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
int minbits = 0;
for (; i < maxi; i++, newtp++)
{
// If terminated truncation point calculate length
if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i])
{
// Calculate length
cblen = cur_cbs[b].truncRates[i] - cblen;
// Calculate number of needed bits
prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp);
minbits = ((cblen > 0)?MathUtil.log2(cblen):0) + 1;
// Update Lblock increment if needed
for (int j = prednbits; j < minbits; j++)
{
lblock[t][c][r][s][b]++;
hbuf.writeBit(1);
}
// Initialize for next length
newtp = 0;
cblen = cur_cbs[b].truncRates[i];
}
}
// Last truncation point length always sent
// Calculate length
cblen = cur_cbs[b].truncRates[i] - cblen;
// Calculate number of bits
prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp);
minbits = ((cblen > 0)?MathUtil.log2(cblen):0) + 1;
// Update Lblock increment if needed
for (int j = prednbits; j < minbits; j++)
{
lblock[t][c][r][s][b]++;
hbuf.writeBit(1);
}
// End of comma-code increment
hbuf.writeBit(0);
// There can be terminated several segments, send length
// info for all terminated truncation points in addition
// to final one
newtp = 1;
maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
cblen = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
// Loop on truncation points and count the groups
i = (cur_prevtIdxs[b] < 0)?0:cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
for (; i < maxi; i++, newtp++)
{
// If terminated truncation point, send length
if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i])
{
cblen = cur_cbs[b].truncRates[i] - cblen;
nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b];
hbuf.writeBits(cblen, nbits);
// Initialize for next length
newtp = 0;
cblen = cur_cbs[b].truncRates[i];
}
}
// Last truncation point length is always signalled
// First calculate number of bits needed to signal
// Calculate length
cblen = cur_cbs[b].truncRates[i] - cblen;
nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b];
hbuf.writeBits(cblen, nbits);
} // End loop on horizontal code-blocks
} // End loop on vertical code-blocks
} // End loop on subband
// -> Copy the data to the body buffer
// Ensure size for body data
if (bbuf == null || bbuf.Length < lblen)
{
bbuf = new byte[lblen];
}
lbbuf = bbuf;
lblen = 0;
for (int s = minsb; s < maxsb; s++)
{
// Loop on subbands
sb = (SubbandAn) root.getSubbandByIdx(r, s);
cur_prevtIdxs = prevtIdxs[t][c][r][s];
cur_cbs = cbs[s];
cur_tIndx = tIndx[s];
ncb = cur_prevtIdxs.Length;
mend = (prec.cblk[s] == null)?0:prec.cblk[s].Length;
for (int m = 0; m < mend; m++)
{
// Vertical code-blocks
nend = (prec.cblk[s][m] == null)?0:prec.cblk[s][m].Length;
for (int n = 0; n < nend; n++)
{
// Horiz. cblks
cbCoord = prec.cblk[s][m][n].idx;
b = cbCoord.x + cbCoord.y * sb.numCb.x;
if (cur_tIndx[b] > cur_prevtIdxs[b])
{
// Block included in this precinct -> Copy data to
// body buffer and get code-size
if (cur_prevtIdxs[b] < 0)
{
cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
Array.Copy(cur_cbs[b].data, 0, lbbuf, lblen, cblen);
}
else
{
cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]] - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
Array.Copy(cur_cbs[b].data, cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]], lbbuf, lblen, cblen);
}
lblen += cblen;
// Verifies if this code-block contains new ROI
// information
if (cur_cbs[b].nROIcoeff != 0 && (cur_prevtIdxs[b] == - 1 || cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <= cur_cbs[b].nROIcp - 1))
{
roiInPkt = true;
roiLen = lblen;
}
// Update truncation point
cur_prevtIdxs[b] = cur_tIndx[b];
}
} // End loop on horizontal code-blocks
} // End loop on vertical code-blocks
} // End loop on subbands
packetWritable = true;
// Must never happen
if (hbuf.Length == 0)
{
throw new System.InvalidOperationException("You have found a bug in PktEncoder, method:" + " encodePacket");
}
return hbuf;
}