diff --git a/Changelog b/Changelog index 3b12e2ae97..1aa814e50c 100644 --- 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: diff --git a/doc/general.texi b/doc/general.texi index 04ca71db91..1b720f51c7 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -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. diff --git a/libavformat/Makefile b/libavformat/Makefile index 1e59a91dc2..4e3a1836ad 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -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 diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 9ba459dd92..9593bd5a08 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -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 index 0000000000..e539b02464 --- /dev/null +++ b/libavformat/icodec.c @@ -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, +};