int VP8DecodeLayer(VP8Decoder* dec) { assert(dec); assert(dec.layer_data_size_ > 0); (void)dec; // TODO: handle enhancement layer here. return 1; }
//------------------------------------------------------------------------------ // Paragraph 9.6 void VP8ParseQuant(VP8Decoder* dec) { VP8BitReader* br = &dec.br_; int base_q0 = VP8GetValue(br, 7); int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; VP8SegmentHeader* hdr = &dec.segment_hdr_; int i; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { int q; if (hdr.use_segment_) { q = hdr.quantizer_[i]; if (!hdr.absolute_delta_) { q += base_q0; } } else { if (i > 0) { dec.dqm_[i] = dec.dqm_[0]; continue; } else { q = base_q0; } } { VP8QuantMatrix* m = &dec.dqm_[i]; m.y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)]; m.y1_mat_[1] = kAcTable[clip(q + 0, 127)]; m.y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; // TODO(skal): make it another table? m.y2_mat_[1] = kAcTable[clip(q + dqy2_ac, 127)] * 155 / 100; if (m.y2_mat_[1] < 8) m.y2_mat_[1] = 8; m.uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)]; m.uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)]; } } }
int VP8SetError(VP8Decoder* dec, VP8StatusCode error, char * msg) { dec.status_ = error; dec.error_msg_ = msg; dec.ready_ = 0; return 0; }
void VP8Delete(VP8Decoder* dec) { if (dec) { VP8Clear(dec); free(dec); } }
char* VP8StatusMessage(VP8Decoder* dec) { if (!dec) return "no object"; if (!dec.error_msg_) return "OK"; return dec.error_msg_; }
VP8StatusCode VP8Status(VP8Decoder* dec) { if (!dec) return VP8_STATUS_INVALID_PARAM; return dec.status_; }
//------------------------------------------------------------------------------ // VP8Decoder static void SetOk(VP8Decoder* dec) { dec.status_ = VP8_STATUS_OK; dec.error_msg_ = "OK"; }
// Topmost call int VP8GetHeaders(VP8Decoder* dec, VP8Io* io) { byte* buf; uint buf_size; byte* alpha_data_tmp; uint alpha_size_tmp; uint vp8_chunk_size; uint bytes_skipped; VP8FrameHeader* frm_hdr; VP8PictureHeader* pic_hdr; VP8BitReader* br; VP8StatusCode status; if (dec == null) { return 0; } SetOk(dec); if (io == null) { return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, "null VP8Io passed to VP8GetHeaders()"); } buf = io.data; buf_size = io.data_size; // Process Pre-VP8 chunks. status = WebPParseHeaders(&buf, &buf_size, &vp8_chunk_size, &bytes_skipped, &alpha_data_tmp, &alpha_size_tmp); if (status != VP8_STATUS_OK) { return VP8SetError(dec, status, "Incorrect/incomplete header."); } if (dec.alpha_data_ == null) { assert(dec.alpha_data_size_ == 0); // We have NOT set alpha data yet. Set it now. // (This is to ensure that dec.alpha_data_ is NOT reset to null if // WebPParseHeaders() is called more than once, as in incremental decoding // case.) dec.alpha_data_ = alpha_data_tmp; dec.alpha_data_size_ = alpha_size_tmp; } // Process the VP8 frame header. if (buf_size < 4) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Truncated header."); } // Paragraph 9.1 { uint bits = buf[0] | (buf[1] << 8) | (buf[2] << 16); frm_hdr = &dec.frm_hdr_; frm_hdr.key_frame_ = !(bits & 1); frm_hdr.profile_ = (bits >> 1) & 7; frm_hdr.show_ = (bits >> 4) & 1; frm_hdr.partition_length_ = (bits >> 5); if (frm_hdr.profile_ > 3) return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Incorrect keyframe parameters."); if (!frm_hdr.show_) return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Frame not displayable."); buf += 3; buf_size -= 3; } pic_hdr = &dec.pic_hdr_; if (frm_hdr.key_frame_) { // Paragraph 9.2 if (buf_size < 7) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "cannot parse picture header"); } if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Bad code word"); } pic_hdr.width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; pic_hdr.xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 pic_hdr.height_ = ((buf[6] << 8) | buf[5]) & 0x3fff; pic_hdr.yscale_ = buf[6] >> 6; buf += 7; buf_size -= 7; dec.mb_w_ = (pic_hdr.width_ + 15) >> 4; dec.mb_h_ = (pic_hdr.height_ + 15) >> 4; // Setup default output area (can be later modified during io.setup()) io.width = pic_hdr.width_; io.height = pic_hdr.height_; io.use_scaling = 0; io.use_cropping = 0; io.crop_top = 0; io.crop_left = 0; io.crop_right = io.width; io.crop_bottom = io.height; io.mb_w = io.width; // sanity check io.mb_h = io.height; // ditto VP8ResetProba(&dec.proba_); ResetSegmentHeader(&dec.segment_hdr_); dec.segment_ = 0; // default for intra } // Check if we have all the partition #0 available, and initialize dec.br_ // to read this partition (and this partition only). if (frm_hdr.partition_length_ > buf_size) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "bad partition length"); } br = &dec.br_; VP8InitBitReader(br, buf, buf + frm_hdr.partition_length_); buf += frm_hdr.partition_length_; buf_size -= frm_hdr.partition_length_; if (frm_hdr.key_frame_) { pic_hdr.colorspace_ = VP8Get(br); pic_hdr.clamp_type_ = VP8Get(br); } if (!ParseSegmentHeader(br, &dec.segment_hdr_, &dec.proba_)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "cannot parse segment header"); } // Filter specs if (!ParseFilterHeader(br, dec)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "cannot parse filter header"); } status = ParsePartitions(dec, buf, buf_size); if (status != VP8_STATUS_OK) { return VP8SetError(dec, status, "cannot parse partitions"); } // quantizer change VP8ParseQuant(dec); // Frame buffer marking if (!frm_hdr.key_frame_) { // Paragraph 9.7 #if !ONLY_KEYFRAME_CODE dec.buffer_flags_ = VP8Get(br) << 0; // update golden dec.buffer_flags_ |= VP8Get(br) << 1; // update alt ref if (!(dec.buffer_flags_ & 1)) { dec.buffer_flags_ |= VP8GetValue(br, 2) << 2; } if (!(dec.buffer_flags_ & 2)) { dec.buffer_flags_ |= VP8GetValue(br, 2) << 4; } dec.buffer_flags_ |= VP8Get(br) << 6; // sign bias golden dec.buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref #else return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Not a key frame."); #endif } else { dec.buffer_flags_ = 0x003 | 0x100; } // Paragraph 9.8 #if !ONLY_KEYFRAME_CODE dec.update_proba_ = VP8Get(br); if (!dec.update_proba_) { // save for later restore dec.proba_saved_ = dec.proba_; } dec.buffer_flags_ &= 1 << 8; dec.buffer_flags_ |= (frm_hdr.key_frame_ || VP8Get(br)) << 8; // refresh last frame #else VP8Get(br); // just ignore the value of update_proba_ #endif VP8ParseProba(br, dec); #if WEBP_EXPERIMENTAL_FEATURES // Extensions if (dec.pic_hdr_.colorspace_) { uint kTrailerSize = 8; byte kTrailerMarker = 0x01; byte* ext_buf = buf - kTrailerSize; uint size; if (frm_hdr.partition_length_ < kTrailerSize || ext_buf[kTrailerSize - 1] != kTrailerMarker) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "RIFF: Inconsistent extra information."); } // Layer size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16); dec.layer_data_size_ = size; dec.layer_data_ = null; // will be set later dec.layer_colorspace_ = ext_buf[3]; } #endif // sanitized state dec.ready_ = 1; return 1; }
// Paragraph 9.4 static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* dec) { VP8FilterHeader* hdr = &dec.filter_hdr_; hdr.simple_ = VP8Get(br); hdr.level_ = VP8GetValue(br, 6); hdr.sharpness_ = VP8GetValue(br, 3); hdr.use_lf_delta_ = VP8Get(br); if (hdr.use_lf_delta_) { if (VP8Get(br)) { // update lf-delta? int i; for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { if (VP8Get(br)) { hdr.ref_lf_delta_[i] = VP8GetSignedValue(br, 6); } } for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { if (VP8Get(br)) { hdr.mode_lf_delta_[i] = VP8GetSignedValue(br, 6); } } } } dec.filter_type_ = (hdr.level_ == 0) ? 0 : hdr.simple_ ? 1 : 2; if (dec.filter_type_ > 0) { // precompute filter levels per segment if (dec.segment_hdr_.use_segment_) { int s; for (s = 0; s < NUM_MB_SEGMENTS; ++s) { int strength = dec.segment_hdr_.filter_strength_[s]; if (!dec.segment_hdr_.absolute_delta_) { strength += hdr.level_; } dec.filter_levels_[s] = strength; } } else { dec.filter_levels_[0] = hdr.level_; } } return !br.eof_; }
// Paragraph 9.5 // This function returns VP8_STATUS_SUSPENDED if we don't have all the // necessary data in 'buf'. // This case is not necessarily an error (for incremental decoding). // Still, no bitreader is ever initialized to make it possible to read // unavailable memory. // If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA // is returned, and this is an unrecoverable error. // If the partitions were positioned ok, VP8_STATUS_OK is returned. static VP8StatusCode ParsePartitions(VP8Decoder* dec, byte* buf, uint size) { VP8BitReader* br = &dec.br_; byte* sz = buf; byte* buf_end = buf + size; byte* part_start; int last_part; int p; dec.num_parts_ = 1 << VP8GetValue(br, 2); last_part = dec.num_parts_ - 1; part_start = buf + last_part * 3; if (buf_end < part_start) { // we can't even read the sizes with sz[]! That's a failure. return VP8_STATUS_NOT_ENOUGH_DATA; } for (p = 0; p < last_part; ++p) { uint psize = sz[0] | (sz[1] << 8) | (sz[2] << 16); byte* part_end = part_start + psize; if (part_end > buf_end) part_end = buf_end; VP8InitBitReader(dec.parts_ + p, part_start, part_end); part_start = part_end; sz += 3; } VP8InitBitReader(dec.parts_ + last_part, part_start, buf_end); return (part_start < buf_end) ? VP8_STATUS_OK : VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data }