LCOV - code coverage report
Current view: top level - libavformat - smush.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 148 67.6 %
Date: 2017-12-16 13:57:32 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * LucasArts Smush demuxer
       3             :  * Copyright (c) 2006 Cyril Zorin
       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             : #include "libavutil/intreadwrite.h"
      23             : 
      24             : #include "avformat.h"
      25             : #include "avio.h"
      26             : #include "internal.h"
      27             : 
      28             : typedef struct SMUSHContext {
      29             :     int version;
      30             :     int audio_stream_index;
      31             :     int video_stream_index;
      32             : } SMUSHContext;
      33             : 
      34        6130 : static int smush_read_probe(AVProbeData *p)
      35             : {
      36        6132 :     if (((AV_RL32(p->buf)     == MKTAG('S', 'A', 'N', 'M') &&
      37        6130 :           AV_RL32(p->buf + 8) == MKTAG('S', 'H', 'D', 'R')) ||
      38        6128 :          (AV_RL32(p->buf)     == MKTAG('A', 'N', 'I', 'M') &&
      39           0 :           AV_RL32(p->buf + 8) == MKTAG('A', 'H', 'D', 'R')))) {
      40           2 :         return AVPROBE_SCORE_MAX;
      41             :     }
      42             : 
      43        6128 :     return 0;
      44             : }
      45             : 
      46           2 : static int smush_read_header(AVFormatContext *ctx)
      47             : {
      48           2 :     SMUSHContext *smush = ctx->priv_data;
      49           2 :     AVIOContext *pb = ctx->pb;
      50             :     AVStream *vst, *ast;
      51             :     uint32_t magic, nframes, size, subversion, i;
      52           2 :     uint32_t width = 0, height = 0, got_audio = 0, read = 0;
      53             :     uint32_t sample_rate, channels, palette[256];
      54             : 
      55           2 :     magic = avio_rb32(pb);
      56           2 :     avio_skip(pb, 4); // skip movie size
      57             : 
      58           2 :     if (magic == MKBETAG('A', 'N', 'I', 'M')) {
      59           0 :         if (avio_rb32(pb) != MKBETAG('A', 'H', 'D', 'R'))
      60           0 :             return AVERROR_INVALIDDATA;
      61             : 
      62           0 :         size = avio_rb32(pb);
      63           0 :         if (size < 3 * 256 + 6)
      64           0 :             return AVERROR_INVALIDDATA;
      65             : 
      66           0 :         smush->version = 0;
      67           0 :         subversion     = avio_rl16(pb);
      68           0 :         nframes        = avio_rl16(pb);
      69           0 :         if (!nframes)
      70           0 :             return AVERROR_INVALIDDATA;
      71             : 
      72           0 :         avio_skip(pb, 2); // skip pad
      73             : 
      74           0 :         for (i = 0; i < 256; i++)
      75           0 :             palette[i] = avio_rb24(pb);
      76             : 
      77           0 :         avio_skip(pb, size - (3 * 256 + 6));
      78           2 :     } else if (magic == MKBETAG('S', 'A', 'N', 'M')) {
      79           2 :         if (avio_rb32(pb) != MKBETAG('S', 'H', 'D', 'R'))
      80           0 :             return AVERROR_INVALIDDATA;
      81             : 
      82           2 :         size = avio_rb32(pb);
      83           2 :         if (size < 14)
      84           0 :             return AVERROR_INVALIDDATA;
      85             : 
      86           2 :         smush->version = 1;
      87           2 :         subversion = avio_rl16(pb);
      88           2 :         nframes = avio_rl32(pb);
      89           2 :         if (!nframes)
      90           0 :             return AVERROR_INVALIDDATA;
      91             : 
      92           2 :         avio_skip(pb, 2); // skip pad
      93           2 :         width  = avio_rl16(pb);
      94           2 :         height = avio_rl16(pb);
      95           2 :         avio_skip(pb, 2); // skip pad
      96           2 :         avio_skip(pb, size - 14);
      97             : 
      98           2 :         if (avio_rb32(pb) != MKBETAG('F', 'L', 'H', 'D'))
      99           0 :             return AVERROR_INVALIDDATA;
     100             : 
     101           2 :         size = avio_rb32(pb);
     102           2 :         while (!got_audio && ((read + 8) < size)) {
     103             :             uint32_t sig, chunk_size;
     104             : 
     105           2 :             if (avio_feof(pb))
     106           0 :                 return AVERROR_EOF;
     107             : 
     108           2 :             sig        = avio_rb32(pb);
     109           2 :             chunk_size = avio_rb32(pb);
     110           2 :             read      += 8;
     111           2 :             switch (sig) {
     112           2 :             case MKBETAG('W', 'a', 'v', 'e'):
     113           2 :                 got_audio = 1;
     114           2 :                 sample_rate = avio_rl32(pb);
     115           2 :                 if (!sample_rate)
     116           0 :                     return AVERROR_INVALIDDATA;
     117             : 
     118           2 :                 channels = avio_rl32(pb);
     119           2 :                 if (!channels)
     120           0 :                     return AVERROR_INVALIDDATA;
     121             : 
     122           2 :                 avio_skip(pb, chunk_size - 8);
     123           2 :                 read += chunk_size;
     124           2 :                 break;
     125           0 :             case MKBETAG('B', 'l', '1', '6'):
     126             :             case MKBETAG('A', 'N', 'N', 'O'):
     127           0 :                 avio_skip(pb, chunk_size);
     128           0 :                 read += chunk_size;
     129           0 :                 break;
     130           0 :             default:
     131           0 :                 return AVERROR_INVALIDDATA;
     132             :             }
     133             :         }
     134             : 
     135           2 :         avio_skip(pb, size - read);
     136             :     } else {
     137           0 :         av_log(ctx, AV_LOG_ERROR, "Wrong magic\n");
     138           0 :         return AVERROR_INVALIDDATA;
     139             :     }
     140             : 
     141           2 :     vst = avformat_new_stream(ctx, 0);
     142           2 :     if (!vst)
     143           0 :         return AVERROR(ENOMEM);
     144             : 
     145           2 :     smush->video_stream_index = vst->index;
     146             : 
     147           2 :     avpriv_set_pts_info(vst, 64, 1, 15);
     148             : 
     149           2 :     vst->start_time        = 0;
     150           2 :     vst->duration          =
     151           2 :     vst->nb_frames         = nframes;
     152           2 :     vst->avg_frame_rate    = av_inv_q(vst->time_base);
     153           2 :     vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     154           2 :     vst->codecpar->codec_id   = AV_CODEC_ID_SANM;
     155           2 :     vst->codecpar->codec_tag  = 0;
     156           2 :     vst->codecpar->width      = width;
     157           2 :     vst->codecpar->height     = height;
     158             : 
     159           2 :     if (!smush->version) {
     160           0 :         if (ff_alloc_extradata(vst->codecpar, 1024 + 2))
     161           0 :             return AVERROR(ENOMEM);
     162             : 
     163           0 :         AV_WL16(vst->codecpar->extradata, subversion);
     164           0 :         for (i = 0; i < 256; i++)
     165           0 :             AV_WL32(vst->codecpar->extradata + 2 + i * 4, palette[i]);
     166             :     }
     167             : 
     168           2 :     if (got_audio) {
     169           2 :         ast = avformat_new_stream(ctx, 0);
     170           2 :         if (!ast)
     171           0 :             return AVERROR(ENOMEM);
     172             : 
     173           2 :         smush->audio_stream_index = ast->index;
     174             : 
     175           2 :         ast->start_time         = 0;
     176           2 :         ast->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
     177           2 :         ast->codecpar->codec_id    = AV_CODEC_ID_ADPCM_VIMA;
     178           2 :         ast->codecpar->codec_tag   = 0;
     179           2 :         ast->codecpar->sample_rate = sample_rate;
     180           2 :         ast->codecpar->channels    = channels;
     181             : 
     182           2 :         avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate);
     183             :     }
     184             : 
     185           2 :     return 0;
     186             : }
     187             : 
     188          68 : static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt)
     189             : {
     190          68 :     SMUSHContext *smush = ctx->priv_data;
     191          68 :     AVIOContext *pb = ctx->pb;
     192          68 :     int done = 0;
     193             :     int ret;
     194             : 
     195         232 :     while (!done) {
     196             :         uint32_t sig, size;
     197             : 
     198         100 :         if (avio_feof(pb))
     199           4 :             return AVERROR_EOF;
     200             : 
     201          96 :         sig  = avio_rb32(pb);
     202          96 :         size = avio_rb32(pb);
     203             : 
     204          96 :         switch (sig) {
     205          32 :         case MKBETAG('F', 'R', 'M', 'E'):
     206          32 :             if (smush->version)
     207          32 :                 break;
     208           0 :             if ((ret = av_get_packet(pb, pkt, size)) < 0)
     209           0 :                 return ret;
     210             : 
     211           0 :             pkt->stream_index = smush->video_stream_index;
     212           0 :             done = 1;
     213           0 :             break;
     214          32 :         case MKBETAG('B', 'l', '1', '6'):
     215          32 :             if ((ret = av_get_packet(pb, pkt, size)) < 0)
     216           0 :                 return ret;
     217             : 
     218          32 :             pkt->stream_index = smush->video_stream_index;
     219          32 :             pkt->duration = 1;
     220          32 :             done = 1;
     221          32 :             break;
     222          32 :         case MKBETAG('W', 'a', 'v', 'e'):
     223          32 :             if (size < 13)
     224           0 :                 return AVERROR_INVALIDDATA;
     225          32 :             if (av_get_packet(pb, pkt, size) < 13)
     226           0 :                 return AVERROR(EIO);
     227             : 
     228          32 :             pkt->stream_index = smush->audio_stream_index;
     229          32 :             pkt->flags       |= AV_PKT_FLAG_KEY;
     230          32 :             pkt->duration     = AV_RB32(pkt->data);
     231          32 :             if (pkt->duration == 0xFFFFFFFFu)
     232          32 :                 pkt->duration = AV_RB32(pkt->data + 8);
     233          32 :             done = 1;
     234          32 :             break;
     235           0 :         default:
     236           0 :             avio_skip(pb, size);
     237           0 :             break;
     238             :         }
     239             :     }
     240             : 
     241          64 :     return 0;
     242             : }
     243             : 
     244             : AVInputFormat ff_smush_demuxer = {
     245             :     .name           = "smush",
     246             :     .long_name      = NULL_IF_CONFIG_SMALL("LucasArts Smush"),
     247             :     .priv_data_size = sizeof(SMUSHContext),
     248             :     .read_probe     = smush_read_probe,
     249             :     .read_header    = smush_read_header,
     250             :     .read_packet    = smush_read_packet,
     251             : };

Generated by: LCOV version 1.13