From 7c402d5866a3fcfeba2768e702a50899d7491b27 Mon Sep 17 00:00:00 2001 From: Zaheer Abbas Merali Date: Fri, 21 May 2010 13:14:04 +0100 Subject: [PATCH] matroskamux: add streamheaders --- gst/matroska/ebml-write.c | 52 +++++++++++++++++++++++++++++++++++ gst/matroska/ebml-write.h | 8 ++++++ gst/matroska/matroska-mux.c | 66 +++++++++++++++++++++++++++++++-------------- 3 files changed, 106 insertions(+), 20 deletions(-) diff --git a/gst/matroska/ebml-write.c b/gst/matroska/ebml-write.c index 2b1e2fd..b31472d 100644 --- a/gst/matroska/ebml-write.c +++ b/gst/matroska/ebml-write.c @@ -62,6 +62,9 @@ gst_ebml_write_init (GstEbmlWrite * ebml, GstEbmlWriteClass * klass) ebml->pos = 0; ebml->cache = NULL; + ebml->streamheader = NULL; + ebml->streamheader_pos = 0; + ebml->writing_streamheader = FALSE; } static void @@ -76,6 +79,11 @@ gst_ebml_write_finalize (GObject * object) ebml->cache = NULL; } + if (ebml->streamheader) { + gst_byte_writer_free (ebml->streamheader); + ebml->streamheader = NULL; + } + GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); } @@ -142,6 +150,33 @@ gst_ebml_last_write_result (GstEbmlWrite * ebml) } +void +gst_ebml_start_streamheader (GstEbmlWrite * ebml) +{ + g_return_if_fail (ebml->streamheader == NULL); + + GST_DEBUG ("Starting streamheader at %" G_GUINT64_FORMAT, ebml->pos); + ebml->streamheader = gst_byte_writer_new_with_size (1000, FALSE); + ebml->streamheader_pos = ebml->pos; + ebml->writing_streamheader = TRUE; +} + +GstBuffer * +gst_ebml_stop_streamheader (GstEbmlWrite * ebml) +{ + GstBuffer *buffer; + + if (!ebml->streamheader) + return NULL; + + buffer = gst_byte_writer_free_and_get_buffer (ebml->streamheader); + ebml->streamheader = NULL; + GST_DEBUG ("Streamheader was size %d", GST_BUFFER_SIZE (buffer)); + + ebml->writing_streamheader = FALSE; + return buffer; +} + /** * gst_ebml_write_set_cache: * @ebml: a #GstEbmlWrite. @@ -336,6 +371,10 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf) ebml->pos += data_size; /* if there's no cache, then don't push it! */ + if (ebml->writing_streamheader) { + gst_byte_writer_put_data (ebml->streamheader, GST_BUFFER_DATA (buf), + data_size); + } if (ebml->cache) { gst_byte_writer_put_data (ebml->cache, GST_BUFFER_DATA (buf), data_size); gst_buffer_unref (buf); @@ -371,6 +410,19 @@ gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos) { GstEvent *event; + if (ebml->writing_streamheader) { + GST_DEBUG ("wanting to seek to pos %" G_GUINT64_FORMAT, pos); + if (pos >= ebml->streamheader_pos && + pos <= ebml->streamheader_pos + ebml->streamheader->parent.size) { + gst_byte_writer_set_pos (ebml->streamheader, + pos - ebml->streamheader_pos); + GST_DEBUG ("seeked in streamheader to position %" G_GUINT64_FORMAT, + pos - ebml->streamheader_pos); + } else { + GST_WARNING + ("we are writing streamheader still and seek is out of bounds"); + } + } /* Cache seeking. A bit dangerous, we assume the client writer * knows what he's doing... */ if (ebml->cache) { diff --git a/gst/matroska/ebml-write.h b/gst/matroska/ebml-write.h index 26e9d9e..72ac2e1 100644 --- a/gst/matroska/ebml-write.h +++ b/gst/matroska/ebml-write.h @@ -55,6 +55,10 @@ typedef struct _GstEbmlWrite { GstFlowReturn last_write_result; gboolean need_newsegment; + + gboolean writing_streamheader; + GstByteWriter *streamheader; + guint64 streamheader_pos; } GstEbmlWrite; typedef struct _GstEbmlWriteClass { @@ -68,6 +72,10 @@ void gst_ebml_write_reset (GstEbmlWrite *ebml); GstFlowReturn gst_ebml_last_write_result (GstEbmlWrite *ebml); +/* Used to create streamheaders */ +void gst_ebml_start_streamheader (GstEbmlWrite *ebml); +GstBuffer* gst_ebml_stop_streamheader (GstEbmlWrite *ebml); + /* * Caching means that we do not push one buffer for * each element, but fill this one until a flush. diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 9a70121..1a15ee5 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2005,11 +2005,13 @@ gst_matroska_mux_start (GstMatroskaMux * mux) GstClockTime duration = 0; guint32 segment_uid[4]; GTimeVal time = { 0, 0 }; + GstBuffer *streamheader_buffer; /* we start with a EBML header */ doctype = mux->doctype; GST_INFO_OBJECT (ebml, "DocType: %s, Version: %d", doctype, mux->doctype_version); + gst_ebml_start_streamheader (ebml); gst_ebml_write_header (ebml, doctype, mux->doctype_version); /* the rest of the header is cached */ @@ -2044,30 +2046,31 @@ gst_matroska_mux_start (GstMatroskaMux * mux) gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TIMECODESCALE, mux->time_scale); mux->duration_pos = ebml->pos; /* get duration */ - 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; - thepad = collect_pad->collect.pad; + if (!mux->is_live) { + for (collected = mux->collect->data; collected; + collected = g_slist_next (collected)) { + GstMatroskaPad *collect_pad; + GstFormat format = GST_FORMAT_TIME; + GstPad *thepad; + gint64 trackduration; - /* Query the total length of the track. */ - GST_DEBUG_OBJECT (thepad, "querying peer duration"); - if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) { - GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT, - GST_TIME_ARGS (trackduration)); - if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) { - duration = (GstClockTime) trackduration; + collect_pad = (GstMatroskaPad *) collected->data; + thepad = collect_pad->collect.pad; + + /* Query the total length of the track. */ + GST_DEBUG_OBJECT (thepad, "querying peer duration"); + if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) { + GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT, + GST_TIME_ARGS (trackduration)); + if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) { + duration = (GstClockTime) trackduration; + } } } + gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION, + gst_guint64_to_gdouble (duration) / + gst_guint64_to_gdouble (mux->time_scale)); } - gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION, - gst_guint64_to_gdouble (duration) / - gst_guint64_to_gdouble (mux->time_scale)); - gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_MUXINGAPP, "GStreamer plugin version " PACKAGE_VERSION); if (mux->writing_app && mux->writing_app[0]) { @@ -2101,6 +2104,29 @@ gst_matroska_mux_start (GstMatroskaMux * mux) /* lastly, flush the cache */ gst_ebml_write_flush_cache (ebml); + streamheader_buffer = gst_ebml_stop_streamheader (ebml); + /* lets set the pad caps, which is how the buffer caps is set currently :( */ + { + GstCaps *caps; + GstStructure *s; + GValue streamheader = { 0 }; + GValue bufval = { 0 }; + if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) { + caps = gst_caps_from_string ("video/webm"); + } else { + caps = gst_caps_from_string ("video/x-matroska"); + } + s = gst_caps_get_structure (caps, 0); + g_value_init (&streamheader, GST_TYPE_ARRAY); + g_value_init (&bufval, GST_TYPE_BUFFER); + gst_value_set_buffer (&bufval, streamheader_buffer); + gst_value_array_append_value (&streamheader, &bufval); + g_value_unset (&bufval); + gst_structure_set_value (s, "streamheader", &streamheader); + g_value_unset (&streamheader); + gst_pad_set_caps (mux->srcpad, caps); + gst_caps_unref (caps); + } } static void -- 2.7.4