diff options
Diffstat (limited to 'gst/flx/gstflxdec.c')
-rw-r--r-- | gst/flx/gstflxdec.c | 610 |
1 files changed, 424 insertions, 186 deletions
diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c index a23797600..aa1bed502 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 |