static void DeleteEncoder(VP8Encoder* enc) { if (enc) { VP8EncDeleteAlpha(enc); #if WEBP_EXPERIMENTAL_FEATURES VP8EncDeleteLayer(enc); #endif free(enc); } }
static void FinalizePSNR(VP8Encoder* enc) { WebPAuxStats* stats = enc.pic_.stats; ulong size = enc.sse_count_; ulong* sse = enc.sse_; stats.PSNR[0] = (float)GetPSNR(sse[0], size); stats.PSNR[1] = (float)GetPSNR(sse[1], size / 4); stats.PSNR[2] = (float)GetPSNR(sse[2], size / 4); stats.PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); }
void VP8IteratorInit(VP8Encoder* enc, VP8EncIterator* it) { it.enc_ = enc; it.y_stride_ = enc.pic_.y_stride; it.uv_stride_ = enc.pic_.uv_stride; // TODO(later): for multithreading, these should be owned by 'it'. it.yuv_in_ = enc.yuv_in_; it.yuv_out_ = enc.yuv_out_; it.yuv_out2_ = enc.yuv_out2_; it.yuv_p_ = enc.yuv_p_; it.lf_stats_ = enc.lf_stats_; it.percent0_ = enc.percent_; VP8IteratorReset(it); }
int WebPReportProgress(VP8Encoder* enc, int percent) { if (percent != enc.percent_) { WebPPicture* pic = enc.pic_; enc.percent_ = percent; if (pic.progress_hook && !pic.progress_hook(percent, pic)) { // user abort requested WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); return 0; } } return 1; // ok }
static void StoreStats(VP8Encoder* enc) { WebPAuxStats* stats = enc.pic_.stats; if (stats) { int i, s; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { stats.segment_level[i] = enc.dqm_[i].fstrength_; stats.segment_quant[i] = enc.dqm_[i].quant_; for (s = 0; s <= 2; ++s) { stats.residual_bytes[s][i] = enc.residual_bytes_[s][i]; } } FinalizePSNR(enc); stats.coded_size = enc.coded_size_; for (i = 0; i < 3; ++i) { stats.block_count[i] = enc.block_count_[i]; } } WebPReportProgress(enc, 100); // done! }
//------------------------------------------------------------------------------ // VP8Encoder //------------------------------------------------------------------------------ static void ResetSegmentHeader(VP8Encoder* enc) { VP8SegmentHeader* hdr = &enc.segment_hdr_; hdr.num_segments_ = enc.config_.segments; hdr.update_map_ = (hdr.num_segments_ > 1); hdr.size_ = 0; }
static void ResetFilterHeader(VP8Encoder* enc) { VP8FilterHeader* hdr = &enc.filter_hdr_; hdr.simple_ = 1; hdr.level_ = 0; hdr.sharpness_ = 0; hdr.i4x4_lf_delta_ = 0; }
static void ResetBoundaryPredictions(VP8Encoder* enc) { // init boundary values once for all // Note: actually, initializing the preds_[] is only needed for intra4. int i; byte* top = enc.preds_ - enc.preds_w_; byte* left = enc.preds_ - 1; for (i = -1; i < 4 * enc.mb_w_; ++i) { top[i] = B_DC_PRED; } for (i = 0; i < 4 * enc.mb_h_; ++i) { left[i * enc.preds_w_] = B_DC_PRED; } enc.nz_[-1] = 0; // constant }
// Map configured quality level to coding tools used. //-------------+---+---+---+---+---+---+ // Quality | 0 | 1 | 2 | 3 | 4 | 5 + //-------------+---+---+---+---+---+---+ // dynamic prob| ~ | x | x | x | x | x | //-------------+---+---+---+---+---+---+ // rd-opt modes| | | x | x | x | x | //-------------+---+---+---+---+---+---+ // fast i4/i16 | x | x | | | | | //-------------+---+---+---+---+---+---+ // rd-opt i4/16| | | x | x | x | x | //-------------+---+---+---+---+---+---+ // Trellis | | x | | | x | x | //-------------+---+---+---+---+---+---+ // full-SNS | | | | | | x | //-------------+---+---+---+---+---+---+ static void MapConfigToTools(VP8Encoder* enc) { int method = enc.config_.method; int limit = 100 - enc.config_.partition_limit; enc.method_ = method; enc.rd_opt_level_ = (method >= 6) ? 3 : (method >= 5) ? 2 : (method >= 3) ? 1 : 0; enc.max_i4_header_bits_ = 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. }
//------------------------------------------------------------------------------ // Simplified k-Means, to assign Nb segments based on alpha-histogram static void AssignSegments(VP8Encoder* enc, int alphas[256])
static int IsVP8XNeeded(VP8Encoder* enc) { return !!enc.has_alpha_; // Currently the only case when VP8X is needed. // This could change in the future. }