Ejemplo n.º 1
0
        int VP8DecodeLayer(VP8Decoder* dec)
        {
            assert(dec);
              assert(dec.layer_data_size_ > 0);
              (void)dec;

              // TODO: handle enhancement layer here.

              return 1;
        }
Ejemplo n.º 2
0
        //------------------------------------------------------------------------------
        // 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)];
            }
              }
        }
Ejemplo n.º 3
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		int VP8SetError(VP8Decoder* dec, VP8StatusCode error, char * msg) {
		  dec.status_ = error;
		  dec.error_msg_ = msg;
		  dec.ready_ = 0;
		  return 0;
		}
Ejemplo n.º 4
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		void VP8Delete(VP8Decoder* dec) {
		  if (dec) {
			VP8Clear(dec);
			free(dec);
		  }
		}
Ejemplo n.º 5
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		char* VP8StatusMessage(VP8Decoder* dec) {
		  if (!dec) return "no object";
		  if (!dec.error_msg_) return "OK";
		  return dec.error_msg_;
		}
Ejemplo n.º 6
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		VP8StatusCode VP8Status(VP8Decoder* dec) {
		  if (!dec) return VP8_STATUS_INVALID_PARAM;
		  return dec.status_;
		}
Ejemplo n.º 7
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		//------------------------------------------------------------------------------
		// VP8Decoder

		static void SetOk(VP8Decoder* dec) {
		  dec.status_ = VP8_STATUS_OK;
		  dec.error_msg_ = "OK";
		}
Ejemplo n.º 8
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		// 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;
		}
Ejemplo n.º 9
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		// 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_;
		}
Ejemplo n.º 10
0
Archivo: vp8.cs Proyecto: soywiz/nwebp
		// 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
		}