tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

syntax_enc.c (12758B)


      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 // Header syntax writing
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include <assert.h>
     15 #include <stddef.h>
     16 
     17 #include "src/dec/common_dec.h"
     18 #include "src/webp/types.h"
     19 #include "src/enc/vp8i_enc.h"
     20 #include "src/utils/bit_writer_utils.h"
     21 #include "src/utils/utils.h"
     22 #include "src/webp/encode.h"
     23 #include "src/webp/format_constants.h"  // RIFF constants
     24 #include "src/webp/mux_types.h"         // ALPHA_FLAG
     25 
     26 //------------------------------------------------------------------------------
     27 // Helper functions
     28 
     29 static int IsVP8XNeeded(const VP8Encoder* const enc) {
     30  return !!enc->has_alpha;  // Currently the only case when VP8X is needed.
     31                            // This could change in the future.
     32 }
     33 
     34 static int PutPaddingByte(const WebPPicture* const pic) {
     35  const uint8_t pad_byte[1] = { 0 };
     36  return !!pic->writer(pad_byte, 1, pic);
     37 }
     38 
     39 //------------------------------------------------------------------------------
     40 // Writers for header's various pieces (in order of appearance)
     41 
     42 static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc,
     43                                       size_t riff_size) {
     44  const WebPPicture* const pic = enc->pic;
     45  uint8_t riff[RIFF_HEADER_SIZE] = {
     46    'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'
     47  };
     48  assert(riff_size == (uint32_t)riff_size);
     49  PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
     50  if (!pic->writer(riff, sizeof(riff), pic)) {
     51    return VP8_ENC_ERROR_BAD_WRITE;
     52  }
     53  return VP8_ENC_OK;
     54 }
     55 
     56 static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
     57  const WebPPicture* const pic = enc->pic;
     58  uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = {
     59    'V', 'P', '8', 'X'
     60  };
     61  uint32_t flags = 0;
     62 
     63  assert(IsVP8XNeeded(enc));
     64  assert(pic->width >= 1 && pic->height >= 1);
     65  assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
     66 
     67  if (enc->has_alpha) {
     68    flags |= ALPHA_FLAG;
     69  }
     70 
     71  PutLE32(vp8x + TAG_SIZE,              VP8X_CHUNK_SIZE);
     72  PutLE32(vp8x + CHUNK_HEADER_SIZE,     flags);
     73  PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
     74  PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
     75  if (!pic->writer(vp8x, sizeof(vp8x), pic)) {
     76    return VP8_ENC_ERROR_BAD_WRITE;
     77  }
     78  return VP8_ENC_OK;
     79 }
     80 
     81 static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) {
     82  const WebPPicture* const pic = enc->pic;
     83  uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = {
     84    'A', 'L', 'P', 'H'
     85  };
     86 
     87  assert(enc->has_alpha);
     88 
     89  // Alpha chunk header.
     90  PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size);
     91  if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) {
     92    return VP8_ENC_ERROR_BAD_WRITE;
     93  }
     94 
     95  // Alpha chunk data.
     96  if (!pic->writer(enc->alpha_data, enc->alpha_data_size, pic)) {
     97    return VP8_ENC_ERROR_BAD_WRITE;
     98  }
     99 
    100  // Padding.
    101  if ((enc->alpha_data_size & 1) && !PutPaddingByte(pic)) {
    102    return VP8_ENC_ERROR_BAD_WRITE;
    103  }
    104  return VP8_ENC_OK;
    105 }
    106 
    107 static WebPEncodingError PutVP8Header(const WebPPicture* const pic,
    108                                      size_t vp8_size) {
    109  uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = {
    110    'V', 'P', '8', ' '
    111  };
    112  assert(vp8_size == (uint32_t)vp8_size);
    113  PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size);
    114  if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) {
    115    return VP8_ENC_ERROR_BAD_WRITE;
    116  }
    117  return VP8_ENC_OK;
    118 }
    119 
    120 static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic,
    121                                           int profile, size_t size0) {
    122  uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE];
    123  uint32_t bits;
    124 
    125  if (size0 >= VP8_MAX_PARTITION0_SIZE) {  // partition #0 is too big to fit
    126    return VP8_ENC_ERROR_PARTITION0_OVERFLOW;
    127  }
    128 
    129  // Paragraph 9.1.
    130  bits = 0                         // keyframe (1b)
    131       | (profile << 1)            // profile (3b)
    132       | (1 << 4)                  // visible (1b)
    133       | ((uint32_t)size0 << 5);   // partition length (19b)
    134  vp8_frm_hdr[0] = (bits >>  0) & 0xff;
    135  vp8_frm_hdr[1] = (bits >>  8) & 0xff;
    136  vp8_frm_hdr[2] = (bits >> 16) & 0xff;
    137  // signature
    138  vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff;
    139  vp8_frm_hdr[4] = (VP8_SIGNATURE >>  8) & 0xff;
    140  vp8_frm_hdr[5] = (VP8_SIGNATURE >>  0) & 0xff;
    141  // dimensions
    142  vp8_frm_hdr[6] = pic->width & 0xff;
    143  vp8_frm_hdr[7] = pic->width >> 8;
    144  vp8_frm_hdr[8] = pic->height & 0xff;
    145  vp8_frm_hdr[9] = pic->height >> 8;
    146 
    147  if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) {
    148    return VP8_ENC_ERROR_BAD_WRITE;
    149  }
    150  return VP8_ENC_OK;
    151 }
    152 
    153 // WebP Headers.
    154 static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
    155                          size_t vp8_size, size_t riff_size) {
    156  WebPPicture* const pic = enc->pic;
    157  WebPEncodingError err = VP8_ENC_OK;
    158 
    159  // RIFF header.
    160  err = PutRIFFHeader(enc, riff_size);
    161  if (err != VP8_ENC_OK) goto Error;
    162 
    163  // VP8X.
    164  if (IsVP8XNeeded(enc)) {
    165    err = PutVP8XHeader(enc);
    166    if (err != VP8_ENC_OK) goto Error;
    167  }
    168 
    169  // Alpha.
    170  if (enc->has_alpha) {
    171    err = PutAlphaChunk(enc);
    172    if (err != VP8_ENC_OK) goto Error;
    173  }
    174 
    175  // VP8 header.
    176  err = PutVP8Header(pic, vp8_size);
    177  if (err != VP8_ENC_OK) goto Error;
    178 
    179  // VP8 frame header.
    180  err = PutVP8FrameHeader(pic, enc->profile, size0);
    181  if (err != VP8_ENC_OK) goto Error;
    182 
    183  // All OK.
    184  return 1;
    185 
    186  // Error.
    187 Error:
    188  return WebPEncodingSetError(pic, err);
    189 }
    190 
    191 // Segmentation header
    192 static void PutSegmentHeader(VP8BitWriter* const bw,
    193                             const VP8Encoder* const enc) {
    194  const VP8EncSegmentHeader* const hdr = &enc->segment_hdr;
    195  const VP8EncProba* const proba = &enc->proba;
    196  if (VP8PutBitUniform(bw, (hdr->num_segments > 1))) {
    197    // We always 'update' the quant and filter strength values
    198    const int update_data = 1;
    199    int s;
    200    VP8PutBitUniform(bw, hdr->update_map);
    201    if (VP8PutBitUniform(bw, update_data)) {
    202      // we always use absolute values, not relative ones
    203      VP8PutBitUniform(bw, 1);   // (segment_feature_mode = 1. Paragraph 9.3.)
    204      for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
    205        VP8PutSignedBits(bw, enc->dqm[s].quant, 7);
    206      }
    207      for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
    208        VP8PutSignedBits(bw, enc->dqm[s].fstrength, 6);
    209      }
    210    }
    211    if (hdr->update_map) {
    212      for (s = 0; s < 3; ++s) {
    213        if (VP8PutBitUniform(bw, (proba->segments[s] != 255u))) {
    214          VP8PutBits(bw, proba->segments[s], 8);
    215        }
    216      }
    217    }
    218  }
    219 }
    220 
    221 // Filtering parameters header
    222 static void PutFilterHeader(VP8BitWriter* const bw,
    223                            const VP8EncFilterHeader* const hdr) {
    224  const int use_lf_delta = (hdr->i4x4_lf_delta != 0);
    225  VP8PutBitUniform(bw, hdr->simple);
    226  VP8PutBits(bw, hdr->level, 6);
    227  VP8PutBits(bw, hdr->sharpness, 3);
    228  if (VP8PutBitUniform(bw, use_lf_delta)) {
    229    // '0' is the default value for i4x4_lf_delta at frame #0.
    230    const int need_update = (hdr->i4x4_lf_delta != 0);
    231    if (VP8PutBitUniform(bw, need_update)) {
    232      // we don't use ref_lf_delta => emit four 0 bits
    233      VP8PutBits(bw, 0, 4);
    234      // we use mode_lf_delta for i4x4
    235      VP8PutSignedBits(bw, hdr->i4x4_lf_delta, 6);
    236      VP8PutBits(bw, 0, 3);    // all others unused
    237    }
    238  }
    239 }
    240 
    241 // Nominal quantization parameters
    242 static void PutQuant(VP8BitWriter* const bw,
    243                     const VP8Encoder* const enc) {
    244  VP8PutBits(bw, enc->base_quant, 7);
    245  VP8PutSignedBits(bw, enc->dq_y1_dc, 4);
    246  VP8PutSignedBits(bw, enc->dq_y2_dc, 4);
    247  VP8PutSignedBits(bw, enc->dq_y2_ac, 4);
    248  VP8PutSignedBits(bw, enc->dq_uv_dc, 4);
    249  VP8PutSignedBits(bw, enc->dq_uv_ac, 4);
    250 }
    251 
    252 // Partition sizes
    253 static int EmitPartitionsSize(const VP8Encoder* const enc,
    254                              WebPPicture* const pic) {
    255  uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)];
    256  int p;
    257  for (p = 0; p < enc->num_parts - 1; ++p) {
    258    const size_t part_size = VP8BitWriterSize(enc->parts + p);
    259    if (part_size >= VP8_MAX_PARTITION_SIZE) {
    260      return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW);
    261    }
    262    buf[3 * p + 0] = (part_size >>  0) & 0xff;
    263    buf[3 * p + 1] = (part_size >>  8) & 0xff;
    264    buf[3 * p + 2] = (part_size >> 16) & 0xff;
    265  }
    266  if (p && !pic->writer(buf, 3 * p, pic)) {
    267    return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
    268  }
    269  return 1;
    270 }
    271 
    272 //------------------------------------------------------------------------------
    273 
    274 static int GeneratePartition0(VP8Encoder* const enc) {
    275  VP8BitWriter* const bw = &enc->bw;
    276  const int mb_size = enc->mb_w * enc->mb_h;
    277  uint64_t pos1, pos2, pos3;
    278 
    279  pos1 = VP8BitWriterPos(bw);
    280  if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) {        // ~7 bits per macroblock
    281    return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
    282  }
    283  VP8PutBitUniform(bw, 0);   // colorspace
    284  VP8PutBitUniform(bw, 0);   // clamp type
    285 
    286  PutSegmentHeader(bw, enc);
    287  PutFilterHeader(bw, &enc->filter_hdr);
    288  VP8PutBits(bw, enc->num_parts == 8 ? 3 :
    289                 enc->num_parts == 4 ? 2 :
    290                 enc->num_parts == 2 ? 1 : 0, 2);
    291  PutQuant(bw, enc);
    292  VP8PutBitUniform(bw, 0);   // no proba update
    293  VP8WriteProbas(bw, &enc->proba);
    294  pos2 = VP8BitWriterPos(bw);
    295  VP8CodeIntraModes(enc);
    296  VP8BitWriterFinish(bw);
    297 
    298  pos3 = VP8BitWriterPos(bw);
    299 
    300 #if !defined(WEBP_DISABLE_STATS)
    301  if (enc->pic->stats) {
    302    enc->pic->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
    303    enc->pic->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
    304    enc->pic->stats->alpha_data_size = (int)enc->alpha_data_size;
    305  }
    306 #else
    307  (void)pos1;
    308  (void)pos2;
    309  (void)pos3;
    310 #endif
    311  if (bw->error) {
    312    return WebPEncodingSetError(enc->pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
    313  }
    314  return 1;
    315 }
    316 
    317 void VP8EncFreeBitWriters(VP8Encoder* const enc) {
    318  int p;
    319  VP8BitWriterWipeOut(&enc->bw);
    320  for (p = 0; p < enc->num_parts; ++p) {
    321    VP8BitWriterWipeOut(enc->parts + p);
    322  }
    323 }
    324 
    325 int VP8EncWrite(VP8Encoder* const enc) {
    326  WebPPicture* const pic = enc->pic;
    327  VP8BitWriter* const bw = &enc->bw;
    328  const int task_percent = 19;
    329  const int percent_per_part = task_percent / enc->num_parts;
    330  const int final_percent = enc->percent + task_percent;
    331  int ok = 0;
    332  size_t vp8_size, pad, riff_size;
    333  int p;
    334 
    335  // Partition #0 with header and partition sizes
    336  ok = GeneratePartition0(enc);
    337  if (!ok) return 0;
    338 
    339  // Compute VP8 size
    340  vp8_size = VP8_FRAME_HEADER_SIZE +
    341             VP8BitWriterSize(bw) +
    342             3 * (enc->num_parts - 1);
    343  for (p = 0; p < enc->num_parts; ++p) {
    344    vp8_size += VP8BitWriterSize(enc->parts + p);
    345  }
    346  pad = vp8_size & 1;
    347  vp8_size += pad;
    348 
    349  // Compute RIFF size
    350  // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size.
    351  riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size;
    352  if (IsVP8XNeeded(enc)) {  // Add size for: VP8X header + data.
    353    riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
    354  }
    355  if (enc->has_alpha) {  // Add size for: ALPH header + data.
    356    const uint32_t padded_alpha_size = enc->alpha_data_size +
    357                                       (enc->alpha_data_size & 1);
    358    riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
    359  }
    360  // RIFF size should fit in 32-bits.
    361  if (riff_size > 0xfffffffeU) {
    362    return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
    363  }
    364 
    365  // Emit headers and partition #0
    366  {
    367    const uint8_t* const part0 = VP8BitWriterBuf(bw);
    368    const size_t size0 = VP8BitWriterSize(bw);
    369    ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
    370            && pic->writer(part0, size0, pic)
    371            && EmitPartitionsSize(enc, pic);
    372    VP8BitWriterWipeOut(bw);    // will free the internal buffer.
    373  }
    374 
    375  // Token partitions
    376  for (p = 0; p < enc->num_parts; ++p) {
    377    const uint8_t* const buf = VP8BitWriterBuf(enc->parts + p);
    378    const size_t size = VP8BitWriterSize(enc->parts + p);
    379    if (size) ok = ok && pic->writer(buf, size, pic);
    380    VP8BitWriterWipeOut(enc->parts + p);    // will free the internal buffer.
    381    ok = ok && WebPReportProgress(pic, enc->percent + percent_per_part,
    382                                  &enc->percent);
    383  }
    384 
    385  // Padding byte
    386  if (ok && pad) {
    387    ok = PutPaddingByte(pic);
    388  }
    389 
    390  enc->coded_size = (int)(CHUNK_HEADER_SIZE + riff_size);
    391  ok = ok && WebPReportProgress(pic, final_percent, &enc->percent);
    392  if (!ok) WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
    393  return ok;
    394 }
    395 
    396 //------------------------------------------------------------------------------