Statistics
| Branch: | Revision:

ffmpeg / libavformat / swfdec.c @ ad0b44b3

History | View | Annotate | Download (6.63 KB)

1
/*
2
 * Flash Compatible Streaming Format
3
 * 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
/*********************************************/
26
/* Extract FLV encoded frame and MP3 from swf
27
   Note that the detection of the real frame
28
   is inaccurate at this point as it can be
29
   quite tricky to determine, you almost certainly
30
   will get a bad audio/video sync */
31

    
32
static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
33
{
34
    int tag, len;
35

    
36
    if (url_feof(pb))
37
        return -1;
38

    
39
    tag = get_le16(pb);
40
    len = tag & 0x3f;
41
    tag = tag >> 6;
42
    if (len == 0x3f) {
43
        len = get_le32(pb);
44
    }
45
//    av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
46
    *len_ptr = len;
47
    return tag;
48
}
49

    
50

    
51
static int swf_probe(AVProbeData *p)
52
{
53
    /* check file header */
54
    if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
55
        p->buf[2] == 'S')
56
        return AVPROBE_SCORE_MAX;
57
    else
58
        return 0;
59
}
60

    
61
static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
62
{
63
    SWFContext *swf = s->priv_data;
64
    ByteIOContext *pb = s->pb;
65
    int nbits, len, tag;
66

    
67
    tag = get_be32(pb) & 0xffffff00;
68

    
69
    if (tag == MKBETAG('C', 'W', 'S', 0)) {
70
        av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
71
        return AVERROR(EIO);
72
    }
73
    if (tag != MKBETAG('F', 'W', 'S', 0))
74
        return AVERROR(EIO);
75
    get_le32(pb);
76
    /* skip rectangle size */
77
    nbits = get_byte(pb) >> 3;
78
    len = (4 * nbits - 3 + 7) / 8;
79
    url_fskip(pb, len);
80
    swf->frame_rate = get_le16(pb); /* 8.8 fixed */
81
    get_le16(pb); /* frame count */
82

    
83
    swf->samples_per_frame = 0;
84
    s->ctx_flags |= AVFMTCTX_NOHEADER;
85
    return 0;
86
}
87

    
88
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
89
{
90
    SWFContext *swf = s->priv_data;
91
    ByteIOContext *pb = s->pb;
92
    AVStream *vst = NULL, *ast = NULL, *st = 0;
93
    int tag, len, i, frame, v;
94

    
95
    for(;;) {
96
        tag = get_swf_tag(pb, &len);
97
        if (tag < 0)
98
            return AVERROR(EIO);
99
        if (tag == TAG_VIDEOSTREAM && !vst) {
100
            int ch_id = get_le16(pb);
101
            get_le16(pb);
102
            get_le16(pb);
103
            get_le16(pb);
104
            get_byte(pb);
105
            /* Check for FLV1 */
106
            vst = av_new_stream(s, ch_id);
107
            if (!vst)
108
                return -1;
109
            vst->codec->codec_type = CODEC_TYPE_VIDEO;
110
            vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
111
            av_set_pts_info(vst, 64, 256, swf->frame_rate);
112
            vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
113
            len -= 10;
114
        } else if ((tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) && !ast) {
115
            /* streaming found */
116
            int sample_rate_code;
117
            get_byte(pb);
118
            v = get_byte(pb);
119
            swf->samples_per_frame = get_le16(pb);
120
            ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
121
            if (!ast)
122
                return -1;
123
            swf->audio_stream_index = ast->index;
124
            ast->codec->channels = 1 + (v&1);
125
            ast->codec->codec_type = CODEC_TYPE_AUDIO;
126
            ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
127
            ast->need_parsing = AVSTREAM_PARSE_FULL;
128
            sample_rate_code= (v>>2) & 3;
129
            if (!sample_rate_code)
130
                return AVERROR(EIO);
131
            ast->codec->sample_rate = 11025 << (sample_rate_code-1);
132
            av_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
133
            len -= 4;
134
        } else if (tag == TAG_VIDEOFRAME) {
135
            int ch_id = get_le16(pb);
136
            len -= 2;
137
            for(i=0; i<s->nb_streams; i++) {
138
                st = s->streams[i];
139
                if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
140
                    frame = get_le16(pb);
141
                    av_get_packet(pb, pkt, len-2);
142
                    pkt->pts = frame;
143
                    pkt->stream_index = st->index;
144
                    return pkt->size;
145
                }
146
            }
147
        } else if (tag == TAG_STREAMBLOCK) {
148
            st = s->streams[swf->audio_stream_index];
149
            if (st->codec->codec_id == CODEC_ID_MP3) {
150
                url_fskip(pb, 4);
151
                av_get_packet(pb, pkt, len-4);
152
            } else { // ADPCM, PCM
153
                av_get_packet(pb, pkt, len);
154
            }
155
            pkt->stream_index = st->index;
156
            return pkt->size;
157
        } else if (tag == TAG_JPEG2) {
158
            for (i=0; i<s->nb_streams; i++) {
159
                st = s->streams[i];
160
                if (st->id == -2)
161
                    break;
162
            }
163
            if (i == s->nb_streams) {
164
                vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
165
                if (!vst)
166
                    return -1;
167
                vst->codec->codec_type = CODEC_TYPE_VIDEO;
168
                vst->codec->codec_id = CODEC_ID_MJPEG;
169
                av_set_pts_info(vst, 64, 256, swf->frame_rate);
170
                vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
171
                st = vst;
172
            }
173
            get_le16(pb); /* BITMAP_ID */
174
            av_new_packet(pkt, len-2);
175
            get_buffer(pb, pkt->data, 4);
176
            if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
177
                AV_RB32(pkt->data) == 0xffd9ffd8) {
178
                /* old SWF files containing SOI/EOI as data start */
179
                /* files created by swink have reversed tag */
180
                pkt->size -= 4;
181
                get_buffer(pb, pkt->data, pkt->size);
182
            } else {
183
                get_buffer(pb, pkt->data + 4, pkt->size - 4);
184
            }
185
            pkt->stream_index = st->index;
186
            return pkt->size;
187
        }
188
        url_fskip(pb, len);
189
    }
190
    return 0;
191
}
192

    
193
AVInputFormat swf_demuxer = {
194
    "swf",
195
    "Flash format",
196
    sizeof(SWFContext),
197
    swf_probe,
198
    swf_read_header,
199
    swf_read_packet,
200
};