~ubuntu-branches/ubuntu/oneiric/gstreamer0.10-ffmpeg/oneiric-201108311726

« back to all changes in this revision

Viewing changes to gst-libs/ext/ffmpeg/libavformat/anm.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2010-02-19 18:14:59 UTC
  • mfrom: (4.1.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20100219181459-mect96st3px2jfsi
Tags: 0.10.9.2-1
* New upstream pre-release:
  + debian/patches/03_restricted-caps.patch,
    debian/patches/04_ignore-vdpau.patch:
    - Dropped, merged upstream.
* debian/patches/03_too-new-codec-ids.patch:
  + Disable some ffmpeg codec IDs because Debian's
    ffmpeg is once again too old...

Show diffs side-by-side

added added

removed removed

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