[FFmpeg-devel] [PATCH]Add an image3 demuxer with format autodetection

wm4 nfxjfg at googlemail.com
Thu May 29 14:21:51 CEST 2014


On Thu, 29 May 2014 11:38:51 +0200
Carl Eugen Hoyos <cehoyos at ag.or.at> wrote:

> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index 30e5d30..847c371 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -150,6 +150,7 @@ void av_register_all(void)
>      REGISTER_DEMUXER (IMAGE2_ALIAS_PIX, image2_alias_pix);
>      REGISTER_DEMUXER (IMAGE2_BRENDER_PIX, image2_brender_pix);
>      REGISTER_DEMUXER (INGENIENT,        ingenient);
> +    REGISTER_DEMUXER (IMAGE3,           image3);
>      REGISTER_DEMUXER (IPMOVIE,          ipmovie);
>      REGISTER_MUXER   (IPOD,             ipod);
>      REGISTER_MUXDEMUX(IRCAM,            ircam);
> diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
> index dc962db..880e26f 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"
> @@ -153,6 +154,107 @@ fail:
>      return -1;
>  }
>  
> +static int bmp_probe(uint8_t *p)
> +{
> +    if (AV_RB16(p) == 0x424d)
> +        if (!AV_RN32(p + 6)) {
> +            return AVPROBE_SCORE_EXTENSION + 1;
> +        } else {
> +            return AVPROBE_SCORE_EXTENSION / 2;
> +        }
> +    return 0;
> +}
> +
> +static int dpx_probe(uint8_t *p)
> +{
> +    if (AV_RN32(p) == AV_RN32("SDPX") || AV_RN32(p) == AV_RN32("XPDS"))
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int exr_probe(uint8_t *p)
> +{
> +    if (AV_RL32(p) == 20000630)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int jpegls_probe(uint8_t *p)
> +{
> +    if (AV_RB32(p) == 0xffd8fff7)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int pictor_probe(uint8_t *p)
> +{
> +    if (AV_RL16(p) == 0x1234)
> +        return AVPROBE_SCORE_EXTENSION / 2;
> +    return 0;
> +}
> +
> +static int png_probe(uint8_t *p)
> +{
> +    if (AV_RB64(p) == 0x89504e470d0a1a0a)
> +        return AVPROBE_SCORE_MAX - 1;
> +    return 0;
> +}
> +
> +static int sgi_probe(uint8_t *p)
> +{
> +    if (AV_RB16(p) == 474 &&
> +        (p[2] & ~1) == 0 &&
> +        (p[3] & ~3) == 0 && p[3] &&
> +        (AV_RB16(p + 4) & ~6) == 0 && AV_RB16(p + 4))
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int sunrast_probe(uint8_t *p)
> +{
> +    if (AV_RB32(p) == 0x59a66a95)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +static int tiff_probe(uint8_t *p)
> +{
> +    if (AV_RB32(p) == 0x49492a00)
> +        return AVPROBE_SCORE_EXTENSION + 1;
> +    return 0;
> +}
> +
> +struct image_probe {
> +    int (*f)(uint8_t *p);
> +    enum AVCodecID codec_id;
> +};
> +
> +static struct image_probe probe_functions[] = {
> +    { bmp_probe,     AV_CODEC_ID_BMP },
> +    { dpx_probe,     AV_CODEC_ID_DPX },
> +    { exr_probe,     AV_CODEC_ID_EXR },
> +    { jpegls_probe,  AV_CODEC_ID_JPEGLS},
> +    { pictor_probe,  AV_CODEC_ID_PICTOR },
> +    { png_probe,     AV_CODEC_ID_PNG },
> +    { sgi_probe,     AV_CODEC_ID_SGI },
> +    { sunrast_probe, AV_CODEC_ID_SUNRAST },
> +    { tiff_probe,    AV_CODEC_ID_TIFF },
> +    { NULL, 0}
> +};
> +
> +static int img3_read_probe(AVProbeData *p)
> +{
> +    struct image_probe *probe;
> +
> +    for (probe = probe_functions; probe->f; probe++) {
> +        int ret;
> +        ret = probe->f(p->buf);
> +        if (ret > 0)
> +            return ret;
> +    }
> +    return 0;
> +}
> +

OK, but why stuff it all into one "super"-demuxer?

Note that for web stuff, the mime-type should also take part in
determining the format.

>  static int img_read_probe(AVProbeData *p)
>  {
>      if (p->filename && ff_guess_image2_codec(p->filename)) {
> @@ -198,7 +300,8 @@ int ff_img_read_header(AVFormatContext *s1)
>          s->is_pipe = 0;
>      else {
>          s->is_pipe       = 1;
> -        st->need_parsing = AVSTREAM_PARSE_FULL;
> +        if (memcmp(s1->iformat->name, "image3", 6))
> +            st->need_parsing = AVSTREAM_PARSE_FULL;

Why not strcmp or at least strncmp? Is iformat some kind of prefix that
has a guaranteed length at this point of the code?

>      }
>  
>      if (s->ts_from_file == 2) {
> @@ -302,7 +405,21 @@ 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[10] = {0};
> +            int ret;
> +
> +            ret = avio_read(s1->pb, probe_buffer, 8);
> +            if (ret < 8)
> +                return AVERROR(EINVAL);
> +            avio_seek(s1->pb, -8, SEEK_CUR);
> +            for (probe = probe_functions; probe->f; probe++)
> +                if (probe->f(probe_buffer))
> +                    st->codec->codec_id = probe->codec_id;
> +        }
> +        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
> @@ -387,6 +504,8 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
>              return AVERROR(EIO);
>          if (s->frame_size > 0) {
>              size[0] = s->frame_size;
> +        } else if (!memcmp(s1->iformat->name, "image3", 6)) {
> +            size[0] = avio_size(s1->pb);

Again...

Also, is it right to pass the whole file as packet, instead of trying
to parse and sanitize the size of the data somehow?

>          } else {
>              size[0] = 4096;
>          }
> @@ -522,3 +641,22 @@ AVInputFormat ff_image2pipe_demuxer = {
>      .priv_class     = &img2pipe_class,
>  };
>  #endif
> +#if CONFIG_IMAGE3_DEMUXER
> +static const AVClass img3_class = {
> +    .class_name = "image3 demuxer",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +AVInputFormat ff_image3_demuxer = {
> +    .name           = "image3",
> +    .long_name      = NULL_IF_CONFIG_SMALL("single image"),
> +    .priv_data_size = sizeof(VideoDemuxData),
> +    .read_probe     = img3_read_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     = &img3_class,
> +};
> +#endif


More information about the ffmpeg-devel mailing list