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