mirror of
https://git.in.rschanz.org/ryan77627/guix.git
synced 2024-11-16 03:45:24 -05:00
1048 lines
34 KiB
Diff
1048 lines
34 KiB
Diff
|
Fixes upstream bug #774859 (flic decoder: Invalid memory read in
|
||
|
flx_decode_chunks):
|
||
|
|
||
|
https://bugzilla.gnome.org/show_bug.cgi?id=774859
|
||
|
|
||
|
Patch copied from upstream source repository:
|
||
|
|
||
|
https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=be670f0daf67304fb92c76aa09c30cae0bfd1fe4
|
||
|
|
||
|
From be670f0daf67304fb92c76aa09c30cae0bfd1fe4 Mon Sep 17 00:00:00 2001
|
||
|
From: Matthew Waters <matthew@centricular.com>
|
||
|
Date: Wed, 23 Nov 2016 07:09:06 +1100
|
||
|
Subject: [PATCH] flxdec: rewrite logic based on GstByteReader/Writer
|
||
|
|
||
|
Solves overreading/writing the given arrays and will error out if the
|
||
|
streams asks to do that.
|
||
|
|
||
|
Also does more error checking that the stream is valid and won't
|
||
|
overrun any allocated arrays. Also mitigate integer overflow errors
|
||
|
calculating allocation sizes.
|
||
|
|
||
|
https://bugzilla.gnome.org/show_bug.cgi?id=774859
|
||
|
---
|
||
|
gst/flx/flx_color.c | 1 -
|
||
|
gst/flx/flx_fmt.h | 72 -------
|
||
|
gst/flx/gstflxdec.c | 610 ++++++++++++++++++++++++++++++++++++----------------
|
||
|
gst/flx/gstflxdec.h | 4 +-
|
||
|
4 files changed, 427 insertions(+), 260 deletions(-)
|
||
|
|
||
|
diff --git a/gst/flx/flx_color.c b/gst/flx/flx_color.c
|
||
|
index 047bfdf..3a58135 100644
|
||
|
--- a/gst/flx/flx_color.c
|
||
|
+++ b/gst/flx/flx_color.c
|
||
|
@@ -101,7 +101,6 @@ flx_set_palette_vector (FlxColorSpaceConverter * flxpal, guint start, guint num,
|
||
|
} else {
|
||
|
memcpy (&flxpal->palvec[start * 3], newpal, grab * 3);
|
||
|
}
|
||
|
-
|
||
|
}
|
||
|
|
||
|
void
|
||
|
diff --git a/gst/flx/flx_fmt.h b/gst/flx/flx_fmt.h
|
||
|
index 9ab31ba..abff200 100644
|
||
|
--- a/gst/flx/flx_fmt.h
|
||
|
+++ b/gst/flx/flx_fmt.h
|
||
|
@@ -123,78 +123,6 @@ typedef struct _FlxFrameType
|
||
|
} FlxFrameType;
|
||
|
#define FlxFrameTypeSize 10
|
||
|
|
||
|
-#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||
|
-#define LE_TO_BE_16(i16) ((guint16) (((i16) << 8) | ((i16) >> 8)))
|
||
|
-#define LE_TO_BE_32(i32) \
|
||
|
- (((guint32) (LE_TO_BE_16((guint16) (i32))) << 16) | (LE_TO_BE_16((i32) >> 16)))
|
||
|
-
|
||
|
-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p) \
|
||
|
- do { \
|
||
|
- (frm_type_p)->chunks = LE_TO_BE_16((frm_type_p)->chunks); \
|
||
|
- (frm_type_p)->delay = LE_TO_BE_16((frm_type_p)->delay); \
|
||
|
- } while(0)
|
||
|
-
|
||
|
-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p) \
|
||
|
- do { \
|
||
|
- (hffmn_table_p)->codelength = \
|
||
|
- LE_TO_BE_16((hffmn_table_p)->codelength); \
|
||
|
- (hffmn_table_p)->numcodes = LE_TO_BE_16((hffmn_table_p)->numcodes); \
|
||
|
- } while(0)
|
||
|
-
|
||
|
-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p) \
|
||
|
- ((sgmnt_table_p)->segments = LE_TO_BE_16((sgmnt_table_p)->segments))
|
||
|
-
|
||
|
-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p) \
|
||
|
- do { \
|
||
|
- (prfx_chnk_p)->chunks = LE_TO_BE_16((prfx_chnk_p)->chunks); \
|
||
|
- } while(0)
|
||
|
-
|
||
|
-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p) \
|
||
|
- do { \
|
||
|
- (frm_chnk_p)->size = LE_TO_BE_32((frm_chnk_p)->size); \
|
||
|
- (frm_chnk_p)->id = LE_TO_BE_16((frm_chnk_p)->id); \
|
||
|
- } while(0)
|
||
|
-
|
||
|
-#define FLX_HDR_FIX_ENDIANNESS(hdr_p) \
|
||
|
- do { \
|
||
|
- (hdr_p)->size = LE_TO_BE_32((hdr_p)->size); \
|
||
|
- (hdr_p)->type = LE_TO_BE_16((hdr_p)->type); \
|
||
|
- (hdr_p)->frames = LE_TO_BE_16((hdr_p)->frames); \
|
||
|
- (hdr_p)->width = LE_TO_BE_16((hdr_p)->width); \
|
||
|
- (hdr_p)->height = LE_TO_BE_16((hdr_p)->height); \
|
||
|
- (hdr_p)->depth = LE_TO_BE_16((hdr_p)->depth); \
|
||
|
- (hdr_p)->flags = LE_TO_BE_16((hdr_p)->flags); \
|
||
|
- (hdr_p)->speed = LE_TO_BE_32((hdr_p)->speed); \
|
||
|
- (hdr_p)->reserved1 = LE_TO_BE_16((hdr_p)->reserved1); \
|
||
|
- (hdr_p)->created = LE_TO_BE_32((hdr_p)->created); \
|
||
|
- (hdr_p)->creator = LE_TO_BE_32((hdr_p)->creator); \
|
||
|
- (hdr_p)->updated = LE_TO_BE_32((hdr_p)->updated); \
|
||
|
- (hdr_p)->updater = LE_TO_BE_32((hdr_p)->updater); \
|
||
|
- (hdr_p)->aspect_dx = LE_TO_BE_16((hdr_p)->aspect_dx); \
|
||
|
- (hdr_p)->aspect_dy = LE_TO_BE_16((hdr_p)->aspect_dy); \
|
||
|
- (hdr_p)->ext_flags = LE_TO_BE_16((hdr_p)->ext_flags); \
|
||
|
- (hdr_p)->keyframes = LE_TO_BE_16((hdr_p)->keyframes); \
|
||
|
- (hdr_p)->totalframes = LE_TO_BE_16((hdr_p)->totalframes); \
|
||
|
- (hdr_p)->req_memory = LE_TO_BE_32((hdr_p)->req_memory); \
|
||
|
- (hdr_p)->max_regions = LE_TO_BE_16((hdr_p)->max_regions); \
|
||
|
- (hdr_p)->transp_num = LE_TO_BE_16((hdr_p)->transp_num); \
|
||
|
- (hdr_p)->oframe1 = LE_TO_BE_32((hdr_p)->oframe1); \
|
||
|
- (hdr_p)->oframe2 = LE_TO_BE_32((hdr_p)->oframe2); \
|
||
|
- } while(0)
|
||
|
-#else
|
||
|
-
|
||
|
-#define LE_TO_BE_16(i16) ((i16))
|
||
|
-#define LE_TO_BE_32(i32) ((i32))
|
||
|
-
|
||
|
-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p)
|
||
|
-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p)
|
||
|
-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p)
|
||
|
-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p)
|
||
|
-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p)
|
||
|
-#define FLX_HDR_FIX_ENDIANNESS(hdr_p)
|
||
|
-
|
||
|
-#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
|
||
|
-
|
||
|
G_END_DECLS
|
||
|
|
||
|
#endif /* __GST_FLX_FMT_H__ */
|
||
|
diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
|
||
|
index a237976..aa1bed5 100644
|
||
|
--- a/gst/flx/gstflxdec.c
|
||
|
+++ b/gst/flx/gstflxdec.c
|
||
|
@@ -1,5 +1,6 @@
|
||
|
/* GStreamer
|
||
|
* Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
|
||
|
+ * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Library General Public
|
||
|
@@ -24,6 +25,7 @@
|
||
|
/*
|
||
|
* http://www.coolutils.com/Formats/FLI
|
||
|
* http://woodshole.er.usgs.gov/operations/modeling/flc.html
|
||
|
+ * http://www.compuphase.com/flic.htm
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
@@ -73,10 +75,14 @@ static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
|
||
|
static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
|
||
|
GstQuery * query);
|
||
|
|
||
|
-static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
|
||
|
-static gboolean flx_decode_brun (GstFlxDec *, guchar *, guchar *);
|
||
|
-static gboolean flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
|
||
|
-static gboolean flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
|
||
|
+static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer, gint scale);
|
||
|
+static gboolean flx_decode_brun (GstFlxDec * flxdec,
|
||
|
+ GstByteReader * reader, GstByteWriter * writer);
|
||
|
+static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
|
||
|
+ GstByteReader * reader, GstByteWriter * writer);
|
||
|
+static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
|
||
|
+ GstByteReader * reader, GstByteWriter * writer);
|
||
|
|
||
|
#define rndalign(off) ((off) + ((off) & 1))
|
||
|
|
||
|
@@ -204,57 +210,59 @@ gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
-flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
||
|
- guchar * dest)
|
||
|
+flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer)
|
||
|
{
|
||
|
- FlxFrameChunk *hdr;
|
||
|
gboolean ret = TRUE;
|
||
|
|
||
|
- g_return_val_if_fail (data != NULL, FALSE);
|
||
|
-
|
||
|
- while (count--) {
|
||
|
- hdr = (FlxFrameChunk *) data;
|
||
|
- FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
|
||
|
- data += FlxFrameChunkSize;
|
||
|
+ while (n_chunks--) {
|
||
|
+ GstByteReader chunk;
|
||
|
+ guint32 size;
|
||
|
+ guint16 type;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &size))
|
||
|
+ goto parse_error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &type))
|
||
|
+ goto parse_error;
|
||
|
+ GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_sub_reader (reader, &chunk,
|
||
|
+ size - FlxFrameChunkSize)) {
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Incorrect size in the chunk header");
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
|
||
|
- switch (hdr->id) {
|
||
|
+ switch (type) {
|
||
|
case FLX_COLOR64:
|
||
|
- flx_decode_color (flxdec, data, dest, 2);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ ret = flx_decode_color (flxdec, &chunk, writer, 2);
|
||
|
break;
|
||
|
|
||
|
case FLX_COLOR256:
|
||
|
- flx_decode_color (flxdec, data, dest, 0);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ ret = flx_decode_color (flxdec, &chunk, writer, 0);
|
||
|
break;
|
||
|
|
||
|
case FLX_BRUN:
|
||
|
- ret = flx_decode_brun (flxdec, data, dest);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ ret = flx_decode_brun (flxdec, &chunk, writer);
|
||
|
break;
|
||
|
|
||
|
case FLX_LC:
|
||
|
- ret = flx_decode_delta_fli (flxdec, data, dest);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ ret = flx_decode_delta_fli (flxdec, &chunk, writer);
|
||
|
break;
|
||
|
|
||
|
case FLX_SS2:
|
||
|
- ret = flx_decode_delta_flc (flxdec, data, dest);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ ret = flx_decode_delta_flc (flxdec, &chunk, writer);
|
||
|
break;
|
||
|
|
||
|
case FLX_BLACK:
|
||
|
- memset (dest, 0, flxdec->size);
|
||
|
+ ret = gst_byte_writer_fill (writer, 0, flxdec->size);
|
||
|
break;
|
||
|
|
||
|
case FLX_MINI:
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
|
||
|
- hdr->id, hdr->size);
|
||
|
- data += rndalign (hdr->size) - FlxFrameChunkSize;
|
||
|
+ GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
|
||
|
+ type, size);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
@@ -263,43 +271,60 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
+
|
||
|
+parse_error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
|
||
|
+error:
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
-static void
|
||
|
-flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
|
||
|
+static gboolean
|
||
|
+flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer, gint scale)
|
||
|
{
|
||
|
- guint packs, count, indx;
|
||
|
+ guint8 count, indx;
|
||
|
+ guint16 packs;
|
||
|
|
||
|
- g_return_if_fail (flxdec != NULL);
|
||
|
-
|
||
|
- packs = (data[0] + (data[1] << 8));
|
||
|
-
|
||
|
- data += 2;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &packs))
|
||
|
+ goto error;
|
||
|
indx = 0;
|
||
|
|
||
|
- GST_LOG ("GstFlxDec: cmap packs: %d", packs);
|
||
|
+ GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
|
||
|
while (packs--) {
|
||
|
+ const guint8 *data;
|
||
|
+ guint16 actual_count;
|
||
|
+
|
||
|
/* color map index + skip count */
|
||
|
- indx += *data++;
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &indx))
|
||
|
+ goto error;
|
||
|
|
||
|
/* number of rgb triplets */
|
||
|
- count = *data++ & 0xff;
|
||
|
- if (count == 0)
|
||
|
- count = 256;
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &count))
|
||
|
+ goto error;
|
||
|
|
||
|
- GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
|
||
|
- flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
|
||
|
+ actual_count = count == 0 ? 256 : count;
|
||
|
|
||
|
- data += (count * 3);
|
||
|
+ if (!gst_byte_reader_get_data (reader, count * 3, &data))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
|
||
|
+ flx_set_palette_vector (flxdec->converter, indx, actual_count,
|
||
|
+ (guchar *) data, scale);
|
||
|
}
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+
|
||
|
+error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
-flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
+flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer)
|
||
|
{
|
||
|
- gulong count, lines, row;
|
||
|
- guchar x;
|
||
|
+ gulong lines, row;
|
||
|
|
||
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||
|
|
||
|
@@ -310,82 +335,125 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
* contain more then 255 RLE packets. we use the frame
|
||
|
* width instead.
|
||
|
*/
|
||
|
- data++;
|
||
|
+ if (!gst_byte_reader_skip (reader, 1))
|
||
|
+ goto error;
|
||
|
|
||
|
row = flxdec->hdr.width;
|
||
|
while (row) {
|
||
|
- count = *data++;
|
||
|
+ gint8 count;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_int8 (reader, &count))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ if (count <= 0) {
|
||
|
+ const guint8 *data;
|
||
|
|
||
|
- if (count > 0x7f) {
|
||
|
/* literal run */
|
||
|
- count = 0x100 - count;
|
||
|
- if ((glong) row - (glong) count < 0) {
|
||
|
- GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
|
||
|
+ count = ABS (count);
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
|
||
|
+
|
||
|
+ if (count > row) {
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
|
||
|
+ "bytes to write exceeds the end of the row");
|
||
|
return FALSE;
|
||
|
}
|
||
|
row -= count;
|
||
|
|
||
|
- while (count--)
|
||
|
- *dest++ = *data++;
|
||
|
-
|
||
|
+ if (!gst_byte_reader_get_data (reader, count, &data))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_put_data (writer, data, count))
|
||
|
+ goto error;
|
||
|
} else {
|
||
|
- if ((glong) row - (glong) count < 0) {
|
||
|
- GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
|
||
|
+ guint8 x;
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
|
||
|
+
|
||
|
+ if (count > row) {
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
|
||
|
+ "bytes to write exceeds the end of the row");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* replicate run */
|
||
|
row -= count;
|
||
|
- x = *data++;
|
||
|
|
||
|
- while (count--)
|
||
|
- *dest++ = x;
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &x))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_fill (writer, x, count))
|
||
|
+ goto error;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
+
|
||
|
+error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
-flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
+flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer)
|
||
|
{
|
||
|
- gulong count, packets, lines, start_line;
|
||
|
- guchar *start_p, x;
|
||
|
+ guint16 start_line, lines;
|
||
|
+ guint line_start_i;
|
||
|
|
||
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||
|
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
|
||
|
|
||
|
/* use last frame for delta */
|
||
|
- memcpy (dest, flxdec->delta_data, flxdec->size);
|
||
|
+ if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &start_line))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &lines))
|
||
|
+ goto error;
|
||
|
+ GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
|
||
|
+ flxdec->hdr.height, start_line, lines);
|
||
|
|
||
|
- start_line = (data[0] + (data[1] << 8));
|
||
|
- lines = (data[2] + (data[3] << 8));
|
||
|
if (start_line + lines > flxdec->hdr.height) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
|
||
|
return FALSE;
|
||
|
}
|
||
|
- data += 4;
|
||
|
|
||
|
- /* start position of delta */
|
||
|
- dest += (flxdec->hdr.width * start_line);
|
||
|
- start_p = dest;
|
||
|
+ line_start_i = flxdec->hdr.width * start_line;
|
||
|
+ if (!gst_byte_writer_set_pos (writer, line_start_i))
|
||
|
+ goto error;
|
||
|
|
||
|
while (lines--) {
|
||
|
+ guint8 packets;
|
||
|
+
|
||
|
/* packet count */
|
||
|
- packets = *data++;
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &packets))
|
||
|
+ goto error;
|
||
|
+ GST_LOG_OBJECT (flxdec, "have %d packets", packets);
|
||
|
|
||
|
while (packets--) {
|
||
|
/* skip count */
|
||
|
- guchar skip = *data++;
|
||
|
- dest += skip;
|
||
|
+ guint8 skip;
|
||
|
+ gint8 count;
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &skip))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ /* skip bytes */
|
||
|
+ if (!gst_byte_writer_set_pos (writer,
|
||
|
+ gst_byte_writer_get_pos (writer) + skip))
|
||
|
+ goto error;
|
||
|
|
||
|
/* RLE count */
|
||
|
- count = *data++;
|
||
|
+ if (!gst_byte_reader_get_int8 (reader, &count))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ if (count < 0) {
|
||
|
+ guint8 x;
|
||
|
|
||
|
- if (count > 0x7f) {
|
||
|
/* literal run */
|
||
|
- count = 0x100 - count;
|
||
|
+ count = ABS (count);
|
||
|
+ GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
|
||
|
+ count, skip);
|
||
|
|
||
|
if (skip + count > flxdec->hdr.width) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
|
||
|
@@ -393,11 +461,16 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
- x = *data++;
|
||
|
- while (count--)
|
||
|
- *dest++ = x;
|
||
|
-
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &x))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_fill (writer, x, count))
|
||
|
+ goto error;
|
||
|
} else {
|
||
|
+ const guint8 *data;
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
|
||
|
+ count, skip);
|
||
|
+
|
||
|
if (skip + count > flxdec->hdr.width) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
|
||
|
"line too long.");
|
||
|
@@ -405,45 +478,60 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
}
|
||
|
|
||
|
/* replicate run */
|
||
|
- while (count--)
|
||
|
- *dest++ = *data++;
|
||
|
+ if (!gst_byte_reader_get_data (reader, count, &data))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_put_data (writer, data, count))
|
||
|
+ goto error;
|
||
|
}
|
||
|
}
|
||
|
- start_p += flxdec->hdr.width;
|
||
|
- dest = start_p;
|
||
|
+ line_start_i += flxdec->hdr.width;
|
||
|
+ if (!gst_byte_writer_set_pos (writer, line_start_i))
|
||
|
+ goto error;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
+
|
||
|
+error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
-flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
+flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
|
||
|
+ GstByteWriter * writer)
|
||
|
{
|
||
|
- gulong count, lines, start_l, opcode;
|
||
|
- guchar *start_p;
|
||
|
+ guint16 lines, start_l;
|
||
|
|
||
|
g_return_val_if_fail (flxdec != NULL, FALSE);
|
||
|
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
|
||
|
|
||
|
/* use last frame for delta */
|
||
|
- memcpy (dest, flxdec->delta_data, flxdec->size);
|
||
|
+ if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &lines))
|
||
|
+ goto error;
|
||
|
|
||
|
- lines = (data[0] + (data[1] << 8));
|
||
|
if (lines > flxdec->hdr.height) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
|
||
|
return FALSE;
|
||
|
}
|
||
|
- data += 2;
|
||
|
|
||
|
- start_p = dest;
|
||
|
start_l = lines;
|
||
|
|
||
|
while (lines) {
|
||
|
- dest = start_p + (flxdec->hdr.width * (start_l - lines));
|
||
|
+ guint16 opcode;
|
||
|
+
|
||
|
+ if (!gst_byte_writer_set_pos (writer,
|
||
|
+ flxdec->hdr.width * (start_l - lines)))
|
||
|
+ goto error;
|
||
|
|
||
|
/* process opcode(s) */
|
||
|
- while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
|
||
|
- data += 2;
|
||
|
+ while (TRUE) {
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &opcode))
|
||
|
+ goto error;
|
||
|
+ if ((opcode & 0xc000) == 0)
|
||
|
+ break;
|
||
|
+
|
||
|
if ((opcode & 0xc000) == 0xc000) {
|
||
|
/* line skip count */
|
||
|
gulong skip = (0x10000 - opcode);
|
||
|
@@ -453,27 +541,44 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
return FALSE;
|
||
|
}
|
||
|
start_l += skip;
|
||
|
- dest += flxdec->hdr.width * skip;
|
||
|
+ if (!gst_byte_writer_set_pos (writer,
|
||
|
+ gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
|
||
|
+ goto error;
|
||
|
} else {
|
||
|
/* last pixel */
|
||
|
- dest += flxdec->hdr.width;
|
||
|
- *dest++ = (opcode & 0xff);
|
||
|
+ if (!gst_byte_writer_set_pos (writer,
|
||
|
+ gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
|
||
|
+ goto error;
|
||
|
}
|
||
|
}
|
||
|
- data += 2;
|
||
|
|
||
|
/* last opcode is the packet count */
|
||
|
+ GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
|
||
|
while (opcode--) {
|
||
|
/* skip count */
|
||
|
- guchar skip = *data++;
|
||
|
- dest += skip;
|
||
|
+ guint8 skip;
|
||
|
+ gint8 count;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint8 (reader, &skip))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_set_pos (writer,
|
||
|
+ gst_byte_writer_get_pos (writer) + skip))
|
||
|
+ goto error;
|
||
|
|
||
|
/* RLE count */
|
||
|
- count = *data++;
|
||
|
+ if (!gst_byte_reader_get_int8 (reader, &count))
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ if (count < 0) {
|
||
|
+ guint16 x;
|
||
|
|
||
|
- if (count > 0x7f) {
|
||
|
/* replicate word run */
|
||
|
- count = 0x100 - count;
|
||
|
+ count = ABS (count);
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
|
||
|
+ count, skip);
|
||
|
|
||
|
if (skip + count > flxdec->hdr.width) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
|
||
|
@@ -481,22 +586,31 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &x))
|
||
|
+ goto error;
|
||
|
+
|
||
|
while (count--) {
|
||
|
- *dest++ = data[0];
|
||
|
- *dest++ = data[1];
|
||
|
+ if (!gst_byte_writer_put_uint16_le (writer, x)) {
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
}
|
||
|
- data += 2;
|
||
|
} else {
|
||
|
+ GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
|
||
|
+ count, skip);
|
||
|
+
|
||
|
if (skip + count > flxdec->hdr.width) {
|
||
|
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
|
||
|
"line too long.");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
- /* literal word run */
|
||
|
while (count--) {
|
||
|
- *dest++ = *data++;
|
||
|
- *dest++ = *data++;
|
||
|
+ guint16 x;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &x))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_writer_put_uint16_le (writer, x))
|
||
|
+ goto error;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
@@ -504,13 +618,91 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
+
|
||
|
+error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
|
||
|
+ return FALSE;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
|
||
|
+{
|
||
|
+ memset (flxh, 0, sizeof (*flxh));
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
|
||
|
+ goto error;
|
||
|
+ if (flxh->size < FlxHeaderSize) {
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_skip (reader, 2)) /* reserved */
|
||
|
+ goto error;
|
||
|
+ /* FLC */
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
|
||
|
+ goto error;
|
||
|
+ /* EGI */
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_skip (reader, 24)) /* reserved */
|
||
|
+ goto error;
|
||
|
+ /* FLC */
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
|
||
|
+ goto error;
|
||
|
+ if (!gst_byte_reader_skip (reader, 40)) /* reserved */
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+
|
||
|
+error:
|
||
|
+ GST_ERROR_OBJECT (flxdec, "Error reading file header");
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
static GstFlowReturn
|
||
|
gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||
|
{
|
||
|
+ GstByteReader reader;
|
||
|
+ GstBuffer *input;
|
||
|
+ GstMapInfo map_info;
|
||
|
GstCaps *caps;
|
||
|
- guint avail;
|
||
|
+ guint available;
|
||
|
GstFlowReturn res = GST_FLOW_OK;
|
||
|
|
||
|
GstFlxDec *flxdec;
|
||
|
@@ -521,31 +713,50 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||
|
g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
|
||
|
|
||
|
gst_adapter_push (flxdec->adapter, buf);
|
||
|
- avail = gst_adapter_available (flxdec->adapter);
|
||
|
+ available = gst_adapter_available (flxdec->adapter);
|
||
|
+ input = gst_adapter_get_buffer (flxdec->adapter, available);
|
||
|
+ if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Failed to map buffer"), (NULL));
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+ gst_byte_reader_init (&reader, map_info.data, map_info.size);
|
||
|
|
||
|
if (flxdec->state == GST_FLXDEC_READ_HEADER) {
|
||
|
- if (avail >= FlxHeaderSize) {
|
||
|
- const guint8 *data = gst_adapter_map (flxdec->adapter, FlxHeaderSize);
|
||
|
+ if (available >= FlxHeaderSize) {
|
||
|
+ GstByteReader header;
|
||
|
GstCaps *templ;
|
||
|
|
||
|
- memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize);
|
||
|
- FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr));
|
||
|
- gst_adapter_unmap (flxdec->adapter);
|
||
|
+ if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Could not read header"), (NULL));
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
|
||
|
+ available -= FlxHeaderSize;
|
||
|
+
|
||
|
+ if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Failed to parse header"), (NULL));
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
|
||
|
flxh = &flxdec->hdr;
|
||
|
|
||
|
/* check header */
|
||
|
if (flxh->type != FLX_MAGICHDR_FLI &&
|
||
|
- flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX)
|
||
|
- goto wrong_type;
|
||
|
+ flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
|
||
|
+ ("not a flx file (type %x)", flxh->type));
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
|
||
|
- GST_LOG ("size : %d", flxh->size);
|
||
|
- GST_LOG ("frames : %d", flxh->frames);
|
||
|
- GST_LOG ("width : %d", flxh->width);
|
||
|
- GST_LOG ("height : %d", flxh->height);
|
||
|
- GST_LOG ("depth : %d", flxh->depth);
|
||
|
- GST_LOG ("speed : %d", flxh->speed);
|
||
|
+ GST_INFO_OBJECT (flxdec, "size : %d", flxh->size);
|
||
|
+ GST_INFO_OBJECT (flxdec, "frames : %d", flxh->frames);
|
||
|
+ GST_INFO_OBJECT (flxdec, "width : %d", flxh->width);
|
||
|
+ GST_INFO_OBJECT (flxdec, "height : %d", flxh->height);
|
||
|
+ GST_INFO_OBJECT (flxdec, "depth : %d", flxh->depth);
|
||
|
+ GST_INFO_OBJECT (flxdec, "speed : %d", flxh->speed);
|
||
|
|
||
|
flxdec->next_time = 0;
|
||
|
|
||
|
@@ -573,18 +784,32 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||
|
gst_pad_set_caps (flxdec->srcpad, caps);
|
||
|
gst_caps_unref (caps);
|
||
|
|
||
|
- if (flxh->depth <= 8)
|
||
|
- flxdec->converter =
|
||
|
- flx_colorspace_converter_new (flxh->width, flxh->height);
|
||
|
+ /* zero means 8 */
|
||
|
+ if (flxh->depth == 0)
|
||
|
+ flxh->depth = 8;
|
||
|
+
|
||
|
+ if (flxh->depth != 8) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
|
||
|
+ ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
+
|
||
|
+ flxdec->converter =
|
||
|
+ flx_colorspace_converter_new (flxh->width, flxh->height);
|
||
|
|
||
|
if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
|
||
|
- GST_LOG ("(FLC) aspect_dx : %d", flxh->aspect_dx);
|
||
|
- GST_LOG ("(FLC) aspect_dy : %d", flxh->aspect_dy);
|
||
|
- GST_LOG ("(FLC) oframe1 : 0x%08x", flxh->oframe1);
|
||
|
- GST_LOG ("(FLC) oframe2 : 0x%08x", flxh->oframe2);
|
||
|
+ GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx : %d", flxh->aspect_dx);
|
||
|
+ GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy : %d", flxh->aspect_dy);
|
||
|
+ GST_INFO_OBJECT (flxdec, "(FLC) oframe1 : 0x%08x", flxh->oframe1);
|
||
|
+ GST_INFO_OBJECT (flxdec, "(FLC) oframe2 : 0x%08x", flxh->oframe2);
|
||
|
}
|
||
|
|
||
|
flxdec->size = ((guint) flxh->width * (guint) flxh->height);
|
||
|
+ if (flxdec->size >= G_MAXSIZE / 4) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Cannot allocate required memory"), (NULL));
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
|
||
|
/* create delta and output frame */
|
||
|
flxdec->frame_data = g_malloc (flxdec->size);
|
||
|
@@ -596,55 +821,66 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||
|
GstBuffer *out;
|
||
|
|
||
|
/* while we have enough data in the adapter */
|
||
|
- while (avail >= FlxFrameChunkSize && res == GST_FLOW_OK) {
|
||
|
- FlxFrameChunk flxfh;
|
||
|
- guchar *chunk;
|
||
|
- const guint8 *data;
|
||
|
- GstMapInfo map;
|
||
|
-
|
||
|
- chunk = NULL;
|
||
|
- data = gst_adapter_map (flxdec->adapter, FlxFrameChunkSize);
|
||
|
- memcpy (&flxfh, data, FlxFrameChunkSize);
|
||
|
- FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh);
|
||
|
- gst_adapter_unmap (flxdec->adapter);
|
||
|
-
|
||
|
- switch (flxfh.id) {
|
||
|
- case FLX_FRAME_TYPE:
|
||
|
- /* check if we have the complete frame */
|
||
|
- if (avail < flxfh.size)
|
||
|
- goto need_more_data;
|
||
|
-
|
||
|
- /* flush header */
|
||
|
- gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize);
|
||
|
-
|
||
|
- chunk = gst_adapter_take (flxdec->adapter,
|
||
|
- flxfh.size - FlxFrameChunkSize);
|
||
|
- FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk);
|
||
|
- if (((FlxFrameType *) chunk)->chunks == 0)
|
||
|
- break;
|
||
|
+ while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
|
||
|
+ guint32 size;
|
||
|
+ guint16 type;
|
||
|
|
||
|
- /* create 32 bits output frame */
|
||
|
-// res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
|
||
|
-// GST_BUFFER_OFFSET_NONE,
|
||
|
-// flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
|
||
|
-// if (res != GST_FLOW_OK)
|
||
|
-// break;
|
||
|
+ if (!gst_byte_reader_get_uint32_le (&reader, &size))
|
||
|
+ goto parse_error;
|
||
|
+ if (available < size)
|
||
|
+ goto need_more_data;
|
||
|
|
||
|
- out = gst_buffer_new_and_alloc (flxdec->size * 4);
|
||
|
+ available -= size;
|
||
|
+ gst_adapter_flush (flxdec->adapter, size);
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint16_le (&reader, &type))
|
||
|
+ goto parse_error;
|
||
|
+
|
||
|
+ switch (type) {
|
||
|
+ case FLX_FRAME_TYPE:{
|
||
|
+ GstByteReader chunks;
|
||
|
+ GstByteWriter writer;
|
||
|
+ guint16 n_chunks;
|
||
|
+ GstMapInfo map;
|
||
|
+
|
||
|
+ GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
|
||
|
+ size);
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
|
||
|
+ size - FlxFrameChunkSize))
|
||
|
+ goto parse_error;
|
||
|
+
|
||
|
+ if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
|
||
|
+ goto parse_error;
|
||
|
+ GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
|
||
|
+
|
||
|
+ if (n_chunks == 0)
|
||
|
+ break;
|
||
|
+ if (!gst_byte_reader_skip (&chunks, 8)) /* reserved */
|
||
|
+ goto parse_error;
|
||
|
+
|
||
|
+ gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
|
||
|
+ flxdec->size, TRUE);
|
||
|
|
||
|
/* decode chunks */
|
||
|
- if (!flx_decode_chunks (flxdec,
|
||
|
- ((FlxFrameType *) chunk)->chunks,
|
||
|
- chunk + FlxFrameTypeSize, flxdec->frame_data)) {
|
||
|
+ if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
|
||
|
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
("%s", "Could not decode chunk"), NULL);
|
||
|
- return GST_FLOW_ERROR;
|
||
|
+ goto unmap_input_error;
|
||
|
}
|
||
|
+ gst_byte_writer_reset (&writer);
|
||
|
|
||
|
/* save copy of the current frame for possible delta. */
|
||
|
memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
|
||
|
|
||
|
- gst_buffer_map (out, &map, GST_MAP_WRITE);
|
||
|
+ out = gst_buffer_new_and_alloc (flxdec->size * 4);
|
||
|
+ if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Could not map output buffer"), NULL);
|
||
|
+ gst_buffer_unref (out);
|
||
|
+ goto unmap_input_error;
|
||
|
+ }
|
||
|
+
|
||
|
/* convert current frame. */
|
||
|
flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
|
||
|
map.data);
|
||
|
@@ -655,30 +891,32 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||
|
|
||
|
res = gst_pad_push (flxdec->srcpad, out);
|
||
|
break;
|
||
|
+ }
|
||
|
default:
|
||
|
- /* check if we have the complete frame */
|
||
|
- if (avail < flxfh.size)
|
||
|
- goto need_more_data;
|
||
|
-
|
||
|
- gst_adapter_flush (flxdec->adapter, flxfh.size);
|
||
|
+ GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
|
||
|
+ type, size);
|
||
|
+ if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
|
||
|
+ goto parse_error;
|
||
|
break;
|
||
|
}
|
||
|
-
|
||
|
- g_free (chunk);
|
||
|
-
|
||
|
- avail = gst_adapter_available (flxdec->adapter);
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ gst_buffer_unmap (input, &map_info);
|
||
|
+ gst_buffer_unref (input);
|
||
|
+
|
||
|
need_more_data:
|
||
|
return res;
|
||
|
|
||
|
/* ERRORS */
|
||
|
-wrong_type:
|
||
|
- {
|
||
|
- GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
|
||
|
- ("not a flx file (type %x)", flxh->type));
|
||
|
- return GST_FLOW_ERROR;
|
||
|
- }
|
||
|
+parse_error:
|
||
|
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
|
||
|
+ ("%s", "Failed to parse stream"), (NULL));
|
||
|
+unmap_input_error:
|
||
|
+ gst_buffer_unmap (input, &map_info);
|
||
|
+ gst_buffer_unref (input);
|
||
|
+error:
|
||
|
+ return GST_FLOW_ERROR;
|
||
|
}
|
||
|
|
||
|
static GstStateChangeReturn
|
||
|
diff --git a/gst/flx/gstflxdec.h b/gst/flx/gstflxdec.h
|
||
|
index 3f9a0aa..4fd8dfd 100644
|
||
|
--- a/gst/flx/gstflxdec.h
|
||
|
+++ b/gst/flx/gstflxdec.h
|
||
|
@@ -23,6 +23,8 @@
|
||
|
#include <gst/gst.h>
|
||
|
|
||
|
#include <gst/base/gstadapter.h>
|
||
|
+#include <gst/base/gstbytereader.h>
|
||
|
+#include <gst/base/gstbytewriter.h>
|
||
|
#include "flx_color.h"
|
||
|
|
||
|
G_BEGIN_DECLS
|
||
|
@@ -45,7 +47,7 @@ struct _GstFlxDec {
|
||
|
|
||
|
guint8 *delta_data, *frame_data;
|
||
|
GstAdapter *adapter;
|
||
|
- gulong size;
|
||
|
+ gsize size;
|
||
|
GstFlxDecState state;
|
||
|
gint64 frame_time;
|
||
|
gint64 next_time;
|
||
|
--
|
||
|
2.10.2
|
||
|
|