[FFmpeg-devel] [PATCH] Add XPM decoder

Paul B Mahol onemda at gmail.com
Sat Mar 11 14:36:24 EET 2017


On 3/11/17, Paras Chadha <paraschadha18 at gmail.com> wrote:
> Here is the patch with all the changes mentioned above
>
> Signed-off-by: Paras <paraschadha18 at gmail.com>
> ---
>  Changelog               |   1 +
>  doc/general.texi        |   2 +
>  libavcodec/Makefile     |   1 +
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 +
>  libavcodec/version.h    |   4 +-
>  libavcodec/xpmdec.c     | 430
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  libavformat/img2.c      |   1 +
>  9 files changed, 446 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/xpmdec.c
>

[...]

> +    { "NavajoWhite",          0xFFFFDEAD },
> +    { "Navy",                 0xFF000080 },
> +    { "None",                 0x00FFFFFF },

None is 0x00000000 AFAIK. Is it?

[...]

> +/*
> +**  functions same as strcspn but ignores characters in reject if they are
> inside a C style comment...
> +**  @param str, reject - same as that of strcspn
> +**  @return length till any character in reject does not occur in str
> +*/
> +static size_t mod_strcspn(const char *str, const char *rej)
> +{
> +    size_t v1, v2;
> +    const char * ptr = str, *temp;
> +
> +    v1 = strcspn(str, "/");
> +    v2 = strcspn(str, rej);
> +
> +    while (v1<v2) {
> +        ptr += v1+1;
> +        if (*(ptr)=='*') {
> +            if (temp = strstr(ptr, "*/")) {
> +                ptr = temp+2;
> +            } else {
> +                ptr++;
> +            }
> +        } else if (*(ptr)=='/') {
> +            if (temp = strstr(ptr, "\n")) {
> +                ptr = temp+1;
> +            } else {
> +                ptr++;
> +            }
> +        } else {
> +            ptr++;
> +        }
> +        v1 = strcspn(ptr, "/");
> +        v2 = strcspn(ptr, rej);
> +    }
> +
> +    return (size_t)(ptr-str)+v2;

This looks too complicated. Instead stole strcspn implementation and
do what it does
but also skip C comments.

[...]

 +
> +static int xpm_decode_frame(AVCodecContext *avctx, void *data,
> +                            int *got_frame, AVPacket *avpkt)
> +{
> +    XPMDecContext *x = avctx->priv_data;
> +    AVFrame *p=data;
> +    const uint8_t *end, *ptr = avpkt->data;
> +    int ncolors, cpp, ret, i, j;
> +    int64_t size;
> +    uint32_t *dst;
> +
> +    avctx->pix_fmt = AV_PIX_FMT_BGRA;
> +
> +    end = avpkt->data + avpkt->size;
> +    if (memcmp(ptr, "/* XPM */", 9)) {
> +        av_log(avctx, AV_LOG_ERROR, "missing signature\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    ptr += mod_strcspn(ptr, "\"");
> +    if (sscanf(ptr, "\"%u %u %u %u\",",
> +               &avctx->width, &avctx->height, &ncolors, &cpp) != 4) {
> +        av_log(avctx, AV_LOG_ERROR, "missing image parameters\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if ((ret = ff_set_dimensions(avctx, avctx->width, avctx->height)) < 0)
> +        return ret;
> +
> +    if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
> +        return ret;
> +
> +    if (ncolors <= 0) {
> +        av_log(avctx, AV_LOG_ERROR, "invalid number of colors: %d\n",
> ncolors);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if (cpp <= 0) {
> +        av_log(avctx, AV_LOG_ERROR, "invalid number of chars per pixel:
> %d\n", cpp);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    size = 1;
> +    j = 1;
> +    for (i=0;i<cpp;i++) {

style.

> +        size += j*94;
> +        j *= 95;
> +    }
> +    size *= 4;
> +
> +    if (size<0) {

Please follow style, spaces between '<' : if (size < 0) {...

> +        av_log(avctx, AV_LOG_ERROR, "unsupported number of chars per
> pixel: %d\n", cpp);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    av_fast_padded_malloc(&x->pixels, &x->pixels_size, size);
> +    if (!x->pixels)
> +        return AVERROR(ENOMEM);
> +
> +    ptr += mod_strcspn(ptr, ",") + 1;
> +    for (i = 0; i < ncolors; i++) {
> +
> +        const uint8_t *index;
> +        int len;
> +
> +        ptr += mod_strcspn(ptr, "\"") + 1;
> +        if (ptr + cpp > end)
> +            return AVERROR_INVALIDDATA;
> +        index = ptr;
> +        ptr += cpp;
> +
> +        ptr = strstr(ptr, "c ");
> +        if (ptr) {
> +            ptr += 2;
> +        } else {
> +            return AVERROR_INVALIDDATA;
> +        }
> +
> +        len = strcspn(ptr, "\" ");
> +
> +        if ((ret = ascii2index(index, cpp)) < 0)
> +            return ret;
> +
> +        x->pixels[ret] = hexstring_to_rgba(ptr, len);
> +
> +        ptr += mod_strcspn(ptr, ",") + 1;
> +    }
> +
> +    for (i = 0; i < avctx->height; i++) {
> +        dst = (uint32_t *)(p->data[0] + i * p->linesize[0]);
> +        ptr += mod_strcspn(ptr, "\"") + 1;
> +        for (j = 0; j < avctx->width; j++) {
> +            if (ptr + cpp > end)
> +                return AVERROR_INVALIDDATA;
> +            ret = ascii2index(ptr, cpp);

Check ret value, it can be negative.

> +            *dst++ = x->pixels[ret];
> +            ptr += cpp;
> +        }
> +        ptr += mod_strcspn(ptr, ",") + 1;
> +    }
> +
> +    p->key_frame = 1;
> +    p->pict_type = AV_PICTURE_TYPE_I;
> +
> +    *got_frame = 1;
> +    *(AVFrame *)data = *p;

This line is redundant.

> +
> +    return avpkt->size;
> +}
> +
> +static av_cold int xpm_decode_close(AVCodecContext *avctx)
> +{
> +    XPMDecContext *x = avctx->priv_data;
> +    av_freep(&x->pixels);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_xpm_decoder = {
> +    .name           = "xpm",
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_XPM,
> +    .priv_data_size = sizeof(XPMDecContext),
> +    .close          = xpm_decode_close,
> +    .decode         = xpm_decode_frame,
> +    .capabilities   = CODEC_CAP_DR1,
> +    .long_name      = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image")
> +};
> diff --git a/libavformat/img2.c b/libavformat/img2.c
> index f9f53ff..29df4f0 100644
> --- a/libavformat/img2.c
> +++ b/libavformat/img2.c
> @@ -75,6 +75,7 @@ const IdStrMap ff_img_tags[] = {
>      { AV_CODEC_ID_V210X,      "yuv10"    },
>      { AV_CODEC_ID_WEBP,       "webp"     },
>      { AV_CODEC_ID_XBM,        "xbm"      },
> +    { AV_CODEC_ID_XPM,        "xpm"      },
>      { AV_CODEC_ID_XFACE,      "xface"    },
>      { AV_CODEC_ID_XWD,        "xwd"      },
>      { AV_CODEC_ID_NONE,       NULL       }

Please also add xpm_pipe demuxer with its probe function.


More information about the ffmpeg-devel mailing list