Home | History | Annotate | Download | only in enc
      1 // Copyright 2011 Google Inc.
      2 //
      3 // This code is licensed under the same terms as WebM:
      4 //  Software License Agreement:  http://www.webmproject.org/license/software/
      5 //  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
      6 // -----------------------------------------------------------------------------
      7 //
      8 // Header syntax writing
      9 //
     10 // Author: Skal (pascal.massimino (at) gmail.com)
     11 
     12 #include <assert.h>
     13 #include <math.h>
     14 
     15 #include "vp8enci.h"
     16 
     17 #if defined(__cplusplus) || defined(c_plusplus)
     18 extern "C" {
     19 #endif
     20 
     21 #define KSIGNATURE 0x9d012a
     22 #define KHEADER_SIZE 10
     23 #define KRIFF_SIZE 20
     24 #define KSIZE_OFFSET (KRIFF_SIZE - 8)
     25 
     26 #define MAX_PARTITION0_SIZE (1 << 19)   // max size of mode partition
     27 #define MAX_PARTITION_SIZE  (1 << 24)   // max size for token partition
     28 
     29 //-----------------------------------------------------------------------------
     30 // Writers for header's various pieces (in order of appearance)
     31 
     32 // Main keyframe header
     33 
     34 static void PutLE32(uint8_t* const data, uint32_t val) {
     35   data[0] = (val >>  0) & 0xff;
     36   data[1] = (val >>  8) & 0xff;
     37   data[2] = (val >> 16) & 0xff;
     38   data[3] = (val >> 24) & 0xff;
     39 }
     40 
     41 static int PutHeader(int profile, size_t size0, size_t total_size,
     42                      WebPPicture* const pic) {
     43   uint8_t buf[KHEADER_SIZE];
     44   uint8_t RIFF[KRIFF_SIZE] = {
     45     'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 'V', 'P', '8', ' '
     46   };
     47   uint32_t bits;
     48 
     49   if (size0 >= MAX_PARTITION0_SIZE) {  // partition #0 is too big to fit
     50     return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION0_OVERFLOW);
     51   }
     52 
     53   PutLE32(RIFF + 4, total_size + KSIZE_OFFSET);
     54   PutLE32(RIFF + 16, total_size);
     55   if (!pic->writer(RIFF, sizeof(RIFF), pic)) {
     56     return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
     57   }
     58 
     59   bits = 0               // keyframe (1b)
     60        | (profile << 1)  // profile (3b)
     61        | (1 << 4)        // visible (1b)
     62        | (size0 << 5);   // partition length (19b)
     63   buf[0] = bits & 0xff;
     64   buf[1] = (bits >> 8) & 0xff;
     65   buf[2] = (bits >> 16) & 0xff;
     66   // signature
     67   buf[3] = (KSIGNATURE >> 16) & 0xff;
     68   buf[4] = (KSIGNATURE >> 8) & 0xff;
     69   buf[5] = (KSIGNATURE >> 0) & 0xff;
     70   // dimensions
     71   buf[6] = pic->width & 0xff;
     72   buf[7] = pic->width >> 8;
     73   buf[8] = pic->height & 0xff;
     74   buf[9] = pic->height >> 8;
     75 
     76   return pic->writer(buf, sizeof(buf), pic);
     77 }
     78 
     79 // Segmentation header
     80 static void PutSegmentHeader(VP8BitWriter* const bw,
     81                              const VP8Encoder* const enc) {
     82   const VP8SegmentHeader* const hdr = &enc->segment_hdr_;
     83   const VP8Proba* const proba = &enc->proba_;
     84   if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) {
     85     // We always 'update' the quant and filter strength values
     86     const int update_data = 1;
     87     int s;
     88     VP8PutBitUniform(bw, hdr->update_map_);
     89     if (VP8PutBitUniform(bw, update_data)) {
     90       // we always use absolute values, not relative ones
     91       VP8PutBitUniform(bw, 1);   // (segment_feature_mode = 1. Paragraph 9.3.)
     92       for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
     93         VP8PutSignedValue(bw, enc->dqm_[s].quant_, 7);
     94       }
     95       for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
     96         VP8PutSignedValue(bw, enc->dqm_[s].fstrength_, 6);
     97       }
     98     }
     99     if (hdr->update_map_) {
    100       for (s = 0; s < 3; ++s) {
    101         if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) {
    102           VP8PutValue(bw, proba->segments_[s], 8);
    103         }
    104       }
    105     }
    106   }
    107 }
    108 
    109 // Filtering parameters header
    110 static void PutFilterHeader(VP8BitWriter* const bw,
    111                             const VP8FilterHeader* const hdr) {
    112   const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0);
    113   VP8PutBitUniform(bw, hdr->simple_);
    114   VP8PutValue(bw, hdr->level_, 6);
    115   VP8PutValue(bw, hdr->sharpness_, 3);
    116   if (VP8PutBitUniform(bw, use_lf_delta)) {
    117     // '0' is the default value for i4x4_lf_delta_ at frame #0.
    118     const int need_update = (hdr->i4x4_lf_delta_ != 0);
    119     if (VP8PutBitUniform(bw, need_update)) {
    120       // we don't use ref_lf_delta => emit four 0 bits
    121       VP8PutValue(bw, 0, 4);
    122       // we use mode_lf_delta for i4x4
    123       VP8PutSignedValue(bw, hdr->i4x4_lf_delta_, 6);
    124       VP8PutValue(bw, 0, 3);    // all others unused
    125     }
    126   }
    127 }
    128 
    129 // Nominal quantization parameters
    130 static void PutQuant(VP8BitWriter* const bw,
    131                      const VP8Encoder* const enc) {
    132   VP8PutValue(bw, enc->base_quant_, 7);
    133   VP8PutSignedValue(bw, enc->dq_y1_dc_, 4);
    134   VP8PutSignedValue(bw, enc->dq_y2_dc_, 4);
    135   VP8PutSignedValue(bw, enc->dq_y2_ac_, 4);
    136   VP8PutSignedValue(bw, enc->dq_uv_dc_, 4);
    137   VP8PutSignedValue(bw, enc->dq_uv_ac_, 4);
    138 }
    139 
    140 // Partition sizes
    141 static int EmitPartitionsSize(const VP8Encoder* const enc,
    142                               WebPPicture* const pic) {
    143   uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)];
    144   int p;
    145   for (p = 0; p < enc->num_parts_ - 1; ++p) {
    146     const size_t part_size = VP8BitWriterSize(enc->parts_ + p);
    147     if (part_size >= MAX_PARTITION_SIZE) {
    148       return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW);
    149     }
    150     buf[3 * p + 0] = (part_size >>  0) & 0xff;
    151     buf[3 * p + 1] = (part_size >>  8) & 0xff;
    152     buf[3 * p + 2] = (part_size >> 16) & 0xff;
    153   }
    154   return p ? pic->writer(buf, 3 * p, pic) : 1;
    155 }
    156 
    157 //-----------------------------------------------------------------------------
    158 
    159 #ifdef WEBP_EXPERIMENTAL_FEATURES
    160 
    161 #define KTRAILER_SIZE 8
    162 
    163 static void PutLE24(uint8_t* buf, size_t value) {
    164   buf[0] = (value >>  0) & 0xff;
    165   buf[1] = (value >>  8) & 0xff;
    166   buf[2] = (value >> 16) & 0xff;
    167 }
    168 
    169 static int WriteExtensions(VP8Encoder* const enc) {
    170   uint8_t buffer[KTRAILER_SIZE];
    171   VP8BitWriter* const bw = &enc->bw_;
    172   WebPPicture* const pic = enc->pic_;
    173 
    174   // Layer (bytes 0..3)
    175   PutLE24(buffer + 0, enc->layer_data_size_);
    176   buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK;
    177   if (enc->layer_data_size_ > 0) {
    178     assert(enc->use_layer_);
    179     // append layer data to last partition
    180     if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1],
    181                             enc->layer_data_, enc->layer_data_size_)) {
    182       return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
    183     }
    184   }
    185   // Alpha (bytes 4..6)
    186   PutLE24(buffer + 4, enc->alpha_data_size_);
    187   if (enc->alpha_data_size_ > 0) {
    188     assert(enc->has_alpha_);
    189     if (!VP8BitWriterAppend(bw, enc->alpha_data_, enc->alpha_data_size_)) {
    190       return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
    191     }
    192   }
    193 
    194   buffer[KTRAILER_SIZE - 1] = 0x01;  // marker
    195   if (!VP8BitWriterAppend(bw, buffer, KTRAILER_SIZE)) {
    196     return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
    197   }
    198   return 1;
    199 }
    200 
    201 #endif    /* WEBP_EXPERIMENTAL_FEATURES */
    202 
    203 //-----------------------------------------------------------------------------
    204 
    205 static size_t GeneratePartition0(VP8Encoder* const enc) {
    206   VP8BitWriter* const bw = &enc->bw_;
    207   const int mb_size = enc->mb_w_ * enc->mb_h_;
    208   uint64_t pos1, pos2, pos3;
    209 #ifdef WEBP_EXPERIMENTAL_FEATURES
    210   const int need_extensions = enc->has_alpha_ || enc->use_layer_;
    211 #endif
    212 
    213   pos1 = VP8BitWriterPos(bw);
    214   VP8BitWriterInit(bw, mb_size * 7 / 8);        // ~7 bits per macroblock
    215 #ifdef WEBP_EXPERIMENTAL_FEATURES
    216   VP8PutBitUniform(bw, need_extensions);   // extensions
    217 #else
    218   VP8PutBitUniform(bw, 0);   // colorspace
    219 #endif
    220   VP8PutBitUniform(bw, 0);   // clamp type
    221 
    222   PutSegmentHeader(bw, enc);
    223   PutFilterHeader(bw, &enc->filter_hdr_);
    224   VP8PutValue(bw, enc->config_->partitions, 2);
    225   PutQuant(bw, enc);
    226   VP8PutBitUniform(bw, 0);   // no proba update
    227   VP8WriteProbas(bw, &enc->proba_);
    228   pos2 = VP8BitWriterPos(bw);
    229   VP8CodeIntraModes(enc);
    230   VP8BitWriterFinish(bw);
    231 
    232 #ifdef WEBP_EXPERIMENTAL_FEATURES
    233   if (need_extensions && !WriteExtensions(enc)) {
    234     return 0;
    235   }
    236 #endif
    237 
    238   pos3 = VP8BitWriterPos(bw);
    239 
    240   if (enc->pic_->stats) {
    241     enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
    242     enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
    243     enc->pic_->stats->alpha_data_size = enc->alpha_data_size_;
    244     enc->pic_->stats->layer_data_size = enc->layer_data_size_;
    245   }
    246   return !bw->error_;
    247 }
    248 
    249 int VP8EncWrite(VP8Encoder* const enc) {
    250   WebPPicture* const pic = enc->pic_;
    251   VP8BitWriter* const bw = &enc->bw_;
    252   int ok = 0;
    253   size_t coded_size, pad;
    254   int p;
    255 
    256   // Partition #0 with header and partition sizes
    257   ok = GeneratePartition0(enc);
    258 
    259   // Compute total size (for the RIFF header)
    260   coded_size = KHEADER_SIZE + VP8BitWriterSize(bw) + 3 * (enc->num_parts_ - 1);
    261   for (p = 0; p < enc->num_parts_; ++p) {
    262     coded_size += VP8BitWriterSize(enc->parts_ + p);
    263   }
    264   pad = coded_size & 1;
    265   coded_size += pad;
    266 
    267   // Emit headers and partition #0
    268   {
    269     const uint8_t* const part0 = VP8BitWriterBuf(bw);
    270     const size_t size0 = VP8BitWriterSize(bw);
    271     ok = ok && PutHeader(enc->profile_, size0, coded_size, pic)
    272             && pic->writer(part0, size0, pic)
    273             && EmitPartitionsSize(enc, pic);
    274     free((void*)part0);
    275   }
    276 
    277   // Token partitions
    278   for (p = 0; p < enc->num_parts_; ++p) {
    279     const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p);
    280     const size_t size = VP8BitWriterSize(enc->parts_ + p);
    281     if (size)
    282       ok = ok && pic->writer(buf, size, pic);
    283     free((void*)buf);
    284   }
    285 
    286   // Padding byte
    287   if (ok && pad) {
    288     const uint8_t pad_byte[1] = { 0 };
    289     ok = pic->writer(pad_byte, 1, pic);
    290   }
    291 
    292   enc->coded_size_ = coded_size + KRIFF_SIZE;
    293   return ok;
    294 }
    295 
    296 //-----------------------------------------------------------------------------
    297 
    298 #if defined(__cplusplus) || defined(c_plusplus)
    299 }    // extern "C"
    300 #endif
    301