Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Deluxe Paint Animation demuxer
  3.  * Copyright (c) 2009 Peter Ross
  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.  * Deluxe Paint Animation demuxer
  25.  */
  26.  
  27. #include "libavutil/intreadwrite.h"
  28. #include "avformat.h"
  29. #include "internal.h"
  30.  
  31. typedef struct {
  32.     int base_record;
  33.     unsigned int nb_records;
  34.     int size;
  35. } Page;
  36.  
  37. typedef struct {
  38.     unsigned int nb_pages;    /**< total pages in file */
  39.     unsigned int nb_records;  /**< total records in file */
  40.     int page_table_offset;
  41. #define MAX_PAGES  256        /**< Deluxe Paint hardcoded value */
  42.     Page pt[MAX_PAGES];       /**< page table */
  43.     int page;                 /**< current page (or AVERROR_xxx code) */
  44.     int record;               /**< current record (with in page) */
  45. } AnmDemuxContext;
  46.  
  47. #define LPF_TAG  MKTAG('L','P','F',' ')
  48. #define ANIM_TAG MKTAG('A','N','I','M')
  49.  
  50. static int probe(AVProbeData *p)
  51. {
  52.     /* verify tags and video dimensions */
  53.     if (AV_RL32(&p->buf[0])  == LPF_TAG &&
  54.         AV_RL32(&p->buf[16]) == ANIM_TAG &&
  55.         AV_RL16(&p->buf[20]) && AV_RL16(&p->buf[22]))
  56.         return AVPROBE_SCORE_MAX;
  57.     return 0;
  58. }
  59.  
  60. /**
  61.  * @return page containing the requested record or AVERROR_XXX
  62.  */
  63. static int find_record(const AnmDemuxContext *anm, int record)
  64. {
  65.     int i;
  66.  
  67.     if (record >= anm->nb_records)
  68.         return AVERROR_EOF;
  69.  
  70.     for (i = 0; i < MAX_PAGES; i++) {
  71.         const Page *p = &anm->pt[i];
  72.         if (p->nb_records > 0 && record >= p->base_record && record < p->base_record + p->nb_records)
  73.             return i;
  74.     }
  75.  
  76.     return AVERROR_INVALIDDATA;
  77. }
  78.  
  79. static int read_header(AVFormatContext *s)
  80. {
  81.     AnmDemuxContext *anm = s->priv_data;
  82.     AVIOContext *pb = s->pb;
  83.     AVStream *st;
  84.     int i, ret;
  85.  
  86.     avio_skip(pb, 4); /* magic number */
  87.     if (avio_rl16(pb) != MAX_PAGES) {
  88.         avpriv_request_sample(s, "max_pages != " AV_STRINGIFY(MAX_PAGES));
  89.         return AVERROR_PATCHWELCOME;
  90.     }
  91.  
  92.     anm->nb_pages   = avio_rl16(pb);
  93.     anm->nb_records = avio_rl32(pb);
  94.     avio_skip(pb, 2); /* max records per page */
  95.     anm->page_table_offset = avio_rl16(pb);
  96.     if (avio_rl32(pb) != ANIM_TAG)
  97.         return AVERROR_INVALIDDATA;
  98.  
  99.     /* video stream */
  100.     st = avformat_new_stream(s, NULL);
  101.     if (!st)
  102.         return AVERROR(ENOMEM);
  103.     st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  104.     st->codec->codec_id   = AV_CODEC_ID_ANM;
  105.     st->codec->codec_tag  = 0; /* no fourcc */
  106.     st->codec->width      = avio_rl16(pb);
  107.     st->codec->height     = avio_rl16(pb);
  108.     if (avio_r8(pb) != 0)
  109.         goto invalid;
  110.     avio_skip(pb, 1); /* frame rate multiplier info */
  111.  
  112.     /* ignore last delta record (used for looping) */
  113.     if (avio_r8(pb))  /* has_last_delta */
  114.         anm->nb_records = FFMAX(anm->nb_records - 1, 0);
  115.  
  116.     avio_skip(pb, 1); /* last_delta_valid */
  117.  
  118.     if (avio_r8(pb) != 0)
  119.         goto invalid;
  120.  
  121.     if (avio_r8(pb) != 1)
  122.         goto invalid;
  123.  
  124.     avio_skip(pb, 1); /* other recs per frame */
  125.  
  126.     if (avio_r8(pb) != 1)
  127.         goto invalid;
  128.  
  129.     avio_skip(pb, 32); /* record_types */
  130.     st->nb_frames = avio_rl32(pb);
  131.     avpriv_set_pts_info(st, 64, 1, avio_rl16(pb));
  132.     avio_skip(pb, 58);
  133.  
  134.     /* color cycling and palette data */
  135.     st->codec->extradata_size = 16*8 + 4*256;
  136.     st->codec->extradata      = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
  137.     if (!st->codec->extradata) {
  138.         return AVERROR(ENOMEM);
  139.     }
  140.     ret = avio_read(pb, st->codec->extradata, st->codec->extradata_size);
  141.     if (ret < 0)
  142.         return ret;
  143.  
  144.     /* read page table */
  145.     ret = avio_seek(pb, anm->page_table_offset, SEEK_SET);
  146.     if (ret < 0)
  147.         return ret;
  148.  
  149.     for (i = 0; i < MAX_PAGES; i++) {
  150.         Page *p = &anm->pt[i];
  151.         p->base_record = avio_rl16(pb);
  152.         p->nb_records  = avio_rl16(pb);
  153.         p->size        = avio_rl16(pb);
  154.     }
  155.  
  156.     /* find page of first frame */
  157.     anm->page = find_record(anm, 0);
  158.     if (anm->page < 0) {
  159.         return anm->page;
  160.     }
  161.  
  162.     anm->record = -1;
  163.     return 0;
  164.  
  165. invalid:
  166.     avpriv_request_sample(s, "Invalid header element");
  167.     return AVERROR_PATCHWELCOME;
  168. }
  169.  
  170. static int read_packet(AVFormatContext *s,
  171.                        AVPacket *pkt)
  172. {
  173.     AnmDemuxContext *anm = s->priv_data;
  174.     AVIOContext *pb = s->pb;
  175.     Page *p;
  176.     int tmp, record_size;
  177.  
  178.     if (url_feof(s->pb))
  179.         return AVERROR(EIO);
  180.  
  181.     if (anm->page < 0)
  182.         return anm->page;
  183.  
  184. repeat:
  185.     p = &anm->pt[anm->page];
  186.  
  187.     /* parse page header */
  188.     if (anm->record < 0) {
  189.         avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16), SEEK_SET);
  190.         avio_skip(pb, 8 + 2*p->nb_records);
  191.         anm->record = 0;
  192.     }
  193.  
  194.     /* if we have fetched all records in this page, then find the
  195.        next page and repeat */
  196.     if (anm->record >= p->nb_records) {
  197.         anm->page = find_record(anm, p->base_record + p->nb_records);
  198.         if (anm->page < 0)
  199.             return anm->page;
  200.         anm->record = -1;
  201.         goto repeat;
  202.     }
  203.  
  204.     /* fetch record size */
  205.     tmp = avio_tell(pb);
  206.     avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16) +
  207.               8 + anm->record * 2, SEEK_SET);
  208.     record_size = avio_rl16(pb);
  209.     avio_seek(pb, tmp, SEEK_SET);
  210.  
  211.     /* fetch record */
  212.     pkt->size = av_get_packet(s->pb, pkt, record_size);
  213.     if (pkt->size < 0)
  214.         return pkt->size;
  215.     if (p->base_record + anm->record == 0)
  216.         pkt->flags |= AV_PKT_FLAG_KEY;
  217.  
  218.     anm->record++;
  219.     return 0;
  220. }
  221.  
  222. AVInputFormat ff_anm_demuxer = {
  223.     .name           = "anm",
  224.     .long_name      = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
  225.     .priv_data_size = sizeof(AnmDemuxContext),
  226.     .read_probe     = probe,
  227.     .read_header    = read_header,
  228.     .read_packet    = read_packet,
  229. };
  230.