00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "libavutil/intreadwrite.h"
00024 #include "swf.h"
00025
00026 static int get_swf_tag(AVIOContext *pb, int *len_ptr)
00027 {
00028 int tag, len;
00029
00030 if (url_feof(pb))
00031 return AVERROR_EOF;
00032
00033 tag = avio_rl16(pb);
00034 len = tag & 0x3f;
00035 tag = tag >> 6;
00036 if (len == 0x3f) {
00037 len = avio_rl32(pb);
00038 }
00039
00040 *len_ptr = len;
00041 return tag;
00042 }
00043
00044
00045 static int swf_probe(AVProbeData *p)
00046 {
00047
00048 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
00049 p->buf[2] == 'S')
00050 return AVPROBE_SCORE_MAX;
00051 else
00052 return 0;
00053 }
00054
00055 #if CONFIG_ZLIB
00056 static int zlib_refill(void *opaque, uint8_t *buf, int buf_size)
00057 {
00058 AVFormatContext *s = opaque;
00059 SWFContext *swf = s->priv_data;
00060 z_stream *z = &swf->zstream;
00061 int ret;
00062
00063 retry:
00064 if (!z->avail_in) {
00065 int n = avio_read(s->pb, swf->zbuf_in, ZBUF_SIZE);
00066 if (n <= 0)
00067 return n;
00068 z->next_in = swf->zbuf_in;
00069 z->avail_in = n;
00070 }
00071
00072 z->next_out = buf;
00073 z->avail_out = buf_size;
00074
00075 ret = inflate(z, Z_NO_FLUSH);
00076 if (ret < 0)
00077 return AVERROR(EINVAL);
00078 if (ret == Z_STREAM_END)
00079 return AVERROR_EOF;
00080
00081 if (buf_size - z->avail_out == 0)
00082 goto retry;
00083
00084 return buf_size - z->avail_out;
00085 }
00086 #endif
00087
00088 static int swf_read_header(AVFormatContext *s)
00089 {
00090 SWFContext *swf = s->priv_data;
00091 AVIOContext *pb = s->pb;
00092 int nbits, len, tag;
00093
00094 tag = avio_rb32(pb) & 0xffffff00;
00095 avio_rl32(pb);
00096
00097 if (tag == MKBETAG('C', 'W', 'S', 0)) {
00098 av_log(s, AV_LOG_INFO, "SWF compressed file detected\n");
00099 #if CONFIG_ZLIB
00100 swf->zbuf_in = av_malloc(ZBUF_SIZE);
00101 swf->zbuf_out = av_malloc(ZBUF_SIZE);
00102 swf->zpb = avio_alloc_context(swf->zbuf_out, ZBUF_SIZE, 0, s,
00103 zlib_refill, NULL, NULL);
00104 if (!swf->zbuf_in || !swf->zbuf_out || !swf->zpb)
00105 return AVERROR(ENOMEM);
00106 swf->zpb->seekable = 0;
00107 if (inflateInit(&swf->zstream) != Z_OK) {
00108 av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
00109 return AVERROR(EINVAL);
00110 }
00111 pb = swf->zpb;
00112 #else
00113 av_log(s, AV_LOG_ERROR, "zlib support is required to read SWF compressed files\n");
00114 return AVERROR(EIO);
00115 #endif
00116 } else if (tag != MKBETAG('F', 'W', 'S', 0))
00117 return AVERROR(EIO);
00118
00119 nbits = avio_r8(pb) >> 3;
00120 len = (4 * nbits - 3 + 7) / 8;
00121 avio_skip(pb, len);
00122 swf->frame_rate = avio_rl16(pb);
00123 avio_rl16(pb);
00124
00125 swf->samples_per_frame = 0;
00126 s->ctx_flags |= AVFMTCTX_NOHEADER;
00127 return 0;
00128 }
00129
00130 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
00131 {
00132 SWFContext *swf = s->priv_data;
00133 AVIOContext *pb = s->pb;
00134 AVStream *vst = NULL, *ast = NULL, *st = 0;
00135 int tag, len, i, frame, v, res;
00136
00137 #if CONFIG_ZLIB
00138 if (swf->zpb)
00139 pb = swf->zpb;
00140 #endif
00141
00142 for(;;) {
00143 uint64_t pos = avio_tell(pb);
00144 tag = get_swf_tag(pb, &len);
00145 if (tag < 0)
00146 return tag;
00147 if (tag == TAG_VIDEOSTREAM) {
00148 int ch_id = avio_rl16(pb);
00149 len -= 2;
00150
00151 for (i=0; i<s->nb_streams; i++) {
00152 st = s->streams[i];
00153 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id)
00154 goto skip;
00155 }
00156
00157 avio_rl16(pb);
00158 avio_rl16(pb);
00159 avio_rl16(pb);
00160 avio_r8(pb);
00161
00162 vst = avformat_new_stream(s, NULL);
00163 if (!vst)
00164 return -1;
00165 vst->id = ch_id;
00166 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00167 vst->codec->codec_id = ff_codec_get_id(swf_codec_tags, avio_r8(pb));
00168 avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
00169 len -= 8;
00170 } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
00171
00172 int sample_rate_code;
00173
00174 for (i=0; i<s->nb_streams; i++) {
00175 st = s->streams[i];
00176 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1)
00177 goto skip;
00178 }
00179
00180 avio_r8(pb);
00181 v = avio_r8(pb);
00182 swf->samples_per_frame = avio_rl16(pb);
00183 ast = avformat_new_stream(s, NULL);
00184 if (!ast)
00185 return -1;
00186 ast->id = -1;
00187 ast->codec->channels = 1 + (v&1);
00188 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00189 ast->codec->codec_id = ff_codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
00190 ast->need_parsing = AVSTREAM_PARSE_FULL;
00191 sample_rate_code= (v>>2) & 3;
00192 ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
00193 avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
00194 len -= 4;
00195 } else if (tag == TAG_VIDEOFRAME) {
00196 int ch_id = avio_rl16(pb);
00197 len -= 2;
00198 for(i=0; i<s->nb_streams; i++) {
00199 st = s->streams[i];
00200 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
00201 frame = avio_rl16(pb);
00202 if ((res = av_get_packet(pb, pkt, len-2)) < 0)
00203 return res;
00204 pkt->pos = pos;
00205 pkt->pts = frame;
00206 pkt->stream_index = st->index;
00207 return pkt->size;
00208 }
00209 }
00210 } else if (tag == TAG_STREAMBLOCK) {
00211 for (i = 0; i < s->nb_streams; i++) {
00212 st = s->streams[i];
00213 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
00214 if (st->codec->codec_id == CODEC_ID_MP3) {
00215 avio_skip(pb, 4);
00216 if ((res = av_get_packet(pb, pkt, len-4)) < 0)
00217 return res;
00218 } else {
00219 if ((res = av_get_packet(pb, pkt, len)) < 0)
00220 return res;
00221 }
00222 pkt->pos = pos;
00223 pkt->stream_index = st->index;
00224 return pkt->size;
00225 }
00226 }
00227 } else if (tag == TAG_JPEG2) {
00228 for (i=0; i<s->nb_streams; i++) {
00229 st = s->streams[i];
00230 if (st->codec->codec_id == CODEC_ID_MJPEG && st->id == -2)
00231 break;
00232 }
00233 if (i == s->nb_streams) {
00234 vst = avformat_new_stream(s, NULL);
00235 if (!vst)
00236 return -1;
00237 vst->id = -2;
00238 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00239 vst->codec->codec_id = CODEC_ID_MJPEG;
00240 avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
00241 st = vst;
00242 }
00243 avio_rl16(pb);
00244 if ((res = av_new_packet(pkt, len-2)) < 0)
00245 return res;
00246 avio_read(pb, pkt->data, 4);
00247 if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
00248 AV_RB32(pkt->data) == 0xffd9ffd8) {
00249
00250
00251 pkt->size -= 4;
00252 avio_read(pb, pkt->data, pkt->size);
00253 } else {
00254 avio_read(pb, pkt->data + 4, pkt->size - 4);
00255 }
00256 pkt->pos = pos;
00257 pkt->stream_index = st->index;
00258 return pkt->size;
00259 }
00260 skip:
00261 avio_skip(pb, len);
00262 }
00263 }
00264
00265 #if CONFIG_ZLIB
00266 static av_cold int swf_read_close(AVFormatContext *avctx)
00267 {
00268 SWFContext *s = avctx->priv_data;
00269 inflateEnd(&s->zstream);
00270 av_freep(&s->zbuf_in);
00271 av_freep(&s->zbuf_out);
00272 av_freep(&s->zpb);
00273 return 0;
00274 }
00275 #endif
00276
00277 AVInputFormat ff_swf_demuxer = {
00278 .name = "swf",
00279 .long_name = NULL_IF_CONFIG_SMALL("Flash format"),
00280 .priv_data_size = sizeof(SWFContext),
00281 .read_probe = swf_probe,
00282 .read_header = swf_read_header,
00283 .read_packet = swf_read_packet,
00284 #if CONFIG_ZLIB
00285 .read_close = swf_read_close,
00286 #endif
00287 };