diff options
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | gst/matroska/ebml-write.c | 12 | ||||
-rw-r--r-- | gst/matroska/matroska-demux.c | 644 | ||||
-rw-r--r-- | gst/matroska/matroska-demux.h | 4 | ||||
-rw-r--r-- | gst/matroska/matroska-ids.c | 22 | ||||
-rw-r--r-- | gst/matroska/matroska-ids.h | 489 | ||||
-rw-r--r-- | gst/matroska/matroska-mux.c | 159 |
7 files changed, 1043 insertions, 333 deletions
@@ -1,5 +1,51 @@ 2008-06-10 Sebastian Dröge <slomo@circular-chaos.org> + * gst/matroska/ebml-write.c: (gst_ebml_write_float): + Use GDOUBLE_TO_BE() instead of (probably slower) custom code. + + * gst/matroska/matroska-demux.c: (gst_matroska_demux_base_init), + (gst_matroska_demux_class_init), (gst_matroska_demux_init), + (gst_matroska_track_free), (gst_matroska_demux_encoding_cmp), + (gst_matroska_demux_read_track_encodings), + (gst_matroska_demux_add_stream), + (gst_matroska_demux_handle_src_query), + (gst_matroska_demux_init_stream), + (gst_matroska_demux_parse_index_cuetrack), + (gst_matroska_demux_parse_index_pointentry), + (gst_matroska_demux_parse_info), + (gst_matroska_demux_parse_metadata_id_simple_tag), + (gst_matroska_demux_parse_metadata), + (gst_matroska_demux_add_wvpk_header), (gst_matroska_decode_buffer), + (gst_matroska_demux_parse_blockgroup_or_simpleblock), + (gst_matroska_demux_parse_cluster), + (gst_matroska_demux_parse_contents_seekentry), + (gst_matroska_demux_loop_stream_parse_id), + (gst_matroska_demux_loop), (gst_matroska_demux_video_caps), + (gst_matroska_demux_audio_caps), + (gst_matroska_demux_subtitle_caps): + * gst/matroska/matroska-demux.h: + * gst/matroska/matroska-ids.c: + (gst_matroska_track_init_subtitle_context): + * gst/matroska/matroska-ids.h: + * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init), + (gst_matroska_mux_class_init), (gst_matroska_mux_init), + (gst_matroska_mux_create_uid), (gst_matroska_mux_reset), + (gst_matroska_mux_video_pad_setcaps), + (gst_matroska_mux_audio_pad_setcaps), + (gst_matroska_mux_subtitle_pad_setcaps), + (gst_matroska_mux_request_new_pad), + (gst_matroska_mux_track_header), (gst_matroska_mux_start), + (gst_matroska_mux_write_simple_tag), (gst_matroska_mux_finish), + (gst_matroska_mux_write_data), (gst_matroska_mux_collected), + (gst_matroska_mux_set_property): + Add many FIXMEs/TODOs all over the matroska muxer and demuxer + elements, do some checks for valid values in the demuxer, handle + tracktimecodescale in the demuxer, set correct default values for all + settings in the demuxer, review and add all missing matroska + IDs and some more raw YUV formats, and some trivial cleanup. + +2008-06-10 Sebastian Dröge <slomo@circular-chaos.org> + * ext/pulse/pulsemixer.c: (gst_pulsemixer_base_init), (gst_pulsemixer_class_init): * ext/pulse/pulsesink.c: (gst_pulsesink_base_init), diff --git a/gst/matroska/ebml-write.c b/gst/matroska/ebml-write.c index 7bc5a75d..e2a6a2f7 100644 --- a/gst/matroska/ebml-write.c +++ b/gst/matroska/ebml-write.c @@ -25,6 +25,7 @@ #endif #include <string.h> +#include <gst/floatcast/floatcast.h> #include "ebml-write.h" #include "ebml-ids.h" @@ -541,21 +542,12 @@ gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num) void gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num) { -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) - gint n; -#endif GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num)); gst_ebml_write_element_id (buf, id); gst_ebml_write_element_size (buf, 8); -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) - for (n = 0; n < 8; n++) { - GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)] = ((guint8 *) & num)[7 - n]; - GST_BUFFER_SIZE (buf) += 1; - } -#else + num = GDOUBLE_TO_BE (num); gst_ebml_write_element_data (buf, (guint8 *) & num, 8); -#endif gst_ebml_write_element_push (ebml, buf); } diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 85bfcafe..7b4933cf 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -20,6 +20,24 @@ * Boston, MA 02111-1307, USA. */ +/* TODO: "Unkown track header" & "Unknown entry": implement if useful + * TODO: dynamic number of tracks without upper bound + * FIXME: uint64 -> int64 overflows! + * FIXME: ignore 0xBF aka. CRC32 elements without warning + * TODO: check CRC32 if present + * FIXME: go out of loops, don't add Track or whatever if something goes wrong + * or required elements are not there + * TODO: there can be a segment after the first segment. Handle like + * chained oggs. Fixes #334082 + * TODO: handle gaps better, especially gaps at the start of a track. + * Needs sending of filler segments, closing of segments and + * other magic... Fixes #429322 + * TODO: Test samples: http://www.matroska.org/samples/matrix/index.html + * http://samples.mplayerhq.hu/Matroska/ + * TODO: check if demuxing is done correct for all codecs according to spec + * TODO: seeking with incomplete or without CUE + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -27,8 +45,8 @@ #include <math.h> #include <string.h> -/* For AVI compatibility mode... Who did that? */ -/* and for fourcc stuff */ +/* For AVI compatibility mode + and for fourcc stuff */ #include <gst/riff/riff-read.h> #include <gst/riff/riff-ids.h> #include <gst/riff/riff-media.h> @@ -56,6 +74,8 @@ static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("video/x-matroska") ); +/* TODO: fill in caps! */ + static GstStaticPadTemplate audio_src_templ = GST_STATIC_PAD_TEMPLATE ("audio_%02d", GST_PAD_SRC, @@ -79,10 +99,6 @@ static GstStaticPadTemplate subtitle_src_templ = "application/x-subtitle-unknown") ); -static void gst_matroska_demux_base_init (GstMatroskaDemuxClass * klass); -static void gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass); -static void gst_matroska_demux_init (GstMatroskaDemux * demux); - /* element functions */ static void gst_matroska_demux_loop (GstPad * pad); @@ -93,6 +109,7 @@ static gboolean gst_matroska_demux_element_send_event (GstElement * element, static gboolean gst_matroska_demux_sink_activate_pull (GstPad * sinkpad, gboolean active); static gboolean gst_matroska_demux_sink_activate (GstPad * sinkpad); + static gboolean gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GstEvent * event); static gboolean gst_matroska_demux_handle_src_event (GstPad * pad, @@ -113,8 +130,6 @@ static GstCaps *gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext static GstCaps *gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * audiocontext, const gchar * codec_id, gpointer data, guint size, gchar ** codec_name); -static GstCaps *gst_matroska_demux_complex_caps (GstMatroskaTrackComplexContext - * complexcontext, const gchar * codec_id, gpointer data, guint size); static GstCaps * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext * subtitlecontext, const gchar * codec_id, gpointer data, guint size); @@ -122,43 +137,13 @@ static GstCaps /* stream methods */ static void gst_matroska_demux_reset (GstElement * element); -static GstEbmlReadClass *parent_class; /* NULL; */ - -static GType -gst_matroska_demux_get_type (void) -{ - static GType gst_matroska_demux_type; /* 0 */ - - if (!gst_matroska_demux_type) { - static const GTypeInfo gst_matroska_demux_info = { - sizeof (GstMatroskaDemuxClass), - (GBaseInitFunc) gst_matroska_demux_base_init, - NULL, - (GClassInitFunc) gst_matroska_demux_class_init, - NULL, - NULL, - sizeof (GstMatroskaDemux), - 0, - (GInstanceInitFunc) gst_matroska_demux_init, - }; - - gst_matroska_demux_type = - g_type_register_static (GST_TYPE_EBML_READ, - "GstMatroskaDemux", &gst_matroska_demux_info, 0); - } - - return gst_matroska_demux_type; -} +GST_BOILERPLATE (GstMatroskaDemux, gst_matroska_demux, GstEbmlRead, + GST_TYPE_EBML_READ); static void -gst_matroska_demux_base_init (GstMatroskaDemuxClass * klass) +gst_matroska_demux_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - static const GstElementDetails gst_matroska_demux_details = - GST_ELEMENT_DETAILS ("Matroska demuxer", - "Codec/Demuxer", - "Demuxes a Matroska Stream into video/audio/subtitles", - "Ronald Bultje <rbultje@ronald.bitfreak.net>"); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&video_src_templ)); @@ -168,20 +153,20 @@ gst_matroska_demux_base_init (GstMatroskaDemuxClass * klass) gst_static_pad_template_get (&subtitle_src_templ)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_templ)); - gst_element_class_set_details (element_class, &gst_matroska_demux_details); - GST_DEBUG_CATEGORY_INIT (matroskademux_debug, "matroskademux", 0, - "Matroska demuxer"); + gst_element_class_set_details_simple (element_class, "Matroska demuxer", + "Codec/Demuxer", + "Demuxes a Matroska Stream into video/audio/subtitles", + "Ronald Bultje <rbultje@ronald.bitfreak.net>"); } static void gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass) { - GstElementClass *gstelement_class; - - gstelement_class = (GstElementClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass;; - parent_class = g_type_class_peek_parent (klass); + GST_DEBUG_CATEGORY_INIT (matroskademux_debug, "matroskademux", 0, + "Matroska demuxer"); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_matroska_demux_change_state); @@ -190,14 +175,12 @@ gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass) } static void -gst_matroska_demux_init (GstMatroskaDemux * demux) +gst_matroska_demux_init (GstMatroskaDemux * demux, + GstMatroskaDemuxClass * klass) { - GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux); gint i; - demux->sinkpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "sink"), "sink"); + demux->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); gst_pad_set_activate_function (demux->sinkpad, GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate)); gst_pad_set_activatepull_function (demux->sinkpad, @@ -239,6 +222,9 @@ gst_matroska_track_free (GstMatroskaTrackContext * track) g_array_free (track->encodings, TRUE); } + if (track->pending_tags) + gst_tag_list_free (track->pending_tags); + g_free (track); } @@ -282,6 +268,7 @@ static void gst_matroska_demux_reset (GstElement * element) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); + guint i; /* reset input */ @@ -347,11 +334,14 @@ static gint gst_matroska_demux_encoding_cmp (gconstpointer a, gconstpointer b) { const GstMatroskaTrackEncoding *enc_a; + const GstMatroskaTrackEncoding *enc_b; enc_a = (const GstMatroskaTrackEncoding *) a; enc_b = (const GstMatroskaTrackEncoding *) b; + /* FIXME: give warning if diff == 0, should be unique! */ + return (gint) enc_b->order - (gint) enc_a->order; } @@ -360,6 +350,7 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, GstMatroskaDemux * demux, GstMatroskaTrackContext * context) { GstFlowReturn ret; + guint32 id; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -380,6 +371,9 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, case GST_MATROSKA_ID_CONTENTENCODING:{ GstMatroskaTrackEncoding enc = { 0, }; + /* Set default values */ + enc.scope = 1; + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { break; } @@ -401,6 +395,7 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + /* FIXME: must be unique, check this! */ enc.order = num; break; } @@ -410,7 +405,7 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } - if (num > 7) + if (num > 7 && num == 0) GST_WARNING ("Unknown scope value in contents encoding."); else enc.scope = num; @@ -434,6 +429,8 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, break; } + /* FIXME: Might be compressed or encrypted, depending on ContentEncodingScope & 0x4 + * and the previous ContentEncodingOrder */ while (ret == GST_FLOW_OK) { if ((ret = @@ -454,14 +451,17 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, &num)) != GST_FLOW_OK) { break; } + /* FIXME: maybe don't add tracks at all for which we don't + * support the compression algorithm */ if (num > 3) - GST_WARNING ("Unknown scope value in encoding compalgo."); + GST_WARNING ("Unknown value in encoding compalgo."); else enc.comp_algo = num; break; } case GST_MATROSKA_ID_CONTENTCOMPSETTINGS:{ guint8 *data; + guint64 size; @@ -491,7 +491,11 @@ gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml, case GST_MATROSKA_ID_CONTENTENCRYPTION: GST_WARNING ("Encrypted tracks not yet supported"); - /* pass-through */ + /* FIXME: Might be compressed, depending on ContentEncodingScope & 0x4 + * and the previous ContentEncodingOrder */ + /* FIXME: don't add encrypted tracks at all */ + ret = gst_ebml_read_skip (ebml); + break; default: GST_WARNING ("Unknown track encoding header entry 0x%x - ignoring", id); @@ -532,14 +536,23 @@ static GstFlowReturn gst_matroska_demux_add_stream (GstMatroskaDemux * demux) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux); + GstEbmlRead *ebml = GST_EBML_READ (demux); + GstMatroskaTrackContext *context; + GstPadTemplate *templ = NULL; + GstCaps *caps = NULL; + gchar *padname = NULL; + GstFlowReturn ret; + guint32 id; + GstTagList *list = NULL; + gchar *codec = NULL; if (demux->num_streams >= GST_MATROSKA_DEMUX_MAX_STREAMS) { @@ -557,6 +570,10 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) context->default_duration = 0; context->pos = 0; context->set_discont = TRUE; + context->timecodescale = 1.0; + context->flags = + GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT | + GST_MATROSKA_TRACK_LACING; context->last_flow = GST_FLOW_OK; demux->num_streams++; @@ -574,6 +591,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) } switch (id) { + /* FIXME: check unique */ /* track number (unique stream ID) */ case GST_MATROSKA_ID_TRACKNUMBER:{ guint64 num; @@ -581,6 +599,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + if (num == 0) { + GST_WARNING ("Invalid track number (0) - skipping"); + ret = GST_FLOW_ERROR; + break; + } + context->num = num; break; } @@ -591,6 +615,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + if (num == 0) { + GST_WARNING ("Invalid track UID (0) - skipping"); + ret = GST_FLOW_ERROR; + break; + } + context->uid = num; break; } @@ -607,6 +637,10 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) GST_WARNING ("More than one tracktype defined in a trackentry - skipping"); break; + } else if (track_type < 1 || track_type > 254) { + GST_WARNING ("Invalid track type (%u) - skipping", + (guint) track_type); + break; } /* ok, so we're actually going to reallocate this thing */ @@ -617,13 +651,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) case GST_MATROSKA_TRACK_TYPE_AUDIO: gst_matroska_track_init_audio_context (&context); break; - case GST_MATROSKA_TRACK_TYPE_COMPLEX: - gst_matroska_track_init_complex_context (&context); - break; case GST_MATROSKA_TRACK_TYPE_SUBTITLE: gst_matroska_track_init_subtitle_context (&context); break; + case GST_MATROSKA_TRACK_TYPE_COMPLEX: case GST_MATROSKA_TRACK_TYPE_LOGO: + case GST_MATROSKA_TRACK_TYPE_BUTTONS: case GST_MATROSKA_TRACK_TYPE_CONTROL: default: GST_WARNING ("Unknown or unsupported track type %" @@ -661,29 +694,43 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) } switch (id) { - /* fixme, this should be one-up, but I get it here (?) */ + /* Should be one level up but some broken muxers write it here. */ case GST_MATROSKA_ID_TRACKDEFAULTDURATION:{ guint64 num; if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid track default duration (0) - ignoring"); + break; + } + context->default_duration = num; break; } /* video framerate */ + /* NOTE: This one is here only for backward compatibility. + * Use _TRACKDEFAULDURATION one level up. */ case GST_MATROSKA_ID_VIDEOFRAMERATE:{ gdouble num; if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK) { break; } - if (num != 0.0) { - context->default_duration = - gst_gdouble_to_guint64 ((gdouble) GST_SECOND / num); - videocontext->default_fps = num; + + if (num <= 0.0) { + GST_WARNING ("Invalid video framerate (%lf fps) - ignoring", + num); + break; } + + if (context->default_duration == 0) + context->default_duration = + gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num)); + videocontext->default_fps = num; break; } @@ -694,6 +741,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid display width (0) - ignoring"); + break; + } + videocontext->display_width = num; GST_DEBUG ("display_width %" G_GUINT64_FORMAT, num); break; @@ -706,6 +759,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid display height (0) - ignoring"); + break; + } + videocontext->display_height = num; GST_DEBUG ("display_height %" G_GUINT64_FORMAT, num); break; @@ -718,6 +777,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid pixel width (0) - ignoring"); + break; + } + videocontext->pixel_width = num; GST_DEBUG ("pixel_width %" G_GUINT64_FORMAT, num); break; @@ -730,6 +795,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid pixel height (0) - ignoring"); + break; + } + videocontext->pixel_height = num; GST_DEBUG ("pixel_height %" G_GUINT64_FORMAT, num); break; @@ -770,7 +841,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) } /* aspect ratio behaviour */ - case GST_MATROSKA_ID_VIDEOASPECTRATIO:{ + case GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE:{ guint64 num; if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { @@ -794,10 +865,22 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num > G_MAXUINT32) { + GST_WARNING ("Invalid video colourspace (%" G_GUINT64_FORMAT + ") - ignoring", num); + break; + } videocontext->fourcc = num; break; } + case GST_MATROSKA_ID_VIDEODISPLAYUNIT: + case GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM: + case GST_MATROSKA_ID_VIDEOPIXELCROPTOP: + case GST_MATROSKA_ID_VIDEOPIXELCROPLEFT: + case GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT: + case GST_MATROSKA_ID_VIDEOGAMMAVALUE: default: GST_WARNING ("Unknown video track header entry 0x%x - ignoring", id); @@ -849,6 +932,17 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num <= 0.0) { + GST_WARNING ("Invalid audio sample rate (%lf) - ignoring)", + num); + break; + } + + if (context->default_duration == 0) + context->default_duration = + gst_gdouble_to_guint64 ((gdouble) GST_SECOND * (1.0 / num)); + audiocontext->samplerate = num; break; } @@ -860,6 +954,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid audio bit depth (0) - ignoring)"); + break; + } + audiocontext->bitdepth = num; break; } @@ -871,10 +971,19 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING + ("Invalid number of audio channels (0) - ignoring)"); + break; + } + audiocontext->channels = num; break; } + case GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS: + case GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ: default: GST_WARNING ("Unknown audio track header entry 0x%x - ignoring", id); @@ -907,6 +1016,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) /* codec private data */ case GST_MATROSKA_ID_CODECPRIVATE:{ guint8 *data; + guint64 size; if ((ret = @@ -914,6 +1024,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) &size)) != GST_FLOW_OK) { break; } + /* TODO: might be compressed or encrypted */ context->codec_priv = data; context->codec_priv_size = size; GST_LOG_OBJECT (demux, "%u bytes of codec private data", (guint) size); @@ -988,6 +1099,20 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) break; } + /* whether the track must be used during playback */ + case GST_MATROSKA_ID_TRACKFLAGFORCED:{ + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num) + context->flags |= GST_MATROSKA_TRACK_FORCED; + else + context->flags &= ~GST_MATROSKA_TRACK_FORCED; + break; + } + /* lacing (like MPEG, where blocks don't end/start on frame * boundaries) */ case GST_MATROSKA_ID_TRACKFLAGLACING:{ @@ -1010,6 +1135,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num == 0) { + GST_WARNING ("Invalid track default duration (0) - ignoring"); + break; + } + context->default_duration = num; break; } @@ -1019,15 +1150,38 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) break; } + case GST_MATROSKA_ID_TRACKTIMECODESCALE:{ + gdouble num; + + if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num <= 0.0) { + GST_WARNING ("Invalid track time code scale (%lf) - ignoring", num); + break; + } + + context->timecodescale = num; + break; + } + default: GST_WARNING ("Unknown track header entry 0x%x - ignoring", id); /* pass-through */ - /* we ignore these because they're nothing useful (i.e. crap). */ - case GST_MATROSKA_ID_CODECINFOURL: - case GST_MATROSKA_ID_CODECDOWNLOADURL: + /* we ignore these because they're nothing useful (i.e. crap) + * or simply not implemented yet. */ case GST_MATROSKA_ID_TRACKMINCACHE: case GST_MATROSKA_ID_TRACKMAXCACHE: + case GST_MATROSKA_ID_MAXBLOCKADDITIONID: + case GST_MATROSKA_ID_TRACKATTACHMENTLINK: + case GST_MATROSKA_ID_TRACKOVERLAY: + case GST_MATROSKA_ID_TRACKTRANSLATE: + case GST_MATROSKA_ID_TRACKOFFSET: + case GST_MATROSKA_ID_CODECSETTINGS: + case GST_MATROSKA_ID_CODECINFOURL: + case GST_MATROSKA_ID_CODECDOWNLOADURL: + case GST_MATROSKA_ID_CODECDECODEALL: case GST_EBML_ID_VOID: ret = gst_ebml_read_skip (ebml); break; @@ -1088,16 +1242,6 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) break; } - case GST_MATROSKA_TRACK_TYPE_COMPLEX:{ - GstMatroskaTrackComplexContext *complexcontext = - (GstMatroskaTrackComplexContext *) context; - padname = g_strdup_printf ("video_%02d", demux->num_v_streams++); - templ = gst_element_class_get_pad_template (klass, "video_%02d"); - caps = gst_matroska_demux_complex_caps (complexcontext, - context->codec_id, context->codec_priv, context->codec_priv_size); - break; - } - case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{ GstMatroskaTrackSubtitleContext *subtitlecontext = (GstMatroskaTrackSubtitleContext *) context; @@ -1108,7 +1252,9 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux) break; } + case GST_MATROSKA_TRACK_TYPE_COMPLEX: case GST_MATROSKA_TRACK_TYPE_LOGO: + case GST_MATROSKA_TRACK_TYPE_BUTTONS: case GST_MATROSKA_TRACK_TYPE_CONTROL: default: /* we should already have quit by now */ @@ -1194,10 +1340,14 @@ static gboolean gst_matroska_demux_handle_src_query (GstPad * pad, GstQuery * query) { GstMatroskaDemux *demux; + gboolean res = FALSE; demux = GST_MATROSKA_DEMUX (gst_pad_get_parent (pad)); + /* FIXME: do queries on the Tracks, not on the Segment. + * Convert between time and frames if we know the duration + * of one frame for the track */ switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: { @@ -1251,6 +1401,7 @@ gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, gint64 seek_pos, gint64 segment_stop, gboolean keyunit) { guint entry; + guint n = 0; if (!demux->num_indexes) @@ -1294,6 +1445,7 @@ static gboolean gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event) { gboolean ret = TRUE; + gint i; g_return_val_if_fail (event != NULL, FALSE); @@ -1322,6 +1474,7 @@ static gboolean gst_matroska_demux_element_send_event (GstElement * element, GstEvent * event) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); + gboolean res; g_return_val_if_fail (event != NULL, FALSE); @@ -1341,14 +1494,23 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GstEvent * event) { GstMatroskaIndex *entry; + GstSeekFlags flags; + GstSeekType cur_type, stop_type; + GstFormat format; + GstEvent *newsegment_event; + gboolean flush, keyunit; + gdouble rate; + gint64 cur, stop; + gint64 segment_start, segment_stop; + gint i; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, @@ -1517,6 +1679,7 @@ static gboolean gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (gst_pad_get_parent (pad)); + gboolean res = TRUE; switch (GST_EVENT_TYPE (event)) { @@ -1546,9 +1709,13 @@ static GstFlowReturn gst_matroska_demux_init_stream (GstMatroskaDemux * demux) { GstEbmlRead *ebml = GST_EBML_READ (demux); + guint32 id; + gchar *doctype; + guint version; + GstFlowReturn ret; if ((ret = gst_ebml_read_header (ebml, &doctype, &version)) != GST_FLOW_OK) @@ -1568,8 +1735,9 @@ gst_matroska_demux_init_stream (GstMatroskaDemux * demux) return GST_FLOW_ERROR; } - /* find segment, must be the next element */ - while (1) { + /* find segment, must be the next element but search as long as + * we find it anyway */ + while (TRUE) { guint last_level; if ((ret = gst_ebml_peek_id (ebml, &last_level, &id)) != GST_FLOW_OK) { @@ -1605,7 +1773,9 @@ static GstFlowReturn gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + guint32 id; while (ret == GST_FLOW_OK) { @@ -1645,7 +1815,9 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, gboolean prevent_eos, GstMatroskaIndex * idx, guint64 length) { GstEbmlRead *ebml = GST_EBML_READ (demux); + guint32 id; + GstFlowReturn ret; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -1671,6 +1843,12 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) goto error; + if (num == 0) { + idx->track = -1; + GST_WARNING ("Invalid cue track number (0)"); + goto error; + break; + } idx->track = num; break; @@ -1684,6 +1862,8 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) goto error; + /* FIXME: may overflow, our seeks, etc are int64 based */ + idx->pos = num; break; } @@ -1692,6 +1872,9 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, GST_WARNING ("Unknown entry 0x%x in CuesTrackPositions", id); /* fall-through */ + case GST_MATROSKA_ID_CUEBLOCKNUMBER: + case GST_MATROSKA_ID_CUECODECSTATE: + case GST_MATROSKA_ID_CUEREFERENCE: case GST_EBML_ID_VOID: if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK) goto error; @@ -1718,8 +1901,11 @@ gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux, gboolean prevent_eos, guint64 length) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstMatroskaIndex idx; + guint32 id; + GstFlowReturn ret; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -1756,7 +1942,7 @@ gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux, } /* position in the file + track to which it belongs */ - case GST_MATROSKA_ID_CUETRACKPOSITION: + case GST_MATROSKA_ID_CUETRACKPOSITIONS: { ret = gst_matroska_demux_parse_index_cuetrack (demux, prevent_eos, &idx, length); @@ -1802,8 +1988,11 @@ static GstFlowReturn gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos) { GstEbmlRead *ebml = GST_EBML_READ (demux); + guint32 id; + guint64 length = 0; + GstFlowReturn ret = GST_FLOW_OK; if (prevent_eos) { @@ -1854,7 +2043,9 @@ static GstFlowReturn gst_matroska_demux_parse_info (GstMatroskaDemux * demux) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + guint32 id; while (ret == GST_FLOW_OK) { @@ -1879,11 +2070,18 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux) case GST_MATROSKA_ID_DURATION:{ gdouble num; + GstClockTime dur; if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK) { break; } + + if (num <= 0.0) { + GST_WARNING ("Invalid duration (%lf) - skipping", num); + break; + } + dur = gst_gdouble_to_guint64 (num * gst_guint64_to_gdouble (demux->time_scale)); if (GST_CLOCK_TIME_IS_VALID (dur) && dur <= G_MAXINT64) @@ -1921,7 +2119,15 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux) break; } - case GST_MATROSKA_ID_SEGMENTUID:{ + case GST_MATROSKA_ID_SEGMENTUID: + case GST_MATROSKA_ID_SEGMENTFILENAME: + case GST_MATROSKA_ID_PREVUID: + case GST_MATROSKA_ID_PREVFILENAME: + case GST_MATROSKA_ID_NEXTUID: + case GST_MATROSKA_ID_NEXTFILENAME: + case GST_MATROSKA_ID_TITLE: + case GST_MATROSKA_ID_SEGMENTFAMILY: + case GST_MATROSKA_ID_CHAPTERTRANSLATE:{ /* TODO not yet implemented. */ ret = gst_ebml_read_skip (ebml); break; @@ -1949,6 +2155,7 @@ static GstFlowReturn gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, gboolean prevent_eos, guint64 length, GstTagList ** p_taglist) { + /* FIXME: check if there are more useful mappings */ struct { gchar *matroska_tagname; @@ -1967,9 +2174,13 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT} }; GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret; + guint32 id; + gchar *value = NULL; + gchar *tag = NULL; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -2005,6 +2216,9 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, GST_WARNING ("Unknown entry 0x%x in metadata collection", id); /* fall-through */ + case GST_MATROSKA_ID_TAGLANGUAGE: + case GST_MATROSKA_ID_TAGDEFAULT: + case GST_MATROSKA_ID_TAGBINARY: case GST_EBML_ID_VOID: ret = gst_ebml_read_skip (ebml); break; @@ -2021,6 +2235,7 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) { const gchar *tagname_gst = tag_conv[i].gstreamer_tagname; + const gchar *tagname_mkv = tag_conv[i].matroska_tagname; if (strcmp (tagname_mkv, tag) == 0) { @@ -2031,10 +2246,10 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, g_value_init (&src, G_TYPE_STRING); g_value_set_string (&src, value); g_value_init (&dest, dest_type); - g_value_transform (&src, &dest); + if (g_value_transform (&src, &dest)) + gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND, + tagname_gst, &dest, NULL); g_value_unset (&src); - gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND, - tagname_gst, &dest, NULL); g_value_unset (&dest); break; } @@ -2052,7 +2267,9 @@ gst_matroska_demux_parse_metadata_id_tag (GstMatroskaDemux * demux, gboolean prevent_eos, guint64 length, GstTagList ** p_taglist) { GstEbmlRead *ebml = GST_EBML_READ (demux); + guint32 id; + GstFlowReturn ret; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -2100,11 +2317,16 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, gboolean prevent_eos) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstTagList *taglist = gst_tag_list_new (); + GstFlowReturn ret = GST_FLOW_OK; + guint64 length = 0; + guint32 id; + /* TODO: review length/eos logic */ if (prevent_eos) { length = gst_ebml_read_get_length (ebml); } @@ -2135,6 +2357,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, /* fall-through */ case GST_EBML_ID_VOID: + /* FIXME: Use to limit the tags to specific pads */ + case GST_MATROSKA_ID_TARGETS: ret = gst_ebml_read_skip (ebml); break; } @@ -2163,6 +2387,7 @@ static gint gst_matroska_ebmlnum_uint (guint8 * data, guint size, guint64 * num) { gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0; + guint64 total; if (size <= 0) { @@ -2200,6 +2425,7 @@ static gint gst_matroska_ebmlnum_sint (guint8 * data, guint size, gint64 * num) { guint64 unum; + gint res; /* read as unsigned number first */ @@ -2261,6 +2487,7 @@ gst_matroska_demux_push_hdr_buf (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream, guint8 * data, guint len) { GstFlowReturn ret, cret; + GstBuffer *header_buf = NULL; ret = gst_pad_alloc_buffer_and_set_caps (stream->pad, @@ -2300,7 +2527,9 @@ gst_matroska_demux_push_flac_codec_priv_data (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream) { GstFlowReturn ret; + guint8 *pdata; + guint off, len; GST_LOG_OBJECT (demux, "priv data size = %u", stream->codec_priv_size); @@ -2345,7 +2574,9 @@ gst_matroska_demux_push_xiph_codec_priv_data (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream) { GstFlowReturn ret; + guint8 *p = (guint8 *) stream->codec_priv; + gint i, offset, length, num_packets; /* start of the stream and vorbis audio or theora video, need to @@ -2400,8 +2631,11 @@ gst_matroska_demux_push_dvd_clut_change_event (GstMatroskaDemux * demux, start = strstr (stream->codec_priv, "palette:"); if (start) { gint i; + guint32 clut[16]; + guint32 col; + guint8 r, g, b, y, u, v; start += 8; @@ -2461,13 +2695,19 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream, gint block_length, GstBuffer ** buf) { GstBuffer *newbuf; + guint8 *data; + guint newlen; + GstFlowReturn ret, cret; /* we need to reconstruct the header of the wavpack block */ Wavpack4Header wvh; + /* FIXME: broken for > 2 channels and hybrid files + http://www.matroska.org/technical/specs/codecid/wavpack.html */ + wvh.ck_id[0] = 'w'; wvh.ck_id[1] = 'v'; wvh.ck_id[2] = 'p'; @@ -2517,10 +2757,15 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream, GstBuffer * buf) { GstMatroskaTrackSubtitleContext *sub_stream; + const gchar *encoding, *data; + GError *err = NULL; + GstBuffer *newbuf; + gchar *utf8; + guint size; sub_stream = (GstMatroskaTrackSubtitleContext *) stream; @@ -2590,8 +2835,11 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf) for (i = 0; i < context->encodings->len; i++) { GstMatroskaTrackEncoding *enc; + guint8 *new_data = NULL; + guint new_size = 0; + GstBuffer *new_buf; enc = &g_array_index (context->encodings, GstMatroskaTrackEncoding, i); @@ -2600,13 +2848,15 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf) if (enc->type != 0) break; - /* FIXME: use enc->scope ? */ + /* FIXME: use enc->scope ! only necessary to decode buffer if scope & 0x1 */ if (enc->comp_algo == 0) { #ifdef HAVE_ZLIB /* zlib encoded track */ z_stream zstream; + guint orig_size; + int result; orig_size = GST_BUFFER_SIZE (buf); @@ -2622,6 +2872,7 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf) new_size = orig_size; new_data = g_malloc (new_size); zstream.avail_out = new_size; + /* FIXME: not exactly fast, right? */ do { new_size += 4000; new_data = g_realloc (new_data, new_size); @@ -2643,6 +2894,9 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf) GST_WARNING ("GZIP encoded tracks not supported."); break; #endif +/* FIXME: add bzip/lzo support, what is header stripped? + * it's insane and requires deeper knowledge of the used codec + */ } else if (enc->comp_algo == 1) { GST_WARNING ("BZIP encoded tracks not supported."); break; @@ -2676,18 +2930,29 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, guint64 cluster_time, gboolean is_simpleblock) { GstMatroskaTrackContext *stream = NULL; + GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + gboolean readblock = FALSE; + guint32 id; + guint64 block_duration = 0; + GstBuffer *buf = NULL; - gint stream_num = 0, n, laces = 0; + + gint stream_num = -1, n, laces = 0; + guint size = 0; + gint *lace_size = NULL; + gint64 time = 0; - gint64 lace_time = 0; + gint flags = 0; + gint64 referenceblock = 0; while (ret == GST_FLOW_OK) { @@ -2711,6 +2976,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, case GST_MATROSKA_ID_BLOCK: { guint64 num; + guint8 *data; if ((ret = gst_ebml_read_buffer (ebml, &id, &buf)) != GST_FLOW_OK) @@ -2736,13 +3002,14 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, gst_buffer_unref (buf); buf = NULL; GST_WARNING ("Invalid stream %d or size %u", stream_num, size); + ret = GST_FLOW_ERROR; break; } stream = demux->src[stream_num]; /* time (relative to cluster time) */ - time = ((gint16) GST_READ_UINT16_BE (data)) * demux->time_scale; + time = ((gint16) GST_READ_UINT16_BE (data)); data += 2; size -= 2; flags = GST_READ_UINT8 (data); @@ -2814,6 +3081,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, total = lace_size[0] = num; for (n = 1; ret == GST_FLOW_OK && n < laces - 1; n++) { gint64 snum; + gint r; if ((r = gst_matroska_ebmlnum_sint (data, size, &snum)) < 0) { @@ -2872,6 +3140,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, GST_WARNING ("Unknown entry 0x%x in blockgroup data", id); /* fall-through */ + case GST_MATROSKA_ID_BLOCKVIRTUAL: + case GST_MATROSKA_ID_BLOCKADDITIONS: + case GST_MATROSKA_ID_REFERENCEPRIORITY: + case GST_MATROSKA_ID_REFERENCEVIRTUAL: + case GST_MATROSKA_ID_CODECSTATE: + case GST_MATROSKA_ID_SLICES: case GST_EBML_ID_VOID: ret = gst_ebml_read_skip (ebml); break; @@ -2886,18 +3160,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, } } - if (cluster_time != GST_CLOCK_TIME_NONE) { - if (time < 0 && (-time) > cluster_time) - lace_time = cluster_time; - else - lace_time = cluster_time + time; - } else { - lace_time = GST_CLOCK_TIME_NONE; - } - - stream = demux->src[stream_num]; - - if (referenceblock && readblock && stream->set_discont) { + if (referenceblock && readblock && demux->src[stream_num]->set_discont) { /* When doing seeks or such, we need to restart on key frames or decoders might choke. */ readblock = FALSE; @@ -2908,12 +3171,38 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, if (ret == GST_FLOW_OK && readblock) { guint64 duration = 0; + gint64 lace_time = 0; + + stream = demux->src[stream_num]; + + if (cluster_time != GST_CLOCK_TIME_NONE) { + /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1? + * Drop unless the lace contains timestamp 0? */ + if (time < 0 && (-time) > cluster_time) { + lace_time = 0; + } else { + if (stream->timecodescale == 1.0) + lace_time = (cluster_time + time) * demux->time_scale; + else + lace_time = + gst_util_guint64_to_gdouble ((cluster_time + time) * + demux->time_scale) * stream->timecodescale; + } + } else { + lace_time = GST_CLOCK_TIME_NONE; + } + if (block_duration) { - duration = block_duration * demux->time_scale; + if (stream->timecodescale == 1.0) + duration = block_duration * demux->time_scale; + else + duration = + gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble + (block_duration * demux->time_scale) * stream->timecodescale); } else if (stream->default_duration) { duration = stream->default_duration; } - + /* else duration is diff between timecode of this and next block */ for (n = 0; n < laces; n++) { GstBuffer *sub; @@ -2939,7 +3228,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, &sub); } - /* FIXME: do all laces have the same lenght? */ + /* FIXME: do all laces have the same length? the lenght of a lace should + * in theory be default_duration as one lace should contain on frame */ if (duration) { GST_BUFFER_DURATION (sub) = duration / laces; stream->pos += GST_BUFFER_DURATION (sub); @@ -2998,8 +3288,11 @@ static GstFlowReturn gst_matroska_demux_parse_cluster (GstMatroskaDemux * demux) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + guint64 cluster_time = GST_CLOCK_TIME_NONE; + guint32 id; while (ret == GST_FLOW_OK) { @@ -3018,7 +3311,7 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux * demux) guint64 num; if ((ret = gst_ebml_read_uint (ebml, &id, &num)) == GST_FLOW_OK) { - cluster_time = num * demux->time_scale; + cluster_time = num; } break; } @@ -3042,6 +3335,10 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux * demux) GST_WARNING ("Unknown entry 0x%x in cluster data", id); /* fall-through */ + case GST_MATROSKA_ID_POSITION: + case GST_MATROSKA_ID_PREVSIZE: + case GST_MATROSKA_ID_ENCRYPTEDBLOCK: + case GST_MATROSKA_ID_SILENTTRACKS: case GST_EBML_ID_VOID: ret = gst_ebml_read_skip (ebml); break; @@ -3061,9 +3358,13 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, gboolean * p_run_loop) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret; + guint64 seek_pos = (guint64) - 1; + guint32 seek_id = 0; + guint32 id; if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) @@ -3123,12 +3424,16 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, return GST_FLOW_OK; } + /* FIXME: Do this for the other elements except CLUSTERS too. + * We can't know that they will come before the CLUSTERS */ switch (seek_id) { case GST_MATROSKA_ID_CUES: case GST_MATROSKA_ID_TAGS: { guint level_up = demux->level_up; + guint64 before_pos, length; + GstEbmlLevel *level; /* remember */ @@ -3175,6 +3480,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, if ((ret = gst_matroska_demux_parse_index (demux, TRUE)) != GST_FLOW_OK) return ret; + /* FIXME: why is this here? */ if (gst_ebml_read_get_length (ebml) == ebml->offset) *p_run_loop = FALSE; else @@ -3187,6 +3493,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, gst_matroska_demux_parse_metadata (demux, TRUE)) != GST_FLOW_OK) return ret; + /* FIXME: why is this here? */ if (gst_ebml_read_get_length (ebml) == ebml->offset) *p_run_loop = FALSE; else @@ -3194,7 +3501,8 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, break; } - /* used to be here in 0.8 version, but makes mewmew sample not work */ + /* FIXME: + * used to be here in 0.8 version, but makes mewmew sample not work */ /* if (*p_run_loop == FALSE) break; */ finish: @@ -3229,7 +3537,9 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, gboolean * p_run_loop) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + guint32 id; while (ret == GST_FLOW_OK) { @@ -3272,17 +3582,23 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, guint32 id, gboolean * p_run_loop) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret; switch (id) { + /* FIXME: not mandatory... will things break? + * Can only happen exactly once, ignore second + * occurences! */ /* stream info */ - case GST_MATROSKA_ID_INFO: + case GST_MATROSKA_ID_SEGMENTINFO: if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) return ret; if ((ret = gst_matroska_demux_parse_info (demux)) != GST_FLOW_OK) return ret; break; + /* FIXME: might happen more than once, second + * occurences must be exactly the same so drop them */ /* track info headers */ case GST_MATROSKA_ID_TRACKS: { @@ -3293,6 +3609,8 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, break; } + /* FIXME: can only happen once or never but + * for the sake of sanity ignore second occurences */ /* stream index */ case GST_MATROSKA_ID_CUES: { @@ -3309,10 +3627,12 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, break; } + /* FIXME: can be there more than once, why do we have + * ->metadata_parsed? */ /* metadata */ case GST_MATROSKA_ID_TAGS: { - if (!demux->index_parsed) { + if (!demux->metadata_parsed) { if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) return ret; if ((ret = @@ -3326,6 +3646,8 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, break; } + /* FIXME: must not be there but can happen more than once with + * different content */ /* file index (if seekable, seek to Cues/Tags to parse it) */ case GST_MATROSKA_ID_SEEKHEAD: { @@ -3338,9 +3660,12 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, break; } + /* FIXME: must not be there */ case GST_MATROSKA_ID_CLUSTER: { if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) { + /* FIXME: Skip first and try to read TRACKS and other things + * first, then go back here. */ demux->state = GST_MATROSKA_DEMUX_STATE_DATA; /* FIXME: different streams might have different lengths! */ /* send initial discont */ @@ -3369,6 +3694,25 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux, break; } + /* TODO: Implement parsing of attachments and push them + * through an attachment pad, one for each attachment */ + /* FIXME: must not be there but can only be once */ + case GST_MATROSKA_ID_ATTACHMENTS:{ + GST_INFO ("Attachments elements are not supported yet"); + if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK) + return ret; + break; + } + + /* TODO: Implement parsing of chapters */ + /* FIXME: Must not be there but can only be once */ + case GST_MATROSKA_ID_CHAPTERS:{ + GST_INFO ("Chapters elements are not supported yet"); + if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK) + return ret; + break; + } + default: GST_WARNING ("Unknown matroska file header ID 0x%x at %" G_GUINT64_FORMAT, id, GST_EBML_READ (demux)->offset); @@ -3388,8 +3732,11 @@ static GstFlowReturn gst_matroska_demux_loop_stream (GstMatroskaDemux * demux) { GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret = GST_FLOW_OK; + gboolean run_loop = TRUE; + guint32 id; /* we've found our segment, start reading the different contents in here */ @@ -3415,8 +3762,10 @@ gst_matroska_demux_loop_stream (GstMatroskaDemux * demux) static void gst_matroska_demux_loop (GstPad * pad) { - GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (gst_pad_get_parent (pad)); + GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (GST_PAD_PARENT (pad)); + GstEbmlRead *ebml = GST_EBML_READ (demux); + GstFlowReturn ret; /* first, if we're to start, let's actually get starting */ @@ -3454,8 +3803,6 @@ gst_matroska_demux_loop (GstPad * pad) goto pause; } - /* all is fine */ - gst_object_unref (demux); return; /* ERRORS */ @@ -3493,7 +3840,6 @@ pause: gst_matroska_demux_send_event (demux, gst_event_new_eos ()); } } - gst_object_unref (demux); return; } } @@ -3531,6 +3877,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * gchar ** codec_name) { GstMatroskaTrackContext *context = (GstMatroskaTrackContext *) videocontext; + GstCaps *caps = NULL; g_assert (videocontext != NULL); @@ -3539,6 +3886,14 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * context->send_xiph_headers = FALSE; context->send_flac_headers = FALSE; + /* TODO: check if we have all codec types from matroska-ids.h + * check if we have to do more special things with codec_private + * + * Add support for + * GST_MATROSKA_CODEC_ID_VIDEO_QUICKTIME + * GST_MATROSKA_CODEC_ID_VIDEO_SNOW + */ + if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC)) { gst_riff_strf_vids *vids = NULL; @@ -3587,7 +3942,6 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED)) { guint32 fourcc = 0; - /* how nice, this is undocumented... */ switch (videocontext->fourcc) { case GST_MAKE_FOURCC ('I', '4', '2', '0'): *codec_name = g_strdup ("Raw planar YUV 4:2:0"); @@ -3597,6 +3951,18 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * *codec_name = g_strdup ("Raw packed YUV 4:2:2"); fourcc = videocontext->fourcc; break; + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + *codec_name = g_strdup ("Raw packed YUV 4:2:0"); + fourcc = videocontext->fourcc; + break; + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + *codec_name = g_strdup ("Raw packed YUV 4:2:2"); + fourcc = videocontext->fourcc; + break; + case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'): + *codec_name = g_strdup ("Raw packed YUV 4:4:4 with alpha channel"); + fourcc = videocontext->fourcc; + break; default: GST_DEBUG ("Unknown fourcc %" GST_FOURCC_FORMAT, @@ -3697,11 +4063,13 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * if (caps != NULL) { int i; + GstStructure *structure; for (i = 0; i < gst_caps_get_size (caps); i++) { structure = gst_caps_get_structure (caps, i); + /* FIXME: use the real unit here! */ GST_DEBUG ("video size %dx%d, target display size %dx%d (any unit)", videocontext->pixel_width, videocontext->pixel_height, @@ -3710,6 +4078,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * /* pixel width and height are the w and h of the video in pixels */ if (videocontext->pixel_width > 0 && videocontext->pixel_height > 0) { gint w = videocontext->pixel_width; + gint h = videocontext->pixel_height; gst_structure_set (structure, @@ -3830,6 +4199,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * gchar ** codec_name) { GstMatroskaTrackContext *context = (GstMatroskaTrackContext *) audiocontext; + GstCaps *caps = NULL; g_assert (audiocontext != NULL); @@ -3838,6 +4208,17 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * context->send_xiph_headers = FALSE; context->send_flac_headers = FALSE; + /* TODO: check if we have all codec types from matroska-ids.h + * check if we have to do more special things with codec_private + * check if we need bitdepth in different places too + * implement channel position magic + * Add support for: + * GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID9 + * GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID10 + * GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDMC + * GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDM2 + */ + if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) || !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) || !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3)) { @@ -3876,7 +4257,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * audiocontext->bitdepth); } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT)) { caps = gst_caps_new_simple ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, + "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "width", G_TYPE_INT, audiocontext->bitdepth, NULL); *codec_name = g_strdup_printf ("Raw %d-bit floating-point audio", audiocontext->bitdepth); @@ -3911,18 +4292,21 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * caps = gst_riff_create_audio_caps (auds->format, NULL, auds, NULL, NULL, codec_name); } - } else if (g_str_has_prefix (codec_id, "A_AAC")) { + } else if (g_str_has_prefix (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC)) { GstBuffer *priv = NULL; + gint mpegversion = -1; + gint rate_idx, profile; + guint8 *data = NULL; /* unspecified AAC profile with opaque private codec data */ - if (strcmp (codec_id, "A_AAC") == 0) { + if (strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC) == 0) { if (context->codec_priv_size >= 2) { guint obj_type, freq_index, explicit_freq_bytes = 0; - codec_id = GST_MATROSKA_CODEC_ID_AUDIO_MPEG4; + codec_id = GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4; freq_index = (GST_READ_UINT16_BE (context->codec_priv) & 0x780) >> 7; obj_type = (GST_READ_UINT16_BE (context->codec_priv) & 0xF800) >> 11; if (freq_index == 15) @@ -3939,7 +4323,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * } else { GST_WARNING ("Opaque A_AAC codec ID, but no codec private data"); /* just try this and see what happens ... */ - codec_id = GST_MATROSKA_CODEC_ID_AUDIO_MPEG4; + codec_id = GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4; } } @@ -3955,11 +4339,11 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * GST_BUFFER_SIZE (priv) = 2; } - if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG2, - strlen (GST_MATROSKA_CODEC_ID_AUDIO_MPEG2))) { + if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2, + strlen (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2))) { mpegversion = 2; - } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG4, - strlen (GST_MATROSKA_CODEC_ID_AUDIO_MPEG4))) { + } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4, + strlen (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4))) { mpegversion = 4; if (g_strrstr (codec_id, "SBR")) { @@ -4037,24 +4421,13 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * } static GstCaps * -gst_matroska_demux_complex_caps (GstMatroskaTrackComplexContext * - complexcontext, const gchar * codec_id, gpointer data, guint size) -{ - GstCaps *caps = NULL; - - GST_DEBUG ("Unknown complex stream: codec_id='%s'", codec_id); - - return caps; -} - -static GstCaps * gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext * subtitlecontext, const gchar * codec_id, gpointer data, guint size) { GstCaps *caps = NULL; /* for backwards compatibility */ - if (!g_ascii_strcasecmp (codec_id, "S_TEXT/ASCII")) + if (!g_ascii_strcasecmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII)) codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8; else if (!g_ascii_strcasecmp (codec_id, "S_SSA")) codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_SSA; @@ -4063,6 +4436,8 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext * else if (!g_ascii_strcasecmp (codec_id, "S_USF")) codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_USF; + /* TODO: Add GST_MATROSKA_CODEC_ID_SUBTITLE_BMP support + * Check if we have to do something with codec_private */ if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8)) { caps = gst_caps_new_simple ("text/plain", NULL); subtitlecontext->check_utf8 = TRUE; @@ -4102,6 +4477,7 @@ gst_matroska_demux_change_state (GstElement * element, GstStateChange transition) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; /* handle upwards state changes here */ diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h index bccec17e..9da56603 100644 --- a/gst/matroska/matroska-demux.h +++ b/gst/matroska/matroska-demux.h @@ -40,7 +40,9 @@ G_BEGIN_DECLS #define GST_IS_MATROSKA_DEMUX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX)) -#define GST_MATROSKA_DEMUX_MAX_STREAMS 64 +/* The spec says that more than 127 stream is discouraged so + * take this as a limit for now */ +#define GST_MATROSKA_DEMUX_MAX_STREAMS 127 typedef enum { GST_MATROSKA_DEMUX_STATE_START, diff --git a/gst/matroska/matroska-ids.c b/gst/matroska/matroska-ids.c index ec71a568..81cfd04a 100644 --- a/gst/matroska/matroska-ids.c +++ b/gst/matroska/matroska-ids.c @@ -109,25 +109,3 @@ gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context) subtitle_context->invalid_utf8 = FALSE; return TRUE; } - -gboolean -gst_matroska_track_init_complex_context (GstMatroskaTrackContext ** p_context) -{ - GstMatroskaTrackComplexContext *complex_context; - - g_assert (p_context != NULL && *p_context != NULL); - - /* already set up? (track info might come before track type) */ - if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_COMPLEX) - return TRUE; - - /* it better not have been set up as some other track type ... */ - if ((*p_context)->type != 0) { - g_return_val_if_reached (FALSE); - } - - complex_context = g_renew (GstMatroskaTrackComplexContext, *p_context, 1); - *p_context = (GstMatroskaTrackContext *) complex_context; - (*p_context)->type = GST_MATROSKA_TRACK_TYPE_COMPLEX; - return TRUE; -} diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index 760dca87..b95111a8 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -30,117 +30,289 @@ * Matroska element IDs. max. 32-bit. */ -/* toplevel segment */ -#define GST_MATROSKA_ID_SEGMENT 0x18538067 - -/* matroska top-level master IDs */ -#define GST_MATROSKA_ID_INFO 0x1549A966 -#define GST_MATROSKA_ID_TRACKS 0x1654AE6B -#define GST_MATROSKA_ID_CUES 0x1C53BB6B -#define GST_MATROSKA_ID_TAGS 0x1254C367 -#define GST_MATROSKA_ID_SEEKHEAD 0x114D9B74 -#define GST_MATROSKA_ID_CLUSTER 0x1F43B675 - -/* IDs in the info master */ -#define GST_MATROSKA_ID_TIMECODESCALE 0x2AD7B1 -#define GST_MATROSKA_ID_DURATION 0x4489 -#define GST_MATROSKA_ID_WRITINGAPP 0x5741 -#define GST_MATROSKA_ID_MUXINGAPP 0x4D80 -#define GST_MATROSKA_ID_DATEUTC 0x4461 -#define GST_MATROSKA_ID_SEGMENTUID 0x73A4 - -/* ID in the tracks master */ -#define GST_MATROSKA_ID_TRACKENTRY 0xAE - -/* IDs in the trackentry master */ -#define GST_MATROSKA_ID_TRACKNUMBER 0xD7 -#define GST_MATROSKA_ID_TRACKUID 0x73C5 -#define GST_MATROSKA_ID_TRACKTYPE 0x83 -#define GST_MATROSKA_ID_TRACKAUDIO 0xE1 -#define GST_MATROSKA_ID_TRACKVIDEO 0xE0 -#define GST_MATROSKA_ID_CODECID 0x86 -#define GST_MATROSKA_ID_CODECPRIVATE 0x63A2 -#define GST_MATROSKA_ID_CODECNAME 0x258688 -#define GST_MATROSKA_ID_CODECINFOURL 0x3B4040 -#define GST_MATROSKA_ID_CODECDOWNLOADURL 0x26B240 -#define GST_MATROSKA_ID_TRACKNAME 0x536E -#define GST_MATROSKA_ID_TRACKLANGUAGE 0x22B59C -#define GST_MATROSKA_ID_TRACKFLAGENABLED 0xB9 -#define GST_MATROSKA_ID_TRACKFLAGDEFAULT 0x88 -#define GST_MATROSKA_ID_TRACKFLAGLACING 0x9C -#define GST_MATROSKA_ID_TRACKMINCACHE 0x6DE7 -#define GST_MATROSKA_ID_TRACKMAXCACHE 0x6DF8 -#define GST_MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 -#define GST_MATROSKA_ID_CONTENTENCODINGS 0x6D80 - -/* IDs in the trackvideo master */ -#define GST_MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 -#define GST_MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 -#define GST_MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA -#define GST_MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 -#define GST_MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA -#define GST_MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A -#define GST_MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 -#define GST_MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 -#define GST_MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 - -/* IDs in the trackaudio master */ -#define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 -#define GST_MATROSKA_ID_AUDIOBITDEPTH 0x6264 -#define GST_MATROSKA_ID_AUDIOCHANNELS 0x9F - -/* ID in the cues master */ -#define GST_MATROSKA_ID_POINTENTRY 0xBB +/* toplevel Segment */ +#define GST_MATROSKA_ID_SEGMENT 0x18538067 + +/* matroska top-level master IDs, childs of Segment */ +#define GST_MATROSKA_ID_SEGMENTINFO 0x1549A966 +#define GST_MATROSKA_ID_TRACKS 0x1654AE6B +#define GST_MATROSKA_ID_CUES 0x1C53BB6B +#define GST_MATROSKA_ID_TAGS 0x1254C367 +#define GST_MATROSKA_ID_SEEKHEAD 0x114D9B74 +#define GST_MATROSKA_ID_CLUSTER 0x1F43B675 +#define GST_MATROSKA_ID_ATTACHMENTS 0x1941A469 +#define GST_MATROSKA_ID_CHAPTERS 0x1043A770 + +/* IDs in the SegmentInfo master */ +#define GST_MATROSKA_ID_TIMECODESCALE 0x2AD7B1 +#define GST_MATROSKA_ID_DURATION 0x4489 +#define GST_MATROSKA_ID_WRITINGAPP 0x5741 +#define GST_MATROSKA_ID_MUXINGAPP 0x4D80 +#define GST_MATROSKA_ID_DATEUTC 0x4461 +#define GST_MATROSKA_ID_SEGMENTUID 0x73A4 +#define GST_MATROSKA_ID_SEGMENTFILENAME 0x7384 +#define GST_MATROSKA_ID_PREVUID 0x3CB923 +#define GST_MATROSKA_ID_PREVFILENAME 0x3C83AB +#define GST_MATROSKA_ID_NEXTUID 0x3EB923 +#define GST_MATROSKA_ID_NEXTFILENAME 0x3E83BB +#define GST_MATROSKA_ID_TITLE 0x7BA9 +#define GST_MATROSKA_ID_SEGMENTFAMILY 0x4444 +#define GST_MATROSKA_ID_CHAPTERTRANSLATE 0x6924 + +/* IDs in the ChapterTranslate master */ +#define GST_MATROSKA_ID_CHAPTERTRANSLATEEDITIONUID 0x69FC +#define GST_MATROSKA_ID_CHAPTERTRANSLATECODEC 0x69BF +#define GST_MATROSKA_ID_CHAPTERTRANSLATEID 0x69A5 + +/* ID in the Tracks master */ +#define GST_MATROSKA_ID_TRACKENTRY 0xAE + +/* IDs in the TrackEntry master */ +#define GST_MATROSKA_ID_TRACKNUMBER 0xD7 +#define GST_MATROSKA_ID_TRACKUID 0x73C5 +#define GST_MATROSKA_ID_TRACKTYPE 0x83 +#define GST_MATROSKA_ID_TRACKAUDIO 0xE1 +#define GST_MATROSKA_ID_TRACKVIDEO 0xE0 +#define GST_MATROSKA_ID_CONTENTENCODINGS 0x6D80 +#define GST_MATROSKA_ID_CODECID 0x86 +#define GST_MATROSKA_ID_CODECPRIVATE 0x63A2 +#define GST_MATROSKA_ID_CODECNAME 0x258688 +#define GST_MATROSKA_ID_TRACKNAME 0x536E +#define GST_MATROSKA_ID_TRACKLANGUAGE 0x22B59C +#define GST_MATROSKA_ID_TRACKFLAGENABLED 0xB9 +#define GST_MATROSKA_ID_TRACKFLAGDEFAULT 0x88 +#define GST_MATROSKA_ID_TRACKFLAGFORCED 0x55AA +#define GST_MATROSKA_ID_TRACKFLAGLACING 0x9C +#define GST_MATROSKA_ID_TRACKMINCACHE 0x6DE7 +#define GST_MATROSKA_ID_TRACKMAXCACHE 0x6DF8 +#define GST_MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 +#define GST_MATROSKA_ID_TRACKTIMECODESCALE 0x23314F +#define GST_MATROSKA_ID_MAXBLOCKADDITIONID 0x55EE +#define GST_MATROSKA_ID_TRACKATTACHMENTLINK 0x7446 +#define GST_MATROSKA_ID_TRACKOVERLAY 0x6FAB +#define GST_MATROSKA_ID_TRACKTRANSLATE 0x6624 +/* semi-draft */ +#define GST_MATROSKA_ID_TRACKOFFSET 0x537F +/* semi-draft */ +#define GST_MATROSKA_ID_CODECSETTINGS 0x3A9697 +/* semi-draft */ +#define GST_MATROSKA_ID_CODECINFOURL 0x3B4040 +/* semi-draft */ +#define GST_MATROSKA_ID_CODECDOWNLOADURL 0x26B240 +/* semi-draft */ +#define GST_MATROSKA_ID_CODECDECODEALL 0xAA + +/* IDs in the TrackTranslate master */ +#define GST_MATROSKA_ID_TRACKTRANSLATEEDITIONUID 0x66FC +#define GST_MATROSKA_ID_TRACKTRANSLATECODEC 0x66BF +#define GST_MATROSKA_ID_TRACKTRANSLATETRACKID 0x66A5 + + +/* IDs in the TrackVideo master */ +/* NOTE: This one is here only for backward compatibility. + * Use _TRACKDEFAULDURATION */ +#define GST_MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 +#define GST_MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 +#define GST_MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA +#define GST_MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2 +#define GST_MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 +#define GST_MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA +#define GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM 0x54AA +#define GST_MATROSKA_ID_VIDEOPIXELCROPTOP 0x54BB +#define GST_MATROSKA_ID_VIDEOPIXELCROPLEFT 0x54CC +#define GST_MATROSKA_ID_VIDEOPIXELCROPRIGHT 0x54DD +#define GST_MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A +/* semi-draft */ +#define GST_MATROSKA_ID_VIDEOSTEREOMODE 0x53B8 +#define GST_MATROSKA_ID_VIDEOASPECTRATIOTYPE 0x54B3 +#define GST_MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 +/* semi-draft */ +#define GST_MATROSKA_ID_VIDEOGAMMAVALUE 0x2FB523 + +/* IDs in the TrackAudio master */ +#define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 +#define GST_MATROSKA_ID_AUDIOBITDEPTH 0x6264 +#define GST_MATROSKA_ID_AUDIOCHANNELS 0x9F +/* semi-draft */ +#define GST_MATROSKA_ID_AUDIOCHANNELPOSITIONS 0x7D7B +#define GST_MATROSKA_ID_AUDIOOUTPUTSAMPLINGFREQ 0x78B5 + +/* IDs in the TrackContentEncoding master */ +#define GST_MATROSKA_ID_CONTENTENCODING 0x6240 + +/* IDs in the ContentEncoding master */ +#define GST_MATROSKA_ID_CONTENTENCODINGORDER 0x5031 +#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE 0x5032 +#define GST_MATROSKA_ID_CONTENTENCODINGTYPE 0x5033 +#define GST_MATROSKA_ID_CONTENTCOMPRESSION 0x5034 +#define GST_MATROSKA_ID_CONTENTENCRYPTION 0x5035 + +/* IDs in the ContentCompression master */ +#define GST_MATROSKA_ID_CONTENTCOMPALGO 0x4254 +#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS 0x4255 + +/* IDs in the ContentEncryption master */ +#define GST_MATROSKA_ID_CONTENTENCALGO 0x47E1 +#define GST_MATROSKA_ID_CONTENTENCKEYID 0x47E2 +#define GST_MATROSKA_ID_CONTENTSIGNATURE 0x47E3 +#define GST_MATROSKA_ID_CONTENTSIGKEYID 0x47E4 +#define GST_MATROSKA_ID_CONTENTSIGALGO 0x47E5 +#define GST_MATROSKA_ID_CONTENTSIGHASHALGO 0x47E6 + +/* ID in the CUEs master */ +#define GST_MATROSKA_ID_POINTENTRY 0xBB /* IDs in the pointentry master */ -#define GST_MATROSKA_ID_CUETIME 0xB3 -#define GST_MATROSKA_ID_CUETRACKPOSITION 0xB7 - -/* IDs in the cuetrackposition master */ -#define GST_MATROSKA_ID_CUETRACK 0xF7 -#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1 - -/* IDs in the tags master */ -#define GST_MATROSKA_ID_TAG 0x7373 - -/* in the tag master */ -#define GST_MATROSKA_ID_SIMPLETAG 0x67C8 - -/* in the simpletag master */ -#define GST_MATROSKA_ID_TAGNAME 0x45A3 -#define GST_MATROSKA_ID_TAGSTRING 0x4487 - -/* IDs in the seekhead master */ -#define GST_MATROSKA_ID_SEEKENTRY 0x4DBB - -/* IDs in the seekpoint master */ -#define GST_MATROSKA_ID_SEEKID 0x53AB -#define GST_MATROSKA_ID_SEEKPOSITION 0x53AC - -/* IDs in the cluster master */ -#define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7 -#define GST_MATROSKA_ID_BLOCKGROUP 0xA0 -#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3 -#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB - -/* IDs in the blockgroup master */ -#define GST_MATROSKA_ID_BLOCK 0xA1 -#define GST_MATROSKA_ID_BLOCKDURATION 0x9B - -/* IDs in the contentencodings master */ -#define GST_MATROSKA_ID_CONTENTENCODING 0x6240 - -/* IDS IN THE CONTENTENCODING MASTER */ -#define GST_MATROSKA_ID_CONTENTENCODINGORDER 0X5031 -#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE 0X5032 -#define GST_MATROSKA_ID_CONTENTENCODINGTYPE 0X5033 -#define GST_MATROSKA_ID_CONTENTCOMPRESSION 0X5034 -#define GST_MATROSKA_ID_CONTENTENCRYPTION 0X5035 - -/* IDS IN THE CONTENTCOMPRESSION MASTER */ -#define GST_MATROSKA_ID_CONTENTCOMPALGO 0X4254 -#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS 0X4255 - +#define GST_MATROSKA_ID_CUETIME 0xB3 +#define GST_MATROSKA_ID_CUETRACKPOSITIONS 0xB7 + +/* IDs in the CueTrackPositions master */ +#define GST_MATROSKA_ID_CUETRACK 0xF7 +#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1 +#define GST_MATROSKA_ID_CUEBLOCKNUMBER 0x5378 +/* semi-draft */ +#define GST_MATROSKA_ID_CUECODECSTATE 0xEA +/* semi-draft */ +#define GST_MATROSKA_ID_CUEREFERENCE 0xDB + +/* IDs in the CueReference master */ +/* semi-draft */ +#define GST_MATROSKA_ID_CUEREFTIME 0x96 +/* semi-draft */ +#define GST_MATROSKA_ID_CUEREFCLUSTER 0x97 +/* semi-draft */ +#define GST_MATROSKA_ID_CUEREFNUMBER 0x535F +/* semi-draft */ +#define GST_MATROSKA_ID_CUEREFCODECSTATE 0xEB + +/* IDs in the Tags master */ +#define GST_MATROSKA_ID_TAG 0x7373 + +/* in the Tag master */ +#define GST_MATROSKA_ID_SIMPLETAG 0x67C8 +#define GST_MATROSKA_ID_TARGETS 0x63C0 + +/* in the SimpleTag master */ +#define GST_MATROSKA_ID_TAGNAME 0x45A3 +#define GST_MATROSKA_ID_TAGSTRING 0x4487 +#define GST_MATROSKA_ID_TAGLANGUAGE 0x447A +#define GST_MATROSKA_ID_TAGDEFAULT 0x4484 +#define GST_MATROSKA_ID_TAGBINARY 0x4485 + +/* in the Targets master */ +#define GST_MATROSKA_ID_TARGETTYPEVALUE 0x68CA +#define GST_MATROSKA_ID_TARGETTYPE 0x63CA +#define GST_MATROSKA_ID_TARGETTRACKUID 0x63C5 +#define GST_MATROSKA_ID_TARGETEDITIONUID 0x63C5 +#define GST_MATROSKA_ID_TARGETCHAPTERUID 0x63C4 +#define GST_MATROSKA_ID_TARGETATTACHMENTUID 0x63C6 + +/* IDs in the SeekHead master */ +#define GST_MATROSKA_ID_SEEKENTRY 0x4DBB + +/* IDs in the SeekEntry master */ +#define GST_MATROSKA_ID_SEEKID 0x53AB +#define GST_MATROSKA_ID_SEEKPOSITION 0x53AC + +/* IDs in the Cluster master */ +#define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7 +#define GST_MATROSKA_ID_BLOCKGROUP 0xA0 +#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3 +#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB +#define GST_MATROSKA_ID_POSITION 0xA7 +#define GST_MATROSKA_ID_PREVSIZE 0xAB +/* semi-draft */ +#define GST_MATROSKA_ID_ENCRYPTEDBLOCK 0xAF +#define GST_MATROSKA_ID_SILENTTRACKS 0x5854 + +/* IDs in the SilentTracks master */ +#define GST_MATROSKA_ID_SILENTTRACKNUMBER 0x58D7 + +/* IDs in the BlockGroup master */ +#define GST_MATROSKA_ID_BLOCK 0xA1 +#define GST_MATROSKA_ID_BLOCKDURATION 0x9B +/* semi-draft */ +#define GST_MATROSKA_ID_BLOCKVIRTUAL 0xA2 +#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB +#define GST_MATROSKA_ID_BLOCKADDITIONS 0x75A1 +#define GST_MATROSKA_ID_REFERENCEPRIORITY 0xFA +/* semi-draft */ +#define GST_MATROSKA_ID_REFERENCEVIRTUAL 0xFD +/* semi-draft */ +#define GST_MATROSKA_ID_CODECSTATE 0xA4 +#define GST_MATROSKA_ID_SLICES 0x8E + +/* IDs in the BlockAdditions master */ +#define GST_MATROSKA_ID_BLOCKMORE 0xA6 + +/* IDs in the BlockMore master */ +#define GST_MATROSKA_ID_BLOCKADDID 0xEE +#define GST_MATROSKA_ID_BLOCKADDITIONAL 0xA5 + +/* IDs in the Slices master */ +#define GST_MATROSKA_ID_TIMESLICE 0xE8 + +/* IDs in the TimeSlice master */ +#define GST_MATROSKA_ID_LACENUMBER 0xCC +/* semi-draft */ +#define GST_MATROSKA_ID_FRAMENUMBER 0xCD +/* semi-draft */ +#define GST_MATROSKA_ID_BLOCKADDITIONID 0xCB +/* semi-draft */ +#define GST_MATROSKA_ID_TIMESLICEDELAY 0xCE +#define GST_MATROSKA_ID_TIMESLICEDURATION 0xCF + +/* IDs in the Attachments master */ +#define GST_MATROSKA_ID_ATTACHEDFILE 0x61A7 + +/* IDs in the AttachedFile master */ +#define GST_MATROSKA_ID_FILEDESCRIPTION 0x467E +#define GST_MATROSKA_ID_FILENAME 0x466E +#define GST_MATROSKA_ID_FILEMIMETYPE 0x4660 +#define GST_MATROSKA_ID_FILEDATA 0x465C +#define GST_MATROSKA_ID_FILEUID 0x46AE +/* semi-draft */ +#define GST_MATROSKA_ID_FILEREFERRAL 0x4675 + +/* IDs in the Chapters master */ +#define GST_MATROSKA_ID_EDITIONENTRY 0x45B9 + +/* IDs in the EditionEntry master */ +#define GST_MATROSKA_ID_EDITIONUID 0x45BC +#define GST_MATROSKA_ID_EDITIONFLAGHIDDEN 0x45BD +#define GST_MATROSKA_ID_EDITIONFLAGDEFAULT 0x45DB +#define GST_MATROSKA_ID_EDITIONFLAGORDERED 0x45DD +#define GST_MATROSKA_ID_CHAPTERATOM 0xB6 + +/* IDs in the ChapterAtom master */ +#define GST_MATROSKA_ID_CHAPTERUID 0x73C4 +#define GST_MATROSKA_ID_CHAPTERTIMESTART 0x91 +#define GST_MATROSKA_ID_CHAPTERTIMESTOP 0x92 +#define GST_MATROSKA_ID_CHAPTERFLAGHIDDEN 0x98 +#define GST_MATROSKA_ID_CHAPTERFLAGENABLED 0x4598 +#define GST_MATROSKA_ID_CHAPTERSEGMENTUID 0x6E67 +#define GST_MATROSKA_ID_CHAPTERSEGMENTEDITIONUID 0x6EBC +#define GST_MATROSKA_ID_CHAPTERPHYSICALEQUIV 0x63C3 +#define GST_MATROSKA_ID_CHAPTERTRACK 0x8F +#define GST_MATROSKA_ID_CHAPTERDISPLAY 0x80 +#define GST_MATROSKA_ID_CHAPPROCESS 0x6944 + +/* IDs in the ChapProcess master */ +#define GST_MATROSKA_ID_CHAPPROCESSCODECID 0x6955 +#define GST_MATROSKA_ID_CHAPPROCESSPRIVATE 0x450D +#define GST_MATROSKA_ID_CHAPPROCESSCOMMAND 0x6911 + +/* IDs in the ChapProcessCommand master */ +#define GST_MATROSKA_ID_CHAPPROCESSTIME 0x6922 +#define GST_MATROSKA_ID_CHAPPROCESSDATA 0x6933 + +/* IDs in the ChapterDisplay master */ +#define GST_MATROSKA_ID_CHAPSTRING 0x85 +#define GST_MATROSKA_ID_CHAPLANGUAGE 0x437C +#define GST_MATROSKA_ID_CHAPCOUNTRY 0x437E + +/* IDs in the ChapterTrack master */ +#define GST_MATROSKA_ID_CHAPTERTRACKNUMBER 0x89 /* * Matroska Codec IDs. Strings. @@ -155,49 +327,61 @@ #define GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3 "V_MPEG4/MS/V3" #define GST_MATROSKA_CODEC_ID_VIDEO_MPEG1 "V_MPEG1" #define GST_MATROSKA_CODEC_ID_VIDEO_MPEG2 "V_MPEG2" +/* FIXME: not (yet) in the spec! */ #define GST_MATROSKA_CODEC_ID_VIDEO_MJPEG "V_MJPEG" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1 "V_REAL/RV10" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2 "V_REAL/RV20" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3 "V_REAL/RV30" #define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4 "V_REAL/RV40" #define GST_MATROSKA_CODEC_ID_VIDEO_THEORA "V_THEORA" +#define GST_MATROSKA_CODEC_ID_VIDEO_QUICKTIME "V_QUICKTIME" +#define GST_MATROSKA_CODEC_ID_VIDEO_SNOW "V_SNOW" #define GST_MATROSKA_CODEC_ID_VIDEO_DIRAC "V_DIRAC" -/* TODO: Quicktime */ - -#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1" -#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2" -#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3" -#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG" -#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT" -#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE" -#define GST_MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3" -#define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS" -#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS" -#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC" -#define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" -#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG2 "A_AAC/MPEG2/" -#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG4 "A_AAC/MPEG4/" -#define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1" -#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4 "A_REAL/28_8" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8 "A_REAL/28_8" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK "A_REAL/COOK" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR "A_REAL/SIPR" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF "A_REAL/RALF" -#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC "A_REAL/ATRC" - -/* TODO: AC3-9/10 (?), Musepack, Quicktime */ +#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1" +#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2" +#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3" +#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG" +#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT" +#define GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE" +#define GST_MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3" +#define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID9 "A_AC3/BSID9" +#define GST_MATROSKA_CODEC_ID_AUDIO_AC3_BSID10 "A_AC3/BSID10" +#define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS" +#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS" +#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC" +#define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" +#define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1" +#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4 "A_REAL/14_4" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8 "A_REAL/28_8" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK "A_REAL/COOK" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR "A_REAL/SIPR" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_RALF "A_REAL/RALF" +#define GST_MATROSKA_CODEC_ID_AUDIO_REAL_ATRC "A_REAL/ATRC" +#define GST_MATROSKA_CODEC_ID_AUDIO_AAC "A_AAC" +#define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "A_AAC/MPEG2/" +#define GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "A_AAC/MPEG4/" +#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDMC "A_QUICKTIME/QDMC" +#define GST_MATROSKA_CODEC_ID_AUDIO_QUICKTIME_QDM2 "A_QUICKTIME/QDM2" +/* Undefined for now: +#define GST_MATROSKA_CODEC_ID_AUDIO_MPC "A_MPC" +*/ + +#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII "S_TEXT/ASCII" #define GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8 "S_TEXT/UTF8" #define GST_MATROSKA_CODEC_ID_SUBTITLE_SSA "S_TEXT/SSA" #define GST_MATROSKA_CODEC_ID_SUBTITLE_ASS "S_TEXT/ASS" #define GST_MATROSKA_CODEC_ID_SUBTITLE_USF "S_TEXT/USF" #define GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB "S_VOBSUB" +#define GST_MATROSKA_CODEC_ID_SUBTITLE_BMP "S_IMAGE/BMP" /* - * Matrodka tags. Strings. + * Matroska tags. Strings. */ +/* TODO: check for other tags */ + #define GST_MATROSKA_TAG_ID_TITLE "TITLE" #define GST_MATROSKA_TAG_ID_AUTHOR "AUTHOR" #define GST_MATROSKA_TAG_ID_ALBUM "ALBUM" @@ -209,6 +393,30 @@ #define GST_MATROSKA_TAG_ID_COPYRIGHT "COPYRIGHT" /* + * TODO: add this tag & mappings + * "URL" -> GST_TAG_LOCATION + * "BPS" -> GST_TAG_BITRATE + * "BPM" -> GST_TAG_BEATS_PER_MINUTE + * "REPLAYGAIN_GAIN" -> GST_TAG_*_GAIN see http://replaygain.hydrogenaudio.org/rg_data_format.html + * "REPLAYGAIN_PEAK" -> GST_TAG_*_PEAK see http://replaygain.hydrogenaudio.org/peak_data_format.html + * "TERMS_OF_USE" -> GST_TAG_LICENSE + * "DATE_RECORDED" -> GST_TAG_DATE + * "COMPOSER" -> GST_TAG_COMPOSER + * "LEAD_PERFORMER" -> GST_TAG_PERFORMER + * "GENRE" -> GST_TAG_GENRE + * + * "TOTAL_PARTS" -> GST_TAG_TRACK_COUNT depending on target + * "PART_NUMBER" -> GST_TAG_TRACK_NUMBER depending on target + * + * "EMAIL" -> + * "ADDRESS" -> + * "FAX" -> GST_TAG_CONTACT + * "PHONE" -> + * + * TODO: maybe add custom gstreamer tags for other standard matroska tags + */ + +/* * Enumerations for various types (mapping from binary * value to what it actually means). */ @@ -219,6 +427,7 @@ typedef enum { GST_MATROSKA_TRACK_TYPE_COMPLEX = 0x3, GST_MATROSKA_TRACK_TYPE_LOGO = 0x10, GST_MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, + GST_MATROSKA_TRACK_TYPE_BUTTONS = 0x12, GST_MATROSKA_TRACK_TYPE_CONTROL = 0x20, } GstMatroskaTrackType; @@ -244,6 +453,7 @@ typedef enum { GST_MATROSKA_TRACK_ENABLED = (1<<0), GST_MATROSKA_TRACK_DEFAULT = (1<<1), GST_MATROSKA_TRACK_LACING = (1<<2), + GST_MATROSKA_TRACK_FORCED = (1<<3), GST_MATROSKA_TRACK_SHIFT = (1<<16) } GstMatroskaTrackFlags; @@ -251,6 +461,7 @@ typedef enum { GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0) } GstMatroskaVideoTrackFlags; +/* TODO: check if all fields are used */ typedef struct _GstMatroskaTrackContext { GstPad *pad; GstCaps *caps; @@ -266,6 +477,7 @@ typedef struct _GstMatroskaTrackContext { GstMatroskaTrackFlags flags; guint64 default_duration; guint64 pos; + gdouble timecodescale; gboolean set_discont; /* TRUE = set DISCONT flag on next buffer */ @@ -313,12 +525,6 @@ typedef struct _GstMatroskaTrackAudioContext { guint samplerate, channels, bitdepth; } GstMatroskaTrackAudioContext; -typedef struct _GstMatroskaTrackComplexContext { - GstMatroskaTrackContext parent; - - /* nothing special goes here, apparently */ -} GstMatroskaTrackComplexContext; - typedef struct _GstMatroskaTrackSubtitleContext { GstMatroskaTrackContext parent; @@ -357,6 +563,5 @@ typedef struct _GstMatroskaTrackEncoding { gboolean gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context); gboolean gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context); gboolean gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context); -gboolean gst_matroska_track_init_complex_context (GstMatroskaTrackContext ** p_context); #endif /* __GST_MATROSKA_IDS_H__ */ diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index dd3fbd32..d41ba0ad 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -20,6 +20,10 @@ * Boston, MA 02111-1307, USA. */ +/* TODO: - check everywhere that we don't write invalid values + * - make sure timestamps are correctly scaled everywhere + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -55,6 +59,10 @@ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src", "width = (int) [ 16, 4096 ], " \ "height = (int) [ 16, 4096 ] " +/* FIXME: + * * require codec data, etc as needed + */ + static GstStaticPadTemplate videosink_templ = GST_STATIC_PAD_TEMPLATE ("video_%d", GST_PAD_SINK, @@ -92,6 +100,7 @@ static GstStaticPadTemplate videosink_templ = /* FIXME: * * audio/x-raw-float: endianness needs defining. + * * require codec data, etc as needed */ static GstStaticPadTemplate audiosink_templ = GST_STATIC_PAD_TEMPLATE ("audio_%d", @@ -184,11 +193,6 @@ static void gst_matroska_mux_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - static const GstElementDetails gst_matroska_mux_details = - GST_ELEMENT_DETAILS ("Matroska muxer", - "Codec/Muxer", - "Muxes video/audio/subtitle streams into a matroska stream", - "Ronald Bultje <rbultje@ronald.bitfreak.net>"); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&videosink_templ)); @@ -198,7 +202,10 @@ gst_matroska_mux_base_init (gpointer g_class) gst_static_pad_template_get (&subtitlesink_templ)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_templ)); - gst_element_class_set_details (element_class, &gst_matroska_mux_details); + gst_element_class_set_details_simple (element_class, "Matroska muxer", + "Codec/Muxer", + "Muxes video/audio/subtitle streams into a matroska stream", + "Ronald Bultje <rbultje@ronald.bitfreak.net>"); GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0, "Matroska muxer"); @@ -208,12 +215,13 @@ static void gst_matroska_mux_class_init (GstMatroskaMuxClass * klass) { GObjectClass *gobject_class; + GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_matroska_mux_finalize); + gobject_class->finalize = gst_matroska_mux_finalize; gobject_class->get_property = gst_matroska_mux_get_property; gobject_class->set_property = gst_matroska_mux_set_property; @@ -246,11 +254,7 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass) static void gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class) { - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - mux->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (gstelement_class, "src"), "src"); + mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src"); gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event); gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad); @@ -301,8 +305,10 @@ static guint32 gst_matroska_mux_create_uid (void) { guint32 uid = 0; + GRand *rand = g_rand_new (); + /* FIXME: array needs locking or moved into instance structure */ while (!uid) { guint i; @@ -357,6 +363,7 @@ static void gst_matroska_mux_reset (GstElement * element) { GstMatroskaMux *mux = GST_MATROSKA_MUX (element); + GSList *walk; /* reset EBML write */ @@ -368,6 +375,7 @@ gst_matroska_mux_reset (GstElement * element) /* clean up existing streams */ while ((walk = mux->collect->data) != NULL) { GstMatroskaPad *collect_pad; + GstPad *thepad; collect_pad = (GstMatroskaPad *) walk->data; @@ -396,7 +404,7 @@ gst_matroska_mux_reset (GstElement * element) mux->index = NULL; /* reset timers */ - mux->time_scale = 1000000; + mux->time_scale = GST_MSECOND; mux->duration = 0; /* reset uid array */ @@ -463,9 +471,13 @@ static gboolean gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event) { GstMatroskaTrackContext *context; + GstMatroskaPad *collect_pad; + GstMatroskaMux *mux; + GstTagList *list; + gboolean ret; mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad)); @@ -514,12 +526,19 @@ static gboolean gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps) { GstMatroskaTrackContext *context = NULL; + GstMatroskaTrackVideoContext *videocontext; + GstMatroskaMux *mux; + GstMatroskaPad *collect_pad; + GstStructure *structure; + const gchar *mimetype; + gint width, height, pixel_width, pixel_height; + gint fps_d, fps_n; mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); @@ -578,6 +597,11 @@ skip_details: videocontext->eye_mode = GST_MATROSKA_EYE_MODE_MONO; videocontext->fourcc = 0; + /* TODO: - check if we handle all codecs by the spec, i.e. codec private + * data and other settings + * - add new formats + */ + /* find type */ if (!strcmp (mimetype, "video/x-raw-yuv")) { context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED); @@ -594,7 +618,9 @@ skip_details: || !strcmp (mimetype, "video/x-dv") || !strcmp (mimetype, "video/x-h263")) { BITMAPINFOHEADER *bih; + const GValue *codec_data; + gint size = sizeof (BITMAPINFOHEADER); bih = g_new0 (BITMAPINFOHEADER, 1); @@ -666,6 +692,7 @@ skip_details: if (codec_data != NULL) { guint8 *priv_data = NULL; + guint priv_data_size = 0; GstBuffer *codec_data_buf = g_value_peek_pointer (codec_data); @@ -735,8 +762,11 @@ xiph3_streamheader_to_codecdata (const GValue * streamheader, GstMatroskaTrackContext * context, GstBuffer ** p_buf0) { GstBuffer *buf[3]; + GArray *bufarr; + guint8 *priv_data; + guint i, offset, priv_data_size; if (streamheader == NULL) @@ -835,6 +865,7 @@ vorbis_streamheader_to_codecdata (const GValue * streamheader, } else { if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) { GstMatroskaTrackAudioContext *audiocontext; + guint8 *hdr; hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4; @@ -865,7 +896,9 @@ theora_streamheader_to_codecdata (const GValue * streamheader, GST_WARNING ("First header not a theora identification header, ignoring"); } else { GstMatroskaTrackVideoContext *videocontext; + guint fps_num, fps_denom, par_num, par_denom; + guint8 *hdr; hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2; @@ -920,11 +953,17 @@ static gboolean gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) { GstMatroskaTrackContext *context = NULL; + GstMatroskaTrackAudioContext *audiocontext; + GstMatroskaMux *mux; + GstMatroskaPad *collect_pad; + const gchar *mimetype; + gint samplerate = 0, channels = 0; + GstStructure *structure; mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); @@ -949,6 +988,11 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) audiocontext->bitdepth = 0; context->default_duration = 0; + /* TODO: - check if we handle all codecs by the spec, i.e. codec private + * data and other settings + * - add new formats + */ + if (!strcmp (mimetype, "audio/mpeg")) { gint mpegversion = 0; @@ -957,6 +1001,10 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) case 1:{ gint layer; + /* FIXME: number of samples per frame also depends on the mpegversion + * which we don't pass as a caps field + */ + gst_structure_get_int (structure, "layer", &layer); switch (layer) { case 1: @@ -980,10 +1028,12 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) break; } case 2: - context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG2 "MAIN"); + context->codec_id = + g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG2 "MAIN"); break; case 4: - context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG4 "MAIN"); + context->codec_id = + g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AAC_MPEG4 "MAIN"); break; default: return FALSE; @@ -992,6 +1042,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) return TRUE; } else if (!strcmp (mimetype, "audio/x-raw-int")) { gint endianness, width, depth; + gboolean signedness; if (!gst_structure_get_int (structure, "width", &width) || @@ -1078,7 +1129,8 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) static gboolean gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps) { - /* Consider this as boilerplate code for now. There is + /* FIXME: + * Consider this as boilerplate code for now. There is * no single subtitle creation element in GStreamer, * neither do I know how subtitling works at all. */ @@ -1101,30 +1153,36 @@ gst_matroska_mux_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * pad_name) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); + GstMatroskaMux *mux = GST_MATROSKA_MUX (element); + GstMatroskaPad *collect_pad; + GstPad *newpad = NULL; + gchar *name = NULL; + GstPadSetCapsFunction setcapsfunc = NULL; + GstMatroskaTrackContext *context = NULL; if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) { name = g_strdup_printf ("audio_%d", mux->num_a_streams++); - setcapsfunc = gst_matroska_mux_audio_pad_setcaps; + setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps); context = (GstMatroskaTrackContext *) g_new0 (GstMatroskaTrackAudioContext, 1); context->type = GST_MATROSKA_TRACK_TYPE_AUDIO; context->name = g_strdup ("Audio"); } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) { name = g_strdup_printf ("video_%d", mux->num_v_streams++); - setcapsfunc = gst_matroska_mux_video_pad_setcaps; + setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps); context = (GstMatroskaTrackContext *) g_new0 (GstMatroskaTrackVideoContext, 1); context->type = GST_MATROSKA_TRACK_TYPE_VIDEO; context->name = g_strdup ("Video"); } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) { name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++); - setcapsfunc = gst_matroska_mux_subtitle_pad_setcaps; + setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps); context = (GstMatroskaTrackContext *) g_new0 (GstMatroskaTrackSubtitleContext, 1); context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE; @@ -1138,6 +1196,8 @@ gst_matroska_mux_request_new_pad (GstElement * element, g_free (name); collect_pad = (GstMatroskaPad *) gst_collect_pads_add_pad (mux->collect, newpad, sizeof (GstMatroskaPad)); + + /* TODO: check default values for the context */ context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT; collect_pad->track = context; collect_pad->buffer = NULL; @@ -1174,12 +1234,14 @@ static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad) { GstMatroskaMux *mux; + GSList *walk; mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad)); for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) { GstCollectData *cdata = (GstCollectData *) walk->data; + GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata; if (cdata->pad == pad) { @@ -1219,8 +1281,11 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux, GstMatroskaTrackContext * context) { GstEbmlWrite *ebml = mux->ebml_write; + guint64 master; + /* TODO: check if everything necessary is written and check default values */ + /* track type goes before the type-specific stuff */ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type); @@ -1298,6 +1363,7 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux, /* FIXME: until we have a nice way of getting the codecname * out of the caps, I'm not going to enable this. Too much * (useless, double, boring) work... */ + /* TODO: Use value from tags if any */ /*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME, context->codec_name); */ gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name); @@ -1314,7 +1380,8 @@ static void gst_matroska_mux_start (GstMatroskaMux * mux) { GstEbmlWrite *ebml = mux->ebml_write; - guint32 seekhead_id[] = { GST_MATROSKA_ID_INFO, + + guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO, GST_MATROSKA_ID_TRACKS, GST_MATROSKA_ID_CUES, GST_MATROSKA_ID_SEEKHEAD, @@ -1322,11 +1389,17 @@ gst_matroska_mux_start (GstMatroskaMux * mux) 0 }; guint64 master, child; + GSList *collected; + int i; + guint tracknum = 1; + GstClockTime duration = 0; + guint32 *segment_uid = (guint32 *) g_malloc (16); + GRand *rand = g_rand_new (); GTimeVal time = { 0, 0 }; @@ -1354,7 +1427,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux) /* segment info */ mux->info_pos = ebml->pos; - master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_INFO); + master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_SEGMENTINFO); for (i = 0; i < 4; i++) { segment_uid[i] = g_rand_int (rand); } @@ -1368,8 +1441,11 @@ gst_matroska_mux_start (GstMatroskaMux * mux) for (collected = mux->collect->data; collected; collected = g_slist_next (collected)) { GstMatroskaPad *collect_pad; + GstFormat format = GST_FORMAT_TIME; + GstPad *thepad; + gint64 trackduration; collect_pad = (GstMatroskaPad *) collected->data; @@ -1406,6 +1482,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux) collected = g_slist_next (collected)) { GstMatroskaPad *collect_pad; + GstPad *thepad; collect_pad = (GstMatroskaPad *) collected->data; @@ -1429,6 +1506,7 @@ static void gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, gpointer data) { + /* TODO: more sensible tag mappings */ struct { gchar *matroska_tagname; @@ -1446,11 +1524,14 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT} }; GstEbmlWrite *ebml = (GstEbmlWrite *) data; + guint i; + guint64 simpletag_master; for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) { const gchar *tagname_gst = tag_conv[i].gstreamer_tagname; + const gchar *tagname_mkv = tag_conv[i].matroska_tagname; if (strcmp (tagname_gst, tag) == 0) { @@ -1486,9 +1567,13 @@ static void gst_matroska_mux_finish (GstMatroskaMux * mux) { GstEbmlWrite *ebml = mux->ebml_write; + guint64 pos; + guint64 duration = 0; + GSList *collected; + GstTagList *tags; /* finish last cluster */ @@ -1499,6 +1584,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) /* cues */ if (mux->index != NULL) { guint n; + guint64 master, pointentry_master, trackpos_master; mux->cues_pos = ebml->pos; @@ -1513,7 +1599,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETIME, idx->time / mux->time_scale); trackpos_master = gst_ebml_write_master_start (ebml, - GST_MATROSKA_ID_CUETRACKPOSITION); + GST_MATROSKA_ID_CUETRACKPOSITIONS); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUETRACK, idx->track); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CUECLUSTERPOSITION, idx->pos - mux->segment_master); @@ -1527,6 +1613,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) if (mux->meta_index != NULL) { guint n; + guint64 master, seekentry_master; mux->meta_pos = ebml->pos; @@ -1554,6 +1641,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) if (tags != NULL) { guint64 master_tags, master_tag; + /* TODO: maybe limit via the TARGETS id by looking at the source pad */ mux->tags_pos = ebml->pos; master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS); master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG); @@ -1618,6 +1706,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) for (collected = mux->collect->data; collected; collected = g_slist_next (collected)) { GstMatroskaPad *collect_pad; + GstClockTime min_duration; /* observed minimum duration */ collect_pad = (GstMatroskaPad *) collected->data; @@ -1650,6 +1739,13 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) gst_guint64_to_gdouble (duration) / gst_guint64_to_gdouble (mux->time_scale)); gst_ebml_write_seek (ebml, pos); + } else { + /* void'ify */ + guint64 my_pos = ebml->pos; + + gst_ebml_write_seek (ebml, mux->duration_pos); + gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 8); + gst_ebml_write_seek (ebml, my_pos); } /* finish segment - this also writes element length */ @@ -1671,6 +1767,7 @@ static GstMatroskaPad * gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped) { GSList *collected; + GstMatroskaPad *best = NULL; *popped = FALSE; @@ -1743,12 +1840,19 @@ static GstFlowReturn gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad) { GstEbmlWrite *ebml = mux->ebml_write; + GstBuffer *buf, *hdr; + guint64 cluster, blockgroup; + gboolean write_duration; + gint16 relative_timestamp; + gint64 relative_timestamp64; + guint64 block_duration; + gboolean is_video_keyframe = FALSE; /* write data */ @@ -1765,6 +1869,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad) /* hm, invalid timestamp (due to --to be fixed--- element upstream); * this would wreak havoc with time stored in matroska file */ + /* TODO: maybe calculate a timestamp by using the previous timestamp + * and default duration */ if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { GST_WARNING_OBJECT (collect_pad->collect.pad, "Invalid buffer timestamp; dropping buffer"); @@ -1871,7 +1977,7 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad) /* write the block, for matroska v2 use SimpleBlock if possible * one slice (*breath*). - * FIXME: lacing, etc. */ + * FIXME: Need to do correct lacing! */ relative_timestamp64 = GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time; if (relative_timestamp64 >= 0) { /* round the timestamp */ @@ -1926,8 +2032,11 @@ static GstFlowReturn gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) { GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data); + GstMatroskaPad *best; + gboolean popped; + GstFlowReturn ret; GST_DEBUG_OBJECT (mux, "Collected pads"); @@ -1965,6 +2074,7 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) * the actual duration later when we send an updated header on eos */ if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) { GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer); + GstClockTime end_ts = start_ts; if (GST_BUFFER_DURATION_IS_VALID (best->buffer)) @@ -2001,6 +2111,7 @@ static GstStateChangeReturn gst_matroska_mux_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; + GstMatroskaMux *mux = GST_MATROSKA_MUX (element); switch (transition) { @@ -2051,7 +2162,7 @@ gst_matroska_mux_set_property (GObject * object, break; } g_free (mux->writing_app); - mux->writing_app = g_strdup (g_value_get_string (value)); + mux->writing_app = g_value_dup_string (value); break; case ARG_MATROSKA_VERSION: mux->matroska_version = g_value_get_int (value); |