Mercurial > libavformat.hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
3301:11b6da5ffe78 | 3302:171f5664d129 |
---|---|
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 }; |