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

wm4 nfxjfg at googlemail.com
Tue Jul 1 02:22:54 CEST 2014


On Tue, 1 Jul 2014 00:27:42 +0200
Michael Niedermayer <michaelni at gmx.at> wrote:

> On Mon, Jun 30, 2014 at 09:53:46PM +0200, wm4 wrote:
> > 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?
> 
> it also allows "-f image2pipe" to recognize the format as well as
> allowing test.png.%dnoname
> this would nt work oterwise as the probing code would try to open
> test.png.%dnoname not finding such a file and neither finding an
> extension to identify it thus would require manually specifying png
> 
> 
> > 
> > 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?
> 
> the 8 byte reading originates from the original patch, iam not happy
> about it either. It should be ok in practice but i certainly would
> prefer if it could be done more generically and robust ...
> but probably better to do this as a seperate patch if its done

In general, it would be nice if avio had some sort of peek() function,
which reads some buffer, but guarantees that the buffer isn't lost. For
now it might be ok in practice, I agree.

> 
> > 
> > > +        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.
> 
> there still one apsect i like to point at so its not missed, the
> new formats are called bmp_pipe, dpx_pipe, ...
> this matches the image2 / image2pipe terminology except the "_"
> we could add non pipe variants but they would not be autoselected
> by the current probe system as it wouldnt scan and open a file with
> wildcards / %d in it

IMO the wildcard thing is a bit odd and should be in its own
pseudo-demuxer, while normal image formats like "bmp" should exist and
work like everything else in libavformat.

Would it be hard to add these formats? Wouldn't it just require
extending the macro above a little?

> 
> If there are no objections / further comments then ill push this
> tomorrow

No objections from me...


More information about the ffmpeg-devel mailing list