2 * Flash Compatible Streaming Format demuxer
3 * Copyright (c) 2000 Fabrice Bellard
4 * Copyright (c) 2003 Tinic Uro
6 * This file is part of FFmpeg.
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.
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.
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
29 #include "libavutil/avassert.h"
30 #include "libavutil/channel_layout.h"
31 #include "libavutil/imgutils.h"
32 #include "libavutil/internal.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavcodec/get_bits.h"
37 static const AVCodecTag swf_audio_codec_tags
[] = {
38 { AV_CODEC_ID_PCM_S16LE
, 0x00 },
39 { AV_CODEC_ID_ADPCM_SWF
, 0x01 },
40 { AV_CODEC_ID_MP3
, 0x02 },
41 { AV_CODEC_ID_PCM_S16LE
, 0x03 },
42 // { AV_CODEC_ID_NELLYMOSER, 0x06 },
43 { AV_CODEC_ID_NONE
, 0 },
46 static int get_swf_tag(AVIOContext
*pb
, int *len_ptr
)
64 static int swf_probe(AVProbeData
*p
)
67 int len
, xmin
, xmax
, ymin
, ymax
;
72 /* check file header */
73 if ( AV_RB24(p
->buf
) != AV_RB24("CWS")
74 && AV_RB24(p
->buf
) != AV_RB24("FWS"))
77 if ( AV_RB24(p
->buf
) == AV_RB24("CWS")
79 return AVPROBE_SCORE_MAX
/ 4 + 1;
81 if (init_get_bits8(&gb
, p
->buf
+ 3, p
->buf_size
- 3) < 0)
85 len
= get_bits(&gb
, 5);
88 xmin
= get_bits_long(&gb
, len
);
89 xmax
= get_bits_long(&gb
, len
);
90 ymin
= get_bits_long(&gb
, len
);
91 ymax
= get_bits_long(&gb
, len
);
92 if (xmin
|| ymin
|| !xmax
|| !ymax
)
95 if (p
->buf
[3] >= 20 || xmax
< 16 || ymax
< 16)
96 return AVPROBE_SCORE_MAX
/ 4;
98 return AVPROBE_SCORE_MAX
;
102 static int zlib_refill(void *opaque
, uint8_t *buf
, int buf_size
)
104 AVFormatContext
*s
= opaque
;
105 SWFContext
*swf
= s
->priv_data
;
106 z_stream
*z
= &swf
->zstream
;
111 int n
= avio_read(s
->pb
, swf
->zbuf_in
, ZBUF_SIZE
);
114 z
->next_in
= swf
->zbuf_in
;
119 z
->avail_out
= buf_size
;
121 ret
= inflate(z
, Z_NO_FLUSH
);
122 if (ret
== Z_STREAM_END
)
125 return AVERROR(EINVAL
);
127 if (buf_size
- z
->avail_out
== 0)
130 return buf_size
- z
->avail_out
;
134 static int swf_read_header(AVFormatContext
*s
)
136 SWFContext
*swf
= s
->priv_data
;
137 AVIOContext
*pb
= s
->pb
;
140 tag
= avio_rb32(pb
) & 0xffffff00;
143 if (tag
== MKBETAG('C', 'W', 'S', 0)) {
144 av_log(s
, AV_LOG_INFO
, "SWF compressed file detected\n");
146 swf
->zbuf_in
= av_malloc(ZBUF_SIZE
);
147 swf
->zbuf_out
= av_malloc(ZBUF_SIZE
);
148 swf
->zpb
= avio_alloc_context(swf
->zbuf_out
, ZBUF_SIZE
, 0, s
,
149 zlib_refill
, NULL
, NULL
);
150 if (!swf
->zbuf_in
|| !swf
->zbuf_out
|| !swf
->zpb
)
151 return AVERROR(ENOMEM
);
152 swf
->zpb
->seekable
= 0;
153 if (inflateInit(&swf
->zstream
) != Z_OK
) {
154 av_log(s
, AV_LOG_ERROR
, "Unable to init zlib context\n");
155 return AVERROR(EINVAL
);
159 av_log(s
, AV_LOG_ERROR
, "zlib support is required to read SWF compressed files\n");
162 } else if (tag
!= MKBETAG('F', 'W', 'S', 0))
164 /* skip rectangle size */
165 nbits
= avio_r8(pb
) >> 3;
166 len
= (4 * nbits
- 3 + 7) / 8;
168 swf
->frame_rate
= avio_rl16(pb
); /* 8.8 fixed */
169 avio_rl16(pb
); /* frame count */
171 swf
->samples_per_frame
= 0;
172 s
->ctx_flags
|= AVFMTCTX_NOHEADER
;
176 static AVStream
*create_new_audio_stream(AVFormatContext
*s
, int id
, int info
)
178 int sample_rate_code
, sample_size_code
;
179 AVStream
*ast
= avformat_new_stream(s
, NULL
);
184 ast
->codecpar
->channels
= 2;
185 ast
->codecpar
->channel_layout
= AV_CH_LAYOUT_STEREO
;
187 ast
->codecpar
->channels
= 1;
188 ast
->codecpar
->channel_layout
= AV_CH_LAYOUT_MONO
;
190 ast
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
191 ast
->codecpar
->codec_id
= ff_codec_get_id(swf_audio_codec_tags
, info
>>4 & 15);
192 ast
->need_parsing
= AVSTREAM_PARSE_FULL
;
193 sample_rate_code
= info
>>2 & 3;
194 sample_size_code
= info
>>1 & 1;
195 if (!sample_size_code
&& ast
->codecpar
->codec_id
== AV_CODEC_ID_PCM_S16LE
)
196 ast
->codecpar
->codec_id
= AV_CODEC_ID_PCM_U8
;
197 ast
->codecpar
->sample_rate
= 44100 >> (3 - sample_rate_code
);
198 avpriv_set_pts_info(ast
, 64, 1, ast
->codecpar
->sample_rate
);
202 static int swf_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
204 SWFContext
*swf
= s
->priv_data
;
205 AVIOContext
*pb
= s
->pb
;
206 AVStream
*vst
= NULL
, *ast
= NULL
, *st
= 0;
207 int tag
, len
, i
, frame
, v
, res
;
215 uint64_t pos
= avio_tell(pb
);
216 tag
= get_swf_tag(pb
, &len
);
220 av_log(s
, AV_LOG_ERROR
, "invalid tag length: %d\n", len
);
221 return AVERROR_INVALIDDATA
;
223 if (tag
== TAG_VIDEOSTREAM
) {
224 int ch_id
= avio_rl16(pb
);
227 for (i
=0; i
<s
->nb_streams
; i
++) {
229 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&& st
->id
== ch_id
)
238 vst
= avformat_new_stream(s
, NULL
);
240 return AVERROR(ENOMEM
);
242 vst
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
243 vst
->codecpar
->codec_id
= ff_codec_get_id(ff_swf_codec_tags
, avio_r8(pb
));
244 avpriv_set_pts_info(vst
, 16, 256, swf
->frame_rate
);
246 } else if (tag
== TAG_STREAMHEAD
|| tag
== TAG_STREAMHEAD2
) {
247 /* streaming found */
249 for (i
=0; i
<s
->nb_streams
; i
++) {
251 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
&& st
->id
== -1)
257 swf
->samples_per_frame
= avio_rl16(pb
);
258 ast
= create_new_audio_stream(s
, -1, v
); /* -1 to avoid clash with video stream ch_id */
260 return AVERROR(ENOMEM
);
262 } else if (tag
== TAG_DEFINESOUND
) {
264 int ch_id
= avio_rl16(pb
);
266 for (i
=0; i
<s
->nb_streams
; i
++) {
268 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
&& st
->id
== ch_id
)
272 // FIXME: The entire audio stream is stored in a single chunk/tag. Normally,
273 // these are smaller audio streams in DEFINESOUND tags, but it's technically
274 // possible they could be huge. Break it up into multiple packets if it's big.
276 ast
= create_new_audio_stream(s
, ch_id
, v
);
278 return AVERROR(ENOMEM
);
279 ast
->duration
= avio_rl32(pb
); // number of samples
280 if (((v
>>4) & 15) == 2) { // MP3 sound data record
281 ast
->skip_samples
= avio_rl16(pb
);
285 if ((res
= av_get_packet(pb
, pkt
, len
)) < 0)
288 pkt
->stream_index
= ast
->index
;
290 } else if (tag
== TAG_VIDEOFRAME
) {
291 int ch_id
= avio_rl16(pb
);
293 for(i
=0; i
<s
->nb_streams
; i
++) {
295 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&& st
->id
== ch_id
) {
296 frame
= avio_rl16(pb
);
300 if ((res
= av_get_packet(pb
, pkt
, len
)) < 0)
304 pkt
->stream_index
= st
->index
;
308 } else if (tag
== TAG_DEFINEBITSLOSSLESS
|| tag
== TAG_DEFINEBITSLOSSLESS2
) {
311 uint8_t *buf
= NULL
, *zbuf
= NULL
, *pal
;
312 uint32_t colormap
[AVPALETTE_COUNT
] = {0};
313 const int alpha_bmp
= tag
== TAG_DEFINEBITSLOSSLESS2
;
314 const int colormapbpp
= 3 + alpha_bmp
;
315 int linesize
, colormapsize
= 0;
317 const int ch_id
= avio_rl16(pb
);
318 const int bmp_fmt
= avio_r8(pb
);
319 const int width
= avio_rl16(pb
);
320 const int height
= avio_rl16(pb
);
328 colormapsize
= avio_r8(pb
) + 1;
332 linesize
= width
* 2;
334 case 5: // RGB24 (0RGB)
335 linesize
= width
* 4;
338 av_log(s
, AV_LOG_ERROR
, "invalid bitmap format %d, skipped\n", bmp_fmt
);
339 goto bitmap_end_skip
;
342 linesize
= FFALIGN(linesize
, 4);
344 if (av_image_check_size(width
, height
, 0, s
) < 0 ||
345 linesize
>= INT_MAX
/ height
||
346 linesize
* height
>= INT_MAX
- colormapsize
* colormapbpp
) {
347 av_log(s
, AV_LOG_ERROR
, "invalid frame size %dx%d\n", width
, height
);
348 goto bitmap_end_skip
;
351 out_len
= colormapsize
* colormapbpp
+ linesize
* height
;
353 ff_dlog(s
, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n",
354 ch_id
, bmp_fmt
, width
, height
, linesize
, len
, out_len
, colormapsize
);
356 zbuf
= av_malloc(len
);
357 buf
= av_malloc(out_len
);
359 res
= AVERROR(ENOMEM
);
363 len
= avio_read(pb
, zbuf
, len
);
364 if (len
< 0 || (res
= uncompress(buf
, &out_len
, zbuf
, len
)) != Z_OK
) {
365 av_log(s
, AV_LOG_WARNING
, "Failed to uncompress one bitmap\n");
366 goto bitmap_end_skip
;
369 for (i
= 0; i
< s
->nb_streams
; i
++) {
371 if (st
->codecpar
->codec_id
== AV_CODEC_ID_RAWVIDEO
&& st
->id
== -3)
374 if (i
== s
->nb_streams
) {
375 vst
= avformat_new_stream(s
, NULL
);
377 res
= AVERROR(ENOMEM
);
380 vst
->id
= -3; /* -3 to avoid clash with video stream and audio stream */
381 vst
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
382 vst
->codecpar
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
383 avpriv_set_pts_info(vst
, 64, 256, swf
->frame_rate
);
387 if ((res
= av_new_packet(pkt
, out_len
- colormapsize
* colormapbpp
)) < 0)
389 if (!st
->codecpar
->width
&& !st
->codecpar
->height
) {
390 st
->codecpar
->width
= width
;
391 st
->codecpar
->height
= height
;
393 ff_add_param_change(pkt
, 0, 0, 0, width
, height
);
396 pkt
->stream_index
= st
->index
;
398 if (linesize
* height
> pkt
->size
) {
399 res
= AVERROR_INVALIDDATA
;
400 av_packet_unref(pkt
);
406 pix_fmt
= AV_PIX_FMT_PAL8
;
407 for (i
= 0; i
< colormapsize
; i
++)
408 if (alpha_bmp
) colormap
[i
] = buf
[3]<<24 | AV_RB24(buf
+ 4*i
);
409 else colormap
[i
] = 0xffU
<<24 | AV_RB24(buf
+ 3*i
);
410 pal
= av_packet_new_side_data(pkt
, AV_PKT_DATA_PALETTE
, AVPALETTE_SIZE
);
412 res
= AVERROR(ENOMEM
);
415 memcpy(pal
, colormap
, AVPALETTE_SIZE
);
418 pix_fmt
= AV_PIX_FMT_RGB555
;
421 pix_fmt
= alpha_bmp
? AV_PIX_FMT_ARGB
: AV_PIX_FMT_0RGB
;
426 if (st
->codecpar
->format
!= AV_PIX_FMT_NONE
&& st
->codecpar
->format
!= pix_fmt
) {
427 av_log(s
, AV_LOG_ERROR
, "pixel format change unsupported\n");
429 st
->codecpar
->format
= pix_fmt
;
431 memcpy(pkt
->data
, buf
+ colormapsize
*colormapbpp
, linesize
* height
);
443 av_log(s
, AV_LOG_ERROR
, "this file requires zlib support compiled in\n");
445 } else if (tag
== TAG_STREAMBLOCK
) {
446 for (i
= 0; i
< s
->nb_streams
; i
++) {
448 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
&& st
->id
== -1) {
449 if (st
->codecpar
->codec_id
== AV_CODEC_ID_MP3
) {
454 if ((res
= av_get_packet(pb
, pkt
, len
)) < 0)
456 } else { // ADPCM, PCM
459 if ((res
= av_get_packet(pb
, pkt
, len
)) < 0)
463 pkt
->stream_index
= st
->index
;
467 } else if (tag
== TAG_JPEG2
) {
468 for (i
=0; i
<s
->nb_streams
; i
++) {
470 if (st
->codecpar
->codec_id
== AV_CODEC_ID_MJPEG
&& st
->id
== -2)
473 if (i
== s
->nb_streams
) {
474 vst
= avformat_new_stream(s
, NULL
);
476 return AVERROR(ENOMEM
);
477 vst
->id
= -2; /* -2 to avoid clash with video stream and audio stream */
478 vst
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
479 vst
->codecpar
->codec_id
= AV_CODEC_ID_MJPEG
;
480 avpriv_set_pts_info(vst
, 64, 256, swf
->frame_rate
);
483 avio_rl16(pb
); /* BITMAP_ID */
487 if ((res
= av_new_packet(pkt
, len
)) < 0)
489 if (avio_read(pb
, pkt
->data
, 4) != 4) {
490 av_packet_unref(pkt
);
491 return AVERROR_INVALIDDATA
;
493 if (AV_RB32(pkt
->data
) == 0xffd8ffd9 ||
494 AV_RB32(pkt
->data
) == 0xffd9ffd8) {
495 /* old SWF files containing SOI/EOI as data start */
496 /* files created by swink have reversed tag */
498 memset(pkt
->data
+pkt
->size
, 0, 4);
499 res
= avio_read(pb
, pkt
->data
, pkt
->size
);
501 res
= avio_read(pb
, pkt
->data
+ 4, pkt
->size
- 4);
505 if (res
!= pkt
->size
) {
507 av_packet_unref(pkt
);
510 av_shrink_packet(pkt
, res
);
514 pkt
->stream_index
= st
->index
;
517 av_log(s
, AV_LOG_DEBUG
, "Unknown tag: %d\n", tag
);
521 av_log(s
, AV_LOG_WARNING
, "Clipping len %d\n", len
);
528 static av_cold
int swf_read_close(AVFormatContext
*avctx
)
530 SWFContext
*s
= avctx
->priv_data
;
531 inflateEnd(&s
->zstream
);
532 av_freep(&s
->zbuf_in
);
533 av_freep(&s
->zbuf_out
);
539 AVInputFormat ff_swf_demuxer
= {
541 .long_name
= NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
542 .priv_data_size
= sizeof(SWFContext
),
543 .read_probe
= swf_probe
,
544 .read_header
= swf_read_header
,
545 .read_packet
= swf_read_packet
,
547 .read_close
= swf_read_close
,