swfdec.c 10.3 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
 * This file is part of Libav.
B
Baptiste Coudurier 已提交
7
 *
8
 * Libav is free software; you can redistribute it and/or
B
Baptiste Coudurier 已提交
9 10 11 12
 * 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.
 *
13
 * Libav is distributed in the hope that it will be useful,
B
Baptiste Coudurier 已提交
14 15 16 17 18
 * 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
19
 * License along with Libav; if not, write to the Free Software
B
Baptiste Coudurier 已提交
20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

C
Clément Bœsch 已提交
23 24 25 26 27 28
#include "config.h"

#if CONFIG_ZLIB
#include <zlib.h>
#endif

J
Justin Ruggles 已提交
29
#include "libavutil/channel_layout.h"
30
#include "libavutil/intreadwrite.h"
B
Baptiste Coudurier 已提交
31 32
#include "swf.h"

33
static const AVCodecTag swf_audio_codec_tags[] = {
34 35 36 37 38 39
    { 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 },
40 41
};

42
static int get_swf_tag(AVIOContext *pb, int *len_ptr)
B
Baptiste Coudurier 已提交
43 44 45
{
    int tag, len;

A
Anton Khirnov 已提交
46
    if (pb->eof_reached)
B
Baptiste Coudurier 已提交
47 48
        return -1;

49
    tag = avio_rl16(pb);
B
Baptiste Coudurier 已提交
50 51 52
    len = tag & 0x3f;
    tag = tag >> 6;
    if (len == 0x3f) {
53
        len = avio_rl32(pb);
B
Baptiste Coudurier 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    }
    *len_ptr = len;
    return tag;
}


static int swf_probe(AVProbeData *p)
{
    /* check file header */
    if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
        p->buf[2] == 'S')
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

C
Clément Bœsch 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#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);
        if (n < 0)
            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 != Z_OK && ret != Z_STREAM_END) {
        av_log(s, AV_LOG_ERROR, "Inflate error: %d\n", ret);
        return AVERROR_UNKNOWN;
    }

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

    return buf_size - z->avail_out;
}
#endif

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

109
    tag = avio_rb32(pb) & 0xffffff00;
C
Clément Bœsch 已提交
110
    avio_rl32(pb);
B
Baptiste Coudurier 已提交
111 112

    if (tag == MKBETAG('C', 'W', 'S', 0)) {
C
Clément Bœsch 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
        av_log(s, AV_LOG_INFO, "Compressed SWF file detected\n");
#if CONFIG_ZLIB
        if (inflateInit(&swf->zstream) != Z_OK) {
            av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
            return AVERROR(EINVAL);
        }
        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) {
            av_freep(&swf->zbuf_in);
            av_freep(&swf->zbuf_out);
            av_freep(&swf->zpb);
            return AVERROR(ENOMEM);
        }
        swf->zpb->seekable = 0;
        pb = swf->zpb;
#else
        av_log(s, AV_LOG_ERROR, "missing zlib support, unable to open\n");
B
Baptiste Coudurier 已提交
133
        return AVERROR(EIO);
C
Clément Bœsch 已提交
134 135
#endif
    } else if (tag != MKBETAG('F', 'W', 'S', 0))
B
Baptiste Coudurier 已提交
136 137
        return AVERROR(EIO);
    /* skip rectangle size */
138
    nbits = avio_r8(pb) >> 3;
B
Baptiste Coudurier 已提交
139
    len = (4 * nbits - 3 + 7) / 8;
140
    avio_skip(pb, len);
141 142
    swf->frame_rate = avio_rl16(pb); /* 8.8 fixed */
    avio_rl16(pb); /* frame count */
B
Baptiste Coudurier 已提交
143 144 145 146 147 148 149 150 151

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

static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    SWFContext *swf = s->priv_data;
152
    AVIOContext *pb = s->pb;
B
Baptiste Coudurier 已提交
153
    AVStream *vst = NULL, *ast = NULL, *st = 0;
154
    int tag, len, i, frame, v, res;
B
Baptiste Coudurier 已提交
155

C
Clément Bœsch 已提交
156 157 158 159 160
#if CONFIG_ZLIB
    if (swf->zpb)
        pb = swf->zpb;
#endif

B
Baptiste Coudurier 已提交
161
    for(;;) {
162
        uint64_t pos = avio_tell(pb);
B
Baptiste Coudurier 已提交
163 164 165
        tag = get_swf_tag(pb, &len);
        if (tag < 0)
            return AVERROR(EIO);
166 167 168 169
        if (len < 0) {
            av_log(s, AV_LOG_ERROR, "invalid tag length: %d\n", len);
            return AVERROR_INVALIDDATA;
        }
170
        if (tag == TAG_VIDEOSTREAM) {
171
            int ch_id = avio_rl16(pb);
172 173 174 175
            len -= 2;

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

180 181 182 183
            avio_rl16(pb);
            avio_rl16(pb);
            avio_rl16(pb);
            avio_r8(pb);
B
Baptiste Coudurier 已提交
184
            /* Check for FLV1 */
185
            vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
186 187
            if (!vst)
                return -1;
188
            vst->id = ch_id;
189
            vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
190
            vst->codec->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
191
            avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
192 193
            len -= 8;
        } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
B
Baptiste Coudurier 已提交
194 195
            /* streaming found */
            int sample_rate_code;
196 197 198

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

203 204 205
            avio_r8(pb);
            v = avio_r8(pb);
            swf->samples_per_frame = avio_rl16(pb);
206
            ast = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
207 208
            if (!ast)
                return -1;
209
            ast->id = -1; /* -1 to avoid clash with video stream ch_id */
J
Justin Ruggles 已提交
210 211 212 213 214 215 216
            if (v & 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;
            }
217
            ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
218
            ast->codec->codec_id = ff_codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
B
Baptiste Coudurier 已提交
219 220
            ast->need_parsing = AVSTREAM_PARSE_FULL;
            sample_rate_code= (v>>2) & 3;
221
            ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
222
            avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
B
Baptiste Coudurier 已提交
223 224
            len -= 4;
        } else if (tag == TAG_VIDEOFRAME) {
225
            int ch_id = avio_rl16(pb);
B
Baptiste Coudurier 已提交
226 227 228
            len -= 2;
            for(i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
229
                if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
230
                    frame = avio_rl16(pb);
231 232 233 234
                    len -= 2;
                    if (len <= 0)
                        goto skip;
                    if ((res = av_get_packet(pb, pkt, len)) < 0)
235
                        return res;
236
                    pkt->pos = pos;
B
Baptiste Coudurier 已提交
237 238 239 240 241 242
                    pkt->pts = frame;
                    pkt->stream_index = st->index;
                    return pkt->size;
                }
            }
        } else if (tag == TAG_STREAMBLOCK) {
243 244
            for (i = 0; i < s->nb_streams; i++) {
                st = s->streams[i];
245
                if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
                    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;
262 263
                }
            }
B
Baptiste Coudurier 已提交
264 265 266
        } else if (tag == TAG_JPEG2) {
            for (i=0; i<s->nb_streams; i++) {
                st = s->streams[i];
267
                if (st->codec->codec_id == AV_CODEC_ID_MJPEG && st->id == -2)
B
Baptiste Coudurier 已提交
268 269 270
                    break;
            }
            if (i == s->nb_streams) {
271
                vst = avformat_new_stream(s, NULL);
B
Baptiste Coudurier 已提交
272 273
                if (!vst)
                    return -1;
274
                vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
275
                vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
276
                vst->codec->codec_id = AV_CODEC_ID_MJPEG;
277
                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
B
Baptiste Coudurier 已提交
278 279
                st = vst;
            }
280
            avio_rl16(pb); /* BITMAP_ID */
281 282 283 284
            len -= 2;
            if (len < 4)
                goto skip;
            if ((res = av_new_packet(pkt, len)) < 0)
285
                return res;
286
            avio_read(pb, pkt->data, 4);
B
Baptiste Coudurier 已提交
287 288 289 290 291
            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;
292
                avio_read(pb, pkt->data, pkt->size);
B
Baptiste Coudurier 已提交
293
            } else {
294
                avio_read(pb, pkt->data + 4, pkt->size - 4);
B
Baptiste Coudurier 已提交
295
            }
296
            pkt->pos = pos;
B
Baptiste Coudurier 已提交
297 298 299
            pkt->stream_index = st->index;
            return pkt->size;
        }
300
    skip:
301
        len = FFMAX(0, len);
302
        avio_skip(pb, len);
B
Baptiste Coudurier 已提交
303 304 305
    }
}

C
Clément Bœsch 已提交
306 307 308 309 310 311 312 313 314 315 316 317
#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

318
AVInputFormat ff_swf_demuxer = {
319
    .name           = "swf",
320
    .long_name      = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
321 322 323 324
    .priv_data_size = sizeof(SWFContext),
    .read_probe     = swf_probe,
    .read_header    = swf_read_header,
    .read_packet    = swf_read_packet,
C
Clément Bœsch 已提交
325 326 327
#if CONFIG_ZLIB
    .read_close     = swf_read_close,
#endif
B
Baptiste Coudurier 已提交
328
};