Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Microsoft Windows ICO demuxer
  3.  * Copyright (c) 2011 Peter Ross (pross@xvid.org)
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * Microsoft Windows ICO demuxer
  25.  */
  26.  
  27. #include "libavutil/intreadwrite.h"
  28. #include "libavcodec/bytestream.h"
  29. #include "libavcodec/bmp.h"
  30. #include "avformat.h"
  31. #include "internal.h"
  32.  
  33. typedef struct {
  34.     int offset;
  35.     int size;
  36.     int nb_pal;
  37. } IcoImage;
  38.  
  39. typedef struct {
  40.     int current_image;
  41.     int nb_images;
  42.     IcoImage * images;
  43. } IcoDemuxContext;
  44.  
  45. static int probe(AVProbeData *p)
  46. {
  47.     if (AV_RL16(p->buf) == 0 && AV_RL16(p->buf + 2) == 1 && AV_RL16(p->buf + 4))
  48.         return AVPROBE_SCORE_MAX / 3;
  49.     return 0;
  50. }
  51.  
  52. static int read_header(AVFormatContext *s)
  53. {
  54.     IcoDemuxContext *ico = s->priv_data;
  55.     AVIOContext *pb = s->pb;
  56.     int i, codec;
  57.  
  58.     avio_skip(pb, 4);
  59.     ico->nb_images = avio_rl16(pb);
  60.  
  61.     ico->images = av_malloc(ico->nb_images * sizeof(IcoImage));
  62.     if (!ico->images)
  63.         return AVERROR(ENOMEM);
  64.  
  65.     for (i = 0; i < ico->nb_images; i++) {
  66.         AVStream *st;
  67.         int tmp;
  68.  
  69.         if (avio_seek(pb, 6 + i * 16, SEEK_SET) < 0)
  70.             break;
  71.  
  72.         st = avformat_new_stream(s, NULL);
  73.         if (!st)
  74.             return AVERROR(ENOMEM);
  75.  
  76.         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  77.         st->codec->width      = avio_r8(pb);
  78.         st->codec->height     = avio_r8(pb);
  79.         ico->images[i].nb_pal = avio_r8(pb);
  80.         if (ico->images[i].nb_pal == 255)
  81.             ico->images[i].nb_pal = 0;
  82.  
  83.         avio_skip(pb, 5);
  84.  
  85.         ico->images[i].size   = avio_rl32(pb);
  86.         ico->images[i].offset = avio_rl32(pb);
  87.  
  88.         if (avio_seek(pb, ico->images[i].offset, SEEK_SET) < 0)
  89.             break;
  90.  
  91.         codec = avio_rl32(pb);
  92.         switch (codec) {
  93.         case MKTAG(0x89, 'P', 'N', 'G'):
  94.             st->codec->codec_id = AV_CODEC_ID_PNG;
  95.             st->codec->width    = 0;
  96.             st->codec->height   = 0;
  97.             break;
  98.         case 40:
  99.             if (ico->images[i].size < 40)
  100.                 return AVERROR_INVALIDDATA;
  101.             st->codec->codec_id = AV_CODEC_ID_BMP;
  102.             tmp = avio_rl32(pb);
  103.             if (tmp)
  104.                 st->codec->width = tmp;
  105.             tmp = avio_rl32(pb);
  106.             if (tmp)
  107.                 st->codec->height = tmp / 2;
  108.             break;
  109.         default:
  110.             avpriv_request_sample(s, "codec %d", codec);
  111.             return AVERROR_INVALIDDATA;
  112.         }
  113.     }
  114.  
  115.     return 0;
  116. }
  117.  
  118. static int read_packet(AVFormatContext *s, AVPacket *pkt)
  119. {
  120.     IcoDemuxContext *ico = s->priv_data;
  121.     IcoImage *image;
  122.     AVIOContext *pb = s->pb;
  123.     AVStream *st = s->streams[0];
  124.     int ret;
  125.  
  126.     if (ico->current_image >= ico->nb_images)
  127.         return AVERROR(EIO);
  128.  
  129.     image = &ico->images[ico->current_image];
  130.  
  131.     if ((ret = avio_seek(pb, image->offset, SEEK_SET)) < 0)
  132.         return ret;
  133.  
  134.     if (s->streams[ico->current_image]->codec->codec_id == AV_CODEC_ID_PNG) {
  135.         if ((ret = av_get_packet(pb, pkt, image->size)) < 0)
  136.             return ret;
  137.     } else {
  138.         uint8_t *buf;
  139.         if ((ret = av_new_packet(pkt, 14 + image->size)) < 0)
  140.             return ret;
  141.         buf = pkt->data;
  142.  
  143.         /* add BMP header */
  144.         bytestream_put_byte(&buf, 'B');
  145.         bytestream_put_byte(&buf, 'M');
  146.         bytestream_put_le32(&buf, pkt->size);
  147.         bytestream_put_le16(&buf, 0);
  148.         bytestream_put_le16(&buf, 0);
  149.         bytestream_put_le32(&buf, 0);
  150.  
  151.         if ((ret = avio_read(pb, buf, image->size)) < 0)
  152.             return ret;
  153.  
  154.         st->codec->bits_per_coded_sample = AV_RL16(buf + 14);
  155.  
  156.         if (AV_RL32(buf + 32))
  157.             image->nb_pal = AV_RL32(buf + 32);
  158.  
  159.         if (st->codec->bits_per_coded_sample <= 8 && !image->nb_pal) {
  160.             image->nb_pal = 1 << st->codec->bits_per_coded_sample;
  161.             AV_WL32(buf + 32, image->nb_pal);
  162.         }
  163.  
  164.         AV_WL32(buf - 4, 14 + 40 + image->nb_pal * 4);
  165.         AV_WL32(buf + 8, AV_RL32(buf + 8) / 2);
  166.     }
  167.  
  168.     pkt->stream_index = ico->current_image++;
  169.     pkt->flags |= AV_PKT_FLAG_KEY;
  170.  
  171.     return 0;
  172. }
  173.  
  174. AVInputFormat ff_ico_demuxer = {
  175.     .name           = "ico",
  176.     .long_name      = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
  177.     .priv_data_size = sizeof(IcoDemuxContext),
  178.     .read_probe     = probe,
  179.     .read_header    = read_header,
  180.     .read_packet    = read_packet,
  181.     .flags          = AVFMT_NOTIMESTAMPS,
  182. };
  183.