token.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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.h"
  22. #include "./vp8enci.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
  29. // bit #14: 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) ((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. const VP8Tokens* p = b->pages_;
  49. while (p != NULL) {
  50. const VP8Tokens* const next = p->next_;
  51. WebPSafeFree((void*)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. const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t);
  60. if (!b->error_) {
  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_DATA(page);
  72. return 1;
  73. }
  74. //------------------------------------------------------------------------------
  75. #define TOKEN_ID(t, b, ctx, p) \
  76. ((p) + NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t))))
  77. static WEBP_INLINE int AddToken(VP8TBuffer* const b,
  78. int bit, uint32_t proba_idx) {
  79. assert(proba_idx < FIXED_PROBA_BIT);
  80. assert(bit == 0 || bit == 1);
  81. if (b->left_ > 0 || TBufferNewPage(b)) {
  82. const int slot = --b->left_;
  83. b->tokens_[slot] = (bit << 15) | proba_idx;
  84. }
  85. return bit;
  86. }
  87. static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
  88. int bit, int proba) {
  89. assert(proba < 256);
  90. assert(bit == 0 || bit == 1);
  91. if (b->left_ > 0 || TBufferNewPage(b)) {
  92. const int slot = --b->left_;
  93. b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
  94. }
  95. }
  96. int VP8RecordCoeffTokens(int ctx, int coeff_type, int first, int last,
  97. const int16_t* const coeffs,
  98. VP8TBuffer* const tokens) {
  99. int n = first;
  100. uint32_t base_id = TOKEN_ID(coeff_type, n, ctx, 0);
  101. if (!AddToken(tokens, last >= 0, base_id + 0)) {
  102. return 0;
  103. }
  104. while (n < 16) {
  105. const int c = coeffs[n++];
  106. const int sign = c < 0;
  107. int v = sign ? -c : c;
  108. if (!AddToken(tokens, v != 0, base_id + 1)) {
  109. ctx = 0;
  110. base_id = TOKEN_ID(coeff_type, VP8EncBands[n], ctx, 0);
  111. continue;
  112. }
  113. if (!AddToken(tokens, v > 1, base_id + 2)) {
  114. ctx = 1;
  115. } else {
  116. if (!AddToken(tokens, v > 4, base_id + 3)) {
  117. if (AddToken(tokens, v != 2, base_id + 4))
  118. AddToken(tokens, v == 4, base_id + 5);
  119. } else if (!AddToken(tokens, v > 10, base_id + 6)) {
  120. if (!AddToken(tokens, v > 6, base_id + 7)) {
  121. AddConstantToken(tokens, v == 6, 159);
  122. } else {
  123. AddConstantToken(tokens, v >= 9, 165);
  124. AddConstantToken(tokens, !(v & 1), 145);
  125. }
  126. } else {
  127. int mask;
  128. const uint8_t* tab;
  129. if (v < 3 + (8 << 1)) { // VP8Cat3 (3b)
  130. AddToken(tokens, 0, base_id + 8);
  131. AddToken(tokens, 0, base_id + 9);
  132. v -= 3 + (8 << 0);
  133. mask = 1 << 2;
  134. tab = VP8Cat3;
  135. } else if (v < 3 + (8 << 2)) { // VP8Cat4 (4b)
  136. AddToken(tokens, 0, base_id + 8);
  137. AddToken(tokens, 1, base_id + 9);
  138. v -= 3 + (8 << 1);
  139. mask = 1 << 3;
  140. tab = VP8Cat4;
  141. } else if (v < 3 + (8 << 3)) { // VP8Cat5 (5b)
  142. AddToken(tokens, 1, base_id + 8);
  143. AddToken(tokens, 0, base_id + 10);
  144. v -= 3 + (8 << 2);
  145. mask = 1 << 4;
  146. tab = VP8Cat5;
  147. } else { // VP8Cat6 (11b)
  148. AddToken(tokens, 1, base_id + 8);
  149. AddToken(tokens, 1, base_id + 10);
  150. v -= 3 + (8 << 3);
  151. mask = 1 << 10;
  152. tab = VP8Cat6;
  153. }
  154. while (mask) {
  155. AddConstantToken(tokens, !!(v & mask), *tab++);
  156. mask >>= 1;
  157. }
  158. }
  159. ctx = 2;
  160. }
  161. AddConstantToken(tokens, sign, 128);
  162. base_id = TOKEN_ID(coeff_type, VP8EncBands[n], ctx, 0);
  163. if (n == 16 || !AddToken(tokens, n <= last, base_id + 0)) {
  164. return 1; // EOB
  165. }
  166. }
  167. return 1;
  168. }
  169. #undef TOKEN_ID
  170. //------------------------------------------------------------------------------
  171. // This function works, but isn't currently used. Saved for later.
  172. #if 0
  173. static void Record(int bit, proba_t* const stats) {
  174. proba_t p = *stats;
  175. if (p >= 0xffff0000u) { // an overflow is inbound.
  176. p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
  177. }
  178. // record bit count (lower 16 bits) and increment total count (upper 16 bits).
  179. p += 0x00010000u + bit;
  180. *stats = p;
  181. }
  182. void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats) {
  183. const VP8Tokens* p = b->pages_;
  184. while (p != NULL) {
  185. const int N = (p->next_ == NULL) ? b->left_ : 0;
  186. int n = MAX_NUM_TOKEN;
  187. const token_t* const tokens = TOKEN_DATA(p);
  188. while (n-- > N) {
  189. const token_t token = tokens[n];
  190. if (!(token & FIXED_PROBA_BIT)) {
  191. Record((token >> 15) & 1, stats + (token & 0x3fffu));
  192. }
  193. }
  194. p = p->next_;
  195. }
  196. }
  197. #endif // 0
  198. //------------------------------------------------------------------------------
  199. // Final coding pass, with known probabilities
  200. int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
  201. const uint8_t* const probas, int final_pass) {
  202. const VP8Tokens* p = b->pages_;
  203. (void)final_pass;
  204. assert(!b->error_);
  205. while (p != NULL) {
  206. const VP8Tokens* const next = p->next_;
  207. const int N = (next == NULL) ? b->left_ : 0;
  208. int n = b->page_size_;
  209. const token_t* const tokens = TOKEN_DATA(p);
  210. while (n-- > N) {
  211. const token_t token = tokens[n];
  212. const int bit = (token >> 15) & 1;
  213. if (token & FIXED_PROBA_BIT) {
  214. VP8PutBit(bw, bit, token & 0xffu); // constant proba
  215. } else {
  216. VP8PutBit(bw, bit, probas[token & 0x3fffu]);
  217. }
  218. }
  219. if (final_pass) WebPSafeFree((void*)p);
  220. p = next;
  221. }
  222. if (final_pass) b->pages_ = NULL;
  223. return 1;
  224. }
  225. // Size estimation
  226. size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
  227. size_t size = 0;
  228. const VP8Tokens* p = b->pages_;
  229. assert(!b->error_);
  230. while (p != NULL) {
  231. const VP8Tokens* const next = p->next_;
  232. const int N = (next == NULL) ? b->left_ : 0;
  233. int n = b->page_size_;
  234. const token_t* const tokens = TOKEN_DATA(p);
  235. while (n-- > N) {
  236. const token_t token = tokens[n];
  237. const int bit = token & (1 << 15);
  238. if (token & FIXED_PROBA_BIT) {
  239. size += VP8BitCost(bit, token & 0xffu);
  240. } else {
  241. size += VP8BitCost(bit, probas[token & 0x3fffu]);
  242. }
  243. }
  244. p = next;
  245. }
  246. return size;
  247. }
  248. //------------------------------------------------------------------------------
  249. #else // DISABLE_TOKEN_BUFFER
  250. void VP8TBufferInit(VP8TBuffer* const b) {
  251. (void)b;
  252. }
  253. void VP8TBufferClear(VP8TBuffer* const b) {
  254. (void)b;
  255. }
  256. #endif // !DISABLE_TOKEN_BUFFER