mirror of
https://github.com/webmproject/libwebp.git
synced 2025-01-26 22:52:55 +01:00
parse one row of intra modes altogether
(instead of per-macroblock) speed unchanged. simplified the context-saving for incremental decoding Change-Id: I301be581bab581ff68de14c4ffe5bc0ec63f34be
This commit is contained in:
parent
a2f608f9e0
commit
bbc23ff34c
@ -72,15 +72,14 @@ struct WebPIDecoder {
|
||||
MemBuffer mem_; // input memory buffer.
|
||||
WebPDecBuffer output_; // output buffer (when no external one is supplied)
|
||||
size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
|
||||
|
||||
int last_mb_y_; // last row reached for intra-mode decoding
|
||||
};
|
||||
|
||||
// MB context to restore in case VP8DecodeMB() fails
|
||||
typedef struct {
|
||||
VP8MB left_;
|
||||
VP8MB info_;
|
||||
uint8_t intra_t_[4];
|
||||
uint8_t intra_l_[4];
|
||||
VP8BitReader br_;
|
||||
VP8BitReader token_br_;
|
||||
} MBContext;
|
||||
|
||||
@ -264,30 +263,16 @@ static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
|
||||
|
||||
static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
|
||||
MBContext* const context) {
|
||||
const VP8BitReader* const br = &dec->br_;
|
||||
const VP8MB* const left = dec->mb_info_ - 1;
|
||||
const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
|
||||
|
||||
context->left_ = *left;
|
||||
context->info_ = *info;
|
||||
context->br_ = *br;
|
||||
context->left_ = dec->mb_info_[-1];
|
||||
context->info_ = dec->mb_info_[dec->mb_x_];
|
||||
context->token_br_ = *token_br;
|
||||
memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
|
||||
memcpy(context->intra_l_, dec->intra_l_, 4);
|
||||
}
|
||||
|
||||
static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
|
||||
VP8BitReader* const token_br) {
|
||||
VP8BitReader* const br = &dec->br_;
|
||||
VP8MB* const left = dec->mb_info_ - 1;
|
||||
VP8MB* const info = dec->mb_info_ + dec->mb_x_;
|
||||
|
||||
*left = context->left_;
|
||||
*info = context->info_;
|
||||
*br = context->br_;
|
||||
dec->mb_info_[-1] = context->left_;
|
||||
dec->mb_info_[dec->mb_x_] = context->info_;
|
||||
*token_br = context->token_br_;
|
||||
memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
|
||||
memcpy(dec->intra_l_, context->intra_l_, 4);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -459,16 +444,26 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
|
||||
|
||||
assert(dec->ready_);
|
||||
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
|
||||
VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
|
||||
if (idec->last_mb_y_ != dec->mb_y_) {
|
||||
if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
|
||||
// note: normally, error shouldn't occur since we already have the whole
|
||||
// partition0 available here in DecodeRemaining(). Reaching EOF while
|
||||
// reading intra modes really means a BITSTREAM_ERROR.
|
||||
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
}
|
||||
idec->last_mb_y_ = dec->mb_y_;
|
||||
}
|
||||
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
|
||||
VP8BitReader* const token_br =
|
||||
&dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
|
||||
MBContext context;
|
||||
SaveContext(dec, token_br, &context);
|
||||
if (!VP8DecodeMB(dec, token_br)) {
|
||||
RestoreContext(&context, dec, token_br);
|
||||
// We shouldn't fail when MAX_MB data was available
|
||||
if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
|
||||
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
}
|
||||
RestoreContext(&context, dec, token_br);
|
||||
return VP8_STATUS_SUSPENDED;
|
||||
}
|
||||
// Release buffer only if there is only one partition
|
||||
@ -585,6 +580,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
||||
idec->state_ = STATE_WEBP_HEADER;
|
||||
idec->chunk_size_ = 0;
|
||||
|
||||
idec->last_mb_y_ = -1;
|
||||
|
||||
InitMemBuffer(&idec->mem_);
|
||||
WebPInitDecBuffer(&idec->output_);
|
||||
VP8InitIo(&idec->io_);
|
||||
|
@ -278,10 +278,23 @@ void VP8ResetProba(VP8Proba* const proba) {
|
||||
// proba->bands_[][] is initialized later
|
||||
}
|
||||
|
||||
void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_;
|
||||
static void ParseIntraMode(VP8BitReader* const br,
|
||||
VP8Decoder* const dec, int mb_x) {
|
||||
uint8_t* const top = dec->intra_t_ + 4 * mb_x;
|
||||
uint8_t* const left = dec->intra_l_;
|
||||
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
|
||||
VP8MBData* const block = dec->mb_data_ + mb_x;
|
||||
|
||||
// Note: we don't save segment map (yet), as we don't expect
|
||||
// to decode more than 1 keyframe.
|
||||
if (dec->segment_hdr_.update_map_) {
|
||||
// Hardcoded tree parsing
|
||||
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0])
|
||||
? VP8GetBit(br, dec->proba_.segments_[1])
|
||||
: 2 + VP8GetBit(br, dec->proba_.segments_[2]);
|
||||
} else {
|
||||
block->segment_ = 0; // default for intra
|
||||
}
|
||||
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_);
|
||||
|
||||
block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
|
||||
if (!block->is_i4x4_) {
|
||||
@ -332,6 +345,14 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
: VP8GetBit(br, 183) ? TM_PRED : H_PRED;
|
||||
}
|
||||
|
||||
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
int mb_x;
|
||||
for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
|
||||
ParseIntraMode(br, dec, mb_x);
|
||||
}
|
||||
return !dec->br_.eof_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Paragraph 13
|
||||
|
||||
|
@ -317,7 +317,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
|
||||
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_
|
||||
@ -479,8 +478,8 @@ static int ParseResiduals(VP8Decoder* const dec,
|
||||
VP8MB* const mb, VP8BitReader* const token_br) {
|
||||
VP8BandProbas (* const bands)[NUM_BANDS] = dec->proba_.bands_;
|
||||
const VP8BandProbas* ac_proba;
|
||||
const VP8QuantMatrix* const q = &dec->dqm_[dec->segment_];
|
||||
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
|
||||
const VP8QuantMatrix* const q = &dec->dqm_[block->segment_];
|
||||
int16_t* dst = block->coeffs_;
|
||||
VP8MB* const left_mb = dec->mb_info_ - 1;
|
||||
uint8_t tnz, lnz;
|
||||
@ -570,26 +569,10 @@ static int ParseResiduals(VP8Decoder* const dec,
|
||||
// Main loop
|
||||
|
||||
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
|
||||
VP8BitReader* const br = &dec->br_;
|
||||
VP8MB* const left = dec->mb_info_ - 1;
|
||||
VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
|
||||
VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
|
||||
int skip;
|
||||
|
||||
// Note: we don't save segment map (yet), as we don't expect
|
||||
// to decode more than 1 keyframe.
|
||||
if (dec->segment_hdr_.update_map_) {
|
||||
// Hardcoded tree parsing
|
||||
dec->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) ?
|
||||
VP8GetBit(br, dec->proba_.segments_[1]) :
|
||||
2 + VP8GetBit(br, dec->proba_.segments_[2]);
|
||||
}
|
||||
skip = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
|
||||
|
||||
VP8ParseIntraMode(br, dec);
|
||||
if (br->eof_) {
|
||||
return 0;
|
||||
}
|
||||
int skip = dec->use_skip_proba_ ? block->skip_ : 0;
|
||||
|
||||
if (!skip) {
|
||||
skip = ParseResiduals(dec, mb, token_br);
|
||||
@ -604,7 +587,7 @@ int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
|
||||
|
||||
if (dec->filter_type_ > 0) { // store filter info
|
||||
VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
|
||||
*finfo = dec->fstrengths_[dec->segment_][block->is_i4x4_];
|
||||
*finfo = dec->fstrengths_[block->segment_][block->is_i4x4_];
|
||||
finfo->f_inner_ |= !skip;
|
||||
}
|
||||
|
||||
@ -624,6 +607,10 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
|
||||
// Parse bitstream for this row.
|
||||
VP8BitReader* const token_br =
|
||||
&dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
|
||||
if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
|
||||
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
||||
"Premature end-of-partition0 encountered.");
|
||||
}
|
||||
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
|
||||
if (!VP8DecodeMB(dec, token_br)) {
|
||||
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
||||
|
@ -195,6 +195,8 @@ typedef struct {
|
||||
uint32_t non_zero_y_;
|
||||
uint32_t non_zero_uv_;
|
||||
uint8_t dither_; // local dithering strength (deduced from non_zero_*)
|
||||
uint8_t skip_;
|
||||
uint8_t segment_;
|
||||
} VP8MBData;
|
||||
|
||||
// Persistent information needed by the parallel processing
|
||||
@ -265,7 +267,6 @@ struct VP8Decoder {
|
||||
uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
|
||||
uint8_t intra_l_[4]; // left intra modes values
|
||||
|
||||
uint8_t segment_; // segment of the currently parsed block
|
||||
VP8TopSamples* yuv_t_; // top y/u/v samples
|
||||
|
||||
VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
|
||||
@ -313,7 +314,8 @@ int VP8SetError(VP8Decoder* const dec,
|
||||
// in tree.c
|
||||
void VP8ResetProba(VP8Proba* const proba);
|
||||
void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec);
|
||||
void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec);
|
||||
// parses one row of intra mode data in partition 0, returns !eof
|
||||
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
|
||||
|
||||
// in quant.c
|
||||
void VP8ParseQuant(VP8Decoder* const dec);
|
||||
|
Loading…
x
Reference in New Issue
Block a user