Subversion Repositories Kolibri OS

Rev

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