swfdec.c 16.4 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"
B
Baptiste Coudurier 已提交
27 28
#include "swf.h"

29
static const AVCodecTag swf_audio_codec_tags[] = {
30 31 32 33 34 35
    { 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 },
36 37
};

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

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

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


static int swf_probe(AVProbeData *p)
{
58 59 60
    if(p->buf_size < 15)
        return 0;

B
Baptiste Coudurier 已提交
61 62
    /* check file header */
    if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
63
        p->buf[2] == 'S' && p->buf[3] < 20)
B
Baptiste Coudurier 已提交
64 65 66 67 68
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

69 70 71 72 73 74 75 76 77 78 79
#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);
80
        if (n < 0)
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
            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

102
static int swf_read_header(AVFormatContext *s)
B
Baptiste Coudurier 已提交
103 104
{
    SWFContext *swf = s->priv_data;
105
    AVIOContext *pb = s->pb;
B
Baptiste Coudurier 已提交
106 107
    int nbits, len, tag;

108
    tag = avio_rb32(pb) & 0xffffff00;
109
    avio_rl32(pb);
B
Baptiste Coudurier 已提交
110 111

    if (tag == MKBETAG('C', 'W', 'S', 0)) {
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        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 已提交
128
        return AVERROR(EIO);
129 130
#endif
    } else if (tag != MKBETAG('F', 'W', 'S', 0))
B
Baptiste Coudurier 已提交
131 132
        return AVERROR(EIO);
    /* skip rectangle size */
133
    nbits = avio_r8(pb) >> 3;
B
Baptiste Coudurier 已提交
134
    len = (4 * nbits - 3 + 7) / 8;
135
    avio_skip(pb, len);
136 137
    swf->frame_rate = avio_rl16(pb); /* 8.8 fixed */
    avio_rl16(pb); /* frame count */
B
Baptiste Coudurier 已提交
138 139 140 141 142 143

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

144 145
static AVStream *create_new_audio_stream(AVFormatContext *s, int id, int info)
{
146
    int sample_rate_code, sample_size_code;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    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;
162 163 164
    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;
165 166 167 168 169
    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 已提交
170 171 172
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    SWFContext *swf = s->priv_data;
173
    AVIOContext *pb = s->pb;
B
Baptiste Coudurier 已提交
174
    AVStream *vst = NULL, *ast = NULL, *st = 0;
175
    int tag, len, i, frame, v, res;
B
Baptiste Coudurier 已提交
176

177 178 179 180 181
#if CONFIG_ZLIB
    if (swf->zpb)
        pb = swf->zpb;
#endif

B
Baptiste Coudurier 已提交
182
    for(;;) {
183
        uint64_t pos = avio_tell(pb);
B
Baptiste Coudurier 已提交
184 185
        tag = get_swf_tag(pb, &len);
        if (tag < 0)
186
            return tag;
M
Michael Niedermayer 已提交
187
        if (len < 0) {
188
            av_log(s, AV_LOG_ERROR, "invalid tag length: %d\n", len);
M
Michael Niedermayer 已提交
189 190
            return AVERROR_INVALIDDATA;
        }
191
        if (tag == TAG_VIDEOSTREAM) {
192
            int ch_id = avio_rl16(pb);
193 194 195 196
            len -= 2;

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

201 202 203 204
            avio_rl16(pb);
            avio_rl16(pb);
            avio_rl16(pb);
            avio_r8(pb);
B
Baptiste Coudurier 已提交
205
            /* Check for FLV1 */
206
            vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
207
            if (!vst)
208
                return AVERROR(ENOMEM);
209
            vst->id = ch_id;
210
            vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
211
            vst->codec->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
212
            avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
213 214
            len -= 8;
        } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
B
Baptiste Coudurier 已提交
215
            /* streaming found */
216 217 218

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

223 224 225
            avio_r8(pb);
            v = avio_r8(pb);
            swf->samples_per_frame = avio_rl16(pb);
226
            ast = create_new_audio_stream(s, -1, v); /* -1 to avoid clash with video stream ch_id */
B
Baptiste Coudurier 已提交
227
            if (!ast)
228
                return AVERROR(ENOMEM);
B
Baptiste Coudurier 已提交
229
            len -= 4;
230 231 232 233 234 235 236 237 238 239 240 241 242 243
        } 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);
244
            ast = create_new_audio_stream(s, ch_id, v);
245
            if (!ast)
246
                return AVERROR(ENOMEM);
247 248 249 250 251 252 253 254 255 256 257
            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 已提交
258
        } else if (tag == TAG_VIDEOFRAME) {
259
            int ch_id = avio_rl16(pb);
B
Baptiste Coudurier 已提交
260 261 262
            len -= 2;
            for(i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
263
                if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
264
                    frame = avio_rl16(pb);
265 266 267 268
                    len -= 2;
                    if (len <= 0)
                        goto skip;
                    if ((res = av_get_packet(pb, pkt, len)) < 0)
269
                        return res;
270
                    pkt->pos = pos;
B
Baptiste Coudurier 已提交
271 272 273 274 275
                    pkt->pts = frame;
                    pkt->stream_index = st->index;
                    return pkt->size;
                }
            }
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 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 377 378 379 380 381 382
        } 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);

            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;
            }
            st->codec->width  = width;
            st->codec->height = height;

            if ((res = av_new_packet(pkt, out_len - colormapsize * colormapbpp)) < 0)
                goto bitmap_end;
            pkt->pos = pos;
            pkt->stream_index = st->index;

            switch (bmp_fmt) {
            case 3:
                st->codec->pix_fmt = AV_PIX_FMT_PAL8;
                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:
                st->codec->pix_fmt = AV_PIX_FMT_RGB555;
                break;
            case 5:
                st->codec->pix_fmt = alpha_bmp ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
                break;
            default:
                av_assert0(0);
            }
383 384 385 386 387

            if (linesize * height > pkt->size) {
                res = AVERROR_INVALIDDATA;
                goto bitmap_end;
            }
388 389 390 391 392 393 394 395 396 397 398 399 400 401
            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 已提交
402
        } else if (tag == TAG_STREAMBLOCK) {
403 404
            for (i = 0; i < s->nb_streams; i++) {
                st = s->streams[i];
405
                if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
                    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;
422 423
                }
            }
B
Baptiste Coudurier 已提交
424 425 426
        } else if (tag == TAG_JPEG2) {
            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
427
                if (st->codec->codec_id == AV_CODEC_ID_MJPEG && st->id == -2)
B
Baptiste Coudurier 已提交
428 429 430
                    break;
            }
            if (i == s->nb_streams) {
431
                vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
432
                if (!vst)
433
                    return AVERROR(ENOMEM);
434
                vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
435
                vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
436
                vst->codec->codec_id = AV_CODEC_ID_MJPEG;
437
                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
B
Baptiste Coudurier 已提交
438 439
                st = vst;
            }
440
            avio_rl16(pb); /* BITMAP_ID */
441 442 443 444
            len -= 2;
            if (len < 4)
                goto skip;
            if ((res = av_new_packet(pkt, len)) < 0)
445
                return res;
446
            avio_read(pb, pkt->data, 4);
B
Baptiste Coudurier 已提交
447 448 449 450 451
            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;
452
                avio_read(pb, pkt->data, pkt->size);
B
Baptiste Coudurier 已提交
453
            } else {
454
                avio_read(pb, pkt->data + 4, pkt->size - 4);
B
Baptiste Coudurier 已提交
455
            }
456
            pkt->pos = pos;
B
Baptiste Coudurier 已提交
457 458
            pkt->stream_index = st->index;
            return pkt->size;
459 460
        } else {
            av_log(s, AV_LOG_DEBUG, "Unknown tag: %d\n", tag);
B
Baptiste Coudurier 已提交
461
        }
462
    skip:
463 464
        if(len<0)
            av_log(s, AV_LOG_WARNING, "Cliping len %d\n", len);
465
        len = FFMAX(0, len);
466
        avio_skip(pb, len);
B
Baptiste Coudurier 已提交
467 468 469
    }
}

470 471 472 473 474 475 476 477 478 479 480 481
#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

482
AVInputFormat ff_swf_demuxer = {
483
    .name           = "swf",
484
    .long_name      = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
485 486 487 488
    .priv_data_size = sizeof(SWFContext),
    .read_probe     = swf_probe,
    .read_header    = swf_read_header,
    .read_packet    = swf_read_packet,
489 490 491
#if CONFIG_ZLIB
    .read_close     = swf_read_close,
#endif
B
Baptiste Coudurier 已提交
492
};