Mercurial > libavformat.hg
annotate swfdec.c @ 3302:171f5664d129 libavformat
split swf de/muxer
author | bcoudurier |
---|---|
date | Tue, 20 May 2008 23:31:10 +0000 |
parents | swf.c@6f61c3b36632 |
children | 811758d926fd |
rev | line source |
---|---|
0 | 1 /* |
2 * Flash Compatible Streaming Format | |
3 * Copyright (c) 2000 Fabrice Bellard. | |
359 | 4 * Copyright (c) 2003 Tinic Uro. |
0 | 5 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
6 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
7 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
8 * FFmpeg is free software; you can redistribute it and/or |
0 | 9 * modify it under the terms of the GNU Lesser General Public |
10 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
11 * version 2.1 of the License, or (at your option) any later version. |
0 | 12 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
13 * FFmpeg is distributed in the hope that it will be useful, |
0 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
19 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 21 */ |
3286 | 22 |
3302 | 23 #include "swf.h" |
0 | 24 |
359 | 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 | |
885 | 29 quite tricky to determine, you almost certainly |
359 | 30 will get a bad audio/video sync */ |
0 | 31 |
32 static int get_swf_tag(ByteIOContext *pb, int *len_ptr) | |
33 { | |
34 int tag, len; | |
885 | 35 |
0 | 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 } | |
806 | 45 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len); |
0 | 46 *len_ptr = len; |
47 return tag; | |
48 } | |
49 | |
50 | |
51 static int swf_probe(AVProbeData *p) | |
52 { | |
53 /* check file header */ | |
806 | 54 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' && |
0 | 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 { | |
1641 | 63 SWFContext *swf = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
64 ByteIOContext *pb = s->pb; |
2310 | 65 int nbits, len, tag; |
359 | 66 |
806 | 67 tag = get_be32(pb) & 0xffffff00; |
68 | |
2309 | 69 if (tag == MKBETAG('C', 'W', 'S', 0)) { |
887 | 70 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n"); |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2164
diff
changeset
|
71 return AVERROR(EIO); |
806 | 72 } |
73 if (tag != MKBETAG('F', 'W', 'S', 0)) | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2164
diff
changeset
|
74 return AVERROR(EIO); |
0 | 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); | |
1889 | 80 swf->frame_rate = get_le16(pb); /* 8.8 fixed */ |
0 | 81 get_le16(pb); /* frame count */ |
885 | 82 |
359 | 83 swf->samples_per_frame = 0; |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
84 s->ctx_flags |= AVFMTCTX_NOHEADER; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
85 return 0; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
86 } |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
87 |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
88 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
89 { |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
90 SWFContext *swf = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
91 ByteIOContext *pb = s->pb; |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
92 AVStream *vst = NULL, *ast = NULL, *st = 0; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
93 int tag, len, i, frame, v; |
0 | 94 |
95 for(;;) { | |
96 tag = get_swf_tag(pb, &len); | |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
97 if (tag < 0) |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
98 return AVERROR(EIO); |
2309 | 99 if (tag == TAG_VIDEOSTREAM && !vst) { |
1637 | 100 int ch_id = get_le16(pb); |
359 | 101 get_le16(pb); |
102 get_le16(pb); | |
103 get_le16(pb); | |
104 get_byte(pb); | |
105 /* Check for FLV1 */ | |
1637 | 106 vst = av_new_stream(s, ch_id); |
2913 | 107 if (!vst) |
108 return -1; | |
1635 | 109 vst->codec->codec_type = CODEC_TYPE_VIDEO; |
110 vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb)); | |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
111 av_set_pts_info(vst, 64, 256, swf->frame_rate); |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
112 vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
113 len -= 10; |
2309 | 114 } else if ((tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) && !ast) { |
0 | 115 /* streaming found */ |
1642 | 116 int sample_rate_code; |
0 | 117 get_byte(pb); |
118 v = get_byte(pb); | |
359 | 119 swf->samples_per_frame = get_le16(pb); |
1638 | 120 ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */ |
2913 | 121 if (!ast) |
122 return -1; | |
1638 | 123 swf->audio_stream_index = ast->index; |
1636 | 124 ast->codec->channels = 1 + (v&1); |
125 ast->codec->codec_type = CODEC_TYPE_AUDIO; | |
1833 | 126 ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15); |
2023 | 127 ast->need_parsing = AVSTREAM_PARSE_FULL; |
1642 | 128 sample_rate_code= (v>>2) & 3; |
129 if (!sample_rate_code) | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2164
diff
changeset
|
130 return AVERROR(EIO); |
1642 | 131 ast->codec->sample_rate = 11025 << (sample_rate_code-1); |
1890
04f9a3ae30af
seems safer to set pts timebase to sample rate, fix some mp3
bcoudurier
parents:
1889
diff
changeset
|
132 av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
133 len -= 4; |
2308 | 134 } else if (tag == TAG_VIDEOFRAME) { |
1637 | 135 int ch_id = get_le16(pb); |
1639 | 136 len -= 2; |
2309 | 137 for(i=0; i<s->nb_streams; i++) { |
887 | 138 st = s->streams[i]; |
1637 | 139 if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) { |
140 frame = get_le16(pb); | |
1639 | 141 av_get_packet(pb, pkt, len-2); |
1889 | 142 pkt->pts = frame; |
1637 | 143 pkt->stream_index = st->index; |
144 return pkt->size; | |
359 | 145 } |
885 | 146 } |
359 | 147 } else if (tag == TAG_STREAMBLOCK) { |
1638 | 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); | |
1833 | 152 } else { // ADPCM, PCM |
153 av_get_packet(pb, pkt, len); | |
359 | 154 } |
1833 | 155 pkt->stream_index = st->index; |
156 return pkt->size; | |
1640 | 157 } else if (tag == TAG_JPEG2) { |
158 for (i=0; i<s->nb_streams; i++) { | |
159 st = s->streams[i]; | |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
160 if (st->id == -2) |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
161 break; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
162 } |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
163 if (i == s->nb_streams) { |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
164 vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */ |
2913 | 165 if (!vst) |
166 return -1; | |
2307
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
167 vst->codec->codec_type = CODEC_TYPE_VIDEO; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
168 vst->codec->codec_id = CODEC_ID_MJPEG; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
169 av_set_pts_info(vst, 64, 256, swf->frame_rate); |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
170 vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
171 st = vst; |
d5508f387614
add streams on the fly, swf is a streaming format and has no real header, correctly detect audio in RamboMJPEGAVP6_112K.swf now
bcoudurier
parents:
2289
diff
changeset
|
172 } |
2308 | 173 get_le16(pb); /* BITMAP_ID */ |
174 av_new_packet(pkt, len-2); | |
175 get_buffer(pb, pkt->data, 4); | |
2402
8decf7585a94
support swink created files which have soi/eoi broken tags reversed
bcoudurier
parents:
2310
diff
changeset
|
176 if (AV_RB32(pkt->data) == 0xffd8ffd9 || |
8decf7585a94
support swink created files which have soi/eoi broken tags reversed
bcoudurier
parents:
2310
diff
changeset
|
177 AV_RB32(pkt->data) == 0xffd9ffd8) { |
2308 | 178 /* old SWF files containing SOI/EOI as data start */ |
2402
8decf7585a94
support swink created files which have soi/eoi broken tags reversed
bcoudurier
parents:
2310
diff
changeset
|
179 /* files created by swink have reversed tag */ |
2308 | 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; | |
0 | 187 } |
1639 | 188 url_fskip(pb, len); |
0 | 189 } |
190 return 0; | |
191 } | |
192 | |
193 static int swf_read_close(AVFormatContext *s) | |
194 { | |
2308 | 195 return 0; |
0 | 196 } |
197 | |
1169 | 198 AVInputFormat swf_demuxer = { |
0 | 199 "swf", |
200 "Flash format", | |
359 | 201 sizeof(SWFContext), |
0 | 202 swf_probe, |
203 swf_read_header, | |
204 swf_read_packet, | |
205 swf_read_close, | |
206 }; |