gst/matroska/ebml-ids.h: Add ID for EBML CRC32 elements.

Original commit message from CVS:
* gst/matroska/ebml-ids.h:
Add ID for EBML CRC32 elements.
* gst/matroska/Makefile.am:
* gst/matroska/ebml-read.c: (gst_ebml_finalize),
(gst_ebml_read_class_init), (gst_ebml_read_peek_bytes),
(gst_ebml_read_get_length), (_ext2dbl), (gst_ebml_read_float),
(gst_ebml_read_header):
Support reading 80bit floats, add finalize method to clean up
in any case, support reading length/id elements with any length
as long as it's smaller than our supported maximum, don't leak
buffers if reading as much data as we wanted failed and some
smaller cleanup.
This commit is contained in:
Sebastian Dröge 2008-03-08 04:40:32 +00:00
parent c7296fe79a
commit 8342c0cc96
4 changed files with 100 additions and 25 deletions

View file

@ -1,3 +1,19 @@
2008-03-08 Sebastian Dröge <slomo@circular-chaos.org>
* gst/matroska/ebml-ids.h:
Add ID for EBML CRC32 elements.
* gst/matroska/Makefile.am:
* gst/matroska/ebml-read.c: (gst_ebml_finalize),
(gst_ebml_read_class_init), (gst_ebml_read_peek_bytes),
(gst_ebml_read_get_length), (_ext2dbl), (gst_ebml_read_float),
(gst_ebml_read_header):
Support reading 80bit floats, add finalize method to clean up
in any case, support reading length/id elements with any length
as long as it's smaller than our supported maximum, don't leak
buffers if reading as much data as we wanted failed and some
smaller cleanup.
2008-03-08 Sebastian Dröge <slomo@circular-chaos.org> 2008-03-08 Sebastian Dröge <slomo@circular-chaos.org>
Patch by: Olivier Crete <tester at tester dot ca> Patch by: Olivier Crete <tester at tester dot ca>

View file

@ -26,5 +26,6 @@ libgstmatroska_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \
$(GST_LIBS) \ $(GST_LIBS) \
-lgstriff-@GST_MAJORMINOR@ \ -lgstriff-@GST_MAJORMINOR@ \
$(ZLIB_LIBS) $(ZLIB_LIBS) \
$(LIBM)
libgstmatroska_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstmatroska_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -44,6 +44,7 @@ G_BEGIN_DECLS
/* general EBML types */ /* general EBML types */
#define GST_EBML_ID_VOID 0xEC #define GST_EBML_ID_VOID 0xEC
#define GST_EBML_ID_CRC32 0xBF
/* EbmlDate offset from the unix epoch in seconds, 2001/01/01 00:00:00 UTC */ /* EbmlDate offset from the unix epoch in seconds, 2001/01/01 00:00:00 UTC */
#define GST_EBML_DATE_OFFSET 978307200 #define GST_EBML_DATE_OFFSET 978307200

View file

@ -28,6 +28,8 @@
#include "ebml-read.h" #include "ebml-read.h"
#include "ebml-ids.h" #include "ebml-ids.h"
#include <math.h>
GST_DEBUG_CATEGORY_STATIC (ebmlread_debug); GST_DEBUG_CATEGORY_STATIC (ebmlread_debug);
#define GST_CAT_DEFAULT ebmlread_debug #define GST_CAT_DEFAULT ebmlread_debug
@ -71,16 +73,35 @@ gst_ebml_read_get_type (void)
return gst_ebml_read_type; return gst_ebml_read_type;
} }
static void
gst_ebml_finalize (GObject * obj)
{
GstEbmlRead *ebml = GST_EBML_READ (obj);
g_list_foreach (ebml->level, (GFunc) g_free, NULL);
g_list_free (ebml->level);
ebml->level = NULL;
if (ebml->cached_buffer) {
gst_buffer_unref (ebml->cached_buffer);
ebml->cached_buffer = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void static void
gst_ebml_read_class_init (GstEbmlReadClass * klass) gst_ebml_read_class_init (GstEbmlReadClass * klass)
{ {
GstElementClass *gstelement_class = (GstElementClass *) klass; GstElementClass *gstelement_class = (GstElementClass *) klass;
GObjectClass *gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread", GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
0, "EBML stream helper class"); 0, "EBML stream helper class");
gobject_class->finalize = gst_ebml_finalize;
gstelement_class->change_state = gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_ebml_read_change_state); GST_DEBUG_FUNCPTR (gst_ebml_read_change_state);
} }
@ -205,27 +226,39 @@ gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf,
return GST_FLOW_OK; return GST_FLOW_OK;
} }
/* FIXME, seems silly to require this */ /* Not possible to get enough data, try a last time with
if (!p_buf) * requesting exactly the size we need */
return GST_FLOW_ERROR; gst_buffer_unref (ebml->cached_buffer);
ebml->cached_buffer = NULL;
ret = gst_pad_pull_range (ebml->sinkpad, ebml->offset, size, p_buf); ret =
gst_pad_pull_range (ebml->sinkpad, ebml->offset, size,
&ebml->cached_buffer);
if (ret != GST_FLOW_OK) { if (ret != GST_FLOW_OK) {
GST_DEBUG ("pull_range returned %d", ret); GST_DEBUG ("pull_range returned %d", ret);
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return ret; return ret;
} }
if (GST_BUFFER_SIZE (*p_buf) < size) { if (GST_BUFFER_SIZE (ebml->cached_buffer) < size) {
GST_WARNING_OBJECT (ebml, "Dropping short buffer at offset %" GST_WARNING_OBJECT (ebml, "Dropping short buffer at offset %"
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", ebml->offset, G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", ebml->offset,
size, GST_BUFFER_SIZE (*p_buf)); size, GST_BUFFER_SIZE (ebml->cached_buffer));
gst_buffer_unref (*p_buf);
*p_buf = NULL; gst_buffer_unref (ebml->cached_buffer);
ebml->cached_buffer = NULL;
if (p_buf)
*p_buf = NULL;
if (bytes) if (bytes)
*bytes = NULL; *bytes = NULL;
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
if (p_buf)
*p_buf = gst_buffer_create_sub (ebml->cached_buffer, 0, size);
if (bytes) if (bytes)
*bytes = GST_BUFFER_DATA (*p_buf); *bytes = GST_BUFFER_DATA (*p_buf);
@ -402,11 +435,10 @@ gst_ebml_read_get_length (GstEbmlRead * ebml)
GstFormat fmt = GST_FORMAT_BYTES; GstFormat fmt = GST_FORMAT_BYTES;
gint64 end; gint64 end;
if (!gst_pad_query_duration (GST_PAD_PEER (ebml->sinkpad), &fmt, &end)) /* FIXME: what to do if we don't get the upstream length */
g_return_val_if_reached (0); ///// FIXME ///////// if (!gst_pad_query_peer_duration (ebml->sinkpad, &fmt, &end) ||
fmt != GST_FORMAT_BYTES || end < 0)
if (fmt != GST_FORMAT_BYTES || end < 0) g_return_val_if_reached (0);
g_return_val_if_reached (0); ///// FIXME /////////
return end; return end;
} }
@ -592,6 +624,36 @@ gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
return ret; return ret;
} }
/* Convert 80 bit extended precision float in big endian format to double.
* Code taken from libavutil/intfloat_readwrite.c from ffmpeg,
* licensed under LGPL */
struct _ext_float
{
guint8 exponent[2];
guint8 mantissa[8];
};
static gdouble
_ext2dbl (guint8 * data)
{
struct _ext_float *ext = (struct _ext_float *) data;
guint64 m = 0;
gint e, i;
for (i = 0; i < 8; i++)
m = (m << 8) + ext->mantissa[i];
e = (((gint) ext->exponent[0] & 0x7f) << 8) | ext->exponent[1];
if (e == 0x7fff && m)
return 0.0 / 0.0;
e -= 16383 + 63; /* In IEEE 80 bits, the whole (i.e. 1.xxxx)
* mantissa bit is written as opposed to the
* single and double precision formats */
if (ext->exponent[0] & 0x80)
m = -m;
return ldexp (m, e);
}
/* /*
* Read the next element as a float. * Read the next element as a float.
*/ */
@ -615,12 +677,6 @@ gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
if (size == 10) {
GST_ELEMENT_ERROR (ebml, CORE, NOT_IMPLEMENTED, (NULL),
("FIXME! 10-byte floats unimplemented"));
return GST_FLOW_NOT_SUPPORTED;
}
if (size == 4) { if (size == 4) {
gfloat f; gfloat f;
@ -634,7 +690,7 @@ gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
#endif #endif
*num = f; *num = f;
} else { } else if (size == 8) {
gdouble d; gdouble d;
#if (G_BYTE_ORDER == G_BIG_ENDIAN) #if (G_BYTE_ORDER == G_BIG_ENDIAN)
@ -647,6 +703,8 @@ gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
#endif #endif
*num = d; *num = d;
} else {
*num = _ext2dbl (data);
} }
return ret; return ret;
@ -835,7 +893,7 @@ gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
return ret; return ret;
g_assert (id == GST_EBML_ID_EBMLMAXSIZELENGTH); g_assert (id == GST_EBML_ID_EBMLMAXSIZELENGTH);
if (num != sizeof (guint64)) { if (num > sizeof (guint64)) {
GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL)); GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL));
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -850,7 +908,7 @@ gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
return ret; return ret;
g_assert (id == GST_EBML_ID_EBMLMAXIDLENGTH); g_assert (id == GST_EBML_ID_EBMLMAXIDLENGTH);
if (num != sizeof (guint32)) { if (num > sizeof (guint32)) {
GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL)); GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL));
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -865,8 +923,7 @@ gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
return ret; return ret;
g_assert (id == GST_EBML_ID_DOCTYPE); g_assert (id == GST_EBML_ID_DOCTYPE);
if (doctype) { if (doctype) {
if (doctype) g_free (*doctype);
g_free (*doctype);
*doctype = text; *doctype = text;
} else } else
g_free (text); g_free (text);