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@gmail.com) 11 12#include <assert.h> 13#include <math.h> 14 15#include "vp8enci.h" 16 17#if defined(__cplusplus) || defined(c_plusplus) 18extern "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 34static 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 41static int PutHeader(int profile, size_t size0, size_t total_size, 42 const 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) { 50 return 0; // partition #0 is too big to fit 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 0; 57 58 bits = 0 // keyframe (1b) 59 | (profile << 1) // profile (3b) 60 | (1 << 4) // visible (1b) 61 | (size0 << 5); // partition length (19b) 62 buf[0] = bits & 0xff; 63 buf[1] = (bits >> 8) & 0xff; 64 buf[2] = (bits >> 16) & 0xff; 65 // signature 66 buf[3] = (KSIGNATURE >> 16) & 0xff; 67 buf[4] = (KSIGNATURE >> 8) & 0xff; 68 buf[5] = (KSIGNATURE >> 0) & 0xff; 69 // dimensions 70 buf[6] = pic->width & 0xff; 71 buf[7] = pic->width >> 8; 72 buf[8] = pic->height & 0xff; 73 buf[9] = pic->height >> 8; 74 75 return pic->writer(buf, sizeof(buf), pic); 76} 77 78// Segmentation header 79static void PutSegmentHeader(VP8BitWriter* const bw, 80 const VP8Encoder* const enc) { 81 const VP8SegmentHeader* const hdr = &enc->segment_hdr_; 82 const VP8Proba* const proba = &enc->proba_; 83 if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) { 84 // We always 'update' the quant and filter strength values 85 const int update_data = 1; 86 int s; 87 VP8PutBitUniform(bw, hdr->update_map_); 88 if (VP8PutBitUniform(bw, update_data)) { 89 // we always use absolute values, not relative ones 90 VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.) 91 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { 92 VP8PutSignedValue(bw, enc->dqm_[s].quant_, 7); 93 } 94 for (s = 0; s < NUM_MB_SEGMENTS; ++s) { 95 VP8PutSignedValue(bw, enc->dqm_[s].fstrength_, 6); 96 } 97 } 98 if (hdr->update_map_) { 99 for (s = 0; s < 3; ++s) { 100 if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) { 101 VP8PutValue(bw, proba->segments_[s], 8); 102 } 103 } 104 } 105 } 106} 107 108// Filtering parameters header 109static void PutFilterHeader(VP8BitWriter* const bw, 110 const VP8FilterHeader* const hdr) { 111 const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0); 112 VP8PutBitUniform(bw, hdr->simple_); 113 VP8PutValue(bw, hdr->level_, 6); 114 VP8PutValue(bw, hdr->sharpness_, 3); 115 if (VP8PutBitUniform(bw, use_lf_delta)) { 116 // '0' is the default value for i4x4_lf_delta_ at frame #0. 117 const int need_update = (hdr->i4x4_lf_delta_ != 0); 118 if (VP8PutBitUniform(bw, need_update)) { 119 // we don't use ref_lf_delta => emit four 0 bits 120 VP8PutValue(bw, 0, 4); 121 // we use mode_lf_delta for i4x4 122 VP8PutSignedValue(bw, hdr->i4x4_lf_delta_, 6); 123 VP8PutValue(bw, 0, 3); // all others unused 124 } 125 } 126} 127 128// Nominal quantization parameters 129static void PutQuant(VP8BitWriter* const bw, 130 const VP8Encoder* const enc) { 131 VP8PutValue(bw, enc->base_quant_, 7); 132 VP8PutSignedValue(bw, enc->dq_y1_dc_, 4); 133 VP8PutSignedValue(bw, enc->dq_y2_dc_, 4); 134 VP8PutSignedValue(bw, enc->dq_y2_ac_, 4); 135 VP8PutSignedValue(bw, enc->dq_uv_dc_, 4); 136 VP8PutSignedValue(bw, enc->dq_uv_ac_, 4); 137} 138 139// Partition sizes 140static int EmitPartitionsSize(const VP8Encoder* const enc, 141 const WebPPicture* const pic) { 142 uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; 143 int p; 144 for (p = 0; p < enc->num_parts_ - 1; ++p) { 145 const size_t part_size = VP8BitWriterSize(enc->parts_ + p); 146 if (part_size >= MAX_PARTITION_SIZE) { 147 return 0; // partition is too big to fit 148 } 149 buf[3 * p + 0] = (part_size >> 0) & 0xff; 150 buf[3 * p + 1] = (part_size >> 8) & 0xff; 151 buf[3 * p + 2] = (part_size >> 16) & 0xff; 152 } 153 return p ? pic->writer(buf, 3 * p, pic) : 1; 154} 155 156//----------------------------------------------------------------------------- 157 158static size_t GeneratePartition0(VP8Encoder* const enc) { 159 VP8BitWriter* const bw = &enc->bw_; 160 const int mb_size = enc->mb_w_ * enc->mb_h_; 161 uint64_t pos1, pos2, pos3; 162 163 pos1 = VP8BitWriterPos(bw); 164 VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock 165 VP8PutBitUniform(bw, 0); // colorspace 166 VP8PutBitUniform(bw, 0); // clamp type 167 168 PutSegmentHeader(bw, enc); 169 PutFilterHeader(bw, &enc->filter_hdr_); 170 VP8PutValue(bw, enc->config_->partitions, 2); 171 PutQuant(bw, enc); 172 VP8PutBitUniform(bw, 0); // no proba update 173 VP8WriteProbas(bw, &enc->proba_); 174 pos2 = VP8BitWriterPos(bw); 175 VP8CodeIntraModes(enc); 176 VP8BitWriterFinish(bw); 177 pos3 = VP8BitWriterPos(bw); 178 179 if (enc->pic_->stats) { 180 enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); 181 enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); 182 } 183 return !bw->error_; 184} 185 186int VP8EncWrite(VP8Encoder* const enc) { 187 WebPPicture* const pic = enc->pic_; 188 VP8BitWriter* const bw = &enc->bw_; 189 int ok = 0; 190 size_t coded_size, pad; 191 int p; 192 193 // Partition #0 with header and partition sizes 194 ok = GeneratePartition0(enc); 195 196 // Compute total size (for the RIFF header) 197 coded_size = KHEADER_SIZE + VP8BitWriterSize(bw) + 3 * (enc->num_parts_ - 1); 198 for (p = 0; p < enc->num_parts_; ++p) { 199 coded_size += VP8BitWriterSize(enc->parts_ + p); 200 } 201 pad = coded_size & 1; 202 coded_size += pad; 203 204 // Emit headers and partition #0 205 { 206 const uint8_t* const part0 = VP8BitWriterBuf(bw); 207 const size_t size0 = VP8BitWriterSize(bw); 208 ok = ok && PutHeader(enc->profile_, size0, coded_size, pic) 209 && pic->writer(part0, size0, pic) 210 && EmitPartitionsSize(enc, pic); 211 free((void*)part0); 212 } 213 214 // Token partitions 215 for (p = 0; p < enc->num_parts_; ++p) { 216 const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); 217 const size_t size = VP8BitWriterSize(enc->parts_ + p); 218 if (size) 219 ok = ok && pic->writer(buf, size, pic); 220 free((void*)buf); 221 } 222 223 // Padding byte 224 if (ok && pad) { 225 const uint8_t pad_byte[1] = { 0 }; 226 ok = pic->writer(pad_byte, 1, pic); 227 } 228 229 enc->coded_size_ = coded_size + KRIFF_SIZE; 230 return ok; 231} 232 233//----------------------------------------------------------------------------- 234 235#if defined(__cplusplus) || defined(c_plusplus) 236} // extern "C" 237#endif 238