LCOV - code coverage report
Current view: top level - libavformat - icoenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 85 0.0 %
Date: 2017-12-10 21:22:29 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Microsoft Windows ICO muxer
       3             :  * Copyright (c) 2012 Michael Bradshaw <mjbshaw gmail com>
       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 muxer
      25             :  */
      26             : 
      27             : #include "libavutil/intreadwrite.h"
      28             : #include "libavutil/pixdesc.h"
      29             : #include "avformat.h"
      30             : 
      31             : typedef struct {
      32             :     int offset;
      33             :     int size;
      34             :     unsigned char width;
      35             :     unsigned char height;
      36             :     short bits;
      37             : } IcoImage;
      38             : 
      39             : typedef struct {
      40             :     int current_image;
      41             :     int nb_images;
      42             :     IcoImage *images;
      43             : } IcoMuxContext;
      44             : 
      45           0 : static int ico_check_attributes(AVFormatContext *s, const AVCodecParameters *p)
      46             : {
      47           0 :     if (p->codec_id == AV_CODEC_ID_BMP) {
      48             :         if (p->format == AV_PIX_FMT_PAL8 && AV_PIX_FMT_RGB32 != AV_PIX_FMT_BGRA) {
      49             :             av_log(s, AV_LOG_ERROR, "Wrong endianness for bmp pixel format\n");
      50             :             return AVERROR(EINVAL);
      51           0 :         } else if (p->format != AV_PIX_FMT_PAL8 &&
      52           0 :                    p->format != AV_PIX_FMT_RGB555LE &&
      53           0 :                    p->format != AV_PIX_FMT_BGR24 &&
      54           0 :                    p->format != AV_PIX_FMT_BGRA) {
      55           0 :             av_log(s, AV_LOG_ERROR, "BMP must be 1bit, 4bit, 8bit, 16bit, 24bit, or 32bit\n");
      56           0 :             return AVERROR(EINVAL);
      57             :         }
      58           0 :     } else if (p->codec_id == AV_CODEC_ID_PNG) {
      59           0 :         if (p->format != AV_PIX_FMT_RGBA) {
      60           0 :             av_log(s, AV_LOG_ERROR, "PNG in ico requires pixel format to be rgba\n");
      61           0 :             return AVERROR(EINVAL);
      62             :         }
      63             :     } else {
      64           0 :         const AVCodecDescriptor *codesc = avcodec_descriptor_get(p->codec_id);
      65           0 :         av_log(s, AV_LOG_ERROR, "Unsupported codec %s\n", codesc ? codesc->name : "");
      66           0 :         return AVERROR(EINVAL);
      67             :     }
      68             : 
      69           0 :     if (p->width > 256 ||
      70           0 :         p->height > 256) {
      71           0 :         av_log(s, AV_LOG_ERROR, "Unsupported dimensions %dx%d (dimensions cannot exceed 256x256)\n", p->width, p->height);
      72           0 :         return AVERROR(EINVAL);
      73             :     }
      74             : 
      75           0 :     return 0;
      76             : }
      77             : 
      78           0 : static int ico_write_header(AVFormatContext *s)
      79             : {
      80           0 :     IcoMuxContext *ico = s->priv_data;
      81           0 :     AVIOContext *pb = s->pb;
      82             :     int ret;
      83             :     int i;
      84             : 
      85           0 :     if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
      86           0 :         av_log(s, AV_LOG_ERROR, "Output is not seekable\n");
      87           0 :         return AVERROR(EINVAL);
      88             :     }
      89             : 
      90           0 :     ico->current_image = 0;
      91           0 :     ico->nb_images = s->nb_streams;
      92             : 
      93           0 :     avio_wl16(pb, 0); // reserved
      94           0 :     avio_wl16(pb, 1); // 1 == icon
      95           0 :     avio_skip(pb, 2); // skip the number of images
      96             : 
      97           0 :     for (i = 0; i < s->nb_streams; i++) {
      98           0 :         if (ret = ico_check_attributes(s, s->streams[i]->codecpar))
      99           0 :             return ret;
     100             : 
     101             :         // Fill in later when writing trailer...
     102           0 :         avio_skip(pb, 16);
     103             :     }
     104             : 
     105           0 :     ico->images = av_mallocz_array(ico->nb_images, sizeof(IcoMuxContext));
     106           0 :     if (!ico->images)
     107           0 :         return AVERROR(ENOMEM);
     108             : 
     109           0 :     avio_flush(pb);
     110             : 
     111           0 :     return 0;
     112             : }
     113             : 
     114           0 : static int ico_write_packet(AVFormatContext *s, AVPacket *pkt)
     115             : {
     116           0 :     IcoMuxContext *ico = s->priv_data;
     117             :     IcoImage *image;
     118           0 :     AVIOContext *pb = s->pb;
     119           0 :     AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
     120             :     int i;
     121             : 
     122           0 :     if (ico->current_image >= ico->nb_images) {
     123           0 :         av_log(s, AV_LOG_ERROR, "ICO already contains %d images\n", ico->current_image);
     124           0 :         return AVERROR(EIO);
     125             :     }
     126             : 
     127           0 :     image = &ico->images[ico->current_image++];
     128             : 
     129           0 :     image->offset = avio_tell(pb);
     130           0 :     image->width = (par->width == 256) ? 0 : par->width;
     131           0 :     image->height = (par->height == 256) ? 0 : par->height;
     132             : 
     133           0 :     if (par->codec_id == AV_CODEC_ID_PNG) {
     134           0 :         image->bits = par->bits_per_coded_sample;
     135           0 :         image->size = pkt->size;
     136             : 
     137           0 :         avio_write(pb, pkt->data, pkt->size);
     138             :     } else { // BMP
     139           0 :         if (AV_RL32(pkt->data + 14) != 40) { // must be BITMAPINFOHEADER
     140           0 :             av_log(s, AV_LOG_ERROR, "Invalid BMP\n");
     141           0 :             return AVERROR(EINVAL);
     142             :         }
     143             : 
     144           0 :         image->bits = AV_RL16(pkt->data + 28); // allows things like 1bit and 4bit images to be preserved
     145           0 :         image->size = pkt->size - 14 + par->height * (par->width + 7) / 8;
     146             : 
     147           0 :         avio_write(pb, pkt->data + 14, 8); // Skip the BITMAPFILEHEADER header
     148           0 :         avio_wl32(pb, AV_RL32(pkt->data + 22) * 2); // rewrite height as 2 * height
     149           0 :         avio_write(pb, pkt->data + 26, pkt->size - 26);
     150             : 
     151           0 :         for (i = 0; i < par->height * (par->width + 7) / 8; ++i)
     152           0 :             avio_w8(pb, 0x00); // Write bitmask (opaque)
     153             :     }
     154             : 
     155           0 :     return 0;
     156             : }
     157             : 
     158           0 : static int ico_write_trailer(AVFormatContext *s)
     159             : {
     160           0 :     IcoMuxContext *ico = s->priv_data;
     161           0 :     AVIOContext *pb = s->pb;
     162             :     int i;
     163             : 
     164           0 :     avio_seek(pb, 4, SEEK_SET);
     165             : 
     166           0 :     avio_wl16(pb, ico->current_image);
     167             : 
     168           0 :     for (i = 0; i < ico->nb_images; i++) {
     169           0 :         avio_w8(pb, ico->images[i].width);
     170           0 :         avio_w8(pb, ico->images[i].height);
     171             : 
     172           0 :         if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_BMP &&
     173           0 :             s->streams[i]->codecpar->format == AV_PIX_FMT_PAL8) {
     174           0 :             avio_w8(pb, (ico->images[i].bits >= 8) ? 0 : 1 << ico->images[i].bits);
     175             :         } else {
     176           0 :             avio_w8(pb, 0);
     177             :         }
     178             : 
     179           0 :         avio_w8(pb, 0); // reserved
     180           0 :         avio_wl16(pb, 1); // color planes
     181           0 :         avio_wl16(pb, ico->images[i].bits);
     182           0 :         avio_wl32(pb, ico->images[i].size);
     183           0 :         avio_wl32(pb, ico->images[i].offset);
     184             :     }
     185             : 
     186           0 :     av_freep(&ico->images);
     187             : 
     188           0 :     return 0;
     189             : }
     190             : 
     191             : AVOutputFormat ff_ico_muxer = {
     192             :     .name           = "ico",
     193             :     .long_name      = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
     194             :     .priv_data_size = sizeof(IcoMuxContext),
     195             :     .mime_type      = "image/vnd.microsoft.icon",
     196             :     .extensions     = "ico",
     197             :     .audio_codec    = AV_CODEC_ID_NONE,
     198             :     .video_codec    = AV_CODEC_ID_BMP,
     199             :     .write_header   = ico_write_header,
     200             :     .write_packet   = ico_write_packet,
     201             :     .write_trailer  = ico_write_trailer,
     202             :     .flags          = AVFMT_NOTIMESTAMPS,
     203             : };

Generated by: LCOV version 1.13