summaryrefslogtreecommitdiff
path: root/libavformat/swfdec.c
diff options
context:
space:
mode:
authorClément Bœsch <ubitux@gmail.com>2015-12-02 18:41:00 -0500
committerVittorio Giovara <vittorio.giovara@gmail.com>2016-01-11 15:32:56 -0500
commit7570c9e04f010c9b3bfdeb4338d330f2cdd25278 (patch)
tree6c54533500d0b3a57c208a1d21654a492ae23669 /libavformat/swfdec.c
parent34d45b36164eee044cfe55d22488b2b65e387872 (diff)
swfdec: support compressed swf
Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
Diffstat (limited to 'libavformat/swfdec.c')
-rw-r--r--libavformat/swfdec.c86
1 files changed, 82 insertions, 4 deletions
diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c
index d7a53145c6..7b5cd358ba 100644
--- a/libavformat/swfdec.c
+++ b/libavformat/swfdec.c
@@ -20,6 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "config.h"
+
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "swf.h"
@@ -61,6 +67,39 @@ static int swf_probe(AVProbeData *p)
return 0;
}
+#if CONFIG_ZLIB
+static int zlib_refill(void *opaque, uint8_t *buf, int buf_size)
+{
+ AVFormatContext *s = opaque;
+ SWFContext *swf = s->priv_data;
+ z_stream *z = &swf->zstream;
+ int ret;
+
+retry:
+ if (!z->avail_in) {
+ int n = avio_read(s->pb, swf->zbuf_in, ZBUF_SIZE);
+ if (n < 0)
+ return n;
+ z->next_in = swf->zbuf_in;
+ z->avail_in = n;
+ }
+
+ z->next_out = buf;
+ z->avail_out = buf_size;
+
+ ret = inflate(z, Z_NO_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ av_log(s, AV_LOG_ERROR, "Inflate error: %d\n", ret);
+ return AVERROR_UNKNOWN;
+ }
+
+ if (buf_size - z->avail_out == 0)
+ goto retry;
+
+ return buf_size - z->avail_out;
+}
+#endif
+
static int swf_read_header(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
@@ -68,14 +107,33 @@ static int swf_read_header(AVFormatContext *s)
int nbits, len, tag;
tag = avio_rb32(pb) & 0xffffff00;
+ avio_rl32(pb);
if (tag == MKBETAG('C', 'W', 'S', 0)) {
- av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
+ av_log(s, AV_LOG_INFO, "Compressed SWF file detected\n");
+#if CONFIG_ZLIB
+ if (inflateInit(&swf->zstream) != Z_OK) {
+ av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
+ return AVERROR(EINVAL);
+ }
+ swf->zbuf_in = av_malloc(ZBUF_SIZE);
+ swf->zbuf_out = av_malloc(ZBUF_SIZE);
+ swf->zpb = avio_alloc_context(swf->zbuf_out, ZBUF_SIZE, 0, s,
+ zlib_refill, NULL, NULL);
+ if (!swf->zbuf_in || !swf->zbuf_out || !swf->zpb) {
+ av_freep(&swf->zbuf_in);
+ av_freep(&swf->zbuf_out);
+ av_freep(&swf->zpb);
+ return AVERROR(ENOMEM);
+ }
+ swf->zpb->seekable = 0;
+ pb = swf->zpb;
+#else
+ av_log(s, AV_LOG_ERROR, "missing zlib support, unable to open\n");
return AVERROR(EIO);
- }
- if (tag != MKBETAG('F', 'W', 'S', 0))
+#endif
+ } else if (tag != MKBETAG('F', 'W', 'S', 0))
return AVERROR(EIO);
- avio_rl32(pb);
/* skip rectangle size */
nbits = avio_r8(pb) >> 3;
len = (4 * nbits - 3 + 7) / 8;
@@ -95,6 +153,11 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *vst = NULL, *ast = NULL, *st = 0;
int tag, len, i, frame, v, res;
+#if CONFIG_ZLIB
+ if (swf->zpb)
+ pb = swf->zpb;
+#endif
+
for(;;) {
uint64_t pos = avio_tell(pb);
tag = get_swf_tag(pb, &len);
@@ -240,6 +303,18 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
}
}
+#if CONFIG_ZLIB
+static av_cold int swf_read_close(AVFormatContext *avctx)
+{
+ SWFContext *s = avctx->priv_data;
+ inflateEnd(&s->zstream);
+ av_freep(&s->zbuf_in);
+ av_freep(&s->zbuf_out);
+ av_freep(&s->zpb);
+ return 0;
+}
+#endif
+
AVInputFormat ff_swf_demuxer = {
.name = "swf",
.long_name = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
@@ -247,4 +322,7 @@ AVInputFormat ff_swf_demuxer = {
.read_probe = swf_probe,
.read_header = swf_read_header,
.read_packet = swf_read_packet,
+#if CONFIG_ZLIB
+ .read_close = swf_read_close,
+#endif
};