LCOV - code coverage report
Current view: top level - libavformat - smacker.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 159 212 75.0 %
Date: 2017-12-15 11:05:35 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Smacker demuxer
       3             :  * Copyright (c) 2006 Konstantin Shishkov
       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             :  * Based on http://wiki.multimedia.cx/index.php?title=Smacker
      24             :  */
      25             : 
      26             : #include <inttypes.h>
      27             : 
      28             : #include "libavutil/bswap.h"
      29             : #include "libavutil/channel_layout.h"
      30             : #include "libavutil/intreadwrite.h"
      31             : #include "avformat.h"
      32             : #include "internal.h"
      33             : 
      34             : #define SMACKER_PAL 0x01
      35             : #define SMACKER_FLAG_RING_FRAME 0x01
      36             : 
      37             : enum SAudFlags {
      38             :     SMK_AUD_PACKED  = 0x80,
      39             :     SMK_AUD_16BITS  = 0x20,
      40             :     SMK_AUD_STEREO  = 0x10,
      41             :     SMK_AUD_BINKAUD = 0x08,
      42             :     SMK_AUD_USEDCT  = 0x04
      43             : };
      44             : 
      45             : typedef struct SmackerContext {
      46             :     /* Smacker file header */
      47             :     uint32_t magic;
      48             :     uint32_t width, height;
      49             :     uint32_t frames;
      50             :     int      pts_inc;
      51             :     uint32_t flags;
      52             :     uint32_t audio[7];
      53             :     uint32_t treesize;
      54             :     uint32_t mmap_size, mclr_size, full_size, type_size;
      55             :     uint8_t  aflags[7];
      56             :     uint32_t rates[7];
      57             :     uint32_t pad;
      58             :     /* frame info */
      59             :     uint32_t *frm_size;
      60             :     uint8_t  *frm_flags;
      61             :     /* internal variables */
      62             :     int cur_frame;
      63             :     int is_ver4;
      64             :     int64_t cur_pts;
      65             :     /* current frame for demuxing */
      66             :     uint8_t pal[768];
      67             :     int indexes[7];
      68             :     int videoindex;
      69             :     uint8_t *bufs[7];
      70             :     int buf_sizes[7];
      71             :     int stream_id[7];
      72             :     int curstream;
      73             :     int64_t nextpos;
      74             :     int64_t aud_pts[7];
      75             : } SmackerContext;
      76             : 
      77             : typedef struct SmackerFrame {
      78             :     int64_t pts;
      79             :     int stream;
      80             : } SmackerFrame;
      81             : 
      82             : /* palette used in Smacker */
      83             : static const uint8_t smk_pal[64] = {
      84             :     0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
      85             :     0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
      86             :     0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
      87             :     0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
      88             :     0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
      89             :     0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
      90             :     0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
      91             :     0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
      92             : };
      93             : 
      94             : 
      95        6130 : static int smacker_probe(AVProbeData *p)
      96             : {
      97        6130 :     if (   AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2')
      98        6128 :         && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4'))
      99        6128 :         return 0;
     100             : 
     101           2 :     if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U)
     102           0 :         return AVPROBE_SCORE_MAX/4;
     103             : 
     104           2 :     return AVPROBE_SCORE_MAX;
     105             : }
     106             : 
     107           2 : static int smacker_read_header(AVFormatContext *s)
     108             : {
     109           2 :     AVIOContext *pb = s->pb;
     110           2 :     SmackerContext *smk = s->priv_data;
     111             :     AVStream *st, *ast[7];
     112             :     int i, ret;
     113             :     int tbase;
     114             : 
     115             :     /* read and check header */
     116           2 :     smk->magic = avio_rl32(pb);
     117           2 :     if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4'))
     118           0 :         return AVERROR_INVALIDDATA;
     119           2 :     smk->width = avio_rl32(pb);
     120           2 :     smk->height = avio_rl32(pb);
     121           2 :     smk->frames = avio_rl32(pb);
     122           2 :     smk->pts_inc = (int32_t)avio_rl32(pb);
     123           2 :     if (smk->pts_inc > INT_MAX / 100) {
     124           0 :         av_log(s, AV_LOG_ERROR, "pts_inc %d is too large\n", smk->pts_inc);
     125           0 :         return AVERROR_INVALIDDATA;
     126             :     }
     127             : 
     128           2 :     smk->flags = avio_rl32(pb);
     129           2 :     if(smk->flags & SMACKER_FLAG_RING_FRAME)
     130           0 :         smk->frames++;
     131          16 :     for(i = 0; i < 7; i++)
     132          14 :         smk->audio[i] = avio_rl32(pb);
     133           2 :     smk->treesize = avio_rl32(pb);
     134             : 
     135           2 :     if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant)
     136           0 :         av_log(s, AV_LOG_ERROR, "treesize too large\n");
     137           0 :         return AVERROR_INVALIDDATA;
     138             :     }
     139             : 
     140             : //FIXME remove extradata "rebuilding"
     141           2 :     smk->mmap_size = avio_rl32(pb);
     142           2 :     smk->mclr_size = avio_rl32(pb);
     143           2 :     smk->full_size = avio_rl32(pb);
     144           2 :     smk->type_size = avio_rl32(pb);
     145          16 :     for(i = 0; i < 7; i++) {
     146          14 :         smk->rates[i]  = avio_rl24(pb);
     147          14 :         smk->aflags[i] = avio_r8(pb);
     148             :     }
     149           2 :     smk->pad = avio_rl32(pb);
     150             :     /* setup data */
     151           2 :     if(smk->frames > 0xFFFFFF) {
     152           0 :         av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n", smk->frames);
     153           0 :         return AVERROR_INVALIDDATA;
     154             :     }
     155           2 :     smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size));
     156           2 :     smk->frm_flags = av_malloc(smk->frames);
     157           2 :     if (!smk->frm_size || !smk->frm_flags) {
     158           0 :         av_freep(&smk->frm_size);
     159           0 :         av_freep(&smk->frm_flags);
     160           0 :         return AVERROR(ENOMEM);
     161             :     }
     162             : 
     163           2 :     smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2'));
     164             : 
     165             :     /* read frame info */
     166         202 :     for(i = 0; i < smk->frames; i++) {
     167         200 :         smk->frm_size[i] = avio_rl32(pb);
     168             :     }
     169         202 :     for(i = 0; i < smk->frames; i++) {
     170         200 :         smk->frm_flags[i] = avio_r8(pb);
     171             :     }
     172             : 
     173             :     /* init video codec */
     174           2 :     st = avformat_new_stream(s, NULL);
     175           2 :     if (!st)
     176           0 :         return AVERROR(ENOMEM);
     177           2 :     smk->videoindex = st->index;
     178           2 :     st->codecpar->width = smk->width;
     179           2 :     st->codecpar->height = smk->height;
     180           2 :     st->codecpar->format = AV_PIX_FMT_PAL8;
     181           2 :     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     182           2 :     st->codecpar->codec_id = AV_CODEC_ID_SMACKVIDEO;
     183           2 :     st->codecpar->codec_tag = smk->magic;
     184             :     /* Smacker uses 100000 as internal timebase */
     185           2 :     if(smk->pts_inc < 0)
     186           0 :         smk->pts_inc = -smk->pts_inc;
     187             :     else
     188           2 :         smk->pts_inc *= 100;
     189           2 :     tbase = 100000;
     190           2 :     av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1);
     191           2 :     avpriv_set_pts_info(st, 33, smk->pts_inc, tbase);
     192           2 :     st->duration = smk->frames;
     193             :     /* handle possible audio streams */
     194          16 :     for(i = 0; i < 7; i++) {
     195          14 :         smk->indexes[i] = -1;
     196          14 :         if (smk->rates[i]) {
     197           2 :             ast[i] = avformat_new_stream(s, NULL);
     198           2 :             if (!ast[i])
     199           0 :                 return AVERROR(ENOMEM);
     200           2 :             smk->indexes[i] = ast[i]->index;
     201           2 :             ast[i]->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     202           2 :             if (smk->aflags[i] & SMK_AUD_BINKAUD) {
     203           0 :                 ast[i]->codecpar->codec_id = AV_CODEC_ID_BINKAUDIO_RDFT;
     204           2 :             } else if (smk->aflags[i] & SMK_AUD_USEDCT) {
     205           0 :                 ast[i]->codecpar->codec_id = AV_CODEC_ID_BINKAUDIO_DCT;
     206           2 :             } else if (smk->aflags[i] & SMK_AUD_PACKED){
     207           2 :                 ast[i]->codecpar->codec_id = AV_CODEC_ID_SMACKAUDIO;
     208           2 :                 ast[i]->codecpar->codec_tag = MKTAG('S', 'M', 'K', 'A');
     209             :             } else {
     210           0 :                 ast[i]->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
     211             :             }
     212           2 :             if (smk->aflags[i] & SMK_AUD_STEREO) {
     213           0 :                 ast[i]->codecpar->channels       = 2;
     214           0 :                 ast[i]->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
     215             :             } else {
     216           2 :                 ast[i]->codecpar->channels       = 1;
     217           2 :                 ast[i]->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
     218             :             }
     219           2 :             ast[i]->codecpar->sample_rate = smk->rates[i];
     220           2 :             ast[i]->codecpar->bits_per_coded_sample = (smk->aflags[i] & SMK_AUD_16BITS) ? 16 : 8;
     221           2 :             if(ast[i]->codecpar->bits_per_coded_sample == 16 && ast[i]->codecpar->codec_id == AV_CODEC_ID_PCM_U8)
     222           0 :                 ast[i]->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
     223           4 :             avpriv_set_pts_info(ast[i], 64, 1, ast[i]->codecpar->sample_rate
     224           2 :                     * ast[i]->codecpar->channels * ast[i]->codecpar->bits_per_coded_sample / 8);
     225             :         }
     226             :     }
     227             : 
     228             : 
     229             :     /* load trees to extradata, they will be unpacked by decoder */
     230           2 :     if(ff_alloc_extradata(st->codecpar, smk->treesize + 16)){
     231           0 :         av_log(s, AV_LOG_ERROR,
     232             :                "Cannot allocate %"PRIu32" bytes of extradata\n",
     233           0 :                smk->treesize + 16);
     234           0 :         av_freep(&smk->frm_size);
     235           0 :         av_freep(&smk->frm_flags);
     236           0 :         return AVERROR(ENOMEM);
     237             :     }
     238           2 :     ret = avio_read(pb, st->codecpar->extradata + 16, st->codecpar->extradata_size - 16);
     239           2 :     if(ret != st->codecpar->extradata_size - 16){
     240           0 :         av_freep(&smk->frm_size);
     241           0 :         av_freep(&smk->frm_flags);
     242           0 :         return AVERROR(EIO);
     243             :     }
     244           2 :     ((int32_t*)st->codecpar->extradata)[0] = av_le2ne32(smk->mmap_size);
     245           2 :     ((int32_t*)st->codecpar->extradata)[1] = av_le2ne32(smk->mclr_size);
     246           2 :     ((int32_t*)st->codecpar->extradata)[2] = av_le2ne32(smk->full_size);
     247           2 :     ((int32_t*)st->codecpar->extradata)[3] = av_le2ne32(smk->type_size);
     248             : 
     249           2 :     smk->curstream = -1;
     250           2 :     smk->nextpos = avio_tell(pb);
     251             : 
     252           2 :     return 0;
     253             : }
     254             : 
     255             : 
     256         374 : static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
     257             : {
     258         374 :     SmackerContext *smk = s->priv_data;
     259             :     int flags;
     260             :     int ret;
     261             :     int i;
     262         374 :     int frame_size = 0;
     263         374 :     int palchange = 0;
     264             : 
     265         374 :     if (avio_feof(s->pb) || smk->cur_frame >= smk->frames)
     266           2 :         return AVERROR_EOF;
     267             : 
     268             :     /* if we demuxed all streams, pass another frame */
     269         372 :     if(smk->curstream < 0) {
     270         200 :         avio_seek(s->pb, smk->nextpos, 0);
     271         200 :         frame_size = smk->frm_size[smk->cur_frame] & (~3);
     272         200 :         flags = smk->frm_flags[smk->cur_frame];
     273             :         /* handle palette change event */
     274         200 :         if(flags & SMACKER_PAL){
     275             :             int size, sz, t, off, j, pos;
     276           2 :             uint8_t *pal = smk->pal;
     277             :             uint8_t oldpal[768];
     278             : 
     279           2 :             memcpy(oldpal, pal, 768);
     280           2 :             size = avio_r8(s->pb);
     281           2 :             size = size * 4 - 1;
     282           2 :             if(size + 1 > frame_size)
     283           0 :                 return AVERROR_INVALIDDATA;
     284           2 :             frame_size -= size;
     285           2 :             frame_size--;
     286           2 :             sz = 0;
     287           2 :             pos = avio_tell(s->pb) + size;
     288         516 :             while(sz < 256){
     289         512 :                 t = avio_r8(s->pb);
     290         512 :                 if(t & 0x80){ /* skip palette entries */
     291           2 :                     sz += (t & 0x7F) + 1;
     292           2 :                     pal += ((t & 0x7F) + 1) * 3;
     293         510 :                 } else if(t & 0x40){ /* copy with offset */
     294           0 :                     off = avio_r8(s->pb);
     295           0 :                     j = (t & 0x3F) + 1;
     296           0 :                     if (off + j > 0x100) {
     297           0 :                         av_log(s, AV_LOG_ERROR,
     298             :                                "Invalid palette update, offset=%d length=%d extends beyond palette size\n",
     299             :                                off, j);
     300           0 :                         return AVERROR_INVALIDDATA;
     301             :                     }
     302           0 :                     off *= 3;
     303           0 :                     while(j-- && sz < 256) {
     304           0 :                         *pal++ = oldpal[off + 0];
     305           0 :                         *pal++ = oldpal[off + 1];
     306           0 :                         *pal++ = oldpal[off + 2];
     307           0 :                         sz++;
     308           0 :                         off += 3;
     309             :                     }
     310             :                 } else { /* new entries */
     311         510 :                     *pal++ = smk_pal[t];
     312         510 :                     *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
     313         510 :                     *pal++ = smk_pal[avio_r8(s->pb) & 0x3F];
     314         510 :                     sz++;
     315             :                 }
     316             :             }
     317           2 :             avio_seek(s->pb, pos, 0);
     318           2 :             palchange |= 1;
     319             :         }
     320         200 :         flags >>= 1;
     321         200 :         smk->curstream = -1;
     322             :         /* if audio chunks are present, put them to stack and retrieve later */
     323        1600 :         for(i = 0; i < 7; i++) {
     324        1400 :             if(flags & 1) {
     325             :                 uint32_t size;
     326             :                 int err;
     327             : 
     328         172 :                 size = avio_rl32(s->pb) - 4;
     329         172 :                 if (!size || size + 4LL > frame_size) {
     330           0 :                     av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
     331           0 :                     return AVERROR_INVALIDDATA;
     332             :                 }
     333         172 :                 frame_size -= size;
     334         172 :                 frame_size -= 4;
     335         172 :                 smk->curstream++;
     336         172 :                 if ((err = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) {
     337           0 :                     smk->buf_sizes[smk->curstream] = 0;
     338           0 :                     return err;
     339             :                 }
     340         172 :                 smk->buf_sizes[smk->curstream] = size;
     341         172 :                 ret = avio_read(s->pb, smk->bufs[smk->curstream], size);
     342         172 :                 if(ret != size)
     343           0 :                     return AVERROR(EIO);
     344         172 :                 smk->stream_id[smk->curstream] = smk->indexes[i];
     345             :             }
     346        1400 :             flags >>= 1;
     347             :         }
     348         200 :         if (frame_size < 0 || frame_size >= INT_MAX/2)
     349           0 :             return AVERROR_INVALIDDATA;
     350         200 :         if (av_new_packet(pkt, frame_size + 769))
     351           0 :             return AVERROR(ENOMEM);
     352         200 :         if(smk->frm_size[smk->cur_frame] & 1)
     353           0 :             palchange |= 2;
     354         200 :         pkt->data[0] = palchange;
     355         200 :         memcpy(pkt->data + 1, smk->pal, 768);
     356         200 :         ret = avio_read(s->pb, pkt->data + 769, frame_size);
     357         200 :         if(ret != frame_size)
     358           0 :             return AVERROR(EIO);
     359         200 :         pkt->stream_index = smk->videoindex;
     360         200 :         pkt->pts          = smk->cur_frame;
     361         200 :         pkt->size = ret + 769;
     362         200 :         smk->cur_frame++;
     363         200 :         smk->nextpos = avio_tell(s->pb);
     364             :     } else {
     365         172 :         if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream])
     366           0 :             return AVERROR_INVALIDDATA;
     367         172 :         if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
     368           0 :             return AVERROR(ENOMEM);
     369         172 :         memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]);
     370         172 :         pkt->size = smk->buf_sizes[smk->curstream];
     371         172 :         pkt->stream_index = smk->stream_id[smk->curstream];
     372         172 :         pkt->pts = smk->aud_pts[smk->curstream];
     373         172 :         smk->aud_pts[smk->curstream] += AV_RL32(pkt->data);
     374         172 :         smk->curstream--;
     375             :     }
     376             : 
     377         372 :     return 0;
     378             : }
     379             : 
     380           2 : static int smacker_read_close(AVFormatContext *s)
     381             : {
     382           2 :     SmackerContext *smk = s->priv_data;
     383             :     int i;
     384             : 
     385          16 :     for(i = 0; i < 7; i++)
     386          14 :         av_freep(&smk->bufs[i]);
     387           2 :     av_freep(&smk->frm_size);
     388           2 :     av_freep(&smk->frm_flags);
     389             : 
     390           2 :     return 0;
     391             : }
     392             : 
     393             : AVInputFormat ff_smacker_demuxer = {
     394             :     .name           = "smk",
     395             :     .long_name      = NULL_IF_CONFIG_SMALL("Smacker"),
     396             :     .priv_data_size = sizeof(SmackerContext),
     397             :     .read_probe     = smacker_probe,
     398             :     .read_header    = smacker_read_header,
     399             :     .read_packet    = smacker_read_packet,
     400             :     .read_close     = smacker_read_close,
     401             : };

Generated by: LCOV version 1.13