/// <summary> Decodes information for the specified element of the tree, given the /// threshold, and updates its value. The information that can be decoded /// 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 in decoding. It must be non-negative. /// /// </param> /// <param name="in">The stream from where to read the coded information. /// /// </param> /// <returns> The updated value at position (m,n). /// /// </returns> /// <exception cref="IOException">If an I/O error occurs while reading from 'in'. /// /// </exception> /// <exception cref="EOFException">If the ned of the 'in' stream is reached before /// getting all the necessary data. /// /// </exception> public virtual int update(int m, int n, int t, PktHeaderBitReader in_Renamed) { int k, tmin; int idx, ts, tv; // Check arguments if (m >= h || n >= w || t < 0) { throw new System.ArgumentException(); } // Initialize k = lvls - 1; tmin = treeS[k][0]; // Loop on levels idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k); while (true) { // Cache state and value ts = treeS[k][idx]; tv = treeV[k][idx]; if (ts < tmin) { ts = tmin; } while (t > ts) { if (tv >= ts) { // We are not done yet if (in_Renamed.readBit() == 0) { // '0' bit // We know that 'value' > treeS[k][idx] ts++; } else { // '1' bit // We know that 'value' = treeS[k][idx] tv = ts++; } // Increment of treeS[k][idx] done above } else { // We are done, we can set ts and get out ts = t; break; // get out of this while } } // Update state and value treeS[k][idx] = ts; treeV[k][idx] = tv; // Update tmin or terminate if (k > 0) { tmin = ts < tv?ts:tv; k--; // Index of element for next iteration idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k); } else { // Return the updated value return(tv); } } }
/// <summary> Read specified packet head and found length of each code-block's piece /// of codewords as well as number of skipped most significant bit-planes. /// /// </summary> /// <param name="l">layer index /// /// </param> /// <param name="r">Resolution level index /// /// </param> /// <param name="c">Component index /// /// </param> /// <param name="p">Precinct index /// /// </param> /// <param name="cbI">CBlkInfo array of relevant component and resolution /// level. /// /// </param> /// <param name="nb">The number of bytes to read in each tile before reaching /// output rate (used by truncation mode) /// /// </param> /// <returns> True if specified output rate or EOF is reached. /// /// </returns> public virtual bool readPktHead(int l, int r, int c, int p, CBlkInfo[][][] cbI, int[] nb) { CBlkInfo ccb; int nSeg; // number of segment to read int cbLen; // Length of cblk's code-words int ltp; // last truncation point index int passtype; // coding pass type TagTreeDecoder tdIncl, tdBD; int tmp, tmp2, totnewtp, lblockCur, tpidx; int sumtotnewtp = 0; Coord cbc; int startPktHead = ehs.Pos; if (startPktHead >= ehs.length()) { // EOF reached at the beginning of this packet head return true; } int tIdx = src.TileIdx; PktHeaderBitReader bin; int mend, nend; int b; SubbandSyn sb; SubbandSyn root = src.getSynSubbandTree(tIdx, c); // If packed packet headers was used, use separate stream for reading // of packet headers if (pph) { bin = new PktHeaderBitReader(pphbais); } else { bin = this.bin; } int mins = (r == 0)?0:1; int maxs = (r == 0)?1:4; bool precFound = false; for (int s = mins; s < maxs; s++) { if (p < ppinfo[c][r].Length) { precFound = true; } } if (!precFound) { return false; } PrecInfo prec = ppinfo[c][r][p]; // Synchronize for bit reading bin.sync(); // If packet is empty there is no info in it (i.e. no code-blocks) if (bin.readBit() == 0) { // No code-block is included cblks = new System.Collections.ArrayList[maxs + 1]; for (int s = mins; s < maxs; s++) { cblks[s] = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); } pktIdx++; // If truncation mode, checks if output rate is reached // unless ncb quit condition is used in which case headers // are not counted if (isTruncMode && maxCB == - 1) { tmp = ehs.Pos - startPktHead; if (tmp > nb[tIdx]) { nb[tIdx] = 0; return true; } else { nb[tIdx] -= tmp; } } // Read EPH marker if needed if (ephUsed) { readEPHMarker(bin); } return false; } // Packet is not empty => decode info // Loop on each subband in this resolution level if (cblks == null || cblks.Length < maxs + 1) { cblks = new System.Collections.ArrayList[maxs + 1]; } for (int s = mins; s < maxs; s++) { if (cblks[s] == null) { cblks[s] = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); } else { cblks[s].Clear(); } sb = (SubbandSyn) root.getSubbandByIdx(r, s); // No code-block in this precinct if (prec.nblk[s] == 0) { // Go to next subband continue; } tdIncl = ttIncl[c][r][p][s]; tdBD = ttMaxBP[c][r][p][s]; 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++) { // Horizontal code-blocks cbc = prec.cblk[s][m][n].idx; b = cbc.x + cbc.y * sb.numCb.x; ccb = cbI[s][cbc.y][cbc.x]; try { // If code-block not included in previous layer(s) if (ccb == null || ccb.ctp == 0) { if (ccb == null) { ccb = cbI[s][cbc.y][cbc.x] = new CBlkInfo(prec.cblk[s][m][n].ulx, prec.cblk[s][m][n].uly, prec.cblk[s][m][n].w, prec.cblk[s][m][n].h, nl); } ccb.pktIdx[l] = pktIdx; // Read inclusion using tag-tree tmp = tdIncl.update(m, n, l + 1, bin); if (tmp > l) { // Not included continue; } // Read bitdepth using tag-tree tmp = 1; // initialization for (tmp2 = 1; tmp >= tmp2; tmp2++) { tmp = tdBD.update(m, n, tmp2, bin); } ccb.msbSkipped = tmp2 - 2; // New code-block => at least one truncation point totnewtp = 1; ccb.addNTP(l, 0); // Check whether ncb quit condition is reached ncb++; if (maxCB != - 1 && !ncbQuit && ncb == maxCB) { // ncb quit contidion reached ncbQuit = true; tQuit = tIdx; cQuit = c; sQuit = s; rQuit = r; xQuit = cbc.x; yQuit = cbc.y; } } else { // If code-block already included in one of // the previous layers. ccb.pktIdx[l] = pktIdx; // If not inclused if (bin.readBit() != 1) { continue; } // At least 1 more truncation point than // prev. packet totnewtp = 1; } // Read new truncation points if (bin.readBit() == 1) { // if bit is 1 totnewtp++; // if next bit is 0 do nothing if (bin.readBit() == 1) { //if is 1 totnewtp++; tmp = bin.readBits(2); totnewtp += tmp; // If next 2 bits are not 11 do nothing if (tmp == 0x3) { //if 11 tmp = bin.readBits(5); totnewtp += tmp; // If next 5 bits are not 11111 do nothing if (tmp == 0x1F) { //if 11111 totnewtp += bin.readBits(7); } } } } ccb.addNTP(l, totnewtp); sumtotnewtp += totnewtp; cblks[s].Add(prec.cblk[s][m][n]); // Code-block length // -- Compute the number of bit to read to obtain // code-block length. // numBits = betaLamda + log2(totnewtp); // The length is signalled for each segment in // addition to the final one. The total length is the // sum of all segment lengths. // If regular termination in use, then there is one // segment per truncation point present. Otherwise, if // selective arithmetic bypass coding mode is present, // then there is one termination per bypass/MQ and // MQ/bypass transition. Otherwise the only // termination is at the end of the code-block. int options = ((System.Int32) decSpec.ecopts.getTileCompVal(tIdx, c)); if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Regular termination in use, one segment per new // pass (i.e. truncation point) nSeg = totnewtp; } else if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS) != 0) { // Selective arithmetic coding bypass coding mode // in use, but no regular termination 1 segment up // to the end of the last pass of the 4th most // significant bit-plane, and, in each following // bit-plane, one segment upto the end of the 2nd // pass and one upto the end of the 3rd pass. if (ccb.ctp <= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX) { nSeg = 1; } else { nSeg = 1; // One at least for last pass // And one for each other terminated pass for (tpidx = ccb.ctp - totnewtp; tpidx < ccb.ctp - 1; tpidx++) { if (tpidx >= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX - 1) { passtype = (tpidx + CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_EMPTY_PASSES_IN_MS_BP) % CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES; if (passtype == 1 || passtype == 2) { // bypass coding just before MQ // pass or MQ pass just before // bypass coding => terminated nSeg++; } } } } } else { // Nothing special in use, just one segment nSeg = 1; } // Reads lblock increment (common to all segments) while (bin.readBit() != 0) { lblock[c][r][s][cbc.y][cbc.x]++; } if (nSeg == 1) { // Only one segment in packet cbLen = bin.readBits(lblock[c][r][s][cbc.y][cbc.x] + MathUtil.log2(totnewtp)); } else { // We must read one length per segment ccb.segLen[l] = new int[nSeg]; cbLen = 0; int j; if ((options & CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS) != 0) { // Regular termination: each pass is terminated for (tpidx = ccb.ctp - totnewtp, j = 0; tpidx < ccb.ctp; tpidx++, j++) { lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin.readBits(lblockCur); ccb.segLen[l][j] = tmp; cbLen += tmp; } } else { // Bypass coding: only some passes are // terminated ltp = ccb.ctp - totnewtp - 1; for (tpidx = ccb.ctp - totnewtp, j = 0; tpidx < ccb.ctp - 1; tpidx++) { if (tpidx >= CSJ2K.j2k.entropy.StdEntropyCoderOptions.FIRST_BYPASS_PASS_IDX - 1) { passtype = (tpidx + CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_EMPTY_PASSES_IN_MS_BP) % CSJ2K.j2k.entropy.StdEntropyCoderOptions.NUM_PASSES; if (passtype == 0) continue; lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin.readBits(lblockCur + MathUtil.log2(tpidx - ltp)); ccb.segLen[l][j] = tmp; cbLen += tmp; ltp = tpidx; j++; } } // Last pass has always the length sent lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin.readBits(lblockCur + MathUtil.log2(tpidx - ltp)); cbLen += tmp; ccb.segLen[l][j] = tmp; } } ccb.len[l] = cbLen; // If truncation mode, checks if output rate is reached // unless ncb and lbody quit contitions used. if (isTruncMode && maxCB == - 1) { tmp = ehs.Pos - startPktHead; if (tmp > nb[tIdx]) { nb[tIdx] = 0; // Remove found information in this code-block if (l == 0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l] = ccb.len[l] = 0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = - 1; } return true; } } } catch (System.IO.EndOfStreamException) { // Remove found information in this code-block if (l == 0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l] = ccb.len[l] = 0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = - 1; } // throw new EOFException(); return true; } } // End loop on horizontal code-blocks } // End loop on vertical code-blocks } // End loop on subbands // Read EPH marker if needed if (ephUsed) { readEPHMarker(bin); } pktIdx++; // If truncation mode, checks if output rate is reached if (isTruncMode && maxCB == - 1) { tmp = ehs.Pos - startPktHead; if (tmp > nb[tIdx]) { nb[tIdx] = 0; return true; } else { nb[tIdx] -= tmp; } } return false; }
/// <summary> Try to read an EPH marker. If it is not possible then an Error is /// thrown. /// /// </summary> /// <param name="bin">The packet header reader to read the EPH marker from /// /// </param> public virtual void readEPHMarker(PktHeaderBitReader bin) { int val; byte[] ephArray = new byte[2]; if (bin.usebais) { bin.bais.Read(ephArray, 0, CSJ2K.j2k.codestream.Markers.EPH_LENGTH); } else { bin.in_Renamed.readFully(ephArray, 0, CSJ2K.j2k.codestream.Markers.EPH_LENGTH); } // Check if this is the correct marker val = ephArray[0]; val <<= 8; val |= ephArray[1]; if (val != CSJ2K.j2k.codestream.Markers.EPH) { throw new System.ApplicationException("Corrupted Bitstream: Could not parse EPH " + "marker ! "); } }
/// <summary> Creates an empty PktDecoder object associated with given decoder /// specifications and HeaderDecoder. This object must be initialized /// thanks to the restart method before being used. /// /// </summary> /// <param name="decSpec">The decoder specifications. /// /// </param> /// <param name="hd">The HeaderDecoder instance. /// /// </param> /// <param name="ehs">The stream where to read data from. /// /// </param> /// <param name="src">The bit stream reader agent. /// /// </param> /// <param name="isTruncMode">Whether or not truncation mode is required. /// /// </param> /// <param name="maxCB">The maximum number of code-blocks to read before ncbquit /// /// /// </param> public PktDecoder(DecoderSpecs decSpec, HeaderDecoder hd, RandomAccessIO ehs, BitstreamReaderAgent src, bool isTruncMode, int maxCB) { this.decSpec = decSpec; this.hd = hd; this.ehs = ehs; this.isTruncMode = isTruncMode; bin = new PktHeaderBitReader(ehs); this.src = src; ncb = 0; ncbQuit = false; this.maxCB = maxCB; }
/// <summary> Decodes information for the specified element of the tree, given the /// threshold, and updates its value. The information that can be decoded /// 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 in decoding. It must be non-negative. /// /// </param> /// <param name="in">The stream from where to read the coded information. /// /// </param> /// <returns> The updated value at position (m,n). /// /// </returns> /// <exception cref="IOException">If an I/O error occurs while reading from 'in'. /// /// </exception> /// <exception cref="EOFException">If the ned of the 'in' stream is reached before /// getting all the necessary data. /// /// </exception> public virtual int update(int m, int n, int t, PktHeaderBitReader in_Renamed) { int k, tmin; int idx, ts, tv; // Check arguments if (m >= h || n >= w || t < 0) { throw new System.ArgumentException(); } // Initialize k = lvls - 1; tmin = treeS[k][0]; // Loop on levels idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k); while (true) { // Cache state and value ts = treeS[k][idx]; tv = treeV[k][idx]; if (ts < tmin) { ts = tmin; } while (t > ts) { if (tv >= ts) { // We are not done yet if (in_Renamed.readBit() == 0) { // '0' bit // We know that 'value' > treeS[k][idx] ts++; } else { // '1' bit // We know that 'value' = treeS[k][idx] tv = ts++; } // Increment of treeS[k][idx] done above } else { // We are done, we can set ts and get out ts = t; break; // get out of this while } } // Update state and value treeS[k][idx] = ts; treeV[k][idx] = tv; // Update tmin or terminate if (k > 0) { tmin = ts < tv?ts:tv; k--; // Index of element for next iteration idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k); } else { // Return the updated value return tv; } } }