2003-11-21 21:34:27 +00:00
|
|
|
/* GStreamer EBML I/O
|
|
|
|
* (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
|
|
|
*
|
|
|
|
* ebml-read.c: read EBML data from file/stream
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "ebml-read.h"
|
|
|
|
#include "ebml-ids.h"
|
|
|
|
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
GST_DEBUG_CATEGORY_STATIC (ebmlread_debug);
|
|
|
|
#define GST_CAT_DEFAULT ebmlread_debug
|
|
|
|
|
2004-03-14 22:34:33 +00:00
|
|
|
static void gst_ebml_read_class_init (GstEbmlReadClass * klass);
|
|
|
|
static void gst_ebml_read_init (GstEbmlRead * ebml);
|
2005-09-02 15:44:50 +00:00
|
|
|
static GstStateChangeReturn gst_ebml_read_change_state (GstElement * element,
|
|
|
|
GstStateChange transition);
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
/* convenience functions */
|
|
|
|
static gboolean gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size,
|
|
|
|
GstBuffer ** p_buf);
|
|
|
|
static gboolean gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size,
|
|
|
|
GstBuffer ** p_buf);
|
|
|
|
|
|
|
|
|
|
|
|
static GstElementClass *parent_class; /* NULL */
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
GType
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_get_type (void)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
static GType gst_ebml_read_type; /* 0 */
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
if (!gst_ebml_read_type) {
|
|
|
|
static const GTypeInfo gst_ebml_read_info = {
|
2004-03-14 22:34:33 +00:00
|
|
|
sizeof (GstEbmlReadClass),
|
2003-11-21 21:34:27 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
(GClassInitFunc) gst_ebml_read_class_init,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
sizeof (GstEbmlRead),
|
|
|
|
0,
|
|
|
|
(GInstanceInitFunc) gst_ebml_read_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
gst_ebml_read_type =
|
2004-03-15 19:32:27 +00:00
|
|
|
g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlRead",
|
|
|
|
&gst_ebml_read_info, 0);
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return gst_ebml_read_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_class_init (GstEbmlReadClass * klass)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
2003-11-21 21:34:27 +00:00
|
|
|
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
|
|
|
|
0, "EBML stream helper class");
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
gstelement_class->change_state =
|
|
|
|
GST_DEBUG_FUNCPTR (gst_ebml_read_change_state);
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_init (GstEbmlRead * ebml)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
ebml->sinkpad = NULL;
|
|
|
|
ebml->level = NULL;
|
|
|
|
}
|
|
|
|
|
2005-09-02 15:44:50 +00:00
|
|
|
static GstStateChangeReturn
|
|
|
|
gst_ebml_read_change_state (GstElement * element, GstStateChange transition)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
GstStateChangeReturn ret;
|
2003-11-21 21:34:27 +00:00
|
|
|
GstEbmlRead *ebml = GST_EBML_READ (element);
|
|
|
|
|
2005-09-02 15:44:50 +00:00
|
|
|
switch (transition) {
|
|
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!ebml->sinkpad) {
|
|
|
|
g_return_val_if_reached (GST_STATE_CHANGE_FAILURE);
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
ext/dvdread/dvdreadsrc.c: Fix. Don't do one big huge loop around the whole DVD, that will cache all data and thus eat...
Original commit message from CVS:
* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
(dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property),
(dvdreadsrc_get_property), (_open), (_seek), (_read),
(dvdreadsrc_get), (dvdreadsrc_open_file),
(dvdreadsrc_change_state):
Fix. Don't do one big huge loop around the whole DVD, that will
cache all data and thus eat sizeof(dvd) (several GB) before we
see something.
* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
Actually NULL'ify event after using it.
* gst/matroska/ebml-read.c: (gst_ebml_read_use_event),
(gst_ebml_read_handle_event), (gst_ebml_read_element_id),
(gst_ebml_read_element_length), (gst_ebml_read_element_data),
(gst_ebml_read_seek), (gst_ebml_read_skip):
Handle events.
* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init),
(gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream),
(gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init):
Fix timing (this will probably break if I seek using menus, but
I didn't get there yet). VOBs and normal DVDs should now work.
Add a mpeg2-only pad with high rank so this get autoplugged for
MPEG-2 movies.
* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init),
(gst_mpeg_demux_class_init), (gst_mpeg_demux_init),
(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream),
(gst_mpeg_demux_get_audio_stream),
(gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet),
(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init):
Use this as second rank for MPEG-1 and MPEG-2. Still use this for
MPEG-1 but use dvddemux for MPEG-2.
* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
(gst_mpeg_parse_init), (gst_mpeg_parse_new_pad),
(gst_mpeg_parse_parse_packhead):
Timing. Only add pad template if it exists. Add sink template from
class and not from ourselves. This means we will always use the
correct sink template even if it is not the one defined in this
file.
2004-10-01 08:42:56 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
switch (transition) {
|
|
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
ebml->offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
ext/dvdread/dvdreadsrc.c: Fix. Don't do one big huge loop around the whole DVD, that will cache all data and thus eat...
Original commit message from CVS:
* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
(dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property),
(dvdreadsrc_get_property), (_open), (_seek), (_read),
(dvdreadsrc_get), (dvdreadsrc_open_file),
(dvdreadsrc_change_state):
Fix. Don't do one big huge loop around the whole DVD, that will
cache all data and thus eat sizeof(dvd) (several GB) before we
see something.
* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
Actually NULL'ify event after using it.
* gst/matroska/ebml-read.c: (gst_ebml_read_use_event),
(gst_ebml_read_handle_event), (gst_ebml_read_element_id),
(gst_ebml_read_element_length), (gst_ebml_read_element_data),
(gst_ebml_read_seek), (gst_ebml_read_skip):
Handle events.
* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init),
(gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream),
(gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init):
Fix timing (this will probably break if I seek using menus, but
I didn't get there yet). VOBs and normal DVDs should now work.
Add a mpeg2-only pad with high rank so this get autoplugged for
MPEG-2 movies.
* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init),
(gst_mpeg_demux_class_init), (gst_mpeg_demux_init),
(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream),
(gst_mpeg_demux_get_audio_stream),
(gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet),
(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init):
Use this as second rank for MPEG-1 and MPEG-2. Still use this for
MPEG-1 but use dvddemux for MPEG-2.
* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
(gst_mpeg_parse_init), (gst_mpeg_parse_new_pad),
(gst_mpeg_parse_parse_packhead):
Timing. Only add pad template if it exists. Add sink template from
class and not from ourselves. This means we will always use the
correct sink template even if it is not the one defined in this
file.
2004-10-01 08:42:56 +00:00
|
|
|
default:
|
2005-10-18 18:12:31 +00:00
|
|
|
break;
|
ext/dvdread/dvdreadsrc.c: Fix. Don't do one big huge loop around the whole DVD, that will cache all data and thus eat...
Original commit message from CVS:
* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
(dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property),
(dvdreadsrc_get_property), (_open), (_seek), (_read),
(dvdreadsrc_get), (dvdreadsrc_open_file),
(dvdreadsrc_change_state):
Fix. Don't do one big huge loop around the whole DVD, that will
cache all data and thus eat sizeof(dvd) (several GB) before we
see something.
* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
Actually NULL'ify event after using it.
* gst/matroska/ebml-read.c: (gst_ebml_read_use_event),
(gst_ebml_read_handle_event), (gst_ebml_read_element_id),
(gst_ebml_read_element_length), (gst_ebml_read_element_data),
(gst_ebml_read_seek), (gst_ebml_read_skip):
Handle events.
* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init),
(gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream),
(gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init):
Fix timing (this will probably break if I seek using menus, but
I didn't get there yet). VOBs and normal DVDs should now work.
Add a mpeg2-only pad with high rank so this get autoplugged for
MPEG-2 movies.
* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init),
(gst_mpeg_demux_class_init), (gst_mpeg_demux_init),
(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream),
(gst_mpeg_demux_get_audio_stream),
(gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet),
(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init):
Use this as second rank for MPEG-1 and MPEG-2. Still use this for
MPEG-1 but use dvddemux for MPEG-2.
* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
(gst_mpeg_parse_init), (gst_mpeg_parse_new_pad),
(gst_mpeg_parse_parse_packhead):
Timing. Only add pad template if it exists. Add sink template from
class and not from ourselves. This means we will always use the
correct sink template even if it is not the one defined in this
file.
2004-10-01 08:42:56 +00:00
|
|
|
}
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
return ret;
|
ext/dvdread/dvdreadsrc.c: Fix. Don't do one big huge loop around the whole DVD, that will cache all data and thus eat...
Original commit message from CVS:
* ext/dvdread/dvdreadsrc.c: (dvdreadsrc_class_init),
(dvdreadsrc_init), (dvdreadsrc_dispose), (dvdreadsrc_set_property),
(dvdreadsrc_get_property), (_open), (_seek), (_read),
(dvdreadsrc_get), (dvdreadsrc_open_file),
(dvdreadsrc_change_state):
Fix. Don't do one big huge loop around the whole DVD, that will
cache all data and thus eat sizeof(dvd) (several GB) before we
see something.
* gst-libs/gst/riff/riff-read.c: (gst_riff_read_seek):
Actually NULL'ify event after using it.
* gst/matroska/ebml-read.c: (gst_ebml_read_use_event),
(gst_ebml_read_handle_event), (gst_ebml_read_element_id),
(gst_ebml_read_element_length), (gst_ebml_read_element_data),
(gst_ebml_read_seek), (gst_ebml_read_skip):
Handle events.
* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_base_init),
(gst_dvd_demux_init), (gst_dvd_demux_get_audio_stream),
(gst_dvd_demux_get_subpicture_stream), (gst_dvd_demux_plugin_init):
Fix timing (this will probably break if I seek using menus, but
I didn't get there yet). VOBs and normal DVDs should now work.
Add a mpeg2-only pad with high rank so this get autoplugged for
MPEG-2 movies.
* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_base_init),
(gst_mpeg_demux_class_init), (gst_mpeg_demux_init),
(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_get_video_stream),
(gst_mpeg_demux_get_audio_stream),
(gst_mpeg_demux_get_private_stream), (gst_mpeg_demux_parse_packet),
(gst_mpeg_demux_parse_pes), (gst_mpeg_demux_plugin_init):
Use this as second rank for MPEG-1 and MPEG-2. Still use this for
MPEG-1 but use dvddemux for MPEG-2.
* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_class_init),
(gst_mpeg_parse_init), (gst_mpeg_parse_new_pad),
(gst_mpeg_parse_parse_packhead):
Timing. Only add pad template if it exists. Add sink template from
class and not from ourselves. This means we will always use the
correct sink template even if it is not the one defined in this
file.
2004-10-01 08:42:56 +00:00
|
|
|
}
|
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
/*
|
|
|
|
* Return: the amount of levels in the hierarchy that the
|
|
|
|
* current element lies higher than the previous one.
|
|
|
|
* The opposite isn't done - that's auto-done using master
|
|
|
|
* element reading.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static guint
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_element_level_up (GstEbmlRead * ebml)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
guint num = 0;
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 pos = ebml->offset;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
while (ebml->level != NULL) {
|
|
|
|
GList *last = g_list_last (ebml->level);
|
|
|
|
GstEbmlLevel *level = last->data;
|
|
|
|
|
|
|
|
if (pos >= level->start + level->length) {
|
|
|
|
ebml->level = g_list_remove (ebml->level, level);
|
|
|
|
g_free (level);
|
|
|
|
num++;
|
2005-10-18 18:12:31 +00:00
|
|
|
} else {
|
2003-11-21 21:34:27 +00:00
|
|
|
break;
|
2005-10-18 18:12:31 +00:00
|
|
|
}
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
/*
|
|
|
|
* Calls pull_range for (offset,size) without advancing our offset
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf)
|
|
|
|
{
|
|
|
|
GstFlowReturn ret;
|
|
|
|
|
|
|
|
/* Caching here actually makes much less difference than one would expect.
|
|
|
|
* We do it mainly to avoid pulling buffers of 1 byte all the time */
|
|
|
|
if (ebml->cached_buffer) {
|
|
|
|
guint64 cache_offset = GST_BUFFER_OFFSET (ebml->cached_buffer);
|
|
|
|
guint cache_size = GST_BUFFER_SIZE (ebml->cached_buffer);
|
|
|
|
|
|
|
|
if (cache_offset <= ebml->offset &&
|
|
|
|
(ebml->offset + size) < (cache_offset + cache_size)) {
|
|
|
|
*p_buf = gst_buffer_create_sub (ebml->cached_buffer,
|
|
|
|
ebml->offset - cache_offset, size);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
gst_buffer_unref (ebml->cached_buffer);
|
|
|
|
ebml->cached_buffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gst_pad_pull_range (ebml->sinkpad, ebml->offset, MAX (size, 64 * 1024),
|
|
|
|
&ebml->cached_buffer) == GST_FLOW_OK &&
|
|
|
|
GST_BUFFER_SIZE (ebml->cached_buffer) >= size) {
|
|
|
|
*p_buf = gst_buffer_create_sub (ebml->cached_buffer, 0, size);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = gst_pad_pull_range (ebml->sinkpad, ebml->offset, size, p_buf);
|
|
|
|
if (ret != GST_FLOW_OK) {
|
|
|
|
GST_DEBUG ("pull_range returned %d", ret);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GST_BUFFER_SIZE (*p_buf) < size) {
|
|
|
|
GST_WARNING_OBJECT (ebml, "Dropping short buffer at offset %"
|
|
|
|
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", ebml->offset,
|
|
|
|
size, GST_BUFFER_SIZE (*p_buf));
|
|
|
|
gst_buffer_unref (*p_buf);
|
|
|
|
*p_buf = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calls pull_range for (offset,size) and advances our offset by size
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf)
|
|
|
|
{
|
|
|
|
if (!gst_ebml_read_peek_bytes (ebml, size, p_buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
ebml->offset += size;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
/*
|
|
|
|
* Read: the element content data ID.
|
2005-10-18 18:12:31 +00:00
|
|
|
* Return: FALSE on error.
|
2003-11-21 21:34:27 +00:00
|
|
|
*/
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
static gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_element_id (GstEbmlRead * ebml, guint32 * id, guint * level_up)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
GstBuffer *buf;
|
2003-11-21 21:34:27 +00:00
|
|
|
gint len_mask = 0x80, read = 1, n = 1;
|
|
|
|
guint32 total;
|
2005-10-18 18:12:31 +00:00
|
|
|
guint8 b;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_read_peek_bytes (ebml, 1, &buf))
|
|
|
|
return FALSE;
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
b = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
total = (guint32) b;
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
while (read <= 4 && !(total & len_mask)) {
|
|
|
|
read++;
|
|
|
|
len_mask >>= 1;
|
|
|
|
}
|
|
|
|
if (read > 4) {
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 pos = ebml->offset;
|
2004-03-14 22:34:33 +00:00
|
|
|
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("Invalid EBML ID size tag (0x%x) at position %llu (0x%llx)",
|
2005-10-18 18:12:31 +00:00
|
|
|
(guint) b, pos, pos));
|
|
|
|
return FALSE;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_read_peek_bytes (ebml, read, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (n < read) {
|
|
|
|
b = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + n);
|
|
|
|
total = (total << 8) | b;
|
|
|
|
++n;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
*id = total;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
/* level */
|
|
|
|
if (level_up)
|
|
|
|
*level_up = gst_ebml_read_element_level_up (ebml);
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
gst_buffer_unref (buf);
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ebml->offset += read;
|
|
|
|
return TRUE;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read: element content length.
|
|
|
|
* Return: the number of bytes read or -1 on error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static gint
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_element_length (GstEbmlRead * ebml, guint64 * length)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
GstBuffer *buf;
|
2003-11-21 21:34:27 +00:00
|
|
|
gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
|
|
|
|
guint64 total;
|
2005-10-18 18:12:31 +00:00
|
|
|
guint8 b;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_peek_bytes (ebml, 1, &buf))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
b = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
total = (guint64) b;
|
2004-01-18 21:46:58 +00:00
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
while (read <= 8 && !(total & len_mask)) {
|
|
|
|
read++;
|
|
|
|
len_mask >>= 1;
|
|
|
|
}
|
|
|
|
if (read > 8) {
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 pos = ebml->offset;
|
2004-03-14 22:34:33 +00:00
|
|
|
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("Invalid EBML length size tag (0x%x) at position %llu (0x%llx)",
|
2005-10-18 18:12:31 +00:00
|
|
|
(guint) b, pos, pos));
|
2003-11-21 21:34:27 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((total &= (len_mask - 1)) == len_mask - 1)
|
|
|
|
num_ffs++;
|
2005-10-18 18:12:31 +00:00
|
|
|
|
|
|
|
if (!gst_ebml_read_peek_bytes (ebml, read, &buf))
|
|
|
|
return -1;
|
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
while (n < read) {
|
2005-10-18 18:12:31 +00:00
|
|
|
guint8 b = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + n);
|
|
|
|
|
|
|
|
if (b == 0xff)
|
2003-11-21 21:34:27 +00:00
|
|
|
num_ffs++;
|
2005-10-18 18:12:31 +00:00
|
|
|
total = (total << 8) | b;
|
|
|
|
++n;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
2005-10-18 18:12:31 +00:00
|
|
|
gst_buffer_unref (buf);
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
if (read == num_ffs)
|
|
|
|
*length = G_MAXUINT64;
|
|
|
|
else
|
|
|
|
*length = total;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ebml->offset += read;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
return read;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return: the ID of the next element.
|
|
|
|
* Level_up contains the amount of levels that this
|
|
|
|
* next element lies higher than the previous one.
|
|
|
|
*/
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
gboolean
|
|
|
|
gst_ebml_peek_id (GstEbmlRead * ebml, guint * level_up, guint32 * id)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 off;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
g_assert (level_up);
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
off = ebml->offset; /* save offset */
|
|
|
|
|
|
|
|
if (!gst_ebml_read_element_id (ebml, id, level_up))
|
|
|
|
return FALSE;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ebml->offset = off; /* restore offset */
|
|
|
|
return TRUE;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-18 18:12:31 +00:00
|
|
|
* Return the length of the stream in bytes
|
2003-11-21 21:34:27 +00:00
|
|
|
*/
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
gint64
|
|
|
|
gst_ebml_read_get_length (GstEbmlRead * ebml)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
GstFormat fmt = GST_FORMAT_BYTES;
|
2005-10-19 15:57:04 +00:00
|
|
|
gint64 end;
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
|
2005-10-19 15:57:04 +00:00
|
|
|
if (!gst_pad_query_duration (GST_PAD_PEER (ebml->sinkpad), &fmt, &end))
|
2005-10-18 18:12:31 +00:00
|
|
|
g_return_val_if_reached (0); ///// FIXME /////////
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (fmt != GST_FORMAT_BYTES || end < 0)
|
|
|
|
g_return_val_if_reached (0); ///// FIXME /////////
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
return end;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-18 18:12:31 +00:00
|
|
|
* Seek to a given offset.
|
2003-11-21 21:34:27 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2005-10-18 18:12:31 +00:00
|
|
|
gst_ebml_read_seek (GstEbmlRead * ebml, guint64 offset)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
if (offset >= gst_ebml_read_get_length (ebml))
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ebml->offset = offset;
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-18 18:12:31 +00:00
|
|
|
* Skip the next element.
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2005-10-18 18:12:31 +00:00
|
|
|
gst_ebml_read_skip (GstEbmlRead * ebml)
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
{
|
|
|
|
guint64 length;
|
|
|
|
guint32 id;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_read_element_id (ebml, &id, NULL))
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (gst_ebml_read_element_length (ebml, &length) < 0)
|
gst/matroska/: Disgustingly evil hack for working around INTERRUPT events and their extremely annoying habit of being...
Original commit message from CVS:
* gst/matroska/ebml-read.c: (gst_ebml_read_class_init),
(gst_ebml_read_init), (gst_ebml_read_use_event),
(gst_ebml_read_element_id), (gst_ebml_peek_id),
(gst_ebml_read_seek), (gst_ebml_read_skip),
(gst_ebml_read_reserve), (gst_ebml_read_buffer),
(gst_ebml_read_master):
* gst/matroska/ebml-read.h:
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_contents),
(gst_matroska_demux_loop_stream), (gst_matroska_demux_audio_caps):
Disgustingly evil hack for working around INTERRUPT events and
their extremely annoying habit of being a pain in the ass. We
simply peek a cluster before reading any of it.
2004-12-03 21:08:17 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
ebml->offset += length;
|
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS:
Riff, EBML, fourcc etc. work. Not fully finished, but better than
what we used to have and definately worth a first broad testing.
I've revived rifflib. Rifflib used to be a bytestream-for-riff, which
just dup'ed bytestream. I've rewritten rifflib to be a modern riff-
chunk parser that uses bytestream fully, plus adds some extra functions
so that riff file parsing becomes extremely easy. It also contains some
small usability functions for strh/strf and metadata parsing. Note that
it doesn't use the new tagging yet, that's a TODO.
Avidemux has been rewritten to use this. I think we all agreed that
avidemux was pretty much a big mess, which is because it used all
sort of bytestream magic all around the place. It was just ugly.
This is a lot nicer, very complete and safe. I think this is far more
robust than what the old avidemux could ever have been. Of course, it
might contain bugs, please let me know.
EBML writing has also been implemented. This is useful for matroska.
I'm intending to modify avidemux (with a riffwriter) similarly. Maybe
I'll change wavparse/-enc too to use rifflib.
Lastly, several plugins have been modified to use rifflib's fourcc
parsing instead of their own. this puts fourcc parsing in one central
place, which should make it a lot simpler to add new fourccs. We might
want to move this to its own lib instead of rifflib.
Enjoy!
2003-12-07 20:00:41 +00:00
|
|
|
return TRUE;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as a GstBuffer (binary).
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
guint64 length;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_read_element_id (ebml, id, NULL))
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
2005-01-19 19:31:54 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (gst_ebml_read_element_length (ebml, &length) < 0)
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
2005-01-19 19:31:54 +00:00
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
*buf = gst_buffer_new ();
|
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
*buf = NULL;
|
|
|
|
if (!gst_ebml_read_pull_bytes (ebml, (guint) length, buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as an unsigned int.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstBuffer *buf;
|
|
|
|
guint8 *data;
|
|
|
|
guint size;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_buffer (ebml, id, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
data = GST_BUFFER_DATA (buf);
|
|
|
|
size = GST_BUFFER_SIZE (buf);
|
|
|
|
if (size < 1 || size > 8) {
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("Invalid integer element size %d at position %llu (0x%llu)",
|
|
|
|
size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
|
2003-11-21 21:34:27 +00:00
|
|
|
gst_buffer_unref (buf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
*num = 0;
|
|
|
|
while (size > 0) {
|
|
|
|
*num = (*num << 8) | data[GST_BUFFER_SIZE (buf) - size];
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as a signed int.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstBuffer *buf;
|
|
|
|
guint8 *data;
|
2004-01-02 20:38:59 +00:00
|
|
|
guint size, negative = 0, n = 0;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
if (!gst_ebml_read_buffer (ebml, id, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
size = GST_BUFFER_SIZE (buf);
|
|
|
|
if (size < 1 || size > 8) {
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("Invalid integer element size %d at position %llu (0x%llx)",
|
|
|
|
size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
|
2003-11-21 21:34:27 +00:00
|
|
|
gst_buffer_unref (buf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2006-04-10 16:09:03 +00:00
|
|
|
|
|
|
|
buf = gst_buffer_make_writable (buf);
|
|
|
|
|
|
|
|
data = GST_BUFFER_DATA (buf);
|
|
|
|
|
2004-01-02 20:38:59 +00:00
|
|
|
if (data[0] & 0x80) {
|
|
|
|
negative = 1;
|
|
|
|
data[0] &= ~0x80;
|
|
|
|
}
|
2006-04-10 16:09:03 +00:00
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
*num = 0;
|
2004-01-02 20:38:59 +00:00
|
|
|
while (n < size) {
|
|
|
|
*num = (*num << 8) | data[n++];
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* make signed */
|
2004-01-02 20:38:59 +00:00
|
|
|
if (negative) {
|
2006-04-09 14:00:32 +00:00
|
|
|
*num = 0 - *num;
|
2004-01-02 20:38:59 +00:00
|
|
|
}
|
2003-11-21 21:34:27 +00:00
|
|
|
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as a float.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstBuffer *buf;
|
|
|
|
guint8 *data;
|
|
|
|
guint size;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_buffer (ebml, id, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
data = GST_BUFFER_DATA (buf);
|
|
|
|
size = GST_BUFFER_SIZE (buf);
|
|
|
|
|
|
|
|
if (size != 4 && size != 8 && size != 10) {
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("Invalid float element size %d at position %llu (0x%llx)",
|
|
|
|
size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
|
2003-11-21 21:34:27 +00:00
|
|
|
gst_buffer_unref (buf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 10) {
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, CORE, NOT_IMPLEMENTED, (NULL),
|
2004-03-15 19:32:27 +00:00
|
|
|
("FIXME! 10-byte floats unimplemented"));
|
2003-11-21 21:34:27 +00:00
|
|
|
gst_buffer_unref (buf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 4) {
|
|
|
|
gfloat f;
|
|
|
|
|
|
|
|
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
|
2004-03-14 22:34:33 +00:00
|
|
|
f = *(gfloat *) data;
|
2003-11-21 21:34:27 +00:00
|
|
|
#else
|
|
|
|
while (size > 0) {
|
2004-03-14 22:34:33 +00:00
|
|
|
((guint8 *) & f)[size - 1] = data[4 - size];
|
2003-11-21 21:34:27 +00:00
|
|
|
size--;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
*num = f;
|
|
|
|
} else {
|
|
|
|
gdouble d;
|
|
|
|
|
|
|
|
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
|
2004-03-14 22:34:33 +00:00
|
|
|
d = *(gdouble *) data;
|
2003-11-21 21:34:27 +00:00
|
|
|
#else
|
|
|
|
while (size > 0) {
|
2004-03-14 22:34:33 +00:00
|
|
|
((guint8 *) & d)[size - 1] = data[8 - size];
|
2003-11-21 21:34:27 +00:00
|
|
|
size--;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
*num = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as an ASCII string.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_ascii (GstEbmlRead * ebml, guint32 * id, gchar ** str)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstBuffer *buf;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_buffer (ebml, id, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*str = g_malloc (GST_BUFFER_SIZE (buf) + 1);
|
|
|
|
memcpy (*str, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
|
|
|
(*str)[GST_BUFFER_SIZE (buf)] = '\0';
|
|
|
|
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as a UTF-8 string.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2005-10-18 18:12:31 +00:00
|
|
|
gboolean ret;
|
2006-02-03 18:07:35 +00:00
|
|
|
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 oldoff = ebml->offset;
|
2006-02-03 18:07:35 +00:00
|
|
|
#endif
|
2005-10-18 18:12:31 +00:00
|
|
|
|
|
|
|
ret = gst_ebml_read_ascii (ebml, id, str);
|
|
|
|
|
|
|
|
if (str != NULL && *str != NULL && **str != '\0' &&
|
|
|
|
!g_utf8_validate (*str, -1, NULL)) {
|
|
|
|
GST_WARNING ("Invalid UTF-8 string at offset %" G_GUINT64_FORMAT, oldoff);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-09-01 12:10:21 +00:00
|
|
|
* Read the next element as a date.
|
|
|
|
* Returns the seconds since the unix epoch.
|
2003-11-21 21:34:27 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
2004-09-01 12:10:21 +00:00
|
|
|
gint64 ebml_date;
|
|
|
|
gboolean res = gst_ebml_read_sint (ebml, id, &ebml_date);
|
|
|
|
|
|
|
|
*date = (ebml_date / GST_SECOND) + GST_EBML_DATE_OFFSET;
|
|
|
|
return res;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element, but only the header. The contents
|
|
|
|
* are supposed to be sub-elements which can be read separately.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_master (GstEbmlRead * ebml, guint32 * id)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstEbmlLevel *level;
|
2005-10-18 18:12:31 +00:00
|
|
|
guint64 length;
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_read_element_id (ebml, id, NULL))
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (gst_ebml_read_element_length (ebml, &length) < 0)
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* remember level */
|
|
|
|
level = g_new (GstEbmlLevel, 1);
|
2005-10-18 18:12:31 +00:00
|
|
|
level->start = ebml->offset;
|
2003-11-21 21:34:27 +00:00
|
|
|
level->length = length;
|
|
|
|
ebml->level = g_list_append (ebml->level, level);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next element as binary data.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_binary (GstEbmlRead * ebml,
|
|
|
|
guint32 * id, guint8 ** binary, guint64 * length)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
GstBuffer *buf;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_buffer (ebml, id, &buf))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*length = GST_BUFFER_SIZE (buf);
|
|
|
|
*binary = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
|
|
|
|
|
|
|
gst_buffer_unref (buf);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read an EBML header.
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
2004-03-14 22:34:33 +00:00
|
|
|
gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
|
2003-11-21 21:34:27 +00:00
|
|
|
{
|
|
|
|
/* this function is the first to be called */
|
|
|
|
guint32 id;
|
|
|
|
guint level_up;
|
|
|
|
|
|
|
|
/* default init */
|
|
|
|
if (doctype)
|
|
|
|
*doctype = NULL;
|
|
|
|
if (version)
|
|
|
|
*version = 1;
|
|
|
|
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_peek_id (ebml, &level_up, &id))
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
2005-10-18 18:12:31 +00:00
|
|
|
|
|
|
|
GST_DEBUG_OBJECT (ebml, "id: %08x", GST_READ_UINT32_BE (&id));
|
|
|
|
|
2003-11-21 21:34:27 +00:00
|
|
|
if (level_up != 0 || id != GST_EBML_ID_HEADER) {
|
2004-02-02 17:23:33 +00:00
|
|
|
GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL));
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (!gst_ebml_read_master (ebml, &id))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (TRUE) {
|
2005-10-18 18:12:31 +00:00
|
|
|
if (!gst_ebml_peek_id (ebml, &level_up, &id))
|
2003-11-21 21:34:27 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* end-of-header */
|
|
|
|
if (level_up)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (id) {
|
2004-03-15 19:32:27 +00:00
|
|
|
/* is our read version uptodate? */
|
2004-03-14 22:34:33 +00:00
|
|
|
case GST_EBML_ID_EBMLREADVERSION:{
|
2004-03-15 19:32:27 +00:00
|
|
|
guint64 num;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_uint (ebml, &id, &num))
|
|
|
|
return FALSE;
|
|
|
|
g_assert (id == GST_EBML_ID_EBMLREADVERSION);
|
|
|
|
if (num != GST_EBML_VERSION)
|
|
|
|
return FALSE;
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-15 19:32:27 +00:00
|
|
|
/* we only handle 8 byte lengths at max */
|
2004-03-14 22:34:33 +00:00
|
|
|
case GST_EBML_ID_EBMLMAXSIZELENGTH:{
|
2004-03-15 19:32:27 +00:00
|
|
|
guint64 num;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_uint (ebml, &id, &num))
|
|
|
|
return FALSE;
|
|
|
|
g_assert (id == GST_EBML_ID_EBMLMAXSIZELENGTH);
|
|
|
|
if (num != sizeof (guint64))
|
|
|
|
return FALSE;
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-15 19:32:27 +00:00
|
|
|
/* we handle 4 byte IDs at max */
|
2004-03-14 22:34:33 +00:00
|
|
|
case GST_EBML_ID_EBMLMAXIDLENGTH:{
|
2004-03-15 19:32:27 +00:00
|
|
|
guint64 num;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_uint (ebml, &id, &num))
|
|
|
|
return FALSE;
|
|
|
|
g_assert (id == GST_EBML_ID_EBMLMAXIDLENGTH);
|
|
|
|
if (num != sizeof (guint32))
|
|
|
|
return FALSE;
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-14 22:34:33 +00:00
|
|
|
case GST_EBML_ID_DOCTYPE:{
|
2004-03-15 19:32:27 +00:00
|
|
|
gchar *text;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_ascii (ebml, &id, &text))
|
|
|
|
return FALSE;
|
|
|
|
g_assert (id == GST_EBML_ID_DOCTYPE);
|
|
|
|
if (doctype) {
|
|
|
|
if (doctype)
|
|
|
|
g_free (*doctype);
|
|
|
|
*doctype = text;
|
|
|
|
} else
|
|
|
|
g_free (text);
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-14 22:34:33 +00:00
|
|
|
case GST_EBML_ID_DOCTYPEREADVERSION:{
|
2004-03-15 19:32:27 +00:00
|
|
|
guint64 num;
|
|
|
|
|
|
|
|
if (!gst_ebml_read_uint (ebml, &id, &num))
|
|
|
|
return FALSE;
|
|
|
|
g_assert (id == GST_EBML_ID_DOCTYPEREADVERSION);
|
|
|
|
if (version)
|
|
|
|
*version = num;
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2004-03-15 19:32:27 +00:00
|
|
|
GST_WARNING ("Unknown data type 0x%x in EBML header (ignored)", id);
|
|
|
|
/* pass-through */
|
2003-11-21 21:34:27 +00:00
|
|
|
|
2004-03-15 19:32:27 +00:00
|
|
|
/* we ignore these two, as they don't tell us anything we care about */
|
2003-11-21 21:34:27 +00:00
|
|
|
case GST_EBML_ID_VOID:
|
|
|
|
case GST_EBML_ID_EBMLVERSION:
|
|
|
|
case GST_EBML_ID_DOCTYPEVERSION:
|
2004-03-15 19:32:27 +00:00
|
|
|
if (!gst_ebml_read_skip (ebml))
|
|
|
|
return FALSE;
|
|
|
|
break;
|
2003-11-21 21:34:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|