token_enc.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright 2011 Google Inc. All Rights Reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the COPYING file in the root of the source
  5. // tree. An additional intellectual property rights grant can be found
  6. // in the file PATENTS. All contributing project authors may
  7. // be found in the AUTHORS file in the root of the source tree.
  8. // -----------------------------------------------------------------------------
  9. //
  10. // Paginated token buffer
  11. //
  12. // A 'token' is a bit value associated with a probability, either fixed
  13. // or a later-to-be-determined after statistics have been collected.
  14. // For dynamic probability, we just record the slot id (idx) for the probability
  15. // value in the final probability array (uint8_t* probas in VP8EmitTokens).
  16. //
  17. // Author: Skal (pascal.massimino@gmail.com)
  18. #include <assert.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "./cost_enc.h"
  22. #include "./vp8i_enc.h"
  23. #include "../utils/utils.h"
  24. #if !defined(DISABLE_TOKEN_BUFFER)
  25. // we use pages to reduce the number of memcpy()
  26. #define MIN_PAGE_SIZE 8192 // minimum number of token per page
  27. #define FIXED_PROBA_BIT (1u << 14)
  28. typedef uint16_t token_t; // bit #15: bit value
  29. // bit #14: flags for constant proba or idx
  30. // bits #0..13: slot or constant proba
  31. struct VP8Tokens {
  32. VP8Tokens* next_; // pointer to next page
  33. };
  34. // Token data is located in memory just after the next_ field.
  35. // This macro is used to return their address and hide the trick.
  36. #define TOKEN_DATA(p) ((const token_t*)&(p)[1])
  37. //------------------------------------------------------------------------------
  38. void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
  39. b->tokens_ = NULL;
  40. b->pages_ = NULL;
  41. b->last_page_ = &b->pages_;
  42. b->left_ = 0;
  43. b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size;
  44. b->error_ = 0;
  45. }
  46. void VP8TBufferClear(VP8TBuffer* const b) {
  47. if (b != NULL) {
  48. VP8Tokens* p = b->pages_;
  49. while (p != NULL) {
  50. VP8Tokens* const next = p->next_;
  51. WebPSafeFree(p);
  52. p = next;
  53. }
  54. VP8TBufferInit(b, b->page_size_);
  55. }
  56. }
  57. static int TBufferNewPage(VP8TBuffer* const b) {
  58. VP8Tokens* page = NULL;
  59. if (!b->error_) {
  60. const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t);
  61. page = (VP8Tokens*)WebPSafeMalloc(1ULL, size);
  62. }
  63. if (page == NULL) {
  64. b->error_ = 1;
  65. return 0;
  66. }
  67. page->next_ = NULL;
  68. *b->last_page_ = page;
  69. b->last_page_ = &page->next_;
  70. b->left_ = b->page_size_;
  71. b->tokens_ = (token_t*)TOKEN_DATA(page);
  72. return 1;
  73. }
  74. //------------------------------------------------------------------------------
  75. #define TOKEN_ID(t, b, ctx) \
  76. (NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t))))
  77. static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit,
  78. uint32_t proba_idx,
  79. proba_t* const stats) {
  80. assert(proba_idx < FIXED_PROBA_BIT);
  81. assert(bit <= 1);
  82. if (b->left_ > 0 || TBufferNewPage(b)) {
  83. const int slot = --b->left_;
  84. b->tokens_[slot] = (bit << 15) | proba_idx;
  85. }
  86. VP8RecordStats(bit, stats);
  87. return bit;
  88. }
  89. static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
  90. uint32_t bit, uint32_t proba) {
  91. assert(proba < 256);
  92. assert(bit <= 1);
  93. if (b->left_ > 0 || TBufferNewPage(b)) {
  94. const int slot = --b->left_;
  95. b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
  96. }
  97. }
  98. int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
  99. VP8TBuffer* const tokens) {
  100. const int16_t* const coeffs = res->coeffs;
  101. const int coeff_type = res->coeff_type;
  102. const int last = res->last;
  103. int n = res->first;
  104. uint32_t base_id = TOKEN_ID(coeff_type, n, ctx);
  105. // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1
  106. proba_t* s = res->stats[n][ctx];
  107. if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) {
  108. return 0;
  109. }
  110. while (n < 16) {
  111. const int c = coeffs[n++];
  112. const int sign = c < 0;
  113. const uint32_t v = sign ? -c : c;
  114. if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) {
  115. base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0
  116. s = res->stats[VP8EncBands[n]][0];
  117. continue;
  118. }
  119. if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) {
  120. base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1
  121. s = res->stats[VP8EncBands[n]][1];
  122. } else {
  123. if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) {
  124. if (AddToken(tokens, v != 2, base_id + 4, s + 4)) {
  125. AddToken(tokens, v == 4, base_id + 5, s + 5);
  126. }
  127. } else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) {
  128. if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) {
  129. AddConstantToken(tokens, v == 6, 159);
  130. } else {
  131. AddConstantToken(tokens, v >= 9, 165);
  132. AddConstantToken(tokens, !(v & 1), 145);
  133. }
  134. } else {
  135. int mask;
  136. const uint8_t* tab;
  137. uint32_t residue = v - 3;
  138. if (residue < (8 << 1)) { // VP8Cat3 (3b)
  139. AddToken(tokens, 0, base_id + 8, s + 8);
  140. AddToken(tokens, 0, base_id + 9, s + 9);
  141. residue -= (8 << 0);
  142. mask = 1 << 2;
  143. tab = VP8Cat3;
  144. } else if (residue < (8 << 2)) { // VP8Cat4 (4b)
  145. AddToken(tokens, 0, base_id + 8, s + 8);
  146. AddToken(tokens, 1, base_id + 9, s + 9);
  147. residue -= (8 << 1);
  148. mask = 1 << 3;
  149. tab = VP8Cat4;
  150. } else if (residue < (8 << 3)) { // VP8Cat5 (5b)
  151. AddToken(tokens, 1, base_id + 8, s + 8);
  152. AddToken(tokens, 0, base_id + 10, s + 9);
  153. residue -= (8 << 2);
  154. mask = 1 << 4;
  155. tab = VP8Cat5;
  156. } else { // VP8Cat6 (11b)
  157. AddToken(tokens, 1, base_id + 8, s + 8);
  158. AddToken(tokens, 1, base_id + 10, s + 9);
  159. residue -= (8 << 3);
  160. mask = 1 << 10;
  161. tab = VP8Cat6;
  162. }
  163. while (mask) {
  164. AddConstantToken(tokens, !!(residue & mask), *tab++);
  165. mask >>= 1;
  166. }
  167. }
  168. base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2
  169. s = res->stats[VP8EncBands[n]][2];
  170. }
  171. AddConstantToken(tokens, sign, 128);
  172. if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) {
  173. return 1; // EOB
  174. }
  175. }
  176. return 1;
  177. }
  178. #undef TOKEN_ID
  179. //------------------------------------------------------------------------------
  180. // Final coding pass, with known probabilities
  181. int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
  182. const uint8_t* const probas, int final_pass) {
  183. const VP8Tokens* p = b->pages_;
  184. assert(!b->error_);
  185. while (p != NULL) {
  186. const VP8Tokens* const next = p->next_;
  187. const int N = (next == NULL) ? b->left_ : 0;
  188. int n = b->page_size_;
  189. const token_t* const tokens = TOKEN_DATA(p);
  190. while (n-- > N) {
  191. const token_t token = tokens[n];
  192. const int bit = (token >> 15) & 1;
  193. if (token & FIXED_PROBA_BIT) {
  194. VP8PutBit(bw, bit, token & 0xffu); // constant proba
  195. } else {
  196. VP8PutBit(bw, bit, probas[token & 0x3fffu]);
  197. }
  198. }
  199. if (final_pass) WebPSafeFree((void*)p);
  200. p = next;
  201. }
  202. if (final_pass) b->pages_ = NULL;
  203. return 1;
  204. }
  205. // Size estimation
  206. size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
  207. size_t size = 0;
  208. const VP8Tokens* p = b->pages_;
  209. assert(!b->error_);
  210. while (p != NULL) {
  211. const VP8Tokens* const next = p->next_;
  212. const int N = (next == NULL) ? b->left_ : 0;
  213. int n = b->page_size_;
  214. const token_t* const tokens = TOKEN_DATA(p);
  215. while (n-- > N) {
  216. const token_t token = tokens[n];
  217. const int bit = token & (1 << 15);
  218. if (token & FIXED_PROBA_BIT) {
  219. size += VP8BitCost(bit, token & 0xffu);
  220. } else {
  221. size += VP8BitCost(bit, probas[token & 0x3fffu]);
  222. }
  223. }
  224. p = next;
  225. }
  226. return size;
  227. }
  228. //------------------------------------------------------------------------------
  229. #else // DISABLE_TOKEN_BUFFER
  230. void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
  231. (void)b;
  232. (void)page_size;
  233. }
  234. void VP8TBufferClear(VP8TBuffer* const b) {
  235. (void)b;
  236. }
  237. #endif // !DISABLE_TOKEN_BUFFER