[FFmpeg-devel] [libav-devel] [PATCHv3] avcodec: Cineform HD Decoder

Vittorio Giovara vittorio.giovara at gmail.com
Mon Jan 25 17:51:43 CET 2016


On Sun, Jan 24, 2016 at 7:34 PM, Kieran Kunhya <kieran at kunhya.com> wrote:
> Decodes YUV 4:2:2 10-bit and RGB 12-bit files.
> Older files with more subbands, skips, Bayer, alpha not supported.
> Alpha requires addition of GBRAP12 pixel format.

Actually you could set AV_PIX_FMT_GBRAP16 and tweak the
bits_per_raw_sample, not sure about the repercussion on the users
though.

> ---
> +static av_cold int cfhd_decode_init(AVCodecContext *avctx)

is this function _decode or _init? or is it decoder_init? imho names
would be simpler with just <tag>_<action> scheme.

> +{
> +    CFHDContext *s = avctx->priv_data;
> +
> +    avctx->pix_fmt             = AV_PIX_FMT_YUV422P10;

if the decoder supports multiple pixel formats it's better not to
initialize the pixel format here, and wait until decode(). Otherwise
it's going to cause a "parameters changed" warning and reinit any
previous filter chain.

> +    avctx->bits_per_raw_sample = 10;
> +    s->avctx                   = avctx;
> +    avctx->width               = 0;
> +    avctx->height              = 0;

isn't the context mallocz anyway?

> +    return ff_cfhd_init_vlcs(s);
> +}
> +

> +static inline void filter(int16_t *output, ptrdiff_t out_stride, int16_t *low, ptrdiff_t low_stride,
> +                          int16_t *high, ptrdiff_t high_stride, int len, uint8_t clip)
> +{
> +    int16_t tmp;
> +
> +    int i;
> +    for (i = 0; i < len; i++) {
> +        if (i == 0) {
> +            tmp = (11*low[0*low_stride] - 4*low[1*low_stride] + low[2*low_stride] + 4) >> 3;
> +            output[(2*i+0)*out_stride] = (tmp + high[0*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+0)*out_stride] = av_clip_uintp2(output[(2*i+0)*out_stride], clip);
> +
> +            tmp = ( 5*low[0*low_stride] + 4*low[1*low_stride] - low[2*low_stride] + 4) >> 3;
> +            output[(2*i+1)*out_stride] = (tmp - high[0*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+1)*out_stride] = av_clip_uintp2(output[(2*i+1)*out_stride], clip);
> +        }
> +        else if (i == len-1){

nit, spacing and new line are still off

> +            tmp = ( 5*low[i*low_stride] + 4*low[(i-1)*low_stride] - low[(i-2)*low_stride] + 4) >> 3;
> +            output[(2*i+0)*out_stride] = (tmp + high[i*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+0)*out_stride] = av_clip_uintp2(output[(2*i+0)*out_stride], clip);
> +
> +            tmp = (11*low[i*low_stride] - 4*low[(i-1)*low_stride] + low[(i-2)*low_stride] + 4) >> 3;
> +            output[(2*i+1)*out_stride] = (tmp - high[i*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+1)*out_stride] = av_clip_uintp2(output[(2*i+1)*out_stride], clip);
> +        }
> +        else {
> +            tmp = (low[(i-1)*low_stride] - low[(i+1)*low_stride] + 4) >> 3;
> +            output[(2*i+0)*out_stride] = (tmp + low[i*low_stride] + high[i*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+0)*out_stride] = av_clip_uintp2(output[(2*i+0)*out_stride], clip);
> +
> +            tmp = (low[(i+1)*low_stride] - low[(i-1)*low_stride] + 4) >> 3;
> +            output[(2*i+1)*out_stride] = (tmp + low[i*low_stride] - high[i*high_stride]) >> 1;
> +            if (clip)
> +                output[(2*i+1)*out_stride] = av_clip_uintp2(output[(2*i+1)*out_stride], clip);
> +        }
> +    }
> +}

+1 on the dsp suggestion

> +}
> +
> +static int alloc_buffers(AVCodecContext *avctx)
> +{
> +    CFHDContext *s = avctx->priv_data;
> +    int i, j, k;
> +
> +    avctx->width = s->coded_width;
> +    avctx->height = s->coded_height;

I think ff_set_dimensions is the function you're looking for (make
sure to check its return value)

> +    avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift);

this again? :)

> +    for (i = 0; i < 3; i++) {
> +        int width = i ? avctx->width >> s->chroma_x_shift : avctx->width;
> +        int height = i ? avctx->height >> s->chroma_y_shift : avctx->height;

could these be candidates for AV_CEIL_RSHIFT?

> +        int stride = FFALIGN(width / 8, 8) * 8;
> +        int w8, h8, w4, h4, w2, h2;
> +        height = FFALIGN(height / 8, 2) * 8;
> +        s->plane[i].width = width;
> +        s->plane[i].height = height;
> +        s->plane[i].stride = stride;
> +
> +        w8 = FFALIGN(s->plane[i].width / 8, 8);
> +        h8 = FFALIGN(s->plane[i].height / 8, 2);
> +        w4 = w8 * 2;
> +        h4 = h8 * 2;
> +        w2 = w4 * 2;
> +        h2 = h4 * 2;
> +
> +        s->plane[i].idwt_buf = av_malloc(height * stride * sizeof(*s->plane[i].idwt_buf));
> +        s->plane[i].idwt_tmp = av_malloc(height * stride * sizeof(*s->plane[i].idwt_tmp));
> +        if (!s->plane[i].idwt_buf || !s->plane[i].idwt_tmp) {
> +            return AVERROR(ENOMEM);

need to av_freep both since you don't know which one failed

> +        }

> +            av_log(avctx, AV_LOG_DEBUG, "Start subband coeffs plane %i level %i codebook %i expected %i \n", s->channel_num, s->level, s->codebook, expected);
> +
> +            init_get_bits(&s->gb, gb.buffer, bytestream2_get_bytes_left(&gb) * 8);
> +            OPEN_READER(re, &s->gb);

i got bit by this too, this needs to go inside a {} block because this
macro initializes new variables, otherwise gcc will fail to compile

> +            if (!s->codebook) {
> +                for (;;) {

> +
> +            bytes = FFALIGN(FF_CEIL_RSHIFT(get_bits_count(&s->gb), 3), 4);

AV_CEIL_RSHIFT

> +            if (bytes > bytestream2_get_bytes_left(&gb)) {
> +                av_log(avctx, AV_LOG_ERROR, "Bitstream overread error \n");

the error message could be improved, since there can't be an overread
if safe bytestream2 is used

> +                ret = AVERROR(EINVAL);
> +                goto end;

> +
> +end:
> +    if (ret < 0)
> +        return ret;
> +
> +    *got_frame = 1;
> +    return avpkt->size;

avpkt->size - bytestream2_get_bytes_left(&gb) no?

> +}
> +
> +static av_cold int cfhd_close_decoder(AVCodecContext *avctx)
> +{
> +    CFHDContext *s = avctx->priv_data;
> +
> +    free_buffers(avctx);
> +
> +    if (!avctx->internal->is_copy) {
> +        ff_free_vlc(&s->vlc_9);
> +        ff_free_vlc(&s->vlc_18);
> +    }

these functions are just av_freep wrappers, you can call them without
the additional is_copy check I think

> +
> +end:
> +    if (ret < 0)
> +        ff_free_vlc(&s->vlc_9);

revising my previous suggestion, this is going to be cleaned by the
close function automatically, especially if is_copy check is removed,
you may just return ret where needed

-- 
Vittorio


More information about the ffmpeg-devel mailing list