Statistics
| Branch: | Revision:

ffmpeg / libavformat / swfdec.c @ 470bce2b

History | View | Annotate | Download (6.39 KB)

1 3b35f4ab Baptiste Coudurier
/*
2 376aefdd Baptiste Coudurier
 * Flash Compatible Streaming Format demuxer
3 3b35f4ab Baptiste Coudurier
 * Copyright (c) 2000 Fabrice Bellard.
4
 * Copyright (c) 2003 Tinic Uro.
5
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include "swf.h"
24
25
static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
26
{
27
    int tag, len;
28
29
    if (url_feof(pb))
30
        return -1;
31
32
    tag = get_le16(pb);
33
    len = tag & 0x3f;
34
    tag = tag >> 6;
35
    if (len == 0x3f) {
36
        len = get_le32(pb);
37
    }
38
//    av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
39
    *len_ptr = len;
40
    return tag;
41
}
42
43
44
static int swf_probe(AVProbeData *p)
45
{
46
    /* check file header */
47
    if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
48
        p->buf[2] == 'S')
49
        return AVPROBE_SCORE_MAX;
50
    else
51
        return 0;
52
}
53
54
static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
55
{
56
    SWFContext *swf = s->priv_data;
57
    ByteIOContext *pb = s->pb;
58
    int nbits, len, tag;
59
60
    tag = get_be32(pb) & 0xffffff00;
61
62
    if (tag == MKBETAG('C', 'W', 'S', 0)) {
63
        av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
64
        return AVERROR(EIO);
65
    }
66
    if (tag != MKBETAG('F', 'W', 'S', 0))
67
        return AVERROR(EIO);
68
    get_le32(pb);
69
    /* skip rectangle size */
70
    nbits = get_byte(pb) >> 3;
71
    len = (4 * nbits - 3 + 7) / 8;
72
    url_fskip(pb, len);
73
    swf->frame_rate = get_le16(pb); /* 8.8 fixed */
74
    get_le16(pb); /* frame count */
75
76
    swf->samples_per_frame = 0;
77
    s->ctx_flags |= AVFMTCTX_NOHEADER;
78
    return 0;
79
}
80
81
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
82
{
83
    SWFContext *swf = s->priv_data;
84
    ByteIOContext *pb = s->pb;
85
    AVStream *vst = NULL, *ast = NULL, *st = 0;
86
    int tag, len, i, frame, v;
87
88
    for(;;) {
89
        tag = get_swf_tag(pb, &len);
90
        if (tag < 0)
91
            return AVERROR(EIO);
92
        if (tag == TAG_VIDEOSTREAM && !vst) {
93
            int ch_id = get_le16(pb);
94
            get_le16(pb);
95
            get_le16(pb);
96
            get_le16(pb);
97
            get_byte(pb);
98
            /* Check for FLV1 */
99
            vst = av_new_stream(s, ch_id);
100
            if (!vst)
101
                return -1;
102
            vst->codec->codec_type = CODEC_TYPE_VIDEO;
103
            vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
104
            av_set_pts_info(vst, 64, 256, swf->frame_rate);
105
            vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
106
            len -= 10;
107
        } else if ((tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) && !ast) {
108
            /* streaming found */
109
            int sample_rate_code;
110
            get_byte(pb);
111
            v = get_byte(pb);
112
            swf->samples_per_frame = get_le16(pb);
113
            ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
114
            if (!ast)
115
                return -1;
116
            swf->audio_stream_index = ast->index;
117
            ast->codec->channels = 1 + (v&1);
118
            ast->codec->codec_type = CODEC_TYPE_AUDIO;
119
            ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
120
            ast->need_parsing = AVSTREAM_PARSE_FULL;
121
            sample_rate_code= (v>>2) & 3;
122
            if (!sample_rate_code)
123
                return AVERROR(EIO);
124
            ast->codec->sample_rate = 11025 << (sample_rate_code-1);
125
            av_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
126
            len -= 4;
127
        } else if (tag == TAG_VIDEOFRAME) {
128
            int ch_id = get_le16(pb);
129
            len -= 2;
130
            for(i=0; i<s->nb_streams; i++) {
131
                st = s->streams[i];
132
                if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
133
                    frame = get_le16(pb);
134
                    av_get_packet(pb, pkt, len-2);
135
                    pkt->pts = frame;
136
                    pkt->stream_index = st->index;
137
                    return pkt->size;
138
                }
139
            }
140
        } else if (tag == TAG_STREAMBLOCK) {
141
            st = s->streams[swf->audio_stream_index];
142
            if (st->codec->codec_id == CODEC_ID_MP3) {
143
                url_fskip(pb, 4);
144
                av_get_packet(pb, pkt, len-4);
145
            } else { // ADPCM, PCM
146
                av_get_packet(pb, pkt, len);
147
            }
148
            pkt->stream_index = st->index;
149
            return pkt->size;
150
        } else if (tag == TAG_JPEG2) {
151
            for (i=0; i<s->nb_streams; i++) {
152
                st = s->streams[i];
153
                if (st->id == -2)
154
                    break;
155
            }
156
            if (i == s->nb_streams) {
157
                vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
158
                if (!vst)
159
                    return -1;
160
                vst->codec->codec_type = CODEC_TYPE_VIDEO;
161
                vst->codec->codec_id = CODEC_ID_MJPEG;
162
                av_set_pts_info(vst, 64, 256, swf->frame_rate);
163
                vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
164
                st = vst;
165
            }
166
            get_le16(pb); /* BITMAP_ID */
167
            av_new_packet(pkt, len-2);
168
            get_buffer(pb, pkt->data, 4);
169
            if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
170
                AV_RB32(pkt->data) == 0xffd9ffd8) {
171
                /* old SWF files containing SOI/EOI as data start */
172
                /* files created by swink have reversed tag */
173
                pkt->size -= 4;
174
                get_buffer(pb, pkt->data, pkt->size);
175
            } else {
176
                get_buffer(pb, pkt->data + 4, pkt->size - 4);
177
            }
178
            pkt->stream_index = st->index;
179
            return pkt->size;
180
        }
181
        url_fskip(pb, len);
182
    }
183
    return 0;
184
}
185
186
AVInputFormat swf_demuxer = {
187
    "swf",
188 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Flash format"),
189 3b35f4ab Baptiste Coudurier
    sizeof(SWFContext),
190
    swf_probe,
191
    swf_read_header,
192
    swf_read_packet,
193
};