001 /**
002  * Copyright (C) 2013 - Francesc Auli-Llinas
003  *
004  * This program is distributed under the BOI License.
005  * This program is distributed in the hope that it will be useful, but without any
006  * warranty; without even the implied warranty of merchantability or fitness for a particular purpose.
007  * You should have received a copy of the BOI License along with this program. If not, see
008  <http://www.deic.uab.cat/~francesc/software/license/>.
009  */
010 package coders;
011 
012 import streams.ByteStream;
013 
014 
015 /**
016  * This class implements the M coder defined in the HEVC standard. This class can perform both the
017  * operations of the encoder and the decoder. The sourcecode is translated from C++ to Java using
018  * the reference software of the HEVC project provided
019  * in https://hevc.hhi.fraunhofer.de/svn/svn_HEVCSoftware/trunk (revision 3517).<br>
020  *
021  * Usage: once the object is created, the functions to code/decode symbols are used to code the
022  * message. Instead of destroying the object and creating another one to encode a new message, it
023  * is more computationally efficient to reuse the same object. When encoding, the same object can be
024  * reused by calling the functions <code>terminate</code>, get the stream wherever is needed, and
025  * call <code>changeStream</code> and <code>restartEncoding</code> in this order. To reuse the
026  * decoder, call the functions <code>changeStream</code> and <code>restartDecoding</code> in this order.<br>
027  *
028  * Multithreading support: the object must be created and manipulated by a single thread. There
029  * can be many objects of this class running simultaneously as long as a single thread manipulates each object.<br>
030  *
031  @author Francesc Auli-Llinas
032  @version 1.0
033  */
034 public final class ArithmeticCoderM{
035 
036   //Variables needed to encode
037   private long m_uiLow;
038   private int m_bitsLeft;
039   private int m_numBufferedBytes;
040   private int m_bufferedByte;
041 
042   //Variables needed to decode
043   private long m_uiValue;
044   private int m_bitsNeeded;
045 
046   //Variables needed both to encode and to decode
047   private int L;
048   private ByteStream stream;
049   private long m_uiRange;
050   private int[] m_ucState = null;
051   final static private short[][] sm_aucLPSTable = {
052     128176208240},
053     128167197227},
054     128158187216},
055     123150178205},
056     116142169195},
057     111135160185},
058     105128152175},
059     100122144166},
060     {  95116137158},
061     {  90110130150},
062     {  85104123142},
063     {  81,  99117135},
064     {  77,  94111128},
065     {  73,  89105122},
066     {  69,  85100116},
067     {  66,  80,  95110},
068     {  62,  76,  90104},
069     {  59,  72,  86,  99},
070     {  56,  69,  81,  94},
071     {  53,  65,  77,  89},
072     {  51,  62,  73,  85},
073     {  48,  59,  69,  80},
074     {  46,  56,  66,  76},
075     {  43,  53,  63,  72},
076     {  41,  50,  59,  69},
077     {  39,  48,  56,  65},
078     {  37,  45,  54,  62},
079     {  35,  43,  51,  59},
080     {  33,  41,  48,  56},
081     {  32,  39,  46,  53},
082     {  30,  37,  43,  50},
083     {  29,  35,  41,  48},
084     {  27,  33,  39,  45},
085     {  26,  31,  37,  43},
086     {  24,  30,  35,  41},
087     {  23,  28,  33,  39},
088     {  22,  27,  32,  37},
089     {  21,  26,  30,  35},
090     {  20,  24,  29,  33},
091     {  19,  23,  27,  31},
092     {  18,  22,  26,  30},
093     {  17,  21,  25,  28},
094     {  16,  20,  23,  27},
095     {  15,  19,  22,  25},
096     {  14,  18,  21,  24},
097     {  14,  17,  20,  23},
098     {  13,  16,  19,  22},
099     {  12,  15,  18,  21},
100     {  12,  14,  17,  20},
101     {  11,  14,  16,  19},
102     {  11,  13,  15,  18},
103     {  10,  12,  15,  17},
104     {  10,  12,  14,  16},
105     {   9,  11,  13,  15},
106     {   9,  11,  12,  14},
107     {   8,  10,  12,  14},
108     {   8,   9,  11,  13},
109     {   7,   9,  11,  12},
110     {   7,   9,  10,  12},
111     {   7,   8,  10,  11},
112     {   6,   8,   9,  11},
113     {   6,   7,   9,  10},
114     {   6,   7,   8,   9},
115     {   2,   2,   2,   2}
116   };
117   final static private byte[] sm_aucRenormTable = {
118     6,  5,  4,  43,  3,  3,  32,  2,  2,  22,  2,  2,  21,  1,  1,  1,
119     1,  1,  1,  11,  1,  1,  11,  1,  1,  1};
120   final static private byte[] m_aucNextStateMPS = {
121     234567891011121314151617181920212223,
122     2425262728293031323334353637383940414243,
123     4445464748495051525354555657585960616263,
124     6465666768697071727374757677787980818283,
125     84858687888990919293949596979899100101102,
126     103104105106107108109110111112113114115116117118,
127     119120121122123124125124125126127};
128   final static private byte[] m_aucNextStateLPS = {
129     1001234545898910111213141516171819,
130     181922232223242526272627303130313233323336,
131     373637383938394243424344454445464748494849,
132     505152535253545554555657585958596061606160,
133     616263646564656667666766676869686970717071,
134     707172737273727374757475747576777677126127};
135 
136 
137   /**
138    * Constructor of the class. Initializes required variables.
139    *
140    @param numContexts number of contexts that will be used
141    */
142   public ArithmeticCoderM(int numContexts){
143     assert(numContexts > 0);
144     m_ucState = new int[numContexts];
145   }
146 
147   /**
148    * Restarts the coder leaving it ready to encode.
149    */
150   public void restartEncoding(){
151     m_uiLow = 0;
152     m_uiRange = 510;
153     m_bitsLeft = 23;
154     m_numBufferedBytes = 0;
155     m_bufferedByte = 0xff;
156     for(int c = 0; c < m_ucState.length; c++){
157       m_ucState[c0;
158     }
159     L = 0;
160   }
161 
162   /**
163    * Restarts the coder leaving it ready to decode.
164    *
165    @throws Exception when some problem reading the stream occurs
166    */
167   public void restartDecoding() throws Exception{
168     m_uiRange = 510;
169     m_bitsNeeded = -8;
170     L = 0;
171     int Tr = 0x00;
172     if(L < stream.getLength()){
173       Tr = (0x000000FF (intstream.getByte(L));
174       L++;
175     }
176     m_uiValue = Tr << 8;
177     Tr = 0x00;
178     if(L < stream.getLength()){
179       Tr = (0x000000FF (intstream.getByte(L));
180       L++;
181     }
182     m_uiValue += Tr;
183     for(int c = 0; c < m_ucState.length; c++){
184       m_ucState[c0;
185     }
186   }
187 
188   /**
189    * Encodes a bit using equiprobable probabilities.
190    *
191    @param binValue the bit to encode
192    */
193   public void encodeBit(boolean binValue){
194     m_uiLow <<= 1;
195     if(binValue){
196       m_uiLow += m_uiRange;
197     }
198     m_bitsLeft--;
199     testAndWriteOut();
200   }
201 
202   /**
203    * Decodes a bit using equiprobable probabilities.
204    *
205    @return the decoded bit
206    @throws Exception when some problem reading the stream occurs
207    */
208   public boolean decodeBit() throws Exception{
209     boolean ruiBin;
210     m_uiValue += m_uiValue;
211     if(++m_bitsNeeded >= 0){
212       m_bitsNeeded = -8;
213       int Tr = 0x00;
214       if(L < stream.getLength()){
215         Tr = (0x000000FF (intstream.getByte(L));
216         L++;
217       }
218       m_uiValue += Tr;
219     }
220     ruiBin = false;
221     long scaledRange = m_uiRange << 7;
222     if(m_uiValue >= scaledRange){
223       ruiBin = true;
224       m_uiValue -= scaledRange;
225     }
226     return(ruiBin);
227   }
228 
229   /**
230    * Encodes a bit employing context-adaptive mechanisms.
231    *
232    @param binValue the bit to encode
233    @param context the context employed to encode the bit
234    */
235   public void encodeBitContext(boolean binValue, int context){
236     int state = m_ucState[context>> 1;
237     int uiLPS = sm_aucLPSTable[state][(int) ((m_uiRange >> 63)];
238     m_uiRange -= uiLPS;
239     boolean MPS = (m_ucState[context1== 1;
240 
241     if(binValue != MPS){
242       int numBits = sm_aucRenormTable[uiLPS >> 3];
243       m_uiLow = (m_uiLow + m_uiRange<< numBits;
244       m_uiRange = uiLPS << numBits;
245       m_ucState[context= m_aucNextStateLPS[m_ucState[context]];
246       m_bitsLeft -= numBits;
247     }else{
248       m_ucState[context= m_aucNextStateMPS[m_ucState[context]];
249       if(m_uiRange >= 256){
250         return;
251       }
252       m_uiLow <<= 1;
253       m_uiRange <<= 1;
254       m_bitsLeft--;
255     }
256     testAndWriteOut();
257   }
258 
259   /**
260    * Decodes a bit employing context-adaptive mechanisms.
261    *
262    @param context the context employed to decode the bit
263    @return the decoded bit
264    @throws Exception when some problem reading the stream occurs
265    */
266   public boolean decodeBitContext(int contextthrows Exception{
267     boolean ruiBin;
268     int state = m_ucState[context>> 1;
269     int uiLPS = sm_aucLPSTable[state][(int) ((m_uiRange >> 64)];
270     m_uiRange -= uiLPS;
271     long scaledRange = m_uiRange << 7;
272     boolean MPS = (m_ucState[context1== 1;
273 
274     if(m_uiValue < scaledRange){
275       ruiBin = MPS;
276       m_ucState[context= m_aucNextStateMPS[m_ucState[context]];
277       if(scaledRange >= (256 << 7)){
278         return(ruiBin);
279       }
280       m_uiRange = scaledRange >> 6;
281       m_uiValue += m_uiValue;
282       if(++m_bitsNeeded == 0){
283         m_bitsNeeded = -8;
284         int Tr = 0x00;
285         if(L < stream.getLength()){
286           Tr = (0x000000FF (intstream.getByte(L));
287           L++;
288         }
289         m_uiValue += Tr;
290       }
291     }else{
292       int numBits = sm_aucRenormTable[uiLPS >> 3];
293       m_uiValue = (m_uiValue - scaledRange<< numBits;
294       m_uiRange = uiLPS << numBits;
295       ruiBin = !MPS;
296       m_ucState[context= m_aucNextStateLPS[m_ucState[context]];
297       m_bitsNeeded += numBits;
298       if(m_bitsNeeded >= 0){
299         int Tr = 0x00;
300         if(L < stream.getLength()){
301           Tr = (0x000000FF (intstream.getByte(L));
302           L++;
303         }
304         m_uiValue += Tr << m_bitsNeeded;
305         m_bitsNeeded -= 8;
306       }
307     }
308     return(ruiBin);
309   }
310 
311   /**
312    * Encodes a bit employing the probability of symbol 0.
313    *
314    @param binValue the bit to encode
315    @param prob0 probability of the symbol 0 computed through the function {@link #prob0ToM(float)}
316    */
317   public void encodeBitProb(boolean binValue, int prob0){
318     boolean MPS = prob0 < 0;
319     int uiLPS = sm_aucLPSTable[Math.abs(prob0)][(int) ((m_uiRange >> 63)];
320     m_uiRange -= uiLPS;
321 
322     if(binValue != MPS){
323       int numBits = sm_aucRenormTable[uiLPS >> 3];
324       m_uiLow = (m_uiLow + m_uiRange<< numBits;
325       m_uiRange = uiLPS << numBits;
326       m_bitsLeft -= numBits;
327     }else{
328       if(m_uiRange >= 256){
329         return;
330       }
331       m_uiLow <<= 1;
332       m_uiRange <<= 1;
333       m_bitsLeft--;
334     }
335     testAndWriteOut();
336   }
337 
338   /**
339    * Decodes a bit employing the probability of symbol 0.
340    *
341    @param prob0 probability of the symbol 0 computed through the function {@link #prob0ToM(float)}
342    @return the decoded bit
343    @throws Exception when some problem reading the stream occurs
344    */
345   public boolean decodeBitProb(int prob0throws Exception{
346     boolean MPS = prob0 < 0;
347     boolean ruiBin;
348     int uiLPS = sm_aucLPSTable[Math.abs(prob0)][(int) ((m_uiRange >> 64)];
349     m_uiRange -= uiLPS;
350     long scaledRange = m_uiRange << 7;
351 
352     if(m_uiValue < scaledRange){
353       ruiBin = MPS;
354       if(scaledRange >= (256 << 7)){
355         return(ruiBin);
356       }
357       m_uiRange = scaledRange >> 6;
358       m_uiValue += m_uiValue;
359       if(++m_bitsNeeded == 0){
360         m_bitsNeeded = -8;
361         int Tr = 0x00;
362         if(L < stream.getLength()){
363           Tr = (0x000000FF (intstream.getByte(L));
364           L++;
365         }
366         m_uiValue += Tr;
367       }
368     }else{
369       int numBits = sm_aucRenormTable[uiLPS >> 3];
370       m_uiValue = (m_uiValue - scaledRange<< numBits;
371       m_uiRange = uiLPS << numBits;
372       ruiBin = !MPS;
373       m_bitsNeeded += numBits;
374       if(m_bitsNeeded >= 0){
375         int Tr = 0x00;
376         if(L < stream.getLength()){
377           Tr = (0x000000FF (intstream.getByte(L));
378           L++;
379         }
380         m_uiValue += Tr << m_bitsNeeded;
381         m_bitsNeeded -= 8;
382       }
383     }
384     return(ruiBin);
385   }
386 
387   /**
388    * Transforms the probability of the symbol 0 (or false) in the range [0:1] into the integer
389    * required in the M coder to represent that probability.
390    *
391    @param prob0 in the range [0:1]
392    @return integer that can be feed to the M coder
393    */
394   public static int prob0ToM(float prob0){
395     boolean MPS;
396     if(prob0 >= 0.5f){
397       MPS = false;
398     }else{
399       MPS = true;
400       prob0 = - prob0;
401     }
402     //determined through reverse engineering (it is the context with closest probability to prob0)
403     float base = 12f;
404     int prob0M = (int) (((Math.pow(base, (prob0 - 0.5f2f1f(base - 1f)) 61f2;
405     if(MPS){
406       prob0M = -prob0M;
407     }
408     return(prob0M);
409   }
410 
411   /**
412    * Does nothing. Added for compatibility purposes.
413    */
414   public void reset(){}
415 
416   /**
417    * Swaps the current stream. When encoding, before calling this function the stream should be
418    * terminated calling the <code>terminate</code> function, and after calling this function the
419    * function <code>restartEncoding</code> must be called. When decoding, after calling this
420    * function the function <code>restartDecoding</code> must be called.
421    *
422    @param stream the new ByteStream
423    */
424   public void changeStream(ByteStream stream){
425     if(stream == null){
426       stream = new ByteStream();
427     }
428     this.stream = stream;
429   }
430 
431   /**
432    * Terminates the encoding process dispatching all bits in the register to the stream.
433    */
434   public void terminate(){
435     encodeBinTrm(1);
436     if((m_uiLow >> (32 - m_bitsLeft)) != 0){
437       stream.putByte((byte) (m_bufferedByte + 1));
438       L++;
439       while(m_numBufferedBytes > 1){
440         stream.putByte((byte0x00);
441         L++;
442         m_numBufferedBytes--;
443       }
444       m_uiLow -= << (32 - m_bitsLeft);
445     }else{
446       if(m_numBufferedBytes > 0){
447         stream.putByte((bytem_bufferedByte);
448         L++;
449       }
450       while(m_numBufferedBytes > 1){
451         stream.putByte((byte0xFF);
452         L++;
453         m_numBufferedBytes--;
454       }
455     }
456     int bitsLeft = 24 - m_bitsLeft;
457     while(bitsLeft > 0){
458       stream.putByte((byte) (m_uiLow >> bitsLeft));
459       L++;
460       bitsLeft -= 8;
461     }
462   }
463 
464   /**
465    * Gets the number of bytes read or written to the stream associated to the coder.
466    *
467    @return the number of bytes
468    */
469   public int getReadBytes(){
470     return(L);
471   }
472 
473   /**
474    * Computes the number of bytes belonging to the currently encoded data needed to flush the
475    * internal registers (for encoding purposes). This function is useful to determine potential
476    * truncation points of the stream.
477    *
478    @return number of bytes
479    */
480   public int remainingBytes(){
481     return(4);
482   }
483 
484   /**
485    * Tests whether the bits in the register have to be dispatched to the stream.
486    */
487   private void testAndWriteOut(){
488     if(m_bitsLeft < 12){
489       writeOut();
490     }
491   }
492 
493   /**
494    * Writes some bits of the internal register to the stream.
495    */
496   private void writeOut(){
497     int leadByte = (int) (m_uiLow >> (24 - m_bitsLeft));
498     m_bitsLeft += 8;
499     m_uiLow &= (0xffffffffl>> m_bitsLeft;
500 
501     if(leadByte == 0xff){
502       m_numBufferedBytes++;
503     }else{
504       if(m_numBufferedBytes > 0){
505         int carry = leadByte >> 8;
506         int byteB = m_bufferedByte + carry;
507         m_bufferedByte = leadByte & 0xff;
508         stream.putByte((bytebyteB);
509         L++;
510 
511         byteB = (0xff + carry0xff;
512         while(m_numBufferedBytes > 1){
513           stream.putByte((bytebyteB);
514           L++;
515           m_numBufferedBytes--;
516         }
517       }else{
518         m_numBufferedBytes = 1;
519         m_bufferedByte = leadByte;
520       }
521     }
522   }
523 
524   /**
525    * Encodes a terminating bit (needed when terminating the encoding process).
526    *
527    @param binValue the bit encoded
528    */
529   public void encodeBinTrm(int binValue){
530     m_uiRange -= 2;
531     if(binValue != 0){
532       m_uiLow  += m_uiRange;
533       m_uiLow <<= 7;
534       m_uiRange = << 7;
535       m_bitsLeft -= 7;
536     }else if(m_uiRange >= 256){
537       return;
538     }else{
539       m_uiLow   <<= 1;
540       m_uiRange <<= 1;
541       m_bitsLeft--;
542     }
543     testAndWriteOut();
544   }
545 }
Java2html