Subversion Repositories Kolibri OS

Rev

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

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