[FFmpeg-devel] [PATCH] avformat: Add image3 demuxers with format autodetection

wm4 nfxjfg at googlemail.com
Mon Jun 30 21:53:46 CEST 2014


On Mon, 30 Jun 2014 03:44:17 +0200
Michael Niedermayer <michaelni at gmx.at> wrote:

> From: Carl Eugen Hoyos <cehoyos at ag.or.at>
> 
> Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> ---
>  Changelog                |    1 +
>  libavformat/Makefile     |    8 +++
>  libavformat/allformats.c |   11 ++++
>  libavformat/img2dec.c    |  137 +++++++++++++++++++++++++++++++++++++++++++++-
>  libavformat/version.h    |    2 +-
>  5 files changed, 157 insertions(+), 2 deletions(-)
> 
> diff --git a/Changelog b/Changelog
> index 0346877..3013c25 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -30,6 +30,7 @@ version <next>:
>  - zoompan filter
>  - signalstats filter
>  - hqx filter (hq2x, hq3x, hq4x)
> +- Image format auto-detection
>  
>  
>  version 2.2:
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 46aac96..857bfbb 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -187,6 +187,14 @@ OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER)        += img2dec.o img2.o
>  OBJS-$(CONFIG_IMAGE2PIPE_MUXER)          += img2enc.o img2.o
>  OBJS-$(CONFIG_IMAGE2_ALIAS_PIX_DEMUXER)  += img2_alias_pix.o
>  OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o
> +OBJS-$(CONFIG_IMAGE_BMP_PIPE_DEMUXER)     += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_DPX_PIPE_DEMUXER)     += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_EXR_PIPE_DEMUXER)     += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_PICTOR_PIPE_DEMUXER)  += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER)     += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER)     += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o
> +OBJS-$(CONFIG_IMAGE_TIFF_PIPE_DEMUXER)    += img2dec.o img2.o
>  OBJS-$(CONFIG_INGENIENT_DEMUXER)         += ingenientdec.o rawdec.o
>  OBJS-$(CONFIG_IPMOVIE_DEMUXER)           += ipmovie.o
>  OBJS-$(CONFIG_IRCAM_DEMUXER)             += ircamdec.o ircam.o pcm.o
> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index dc5557c..dbde432 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -318,6 +318,17 @@ void av_register_all(void)
>      REGISTER_DEMUXER (YOP,              yop);
>      REGISTER_MUXDEMUX(YUV4MPEGPIPE,     yuv4mpegpipe);
>  
> +    /* image demuxers */
> +    REGISTER_DEMUXER (IMAGE_BMP_PIPE,        image_bmp_pipe);
> +    REGISTER_DEMUXER (IMAGE_DPX_PIPE,        image_dpx_pipe);
> +    REGISTER_DEMUXER (IMAGE_EXR_PIPE,        image_exr_pipe);
> +    REGISTER_DEMUXER (IMAGE_PICTOR_PIPE,     image_pictor_pipe);
> +    REGISTER_DEMUXER (IMAGE_PNG_PIPE,        image_png_pipe);
> +    REGISTER_DEMUXER (IMAGE_SGI_PIPE,        image_sgi_pipe);
> +    REGISTER_DEMUXER (IMAGE_SUNRAST_PIPE,    image_sunrast_pipe);
> +    REGISTER_DEMUXER (IMAGE_TIFF_PIPE,       image_tiff_pipe);
> +
> +
>      /* protocols */
>      REGISTER_PROTOCOL(BLURAY,           bluray);
>      REGISTER_PROTOCOL(CACHE,            cache);
> diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
> index dc962db..6fa6157 100644
> --- a/libavformat/img2dec.c
> +++ b/libavformat/img2dec.c
> @@ -27,6 +27,7 @@
>  #include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavutil/parseutils.h"
> +#include "libavutil/intreadwrite.h"
>  #include "avformat.h"
>  #include "internal.h"
>  #include "img2.h"
> @@ -302,7 +303,34 @@ int ff_img_read_header(AVFormatContext *s1)
>          const char *str = strrchr(s->path, '.');
>          s->split_planes       = str && !av_strcasecmp(str + 1, "y");
>          st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
> -        st->codec->codec_id   = ff_guess_image2_codec(s->path);
> +        if (s1->pb) {
> +            struct image_probe *probe;
> +            uint8_t probe_buffer[AVPROBE_PADDING_SIZE] = {0};
> +            AVInputFormat *fmt = NULL;
> +            AVProbeData pd;
> +            int ret = avio_read(s1->pb, probe_buffer, 8);
> +            if (ret < 8)
> +                return AVERROR(EINVAL);
> +            avio_seek(s1->pb, -8, SEEK_CUR);
> +
> +            pd.buf = probe_buffer;
> +            pd.buf_size = 8;
> +            pd.filename = s1->filename;
> +
> +            while ((fmt = av_iformat_next(fmt))) {
> +                if (fmt->read_header != ff_img_read_header ||
> +                    !fmt->read_probe ||
> +                    (fmt->flags & AVFMT_NOFILE) ||
> +                    !fmt->raw_codec_id)
> +                    continue;
> +                if (fmt->read_probe(&pd) > 0) {
> +                    st->codec->codec_id = fmt->raw_codec_id;
> +                    break;
> +                }
> +            }
> +        }

I guess all this is needed only to avoid having a separate
ff_img_read_header function for each format?

Also, I suppose reading and seeking back by 8 bytes always works, even
if the underlying stream is not seekable, and there are no corner cases
that could happen that would lead to the buffer being flushed when
reading these 8 bytes?

> +        if (st->codec->codec_id == AV_CODEC_ID_NONE)
> +            st->codec->codec_id = ff_guess_image2_codec(s->path);
>          if (st->codec->codec_id == AV_CODEC_ID_LJPEG)
>              st->codec->codec_id = AV_CODEC_ID_MJPEG;
>          if (st->codec->codec_id == AV_CODEC_ID_ALIAS_PIX) // we cannot distingiush this from BRENDER_PIX
> @@ -522,3 +550,110 @@ AVInputFormat ff_image2pipe_demuxer = {
>      .priv_class     = &img2pipe_class,
>  };
>  #endif
> +
> +static int bmp_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RB16(b) == 0x424d)
> +        if (!AV_RN32(p + 6)) {
> +            return AVPROBE_SCORE_EXTENSION + 1;
> +        } else {
> +            return AVPROBE_SCORE_EXTENSION / 4;
> +        }
> +    return 0;
> +}
> +
> +static int dpx_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RN32(b) == AV_RN32("SDPX") || AV_RN32(b) == AV_RN32("XPDS"))
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int exr_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RL32(b) == 20000630)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int pictor_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RL16(b) == 0x1234)
> +        return AVPROBE_SCORE_EXTENSION / 4;
> +    return 0;
> +}
> +
> +static int png_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RB64(b) == 0x89504e470d0a1a0a)
> +        return AVPROBE_SCORE_MAX - 1;
> +    return 0;
> +}
> +
> +static int sgi_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RB16(b) == 474 &&
> +        (b[2] & ~1) == 0 &&
> +        (b[3] & ~3) == 0 && b[3] &&
> +        (AV_RB16(b + 4) & ~7) == 0 && AV_RB16(b + 4))
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int sunrast_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RB32(b) == 0x59a66a95)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int tiff_probe(AVProbeData *p)
> +{
> +    const uint8_t *b = p->buf;
> +
> +    if (AV_RB32(b) == 0x49492a00)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +#define IMAGEAUTO_DEMUXER(imgname, codecid)\
> +static const AVClass imgname ## _class = {\
> +    .class_name = AV_STRINGIFY(imgname) " demuxer",\
> +    .item_name  = av_default_item_name,\
> +    .option     = options,\
> +    .version    = LIBAVUTIL_VERSION_INT,\
> +};\
> +AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\
> +    .name           = AV_STRINGIFY(imgname) "_pipe",\
> +    .priv_data_size = sizeof(VideoDemuxData),\
> +    .read_probe     = imgname ## _probe,\
> +    .read_header    = ff_img_read_header,\
> +    .read_packet    = ff_img_read_packet,\
> +    .read_close     = img_read_close,\
> +    .read_seek      = img_read_seek,\
> +    .priv_class     = & imgname ## _class,\
> +    .raw_codec_id   = codecid,\
> +};
> +
> +IMAGEAUTO_DEMUXER(bmp,     AV_CODEC_ID_BMP)
> +IMAGEAUTO_DEMUXER(dpx,     AV_CODEC_ID_DPX)
> +IMAGEAUTO_DEMUXER(exr,     AV_CODEC_ID_EXR)
> +IMAGEAUTO_DEMUXER(pictor,  AV_CODEC_ID_PICTOR)
> +IMAGEAUTO_DEMUXER(png,     AV_CODEC_ID_PNG)
> +IMAGEAUTO_DEMUXER(sgi,     AV_CODEC_ID_SGI)
> +IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST)
> +IMAGEAUTO_DEMUXER(tiff,    AV_CODEC_ID_TIFF)
> diff --git a/libavformat/version.h b/libavformat/version.h
> index 67393e0..a5b24bf 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -30,7 +30,7 @@
>  #include "libavutil/version.h"
>  
>  #define LIBAVFORMAT_VERSION_MAJOR 55
> -#define LIBAVFORMAT_VERSION_MINOR 44
> +#define LIBAVFORMAT_VERSION_MINOR 45
>  #define LIBAVFORMAT_VERSION_MICRO 100
>  
>  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \

Looks good to me. IMO better than other hacks, and looks clean at least
from the outside.


More information about the ffmpeg-devel mailing list