Microsoft Windows ICO demuxer
authorPeter Ross <pross@xvid.org>
Sun, 4 Dec 2011 06:45:24 +0000 (17:45 +1100)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 4 Dec 2011 15:44:20 +0000 (16:44 +0100)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Changelog
doc/general.texi
libavformat/Makefile
libavformat/allformats.c
libavformat/icodec.c [new file with mode: 0644]

index 3b12e2a..1aa814e 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -127,6 +127,7 @@ easier to use. The changes are:
 - ass filter
 - CRI ADX audio format demuxer
 - Playstation Portable PMP format demuxer
+- Microsoft Windows ICO demuxer
 
 
 version 0.8:
index 04ca71d..1b720f5 100644 (file)
@@ -125,6 +125,8 @@ library:
     @tab General eXchange Format SMPTE 360M, used by Thomson Grass Valley
          playout servers.
 @item iCEDraw File              @tab   @tab X
+@item ICO                       @tab   @tab X
+    @tab Microsoft Windows ICO
 @item id Quake II CIN video     @tab   @tab X
 @item id RoQ                    @tab X @tab X
     @tab Used in Quake III, Jedi Knight 2 and other computer games.
index 1e59a91..4e3a183 100644 (file)
@@ -111,6 +111,7 @@ OBJS-$(CONFIG_H263_DEMUXER)              += h263dec.o rawdec.o
 OBJS-$(CONFIG_H263_MUXER)                += rawenc.o
 OBJS-$(CONFIG_H264_DEMUXER)              += h264dec.o rawdec.o
 OBJS-$(CONFIG_H264_MUXER)                += rawenc.o
+OBJS-$(CONFIG_ICO_DEMUXER)               += icodec.o
 OBJS-$(CONFIG_IDCIN_DEMUXER)             += idcin.o
 OBJS-$(CONFIG_IDF_DEMUXER)               += bintext.o
 OBJS-$(CONFIG_IFF_DEMUXER)               += iff.o
index 9ba459d..9593bd5 100644 (file)
@@ -110,6 +110,7 @@ void av_register_all(void)
     REGISTER_MUXDEMUX (H261, h261);
     REGISTER_MUXDEMUX (H263, h263);
     REGISTER_MUXDEMUX (H264, h264);
+    REGISTER_DEMUXER  (ICO, ico);
     REGISTER_DEMUXER  (IDCIN, idcin);
     REGISTER_DEMUXER  (IDF, idf);
     REGISTER_DEMUXER  (IFF, iff);
diff --git a/libavformat/icodec.c b/libavformat/icodec.c
new file mode 100644 (file)
index 0000000..e539b02
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Microsoft Windows ICO demuxer
+ * Copyright (c) 2011 Peter Ross (pross@xvid.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Microsoft Windows ICO demuxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/bytestream.h"
+#include "libavcodec/bmp.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct {
+    int offset;
+    int size;
+    int nb_pal;
+} IcoImage;
+
+typedef struct {
+    int current_image;
+    int nb_images;
+    IcoImage * images;
+} IcoDemuxContext;
+
+static int probe(AVProbeData *p)
+{
+    if (AV_RL16(p->buf) == 0 && AV_RL16(p->buf + 2) == 1 && AV_RL16(p->buf + 4))
+        return AVPROBE_SCORE_MAX / 3;
+    return 0;
+}
+
+static int read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+    IcoDemuxContext *ico = s->priv_data;
+    AVIOContext *pb = s->pb;
+    int i;
+
+    avio_skip(pb, 4);
+    ico->nb_images = avio_rl16(pb);
+
+    ico->images = av_malloc(ico->nb_images * sizeof(IcoImage));
+    if (!ico->images)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < ico->nb_images; i++) {
+        AVStream *st;
+
+        if (avio_seek(pb, 6 + i * 16, SEEK_SET) < 0)
+            break;
+
+        st = avformat_new_stream(s, NULL);
+        if (!st)
+            return AVERROR(ENOMEM);
+
+        st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+        st->codec->width      = avio_r8(pb);
+        st->codec->height     = avio_r8(pb);
+        ico->images[i].nb_pal = avio_r8(pb);
+
+        avio_skip(pb, 3);
+        st->codec->bits_per_coded_sample = avio_rl16(pb);
+        if (st->codec->bits_per_coded_sample <= 8 && !ico->images[i].nb_pal)
+            ico->images[i].nb_pal = 1 << st->codec->bits_per_coded_sample;
+
+        ico->images[i].size   = avio_rl32(pb);
+        ico->images[i].offset = avio_rl32(pb);
+
+        if (avio_seek(pb, ico->images[i].offset, SEEK_SET) < 0)
+            break;
+
+        switch(avio_rl32(pb)) {
+        case MKTAG(0x89, 'P', 'N', 'G'):
+            st->codec->codec_id = CODEC_ID_PNG;
+            st->codec->width    = 0;
+            st->codec->height   = 0;
+            break;
+        case 40:
+            st->codec->codec_id = CODEC_ID_BMP;
+            if (!st->codec->width || !st->codec->height) {
+                st->codec->width  = avio_rl32(pb);
+                st->codec->height = avio_rl32(pb) / 2;
+            }
+            break;
+        default:
+            av_log_ask_for_sample(s, "unsupported codec\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    IcoDemuxContext *ico = s->priv_data;
+    IcoImage *image;
+    AVIOContext *pb = s->pb;
+    int ret;
+
+    if (ico->current_image >= ico->nb_images)
+        return AVERROR(EIO);
+
+    image = &ico->images[ico->current_image];
+
+    if ((ret = avio_seek(pb, image->offset, SEEK_SET)) < 0)
+        return ret;
+
+    if (s->streams[ico->current_image]->codec->codec_id == CODEC_ID_PNG) {
+        if ((ret = av_get_packet(pb, pkt, image->size)) < 0)
+            return ret;
+    } else {
+        uint8_t *buf;
+        if ((ret = av_new_packet(pkt, 14 + image->size)) < 0)
+            return ret;
+        buf = pkt->data;
+
+        /* add BMP header */
+        bytestream_put_byte(&buf, 'B');
+        bytestream_put_byte(&buf, 'M');
+        bytestream_put_le32(&buf, pkt->size);
+        bytestream_put_le16(&buf, 0);
+        bytestream_put_le16(&buf, 0);
+        bytestream_put_le32(&buf, 14 + 40 + image->nb_pal * 4);
+
+        if ((ret = avio_read(pb, buf, image->size)) < 0)
+            return ret;
+
+        AV_WL32(buf + 8, AV_RL32(buf + 8) / 2);
+        AV_WL32(buf + 32, image->nb_pal);
+    }
+
+    pkt->stream_index = ico->current_image++;
+    pkt->flags |= AV_PKT_FLAG_KEY;
+
+    return 0;
+}
+
+AVInputFormat ff_ico_demuxer = {
+    .name           = "ico",
+    .long_name      = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
+    .priv_data_size = sizeof(IcoDemuxContext),
+    .read_probe     = probe,
+    .read_header    = read_header,
+    .read_packet    = read_packet,
+    .flags          = AVFMT_NOTIMESTAMPS,
+};