Subversion Repositories Kolibri OS

Rev

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

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