swfdec.c 17.7 KB
Newer Older
B
Baptiste Coudurier 已提交
1
/*
B
Baptiste Coudurier 已提交
2
 * Flash Compatible Streaming Format demuxer
3 4
 * Copyright (c) 2000 Fabrice Bellard
 * Copyright (c) 2003 Tinic Uro
B
Baptiste Coudurier 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

23
#include "libavutil/avassert.h"
J
Justin Ruggles 已提交
24
#include "libavutil/channel_layout.h"
25
#include "libavutil/imgutils.h"
26
#include "libavutil/intreadwrite.h"
27
#include "libavcodec/get_bits.h"
B
Baptiste Coudurier 已提交
28 29
#include "swf.h"

30
static const AVCodecTag swf_audio_codec_tags[] = {
31 32 33 34 35 36
    { AV_CODEC_ID_PCM_S16LE,  0x00 },
    { AV_CODEC_ID_ADPCM_SWF,  0x01 },
    { AV_CODEC_ID_MP3,        0x02 },
    { AV_CODEC_ID_PCM_S16LE,  0x03 },
//  { AV_CODEC_ID_NELLYMOSER, 0x06 },
    { AV_CODEC_ID_NONE,          0 },
37 38
};

39
static int get_swf_tag(AVIOContext *pb, int *len_ptr)
B
Baptiste Coudurier 已提交
40 41 42
{
    int tag, len;

43
    if (avio_feof(pb))
44
        return AVERROR_EOF;
B
Baptiste Coudurier 已提交
45

46
    tag = avio_rl16(pb);
B
Baptiste Coudurier 已提交
47 48 49
    len = tag & 0x3f;
    tag = tag >> 6;
    if (len == 0x3f) {
50
        len = avio_rl32(pb);
B
Baptiste Coudurier 已提交
51 52 53 54 55 56 57 58
    }
    *len_ptr = len;
    return tag;
}


static int swf_probe(AVProbeData *p)
{
59 60 61
    GetBitContext gb;
    int len, xmin, xmax, ymin, ymax;

62 63 64
    if(p->buf_size < 15)
        return 0;

B
Baptiste Coudurier 已提交
65
    /* check file header */
66 67
    if (   AV_RB24(p->buf) != AV_RB24("CWS")
        && AV_RB24(p->buf) != AV_RB24("FWS"))
B
Baptiste Coudurier 已提交
68
        return 0;
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83
    init_get_bits8(&gb, p->buf + 3, p->buf_size - 3);

    skip_bits(&gb, 40);
    len = get_bits(&gb, 5);
    if (!len)
        return 0;
    xmin = get_bits_long(&gb, len);
    xmax = get_bits_long(&gb, len);
    ymin = get_bits_long(&gb, len);
    ymax = get_bits_long(&gb, len);
    if (xmin || ymin || !xmax || !ymax)
        return 0;

    if (p->buf[3] >= 20 || xmax < 16 || ymax < 16)
84 85 86
        return AVPROBE_SCORE_MAX / 4;

    return AVPROBE_SCORE_MAX;
B
Baptiste Coudurier 已提交
87 88
}

89 90 91 92 93 94 95 96 97 98 99
#if CONFIG_ZLIB
static int zlib_refill(void *opaque, uint8_t *buf, int buf_size)
{
    AVFormatContext *s = opaque;
    SWFContext *swf = s->priv_data;
    z_stream *z = &swf->zstream;
    int ret;

retry:
    if (!z->avail_in) {
        int n = avio_read(s->pb, swf->zbuf_in, ZBUF_SIZE);
100
        if (n < 0)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
            return n;
        z->next_in  = swf->zbuf_in;
        z->avail_in = n;
    }

    z->next_out  = buf;
    z->avail_out = buf_size;

    ret = inflate(z, Z_NO_FLUSH);
    if (ret < 0)
        return AVERROR(EINVAL);
    if (ret == Z_STREAM_END)
        return AVERROR_EOF;

    if (buf_size - z->avail_out == 0)
        goto retry;

    return buf_size - z->avail_out;
}
#endif

122
static int swf_read_header(AVFormatContext *s)
B
Baptiste Coudurier 已提交
123 124
{
    SWFContext *swf = s->priv_data;
125
    AVIOContext *pb = s->pb;
B
Baptiste Coudurier 已提交
126 127
    int nbits, len, tag;

128
    tag = avio_rb32(pb) & 0xffffff00;
129
    avio_rl32(pb);
B
Baptiste Coudurier 已提交
130 131

    if (tag == MKBETAG('C', 'W', 'S', 0)) {
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
        av_log(s, AV_LOG_INFO, "SWF compressed file detected\n");
#if CONFIG_ZLIB
        swf->zbuf_in  = av_malloc(ZBUF_SIZE);
        swf->zbuf_out = av_malloc(ZBUF_SIZE);
        swf->zpb = avio_alloc_context(swf->zbuf_out, ZBUF_SIZE, 0, s,
                                      zlib_refill, NULL, NULL);
        if (!swf->zbuf_in || !swf->zbuf_out || !swf->zpb)
            return AVERROR(ENOMEM);
        swf->zpb->seekable = 0;
        if (inflateInit(&swf->zstream) != Z_OK) {
            av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
            return AVERROR(EINVAL);
        }
        pb = swf->zpb;
#else
        av_log(s, AV_LOG_ERROR, "zlib support is required to read SWF compressed files\n");
B
Baptiste Coudurier 已提交
148
        return AVERROR(EIO);
149 150
#endif
    } else if (tag != MKBETAG('F', 'W', 'S', 0))
B
Baptiste Coudurier 已提交
151 152
        return AVERROR(EIO);
    /* skip rectangle size */
153
    nbits = avio_r8(pb) >> 3;
B
Baptiste Coudurier 已提交
154
    len = (4 * nbits - 3 + 7) / 8;
155
    avio_skip(pb, len);
156 157
    swf->frame_rate = avio_rl16(pb); /* 8.8 fixed */
    avio_rl16(pb); /* frame count */
B
Baptiste Coudurier 已提交
158 159 160 161 162 163

    swf->samples_per_frame = 0;
    s->ctx_flags |= AVFMTCTX_NOHEADER;
    return 0;
}

164 165
static AVStream *create_new_audio_stream(AVFormatContext *s, int id, int info)
{
166
    int sample_rate_code, sample_size_code;
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    AVStream *ast = avformat_new_stream(s, NULL);
    if (!ast)
        return NULL;
    ast->id = id;
    if (info & 1) {
        ast->codec->channels       = 2;
        ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
    } else {
        ast->codec->channels       = 1;
        ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
    }
    ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
    ast->codec->codec_id   = ff_codec_get_id(swf_audio_codec_tags, info>>4 & 15);
    ast->need_parsing = AVSTREAM_PARSE_FULL;
    sample_rate_code = info>>2 & 3;
182 183 184
    sample_size_code = info>>1 & 1;
    if (!sample_size_code && ast->codec->codec_id == AV_CODEC_ID_PCM_S16LE)
        ast->codec->codec_id = AV_CODEC_ID_PCM_U8;
185 186 187 188 189
    ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
    avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
    return ast;
}

B
Baptiste Coudurier 已提交
190 191 192
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    SWFContext *swf = s->priv_data;
193
    AVIOContext *pb = s->pb;
B
Baptiste Coudurier 已提交
194
    AVStream *vst = NULL, *ast = NULL, *st = 0;
195
    int tag, len, i, frame, v, res;
B
Baptiste Coudurier 已提交
196

197 198 199 200 201
#if CONFIG_ZLIB
    if (swf->zpb)
        pb = swf->zpb;
#endif

B
Baptiste Coudurier 已提交
202
    for(;;) {
203
        uint64_t pos = avio_tell(pb);
B
Baptiste Coudurier 已提交
204 205
        tag = get_swf_tag(pb, &len);
        if (tag < 0)
206
            return tag;
M
Michael Niedermayer 已提交
207
        if (len < 0) {
208
            av_log(s, AV_LOG_ERROR, "invalid tag length: %d\n", len);
M
Michael Niedermayer 已提交
209 210
            return AVERROR_INVALIDDATA;
        }
211
        if (tag == TAG_VIDEOSTREAM) {
212
            int ch_id = avio_rl16(pb);
213 214 215 216
            len -= 2;

            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
217
                if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id)
218 219 220
                    goto skip;
            }

221 222 223 224
            avio_rl16(pb);
            avio_rl16(pb);
            avio_rl16(pb);
            avio_r8(pb);
B
Baptiste Coudurier 已提交
225
            /* Check for FLV1 */
226
            vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
227
            if (!vst)
228
                return AVERROR(ENOMEM);
229
            vst->id = ch_id;
230
            vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
231
            vst->codec->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
232
            avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
233 234
            len -= 8;
        } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
B
Baptiste Coudurier 已提交
235
            /* streaming found */
236 237 238

            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
239
                if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1)
240 241 242
                    goto skip;
            }

243 244 245
            avio_r8(pb);
            v = avio_r8(pb);
            swf->samples_per_frame = avio_rl16(pb);
246
            ast = create_new_audio_stream(s, -1, v); /* -1 to avoid clash with video stream ch_id */
B
Baptiste Coudurier 已提交
247
            if (!ast)
248
                return AVERROR(ENOMEM);
B
Baptiste Coudurier 已提交
249
            len -= 4;
250 251 252 253 254 255 256 257 258 259 260 261 262 263
        } else if (tag == TAG_DEFINESOUND) {
            /* audio stream */
            int ch_id = avio_rl16(pb);

            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
                if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == ch_id)
                    goto skip;
            }

            // FIXME: The entire audio stream is stored in a single chunk/tag. Normally,
            // these are smaller audio streams in DEFINESOUND tags, but it's technically
            // possible they could be huge. Break it up into multiple packets if it's big.
            v = avio_r8(pb);
264
            ast = create_new_audio_stream(s, ch_id, v);
265
            if (!ast)
266
                return AVERROR(ENOMEM);
267 268 269 270 271 272 273 274 275 276 277
            ast->duration = avio_rl32(pb); // number of samples
            if (((v>>4) & 15) == 2) { // MP3 sound data record
                ast->skip_samples = avio_rl16(pb);
                len -= 2;
            }
            len -= 7;
            if ((res = av_get_packet(pb, pkt, len)) < 0)
                return res;
            pkt->pos = pos;
            pkt->stream_index = ast->index;
            return pkt->size;
B
Baptiste Coudurier 已提交
278
        } else if (tag == TAG_VIDEOFRAME) {
279
            int ch_id = avio_rl16(pb);
B
Baptiste Coudurier 已提交
280 281 282
            len -= 2;
            for(i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
283
                if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
284
                    frame = avio_rl16(pb);
285 286 287 288
                    len -= 2;
                    if (len <= 0)
                        goto skip;
                    if ((res = av_get_packet(pb, pkt, len)) < 0)
289
                        return res;
290
                    pkt->pos = pos;
B
Baptiste Coudurier 已提交
291 292 293 294 295
                    pkt->pts = frame;
                    pkt->stream_index = st->index;
                    return pkt->size;
                }
            }
296 297 298 299 300 301 302 303 304 305 306 307 308
        } else if (tag == TAG_DEFINEBITSLOSSLESS || tag == TAG_DEFINEBITSLOSSLESS2) {
#if CONFIG_ZLIB
            long out_len;
            uint8_t *buf = NULL, *zbuf = NULL, *pal;
            uint32_t colormap[AVPALETTE_COUNT] = {0};
            const int alpha_bmp = tag == TAG_DEFINEBITSLOSSLESS2;
            const int colormapbpp = 3 + alpha_bmp;
            int linesize, colormapsize = 0;

            const int ch_id   = avio_rl16(pb);
            const int bmp_fmt = avio_r8(pb);
            const int width   = avio_rl16(pb);
            const int height  = avio_rl16(pb);
309
            int pix_fmt;
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

            len -= 2+1+2+2;

            switch (bmp_fmt) {
            case 3: // PAL-8
                linesize = width;
                colormapsize = avio_r8(pb) + 1;
                len--;
                break;
            case 4: // RGB15
                linesize = width * 2;
                break;
            case 5: // RGB24 (0RGB)
                linesize = width * 4;
                break;
            default:
                av_log(s, AV_LOG_ERROR, "invalid bitmap format %d, skipped\n", bmp_fmt);
                goto bitmap_end_skip;
            }

            linesize = FFALIGN(linesize, 4);

            if (av_image_check_size(width, height, 0, s) < 0 ||
                linesize >= INT_MAX / height ||
                linesize * height >= INT_MAX - colormapsize * colormapbpp) {
                av_log(s, AV_LOG_ERROR, "invalid frame size %dx%d\n", width, height);
                goto bitmap_end_skip;
            }

            out_len = colormapsize * colormapbpp + linesize * height;

            av_dlog(s, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n",
                    ch_id, bmp_fmt, width, height, linesize, len, out_len, colormapsize);

            zbuf = av_malloc(len);
            buf  = av_malloc(out_len);
            if (!zbuf || !buf) {
                res = AVERROR(ENOMEM);
                goto bitmap_end;
            }

            len = avio_read(pb, zbuf, len);
            if (len < 0 || (res = uncompress(buf, &out_len, zbuf, len)) != Z_OK) {
                av_log(s, AV_LOG_WARNING, "Failed to uncompress one bitmap\n");
                goto bitmap_end_skip;
            }

            for (i = 0; i < s->nb_streams; i++) {
                st = s->streams[i];
                if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && st->id == -3)
                    break;
            }
            if (i == s->nb_streams) {
                vst = avformat_new_stream(s, NULL);
                if (!vst) {
                    res = AVERROR(ENOMEM);
                    goto bitmap_end;
                }
                vst->id = -3; /* -3 to avoid clash with video stream and audio stream */
                vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
                vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
                st = vst;
            }

            if ((res = av_new_packet(pkt, out_len - colormapsize * colormapbpp)) < 0)
                goto bitmap_end;
377 378 379 380 381 382
            if (!st->codec->width && !st->codec->height) {
                st->codec->width  = width;
                st->codec->height = height;
            } else {
                ff_add_param_change(pkt, 0, 0, 0, width, height);
            }
383 384 385 386 387
            pkt->pos = pos;
            pkt->stream_index = st->index;

            switch (bmp_fmt) {
            case 3:
388
                pix_fmt = AV_PIX_FMT_PAL8;
389 390 391 392 393 394 395 396 397 398 399
                for (i = 0; i < colormapsize; i++)
                    if (alpha_bmp)  colormap[i] = buf[3]<<24 | AV_RB24(buf + 4*i);
                    else            colormap[i] = 0xffU <<24 | AV_RB24(buf + 3*i);
                pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
                if (!pal) {
                    res = AVERROR(ENOMEM);
                    goto bitmap_end;
                }
                memcpy(pal, colormap, AVPALETTE_SIZE);
                break;
            case 4:
400
                pix_fmt = AV_PIX_FMT_RGB555;
401 402
                break;
            case 5:
403
                pix_fmt = alpha_bmp ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
404 405 406 407
                break;
            default:
                av_assert0(0);
            }
408 409
            if (st->codec->pix_fmt != AV_PIX_FMT_NONE && st->codec->pix_fmt != pix_fmt) {
                av_log(s, AV_LOG_ERROR, "pixel format change unsupported\n");
410
            } else
411
                st->codec->pix_fmt = pix_fmt;
412 413 414 415 416

            if (linesize * height > pkt->size) {
                res = AVERROR_INVALIDDATA;
                goto bitmap_end;
            }
417 418 419 420 421 422 423 424 425 426 427 428 429 430
            memcpy(pkt->data, buf + colormapsize*colormapbpp, linesize * height);

            res = pkt->size;

bitmap_end:
            av_freep(&zbuf);
            av_freep(&buf);
            return res;
bitmap_end_skip:
            av_freep(&zbuf);
            av_freep(&buf);
#else
            av_log(s, AV_LOG_ERROR, "this file requires zlib support compiled in\n");
#endif
B
Baptiste Coudurier 已提交
431
        } else if (tag == TAG_STREAMBLOCK) {
432 433
            for (i = 0; i < s->nb_streams; i++) {
                st = s->streams[i];
434
                if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
                    if (st->codec->codec_id == AV_CODEC_ID_MP3) {
                        avio_skip(pb, 4);
                        len -= 4;
                        if (len <= 0)
                            goto skip;
                        if ((res = av_get_packet(pb, pkt, len)) < 0)
                            return res;
                    } else { // ADPCM, PCM
                        if (len <= 0)
                            goto skip;
                        if ((res = av_get_packet(pb, pkt, len)) < 0)
                            return res;
                    }
                    pkt->pos          = pos;
                    pkt->stream_index = st->index;
                    return pkt->size;
451 452
                }
            }
B
Baptiste Coudurier 已提交
453 454 455
        } else if (tag == TAG_JPEG2) {
            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
456
                if (st->codec->codec_id == AV_CODEC_ID_MJPEG && st->id == -2)
B
Baptiste Coudurier 已提交
457 458 459
                    break;
            }
            if (i == s->nb_streams) {
460
                vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
461
                if (!vst)
462
                    return AVERROR(ENOMEM);
463
                vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
464
                vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
465
                vst->codec->codec_id = AV_CODEC_ID_MJPEG;
466
                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
B
Baptiste Coudurier 已提交
467 468
                st = vst;
            }
469
            avio_rl16(pb); /* BITMAP_ID */
470 471 472 473
            len -= 2;
            if (len < 4)
                goto skip;
            if ((res = av_new_packet(pkt, len)) < 0)
474
                return res;
475 476 477 478
            if (avio_read(pb, pkt->data, 4) != 4) {
                av_free_packet(pkt);
                return AVERROR_INVALIDDATA;
            }
B
Baptiste Coudurier 已提交
479 480 481 482 483
            if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
                AV_RB32(pkt->data) == 0xffd9ffd8) {
                /* old SWF files containing SOI/EOI as data start */
                /* files created by swink have reversed tag */
                pkt->size -= 4;
484
                memset(pkt->data+pkt->size, 0, 4);
485
                res = avio_read(pb, pkt->data, pkt->size);
B
Baptiste Coudurier 已提交
486
            } else {
487 488 489
                res = avio_read(pb, pkt->data + 4, pkt->size - 4);
                if (res >= 0)
                    res += 4;
B
Baptiste Coudurier 已提交
490
            }
491 492 493 494 495 496 497 498
            if (res != pkt->size) {
                if (res < 0) {
                    av_free_packet(pkt);
                    return res;
                }
                av_shrink_packet(pkt, res);
            }

499
            pkt->pos = pos;
B
Baptiste Coudurier 已提交
500 501
            pkt->stream_index = st->index;
            return pkt->size;
502 503
        } else {
            av_log(s, AV_LOG_DEBUG, "Unknown tag: %d\n", tag);
B
Baptiste Coudurier 已提交
504
        }
505
    skip:
506 507
        if(len<0)
            av_log(s, AV_LOG_WARNING, "Cliping len %d\n", len);
508
        len = FFMAX(0, len);
509
        avio_skip(pb, len);
B
Baptiste Coudurier 已提交
510 511 512
    }
}

513 514 515 516 517 518 519 520 521 522 523 524
#if CONFIG_ZLIB
static av_cold int swf_read_close(AVFormatContext *avctx)
{
    SWFContext *s = avctx->priv_data;
    inflateEnd(&s->zstream);
    av_freep(&s->zbuf_in);
    av_freep(&s->zbuf_out);
    av_freep(&s->zpb);
    return 0;
}
#endif

525
AVInputFormat ff_swf_demuxer = {
526
    .name           = "swf",
527
    .long_name      = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
528 529 530 531
    .priv_data_size = sizeof(SWFContext),
    .read_probe     = swf_probe,
    .read_header    = swf_read_header,
    .read_packet    = swf_read_packet,
532 533 534
#if CONFIG_ZLIB
    .read_close     = swf_read_close,
#endif
B
Baptiste Coudurier 已提交
535
};