split swf de/muxer
[ffmpeg.git] / libavformat / swfdec.c
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 static int swf_read_close(AVFormatContext *s)
194 {
195     return 0;
196 }
197
198 AVInputFormat swf_demuxer = {
199     "swf",
200     "Flash format",
201     sizeof(SWFContext),
202     swf_probe,
203     swf_read_header,
204     swf_read_packet,
205     swf_read_close,
206 };