[FFmpeg-devel] [RFC v5] libavcodec: add a native Daala decoder
Andreas Cadhalpun
andreas.cadhalpun at googlemail.com
Sun Jan 3 20:27:55 CET 2016
On 02.01.2016 18:56, Rostislav Pehlivanov wrote:
> --- /dev/null
> +++ b/libavcodec/daala_entropy.h
> @@ -0,0 +1,464 @@
[...]
> +/* Expectation value is in Q16 */
> +static inline int daalaent_decode_generic(DaalaEntropy *e, DaalaCDF *c, int *ex,
> + int max, int integrate)
> +{
> + int rval, lsb = 0, log_ex = daalaent_log_ex(*ex);
> + const int shift = FFMAX(0, (log_ex - 5) >> 1);
> + const int id = FFMIN(DAALAENT_MODEL_TAB - 1, log_ex);
> + const int ms = (max + (1 << shift >> 1)) >> shift;
> + int xs = (max == -1) ? 16 : FFMIN(ms + 1, 16);
> + ent_rng *cdf = &c->cdf[id*c->y];
> + if (!max)
> + return 0;
> + if ((xs = daalaent_decode_cdf(e, cdf, xs, 0, CDF_UNSCALED)) == 15) {
> + int g = ((2*(*ex) >> 8) + (1 << shift >> 1)) >> shift;
This can still overflow to -256 causing the following line to crash.
A first step towards fixing this would be to replace '2*(*ex) >> 8'
with '*ex >> 7'. That has the same result whenever the first expression
is not undefined and should be faster, as well. ;)
This prevents most of these crashes, but a few remain, because *ex
can already be negative here due to a previous overflow.
> + ent_win decay = FFMAX(2, FFMIN(254, 256*g/(g + 256)));
> + xs += daalaent_decode_laplace(e, decay, (max == -1) ? -1 : ms - 15);
> + }
> + if (shift) {
> + if (shift > !xs)
> + lsb = daalaent_decode_bits(e, shift - !xs);
> + lsb -= !!xs << (shift - 1);
> + }
> + rval = (xs << shift) + lsb;
> + daalaent_exp_model_update(c, ex, rval, xs, id, integrate);
> + return rval;
> +}
> --- /dev/null
> +++ b/libavcodec/daala_pvq.h
> @@ -0,0 +1,491 @@
[...]
> +static void daalapvq_decode_vector(DaalaEntropy *e, DaalaPVQ *pvq,
> + dctcoef *out, dctcoef *ref, const double beta,
> + uint8_t key_frame, int p, uint8_t *skip_rest,
> + uint8_t has_err, int band_idx,
> + int qm_off, enum DaalaBsize bsize)
> +{
> + int i, k;
> + int qg = 0, skip = 0, itheta = (!!key_frame), has_ref = !key_frame;
> + double qcg, gain, theta = 0.0f, gr = 0.0f, gain_off = 0.0f;
> + dctcoef tmp[DAALAPVQ_MAX_PART_SIZE] = {0};
> +
> + const int robust = has_err || key_frame;
> + const int band_len = pvq->size[band_idx];
> + const int16_t *qmatrix = &pvq->qmatrix[qm_off];
> + const int16_t *qmatrix_inv = &pvq->qmatrix_inv[qm_off];
> +
> + if (!skip_rest[(band_idx + 2) % 3]) {
> + int iloc = (!!p)*DAALA_NBSIZES*DAALAPVQ_PARTITIONS_MAX + bsize*DAALAPVQ_PARTITIONS_MAX + band_idx;
> + i = daalaent_decode_cdf_adapt(e, &pvq->pvqtheta_gain_cdf, iloc, 8 + 7*pvq->skip[band_idx]);
> + if (!key_frame && i >= 10)
> + i++;
> + if (key_frame && i >= 8)
> + i++;
> + if (i >= 8) {
> + i -= 8;
> + skip_rest[0] = skip_rest[1] = skip_rest[2] = 1;
> + }
> + qg = i & 1;
> + itheta = (i >> 1) - 1;
> + has_ref = !(itheta == -1);
> + }
> + if (qg) {
> + int *ex = pvq->pvqgain_ex[p][bsize] + band_idx, ex_tmp = *ex;
> + DaalaCDF *mcdf = has_ref ? &pvq->pvqgain_ref_mcdf : &pvq->pvqgain_noref_mcdf;
> + qg = 1 + daalaent_decode_generic(e, mcdf, &ex_tmp, -1, 2);
> + *ex += ((qg << 16) - *ex) >> 2;
Here is the other overflow that can cause above crash.
To avoid this problem, this line could be replaced with:
*ex += (qg << 14) - (*ex >> 2);
This illustrates quite well why I think that overflows should be fixed
if reasonably possible, as they can cause weird problems in different
parts of the code.
> --- /dev/null
> +++ b/libavcodec/daaladec.c
> @@ -0,0 +1,824 @@
[...]
> +static int daala_decode_frame(AVCodecContext *avctx, void *data,
> + int *got_frame, AVPacket *avpkt)
> +{
> + int i, j, p, ret;
> + AVFrame *frame = data;
> + DaalaContext *s = avctx->priv_data;
The width, height and pixel format can change in the middle of a stream,
which currently causes segmentation faults due to out of bounds
reads/writes.
It's probably possible to re-initialize the decoder for the new values,
but until that is implemented there should be a check here preventing
the crashes, e.g.:
if (avctx->width > s->width || avctx->height > s->height || avctx->pix_fmt != s->fmt->fmt) {
av_log(avctx, AV_LOG_ERROR, "reinit not yet implemented (s:%dx%d %s; c:%dx%d %s)\n",
s->width, s->height, av_get_pix_fmt_name(s->fmt->fmt),
avctx->width, avctx->height, av_get_pix_fmt_name(avctx->pix_fmt));
return AVERROR_PATCHWELCOME;
}
> --- /dev/null
> +++ b/libavcodec/daaladsp.c
> @@ -0,0 +1,1890 @@
The code in this file still overflows quite often, but fixing above overflows
also fixes a few of these. So maybe fixing all overflows outside this file
will magically fix the overflows seen here, but that has to be investigated first.
So I suggest to add a TODO comment here to look into/fix these overflows.
If they turn out not to be reasonably fixable the comment could be replaced
with an explanation of that.
Best regards,
Andreas
More information about the ffmpeg-devel
mailing list