/// <summary> Encodes information for the specified element of the tree, given the /// threshold and sends it to the 'out' stream. The information that is /// coded is whether or not the value of the element is greater than or /// equal to the value of the threshold. /// /// </summary> /// <param name="m">The vertical index of the element. /// /// </param> /// <param name="n">The horizontal index of the element. /// /// </param> /// <param name="t">The threshold to use for encoding. It must be non-negative. /// /// </param> /// <param name="out">The stream where to write the coded information. /// /// </param> public virtual void encode(int m, int n, int t, BitOutputBuffer out_Renamed) { int k, ts, idx, tmin; // Check arguments if (m >= h || n >= w || t < 0) { throw new System.ArgumentException(); } // Initialize k = lvls - 1; tmin = treeS[k][0]; // Loop on levels while (true) { // Index of element in level 'k' idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k); // Cache state ts = treeS[k][idx]; if (ts < tmin) { ts = tmin; } while (t > ts) { if (treeV[k][idx] > ts) { out_Renamed.writeBit(0); // Send '0' bit } else if (treeV[k][idx] == ts) { out_Renamed.writeBit(1); // Send '1' bit } else { // we are done: set ts and get out of this while ts = t; break; } // Increment of treeS[k][idx] ts++; } // Update state treeS[k][idx] = ts; // Update tmin or terminate if (k > 0) { tmin = ts < treeV[k][idx]?ts:treeV[k][idx]; k--; } else { // Terminate return ; } } }
/// <summary> Encodes a packet and returns the buffer containing the encoded packet /// header. The code-blocks appear in a 3D array of CBlkRateDistStats, /// 'cbs'. The first index is the tile index in lexicographical order, the /// second index is the subband index (as defined in the Subband class), /// and the third index is the code-block index (whithin the subband tile) /// in lexicographical order as well. The indexes of the new truncation /// points for each code-block are specified by the 3D array of int /// 'tIndx'. The indices of this array are the same as for cbs. The /// truncation point indices in 'tIndx' are the indices of the elements of /// the 'truncIdxs' array, of the CBlkRateDistStats class, that give the /// real truncation points. If a truncation point index is negative it /// means that the code-block has not been included in any layer yet. If /// the truncation point is less than or equal to the highest truncation /// point used in previous layers then the code-block is not included in /// the packet. Otherwise, if larger, the code-block is included in the /// packet. The body of the packet can be obtained with the /// getLastBodyBuf() and getLastBodyLen() methods. /// /// <p>Layers must be coded in increasing order, in consecutive manner, for /// each tile, component and resolution level (e.g., layer 1, then layer 2, /// etc.). For different tile, component and/or resolution level no /// particular order must be followed.</p> /// /// </summary> /// <param name="ly">The layer index (starts at 1). /// /// </param> /// <param name="c">The component index. /// /// </param> /// <param name="r">The resolution level /// /// </param> /// <param name="t">Index of the current tile /// /// </param> /// <param name="cbs">The 3D array of coded code-blocks. /// /// </param> /// <param name="tIndx">The truncation point indices for each code-block. /// /// </param> /// <param name="hbuf">The header buffer. If null a new BitOutputBuffer is created /// and returned. This buffer is reset before anything is written to it. /// /// </param> /// <param name="bbuf">The body buffer. If null a new one is created. If not large /// enough a new one is created. /// /// </param> /// <param name="pIdx">The precinct index. /// /// </param> /// <returns> The buffer containing the packet header. /// /// </returns> 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; }