[FFmpeg-devel] [libav-devel] [PATCHv3] avcodec: Cineform HD Decoder
Kieran Kunhya
kieran618 at googlemail.com
Tue Jan 26 00:15:54 CET 2016
On Mon, Jan 25, 2016 at 4:51 PM, Vittorio Giovara
<vittorio.giovara at gmail.com> wrote:
> 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.
Dunno was told to do that.
>> +{
>> + 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.
There are some samples which don't have a pixel format flagged and are
implicitly AV_PIX_FMT_YUV422P10.
>> + avctx->bits_per_raw_sample = 10;
>> + s->avctx = avctx;
>> + avctx->width = 0;
>> + avctx->height = 0;
>
> isn't the context mallocz anyway?
No it's allocated from the demuxer
>> + 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
Fixed this properly by freeing all the planes if the function fails
>> + }
>
>> + 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?
Guaranteed to read all tags.
>
>> +}
>> +
>> +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
Crashes with frame threads otherwise
>> +
>> +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
If you say so.
Kieran
More information about the ffmpeg-devel
mailing list