From a1b7eeceb168dc6b536ecedaecb8e37a90195149 Mon Sep 17 00:00:00 2001 From: Chris E Jones Date: Wed, 20 Apr 2011 15:25:58 -0400 Subject: [PATCH 01/28] auparse: implement seeking Implement seeking and seeking query. Fixes #644512 --- gst/auparse/gstauparse.c | 117 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/gst/auparse/gstauparse.c b/gst/auparse/gstauparse.c index 715acb2c2d..69e5273192 100644 --- a/gst/auparse/gstauparse.c +++ b/gst/auparse/gstauparse.c @@ -78,6 +78,9 @@ static gboolean gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * caps); static gboolean gst_au_parse_src_query (GstPad * pad, GstQuery * query); static gboolean gst_au_parse_src_event (GstPad * pad, GstEvent * event); static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_au_parse_src_convert (GstAuParse * auparse, + GstFormat src_format, gint64 srcval, GstFormat dest_format, + gint64 * destval); GST_BOILERPLATE (GstAuParse, gst_au_parse, GstElement, GST_TYPE_ELEMENT); @@ -251,7 +254,9 @@ gst_au_parse_parse_header (GstAuParse * auparse) } auparse->offset = GST_READ_UINT32_BE (head + 4); - /* Do not trust size, could be set to -1 : unknown */ + /* Do not trust size, could be set to -1 : unknown + * otherwise: filesize = size + auparse->offset + */ size = GST_READ_UINT32_BE (head + 8); auparse->encoding = GST_READ_UINT32_BE (head + 12); auparse->samplerate = GST_READ_UINT32_BE (head + 16); @@ -425,6 +430,9 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf) GstFlowReturn ret = GST_FLOW_OK; GstAuParse *auparse; gint avail, sendnow = 0; + gint64 timestamp; + gint64 duration; + gint64 offset; auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); @@ -446,7 +454,7 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf) goto out; gst_pad_push_event (auparse->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0)); } @@ -464,6 +472,7 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf) if (sendnow > 0) { GstBuffer *outbuf; const guint8 *data; + gint64 pos; ret = gst_pad_alloc_buffer_and_set_caps (auparse->srcpad, auparse->buffer_offset, sendnow, GST_PAD_CAPS (auparse->srcpad), @@ -478,6 +487,22 @@ gst_au_parse_chain (GstPad * pad, GstBuffer * buf) memcpy (GST_BUFFER_DATA (outbuf), data, sendnow); gst_adapter_flush (auparse->adapter, sendnow); + pos = auparse->buffer_offset - auparse->offset; + pos = MAX (pos, 0); + + if (auparse->sample_size > 0 && auparse->samplerate > 0) { + gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos, + GST_FORMAT_DEFAULT, &offset); + gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos, + GST_FORMAT_TIME, ×tamp); + gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, + sendnow, GST_FORMAT_TIME, &duration); + + GST_BUFFER_OFFSET (outbuf) = offset; + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + GST_BUFFER_DURATION (outbuf) = duration; + } + auparse->buffer_offset += sendnow; ret = gst_pad_push (auparse->srcpad, outbuf); @@ -517,6 +542,9 @@ gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format, /* fallthrough */ case GST_FORMAT_DEFAULT:{ switch (dest_format) { + case GST_FORMAT_DEFAULT: + *destval = srcval; + break; case GST_FORMAT_BYTES: *destval = srcval * samplesize; break; @@ -532,8 +560,8 @@ gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format, case GST_FORMAT_TIME:{ switch (dest_format) { case GST_FORMAT_BYTES: - *destval = - gst_util_uint64_scale_int (srcval, rate * samplesize, GST_SECOND); + *destval = samplesize * + gst_util_uint64_scale_int (srcval, rate, GST_SECOND); break; case GST_FORMAT_DEFAULT: *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND); @@ -581,8 +609,7 @@ gst_au_parse_src_query (GstPad * pad, GstQuery * query) len -= auparse->offset; GST_OBJECT_UNLOCK (auparse); - ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len, - format, &val); + ret = gst_au_parse_src_convert (auparse, bformat, len, format, &val); if (ret) { gst_query_set_duration (query, format, val); @@ -611,6 +638,17 @@ gst_au_parse_src_query (GstPad * pad, GstQuery * query) } break; } + case GST_QUERY_SEEKING:{ + GstFormat format; + + gst_query_parse_seeking (query, &format, NULL, NULL, NULL); + /* FIXME: query duration in 'format' + gst_query_set_seeking (query, format, TRUE, 0, duration); + */ + gst_query_set_seeking (query, format, TRUE, 0, GST_CLOCK_TIME_NONE); + ret = TRUE; + break; + } default: ret = gst_pad_query_default (pad, query); break; @@ -628,6 +666,7 @@ gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event) GstFormat format; gdouble rate; gint64 start, stop; + gboolean res; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); @@ -637,19 +676,79 @@ gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event) return FALSE; } - /* FIXME: implement seeking */ - return FALSE; + res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, start, + GST_FORMAT_BYTES, &start); + + if (stop > 0) { + res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, stop, + GST_FORMAT_BYTES, &stop); + } + + GST_INFO_OBJECT (auparse, + "seeking: %" G_GINT64_FORMAT " ... %" G_GINT64_FORMAT, start, stop); + + event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start, + stop_type, stop); + res = gst_pad_push_event (auparse->sinkpad, event); + return res; } static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event) { GstAuParse *auparse; - gboolean ret; + gboolean ret = TRUE; auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time, offset = 0; + gboolean update; + GstSegment segment; + GstEvent *new_event = NULL; + + gst_segment_init (&segment, GST_FORMAT_UNDEFINED); + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + gst_segment_set_newsegment_full (&segment, update, rate, arate, format, + start, stop, time); + + if (auparse->sample_size > 0) { + if (start > 0) { + offset = start; + start -= auparse->offset; + start = MAX (start, 0); + } + if (stop > 0) { + stop -= auparse->offset; + stop = MAX (stop, 0); + } + gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, start, + GST_FORMAT_TIME, &start); + gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, stop, + GST_FORMAT_TIME, &stop); + } + + if (auparse->srcpad) { + GST_INFO_OBJECT (auparse, + "new segment: %" GST_TIME_FORMAT " ... %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); + + new_event = gst_event_new_new_segment_full (update, rate, arate, + GST_FORMAT_TIME, start, stop, start); + + ret = gst_pad_push_event (auparse->srcpad, new_event); + } + + auparse->buffer_offset = offset; + + gst_event_unref (event); + break; + } default: ret = gst_pad_event_default (pad, event); break; From e34ab464209eefffbc46f0157a44416f5d73ee0f Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 28 Apr 2011 15:37:40 +0300 Subject: [PATCH 02/28] various: fix author tag in element details --- gst/debugutils/rndbuffersize.c | 2 +- gst/videofilter/gstgamma.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gst/debugutils/rndbuffersize.c b/gst/debugutils/rndbuffersize.c index a9ed67fb6f..41934905d7 100644 --- a/gst/debugutils/rndbuffersize.c +++ b/gst/debugutils/rndbuffersize.c @@ -113,7 +113,7 @@ gst_rnd_buffer_size_base_init (gpointer g_class) gst_element_class_set_details_simple (gstelement_class, "Random buffer size", "Testing", "pull random sized buffers", - "Stefan Kost )"); + "Stefan Kost "); } diff --git a/gst/videofilter/gstgamma.c b/gst/videofilter/gstgamma.c index 86663b6a01..5915d5a590 100644 --- a/gst/videofilter/gstgamma.c +++ b/gst/videofilter/gstgamma.c @@ -139,7 +139,8 @@ gst_gamma_base_init (gpointer g_class) gst_element_class_set_details_simple (element_class, "Video gamma correction", "Filter/Effect/Video", - "Adjusts gamma on a video stream", "Arwed v. Merkatz "); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_gamma_sink_template)); From be413185d0fc947c9cc34aa06ea7a65a6b1c7e27 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 18 May 2011 10:22:27 +0300 Subject: [PATCH 03/28] rtspsrc: use EINVAL for missing url parameter Fixes gcc warning about using uninitialized variable 'res'. --- gst/rtsp/gstrtspsrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 86ba69bf54..b42be255a5 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -5525,8 +5525,10 @@ restart: src->need_redirect = FALSE; /* can't continue without a valid url */ - if (G_UNLIKELY (src->conninfo.url == NULL)) + if (G_UNLIKELY (src->conninfo.url == NULL)) { + res = GST_RTSP_EINVAL; goto no_url; + } src->tried_url_auth = FALSE; if ((res = gst_rtsp_conninfo_connect (src, &src->conninfo, async)) < 0) From ee8aef2901eb422999d0fc1c4235a6d49ca1a599 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 18 May 2011 12:24:25 +0300 Subject: [PATCH 04/28] Automatic update of common submodule From 46dfcea to fd35073 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 46dfcea233..fd3507359e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893 +Subproject commit fd3507359e845119d199b348c7779b987cee1c45 From 4cd2dac1da66947834426d384f60831f20767f5d Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 18 May 2011 12:52:31 +0200 Subject: [PATCH 05/28] avidemux: ensure 0-padding when correcting dubious list size --- gst/avi/gstavidemux.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index e69c08c93c..5f2673b047 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -1893,14 +1893,16 @@ gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force) static inline void gst_avi_demux_roundup_list (GstAviDemux * avi, GstBuffer ** buf) { - if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) & 1)) { + gint size = GST_BUFFER_SIZE (*buf); + + if (G_UNLIKELY (size & 1)) { GstBuffer *obuf; - GST_DEBUG_OBJECT (avi, "rounding up dubious list size %d", - GST_BUFFER_SIZE (*buf)); - obuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + 1); - memcpy (GST_BUFFER_DATA (obuf), GST_BUFFER_DATA (*buf), - GST_BUFFER_SIZE (*buf)); + GST_DEBUG_OBJECT (avi, "rounding up dubious list size %d", size); + obuf = gst_buffer_new_and_alloc (size + 1); + memcpy (GST_BUFFER_DATA (obuf), GST_BUFFER_DATA (*buf), size); + /* assume 0 padding, at least makes outcome deterministic */ + (GST_BUFFER_DATA (obuf))[size] = 0; gst_buffer_replace (buf, obuf); } } From 23ecab67d62ab6627d460a704a6e147005cd0332 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 18 May 2011 16:10:07 +0300 Subject: [PATCH 06/28] Automatic update of common submodule From fd35073 to 9e5bbd5 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index fd3507359e..9e5bbd5085 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit fd3507359e845119d199b348c7779b987cee1c45 +Subproject commit 9e5bbd508588961696e70c38e764492e0312ec4c From 9d322436711d6769d7ec7b0917a7b038e3591d7a Mon Sep 17 00:00:00 2001 From: Jose Antonio Santos Cadenas Date: Wed, 18 May 2011 12:36:40 +0200 Subject: [PATCH 07/28] rtp: Fix segmentation fault processing payload buffers This commit checks if the value returned by gst_rtp_buffer_get_payload_buffer and gst_rtp_buffer_get_payload_subbuffer is NULL before using it. --- gst/rtp/gstrtpac3depay.c | 5 +++-- gst/rtp/gstrtpbvdepay.c | 2 +- gst/rtp/gstrtpg722depay.c | 2 +- gst/rtp/gstrtpg726depay.c | 9 +++++++++ gst/rtp/gstrtpgsmdepay.c | 2 +- gst/rtp/gstrtpilbcdepay.c | 2 +- gst/rtp/gstrtpmp1sdepay.c | 5 +++-- gst/rtp/gstrtpmp2tdepay.c | 5 +++-- gst/rtp/gstrtpmpvdepay.c | 8 +++++--- gst/rtp/gstrtppcmadepay.c | 12 +++++++----- gst/rtp/gstrtppcmudepay.c | 12 +++++++----- gst/rtp/gstrtpspeexdepay.c | 3 ++- 12 files changed, 43 insertions(+), 24 deletions(-) diff --git a/gst/rtp/gstrtpac3depay.c b/gst/rtp/gstrtpac3depay.c index 2ba4cefe77..cb6304e6d8 100644 --- a/gst/rtp/gstrtpac3depay.c +++ b/gst/rtp/gstrtpac3depay.c @@ -193,8 +193,9 @@ gst_rtp_ac3_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) /* We don't bother with fragmented packets yet */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); - GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d", - GST_BUFFER_SIZE (outbuf)); + if (outbuf) + GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d", + GST_BUFFER_SIZE (outbuf)); return outbuf; } diff --git a/gst/rtp/gstrtpbvdepay.c b/gst/rtp/gstrtpbvdepay.c index 3ee660ae46..1957ceeaa8 100644 --- a/gst/rtp/gstrtpbvdepay.c +++ b/gst/rtp/gstrtpbvdepay.c @@ -165,7 +165,7 @@ gst_rtp_bv_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (buf); - if (marker) { + if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } diff --git a/gst/rtp/gstrtpg722depay.c b/gst/rtp/gstrtpg722depay.c index 1e892fbc18..0815b2314a 100644 --- a/gst/rtp/gstrtpg722depay.c +++ b/gst/rtp/gstrtpg722depay.c @@ -236,7 +236,7 @@ gst_rtp_g722_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (buf); marker = gst_rtp_buffer_get_marker (buf); - if (marker) { + if (marker && outbuf) { /* mark talk spurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } diff --git a/gst/rtp/gstrtpg726depay.c b/gst/rtp/gstrtpg726depay.c index 2b36755e71..33247d0994 100644 --- a/gst/rtp/gstrtpg726depay.c +++ b/gst/rtp/gstrtpg726depay.c @@ -222,6 +222,8 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) if (depay->aal2 || depay->force_aal2) { /* AAL2, we can just copy the bytes */ outbuf = gst_rtp_buffer_get_payload_buffer (buf); + if (!outbuf) + goto bad_len; } else { guint8 *in, *out, tmp; guint len; @@ -239,6 +241,10 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (copy); gst_buffer_unref (copy); } + + if (!outbuf) + goto bad_len; + out = GST_BUFFER_DATA (outbuf); /* we need to reshuffle the bytes, input is always of the form @@ -335,6 +341,9 @@ gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) } return outbuf; + +bad_len: + return NULL; } static void diff --git a/gst/rtp/gstrtpgsmdepay.c b/gst/rtp/gstrtpgsmdepay.c index bb62c50917..ca54ea8865 100644 --- a/gst/rtp/gstrtpgsmdepay.c +++ b/gst/rtp/gstrtpgsmdepay.c @@ -136,7 +136,7 @@ gst_rtp_gsm_depay_process (GstBaseRTPDepayload * _depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (buf); - if (marker) { + if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } diff --git a/gst/rtp/gstrtpilbcdepay.c b/gst/rtp/gstrtpilbcdepay.c index 18ca426a7c..d5465c2d0a 100644 --- a/gst/rtp/gstrtpilbcdepay.c +++ b/gst/rtp/gstrtpilbcdepay.c @@ -188,7 +188,7 @@ gst_rtp_ilbc_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (buf); - if (marker) { + if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } diff --git a/gst/rtp/gstrtpmp1sdepay.c b/gst/rtp/gstrtpmp1sdepay.c index 4887c4cdea..b7063d6d3e 100644 --- a/gst/rtp/gstrtpmp1sdepay.c +++ b/gst/rtp/gstrtpmp1sdepay.c @@ -131,8 +131,9 @@ gst_rtp_mp1s_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_buffer (buf); - GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %d", - GST_BUFFER_SIZE (outbuf)); + if (outbuf) + GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %d", + GST_BUFFER_SIZE (outbuf)); return outbuf; } diff --git a/gst/rtp/gstrtpmp2tdepay.c b/gst/rtp/gstrtpmp2tdepay.c index fe6c5dee2a..4f5e7202e0 100644 --- a/gst/rtp/gstrtpmp2tdepay.c +++ b/gst/rtp/gstrtpmp2tdepay.c @@ -169,8 +169,9 @@ gst_rtp_mp2t_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) gst_rtp_buffer_get_payload_subbuffer (buf, rtpmp2tdepay->skip_first_bytes, -1); - GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %d", - GST_BUFFER_SIZE (outbuf)); + if (outbuf) + GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %d", + GST_BUFFER_SIZE (outbuf)); return outbuf; diff --git a/gst/rtp/gstrtpmpvdepay.c b/gst/rtp/gstrtpmpvdepay.c index f9786048d4..1dea39403c 100644 --- a/gst/rtp/gstrtpmpvdepay.c +++ b/gst/rtp/gstrtpmpvdepay.c @@ -176,9 +176,11 @@ gst_rtp_mpv_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, payload_header, -1); - GST_DEBUG_OBJECT (rtpmpvdepay, - "gst_rtp_mpv_depay_chain: pushing buffer of size %d", - GST_BUFFER_SIZE (outbuf)); + if (outbuf) { + GST_DEBUG_OBJECT (rtpmpvdepay, + "gst_rtp_mpv_depay_chain: pushing buffer of size %d", + GST_BUFFER_SIZE (outbuf)); + } return outbuf; } diff --git a/gst/rtp/gstrtppcmadepay.c b/gst/rtp/gstrtppcmadepay.c index 35fc0a9891..7dabc8052e 100644 --- a/gst/rtp/gstrtppcmadepay.c +++ b/gst/rtp/gstrtppcmadepay.c @@ -143,12 +143,14 @@ gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) len = gst_rtp_buffer_get_payload_len (buf); outbuf = gst_rtp_buffer_get_payload_buffer (buf); - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); + if (outbuf) { + GST_BUFFER_DURATION (outbuf) = + gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); - if (marker) { - /* mark start of talkspurt with DISCONT */ - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + if (marker) { + /* mark start of talkspurt with DISCONT */ + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + } } return outbuf; diff --git a/gst/rtp/gstrtppcmudepay.c b/gst/rtp/gstrtppcmudepay.c index fd1f1e5021..0b7e56d673 100644 --- a/gst/rtp/gstrtppcmudepay.c +++ b/gst/rtp/gstrtppcmudepay.c @@ -143,12 +143,14 @@ gst_rtp_pcmu_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) len = gst_rtp_buffer_get_payload_len (buf); outbuf = gst_rtp_buffer_get_payload_buffer (buf); - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); + if (outbuf) { + GST_BUFFER_DURATION (outbuf) = + gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); - if (marker) { - /* mark start of talkspurt with DISCONT */ - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + if (marker) { + /* mark start of talkspurt with DISCONT */ + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + } } return outbuf; diff --git a/gst/rtp/gstrtpspeexdepay.c b/gst/rtp/gstrtpspeexdepay.c index 10dea1a703..87e8a77297 100644 --- a/gst/rtp/gstrtpspeexdepay.c +++ b/gst/rtp/gstrtpspeexdepay.c @@ -212,7 +212,8 @@ gst_rtp_speex_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) /* nothing special to be done */ outbuf = gst_rtp_buffer_get_payload_buffer (buf); - GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; + if (outbuf) + GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; return outbuf; } From 165fbc368e1d036b5a9c64b5f8fabba9693378f4 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 10 May 2011 16:25:40 -0700 Subject: [PATCH 08/28] configure: Remove config script check for caca --- configure.ac | 9 --------- 1 file changed, 9 deletions(-) diff --git a/configure.ac b/configure.ac index bc17a54cfc..e7171206cc 100644 --- a/configure.ac +++ b/configure.ac @@ -813,15 +813,6 @@ dnl *** libcaca *** translit(dnm, m, l) AM_CONDITIONAL(USE_LIBCACA, true) AG_GST_CHECK_FEATURE(LIBCACA, [libcaca coloured ASCII art], cacasink, [ AG_GST_PKG_CHECK_MODULES(LIBCACA, caca) - dnl only newer versions of libcaca ship caca.pc, so try caca-config as well - if test "x$HAVE_LIBCACA" != "xyes"; then - AG_GST_CHECK_CONFIGPROG(LIBCACA, caca-config) - dnl see if it compilation works too, might not if we are cross-compiling - if test "x$HAVE_LIBCACA" = "xyes"; then - AC_CHECK_LIB([caca], [caca_init], [HAVE_LIBCACA=yes], - [HAVE_LIBCACA=no], [$LIBCACA_LIBS]) - fi - fi ]) dnl *** libdv *** From c1b100cf9cbe50dd677fddef0eba68c7a195573f Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Mon, 8 Nov 2010 14:06:15 +0100 Subject: [PATCH 09/28] deinterlace: Add support for deinterlacing using buffer caps/flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When not using the fieldanalysis element immediately upstream of deinterlace, behaviour should remain unchanged. fieldanalysis will set the caps and flags on the buffers such that they can be interpreted and acted upon to produce progressive output. There are two main modes of operation: - Passive pattern locking Passive pattern locking is a non-blocking, low-latency mode of operation that is suitable for close-to-live usage. Initially a telecine stream will be output as variable framerate with naïve timestamp adjustment. With each incoming buffer, an attempt is made to lock onto a pattern. When a lock is obtained, the src pad and output buffer caps will reflect the pattern and timestamps will be accurately interpolated between pattern repeats. This means that initially and at pattern transitions there will be short periods of inaccurate timestamping. - Active pattern locking Active pattern locking is a blocking, high-latency mode of operation that is targeted at use-cases where timestamp accuracy is paramount. Buffers will be queued until enough are present to make a lock. When locked, timestamps will be accurately interpolated between pattern repeats. Orphan fields can be dropped or deinterlaced. If no lock can be obtained, a single field might be pushed through to be deinterlaced. Locking can also be disabled or 'auto' chooses between passive and active locking modes depending on whether upstream is live. --- gst/deinterlace/gstdeinterlace.c | 1196 +++++++++++++++++++++++++----- gst/deinterlace/gstdeinterlace.h | 59 +- 2 files changed, 1075 insertions(+), 180 deletions(-) diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index ce76f720c8..0ea263b5c6 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -2,6 +2,7 @@ * GStreamer * Copyright (C) 2005 Martin Eikermann * Copyright (C) 2008-2010 Sebastian Dröge + * Copyright (C) 2011 Robert Swain * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -55,6 +56,9 @@ GST_DEBUG_CATEGORY_STATIC (deinterlace_debug); #define DEFAULT_METHOD GST_DEINTERLACE_LINEAR #define DEFAULT_FIELDS GST_DEINTERLACE_ALL #define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE_LAYOUT_AUTO +#define DEFAULT_LOCKING GST_DEINTERLACE_LOCKING_NONE +#define DEFAULT_IGNORE_OBSCURE TRUE +#define DEFAULT_DROP_ORPHANS TRUE enum { @@ -63,9 +67,73 @@ enum PROP_METHOD, PROP_FIELDS, PROP_FIELD_LAYOUT, + PROP_LOCKING, + PROP_IGNORE_OBSCURE, + PROP_DROP_ORPHANS, PROP_LAST }; +#define GST_DEINTERLACE_BUFFER_STATE_P (1<<0) +#define GST_DEINTERLACE_BUFFER_STATE_I (1<<1) +#define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2) +#define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3) +#define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4) +#define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5) +#define GST_DEINTERLACE_BUFFER_STATE_DROP (1<<6) + +#define GST_ONE \ + (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B) +#define GST_PRG \ + (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P) +#define GST_INT \ + (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M) +#define GST_DRP (GST_DEINTERLACE_BUFFER_STATE_DROP) + +#define GST_DEINTERLACE_OBSCURE_THRESHOLD 5 + +static const TelecinePattern telecine_patterns[] = { + /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */ + {"1:1", 1, 2, 1, {GST_ONE,}}, + /* 60i -> 30p or 50i -> 25p */ + {"2:2", 1, 1, 1, {GST_INT,}}, + /* 60i telecine -> 24p */ + {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}}, + {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}}, + {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}}, + + /* The following patterns are obscure and are ignored if ignore-obscure is + * set to true. If any patterns are added above this line, check and edit + * GST_DEINTERLACE_OBSCURE_THRESHOLD */ + + /* 50i Euro pulldown -> 24p */ + {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG, + GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG, + GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT, + GST_INT, GST_INT, GST_INT, GST_INT, GST_INT, + GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}}, + /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */ + {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG, + GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP, + GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}}, + /* 50i (PAL) -> 16p */ + {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP, + GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG, + GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG, + GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG, + GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}}, + /* NTSC 60i -> 18p */ + {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}}, + /* NTSC 60i -> 20p */ + {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}}, + /* NTSC 60i -> 27.5 */ + {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG, + GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT, + GST_ONE,}}, + /* PAL 50i -> 27.5 */ + {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT, + GST_INT, GST_INT, GST_INT, GST_INT,}}, +}; + static const GEnumValue methods_types[] = { {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search", "tomsmocomp"}, @@ -85,6 +153,21 @@ static const GEnumValue methods_types[] = { {0, NULL, NULL}, }; +static const GEnumValue locking_types[] = { + {GST_DEINTERLACE_LOCKING_NONE, + "No pattern locking", "none"}, + {GST_DEINTERLACE_LOCKING_AUTO, + "Choose passive/active locking depending on whether upstream is live", + "auto"}, + {GST_DEINTERLACE_LOCKING_ACTIVE, + "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.", + "active"}, + {GST_DEINTERLACE_LOCKING_PASSIVE, + "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.", + "passive"}, + {0, NULL, NULL}, +}; + #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ()) static GType @@ -160,6 +243,21 @@ gst_deinterlace_modes_get_type (void) return deinterlace_modes_type; } +#define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ()) +static GType +gst_deinterlace_locking_get_type (void) +{ + static GType deinterlace_locking_type = 0; + + if (!deinterlace_locking_type) { + deinterlace_locking_type = + g_enum_register_static ("GstDeinterlaceLocking", locking_types); + } + + return deinterlace_locking_type; +} + + #define DEINTERLACE_CAPS \ GST_VIDEO_CAPS_YUV ("{ AYUV, Y444, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }") ";" \ GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";" \ @@ -504,6 +602,51 @@ gst_deinterlace_class_init (GstDeinterlaceClass * klass) DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + /** + * GstDeinterlace:locking + * + * This selects which approach to pattern locking is used which affects + * processing latency and accuracy of timestamp adjustment for telecine + * streams. + * + * Since: 0.10.29. + * + */ + g_object_class_install_property (gobject_class, PROP_LOCKING, + g_param_spec_enum ("locking", "locking", "Pattern locking mode", + GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstDeinterlace:ignore-obscure + * + * This selects whether to ignore obscure/rare telecine patterns. + * NTSC 2:3 pulldown variants are the only really common patterns. + * + * Since: 0.10.29. + * + */ + g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE, + g_param_spec_boolean ("ignore-obscure", "ignore-obscure", + "Ignore obscure telecine patterns (only consider P, I and 2:3 " + "variants).", DEFAULT_IGNORE_OBSCURE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstDeinterlace:drop-orphans + * + * This selects whether to drop orphan fields at the beginning of telecine + * patterns in active locking mode. + * + * Since: 0.10.29. + * + */ + g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS, + g_param_spec_boolean ("drop-orphans", "drop-orphans", + "Drop orphan fields at the beginning of telecine patterns in " + "active locking mode.", DEFAULT_DROP_ORPHANS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_deinterlace_change_state); } @@ -571,7 +714,17 @@ gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass) gst_deinterlace_set_method (self, self->user_set_method_id); self->fields = DEFAULT_FIELDS; self->field_layout = DEFAULT_FIELD_LAYOUT; + self->locking = DEFAULT_LOCKING; + self->ignore_obscure = DEFAULT_IGNORE_OBSCURE; + self->drop_orphans = DEFAULT_DROP_ORPHANS; + self->low_latency = -1; + self->pattern = -1; + self->pattern_phase = -1; + self->pattern_count = 0; + self->output_count = 0; + self->pattern_base_ts = GST_CLOCK_TIME_NONE; + self->pattern_buf_dur = GST_CLOCK_TIME_NONE; self->still_frame_mode = FALSE; gst_deinterlace_reset (self); @@ -606,6 +759,12 @@ gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all) memset (self->field_history, 0, GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField)); self->history_count = 0; + memset (self->buf_states, 0, + GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY * + sizeof (GstDeinterlaceBufferState)); + self->state_count = 0; + self->pattern_lock = FALSE; + self->pattern_refresh = TRUE; if (!self->still_frame_mode && self->last_buffer) { gst_buffer_unref (self->last_buffer); @@ -650,6 +809,9 @@ gst_deinterlace_reset (GstDeinterlace * self) gst_deinterlace_reset_history (self, TRUE); gst_deinterlace_reset_qos (self); + + self->need_more = FALSE; + self->have_eos = FALSE; } static void @@ -698,6 +860,15 @@ gst_deinterlace_set_property (GObject * object, guint prop_id, case PROP_FIELD_LAYOUT: self->field_layout = g_value_get_enum (value); break; + case PROP_LOCKING: + self->locking = g_value_get_enum (value); + break; + case PROP_IGNORE_OBSCURE: + self->ignore_obscure = g_value_get_boolean (value); + break; + case PROP_DROP_ORPHANS: + self->drop_orphans = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); } @@ -726,6 +897,15 @@ gst_deinterlace_get_property (GObject * object, guint prop_id, case PROP_FIELD_LAYOUT: g_value_set_enum (value, self->field_layout); break; + case PROP_LOCKING: + g_value_set_enum (value, self->locking); + break; + case PROP_IGNORE_OBSCURE: + g_value_set_boolean (value, self->ignore_obscure); + break; + case PROP_DROP_ORPHANS: + g_value_set_boolean (value, self->drop_orphans); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); } @@ -746,6 +926,32 @@ gst_deinterlace_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self) +{ + gint state_idx; + if (self->low_latency) { + /* in low-latency mode the buffer state history contains old buffer + * states as well as the current one and perhaps some future ones. + * the current buffer's state is given by the number of field pairs + * rounded up, minus 1. the below is equivalent */ + state_idx = (self->history_count - 1) >> 1; + } else { + /* in high-latency mode state_count - 1 is the current buffer's state */ + state_idx = self->state_count - 1; + } + + self->pattern_base_ts = self->buf_states[state_idx].timestamp; + self->pattern_buf_dur = + (self->buf_states[state_idx].duration * + telecine_patterns[self->pattern].ratio_d) / + telecine_patterns[self->pattern].ratio_n; + GST_DEBUG_OBJECT (self, + "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT + " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts), + GST_TIME_ARGS (self->pattern_buf_dur)); +} + static GstBuffer * gst_deinterlace_pop_history (GstDeinterlace * self) { @@ -759,6 +965,21 @@ gst_deinterlace_pop_history (GstDeinterlace * self) buffer = self->field_history[self->history_count - 1].buf; self->history_count--; + if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count + || GST_BUFFER_DATA (buffer) != + GST_BUFFER_DATA (self->field_history[self->history_count - 1].buf))) { + if (!self->low_latency) + self->state_count--; + if (self->pattern_lock) { + self->pattern_count++; + if (self->pattern != -1 + && self->pattern_count >= telecine_patterns[self->pattern].length) { + self->pattern_count = 0; + self->output_count = 0; + gst_deinterlace_update_pattern_timestamps (self); + } + } + } GST_DEBUG_OBJECT (self, "Returning buffer: %p %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT " and size %u", buffer, @@ -768,6 +989,78 @@ gst_deinterlace_pop_history (GstDeinterlace * self) return buffer; } +typedef enum +{ + GST_DEINTERLACE_PROGRESSIVE, + GST_DEINTERLACE_INTERLACED, + GST_DEINTERLACE_TELECINE, +} GstDeinterlaceInterlacingMethod; + +static GstDeinterlaceInterlacingMethod +gst_deinterlace_get_interlacing_method (const GstCaps * caps) +{ + GstDeinterlaceInterlacingMethod method = 0; + gboolean interlaced; + + /* check interlaced cap */ + gst_structure_get_boolean (gst_caps_get_structure (caps, 0), "interlaced", + &interlaced); + + method = + interlaced ? GST_DEINTERLACE_INTERLACED : GST_DEINTERLACE_PROGRESSIVE; + + if (method == GST_DEINTERLACE_INTERLACED) { + const gchar *temp = + gst_structure_get_string (gst_caps_get_structure (caps, 0), + "interlacing-method"); + if (temp && g_str_equal (temp, "telecine")) + method = GST_DEINTERLACE_TELECINE; + } + + return method; +} + +static void +gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstBuffer * buffer, + guint8 * state, GstDeinterlaceInterlacingMethod * i_method) +{ + GstDeinterlaceInterlacingMethod interlacing_method; + + if (!(i_method || state)) + return; + + interlacing_method = + gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (buffer)); + + if (state) { + if (interlacing_method == GST_DEINTERLACE_TELECINE) { + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF)) { + *state = GST_DEINTERLACE_BUFFER_STATE_DROP; + } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD)) { + /* tc top if tff, tc bottom otherwise */ + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF)) { + *state = GST_DEINTERLACE_BUFFER_STATE_TC_T; + } else { + *state = GST_DEINTERLACE_BUFFER_STATE_TC_B; + } + } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_PROGRESSIVE)) { + *state = GST_DEINTERLACE_BUFFER_STATE_TC_P; + } else { + *state = GST_DEINTERLACE_BUFFER_STATE_TC_M; + } + } else { + if (interlacing_method == GST_DEINTERLACE_INTERLACED) { + *state = GST_DEINTERLACE_BUFFER_STATE_I; + } else { + *state = GST_DEINTERLACE_BUFFER_STATE_P; + } + } + } + + if (i_method) + *i_method = interlacing_method; +} + static void gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer) { @@ -781,14 +1074,47 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer) GstBuffer *field1, *field2; guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3; gint field1_flags, field2_flags; + GstDeinterlaceInterlacingMethod interlacing_method; + guint8 buf_state; g_return_if_fail (self->history_count < GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push); - GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT - " with duration %" GST_TIME_FORMAT " and size %u", + gst_deinterlace_get_buffer_state (self, buffer, &buf_state, + &interlacing_method); + + GST_DEBUG_OBJECT (self, + "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT + " with duration %" GST_TIME_FORMAT + ", size %u, state %u, interlacing method %d", GST_BUFFER_DATA (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer)); + GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer), + buf_state, + interlacing_method == + GST_DEINTERLACE_TELECINE ? "TC" : interlacing_method == + GST_DEINTERLACE_INTERLACED ? "I" : "P"); + + /* move up for new state */ + memmove (&self->buf_states[1], &self->buf_states[0], + (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) * + sizeof (GstDeinterlaceBufferState)); + self->buf_states[0].state = buf_state; + self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer); + self->buf_states[0].duration = GST_BUFFER_DURATION (buffer); + if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY) + self->state_count++; + + if (buf_state == GST_DEINTERLACE_BUFFER_STATE_DROP) { + GST_DEBUG_OBJECT (self, + "Buffer contains only unneeded repeated fields, dropping and not" + "adding to field history"); + gst_buffer_unref (buffer); + return; + } + + /* telecine does not make use of repeated fields */ + if (interlacing_method == GST_DEINTERLACE_TELECINE) + repeated = FALSE; for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) { self->field_history[i].buf = self->field_history[i - fields_to_push].buf; @@ -821,12 +1147,16 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer) field2_flags = PICTURE_INTERLACED_TOP; } - /* Timestamps are assigned to the field buffers under the assumption that - the timestamp of the buffer equals the first fields timestamp */ + if (interlacing_method != GST_DEINTERLACE_TELECINE) { + /* Timestamps are assigned to the field buffers under the assumption that + the timestamp of the buffer equals the first fields timestamp */ - timestamp = GST_BUFFER_TIMESTAMP (buffer); - GST_BUFFER_TIMESTAMP (field1) = timestamp; - GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration; + timestamp = GST_BUFFER_TIMESTAMP (buffer); + GST_BUFFER_TIMESTAMP (field1) = timestamp; + GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration; + if (repeated) + GST_BUFFER_TIMESTAMP (field2) += self->field_duration; + } if (repeated) { self->field_history[2].buf = field1; @@ -943,84 +1273,553 @@ gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp) return TRUE; } +static gboolean +gst_deinterlace_fix_timestamps (GstDeinterlace * self, + GstDeinterlaceField * field1, GstDeinterlaceField * field2) +{ + GstDeinterlaceField *field3, *field4; + GstDeinterlaceInterlacingMethod interlacing_method; + + if (self->pattern_lock && self->pattern > -1) { + /* accurate pattern-locked timestamp adjustment */ + if (!self->pattern_count) + gst_deinterlace_update_pattern_timestamps (self); + + GST_BUFFER_TIMESTAMP (field1->buf) = + self->pattern_base_ts + self->output_count * self->pattern_buf_dur; + GST_BUFFER_DURATION (field1->buf) = self->pattern_buf_dur; + self->output_count++; + } else { + /* naive (but low-latency) timestamp adjustment based on subsequent + * fields/buffers */ + if (field2 + && GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) { + if (GST_BUFFER_TIMESTAMP (field1->buf) + + GST_BUFFER_DURATION (field1->buf) == + GST_BUFFER_TIMESTAMP (field2->buf)) { + GST_BUFFER_TIMESTAMP (field1->buf) = + GST_BUFFER_TIMESTAMP (field2->buf) = + (GST_BUFFER_TIMESTAMP (field1->buf) + + GST_BUFFER_TIMESTAMP (field2->buf)) / 2; + } else { + GST_BUFFER_TIMESTAMP (field2->buf) = GST_BUFFER_TIMESTAMP (field1->buf); + } + } + + if (self->history_count < 3) { + GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)", + self->history_count); + return FALSE; + } + + field3 = &self->field_history[self->history_count - 3]; + interlacing_method = + gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (field3->buf)); + if (interlacing_method == GST_DEINTERLACE_TELECINE) { + if (self->history_count < 4) { + GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)", + self->history_count); + return FALSE; + } + + field4 = &self->field_history[self->history_count - 4]; + if (GST_BUFFER_DATA (field3->buf) != GST_BUFFER_DATA (field4->buf)) { + /* telecine fields in separate buffers */ + GST_BUFFER_TIMESTAMP (field3->buf) = + (GST_BUFFER_TIMESTAMP (field3->buf) + + GST_BUFFER_TIMESTAMP (field4->buf)) / 2; + } + } + + GST_BUFFER_DURATION (field1->buf) = + GST_BUFFER_TIMESTAMP (field3->buf) - GST_BUFFER_TIMESTAMP (field1->buf); + } + + GST_DEBUG_OBJECT (self, + "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buf))); + return TRUE; +} + +static void +gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one) +{ + /* loop over all possible patterns and all possible phases + * giving each a score. the highest score gets the lock */ + /* the score is calculated as the number of matched buffers in the + * sequence starting at the phase offset with those from the history + * then the longest duration pattern match is taken. if there is more than + * one pattern matching all buffers, we take the longest pattern of those. + * matches to complete patterns are preferred. if no non-trivial pattern is + * matched, trivial patterns are tested. */ + gint i, j, k, score, pattern, phase; + const gint state_count = self->state_count; + const gint n_required = self->ignore_obscure ? + GST_DEINTERLACE_OBSCURE_THRESHOLD : + GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY; + + /* set unknown pattern as this is used in logic outside this function */ + self->pattern = -1; + + /* wait for more buffers */ + if (!self->have_eos && state_count < n_required) { + GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d", + state_count, n_required); + return; + } + + score = pattern = phase = -1; + + /* loop over all patterns */ + for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) { + const guint8 length = telecine_patterns[i].length; + + if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD) + break; + + if (state_count < length) + continue; + + /* loop over all phases */ + for (j = 0; j < length; j++) { + /* low-latency mode looks at past buffers, high latency at future buffers */ + const gint state_idx = (self->low_latency ? length : state_count) - 1; + /* loop over history, breaking on differing buffer states */ + for (k = 0; k < length && k < state_count; k++) { + const guint8 hist = self->buf_states[state_idx - k].state; + const guint8 patt = telecine_patterns[i].states[(j + k) % length]; + if (!(hist & patt)) + break; + } + + /* make complete matches more signficant */ + if (k == length) + k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY; + + /* take as new best pattern if the number of matched buffers is more than + * for other patterns */ + if (k > score) { + score = k; + pattern = i; + phase = j; + if (self->low_latency) { + /* state_idx + 1 is the number of buffers yet to be pushed out + * so length - state_idx - 1 is the number of old buffers in the + * pattern */ + phase = (phase + length - state_idx - 1) % length; + } + } + } + } + + GST_DEBUG_OBJECT (self, + "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase, + telecine_patterns[pattern].length, score); + self->pattern = pattern; + self->pattern_phase = phase; + self->pattern_count = 0; + self->output_count = 0; + self->pattern_lock = TRUE; + + /* check for the case that the first field of the pattern is an orphan */ + if (pattern > 1 + && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) { + gint i = phase, field_count = 0; + guint8 state = telecine_patterns[pattern].states[i]; + + do { + if (state & GST_ONE) { + field_count++; + } else if (!(state & GST_DRP)) { + field_count += 2; + } + i++; + i %= telecine_patterns[pattern].length; + state = telecine_patterns[pattern].states[i]; + } while (!(state & GST_PRG)); + + /* if field_count is odd, we have an orphan field at the beginning of the + * sequence + * note - don't do this in low-latency mode as we are somewhere within the + * pattern already */ + if (!self->low_latency && (*flush_one = field_count & 1)) { + GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the " + "pattern - it will be deinterlaced."); + } + } +} + static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing) { GstClockTime timestamp; - GstFlowReturn ret = GST_FLOW_OK; - gint fields_required = 0; - gint cur_field_idx = 0; + GstFlowReturn ret; + gint fields_required; + gint cur_field_idx; GstBuffer *buf, *outbuf; + GstDeinterlaceField *field1, *field2; + GstDeinterlaceInterlacingMethod interlacing_method; + guint8 buf_state; + gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */ + gboolean same_buffer; /* are field1 and field2 in the same buffer? */ + gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */ + TelecinePattern pattern; + guint8 phase, count; + const GstDeinterlaceLocking locking = self->locking; - gst_deinterlace_set_method (self, self->user_set_method_id); - fields_required = gst_deinterlace_method_get_fields_required (self->method); +restart: + ret = GST_FLOW_OK; + fields_required = 0; + cur_field_idx = 0; + hl_no_lock = FALSE; + same_buffer = FALSE; + flush_one = FALSE; + self->need_more = FALSE; + phase = self->pattern_phase; + count = self->pattern_count; - if (self->history_count < fields_required) { - if (flushing) { - /* FIXME: if there are any methods implemented that output different - * dimensions (e.g. half height) that require more than one field of - * history, it is desirable to degrade to something that outputs - * half-height also */ - gst_deinterlace_set_method (self, - self->history_count >= 2 ? - GST_DEINTERLACE_VFIR : GST_DEINTERLACE_LINEAR); + if (!self->history_count) { + GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!"); + goto need_more; + } + + field1 = &self->field_history[self->history_count - 1]; + + if (locking != GST_DEINTERLACE_LOCKING_NONE) { + if (!self->state_count) { + GST_ERROR_OBJECT (self, + "BROKEN! Fields in history + no states should not happen!"); + return GST_FLOW_ERROR; + } + + gst_deinterlace_get_buffer_state (self, field1->buf, &buf_state, + &interlacing_method); + + if (self->pattern != -1) + pattern = telecine_patterns[self->pattern]; + + /* patterns 0 and 1 are interlaced, the rest are telecine */ + if (self->pattern > 1) + interlacing_method = GST_DEINTERLACE_TELECINE; + + if (self->pattern == -1 || self->pattern_refresh + || !(buf_state & pattern.states[(phase + count) % pattern.length])) { + /* no pattern, pattern refresh set or unexpected buffer state */ + self->pattern_lock = FALSE; + self->pattern_refresh = TRUE; + + /* refresh pattern lock */ + gst_deinterlace_get_pattern_lock (self, &flush_one); + + if (self->pattern != -1) { + /* locked onto a valid pattern so refresh complete */ + GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d", + telecine_patterns[self->pattern].nick, self->pattern_phase); + self->pattern_refresh = FALSE; + } else if (!self->low_latency) { + if (!self->pattern_lock) { + goto need_more; + } else { + hl_no_lock = TRUE; + } + } + + /* setcaps on sink and src pads */ + gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad)); + + if (flush_one && self->drop_orphans) { + GST_DEBUG_OBJECT (self, "Dropping orphan first field"); + gst_buffer_unref (gst_deinterlace_pop_history (self)); + goto restart; + } + } + } else { + gst_deinterlace_get_buffer_state (self, field1->buf, NULL, + &interlacing_method); + } + + same_buffer = self->history_count >= 2 + && (GST_BUFFER_DATA (field1->buf) == + GST_BUFFER_DATA (self->field_history[self->history_count - 2].buf)); + + if ((flushing && self->history_count == 1) || (flush_one + && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1 + || !same_buffer))) { + GST_DEBUG_OBJECT (self, "Flushing one field using linear method"); + gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR); + fields_required = gst_deinterlace_method_get_fields_required (self->method); + } else if (interlacing_method == GST_DEINTERLACE_TELECINE + && (self->low_latency > 0 || self->pattern != -1 || (hl_no_lock + && same_buffer + && GST_BUFFER_FLAG_IS_SET (field1->buf, + GST_VIDEO_BUFFER_PROGRESSIVE)))) { + /* telecined - we reconstruct frames by weaving pairs of fields */ + fields_required = 2; + if (!flushing && self->history_count < fields_required) { + GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)", + self->history_count, fields_required); + goto need_more; + } + + field2 = &self->field_history[self->history_count - 2]; + if (!gst_deinterlace_fix_timestamps (self, field1, field2) && !flushing) + goto need_more; + + if (same_buffer) { + /* telecine progressive */ + GstBuffer *field1_buf; + + GST_DEBUG_OBJECT (self, + "Frame type: Telecine Progressive; pushing buffer as a frame"); + /* pop and push */ + field1_buf = gst_deinterlace_pop_history (self); + /* field2 is the same buffer as field1, but we need to remove it from + * the history anyway */ + gst_buffer_unref (gst_deinterlace_pop_history (self)); + /* set the caps from the src pad on the buffer as they should be correct */ + gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad)); + GST_DEBUG_OBJECT (self, + "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) + + GST_BUFFER_DURATION (field1_buf))); + return gst_pad_push (self->srcpad, field1_buf); + } else { + /* telecine fields in separate buffers */ + + /* check field1 and field2 buffer caps and flags are corresponding */ + if (field1->flags == field2->flags) { + /* ERROR - fields are of same parity - what should be done here? + * perhaps deinterlace the tip field and start again? */ + GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!"); + } + GST_DEBUG_OBJECT (self, + "Frame type: Telecine Mixed; weaving tip two fields into a frame"); + /* set method to WEAVE */ + gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE); + } + } else if (interlacing_method == GST_DEINTERLACE_INTERLACED || (hl_no_lock + && interlacing_method == GST_DEINTERLACE_TELECINE && same_buffer + && !GST_BUFFER_FLAG_IS_SET (field1->buf, + GST_VIDEO_BUFFER_PROGRESSIVE))) { + gst_deinterlace_set_method (self, self->user_set_method_id); + fields_required = gst_deinterlace_method_get_fields_required (self->method); + if (flushing && self->history_count < fields_required) { + /* note: we already checked for flushing with history count == 1 above + * so we must have 2 or more fields in here */ + gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR); fields_required = gst_deinterlace_method_get_fields_required (self->method); GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method", methods_types[self->method_id].value_nick); - } else { - /* Not enough fields in the history */ + } + + /* Not enough fields in the history */ + if (self->history_count < fields_required) { GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)", self->history_count, fields_required); - return GST_FLOW_OK; + goto need_more; + } + + GST_DEBUG_OBJECT (self, + "Frame type: Interlaced; deinterlacing using %s method", + methods_types[self->method_id].value_nick); + } else { + GstBuffer *field1_buf; + + /* progressive */ + fields_required = 2; + + /* Not enough fields in the history */ + if (self->history_count < fields_required) { + GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)", + self->history_count, fields_required); + goto need_more; + } + + field2 = &self->field_history[self->history_count - 2]; + if (GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) { + /* ERROR - next two fields in field history are not one progressive buffer - weave? */ + GST_ERROR_OBJECT (self, + "Progressive buffer but two fields at tip aren't in the same buffer!"); + } + + GST_DEBUG_OBJECT (self, + "Frame type: Progressive; pushing buffer as a frame"); + /* pop and push */ + field1_buf = gst_deinterlace_pop_history (self); + /* field2 is the same buffer as field1, but we need to remove it from the + * history anyway */ + gst_buffer_unref (gst_deinterlace_pop_history (self)); + GST_DEBUG_OBJECT (self, + "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) + + GST_BUFFER_DURATION (field1_buf))); + return gst_pad_push (self->srcpad, field1_buf); + } + + if (self->fields == GST_DEINTERLACE_ALL + || interlacing_method == GST_DEINTERLACE_TELECINE) + GST_DEBUG_OBJECT (self, "All fields"); + else if (self->fields == GST_DEINTERLACE_TF) + GST_DEBUG_OBJECT (self, "Top fields"); + else if (self->fields == GST_DEINTERLACE_BF) + GST_DEBUG_OBJECT (self, "Bottom fields"); + + cur_field_idx = self->history_count - fields_required; + + if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP + && (self->fields == GST_DEINTERLACE_TF + || interlacing_method == GST_DEINTERLACE_TELECINE)) + || self->fields == GST_DEINTERLACE_ALL) { + GST_DEBUG_OBJECT (self, "deinterlacing top field"); + + /* create new buffer */ + ret = + gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE, + self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf); + if (ret != GST_FLOW_OK) + return ret; + + if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) && + !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad), + GST_BUFFER_CAPS (outbuf))) { + gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf)); + GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT, + self->request_caps); + + gst_buffer_unref (outbuf); + outbuf = gst_buffer_try_new_and_alloc (self->frame_size); + + if (!outbuf) + return GST_FLOW_ERROR; + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); + } + + g_return_val_if_fail (self->history_count - 1 - + gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR); + + buf = + self->field_history[self->history_count - 1 - + gst_deinterlace_method_get_latency (self->method)].buf; + + if (interlacing_method != GST_DEINTERLACE_TELECINE) { + timestamp = GST_BUFFER_TIMESTAMP (buf); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + if (self->fields == GST_DEINTERLACE_ALL) + GST_BUFFER_DURATION (outbuf) = self->field_duration; + else + GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration; + } else { + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); + GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); + } + + /* Check if we need to drop the frame because of QoS */ + if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) { + gst_buffer_unref (gst_deinterlace_pop_history (self)); + gst_buffer_unref (outbuf); + outbuf = NULL; + ret = GST_FLOW_OK; + } else { + /* do magic calculus */ + gst_deinterlace_method_deinterlace_frame (self->method, + self->field_history, self->history_count, outbuf); + + gst_buffer_unref (gst_deinterlace_pop_history (self)); + + if (gst_deinterlace_clip_buffer (self, outbuf)) { + GST_DEBUG_OBJECT (self, + "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) + + GST_BUFFER_DURATION (outbuf))); + ret = gst_pad_push (self->srcpad, outbuf); + } else { + ret = GST_FLOW_OK; + gst_buffer_unref (outbuf); + } + + outbuf = NULL; + if (ret != GST_FLOW_OK) + return ret; + if (interlacing_method == GST_DEINTERLACE_TELECINE + && self->method_id == GST_DEINTERLACE_WEAVE) { + /* pop off the second field */ + GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)", + self->history_count); + gst_buffer_unref (gst_deinterlace_pop_history (self)); + interlacing_method = GST_DEINTERLACE_INTERLACED; + return ret; + } + } + + if (flush_one && !self->drop_orphans) { + GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring"); + goto restart; + } + } + /* no calculation done: remove excess field */ + else if (self->field_history[cur_field_idx].flags == + PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF + && interlacing_method != GST_DEINTERLACE_TELECINE)) { + GST_DEBUG_OBJECT (self, "Removing unused top field"); + gst_buffer_unref (gst_deinterlace_pop_history (self)); + + if (flush_one && !self->drop_orphans) { + GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring"); + goto restart; } } - while (self->history_count >= fields_required) { - if (self->fields == GST_DEINTERLACE_ALL) - GST_DEBUG_OBJECT (self, "All fields"); - else if (self->fields == GST_DEINTERLACE_TF) - GST_DEBUG_OBJECT (self, "Top fields"); - else if (self->fields == GST_DEINTERLACE_BF) - GST_DEBUG_OBJECT (self, "Bottom fields"); + cur_field_idx = self->history_count - fields_required; + if (self->history_count < fields_required) + return ret; - cur_field_idx = self->history_count - fields_required; + /* deinterlace bottom_field */ + if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM + && (self->fields == GST_DEINTERLACE_BF + || interlacing_method == GST_DEINTERLACE_TELECINE)) + || self->fields == GST_DEINTERLACE_ALL) { + GST_DEBUG_OBJECT (self, "deinterlacing bottom field"); - if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP - && self->fields == GST_DEINTERLACE_TF) || - self->fields == GST_DEINTERLACE_ALL) { - GST_DEBUG_OBJECT (self, "deinterlacing top field"); + /* create new buffer */ + ret = + gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE, + self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf); + if (ret != GST_FLOW_OK) + return ret; - /* create new buffer */ - ret = - gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE, - self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf); - if (ret != GST_FLOW_OK) - return ret; + if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) && + !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad), + GST_BUFFER_CAPS (outbuf))) { + gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf)); + GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT, + self->request_caps); - if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) - && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad), - GST_BUFFER_CAPS (outbuf))) { - gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf)); - GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT, - self->request_caps); + gst_buffer_unref (outbuf); + outbuf = gst_buffer_try_new_and_alloc (self->frame_size); - gst_buffer_unref (outbuf); - outbuf = gst_buffer_try_new_and_alloc (self->frame_size); + if (!outbuf) + return GST_FLOW_ERROR; - if (!outbuf) - return GST_FLOW_ERROR; + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); + } - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); - } + g_return_val_if_fail (self->history_count - 1 - + gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR); - g_return_val_if_fail (self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method) >= 0, - GST_FLOW_ERROR); - - buf = - self->field_history[self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method)].buf; + buf = + self->field_history[self->history_count - 1 - + gst_deinterlace_method_get_latency (self->method)].buf; + if (interlacing_method != GST_DEINTERLACE_TELECINE) { timestamp = GST_BUFFER_TIMESTAMP (buf); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; @@ -1028,127 +1827,111 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing) GST_BUFFER_DURATION (outbuf) = self->field_duration; else GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration; - - /* Check if we need to drop the frame because of QoS */ - if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) { - gst_buffer_unref (gst_deinterlace_pop_history (self)); - gst_buffer_unref (outbuf); - outbuf = NULL; - ret = GST_FLOW_OK; - } else { - /* do magic calculus */ - gst_deinterlace_method_deinterlace_frame (self->method, - self->field_history, self->history_count, outbuf); - - gst_buffer_unref (gst_deinterlace_pop_history (self)); - - if (gst_deinterlace_clip_buffer (self, outbuf)) { - ret = gst_pad_push (self->srcpad, outbuf); - } else { - ret = GST_FLOW_OK; - gst_buffer_unref (outbuf); - } - - outbuf = NULL; - if (ret != GST_FLOW_OK) - return ret; - } + } else { + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); + GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); } - /* no calculation done: remove excess field */ - else if (self->field_history[cur_field_idx].flags == - PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE_BF) { - GST_DEBUG_OBJECT (self, "Removing unused top field"); + + /* Check if we need to drop the frame because of QoS */ + if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) { gst_buffer_unref (gst_deinterlace_pop_history (self)); - } + gst_buffer_unref (outbuf); + outbuf = NULL; + ret = GST_FLOW_OK; + } else { + /* do magic calculus */ + gst_deinterlace_method_deinterlace_frame (self->method, + self->field_history, self->history_count, outbuf); - cur_field_idx = self->history_count - fields_required; - if (self->history_count < fields_required) - break; + gst_buffer_unref (gst_deinterlace_pop_history (self)); - /* deinterlace bottom_field */ - if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM - && self->fields == GST_DEINTERLACE_BF) || - self->fields == GST_DEINTERLACE_ALL) { - GST_DEBUG_OBJECT (self, "deinterlacing bottom field"); + if (gst_deinterlace_clip_buffer (self, outbuf)) { + GST_DEBUG_OBJECT (self, + "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) + + GST_BUFFER_DURATION (outbuf))); + ret = gst_pad_push (self->srcpad, outbuf); + } else { + ret = GST_FLOW_OK; + gst_buffer_unref (outbuf); + } - /* create new buffer */ - ret = - gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE, - self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf); + outbuf = NULL; if (ret != GST_FLOW_OK) return ret; - - if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) - && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad), - GST_BUFFER_CAPS (outbuf))) { - gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf)); - GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT, - self->request_caps); - - gst_buffer_unref (outbuf); - outbuf = gst_buffer_try_new_and_alloc (self->frame_size); - - if (!outbuf) - return GST_FLOW_ERROR; - - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); - } - - g_return_val_if_fail (self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method) >= 0, - GST_FLOW_ERROR); - - buf = - self->field_history[self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method)].buf; - timestamp = GST_BUFFER_TIMESTAMP (buf); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - if (self->fields == GST_DEINTERLACE_ALL) - GST_BUFFER_DURATION (outbuf) = self->field_duration; - else - GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration; - - /* Check if we need to drop the frame because of QoS */ - if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) { + if (interlacing_method == GST_DEINTERLACE_TELECINE + && self->method_id == GST_DEINTERLACE_WEAVE) { + /* pop off the second field */ + GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)", + self->history_count); gst_buffer_unref (gst_deinterlace_pop_history (self)); - gst_buffer_unref (outbuf); - outbuf = NULL; - ret = GST_FLOW_OK; - } else { - /* do magic calculus */ - gst_deinterlace_method_deinterlace_frame (self->method, - self->field_history, self->history_count, outbuf); - - gst_buffer_unref (gst_deinterlace_pop_history (self)); - - if (gst_deinterlace_clip_buffer (self, outbuf)) { - ret = gst_pad_push (self->srcpad, outbuf); - } else { - ret = GST_FLOW_OK; - gst_buffer_unref (outbuf); - } - - outbuf = NULL; - if (ret != GST_FLOW_OK) - return ret; + interlacing_method = GST_DEINTERLACE_INTERLACED; + return ret; } } - /* no calculation done: remove excess field */ - else if (self->field_history[cur_field_idx].flags == - PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) { - GST_DEBUG_OBJECT (self, "Removing unused bottom field"); - gst_buffer_unref (gst_deinterlace_pop_history (self)); + + if (flush_one && !self->drop_orphans) { + GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring"); + goto restart; + } + } + /* no calculation done: remove excess field */ + else if (self->field_history[cur_field_idx].flags == + PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF + && interlacing_method != GST_DEINTERLACE_TELECINE)) { + GST_DEBUG_OBJECT (self, "Removing unused bottom field"); + gst_buffer_unref (gst_deinterlace_pop_history (self)); + + if (flush_one && !self->drop_orphans) { + GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring"); + goto restart; } } return ret; + +need_more: + self->need_more = TRUE; + return ret; +} + +static gboolean +gst_deinterlace_get_latency (GstDeinterlace * self) +{ + if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) { + gboolean res; + GstQuery *query; + + query = gst_query_new_latency (); + if ((res = gst_pad_peer_query (self->sinkpad, query))) { + gboolean is_live; + /* if upstream is live, we use low-latency passive locking mode + * else high-latency active locking mode */ + gst_query_parse_latency (query, &is_live, NULL, NULL); + GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s", + is_live ? "live - using passive locking" : + "not live - using active locking"); + gst_query_unref (query); + return is_live; + } else { + /* conservatively use passive locking if the query fails */ + GST_WARNING_OBJECT (self, + "Latency query failed - fall back to using passive locking"); + gst_query_unref (query); + return TRUE; + } + } else { + return self->locking - 2; + } } static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buf) { GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad)); + GstFlowReturn ret = GST_FLOW_OK; GST_OBJECT_LOCK (self); if (self->reconfigure) { @@ -1166,8 +1949,23 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf) GST_OBJECT_UNLOCK (self); } - if (self->still_frame_mode || self->passthrough) + GST_DEBUG_OBJECT (self, + "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf))); + + if (self->still_frame_mode || self->passthrough) { + GST_DEBUG_OBJECT (self, + "Frame type: Progressive?; pushing buffer using pass-through"); + GST_DEBUG_OBJECT (self, + "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf))); + return gst_pad_push (self->srcpad, buf); + } if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history"); @@ -1177,7 +1975,11 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf) gst_deinterlace_push_history (self, buf); buf = NULL; - return gst_deinterlace_output_frame (self, FALSE); + do { + ret = gst_deinterlace_output_frame (self, FALSE); + } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK); + + return ret; } static gint @@ -1386,6 +2188,23 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps) gboolean res = TRUE; GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad)); GstCaps *srccaps; + GstDeinterlaceInterlacingMethod interlacing_method; + + if (self->locking != GST_DEINTERLACE_LOCKING_NONE) { + if (self->low_latency == -1) + self->low_latency = gst_deinterlace_get_latency (self); + + if (self->pattern_lock) { + /* refresh has been successful - we have a lock now */ + self->pattern_refresh = FALSE; + } else { + /* if we were not refreshing (!pattern_refresh) the caps have changed + * so we need to refresh and we don't have a lock anymore + * otherwise we have pattern_fresh and !pattern_lock anyway */ + self->pattern_refresh = TRUE; + self->pattern_lock = FALSE; + } + } res = gst_video_format_parse_caps (caps, &self->format, &self->width, @@ -1398,27 +2217,51 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps) gst_deinterlace_update_passthrough (self); - if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) { - gint fps_n = self->fps_n, fps_d = self->fps_d; - - if (!gst_fraction_double (&fps_n, &fps_d, FALSE)) - goto invalid_caps; + interlacing_method = gst_deinterlace_get_interlacing_method (caps); + if (self->pattern_lock) { srccaps = gst_caps_copy (caps); + if (self->pattern != -1 + && G_UNLIKELY (!gst_util_fraction_multiply (self->fps_n, self->fps_d, + telecine_patterns[self->pattern].ratio_n, + telecine_patterns[self->pattern].ratio_d, &self->fps_n, + &self->fps_d))) + GST_ERROR_OBJECT (self, + "Multiplying the framerate by the telecine pattern ratio overflowed!"); + gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, self->fps_n, + self->fps_d, NULL); + } else if (self->low_latency > 0) { + if (interlacing_method == GST_DEINTERLACE_TELECINE) { + /* for initial buffers of a telecine pattern, until there is a lock we + * we output naïvely adjusted timestamps */ + srccaps = gst_caps_copy (caps); + gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); + } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) { + gint fps_n = self->fps_n, fps_d = self->fps_d; - gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n, - fps_d, NULL); + if (!gst_fraction_double (&fps_n, &fps_d, FALSE)) + goto invalid_caps; + + srccaps = gst_caps_copy (caps); + + gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n, + fps_d, NULL); + } else { + srccaps = gst_caps_ref (caps); + } } else { + /* in high latency pattern locking mode if we don't have a pattern lock, + * the sink pad caps are the best we know */ srccaps = gst_caps_ref (caps); } if (self->mode != GST_DEINTERLACE_MODE_DISABLED) { srccaps = gst_caps_make_writable (srccaps); + gst_structure_remove_field (gst_caps_get_structure (srccaps, 0), + "interlacing-method"); gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL); } - gst_deinterlace_reset_history (self, FALSE); - if (!gst_pad_set_caps (self->srcpad, srccaps)) goto caps_not_accepted; @@ -1475,8 +2318,8 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event) gint64 start, end, base; gdouble rate, applied_rate; - gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate, - &fmt, &start, &end, &base); + gst_event_parse_new_segment_full (event, &is_update, &rate, + &applied_rate, &fmt, &start, &end, &base); gst_deinterlace_reset_qos (self); gst_deinterlace_reset_history (self, FALSE); @@ -1524,6 +2367,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstEvent * event) } /* fall through */ case GST_EVENT_EOS: + self->have_eos = TRUE; gst_deinterlace_reset_history (self, FALSE); /* fall through */ diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h index df996f8425..ac97a555ec 100644 --- a/gst/deinterlace/gstdeinterlace.h +++ b/gst/deinterlace/gstdeinterlace.h @@ -43,8 +43,6 @@ G_BEGIN_DECLS typedef struct _GstDeinterlace GstDeinterlace; typedef struct _GstDeinterlaceClass GstDeinterlaceClass; -#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10 - typedef enum { GST_DEINTERLACE_TOMSMOCOMP, @@ -79,6 +77,39 @@ typedef enum { GST_DEINTERLACE_MODE_DISABLED } GstDeinterlaceMode; +typedef enum +{ + GST_DEINTERLACE_LOCKING_NONE, + GST_DEINTERLACE_LOCKING_AUTO, + GST_DEINTERLACE_LOCKING_ACTIVE, + GST_DEINTERLACE_LOCKING_PASSIVE, +} GstDeinterlaceLocking; + +#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10 +#define GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY 50 +/* check max field history is large enough */ +#if GST_DEINTERLACE_MAX_FIELD_HISTORY < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY * 3 +#undef GST_DEINTERLACE_MAX_FIELD_HISTORY +#define GST_DEINTERLACE_MAX_FIELD_HISTORY (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY * 3) +#endif + +typedef struct _TelecinePattern TelecinePattern; +struct _TelecinePattern +{ + const gchar *nick; + guint8 length; + guint8 ratio_n, ratio_d; + guint8 states[GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY]; +}; + +typedef struct _GstDeinterlaceBufferState GstDeinterlaceBufferState; +struct _GstDeinterlaceBufferState +{ + GstClockTime timestamp; + GstClockTime duration; + guint8 state; +}; + struct _GstDeinterlace { GstElement parent; @@ -92,8 +123,10 @@ struct _GstDeinterlace GstDeinterlaceFields fields; - GstDeinterlaceMethods method_id; /* current state (differs when flushing) */ - GstDeinterlaceMethods user_set_method_id; /* property value */ + /* current state (differs when flushing/inverse telecine using weave) */ + GstDeinterlaceMethods method_id; + /* property value */ + GstDeinterlaceMethods user_set_method_id; GstDeinterlaceMethod *method; GstVideoFormat format; @@ -134,6 +167,24 @@ struct _GstDeinterlace gboolean reconfigure; GstDeinterlaceMode new_mode; GstDeinterlaceFields new_fields; + + GstDeinterlaceLocking locking; + gint low_latency; + gboolean drop_orphans; + gboolean ignore_obscure; + gboolean pattern_lock; + gboolean pattern_refresh; + GstDeinterlaceBufferState buf_states[GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY]; + gint state_count; + gint pattern; + guint8 pattern_phase; + guint8 pattern_count; + guint8 output_count; + GstClockTime pattern_base_ts; + GstClockTime pattern_buf_dur; + + gboolean need_more; + gboolean have_eos; }; struct _GstDeinterlaceClass From 9f3ae3244c2221374146b7ae96c3239410d70575 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 19 May 2011 18:21:33 +0300 Subject: [PATCH 10/28] qtdemux: add missing break --- gst/isomp4/qtdemux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 9388a504cc..416b164e54 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -9320,6 +9320,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, case GST_MAKE_FOURCC ('V', 'P', '8', '0'): _codec ("On2 VP8"); caps = gst_caps_from_string ("video/x-vp8"); + break; case FOURCC_ovc1: _codec ("VC-1"); caps = gst_caps_new_simple ("video/x-wmv", From 7105ead626c1db2e0ff5ea47b2c46d2c7cc18207 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 19 May 2011 22:57:15 +0300 Subject: [PATCH 11/28] Automatic update of common submodule From 9e5bbd5 to 69b981f --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 9e5bbd5085..69b981f10c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 9e5bbd508588961696e70c38e764492e0312ec4c +Subproject commit 69b981f10caa234ad0ff639179d0fda8505bd94b From aff7701f806cd87b5ba1e25e6bc663f44a076fab Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 19 May 2011 23:31:19 +0300 Subject: [PATCH 12/28] docs: update plugin introspection data Now more files are merged and produced in a canonical fashion, which hopefully creates less or no delta in the future. --- docs/plugins/gst-plugins-good-plugins.args | 90 ++-- .../gst-plugins-good-plugins.hierarchy | 480 +++++++++--------- .../gst-plugins-good-plugins.interfaces | 105 ++-- .../gst-plugins-good-plugins.prerequisites | 13 +- 4 files changed, 362 insertions(+), 326 deletions(-) diff --git a/docs/plugins/gst-plugins-good-plugins.args b/docs/plugins/gst-plugins-good-plugins.args index acbd788a0f..0c96249e11 100644 --- a/docs/plugins/gst-plugins-good-plugins.args +++ b/docs/plugins/gst-plugins-good-plugins.args @@ -461,7 +461,7 @@ GstUDPSrc::sockfd gint ->= G_MAXULONG +>= -1 rw Socket Handle Socket to use for UDP reception. (-1 == allocate). @@ -511,7 +511,7 @@ GstUDPSrc::sock gint ->= G_MAXULONG +>= -1 r Socket Handle Socket currently in use for UDP reception. (-1 = no socket). @@ -1651,7 +1651,7 @@ GstDV1394Src::port gint -[G_MAXULONG,16] +[-1,16] rw Port Port number (-1 automatic). @@ -1901,7 +1901,7 @@ GstTest::allowed-timestamp-deviation gint64 ->= G_MAXULONG +>= -1 rwx allowed timestamp deviation allowed average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer. @@ -1911,7 +1911,7 @@ GstTest::buffer-count gint64 ->= G_MAXULONG +>= -1 r buffer count number of buffers in stream. @@ -1921,7 +1921,7 @@ GstTest::expected-buffer-count gint64 ->= G_MAXULONG +>= -1 rwx expected buffer count expected number of buffers in stream. @@ -1931,7 +1931,7 @@ GstTest::expected-length gint64 ->= G_MAXULONG +>= -1 rwx expected length expected length of stream. @@ -1951,7 +1951,7 @@ GstTest::length gint64 ->= G_MAXULONG +>= -1 r length length of stream. @@ -1971,7 +1971,7 @@ GstTest::timestamp-deviation gint64 ->= G_MAXULONG +>= -1 r timestamp deviation average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer. @@ -2051,7 +2051,7 @@ GstBreakMyData::set-to gint -[G_MAXULONG,255] +[-1,255] rwx set-to set changed bytes to this value (-1 means random value. @@ -2391,7 +2391,7 @@ GstDynUDPSink::sockfd gint -[G_MAXULONG,32767] +[-1,32767] rw socket handle Socket to use for UDP sending. (-1 == allocate). @@ -2461,7 +2461,7 @@ GstMultiUDPSink::sock gint ->= G_MAXULONG +>= -1 r Socket Handle Socket currently in use for UDP sending. (-1 == no socket). @@ -2471,7 +2471,7 @@ GstMultiUDPSink::sockfd gint ->= G_MAXULONG +>= -1 rw Socket Handle Socket to use for UDP sending. (-1 == allocate). @@ -2501,7 +2501,7 @@ GstMultiUDPSink::qos-dscp gint -[G_MAXULONG,63] +[-1,63] rw QoS diff srv code point Quality of Service, differentiated services code point (-1 default). @@ -2651,7 +2651,7 @@ GstXImageSrc::screen-num guint -<= G_MAXINT +<= G_MAXLONG rw Screen number X Screen Number. @@ -2671,7 +2671,7 @@ GstXImageSrc::endx guint -<= G_MAXINT +<= G_MAXLONG rw End X X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen). @@ -2681,7 +2681,7 @@ GstXImageSrc::endy guint -<= G_MAXINT +<= G_MAXLONG rw End Y Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen). @@ -2691,7 +2691,7 @@ GstXImageSrc::startx guint -<= G_MAXINT +<= G_MAXLONG rw Start X co-ordinate X coordinate of top left corner of area to be recorded (0 for top left of screen). @@ -2701,7 +2701,7 @@ GstXImageSrc::starty guint -<= G_MAXINT +<= G_MAXLONG rw Start Y co-ordinate Y coordinate of top left corner of area to be recorded (0 for top left of screen). @@ -2811,7 +2811,7 @@ GstJpegDec::max-errors gint ->= G_MAXULONG +>= -1 rw Maximum Consecutive Decoding Errors Error out after receiving N consecutive decoding errors (-1 = never fail, 0 = automatic, 1 = fail on first error). @@ -3121,7 +3121,7 @@ GstV4l2Src::device-fd gint ->= G_MAXULONG +>= -1 r File descriptor File descriptor of the device. @@ -3391,7 +3391,7 @@ GstRndBufferSize::max glong -[1,G_MAXINT] +>= 1 rwx maximum maximum buffer size. @@ -3401,7 +3401,7 @@ GstRndBufferSize::min glong -[0,G_MAXINT] +>= 0 rwx mininum mininum buffer size. @@ -3411,7 +3411,7 @@ GstRndBufferSize::seed gulong -<= G_MAXUINT + rwx random number seed seed for randomness (initialized when going from READY to PAUSED). @@ -20111,7 +20111,7 @@ GstHDV1394Src::port gint -[G_MAXULONG,16] +[-1,16] rw Port Port number (-1 automatic). @@ -20398,6 +20398,36 @@ Auto detection + +GstDeinterlace::drop-orphans +gboolean + +rw +drop-orphans +Drop orphan fields at the beginning of telecine patterns in active locking mode. +TRUE + + + +GstDeinterlace::ignore-obscure +gboolean + +rw +ignore-obscure +Ignore obscure telecine patterns (only consider P, I and 2:3 variants). +TRUE + + + +GstDeinterlace::locking +GstDeinterlaceLocking + +rw +locking +Pattern locking mode. +No pattern locking + + GstAgingTV::color-aging gboolean @@ -20461,7 +20491,7 @@ GstOpTV::threshold guint -<= G_MAXINT +<= G_MAXLONG rw Threshold Luma threshold. @@ -20481,7 +20511,7 @@ GstRadioacTV::interval guint -<= G_MAXINT +<= G_MAXLONG rw Interval Snapshot interval (in strobe mode). @@ -20751,7 +20781,7 @@ GstRtpSession::rtcp-rr-bandwidth gint ->= G_MAXULONG +>= -1 rw RTCP RR bandwidth The RTCP bandwidth used for receivers in bytes per second (-1 = default). @@ -20761,7 +20791,7 @@ GstRtpSession::rtcp-rs-bandwidth gint ->= G_MAXULONG +>= -1 rw RTCP RS bandwidth The RTCP bandwidth used for senders in bytes per second (-1 = default). @@ -20801,7 +20831,7 @@ GstV4l2Sink::device-fd gint ->= G_MAXULONG +>= -1 r File descriptor File descriptor of the device. diff --git a/docs/plugins/gst-plugins-good-plugins.hierarchy b/docs/plugins/gst-plugins-good-plugins.hierarchy index 33aceea49a..5e1dff3865 100644 --- a/docs/plugins/gst-plugins-good-plugins.hierarchy +++ b/docs/plugins/gst-plugins-good-plugins.hierarchy @@ -1,315 +1,319 @@ GObject + GdkPixbuf + GstCmmlTagClip + GstCmmlTagHead + GstCmmlTagStream + GstColorBalanceChannel GstObject - GstPad - GstVideoMixer2Pad - GstVideoMixerPad - GstInterleavePad - GstPadTemplate - GstPluginFeature - GstElementFactory - GstTypeFindFactory - GstIndexFactory + GstBus + GstClock + GstSystemClock + GstAudioClock GstElement - GstBin - GstPipeline - GstQTMoovRecover - GstSwitchSink - GstGConfVideoSink - GstGConfAudioSink - GstSwitchSrc - GstGConfVideoSrc - GstGConfAudioSrc - GstHalAudioSink - GstHalAudioSrc - GstRtpBin - GstAutoVideoSink - GstAutoVideoSrc - GstAutoAudioSink - GstAutoAudioSrc - GstPushFileSrc - GstRTSPSrc - GstRgVolume - GstAspectRatioCrop - GstCmmlEnc - GstCmmlDec - GstBaseSink - GstAASink - GstBaseAudioSink - GstPulseSink - GstJackAudioSink - GstAudioSink - GstEsdSink - GstOssSink - GstOss4Sink - GstCACASink - GstVideoSink - GstGdkPixbufSink - GstShout2send - GstTest - GstMultiFileSink - GstMultiUDPSink - GstUDPSink - GstDynUDPSink - GstBaseSrc - GstPushSrc - GstDV1394Src - GstHDV1394Src - GstSoupHTTPSrc - GstBaseAudioSrc - GstAudioSrc - GstPulseSrc - GstOssSrc - GstOss4Source - GstJackAudioSrc - GstV4l2Src - GstXImageSrc - GstMultiFileSrc - GstUDPSrc - GstWavpackParse - GstWavpackDec - GstWavpackEnc - GstDVDemux - GstDVDec - GstTagLibMux - GstId3v2Mux - GstApev2Mux - GstFlacEnc - GstFlacDec - GstFlacTag - GstCairoTextOverlay - GstBaseTransform - GstCairoTimeOverlay - GstVideoFilter - GstCairoOverlay - GstEdgeTV - GstAgingTV - GstDiceTV - GstWarpTV - GstShagadelicTV - GstVertigoTV - GstRevTV - GstQuarkTV - GstOpTV - GstRadioacTV - GstStreakTV - GstRippleTV - GstNavigationtest - GstGamma - GstVideoBalance - GstVideoFlip - GstSMPTEAlpha - GstAlpha - GstAlphaColor - GstPixbufScale - GstVideoBox - GstBreakMyData - GstCapsSetter - GstNavSeek - GstProgressReport - GstTagInject - GstCpuReport - GstLevel - GstAudioFilter - GstIirEqualizer - GstIirEqualizerNBands - GstIirEqualizer3Bands - GstIirEqualizer10Bands - GstSpectrum - GstAudioInvert - GstAudioKaraoke - GstAudioAmplify - GstAudioDynamic - GstAudioFXBaseIIRFilter - GstAudioChebLimit - GstAudioChebBand - GstAudioIIRFilter - GstAudioFXBaseFIRFilter - GstAudioWSincLimit - GstAudioWSincBand - GstAudioFIRFilter - GstAudioEcho - GstRgAnalysis - GstRgLimiter - GstVideoCrop - GstAudioPanorama - GstCairoRender - GstPulseMixer - GstSpeexEnc - GstSpeexDec - GstJpegEnc - GstJpegDec - GstSmokeEnc - GstSmokeDec - GstPngDec - GstPngEnc - GstGdkPixbuf - GstOssMixerElement - GstV4l2Radio - GstOss4Mixer - GstShapeWipe + Gst3GPPMux + GstALawDec + GstALawEnc + GstAsteriskh263 + GstAuParse GstAviDemux GstAviMux GstAviSubtitle - GstRTPDepay + GstBaseParse + GstAacParse + GstAc3Parse + GstAmrParse + GstDcaParse + GstFlacParse + GstMpegAudioParse GstBaseRTPDepayload - GstRtpAC3Depay GstRTPBVDepay - GstRtpCELTDepay GstRTPDVDepay - GstRtpGSTDepay + GstRTPGSMDepay + GstRTPSirenDepay GstRTPiLBCDepay + GstRtpAC3Depay + GstRtpAMRDepay + GstRtpCELTDepay GstRtpG722Depay GstRtpG723Depay GstRtpG726Depay GstRtpG729Depay - GstRTPGSMDepay - GstRtpAMRDepay - GstRtpPcmaDepay - GstRtpPcmuDepay - GstRtpMPADepay - GstRtpMPARobustDepay - GstRtpMPVDepay - GstRtpH263PDepay + GstRtpGSTDepay GstRtpH263Depay + GstRtpH263PDepay GstRtpH264Depay GstRtpJ2KDepay GstRtpJPEGDepay GstRtpL16Depay GstRtpMP1SDepay GstRtpMP2TDepay - GstRtpMP4VDepay GstRtpMP4ADepay GstRtpMP4GDepay + GstRtpMP4VDepay + GstRtpMPADepay + GstRtpMPARobustDepay + GstRtpMPVDepay + GstRtpPcmaDepay + GstRtpPcmuDepay GstRtpQCELPDepay GstRtpQDM2Depay - GstRTPSirenDepay GstRtpSPEEXDepay GstRtpSV3VDepay GstRtpTheoraDepay - GstRtpVorbisDepay GstRtpVRawDepay + GstRtpVorbisDepay GstRtpXQTDepay GstBaseRTPPayload - GstRtpAC3Pay GstBaseRTPAudioPayload GstRTPBVPay GstRTPILBCPay + GstRTPSirenPay GstRtpG722Pay GstRtpG726Pay - GstRtpPcmuPay - GstRtpPcmaPay GstRtpL16Pay - GstRTPSirenPay - GstRtpCELTPay + GstRtpPcmaPay + GstRtpPcmuPay GstRTPDVPay - GstRtpGSTPay GstRTPG723Pay GstRTPG729Pay GstRTPGSMPay - GstRtpAMRPay - GstRtpMPAPay + GstRTPMP2TPay GstRTPMPVPay + GstRtpAC3Pay + GstRtpAMRPay + GstRtpCELTPay + GstRtpGSTPay GstRtpH263PPay GstRtpH263Pay GstRtpH264Pay GstRtpJ2KPay GstRtpJPEGPay - GstRTPMP2TPay - GstRtpMP4VPay GstRtpMP4APay GstRtpMP4GPay + GstRtpMP4VPay + GstRtpMPAPay GstRtpSPEEXPay GstRtpTheoraPay - GstRtpVorbisPay GstRtpVRawPay - GstAsteriskh263 + GstRtpVorbisPay + GstBaseSink + GstAASink + GstBaseAudioSink + GstAudioSink + GstEsdSink + GstOss4Sink + GstOssSink + GstJackAudioSink + GstPulseSink + GstCACASink + GstDynUDPSink + GstMultiFileSink + GstMultiUDPSink + GstUDPSink + GstShout2send + GstTest + GstVideoSink + GstGdkPixbufSink + GstV4l2Sink + GstBaseSrc + GstPushSrc + GstBaseAudioSrc + GstAudioSrc + GstOss4Source + GstOssSrc + GstPulseSrc + GstJackAudioSrc + GstDV1394Src + GstHDV1394Src + GstMultiFileSrc + GstSoupHTTPSrc + GstUDPSrc + GstV4l2Src + GstXImageSrc + GstBaseTransform + GstAudioFilter + GstAudioAmplify + GstAudioDynamic + GstAudioEcho + GstAudioFXBaseFIRFilter + GstAudioFIRFilter + GstAudioWSincBand + GstAudioWSincLimit + GstAudioFXBaseIIRFilter + GstAudioChebBand + GstAudioChebLimit + GstAudioIIRFilter + GstAudioInvert + GstAudioKaraoke + GstIirEqualizer + GstIirEqualizer10Bands + GstIirEqualizer3Bands + GstIirEqualizerNBands + GstSpectrum + GstAudioPanorama + GstBreakMyData + GstCairoTimeOverlay + GstCapsSetter + GstCpuReport + GstLevel + GstNavSeek + GstPixbufScale + GstProgressReport + GstRgAnalysis + GstRgLimiter + GstTagInject + GstVideoBox + GstVideoCrop + GstVideoFilter + GstAgingTV + GstAlpha + GstAlphaColor + GstCairoOverlay + GstDiceTV + GstEdgeTV + GstGamma + GstNavigationtest + GstOpTV + GstQuarkTV + GstRadioacTV + GstRevTV + GstRippleTV + GstSMPTEAlpha + GstShagadelicTV + GstStreakTV + GstVertigoTV + GstVideoBalance + GstVideoFlip + GstWarpTV + GstBin + GstAspectRatioCrop + GstAutoAudioSink + GstAutoAudioSrc + GstAutoVideoSink + GstAutoVideoSrc + GstHalAudioSink + GstHalAudioSrc + GstPipeline + GstQTMoovRecover + GstPushFileSrc + GstRTSPSrc + GstRgVolume + GstRtpBin + GstSwitchSink + GstGConfAudioSink + GstGConfVideoSink + GstSwitchSrc + GstGConfAudioSrc + GstGConfVideoSrc + GstCairoRender + GstCairoTextOverlay + GstCapsDebug + GstCmmlDec + GstCmmlEnc + GstCutter + GstDVDec + GstDVDemux + GstDeinterlace + GstDeinterleave + GstEFence + GstFlacDec + GstFlacEnc + GstFlacTag + GstFlvDemux + GstFlvMux + GstFlxDec + GstGPPMux + GstGdkPixbuf GstGoom GstGoom2k1 - GstWavEnc + GstICYDemux + GstISMLMux + GstImageFreeze + GstInterleave + GstJpegDec + GstJpegEnc + GstMJ2Mux + GstMP4Mux + GstMatroskaDemux + GstMatroskaMux + GstWebMMux + GstMatroskaParse + GstMonoscope + GstMuLawDec + GstMuLawEnc + GstMultipartDemux + GstMultipartMux + GstOss4Mixer + GstOssMixerElement + GstPngDec + GstPngEnc + GstPulseMixer + GstQTDemux + GstQTMux + GstRTPDec + GstRTPDepay + GstRndBufferSize GstRtpJitterBuffer GstRtpPtDemux GstRtpSession GstRtpSsrcDemux - GstRndBufferSize - GstCapsDebug - GstEFence - GstCutter - GstMatroskaDemux - GstMatroskaParse - GstMatroskaMux - GstWebMMux - GstRTPDec GstSMPTE - GstAuParse - GstMultipartDemux - GstMultipartMux - GstALawEnc - GstALawDec - GstMuLawEnc - GstMuLawDec + GstShapeWipe + GstSmokeDec + GstSmokeEnc + GstSpeexDec + GstSpeexEnc GstTagDemux GstApeDemux GstID3Demux - GstFlxDec - GstDeinterlace - GstImageFreeze - GstBaseParse - GstAacParse - GstAmrParse - GstAc3Parse - GstDcaParse - GstFlacParse - GstMpegAudioParse - GstY4mEncode - GstInterleave - GstDeinterleave - GstWavParse - GstFlvDemux - GstFlvMux - GstQTDemux - GstQTMux - GstMP4Mux - GstISMLMux - Gst3GPPMux - GstGPPMux - GstMJ2Mux - GstICYDemux + GstTagLibMux + GstApev2Mux + GstId3v2Mux + GstV4l2Radio GstVideoMixer GstVideoMixer2 - GstBus - GstTask - GstTaskPool - GstClock - GstSystemClock - GstAudioClock + GstWavEnc + GstWavParse + GstWavpackDec + GstWavpackEnc + GstWavpackParse + GstY4mEncode + GstPad + GstInterleavePad + GstVideoMixer2Pad + GstVideoMixerPad + GstPadTemplate GstPlugin + GstPluginFeature + GstElementFactory + GstIndexFactory + GstTypeFindFactory GstRegistry GstRingBuffer - GstAudioSrcRingBuffer GstAudioSinkRingBuffer - GstJackAudioSrcRingBuffer + GstAudioSrcRingBuffer GstJackAudioSinkRingBuffer + GstJackAudioSrcRingBuffer + GstTask + GstTaskPool GstSignalObject - GstCmmlTagStream - GstCmmlTagHead - GstCmmlTagClip - GstColorBalanceChannel - RTPSession - GstTunerNorm GstTunerChannel - GdkPixbuf + GstTunerNorm + RTPSession GInterface + GIcon GTypePlugin GstChildProxy - GstURIHandler - GstPropertyProbe - GstPreset - GstTagSetter - GstStreamVolume + GstColorBalance GstImplementsInterface GstMixer - GstTuner - GstColorBalance - GstVideoOrientation + GstNavigation + GstPreset + GstPropertyProbe + GstStreamVolume + GstTagSetter GstTagXmpWriter - GIcon + GstTuner + GstURIHandler + GstVideoOrientation + GstXOverlay diff --git a/docs/plugins/gst-plugins-good-plugins.interfaces b/docs/plugins/gst-plugins-good-plugins.interfaces index 8cb7022d8d..518366a8ab 100644 --- a/docs/plugins/gst-plugins-good-plugins.interfaces +++ b/docs/plugins/gst-plugins-good-plugins.interfaces @@ -1,62 +1,63 @@ -GstBin GstChildProxy -GstPipeline GstChildProxy -GstQTMoovRecover GstChildProxy -GstSwitchSink GstChildProxy -GstGConfVideoSink GstChildProxy -GstGConfAudioSink GstChildProxy -GstSwitchSrc GstChildProxy -GstGConfVideoSrc GstChildProxy -GstGConfAudioSrc GstChildProxy -GstHalAudioSink GstChildProxy -GstHalAudioSrc GstChildProxy -GstRtpBin GstChildProxy -GstAutoVideoSink GstChildProxy -GstAutoVideoSrc GstChildProxy +GdkPixbuf GIcon +Gst3GPPMux GstTagSetter GstTagXmpWriter +GstApev2Mux GstTagSetter +GstAspectRatioCrop GstChildProxy GstAutoAudioSink GstChildProxy GstAutoAudioSrc GstChildProxy -GstPushFileSrc GstChildProxy GstURIHandler -GstRTSPSrc GstChildProxy GstURIHandler -GstRgVolume GstChildProxy -GstAspectRatioCrop GstChildProxy -GstPulseSink GstStreamVolume GstImplementsInterface GstPropertyProbe -GstOss4Sink GstStreamVolume GstPropertyProbe -GstShout2send GstTagSetter -GstUDPSink GstURIHandler +GstAutoVideoSink GstChildProxy +GstAutoVideoSrc GstChildProxy +GstAviMux GstTagSetter +GstBin GstChildProxy GstDV1394Src GstURIHandler GstPropertyProbe -GstHDV1394Src GstURIHandler GstPropertyProbe -GstSoupHTTPSrc GstURIHandler -GstPulseSrc GstImplementsInterface GstMixer GstPropertyProbe -GstOssSrc GstImplementsInterface GstMixer -GstOss4Source GstImplementsInterface GstMixer GstPropertyProbe -GstV4l2Src GstURIHandler GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation GstPropertyProbe -GstUDPSrc GstURIHandler -GstWavpackEnc GstPreset -GstTagLibMux GstTagSetter -GstId3v2Mux GstTagSetter -GstApev2Mux GstTagSetter +GstDeinterlace GstChildProxy GstFlacEnc GstTagSetter GstPreset GstFlacTag GstTagSetter -GstVideoBalance GstImplementsInterface GstColorBalance -GstIirEqualizer GstChildProxy -GstIirEqualizerNBands GstChildProxy -GstIirEqualizer3Bands GstChildProxy GstPreset -GstIirEqualizer10Bands GstChildProxy GstPreset -GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe -GstSpeexEnc GstTagSetter GstPreset -GstOssMixerElement GstImplementsInterface GstMixer -GstV4l2Radio GstURIHandler GstImplementsInterface GstTuner GstPropertyProbe -GstOss4Mixer GstImplementsInterface GstMixer GstPropertyProbe -GstAviMux GstTagSetter -GstMatroskaMux GstTagSetter -GstWebMMux GstTagSetter -GstDeinterlace GstChildProxy GstFlvMux GstTagSetter -GstQTMux GstTagSetter GstTagXmpWriter -GstMP4Mux GstTagSetter GstTagXmpWriter -GstISMLMux GstTagSetter GstTagXmpWriter -Gst3GPPMux GstTagSetter GstTagXmpWriter +GstGConfAudioSink GstChildProxy +GstGConfAudioSrc GstChildProxy +GstGConfVideoSink GstChildProxy +GstGConfVideoSrc GstChildProxy GstGPPMux GstTagSetter GstTagXmpWriter +GstHDV1394Src GstURIHandler GstPropertyProbe +GstHalAudioSink GstChildProxy +GstHalAudioSrc GstChildProxy +GstISMLMux GstTagSetter GstTagXmpWriter +GstId3v2Mux GstTagSetter +GstIirEqualizer GstChildProxy +GstIirEqualizer10Bands GstChildProxy GstPreset +GstIirEqualizer3Bands GstChildProxy GstPreset +GstIirEqualizerNBands GstChildProxy GstMJ2Mux GstTagSetter GstTagXmpWriter +GstMP4Mux GstTagSetter GstTagXmpWriter +GstMatroskaMux GstTagSetter +GstOss4Mixer GstImplementsInterface GstMixer GstPropertyProbe +GstOss4Sink GstStreamVolume GstPropertyProbe +GstOss4Source GstImplementsInterface GstMixer GstPropertyProbe +GstOssMixerElement GstImplementsInterface GstMixer +GstOssSrc GstImplementsInterface GstMixer +GstPipeline GstChildProxy +GstPulseMixer GstImplementsInterface GstMixer GstPropertyProbe +GstPulseSink GstStreamVolume GstImplementsInterface GstPropertyProbe +GstPulseSrc GstImplementsInterface GstMixer GstPropertyProbe +GstPushFileSrc GstChildProxy GstURIHandler +GstQTMoovRecover GstChildProxy +GstQTMux GstTagSetter GstTagXmpWriter +GstRTSPSrc GstChildProxy GstURIHandler +GstRgVolume GstChildProxy +GstRtpBin GstChildProxy +GstShout2send GstTagSetter +GstSoupHTTPSrc GstURIHandler +GstSpeexEnc GstTagSetter GstPreset +GstSwitchSink GstChildProxy +GstSwitchSrc GstChildProxy +GstTagLibMux GstTagSetter +GstUDPSink GstURIHandler +GstUDPSrc GstURIHandler +GstV4l2Radio GstURIHandler GstImplementsInterface GstTuner GstPropertyProbe +GstV4l2Sink GstImplementsInterface GstXOverlay GstNavigation GstColorBalance GstVideoOrientation GstPropertyProbe +GstV4l2Src GstURIHandler GstImplementsInterface GstTuner GstColorBalance GstVideoOrientation GstPropertyProbe +GstVideoBalance GstImplementsInterface GstColorBalance GstVideoMixer GstChildProxy GstVideoMixer2 GstChildProxy -GdkPixbuf GIcon +GstWavpackEnc GstPreset +GstWebMMux GstTagSetter diff --git a/docs/plugins/gst-plugins-good-plugins.prerequisites b/docs/plugins/gst-plugins-good-plugins.prerequisites index ec5b5e29be..5c212bb7a4 100644 --- a/docs/plugins/gst-plugins-good-plugins.prerequisites +++ b/docs/plugins/gst-plugins-good-plugins.prerequisites @@ -1,10 +1,11 @@ +GIcon GObject GstChildProxy GstObject -GstTagSetter GstElement -GstStreamVolume GObject +GstColorBalance GstImplementsInterface GstElement GstImplementsInterface GstElement GstMixer GstImplementsInterface GstElement -GstTuner GstImplementsInterface GstElement -GstColorBalance GstImplementsInterface GstElement -GstVideoOrientation GstImplementsInterface GstElement +GstStreamVolume GObject +GstTagSetter GstElement GstTagXmpWriter GstElement -GIcon GObject +GstTuner GstImplementsInterface GstElement +GstVideoOrientation GstImplementsInterface GstElement +GstXOverlay GstImplementsInterface GstElement From 5792d3b9c08ac2eefb793abdaee2e2ec6c48bd71 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 20 May 2011 00:53:44 +0300 Subject: [PATCH 13/28] rtp: fix static array overruns Yes array[10] has elements from 0...9. --- gst/rtp/gstrtpjpegpay.c | 2 +- gst/rtp/gstrtpmp4adepay.c | 2 +- gst/rtp/gstrtpqcelpdepay.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c index fc4096d5c2..9a34447031 100644 --- a/gst/rtp/gstrtpjpegpay.c +++ b/gst/rtp/gstrtpjpegpay.c @@ -716,7 +716,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload, guint qt; qt = info[i].qt; - if (qt > 15) + if (qt > 14) goto invalid_quant; qsize = tables[qt].size; diff --git a/gst/rtp/gstrtpmp4adepay.c b/gst/rtp/gstrtpmp4adepay.c index 18ebfd2190..edcd8dbedf 100644 --- a/gst/rtp/gstrtpmp4adepay.c +++ b/gst/rtp/gstrtpmp4adepay.c @@ -229,7 +229,7 @@ gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4)) goto bad_config; - if (sr_idx > 12 && sr_idx != 15) { + if (sr_idx > 11 && sr_idx != 15) { GST_WARNING_OBJECT (depayload, "invalid sample rate index %d", sr_idx); goto bad_config; } diff --git a/gst/rtp/gstrtpqcelpdepay.c b/gst/rtp/gstrtpqcelpdepay.c index 7949ae7804..e83ed2cca1 100644 --- a/gst/rtp/gstrtpqcelpdepay.c +++ b/gst/rtp/gstrtpqcelpdepay.c @@ -164,7 +164,7 @@ static const gint frame_size[16] = { static gint get_frame_len (GstRtpQCELPDepay * depay, guint8 frame_type) { - if (frame_type > 16) + if (frame_type > 15) return 0; return frame_size[frame_type]; From d122ea01222f6a4ed08f2935ef6e0e06f06bfa20 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 20 May 2011 10:34:47 +0300 Subject: [PATCH 14/28] rtp: fix static array overruns in a nicer way Use G_N_ELEMENTS instead of hard-coding the array size. --- gst/rtp/gstrtpjpegpay.c | 2 +- gst/rtp/gstrtpmp4adepay.c | 4 ++-- gst/rtp/gstrtpqcelpdepay.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c index 9a34447031..f22384709f 100644 --- a/gst/rtp/gstrtpjpegpay.c +++ b/gst/rtp/gstrtpjpegpay.c @@ -716,7 +716,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload, guint qt; qt = info[i].qt; - if (qt > 14) + if (qt >= G_N_ELEMENTS (tables)) goto invalid_quant; qsize = tables[qt].size; diff --git a/gst/rtp/gstrtpmp4adepay.c b/gst/rtp/gstrtpmp4adepay.c index edcd8dbedf..664864abe1 100644 --- a/gst/rtp/gstrtpmp4adepay.c +++ b/gst/rtp/gstrtpmp4adepay.c @@ -51,7 +51,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", /* All optional parameters * * "profile-level-id=[1,MAX]" - * "config=" + * "config=" */ ) ); @@ -229,7 +229,7 @@ gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4)) goto bad_config; - if (sr_idx > 11 && sr_idx != 15) { + if (sr_idx >= G_N_ELEMENTS (aac_sample_rates) && sr_idx != 15) { GST_WARNING_OBJECT (depayload, "invalid sample rate index %d", sr_idx); goto bad_config; } diff --git a/gst/rtp/gstrtpqcelpdepay.c b/gst/rtp/gstrtpqcelpdepay.c index e83ed2cca1..ce947d4c01 100644 --- a/gst/rtp/gstrtpqcelpdepay.c +++ b/gst/rtp/gstrtpqcelpdepay.c @@ -164,7 +164,7 @@ static const gint frame_size[16] = { static gint get_frame_len (GstRtpQCELPDepay * depay, guint8 frame_type) { - if (frame_type > 15) + if (frame_type >= G_N_ELEMENTS (frame_size)) return 0; return frame_size[frame_type]; From e0cadab5c2a54acfa5ac607b854890fea74c013f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 22 May 2011 18:50:51 +0100 Subject: [PATCH 15/28] flacparse: don't error out on invalid minimum_blocksize value in streaminfo header We don't use it, so may just as well accept an invalid value of 0 here, which is likely inconsequential anyway. https://bugzilla.gnome.org/show_bug.cgi?id=650691 --- gst/audioparsers/gstflacparse.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0249e88a2d..0671187dab 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -756,17 +756,15 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->min_blocksize, 16)) goto error; if (flacparse->min_blocksize < 16) { - GST_ERROR_OBJECT (flacparse, "Invalid minimum block size: %u", + GST_WARNING_OBJECT (flacparse, "Invalid minimum block size: %u", flacparse->min_blocksize); - return FALSE; } if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->max_blocksize, 16)) goto error; if (flacparse->max_blocksize < 16) { - GST_ERROR_OBJECT (flacparse, "Invalid maximum block size: %u", + GST_WARNING_OBJECT (flacparse, "Invalid maximum block size: %u", flacparse->max_blocksize); - return FALSE; } if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->min_framesize, 24)) From 8823ae251a72bd18fc93322914c70390fc16c6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 23 May 2011 11:36:36 +0200 Subject: [PATCH 16/28] flacparse: Implement conversions between TIME and DEFAULT format Fixes bug #650785. --- gst/audioparsers/gstflacparse.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0671187dab..0c766552bf 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -198,6 +198,9 @@ static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); +static gboolean gst_flac_parse_convert (GstBaseParse * parse, + GstFormat src_format, gint64 src_value, GstFormat dest_format, + gint64 * dest_value); GST_BOILERPLATE (GstFlacParse, gst_flac_parse, GstBaseParse, GST_TYPE_BASE_PARSE); @@ -244,6 +247,7 @@ gst_flac_parse_class_init (GstFlacParseClass * klass) baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame); baseparse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame); + baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert); } static void @@ -1351,3 +1355,34 @@ gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) return GST_FLOW_OK; } + +static gboolean +gst_flac_parse_convert (GstBaseParse * parse, + GstFormat src_format, gint64 src_value, GstFormat dest_format, + gint64 * dest_value) +{ + GstFlacParse *flacparse = GST_FLAC_PARSE (parse); + + if (flacparse->samplerate > 0) { + if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) { + if (src_value != -1) + *dest_value = + gst_util_uint64_scale (src_value, GST_SECOND, + flacparse->samplerate); + else + *dest_value = -1; + return TRUE; + } else if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_TIME) { + if (src_value != -1) + *dest_value = + gst_util_uint64_scale (src_value, flacparse->samplerate, + GST_SECOND); + else + *dest_value = -1; + return TRUE; + } + } + + return GST_BASE_PARSE_CLASS (parent_class)->convert (parse, src_format, + src_value, dest_format, dest_value); +} From 1183d0c1ab9b567e085e30006b984a578f4a6a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 23 May 2011 13:23:21 +0100 Subject: [PATCH 17/28] flacparse: make conversion from TIME to DEFAULT format (samples) work Fix copy'n'paste error in the previous commit. --- gst/audioparsers/gstflacparse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0c766552bf..0995d79784 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -1372,7 +1372,8 @@ gst_flac_parse_convert (GstBaseParse * parse, else *dest_value = -1; return TRUE; - } else if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_TIME) { + } else if (src_format == GST_FORMAT_TIME && + dest_format == GST_FORMAT_DEFAULT) { if (src_value != -1) *dest_value = gst_util_uint64_scale (src_value, flacparse->samplerate, From 900b2fb63dac15fe1013d9e326a7a5c8d4da1cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 23 May 2011 13:25:44 +0100 Subject: [PATCH 18/28] flacdec: also try upstream first for duration query in DEFAULT format https://bugzilla.gnome.org/show_bug.cgi?id=650785 --- ext/flac/gstflacdec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 4957129dc0..2e4085dd63 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -1724,8 +1724,9 @@ gst_flac_dec_src_query (GstPad * pad, GstQuery * query) gst_query_parse_duration (query, &fmt, NULL); - /* try any demuxers before us first */ - if (fmt == GST_FORMAT_TIME && peer && gst_pad_query (peer, query)) { + /* try any demuxers or parsers before us first */ + if ((fmt == GST_FORMAT_TIME || fmt == GST_FORMAT_DEFAULT) && + peer != NULL && gst_pad_query (peer, query)) { gst_query_parse_duration (query, NULL, &len); GST_DEBUG_OBJECT (flacdec, "peer returned duration %" GST_TIME_FORMAT, GST_TIME_ARGS (len)); From a53540346a18d27b94f5254ac2582cb844e9bde0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 23 May 2011 13:50:46 +0100 Subject: [PATCH 19/28] flacparse: tell baseparse the duration in samples for better accuracy Tell GstBaseParse the duration in samples instead of time, so that a duration query in DEFAULT format will return the correct number of samples without rounding errors. Baseparse will convert this into time itself when needed. https://bugzilla.gnome.org/show_bug.cgi?id=650785 --- gst/audioparsers/gstflacparse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0995d79784..0c6c529875 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -798,10 +798,10 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) if (!gst_bit_reader_get_bits_uint64 (&reader, &flacparse->total_samples, 36)) goto error; - if (flacparse->total_samples) - gst_base_parse_set_duration (GST_BASE_PARSE (flacparse), GST_FORMAT_TIME, - GST_FRAMES_TO_CLOCK_TIME (flacparse->total_samples, - flacparse->samplerate), 0); + if (flacparse->total_samples) { + gst_base_parse_set_duration (GST_BASE_PARSE (flacparse), + GST_FORMAT_DEFAULT, flacparse->total_samples, 0); + } GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n" "\tmin/max blocksize: %u/%u,\n" From 15ce1142ca8bb70931eb2bd2eddd2f17142acb2b Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 23 May 2011 18:06:44 +0300 Subject: [PATCH 20/28] matroska: refactor code common to matroskademux and matroskaparse Replace the following functions with their gst_matroska_read_common_* counterparts: - gst_matroska_{demux,parse}_parse_index - gst_matroska_{demux,parse}_parse_skip - gst_matroska_{demux,parse}_stream_from_num Introduce GstMatroskaReadCommon to contain those members of GstMatroskaDemux and GstMatroskaParse that were used by the above functions. https://bugzilla.gnome.org/show_bug.cgi?id=650877 --- gst/matroska/Makefile.am | 2 + gst/matroska/matroska-demux.c | 592 +++++++--------------------- gst/matroska/matroska-demux.h | 15 +- gst/matroska/matroska-parse.c | 530 +++++-------------------- gst/matroska/matroska-parse.h | 16 +- gst/matroska/matroska-read-common.c | 382 ++++++++++++++++++ gst/matroska/matroska-read-common.h | 69 ++++ 7 files changed, 703 insertions(+), 903 deletions(-) create mode 100644 gst/matroska/matroska-read-common.c create mode 100644 gst/matroska/matroska-read-common.h diff --git a/gst/matroska/Makefile.am b/gst/matroska/Makefile.am index 195c68057a..7d569737b3 100644 --- a/gst/matroska/Makefile.am +++ b/gst/matroska/Makefile.am @@ -8,6 +8,7 @@ libgstmatroska_la_SOURCES = \ matroska-parse.c \ matroska-ids.c \ matroska-mux.c \ + matroska-read-common.c \ webm-mux.c \ lzo.c @@ -19,6 +20,7 @@ noinst_HEADERS = \ matroska-parse.h \ matroska-ids.h \ matroska-mux.h \ + matroska-read-common.h \ webm-mux.h \ lzo.h diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 1f3dbd4138..5358652496 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -208,9 +208,9 @@ gst_matroska_demux_finalize (GObject * object) { GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object); - if (demux->src) { - g_ptr_array_free (demux->src, TRUE); - demux->src = NULL; + if (demux->common.src) { + g_ptr_array_free (demux->common.src, TRUE); + demux->common.src = NULL; } if (demux->global_tags) { @@ -263,11 +263,11 @@ gst_matroska_demux_init (GstMatroskaDemux * demux, gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); /* initial stream no. */ - demux->src = NULL; + demux->common.src = NULL; demux->writing_app = NULL; demux->muxing_app = NULL; - demux->index = NULL; + demux->common.index = NULL; demux->global_tags = NULL; demux->adapter = gst_adapter_new (); @@ -325,9 +325,10 @@ gst_matroska_demux_combine_flows (GstMatroskaDemux * demux, goto done; /* only return NOT_LINKED if all other pads returned NOT_LINKED */ - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->common.src, + i); if (ostream == NULL) continue; @@ -363,10 +364,11 @@ gst_matroska_demux_reset (GstElement * element) demux->state = GST_MATROSKA_DEMUX_STATE_START; /* clean up existing streams */ - if (demux->src) { - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + if (demux->common.src) { + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); if (context->pad != NULL) gst_element_remove_pad (GST_ELEMENT (demux), context->pad); @@ -374,11 +376,11 @@ gst_matroska_demux_reset (GstElement * element) gst_caps_replace (&context->caps, NULL); gst_matroska_track_free (context); } - g_ptr_array_free (demux->src, TRUE); + g_ptr_array_free (demux->common.src, TRUE); } - demux->src = g_ptr_array_new (); + demux->common.src = g_ptr_array_new (); - demux->num_streams = 0; + demux->common.num_streams = 0; demux->num_a_streams = 0; demux->num_t_streams = 0; demux->num_v_streams = 0; @@ -390,9 +392,9 @@ gst_matroska_demux_reset (GstElement * element) demux->muxing_app = NULL; /* reset indexes */ - if (demux->index) { - g_array_free (demux->index, TRUE); - demux->index = NULL; + if (demux->common.index) { + g_array_free (demux->common.index, TRUE); + demux->common.index = NULL; } if (demux->clusters) { @@ -402,10 +404,10 @@ gst_matroska_demux_reset (GstElement * element) /* reset timers */ demux->clock = NULL; - demux->time_scale = 1000000; + demux->common.time_scale = 1000000; demux->created = G_MININT64; - demux->index_parsed = FALSE; + demux->common.index_parsed = FALSE; demux->tracks_parsed = FALSE; demux->segmentinfo_parsed = FALSE; demux->attachments_parsed = FALSE; @@ -450,11 +452,11 @@ gst_matroska_demux_reset (GstElement * element) demux->new_segment = NULL; } - if (demux->element_index) { - gst_object_unref (demux->element_index); - demux->element_index = NULL; + if (demux->common.element_index) { + gst_object_unref (demux->common.element_index); + demux->common.element_index = NULL; } - demux->element_index_writer_id = -1; + demux->common.element_index_writer_id = -1; if (demux->global_tags) { gst_tag_list_free (demux->global_tags); @@ -583,27 +585,6 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux) return end; } -static gint -gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num) -{ - guint n; - - g_assert (demux->src->len == demux->num_streams); - for (n = 0; n < demux->src->len; n++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, n); - - if (context->num == track_num) { - return n; - } - } - - if (n == demux->num_streams) - GST_WARNING_OBJECT (demux, - "Failed to find corresponding pad for tracknum %d", track_num); - - return -1; -} - static gint gst_matroska_demux_encoding_cmp (GstMatroskaTrackEncoding * a, GstMatroskaTrackEncoding * b) @@ -1151,9 +1132,10 @@ gst_matroska_demux_tracknumber_unique (GstMatroskaDemux * demux, guint64 num) { gint i; - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); if (context->num == num) return FALSE; @@ -1187,8 +1169,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) /* allocate generic... if we know the type, we'll g_renew() * with the precise type */ context = g_new0 (GstMatroskaTrackContext, 1); - g_ptr_array_add (demux->src, context); - context->index = demux->num_streams; + g_ptr_array_add (demux->common.src, context); + context->index = demux->common.num_streams; context->index_writer_id = -1; context->type = 0; /* no type yet */ context->default_duration = 0; @@ -1200,8 +1182,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) GST_MATROSKA_TRACK_LACING; context->last_flow = GST_FLOW_OK; context->to_offset = G_MAXINT64; - demux->num_streams++; - g_assert (demux->src->len == demux->num_streams); + demux->common.num_streams++; + g_assert (demux->common.src->len == demux->common.num_streams); GST_DEBUG_OBJECT (demux, "Stream number %d", context->index); @@ -1293,7 +1275,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) context->type = 0; break; } - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; break; } @@ -1312,7 +1295,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; } videocontext = (GstMatroskaTrackVideoContext *) context; - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1532,7 +1516,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; audiocontext = (GstMatroskaTrackAudioContext *) context; - g_ptr_array_index (demux->src, demux->num_streams - 1) = context; + g_ptr_array_index (demux->common.src, demux->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1832,9 +1817,9 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml) if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header"); - demux->num_streams--; - g_ptr_array_remove_index (demux->src, demux->num_streams); - g_assert (demux->src->len == demux->num_streams); + demux->common.num_streams--; + g_ptr_array_remove_index (demux->common.src, demux->common.num_streams); + g_assert (demux->common.src->len == demux->common.num_streams); if (context) { gst_matroska_track_free (context); } @@ -2127,14 +2112,14 @@ gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, GstMatroskaIndex *entry = NULL; GArray *index; - if (!demux->index || !demux->index->len) + if (!demux->common.index || !demux->common.index->len) return NULL; /* find entry just before or at the requested position */ if (track && track->index_table) index = track->index_table; else - index = demux->index; + index = demux->common.index; entry = gst_util_array_binary_search (index->data, index->len, @@ -2187,11 +2172,11 @@ gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event) is_newsegment = (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT); - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (demux->src, i); + stream = g_ptr_array_index (demux->common.src, i); gst_event_ref (event); gst_pad_push_event (stream->pad, event); ret = TRUE; @@ -2249,10 +2234,10 @@ gst_matroska_demux_get_seek_track (GstMatroskaDemux * demux, if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) return track; - for (i = 0; i < demux->src->len; i++) { + for (i = 0; i < demux->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (demux->src, i); + stream = g_ptr_array_index (demux->common.src, i); if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table) track = stream; } @@ -2269,9 +2254,10 @@ gst_matroska_demux_reset_streams (GstMatroskaDemux * demux, GstClockTime time, GST_DEBUG_OBJECT (demux, "resetting stream state"); - g_assert (demux->src->len == demux->num_streams); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.src->len == demux->common.num_streams); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); context->pos = time; context->set_discont = TRUE; context->eos = FALSE; @@ -2297,10 +2283,10 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux, /* seek (relative to matroska segment) */ /* position might be invalid; will error when streaming resumes ... */ - demux->offset = entry->pos + demux->ebml_segment_start; + demux->offset = entry->pos + demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, " - "time %" GST_TIME_FORMAT, entry->pos + demux->ebml_segment_start, + "time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start, entry->block, GST_TIME_ARGS (entry->time)); /* update the time */ @@ -2310,8 +2296,8 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux, demux->seek_first = TRUE; demux->last_stop_end = GST_CLOCK_TIME_NONE; - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i); if (reset) { stream->to_offset = G_MAXINT64; @@ -2487,7 +2473,7 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time) /* estimate using start and current position */ GST_OBJECT_LOCK (demux); - opos = demux->offset - demux->ebml_segment_start; + opos = demux->offset - demux->common.ebml_segment_start; otime = demux->segment.last_stop; GST_OBJECT_UNLOCK (demux); @@ -2500,7 +2486,7 @@ retry: newpos = 0; /* favour undershoot */ newpos = newpos * 90 / 100; - newpos += demux->ebml_segment_start; + newpos += demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "estimated offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT, @@ -2558,7 +2544,7 @@ retry: } if (demux->cluster_time != GST_CLOCK_TIME_NONE && cluster_time == GST_CLOCK_TIME_NONE) { - cluster_time = demux->cluster_time * demux->time_scale; + cluster_time = demux->cluster_time * demux->common.time_scale; cluster_offset = demux->cluster_offset; GST_DEBUG_OBJECT (demux, "found cluster at offset %" G_GINT64_FORMAT " with time %" GST_TIME_FORMAT, cluster_offset, @@ -2609,7 +2595,7 @@ retry: entry = g_new0 (GstMatroskaIndex, 1); entry->time = prev_cluster_time; - entry->pos = prev_cluster_offset - demux->ebml_segment_start; + entry->pos = prev_cluster_offset - demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "simulated index entry; time %" GST_TIME_FORMAT ", pos %" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->time), entry->pos); @@ -2673,7 +2659,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, seeksegment.last_stop, &demux->seek_index, &demux->seek_entry)) == NULL) { /* pull mode without index can scan later on */ - if (demux->index || demux->streaming) { + if (demux->common.index || demux->streaming) { GST_DEBUG_OBJECT (demux, "No matching seek entry in index"); GST_OBJECT_UNLOCK (demux); return FALSE; @@ -2687,7 +2673,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, /* upstream takes care of flushing and all that * ... and newsegment event handling takes care of the rest */ return perform_seek_to_offset (demux, - entry->pos + demux->ebml_segment_start); + entry->pos + demux->common.ebml_segment_start); } flush = ! !(flags & GST_SEEK_FLAG_FLUSH); @@ -2709,7 +2695,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GST_PAD_STREAM_LOCK (demux->sinkpad); /* pull mode without index can do some scanning */ - if (!demux->streaming && !demux->index) { + if (!demux->streaming && !demux->common.index) { /* need to stop flushing upstream as we need it next */ if (flush) gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); @@ -2840,7 +2826,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad, } /* check for having parsed index already */ - if (!demux->index_parsed) { + if (!demux->common.index_parsed) { gboolean building_index; guint64 offset = 0; @@ -2958,8 +2944,8 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux) goto exit; } - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i); GST_DEBUG_OBJECT (demux, "segment start %" GST_TIME_FORMAT ", stream %d at %" GST_TIME_FORMAT, @@ -2993,23 +2979,6 @@ exit: return ret; } -/* skip unknown or alike element */ -static GstFlowReturn -gst_matroska_demux_parse_skip (GstMatroskaDemux * demux, GstEbmlRead * ebml, - const gchar * parent_name, guint id) -{ - if (id == GST_EBML_ID_VOID) { - GST_DEBUG_OBJECT (demux, "Skipping EBML Void element"); - } else if (id == GST_EBML_ID_CRC32) { - GST_DEBUG_OBJECT (demux, "Skipping EBML CRC32 element"); - } else { - GST_WARNING_OBJECT (demux, - "Unknown %s subelement 0x%x - ignoring", parent_name, id); - } - - return gst_ebml_read_skip (ebml); -} - static GstFlowReturn gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml) { @@ -3121,7 +3090,8 @@ gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "EBML header", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "EBML header", id); if (ret != GST_FLOW_OK) return ret; break; @@ -3190,7 +3160,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Track", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Track", id); break; } } @@ -3201,306 +3172,6 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml) return ret; } -static GstFlowReturn -gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux, - GstEbmlRead * ebml, guint * nentries) -{ - guint32 id; - GstFlowReturn ret; - GstMatroskaIndex idx; - - idx.pos = (guint64) - 1; - idx.track = 0; - idx.time = GST_CLOCK_TIME_NONE; - idx.block = 1; - - DEBUG_ELEMENT_START (demux, ebml, "CueTrackPositions"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* track number */ - case GST_MATROSKA_ID_CUETRACK: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - idx.track = 0; - GST_WARNING_OBJECT (demux, "Invalid CueTrack 0"); - break; - } - - GST_DEBUG_OBJECT (demux, "CueTrack: %" G_GUINT64_FORMAT, num); - idx.track = num; - break; - } - - /* position in file */ - case GST_MATROSKA_ID_CUECLUSTERPOSITION: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num > G_MAXINT64) { - GST_WARNING_OBJECT (demux, "CueClusterPosition %" G_GUINT64_FORMAT - " too large", num); - break; - } - - idx.pos = num; - break; - } - - /* number of block in the cluster */ - case GST_MATROSKA_ID_CUEBLOCKNUMBER: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - GST_WARNING_OBJECT (demux, "Invalid CueBlockNumber 0"); - break; - } - - GST_DEBUG_OBJECT (demux, "CueBlockNumber: %" G_GUINT64_FORMAT, num); - idx.block = num; - - /* mild sanity check, disregard strange cases ... */ - if (idx.block > G_MAXUINT16) { - GST_DEBUG_OBJECT (demux, "... looks suspicious, ignoring"); - idx.block = 1; - } - break; - } - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "CueTrackPositions", - id); - break; - - case GST_MATROSKA_ID_CUECODECSTATE: - case GST_MATROSKA_ID_CUEREFERENCE: - ret = gst_ebml_read_skip (ebml); - break; - } - } - - DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret); - - if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) - && idx.pos != (guint64) - 1 && idx.track > 0) { - g_array_append_val (demux->index, idx); - (*nentries)++; - } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { - GST_DEBUG_OBJECT (demux, "CueTrackPositions without valid content"); - } - - return ret; -} - -static GstFlowReturn -gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux, - GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret; - GstClockTime time = GST_CLOCK_TIME_NONE; - guint nentries = 0; - - DEBUG_ELEMENT_START (demux, ebml, "CuePoint"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_CUETIME: - { - if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) - break; - - GST_DEBUG_OBJECT (demux, "CueTime: %" G_GUINT64_FORMAT, time); - time = time * demux->time_scale; - break; - } - - /* position in the file + track to which it belongs */ - case GST_MATROSKA_ID_CUETRACKPOSITIONS: - { - if ((ret = - gst_matroska_demux_parse_index_cuetrack (demux, ebml, - &nentries)) != GST_FLOW_OK) - break; - break; - } - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "CuePoint", id); - break; - } - } - - DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret); - - if (nentries > 0) { - if (time == GST_CLOCK_TIME_NONE) { - GST_WARNING_OBJECT (demux, "CuePoint without valid time"); - g_array_remove_range (demux->index, demux->index->len - nentries, - nentries); - } else { - gint i; - - for (i = demux->index->len - nentries; i < demux->index->len; i++) { - GstMatroskaIndex *idx = - &g_array_index (demux->index, GstMatroskaIndex, i); - - idx->time = time; - GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT - ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, - GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); - } - } - } else { - GST_DEBUG_OBJECT (demux, "Empty CuePoint"); - } - - return ret; -} - -static gint -gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) -{ - if (i1->time < i2->time) - return -1; - else if (i1->time > i2->time) - return 1; - else if (i1->block < i2->block) - return -1; - else if (i1->block > i2->block) - return 1; - else - return 0; -} - -static GstFlowReturn -gst_matroska_demux_parse_index (GstMatroskaDemux * demux, GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret = GST_FLOW_OK; - guint i; - - if (demux->index) - g_array_free (demux->index, TRUE); - demux->index = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - DEBUG_ELEMENT_START (demux, ebml, "Cues"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_POINTENTRY: - ret = gst_matroska_demux_parse_index_pointentry (demux, ebml); - break; - - default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Cues", id); - break; - } - } - DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret); - - /* Sort index by time, smallest time first, for easier searching */ - g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare); - - /* Now sort the track specific index entries into their own arrays */ - for (i = 0; i < demux->index->len; i++) { - GstMatroskaIndex *idx = &g_array_index (demux->index, GstMatroskaIndex, i); - gint track_num; - GstMatroskaTrackContext *ctx; - - if (demux->element_index) { - gint writer_id; - - if (idx->track != 0 && - (track_num = - gst_matroska_demux_stream_from_num (demux, idx->track)) != -1) { - ctx = g_ptr_array_index (demux->src, track_num); - - if (ctx->index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, GST_OBJECT (ctx->pad), - &ctx->index_writer_id); - writer_id = ctx->index_writer_id; - } else { - if (demux->element_index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, GST_OBJECT (demux), - &demux->element_index_writer_id); - writer_id = demux->element_index_writer_id; - } - - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), - idx->pos, writer_id); - gst_index_add_association (demux->element_index, writer_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, - GST_FORMAT_BYTES, idx->pos + demux->ebml_segment_start, NULL); - } - - if (idx->track == 0) - continue; - - track_num = gst_matroska_demux_stream_from_num (demux, idx->track); - if (track_num == -1) - continue; - - ctx = g_ptr_array_index (demux->src, track_num); - - if (ctx->index_table == NULL) - ctx->index_table = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - g_array_append_vals (ctx->index_table, idx, 1); - } - - demux->index_parsed = TRUE; - - /* sanity check; empty index normalizes to no index */ - if (demux->index->len == 0) { - g_array_free (demux->index, TRUE); - demux->index = NULL; - } - - return ret; -} - static GstFlowReturn gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) { @@ -3529,7 +3200,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) GST_DEBUG_OBJECT (demux, "TimeCodeScale: %" G_GUINT64_FORMAT, num); - demux->time_scale = num; + demux->common.time_scale = num; break; } @@ -3596,7 +3267,8 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SegmentInfo", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SegmentInfo", id); break; /* fall through */ @@ -3617,7 +3289,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml) GstClockTime dur_u; dur_u = gst_gdouble_to_guint64 (dur_f * - gst_guint64_to_gdouble (demux->time_scale)); + gst_guint64_to_gdouble (demux->common.time_scale)); if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64) gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME, dur_u); } @@ -3692,7 +3364,8 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SimpleTag", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SimpleTag", id); break; /* fall-through */ @@ -3778,7 +3451,8 @@ gst_matroska_demux_parse_metadata_id_tag (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Tag", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Tag", id); break; } } @@ -3834,7 +3508,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, GstEbmlRead * ebml) break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Tags", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Tags", id); break; /* FIXME: Use to limit the tags to specific pads */ case GST_MATROSKA_ID_TARGETS: @@ -3917,7 +3592,8 @@ gst_matroska_demux_parse_attached_file (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "AttachedFile", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "AttachedFile", id); break; case GST_MATROSKA_ID_FILEUID: ret = gst_ebml_read_skip (ebml); @@ -4030,7 +3706,8 @@ gst_matroska_demux_parse_attachments (GstMatroskaDemux * demux, break; default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "Attachments", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "Attachments", id); break; } } @@ -4157,11 +3834,11 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux) GST_LOG_OBJECT (demux, "Sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (demux->segment.last_stop)); - g_assert (demux->num_streams == demux->src->len); - for (stream_nr = 0; stream_nr < demux->src->len; stream_nr++) { + g_assert (demux->common.num_streams == demux->common.src->len); + for (stream_nr = 0; stream_nr < demux->common.src->len; stream_nr++) { GstMatroskaTrackContext *context; - context = g_ptr_array_index (demux->src, stream_nr); + context = g_ptr_array_index (demux->common.src, stream_nr); GST_LOG_OBJECT (demux, "Checking for resync on stream %d (%" GST_TIME_FORMAT ")", stream_nr, @@ -4769,14 +4446,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, size -= n; /* fetch stream from num */ - stream_num = gst_matroska_demux_stream_from_num (demux, num); + stream_num = gst_matroska_read_common_stream_from_num (&demux->common, + num); if (G_UNLIKELY (size < 3)) { GST_WARNING_OBJECT (demux, "Invalid size %u", size); /* non-fatal, try next block(group) */ ret = GST_FLOW_OK; goto done; } else if (G_UNLIKELY (stream_num < 0 || - stream_num >= demux->num_streams)) { + stream_num >= demux->common.num_streams)) { /* let's not give up on a stray invalid track number */ GST_WARNING_OBJECT (demux, "Invalid stream %d for track number %" G_GUINT64_FORMAT @@ -4784,7 +4462,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, goto done; } - stream = g_ptr_array_index (demux->src, stream_num); + stream = g_ptr_array_index (demux->common.src, stream_num); /* time (relative to cluster time) */ time = ((gint16) GST_READ_UINT16_BE (data)); @@ -4944,7 +4622,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "BlockGroup", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "BlockGroup", id); break; case GST_MATROSKA_ID_BLOCKVIRTUAL: @@ -4971,7 +4650,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, gint64 lace_time = 0; gboolean delta_unit; - stream = g_ptr_array_index (demux->src, stream_num); + stream = g_ptr_array_index (demux->common.src, stream_num); if (cluster_time != GST_CLOCK_TIME_NONE) { /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1? @@ -4980,11 +4659,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, lace_time = 0; } else { if (stream->timecodescale == 1.0) - lace_time = (cluster_time + time) * demux->time_scale; + lace_time = (cluster_time + time) * demux->common.time_scale; else lace_time = gst_util_guint64_to_gdouble ((cluster_time + time) * - demux->time_scale) * stream->timecodescale; + demux->common.time_scale) * stream->timecodescale; } } else { lace_time = GST_CLOCK_TIME_NONE; @@ -5008,11 +4687,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, if (block_duration) { if (stream->timecodescale == 1.0) - duration = gst_util_uint64_scale (block_duration, demux->time_scale, 1); + duration = gst_util_uint64_scale (block_duration, + demux->common.time_scale, 1); else duration = gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble - (gst_util_uint64_scale (block_duration, demux->time_scale, + (gst_util_uint64_scale (block_duration, demux->common.time_scale, 1)) * stream->timecodescale); } else if (stream->default_duration) { duration = stream->default_duration * laces; @@ -5214,16 +4894,16 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), GST_TIME_ARGS (GST_BUFFER_DURATION (sub))); - if (demux->element_index) { + if (demux->common.element_index) { if (stream->index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, + gst_index_get_writer_id (demux->common.element_index, GST_OBJECT (stream->pad), &stream->index_writer_id); GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), cluster_offset, stream->index_writer_id); - gst_index_add_association (demux->element_index, + gst_index_add_association (demux->common.element_index, stream->index_writer_id, GST_BUFFER_FLAG_IS_SET (sub, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (sub), GST_FORMAT_BYTES, @@ -5360,7 +5040,8 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, ebml, + "SeekHead", id); break; } } @@ -5398,18 +5079,19 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } /* check for validity */ - if (seek_pos + demux->ebml_segment_start + 12 >= length) { + if (seek_pos + demux->common.ebml_segment_start + 12 >= length) { GST_WARNING_OBJECT (demux, "SeekHead reference lies outside file!" " (%" G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %" - G_GUINT64_FORMAT ")", seek_pos, demux->ebml_segment_start, length); + G_GUINT64_FORMAT ")", seek_pos, demux->common.ebml_segment_start, + length); break; } /* only pick up index location when streaming */ if (demux->streaming) { if (seek_id == GST_MATROSKA_ID_CUES) { - demux->index_offset = seek_pos + demux->ebml_segment_start; + demux->index_offset = seek_pos + demux->common.ebml_segment_start; GST_DEBUG_OBJECT (demux, "Cues located at offset %" G_GUINT64_FORMAT, demux->index_offset); } @@ -5417,7 +5099,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, } /* seek */ - demux->offset = seek_pos + demux->ebml_segment_start; + demux->offset = seek_pos + demux->common.ebml_segment_start; /* check ID */ if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length, @@ -5427,7 +5109,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, if (id != seek_id) { GST_WARNING_OBJECT (demux, "We looked for ID=0x%x but got ID=0x%x (pos=%" G_GUINT64_FORMAT ")", - seek_id, id, seek_pos + demux->ebml_segment_start); + seek_id, id, seek_pos + demux->common.ebml_segment_start); } else { /* now parse */ ret = gst_matroska_demux_parse_id (demux, id, length, needed); @@ -5441,7 +5123,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux, case GST_MATROSKA_ID_CLUSTER: { - guint64 pos = seek_pos + demux->ebml_segment_start; + guint64 pos = seek_pos + demux->common.ebml_segment_start; GST_LOG_OBJECT (demux, "Cluster position"); if (G_UNLIKELY (!demux->clusters)) @@ -5489,7 +5171,8 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml) } default: - ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&demux->common, + ebml, "SeekHead", id); break; } } @@ -5757,7 +5440,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, demux->offset); /* seeks are from the beginning of the segment, * after the segment ID/length */ - demux->ebml_segment_start = demux->offset; + demux->common.ebml_segment_start = demux->offset; demux->state = GST_MATROSKA_DEMUX_STATE_HEADER; break; default: @@ -5840,16 +5523,17 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, goto parse_failed; GST_DEBUG_OBJECT (demux, "ClusterTimeCode: %" G_GUINT64_FORMAT, num); demux->cluster_time = num; - if (demux->element_index) { - if (demux->element_index_writer_id == -1) - gst_index_get_writer_id (demux->element_index, - GST_OBJECT (demux), &demux->element_index_writer_id); + if (demux->common.element_index) { + if (demux->common.element_index_writer_id == -1) + gst_index_get_writer_id (demux->common.element_index, + GST_OBJECT (demux), &demux->common.element_index_writer_id); GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (demux->cluster_time), demux->cluster_offset, - demux->element_index_writer_id); - gst_index_add_association (demux->element_index, - demux->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT, + demux->common.element_index_writer_id); + gst_index_add_association (demux->common.element_index, + demux->common.element_index_writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, demux->cluster_time, GST_FORMAT_BYTES, demux->cluster_offset, NULL); } @@ -5896,12 +5580,12 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, ret = gst_matroska_demux_parse_contents (demux, &ebml); break; case GST_MATROSKA_ID_CUES: - if (demux->index_parsed) { + if (demux->common.index_parsed) { GST_READ_CHECK (gst_matroska_demux_flush (demux, read)); break; } GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml)); - ret = gst_matroska_demux_parse_index (demux, &ebml); + ret = gst_matroska_read_common_parse_index (&demux->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK && demux->state == GST_MATROSKA_DEMUX_STATE_SEEK) { @@ -6029,12 +5713,13 @@ gst_matroska_demux_loop (GstPad * pad) goto pause; /* check if we're at the end of a configured segment */ - if (G_LIKELY (demux->src->len)) { + if (G_LIKELY (demux->common.src->len)) { guint i; - g_assert (demux->num_streams == demux->src->len); - for (i = 0; i < demux->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i); + g_assert (demux->common.num_streams == demux->common.src->len); + for (i = 0; i < demux->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src, + i); GST_DEBUG_OBJECT (context->pad, "pos %" GST_TIME_FORMAT, GST_TIME_ARGS (context->pos)); if (context->eos == FALSE) @@ -6274,7 +5959,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); - } else if (demux->num_streams == 0) { + } else if (demux->common.num_streams == 0) { GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("got eos but no streams (yet)")); } else { @@ -7093,11 +6778,12 @@ gst_matroska_demux_set_index (GstElement * element, GstIndex * index) GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); GST_OBJECT_LOCK (demux); - if (demux->element_index) - gst_object_unref (demux->element_index); - demux->element_index = index ? gst_object_ref (index) : NULL; + if (demux->common.element_index) + gst_object_unref (demux->common.element_index); + demux->common.element_index = index ? gst_object_ref (index) : NULL; GST_OBJECT_UNLOCK (demux); - GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index); + GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, + demux->common.element_index); } static GstIndex * @@ -7107,8 +6793,8 @@ gst_matroska_demux_get_index (GstElement * element) GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element); GST_OBJECT_LOCK (demux); - if (demux->element_index) - result = gst_object_ref (demux->element_index); + if (demux->common.element_index) + result = gst_object_ref (demux->common.element_index); GST_OBJECT_UNLOCK (demux); GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result); diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h index a35a5935ac..a40366fd21 100644 --- a/gst/matroska/matroska-demux.h +++ b/gst/matroska/matroska-demux.h @@ -27,6 +27,7 @@ #include "ebml-read.h" #include "matroska-ids.h" +#include "matroska-read-common.h" G_BEGIN_DECLS @@ -55,14 +56,11 @@ typedef struct _GstMatroskaDemux { /* < private > */ - GstIndex *element_index; - gint element_index_writer_id; + GstMatroskaReadCommon common; /* pads */ GstPad *sinkpad; - GPtrArray *src; GstClock *clock; - guint num_streams; guint num_v_streams; guint num_a_streams; guint num_t_streams; @@ -80,24 +78,15 @@ typedef struct _GstMatroskaDemux { gboolean seek_first; /* did we parse cues/tracks/segmentinfo already? */ - gboolean index_parsed; gboolean tracks_parsed; gboolean segmentinfo_parsed; gboolean attachments_parsed; GList *tags_parsed; GList *seek_parsed; - /* start-of-segment */ - guint64 ebml_segment_start; - - /* a cue (index) table */ - GArray *index; /* cluster positions (optional) */ GArray *clusters; - /* timescale in the file */ - guint64 time_scale; - /* keeping track of playback position */ GstSegment segment; gboolean segment_running; diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c index 7d488494cf..927438bdba 100644 --- a/gst/matroska/matroska-parse.c +++ b/gst/matroska/matroska-parse.c @@ -170,9 +170,9 @@ gst_matroska_parse_finalize (GObject * object) { GstMatroskaParse *parse = GST_MATROSKA_PARSE (object); - if (parse->src) { - g_ptr_array_free (parse->src, TRUE); - parse->src = NULL; + if (parse->common.src) { + g_ptr_array_free (parse->common.src, TRUE); + parse->common.src = NULL; } if (parse->global_tags) { @@ -232,11 +232,11 @@ gst_matroska_parse_init (GstMatroskaParse * parse, gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); /* initial stream no. */ - parse->src = NULL; + parse->common.src = NULL; parse->writing_app = NULL; parse->muxing_app = NULL; - parse->index = NULL; + parse->common.index = NULL; parse->global_tags = NULL; parse->adapter = gst_adapter_new (); @@ -295,19 +295,20 @@ gst_matroska_parse_reset (GstElement * element) parse->state = GST_MATROSKA_PARSE_STATE_START; /* clean up existing streams */ - if (parse->src) { - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + if (parse->common.src) { + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); gst_caps_replace (&context->caps, NULL); gst_matroska_track_free (context); } - g_ptr_array_free (parse->src, TRUE); + g_ptr_array_free (parse->common.src, TRUE); } - parse->src = g_ptr_array_new (); + parse->common.src = g_ptr_array_new (); - parse->num_streams = 0; + parse->common.num_streams = 0; parse->num_a_streams = 0; parse->num_t_streams = 0; parse->num_v_streams = 0; @@ -319,17 +320,17 @@ gst_matroska_parse_reset (GstElement * element) parse->muxing_app = NULL; /* reset indexes */ - if (parse->index) { - g_array_free (parse->index, TRUE); - parse->index = NULL; + if (parse->common.index) { + g_array_free (parse->common.index, TRUE); + parse->common.index = NULL; } /* reset timers */ parse->clock = NULL; - parse->time_scale = 1000000; + parse->common.time_scale = 1000000; parse->created = G_MININT64; - parse->index_parsed = FALSE; + parse->common.index_parsed = FALSE; parse->tracks_parsed = FALSE; parse->segmentinfo_parsed = FALSE; parse->attachments_parsed = FALSE; @@ -374,11 +375,11 @@ gst_matroska_parse_reset (GstElement * element) parse->new_segment = NULL; } - if (parse->element_index) { - gst_object_unref (parse->element_index); - parse->element_index = NULL; + if (parse->common.element_index) { + gst_object_unref (parse->common.element_index); + parse->common.element_index = NULL; } - parse->element_index_writer_id = -1; + parse->common.element_index_writer_id = -1; if (parse->global_tags) { gst_tag_list_free (parse->global_tags); @@ -507,27 +508,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse) return end; } -static gint -gst_matroska_parse_stream_from_num (GstMatroskaParse * parse, guint track_num) -{ - guint n; - - g_assert (parse->src->len == parse->num_streams); - for (n = 0; n < parse->src->len; n++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, n); - - if (context->num == track_num) { - return n; - } - } - - if (n == parse->num_streams) - GST_WARNING_OBJECT (parse, - "Failed to find corresponding pad for tracknum %d", track_num); - - return -1; -} - static gint gst_matroska_parse_encoding_cmp (GstMatroskaTrackEncoding * a, GstMatroskaTrackEncoding * b) @@ -1041,9 +1021,10 @@ gst_matroska_parse_tracknumber_unique (GstMatroskaParse * parse, guint64 num) { gint i; - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); if (context->num == num) return FALSE; @@ -1070,8 +1051,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) /* allocate generic... if we know the type, we'll g_renew() * with the precise type */ context = g_new0 (GstMatroskaTrackContext, 1); - g_ptr_array_add (parse->src, context); - context->index = parse->num_streams; + g_ptr_array_add (parse->common.src, context); + context->index = parse->common.num_streams; context->index_writer_id = -1; context->type = 0; /* no type yet */ context->default_duration = 0; @@ -1083,8 +1064,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) GST_MATROSKA_TRACK_LACING; context->last_flow = GST_FLOW_OK; context->to_offset = G_MAXINT64; - parse->num_streams++; - g_assert (parse->src->len == parse->num_streams); + parse->common.num_streams++; + g_assert (parse->common.src->len == parse->common.num_streams); GST_DEBUG_OBJECT (parse, "Stream number %d", context->index); @@ -1176,7 +1157,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) context->type = 0; break; } - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; break; } @@ -1195,7 +1177,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) break; } videocontext = (GstMatroskaTrackVideoContext *) context; - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1415,7 +1398,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) break; audiocontext = (GstMatroskaTrackAudioContext *) context; - g_ptr_array_index (parse->src, parse->num_streams - 1) = context; + g_ptr_array_index (parse->common.src, parse->common.num_streams - 1) + = context; while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { @@ -1715,9 +1699,9 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml) if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header"); - parse->num_streams--; - g_ptr_array_remove_index (parse->src, parse->num_streams); - g_assert (parse->src->len == parse->num_streams); + parse->common.num_streams--; + g_ptr_array_remove_index (parse->common.src, parse->common.num_streams); + g_assert (parse->common.src->len == parse->common.num_streams); if (context) { gst_matroska_track_free (context); } @@ -1880,14 +1864,14 @@ gst_matroskaparse_do_index_seek (GstMatroskaParse * parse, GstMatroskaIndex *entry = NULL; GArray *index; - if (!parse->index || !parse->index->len) + if (!parse->common.index || !parse->common.index->len) return NULL; /* find entry just before or at the requested position */ if (track && track->index_table) index = track->index_table; else - index = parse->index; + index = parse->common.index; entry = gst_util_array_binary_search (index->data, index->len, @@ -1970,10 +1954,10 @@ gst_matroska_parse_get_seek_track (GstMatroskaParse * parse, if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO) return track; - for (i = 0; i < parse->src->len; i++) { + for (i = 0; i < parse->common.src->len; i++) { GstMatroskaTrackContext *stream; - stream = g_ptr_array_index (parse->src, i); + stream = g_ptr_array_index (parse->common.src, i); if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table) track = stream; } @@ -1989,9 +1973,10 @@ gst_matroska_parse_reset_streams (GstMatroskaParse * parse, GstClockTime time, GST_DEBUG_OBJECT (parse, "resetting stream state"); - g_assert (parse->src->len == parse->num_streams); - for (i = 0; i < parse->src->len; i++) { - GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i); + g_assert (parse->common.src->len == parse->common.num_streams); + for (i = 0; i < parse->common.src->len; i++) { + GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src, + i); context->pos = time; context->set_discont = TRUE; context->eos = FALSE; @@ -2153,7 +2138,8 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse, /* need to seek to cluster start to pick up cluster time */ /* upstream takes care of flushing and all that * ... and newsegment event handling takes care of the rest */ - return perform_seek_to_offset (parse, entry->pos + parse->ebml_segment_start); + return perform_seek_to_offset (parse, entry->pos + + parse->common.ebml_segment_start); } /* @@ -2198,7 +2184,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad, } /* check for having parsed index already */ - if (!parse->index_parsed) { + if (!parse->common.index_parsed) { gboolean building_index; guint64 offset = 0; @@ -2295,24 +2281,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event) return res; } - -/* skip unknown or alike element */ -static GstFlowReturn -gst_matroska_parse_parse_skip (GstMatroskaParse * parse, GstEbmlRead * ebml, - const gchar * parent_name, guint id) -{ - if (id == GST_EBML_ID_VOID) { - GST_DEBUG_OBJECT (parse, "Skipping EBML Void element"); - } else if (id == GST_EBML_ID_CRC32) { - GST_DEBUG_OBJECT (parse, "Skipping EBML CRC32 element"); - } else { - GST_WARNING_OBJECT (parse, - "Unknown %s subelement 0x%x - ignoring", parent_name, id); - } - - return gst_ebml_read_skip (ebml); -} - static GstFlowReturn gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml) { @@ -2424,7 +2392,8 @@ gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "EBML header", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "EBML header", id); if (ret != GST_FLOW_OK) return ret; break; @@ -2493,7 +2462,8 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml) break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Track", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Track", id); break; } } @@ -2504,306 +2474,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml) return ret; } -static GstFlowReturn -gst_matroska_parse_parse_index_cuetrack (GstMatroskaParse * parse, - GstEbmlRead * ebml, guint * nentries) -{ - guint32 id; - GstFlowReturn ret; - GstMatroskaIndex idx; - - idx.pos = (guint64) - 1; - idx.track = 0; - idx.time = GST_CLOCK_TIME_NONE; - idx.block = 1; - - DEBUG_ELEMENT_START (parse, ebml, "CueTrackPositions"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* track number */ - case GST_MATROSKA_ID_CUETRACK: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - idx.track = 0; - GST_WARNING_OBJECT (parse, "Invalid CueTrack 0"); - break; - } - - GST_DEBUG_OBJECT (parse, "CueTrack: %" G_GUINT64_FORMAT, num); - idx.track = num; - break; - } - - /* position in file */ - case GST_MATROSKA_ID_CUECLUSTERPOSITION: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num > G_MAXINT64) { - GST_WARNING_OBJECT (parse, "CueClusterPosition %" G_GUINT64_FORMAT - " too large", num); - break; - } - - idx.pos = num; - break; - } - - /* number of block in the cluster */ - case GST_MATROSKA_ID_CUEBLOCKNUMBER: - { - guint64 num; - - if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) - break; - - if (num == 0) { - GST_WARNING_OBJECT (parse, "Invalid CueBlockNumber 0"); - break; - } - - GST_DEBUG_OBJECT (parse, "CueBlockNumber: %" G_GUINT64_FORMAT, num); - idx.block = num; - - /* mild sanity check, disregard strange cases ... */ - if (idx.block > G_MAXUINT16) { - GST_DEBUG_OBJECT (parse, "... looks suspicious, ignoring"); - idx.block = 1; - } - break; - } - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "CueTrackPositions", - id); - break; - - case GST_MATROSKA_ID_CUECODECSTATE: - case GST_MATROSKA_ID_CUEREFERENCE: - ret = gst_ebml_read_skip (ebml); - break; - } - } - - DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret); - - if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) - && idx.pos != (guint64) - 1 && idx.track > 0) { - g_array_append_val (parse->index, idx); - (*nentries)++; - } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { - GST_DEBUG_OBJECT (parse, "CueTrackPositions without valid content"); - } - - return ret; -} - -static GstFlowReturn -gst_matroska_parse_parse_index_pointentry (GstMatroskaParse * parse, - GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret; - GstClockTime time = GST_CLOCK_TIME_NONE; - guint nentries = 0; - - DEBUG_ELEMENT_START (parse, ebml, "CuePoint"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_CUETIME: - { - if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) - break; - - GST_DEBUG_OBJECT (parse, "CueTime: %" G_GUINT64_FORMAT, time); - time = time * parse->time_scale; - break; - } - - /* position in the file + track to which it belongs */ - case GST_MATROSKA_ID_CUETRACKPOSITIONS: - { - if ((ret = - gst_matroska_parse_parse_index_cuetrack (parse, ebml, - &nentries)) != GST_FLOW_OK) - break; - break; - } - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "CuePoint", id); - break; - } - } - - DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret); - - if (nentries > 0) { - if (time == GST_CLOCK_TIME_NONE) { - GST_WARNING_OBJECT (parse, "CuePoint without valid time"); - g_array_remove_range (parse->index, parse->index->len - nentries, - nentries); - } else { - gint i; - - for (i = parse->index->len - nentries; i < parse->index->len; i++) { - GstMatroskaIndex *idx = - &g_array_index (parse->index, GstMatroskaIndex, i); - - idx->time = time; - GST_DEBUG_OBJECT (parse, "Index entry: pos=%" G_GUINT64_FORMAT - ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, - GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); - } - } - } else { - GST_DEBUG_OBJECT (parse, "Empty CuePoint"); - } - - return ret; -} - -static gint -gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) -{ - if (i1->time < i2->time) - return -1; - else if (i1->time > i2->time) - return 1; - else if (i1->block < i2->block) - return -1; - else if (i1->block > i2->block) - return 1; - else - return 0; -} - -static GstFlowReturn -gst_matroska_parse_parse_index (GstMatroskaParse * parse, GstEbmlRead * ebml) -{ - guint32 id; - GstFlowReturn ret = GST_FLOW_OK; - guint i; - - if (parse->index) - g_array_free (parse->index, TRUE); - parse->index = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - DEBUG_ELEMENT_START (parse, ebml, "Cues"); - - if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { - DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret); - return ret; - } - - while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { - if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) - break; - - switch (id) { - /* one single index entry ('point') */ - case GST_MATROSKA_ID_POINTENTRY: - ret = gst_matroska_parse_parse_index_pointentry (parse, ebml); - break; - - default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Cues", id); - break; - } - } - DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret); - - /* Sort index by time, smallest time first, for easier searching */ - g_array_sort (parse->index, (GCompareFunc) gst_matroska_index_compare); - - /* Now sort the track specific index entries into their own arrays */ - for (i = 0; i < parse->index->len; i++) { - GstMatroskaIndex *idx = &g_array_index (parse->index, GstMatroskaIndex, i); - gint track_num; - GstMatroskaTrackContext *ctx; - - if (parse->element_index) { - gint writer_id; - - if (idx->track != 0 && - (track_num = - gst_matroska_parse_stream_from_num (parse, idx->track)) != -1) { - ctx = g_ptr_array_index (parse->src, track_num); - - if (ctx->index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, GST_OBJECT (ctx->pad), - &ctx->index_writer_id); - writer_id = ctx->index_writer_id; - } else { - if (parse->element_index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, GST_OBJECT (parse), - &parse->element_index_writer_id); - writer_id = parse->element_index_writer_id; - } - - GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), - idx->pos, writer_id); - gst_index_add_association (parse->element_index, writer_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, - GST_FORMAT_BYTES, idx->pos + parse->ebml_segment_start, NULL); - } - - if (idx->track == 0) - continue; - - track_num = gst_matroska_parse_stream_from_num (parse, idx->track); - if (track_num == -1) - continue; - - ctx = g_ptr_array_index (parse->src, track_num); - - if (ctx->index_table == NULL) - ctx->index_table = - g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); - - g_array_append_vals (ctx->index_table, idx, 1); - } - - parse->index_parsed = TRUE; - - /* sanity check; empty index normalizes to no index */ - if (parse->index->len == 0) { - g_array_free (parse->index, TRUE); - parse->index = NULL; - } - - return ret; -} - static GstFlowReturn gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) { @@ -2832,7 +2502,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num); - parse->time_scale = num; + parse->common.time_scale = num; break; } @@ -2899,7 +2569,8 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SegmentInfo", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SegmentInfo", id); break; /* fall through */ @@ -2920,7 +2591,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml) GstClockTime dur_u; dur_u = gst_gdouble_to_guint64 (dur_f * - gst_guint64_to_gdouble (parse->time_scale)); + gst_guint64_to_gdouble (parse->common.time_scale)); if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64) gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u); } @@ -2994,7 +2665,8 @@ gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SimpleTag", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SimpleTag", id); break; /* fall-through */ @@ -3080,7 +2752,8 @@ gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Tag", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Tag", id); break; } } @@ -3136,7 +2809,8 @@ gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml) break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Tags", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Tags", id); break; /* FIXME: Use to limit the tags to specific pads */ case GST_MATROSKA_ID_TARGETS: @@ -3219,7 +2893,8 @@ gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "AttachedFile", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "AttachedFile", id); break; case GST_MATROSKA_ID_FILEUID: ret = gst_ebml_read_skip (ebml); @@ -3332,7 +3007,8 @@ gst_matroska_parse_parse_attachments (GstMatroskaParse * parse, break; default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "Attachments", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "Attachments", id); break; } } @@ -3498,14 +3174,15 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, size -= n; /* fetch stream from num */ - stream_num = gst_matroska_parse_stream_from_num (parse, num); + stream_num = gst_matroska_read_common_stream_from_num (&parse->common, + num); if (G_UNLIKELY (size < 3)) { GST_WARNING_OBJECT (parse, "Invalid size %u", size); /* non-fatal, try next block(group) */ ret = GST_FLOW_OK; goto done; } else if (G_UNLIKELY (stream_num < 0 || - stream_num >= parse->num_streams)) { + stream_num >= parse->common.num_streams)) { /* let's not give up on a stray invalid track number */ GST_WARNING_OBJECT (parse, "Invalid stream %d for track number %" G_GUINT64_FORMAT @@ -3513,7 +3190,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, goto done; } - stream = g_ptr_array_index (parse->src, stream_num); + stream = g_ptr_array_index (parse->common.src, stream_num); /* time (relative to cluster time) */ time = ((gint16) GST_READ_UINT16_BE (data)); @@ -3640,7 +3317,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "BlockGroup", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "BlockGroup", id); break; case GST_MATROSKA_ID_BLOCKVIRTUAL: @@ -3667,7 +3345,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, gint64 lace_time = 0; gboolean delta_unit; - stream = g_ptr_array_index (parse->src, stream_num); + stream = g_ptr_array_index (parse->common.src, stream_num); if (cluster_time != GST_CLOCK_TIME_NONE) { /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1? @@ -3676,11 +3354,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, lace_time = 0; } else { if (stream->timecodescale == 1.0) - lace_time = (cluster_time + time) * parse->time_scale; + lace_time = (cluster_time + time) * parse->common.time_scale; else lace_time = gst_util_guint64_to_gdouble ((cluster_time + time) * - parse->time_scale) * stream->timecodescale; + parse->common.time_scale) * stream->timecodescale; } } else { lace_time = GST_CLOCK_TIME_NONE; @@ -3707,11 +3385,12 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse, if (block_duration) { if (stream->timecodescale == 1.0) - duration = gst_util_uint64_scale (block_duration, parse->time_scale, 1); + duration = gst_util_uint64_scale (block_duration, + parse->common.time_scale, 1); else duration = gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble - (gst_util_uint64_scale (block_duration, parse->time_scale, + (gst_util_uint64_scale (block_duration, parse->common.time_scale, 1)) * stream->timecodescale); } else if (stream->default_duration) { duration = stream->default_duration * laces; @@ -4041,7 +3720,8 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse, } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SeekHead", id); break; } } @@ -4077,17 +3757,18 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse, } /* check for validity */ - if (seek_pos + parse->ebml_segment_start + 12 >= length) { + if (seek_pos + parse->common.ebml_segment_start + 12 >= length) { GST_WARNING_OBJECT (parse, "SeekHead reference lies outside file!" " (%" G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %" - G_GUINT64_FORMAT ")", seek_pos, parse->ebml_segment_start, length); + G_GUINT64_FORMAT ")", seek_pos, parse->common.ebml_segment_start, + length); break; } /* only pick up index location when streaming */ if (seek_id == GST_MATROSKA_ID_CUES) { - parse->index_offset = seek_pos + parse->ebml_segment_start; + parse->index_offset = seek_pos + parse->common.ebml_segment_start; GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT, parse->index_offset); } @@ -4133,7 +3814,8 @@ gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml) } default: - ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id); + ret = gst_matroska_read_common_parse_skip (&parse->common, ebml, + "SeekHead", id); break; } } @@ -4442,7 +4124,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, parse->offset); /* seeks are from the beginning of the segment, * after the segment ID/length */ - parse->ebml_segment_start = parse->offset; + parse->common.ebml_segment_start = parse->offset; parse->state = GST_MATROSKA_PARSE_STATE_HEADER; gst_matroska_parse_accumulate_streamheader (parse, ebml.buf); break; @@ -4514,16 +4196,17 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, goto parse_failed; GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num); parse->cluster_time = num; - if (parse->element_index) { - if (parse->element_index_writer_id == -1) - gst_index_get_writer_id (parse->element_index, - GST_OBJECT (parse), &parse->element_index_writer_id); + if (parse->common.element_index) { + if (parse->common.element_index_writer_id == -1) + gst_index_get_writer_id (parse->common.element_index, + GST_OBJECT (parse), &parse->common.element_index_writer_id); GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (parse->cluster_time), parse->cluster_offset, - parse->element_index_writer_id); - gst_index_add_association (parse->element_index, - parse->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT, + parse->common.element_index_writer_id); + gst_index_add_association (parse->common.element_index, + parse->common.element_index_writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, parse->cluster_time, GST_FORMAT_BYTES, parse->cluster_offset, NULL); } @@ -4576,8 +4259,8 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, break; case GST_MATROSKA_ID_CUES: GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml)); - if (!parse->index_parsed) { - ret = gst_matroska_parse_parse_index (parse, &ebml); + if (!parse->common.index_parsed) { + ret = gst_matroska_read_common_parse_index (&parse->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK && parse->state == GST_MATROSKA_PARSE_STATE_SEEK) { @@ -4955,7 +4638,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); - } else if (parse->num_streams == 0) { + } else if (parse->common.num_streams == 0) { GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("got eos but no streams (yet)")); } else { @@ -4988,11 +4671,12 @@ gst_matroska_parse_set_index (GstElement * element, GstIndex * index) GstMatroskaParse *parse = GST_MATROSKA_PARSE (element); GST_OBJECT_LOCK (parse); - if (parse->element_index) - gst_object_unref (parse->element_index); - parse->element_index = index ? gst_object_ref (index) : NULL; + if (parse->common.element_index) + gst_object_unref (parse->common.element_index); + parse->common.element_index = index ? gst_object_ref (index) : NULL; GST_OBJECT_UNLOCK (parse); - GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, parse->element_index); + GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, + parse->common.element_index); } static GstIndex * @@ -5002,8 +4686,8 @@ gst_matroska_parse_get_index (GstElement * element) GstMatroskaParse *parse = GST_MATROSKA_PARSE (element); GST_OBJECT_LOCK (parse); - if (parse->element_index) - result = gst_object_ref (parse->element_index); + if (parse->common.element_index) + result = gst_object_ref (parse->common.element_index); GST_OBJECT_UNLOCK (parse); GST_DEBUG_OBJECT (parse, "Returning index %" GST_PTR_FORMAT, result); diff --git a/gst/matroska/matroska-parse.h b/gst/matroska/matroska-parse.h index 595ead2e3c..452f6e0926 100644 --- a/gst/matroska/matroska-parse.h +++ b/gst/matroska/matroska-parse.h @@ -27,6 +27,7 @@ #include "ebml-read.h" #include "matroska-ids.h" +#include "matroska-read-common.h" G_BEGIN_DECLS @@ -55,15 +56,12 @@ typedef struct _GstMatroskaParse { /* < private > */ - GstIndex *element_index; - gint element_index_writer_id; + GstMatroskaReadCommon common; /* pads */ GstPad *sinkpad; GstPad *srcpad; - GPtrArray *src; GstClock *clock; - guint num_streams; guint num_v_streams; guint num_a_streams; guint num_t_streams; @@ -85,22 +83,12 @@ typedef struct _GstMatroskaParse { gboolean seek_first; /* did we parse cues/tracks/segmentinfo already? */ - gboolean index_parsed; gboolean tracks_parsed; gboolean segmentinfo_parsed; gboolean attachments_parsed; GList *tags_parsed; GList *seek_parsed; - /* start-of-segment */ - guint64 ebml_segment_start; - - /* a cue (index) table */ - GArray *index; - - /* timescale in the file */ - guint64 time_scale; - /* keeping track of playback position */ GstSegment segment; gboolean segment_running; diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c new file mode 100644 index 0000000000..9172c171d8 --- /dev/null +++ b/gst/matroska/matroska-read-common.c @@ -0,0 +1,382 @@ +/* GStreamer Matroska muxer/demuxer + * (c) 2011 Debarshi Ray + * + * matroska-read-common.c: shared by matroska file/stream demuxer and parser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ebml-read.h" +#include "matroska-ids.h" +#include "matroska-read-common.h" + +GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug); +#define GST_CAT_DEFAULT matroskareadcommon_debug + +#define DEBUG_ELEMENT_START(common, ebml, element) \ + GST_DEBUG_OBJECT (common, "Parsing " element " element at offset %" \ + G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml)) + +#define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \ + GST_DEBUG_OBJECT (common, "Parsing " element " element " \ + " finished with '%s'", gst_flow_get_name (ret)) + +static gint +gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) +{ + if (i1->time < i2->time) + return -1; + else if (i1->time > i2->time) + return 1; + else if (i1->block < i2->block) + return -1; + else if (i1->block > i2->block) + return 1; + else + return 0; +} + +/* skip unknown or alike element */ +GstFlowReturn +gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common, + GstEbmlRead * ebml, const gchar * parent_name, guint id) +{ + if (id == GST_EBML_ID_VOID) { + GST_DEBUG_OBJECT (common, "Skipping EBML Void element"); + } else if (id == GST_EBML_ID_CRC32) { + GST_DEBUG_OBJECT (common, "Skipping EBML CRC32 element"); + } else { + GST_WARNING_OBJECT (common, + "Unknown %s subelement 0x%x - ignoring", parent_name, id); + } + + return gst_ebml_read_skip (ebml); +} + +static GstFlowReturn +gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common, + GstEbmlRead * ebml, guint * nentries) +{ + guint32 id; + GstFlowReturn ret; + GstMatroskaIndex idx; + + idx.pos = (guint64) - 1; + idx.track = 0; + idx.time = GST_CLOCK_TIME_NONE; + idx.block = 1; + + DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* track number */ + case GST_MATROSKA_ID_CUETRACK: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num == 0) { + idx.track = 0; + GST_WARNING_OBJECT (common, "Invalid CueTrack 0"); + break; + } + + GST_DEBUG_OBJECT (common, "CueTrack: %" G_GUINT64_FORMAT, num); + idx.track = num; + break; + } + + /* position in file */ + case GST_MATROSKA_ID_CUECLUSTERPOSITION: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num > G_MAXINT64) { + GST_WARNING_OBJECT (common, "CueClusterPosition %" G_GUINT64_FORMAT + " too large", num); + break; + } + + idx.pos = num; + break; + } + + /* number of block in the cluster */ + case GST_MATROSKA_ID_CUEBLOCKNUMBER: + { + guint64 num; + + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + break; + + if (num == 0) { + GST_WARNING_OBJECT (common, "Invalid CueBlockNumber 0"); + break; + } + + GST_DEBUG_OBJECT (common, "CueBlockNumber: %" G_GUINT64_FORMAT, num); + idx.block = num; + + /* mild sanity check, disregard strange cases ... */ + if (idx.block > G_MAXUINT16) { + GST_DEBUG_OBJECT (common, "... looks suspicious, ignoring"); + idx.block = 1; + } + break; + } + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, + "CueTrackPositions", id); + break; + + case GST_MATROSKA_ID_CUECODECSTATE: + case GST_MATROSKA_ID_CUEREFERENCE: + ret = gst_ebml_read_skip (ebml); + break; + } + } + + DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret); + + if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) + && idx.pos != (guint64) - 1 && idx.track > 0) { + g_array_append_val (common->index, idx); + (*nentries)++; + } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) { + GST_DEBUG_OBJECT (common, "CueTrackPositions without valid content"); + } + + return ret; +} + +static GstFlowReturn +gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon * + common, GstEbmlRead * ebml) +{ + guint32 id; + GstFlowReturn ret; + GstClockTime time = GST_CLOCK_TIME_NONE; + guint nentries = 0; + + DEBUG_ELEMENT_START (common, ebml, "CuePoint"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* one single index entry ('point') */ + case GST_MATROSKA_ID_CUETIME: + { + if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK) + break; + + GST_DEBUG_OBJECT (common, "CueTime: %" G_GUINT64_FORMAT, time); + time = time * common->time_scale; + break; + } + + /* position in the file + track to which it belongs */ + case GST_MATROSKA_ID_CUETRACKPOSITIONS: + { + if ((ret = + gst_matroska_read_common_parse_index_cuetrack (common, ebml, + &nentries)) != GST_FLOW_OK) + break; + break; + } + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint", + id); + break; + } + } + + DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret); + + if (nentries > 0) { + if (time == GST_CLOCK_TIME_NONE) { + GST_WARNING_OBJECT (common, "CuePoint without valid time"); + g_array_remove_range (common->index, common->index->len - nentries, + nentries); + } else { + gint i; + + for (i = common->index->len - nentries; i < common->index->len; i++) { + GstMatroskaIndex *idx = + &g_array_index (common->index, GstMatroskaIndex, i); + + idx->time = time; + GST_DEBUG_OBJECT (common, "Index entry: pos=%" G_GUINT64_FORMAT + ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos, + GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block); + } + } + } else { + GST_DEBUG_OBJECT (common, "Empty CuePoint"); + } + + return ret; +} + +gint +gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common, + guint track_num) +{ + guint n; + + g_assert (common->src->len == common->num_streams); + for (n = 0; n < common->src->len; n++) { + GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n); + + if (context->num == track_num) { + return n; + } + } + + if (n == common->num_streams) + GST_WARNING_OBJECT (common, + "Failed to find corresponding pad for tracknum %d", track_num); + + return -1; +} + +GstFlowReturn +gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common, + GstEbmlRead * ebml) +{ + guint32 id; + GstFlowReturn ret = GST_FLOW_OK; + guint i; + + if (common->index) + g_array_free (common->index, TRUE); + common->index = + g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); + + DEBUG_ELEMENT_START (common, ebml, "Cues"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { + DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret); + return ret; + } + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + break; + + switch (id) { + /* one single index entry ('point') */ + case GST_MATROSKA_ID_POINTENTRY: + ret = gst_matroska_read_common_parse_index_pointentry (common, ebml); + break; + + default: + ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id); + break; + } + } + DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret); + + /* Sort index by time, smallest time first, for easier searching */ + g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare); + + /* Now sort the track specific index entries into their own arrays */ + for (i = 0; i < common->index->len; i++) { + GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex, + i); + gint track_num; + GstMatroskaTrackContext *ctx; + + if (common->element_index) { + gint writer_id; + + if (idx->track != 0 && + (track_num = + gst_matroska_read_common_stream_from_num (common, + idx->track)) != -1) { + ctx = g_ptr_array_index (common->src, track_num); + + if (ctx->index_writer_id == -1) + gst_index_get_writer_id (common->element_index, + GST_OBJECT (ctx->pad), &ctx->index_writer_id); + writer_id = ctx->index_writer_id; + } else { + if (common->element_index_writer_id == -1) + gst_index_get_writer_id (common->element_index, GST_OBJECT (common), + &common->element_index_writer_id); + writer_id = common->element_index_writer_id; + } + + GST_LOG_OBJECT (common, "adding association %" GST_TIME_FORMAT "-> %" + G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time), + idx->pos, writer_id); + gst_index_add_association (common->element_index, writer_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time, + GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL); + } + + if (idx->track == 0) + continue; + + track_num = gst_matroska_read_common_stream_from_num (common, idx->track); + if (track_num == -1) + continue; + + ctx = g_ptr_array_index (common->src, track_num); + + if (ctx->index_table == NULL) + ctx->index_table = + g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128); + + g_array_append_vals (ctx->index_table, idx, 1); + } + + common->index_parsed = TRUE; + + /* sanity check; empty index normalizes to no index */ + if (common->index->len == 0) { + g_array_free (common->index, TRUE); + common->index = NULL; + } + + return ret; +} diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h new file mode 100644 index 0000000000..df3f54b2bf --- /dev/null +++ b/gst/matroska/matroska-read-common.h @@ -0,0 +1,69 @@ +/* GStreamer Matroska muxer/demuxer + * (c) 2011 Debarshi Ray + * + * matroska-read-common.h: shared by matroska file/stream demuxer and parser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_MATROSKA_READ_COMMON_H__ +#define __GST_MATROSKA_READ_COMMON_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef enum { + GST_MATROSKA_READ_COMMON_STATE_START, + GST_MATROSKA_READ_COMMON_STATE_SEGMENT, + GST_MATROSKA_READ_COMMON_STATE_HEADER, + GST_MATROSKA_READ_COMMON_STATE_DATA, + GST_MATROSKA_READ_COMMON_STATE_SEEK, + GST_MATROSKA_READ_COMMON_STATE_SCANNING +} GstMatroskaReadCommonState; + +typedef struct _GstMatroskaReadCommon { + GstIndex *element_index; + gint element_index_writer_id; + + /* pads */ + GPtrArray *src; + guint num_streams; + + /* did we parse cues/tracks/segmentinfo already? */ + gboolean index_parsed; + + /* start-of-segment */ + guint64 ebml_segment_start; + + /* a cue (index) table */ + GArray *index; + + /* timescale in the file */ + guint64 time_scale; +} GstMatroskaReadCommon; + +GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon * + common, GstEbmlRead * ebml); +GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * + common, GstEbmlRead * ebml, const gchar * parent_name, guint id); +gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common, + guint track_num); + +G_END_DECLS + +#endif /* __GST_MATROSKA_READ_COMMON_H__ */ From 16d71c7d96ac6a3b9a7f55f37da64011597605c4 Mon Sep 17 00:00:00 2001 From: Miguel Angel Cabrera Moya Date: Mon, 23 May 2011 02:46:38 -0700 Subject: [PATCH 21/28] deinterlace: fix parameter type in trace https://bugzilla.gnome.org/show_bug.cgi?id=650937 --- gst/deinterlace/gstdeinterlace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index 0ea263b5c6..415cb00691 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -1086,7 +1086,7 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer) GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT - ", size %u, state %u, interlacing method %d", GST_BUFFER_DATA (buffer), + ", size %u, state %u, interlacing method %s", GST_BUFFER_DATA (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer), buf_state, From 090e3a6f41c0016bf7d96c93970a6ebd0224603f Mon Sep 17 00:00:00 2001 From: Jonas Larsson Date: Tue, 24 May 2011 09:48:56 +0200 Subject: [PATCH 22/28] qtdemux: Fix buffer leak with corrupted files Fixes bug #650912. --- gst/isomp4/qtdemux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 416b164e54..898fc71f6d 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -2723,6 +2723,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) ("We got less than expected (received %u, wanted %u, offset %" G_GUINT64_FORMAT ")", GST_BUFFER_SIZE (moov), (guint) length, cur_offset)); + gst_buffer_unref (moov); ret = GST_FLOW_ERROR; goto beach; } From 51c7e6d252466bc332332fb91234f4519e58b57a Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 23 May 2011 18:48:57 +0300 Subject: [PATCH 23/28] matroska: move GstMatroska{Demux,Parse}::state to GstMatroskaReadCommon https://bugzilla.gnome.org/show_bug.cgi?id=650877 --- gst/matroska/matroska-demux.c | 50 +++++++++++++++-------------- gst/matroska/matroska-demux.h | 11 +------ gst/matroska/matroska-parse.c | 40 ++++++++++++----------- gst/matroska/matroska-parse.h | 11 +------ gst/matroska/matroska-read-common.h | 17 ++++++---- 5 files changed, 59 insertions(+), 70 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 5358652496..8a358bca28 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -2,6 +2,7 @@ * (c) 2003 Ronald Bultje * (c) 2006 Tim-Philipp Müller * (c) 2008 Sebastian Dröge + * (c) 2011 Debarshi Ray * * matroska-demux.c: matroska file/stream demuxer * @@ -361,7 +362,7 @@ gst_matroska_demux_reset (GstElement * element) GST_DEBUG_OBJECT (demux, "Resetting state"); /* reset input */ - demux->state = GST_MATROSKA_DEMUX_STATE_START; + demux->common.state = GST_MATROSKA_READ_STATE_START; /* clean up existing streams */ if (demux->common.src) { @@ -2444,7 +2445,7 @@ static GstMatroskaIndex * gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time) { GstMatroskaIndex *entry = NULL; - GstMatroskaDemuxState current_state; + GstMatroskaReadState current_state; GstClockTime otime, prev_cluster_time, current_cluster_time, cluster_time; gint64 opos, newpos, startpos = 0, current_offset; gint64 prev_cluster_offset = -1, current_cluster_offset, cluster_offset; @@ -2462,14 +2463,14 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time) prev_cluster_time = GST_CLOCK_TIME_NONE; /* store some current state */ - current_state = demux->state; - g_return_val_if_fail (current_state == GST_MATROSKA_DEMUX_STATE_DATA, NULL); + current_state = demux->common.state; + g_return_val_if_fail (current_state == GST_MATROSKA_READ_STATE_DATA, NULL); current_cluster_offset = demux->cluster_offset; current_cluster_time = demux->cluster_time; current_offset = demux->offset; - demux->state = GST_MATROSKA_DEMUX_STATE_SCANNING; + demux->common.state = GST_MATROSKA_READ_STATE_SCANNING; /* estimate using start and current position */ GST_OBJECT_LOCK (demux); @@ -2607,7 +2608,7 @@ exit: demux->cluster_offset = current_cluster_offset; demux->cluster_time = current_cluster_time; demux->offset = current_offset; - demux->state = current_state; + demux->common.state = current_state; return entry; } @@ -2837,7 +2838,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad, GST_OBJECT_LOCK (demux); /* handle the seek event in the chain function */ - demux->state = GST_MATROSKA_DEMUX_STATE_SEEK; + demux->common.state = GST_MATROSKA_READ_STATE_SEEK; /* no more seek can be issued until state reset to _DATA */ /* copy the event */ @@ -2877,7 +2878,7 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: /* no seeking until we are (safely) ready */ - if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) { + if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) { GST_DEBUG_OBJECT (demux, "not ready for seeking yet"); return FALSE; } @@ -5414,15 +5415,15 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, if (G_LIKELY (length != G_MAXUINT64)) read += needed; - switch (demux->state) { - case GST_MATROSKA_DEMUX_STATE_START: + switch (demux->common.state) { + case GST_MATROSKA_READ_STATE_START: switch (id) { case GST_EBML_ID_HEADER: GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml)); ret = gst_matroska_demux_parse_header (demux, &ebml); if (ret != GST_FLOW_OK) goto parse_failed; - demux->state = GST_MATROSKA_DEMUX_STATE_SEGMENT; + demux->common.state = GST_MATROSKA_READ_STATE_SEGMENT; gst_matroska_demux_check_seekability (demux); break; default: @@ -5430,7 +5431,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, break; } break; - case GST_MATROSKA_DEMUX_STATE_SEGMENT: + case GST_MATROSKA_READ_STATE_SEGMENT: switch (id) { case GST_MATROSKA_ID_SEGMENT: /* eat segment prefix */ @@ -5441,7 +5442,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, /* seeks are from the beginning of the segment, * after the segment ID/length */ demux->common.ebml_segment_start = demux->offset; - demux->state = GST_MATROSKA_DEMUX_STATE_HEADER; + demux->common.state = GST_MATROSKA_READ_STATE_HEADER; break; default: GST_WARNING_OBJECT (demux, @@ -5451,14 +5452,14 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, break; } break; - case GST_MATROSKA_DEMUX_STATE_SCANNING: + case GST_MATROSKA_READ_STATE_SCANNING: if (id != GST_MATROSKA_ID_CLUSTER && id != GST_MATROSKA_ID_CLUSTERTIMECODE) goto skip; /* fall-through */ - case GST_MATROSKA_DEMUX_STATE_HEADER: - case GST_MATROSKA_DEMUX_STATE_DATA: - case GST_MATROSKA_DEMUX_STATE_SEEK: + case GST_MATROSKA_READ_STATE_HEADER: + case GST_MATROSKA_READ_STATE_DATA: + case GST_MATROSKA_READ_STATE_SEEK: switch (id) { case GST_MATROSKA_ID_SEGMENTINFO: if (!demux->segmentinfo_parsed) { @@ -5487,8 +5488,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, goto no_tracks; } } - if (G_UNLIKELY (demux->state == GST_MATROSKA_DEMUX_STATE_HEADER)) { - demux->state = GST_MATROSKA_DEMUX_STATE_DATA; + if (G_UNLIKELY (demux->common.state + == GST_MATROSKA_READ_STATE_HEADER)) { + demux->common.state = GST_MATROSKA_READ_STATE_DATA; demux->first_cluster_offset = demux->offset; GST_DEBUG_OBJECT (demux, "signaling no more pads"); gst_element_no_more_pads (GST_ELEMENT (demux)); @@ -5588,7 +5590,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, ret = gst_matroska_read_common_parse_index (&demux->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK - && demux->state == GST_MATROSKA_DEMUX_STATE_SEEK) { + && demux->common.state == GST_MATROSKA_READ_STATE_SEEK) { GstEvent *event; GST_OBJECT_LOCK (demux); @@ -5602,7 +5604,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id, goto seek_failed; /* resume data handling, main thread clear to seek again */ GST_OBJECT_LOCK (demux); - demux->state = GST_MATROSKA_DEMUX_STATE_DATA; + demux->common.state = GST_MATROSKA_READ_STATE_DATA; GST_OBJECT_UNLOCK (demux); } break; @@ -5681,7 +5683,7 @@ gst_matroska_demux_loop (GstPad * pad) guint needed; /* If we have to close a segment, send a new segment to do this now */ - if (G_LIKELY (demux->state == GST_MATROSKA_DEMUX_STATE_DATA)) { + if (G_LIKELY (demux->common.state == GST_MATROSKA_READ_STATE_DATA)) { if (G_UNLIKELY (demux->close_segment)) { gst_matroska_demux_send_event (demux, demux->close_segment); demux->close_segment = NULL; @@ -5919,7 +5921,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event) "received format %d newsegment %" GST_SEGMENT_FORMAT, format, &segment); - if (demux->state < GST_MATROSKA_DEMUX_STATE_DATA) { + if (demux->common.state < GST_MATROSKA_READ_STATE_DATA) { GST_DEBUG_OBJECT (demux, "still starting"); goto exit; } @@ -5955,7 +5957,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event) } case GST_EVENT_EOS: { - if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) { + if (demux->common.state != GST_MATROSKA_READ_STATE_DATA) { gst_event_unref (event); GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h index a40366fd21..d0df0ac939 100644 --- a/gst/matroska/matroska-demux.h +++ b/gst/matroska/matroska-demux.h @@ -1,5 +1,6 @@ /* GStreamer Matroska muxer/demuxer * (c) 2003 Ronald Bultje + * (c) 2011 Debarshi Ray * * matroska-demux.h: matroska file/stream demuxer definition * @@ -42,15 +43,6 @@ G_BEGIN_DECLS #define GST_IS_MATROSKA_DEMUX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_DEMUX)) -typedef enum { - GST_MATROSKA_DEMUX_STATE_START, - GST_MATROSKA_DEMUX_STATE_SEGMENT, - GST_MATROSKA_DEMUX_STATE_HEADER, - GST_MATROSKA_DEMUX_STATE_DATA, - GST_MATROSKA_DEMUX_STATE_SEEK, - GST_MATROSKA_DEMUX_STATE_SCANNING -} GstMatroskaDemuxState; - typedef struct _GstMatroskaDemux { GstElement parent; @@ -72,7 +64,6 @@ typedef struct _GstMatroskaDemux { /* state */ gboolean streaming; - GstMatroskaDemuxState state; guint level_up; guint64 seek_block; gboolean seek_first; diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c index 927438bdba..3dfb94426f 100644 --- a/gst/matroska/matroska-parse.c +++ b/gst/matroska/matroska-parse.c @@ -2,6 +2,7 @@ * (c) 2003 Ronald Bultje * (c) 2006 Tim-Philipp Müller * (c) 2008 Sebastian Dröge + * (c) 2011 Debarshi Ray * * matroska-parse.c: matroska file/stream parser * @@ -292,7 +293,7 @@ gst_matroska_parse_reset (GstElement * element) GST_DEBUG_OBJECT (parse, "Resetting state"); /* reset input */ - parse->state = GST_MATROSKA_PARSE_STATE_START; + parse->common.state = GST_MATROSKA_READ_STATE_START; /* clean up existing streams */ if (parse->common.src) { @@ -2195,7 +2196,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad, GST_OBJECT_LOCK (parse); /* handle the seek event in the chain function */ - parse->state = GST_MATROSKA_PARSE_STATE_SEEK; + parse->common.state = GST_MATROSKA_READ_STATE_SEEK; /* no more seek can be issued until state reset to _DATA */ /* copy the event */ @@ -2235,7 +2236,7 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: /* no seeking until we are (safely) ready */ - if (parse->state != GST_MATROSKA_PARSE_STATE_DATA) { + if (parse->common.state != GST_MATROSKA_READ_STATE_DATA) { GST_DEBUG_OBJECT (parse, "not ready for seeking yet"); return FALSE; } @@ -4097,15 +4098,15 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, if (G_LIKELY (length != G_MAXUINT64)) read += needed; - switch (parse->state) { - case GST_MATROSKA_PARSE_STATE_START: + switch (parse->common.state) { + case GST_MATROSKA_READ_STATE_START: switch (id) { case GST_EBML_ID_HEADER: GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml)); ret = gst_matroska_parse_parse_header (parse, &ebml); if (ret != GST_FLOW_OK) goto parse_failed; - parse->state = GST_MATROSKA_PARSE_STATE_SEGMENT; + parse->common.state = GST_MATROSKA_READ_STATE_SEGMENT; gst_matroska_parse_check_seekability (parse); gst_matroska_parse_accumulate_streamheader (parse, ebml.buf); break; @@ -4114,7 +4115,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, break; } break; - case GST_MATROSKA_PARSE_STATE_SEGMENT: + case GST_MATROSKA_READ_STATE_SEGMENT: switch (id) { case GST_MATROSKA_ID_SEGMENT: /* eat segment prefix */ @@ -4125,7 +4126,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, /* seeks are from the beginning of the segment, * after the segment ID/length */ parse->common.ebml_segment_start = parse->offset; - parse->state = GST_MATROSKA_PARSE_STATE_HEADER; + parse->common.state = GST_MATROSKA_READ_STATE_HEADER; gst_matroska_parse_accumulate_streamheader (parse, ebml.buf); break; default: @@ -4137,14 +4138,14 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, break; } break; - case GST_MATROSKA_PARSE_STATE_SCANNING: + case GST_MATROSKA_READ_STATE_SCANNING: if (id != GST_MATROSKA_ID_CLUSTER && id != GST_MATROSKA_ID_CLUSTERTIMECODE) goto skip; /* fall-through */ - case GST_MATROSKA_PARSE_STATE_HEADER: - case GST_MATROSKA_PARSE_STATE_DATA: - case GST_MATROSKA_PARSE_STATE_SEEK: + case GST_MATROSKA_READ_STATE_HEADER: + case GST_MATROSKA_READ_STATE_DATA: + case GST_MATROSKA_READ_STATE_SEEK: switch (id) { case GST_MATROSKA_ID_SEGMENTINFO: GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml)); @@ -4165,8 +4166,9 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, GST_DEBUG_OBJECT (parse, "Cluster before Track"); goto not_streamable; } - if (G_UNLIKELY (parse->state == GST_MATROSKA_PARSE_STATE_HEADER)) { - parse->state = GST_MATROSKA_PARSE_STATE_DATA; + if (G_UNLIKELY (parse->common.state + == GST_MATROSKA_READ_STATE_HEADER)) { + parse->common.state = GST_MATROSKA_READ_STATE_DATA; parse->first_cluster_offset = parse->offset; GST_DEBUG_OBJECT (parse, "signaling no more pads"); } @@ -4263,7 +4265,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, ret = gst_matroska_read_common_parse_index (&parse->common, &ebml); /* only push based; delayed index building */ if (ret == GST_FLOW_OK - && parse->state == GST_MATROSKA_PARSE_STATE_SEEK) { + && parse->common.state == GST_MATROSKA_READ_STATE_SEEK) { GstEvent *event; GST_OBJECT_LOCK (parse); @@ -4277,7 +4279,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id, goto seek_failed; /* resume data handling, main thread clear to seek again */ GST_OBJECT_LOCK (parse); - parse->state = GST_MATROSKA_PARSE_STATE_DATA; + parse->common.state = GST_MATROSKA_READ_STATE_DATA; GST_OBJECT_UNLOCK (parse); } } @@ -4362,7 +4364,7 @@ gst_matroska_parse_loop (GstPad * pad) guint needed; /* If we have to close a segment, send a new segment to do this now */ - if (G_LIKELY (parse->state == GST_MATROSKA_PARSE_STATE_DATA)) { + if (G_LIKELY (parse->common.state == GST_MATROSKA_READ_STATE_DATA)) { if (G_UNLIKELY (parse->close_segment)) { gst_matroska_parse_send_event (parse, parse->close_segment); parse->close_segment = NULL; @@ -4600,7 +4602,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event) "received format %d newsegment %" GST_SEGMENT_FORMAT, format, &segment); - if (parse->state < GST_MATROSKA_PARSE_STATE_DATA) { + if (parse->common.state < GST_MATROSKA_READ_STATE_DATA) { GST_DEBUG_OBJECT (parse, "still starting"); goto exit; } @@ -4634,7 +4636,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event) } case GST_EVENT_EOS: { - if (parse->state != GST_MATROSKA_PARSE_STATE_DATA) { + if (parse->common.state != GST_MATROSKA_READ_STATE_DATA) { gst_event_unref (event); GST_ELEMENT_ERROR (parse, STREAM, DEMUX, (NULL), ("got eos and didn't receive a complete header object")); diff --git a/gst/matroska/matroska-parse.h b/gst/matroska/matroska-parse.h index 452f6e0926..98b399d3bc 100644 --- a/gst/matroska/matroska-parse.h +++ b/gst/matroska/matroska-parse.h @@ -1,5 +1,6 @@ /* GStreamer Matroska muxer/demuxer * (c) 2003 Ronald Bultje + * (c) 2011 Debarshi Ray * * matroska-parse.h: matroska file/stream parseer definition * @@ -42,15 +43,6 @@ G_BEGIN_DECLS #define GST_IS_MATROSKA_PARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MATROSKA_PARSE)) -typedef enum { - GST_MATROSKA_PARSE_STATE_START, - GST_MATROSKA_PARSE_STATE_SEGMENT, - GST_MATROSKA_PARSE_STATE_HEADER, - GST_MATROSKA_PARSE_STATE_DATA, - GST_MATROSKA_PARSE_STATE_SEEK, - GST_MATROSKA_PARSE_STATE_SCANNING -} GstMatroskaParseState; - typedef struct _GstMatroskaParse { GstElement parent; @@ -77,7 +69,6 @@ typedef struct _GstMatroskaParse { /* state */ //gboolean streaming; - GstMatroskaParseState state; guint level_up; guint64 seek_block; gboolean seek_first; diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h index df3f54b2bf..a413f0b165 100644 --- a/gst/matroska/matroska-read-common.h +++ b/gst/matroska/matroska-read-common.h @@ -28,13 +28,13 @@ G_BEGIN_DECLS typedef enum { - GST_MATROSKA_READ_COMMON_STATE_START, - GST_MATROSKA_READ_COMMON_STATE_SEGMENT, - GST_MATROSKA_READ_COMMON_STATE_HEADER, - GST_MATROSKA_READ_COMMON_STATE_DATA, - GST_MATROSKA_READ_COMMON_STATE_SEEK, - GST_MATROSKA_READ_COMMON_STATE_SCANNING -} GstMatroskaReadCommonState; + GST_MATROSKA_READ_STATE_START, + GST_MATROSKA_READ_STATE_SEGMENT, + GST_MATROSKA_READ_STATE_HEADER, + GST_MATROSKA_READ_STATE_DATA, + GST_MATROSKA_READ_STATE_SEEK, + GST_MATROSKA_READ_STATE_SCANNING +} GstMatroskaReadState; typedef struct _GstMatroskaReadCommon { GstIndex *element_index; @@ -44,6 +44,9 @@ typedef struct _GstMatroskaReadCommon { GPtrArray *src; guint num_streams; + /* state */ + GstMatroskaReadState state; + /* did we parse cues/tracks/segmentinfo already? */ gboolean index_parsed; From 85036682cbe341da237830aae6123e52e6aa6580 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 23 May 2011 18:06:44 +0300 Subject: [PATCH 24/28] matroska: refactor code common to matroskademux and matroskaparse Move the following functions to matroska-read-common.[ch] from matroska-demux.c and matroska-parse.c: - gst_matroska_decode_content_encodings - gst_matroska_decompress_data https://bugzilla.gnome.org/show_bug.cgi?id=650877 --- gst/matroska/matroska-demux.c | 223 --------------------------- gst/matroska/matroska-parse.c | 223 --------------------------- gst/matroska/matroska-read-common.c | 226 +++++++++++++++++++++++++++- gst/matroska/matroska-read-common.h | 6 + 4 files changed, 231 insertions(+), 447 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 8a358bca28..3a4be60850 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -63,18 +63,8 @@ #include -#ifdef HAVE_ZLIB -#include -#endif - -#ifdef HAVE_BZ2 -#include -#endif - #include -#include "lzo.h" - #include "matroska-demux.h" #include "matroska-ids.h" @@ -775,176 +765,6 @@ gst_matroska_demux_read_track_encoding (GstMatroskaDemux * demux, return ret; } -static gboolean -gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc, - guint8 ** data_out, guint * size_out, - GstMatroskaTrackCompressionAlgorithm algo) -{ - guint8 *new_data = NULL; - guint new_size = 0; - guint8 *data = *data_out; - guint size = *size_out; - gboolean ret = TRUE; - - if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) { -#ifdef HAVE_ZLIB - /* zlib encoded data */ - z_stream zstream; - guint orig_size; - int result; - - orig_size = size; - zstream.zalloc = (alloc_func) 0; - zstream.zfree = (free_func) 0; - zstream.opaque = (voidpf) 0; - if (inflateInit (&zstream) != Z_OK) { - GST_WARNING ("zlib initialization failed."); - ret = FALSE; - goto out; - } - zstream.next_in = (Bytef *) data; - zstream.avail_in = orig_size; - new_size = orig_size; - new_data = g_malloc (new_size); - zstream.avail_out = new_size; - zstream.next_out = (Bytef *) new_data; - - do { - result = inflate (&zstream, Z_NO_FLUSH); - if (result != Z_OK && result != Z_STREAM_END) { - GST_WARNING ("zlib decompression failed."); - g_free (new_data); - inflateEnd (&zstream); - break; - } - new_size += 4000; - new_data = g_realloc (new_data, new_size); - zstream.next_out = (Bytef *) (new_data + zstream.total_out); - zstream.avail_out += 4000; - } while (zstream.avail_in != 0 && result != Z_STREAM_END); - - if (result != Z_STREAM_END) { - ret = FALSE; - goto out; - } else { - new_size = zstream.total_out; - inflateEnd (&zstream); - } -#else - GST_WARNING ("zlib encoded tracks not supported."); - ret = FALSE; - goto out; -#endif - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) { -#ifdef HAVE_BZ2 - /* bzip2 encoded data */ - bz_stream bzstream; - guint orig_size; - int result; - - bzstream.bzalloc = NULL; - bzstream.bzfree = NULL; - bzstream.opaque = NULL; - orig_size = size; - - if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) { - GST_WARNING ("bzip2 initialization failed."); - ret = FALSE; - goto out; - } - - bzstream.next_in = (char *) data; - bzstream.avail_in = orig_size; - new_size = orig_size; - new_data = g_malloc (new_size); - bzstream.avail_out = new_size; - bzstream.next_out = (char *) new_data; - - do { - result = BZ2_bzDecompress (&bzstream); - if (result != BZ_OK && result != BZ_STREAM_END) { - GST_WARNING ("bzip2 decompression failed."); - g_free (new_data); - BZ2_bzDecompressEnd (&bzstream); - break; - } - new_size += 4000; - new_data = g_realloc (new_data, new_size); - bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32); - bzstream.avail_out += 4000; - } while (bzstream.avail_in != 0 && result != BZ_STREAM_END); - - if (result != BZ_STREAM_END) { - ret = FALSE; - goto out; - } else { - new_size = bzstream.total_out_lo32; - BZ2_bzDecompressEnd (&bzstream); - } -#else - GST_WARNING ("bzip2 encoded tracks not supported."); - ret = FALSE; - goto out; -#endif - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) { - /* lzo encoded data */ - int result; - int orig_size, out_size; - - orig_size = size; - out_size = size; - new_size = size; - new_data = g_malloc (new_size); - - do { - orig_size = size; - out_size = new_size; - - result = lzo1x_decode (new_data, &out_size, data, &orig_size); - - if (orig_size > 0) { - new_size += 4000; - new_data = g_realloc (new_data, new_size); - } - } while (orig_size > 0 && result == LZO_OUTPUT_FULL); - - new_size -= out_size; - - if (result != LZO_OUTPUT_FULL) { - GST_WARNING ("lzo decompression failed"); - g_free (new_data); - - ret = FALSE; - goto out; - } - - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) { - /* header stripped encoded data */ - if (enc->comp_settings_length > 0) { - new_data = g_malloc (size + enc->comp_settings_length); - new_size = size + enc->comp_settings_length; - - memcpy (new_data, enc->comp_settings, enc->comp_settings_length); - memcpy (new_data + enc->comp_settings_length, data, size); - } - } else { - GST_ERROR ("invalid compression algorithm %d", algo); - ret = FALSE; - } - -out: - - if (!ret) { - *data_out = NULL; - *size_out = 0; - } else { - *data_out = new_data; - *size_out = new_size; - } - - return ret; -} - static gboolean gst_matroska_decode_data (GArray * encodings, guint8 ** data_out, guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free) @@ -1041,49 +861,6 @@ gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf) } } -static GstFlowReturn -gst_matroska_decode_content_encodings (GArray * encodings) -{ - gint i; - - if (encodings == NULL) - return GST_FLOW_OK; - - for (i = 0; i < encodings->len; i++) { - GstMatroskaTrackEncoding *enc = - &g_array_index (encodings, GstMatroskaTrackEncoding, i); - guint8 *data = NULL; - guint size; - - if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING) - == 0) - continue; - - /* Encryption not supported yet */ - if (enc->type != 0) - return GST_FLOW_ERROR; - - if (i + 1 >= encodings->len) - return GST_FLOW_ERROR; - - if (enc->comp_settings_length == 0) - continue; - - data = enc->comp_settings; - size = enc->comp_settings_length; - - if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo)) - return GST_FLOW_ERROR; - - g_free (enc->comp_settings); - - enc->comp_settings = data; - enc->comp_settings_length = size; - } - - return GST_FLOW_OK; -} - static GstFlowReturn gst_matroska_demux_read_track_encodings (GstMatroskaDemux * demux, GstEbmlRead * ebml, GstMatroskaTrackContext * context) diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c index 3dfb94426f..1b4f724de7 100644 --- a/gst/matroska/matroska-parse.c +++ b/gst/matroska/matroska-parse.c @@ -63,18 +63,8 @@ #include -#ifdef HAVE_ZLIB -#include -#endif - -#ifdef HAVE_BZ2 -#include -#endif - #include -#include "lzo.h" - #include "matroska-parse.h" #include "matroska-ids.h" @@ -698,176 +688,6 @@ gst_matroska_parse_read_track_encoding (GstMatroskaParse * parse, return ret; } -static gboolean -gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc, - guint8 ** data_out, guint * size_out, - GstMatroskaTrackCompressionAlgorithm algo) -{ - guint8 *new_data = NULL; - guint new_size = 0; - guint8 *data = *data_out; - guint size = *size_out; - gboolean ret = TRUE; - - if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) { -#ifdef HAVE_ZLIB - /* zlib encoded data */ - z_stream zstream; - guint orig_size; - int result; - - orig_size = size; - zstream.zalloc = (alloc_func) 0; - zstream.zfree = (free_func) 0; - zstream.opaque = (voidpf) 0; - if (inflateInit (&zstream) != Z_OK) { - GST_WARNING ("zlib initialization failed."); - ret = FALSE; - goto out; - } - zstream.next_in = (Bytef *) data; - zstream.avail_in = orig_size; - new_size = orig_size; - new_data = g_malloc (new_size); - zstream.avail_out = new_size; - zstream.next_out = (Bytef *) new_data; - - do { - result = inflate (&zstream, Z_NO_FLUSH); - if (result != Z_OK && result != Z_STREAM_END) { - GST_WARNING ("zlib decompression failed."); - g_free (new_data); - inflateEnd (&zstream); - break; - } - new_size += 4000; - new_data = g_realloc (new_data, new_size); - zstream.next_out = (Bytef *) (new_data + zstream.total_out); - zstream.avail_out += 4000; - } while (zstream.avail_in != 0 && result != Z_STREAM_END); - - if (result != Z_STREAM_END) { - ret = FALSE; - goto out; - } else { - new_size = zstream.total_out; - inflateEnd (&zstream); - } -#else - GST_WARNING ("zlib encoded tracks not supported."); - ret = FALSE; - goto out; -#endif - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) { -#ifdef HAVE_BZ2 - /* bzip2 encoded data */ - bz_stream bzstream; - guint orig_size; - int result; - - bzstream.bzalloc = NULL; - bzstream.bzfree = NULL; - bzstream.opaque = NULL; - orig_size = size; - - if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) { - GST_WARNING ("bzip2 initialization failed."); - ret = FALSE; - goto out; - } - - bzstream.next_in = (char *) data; - bzstream.avail_in = orig_size; - new_size = orig_size; - new_data = g_malloc (new_size); - bzstream.avail_out = new_size; - bzstream.next_out = (char *) new_data; - - do { - result = BZ2_bzDecompress (&bzstream); - if (result != BZ_OK && result != BZ_STREAM_END) { - GST_WARNING ("bzip2 decompression failed."); - g_free (new_data); - BZ2_bzDecompressEnd (&bzstream); - break; - } - new_size += 4000; - new_data = g_realloc (new_data, new_size); - bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32); - bzstream.avail_out += 4000; - } while (bzstream.avail_in != 0 && result != BZ_STREAM_END); - - if (result != BZ_STREAM_END) { - ret = FALSE; - goto out; - } else { - new_size = bzstream.total_out_lo32; - BZ2_bzDecompressEnd (&bzstream); - } -#else - GST_WARNING ("bzip2 encoded tracks not supported."); - ret = FALSE; - goto out; -#endif - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) { - /* lzo encoded data */ - int result; - int orig_size, out_size; - - orig_size = size; - out_size = size; - new_size = size; - new_data = g_malloc (new_size); - - do { - orig_size = size; - out_size = new_size; - - result = lzo1x_decode (new_data, &out_size, data, &orig_size); - - if (orig_size > 0) { - new_size += 4000; - new_data = g_realloc (new_data, new_size); - } - } while (orig_size > 0 && result == LZO_OUTPUT_FULL); - - new_size -= out_size; - - if (result != LZO_OUTPUT_FULL) { - GST_WARNING ("lzo decompression failed"); - g_free (new_data); - - ret = FALSE; - goto out; - } - - } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) { - /* header stripped encoded data */ - if (enc->comp_settings_length > 0) { - new_data = g_malloc (size + enc->comp_settings_length); - new_size = size + enc->comp_settings_length; - - memcpy (new_data, enc->comp_settings, enc->comp_settings_length); - memcpy (new_data + enc->comp_settings_length, data, size); - } - } else { - GST_ERROR ("invalid compression algorithm %d", algo); - ret = FALSE; - } - -out: - - if (!ret) { - *data_out = NULL; - *size_out = 0; - } else { - *data_out = new_data; - *size_out = new_size; - } - - return ret; -} - static gboolean gst_matroska_decode_data (GArray * encodings, guint8 ** data_out, guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free) @@ -930,49 +750,6 @@ gst_matroska_decode_data (GArray * encodings, guint8 ** data_out, return ret; } -static GstFlowReturn -gst_matroska_decode_content_encodings (GArray * encodings) -{ - gint i; - - if (encodings == NULL) - return GST_FLOW_OK; - - for (i = 0; i < encodings->len; i++) { - GstMatroskaTrackEncoding *enc = - &g_array_index (encodings, GstMatroskaTrackEncoding, i); - guint8 *data = NULL; - guint size; - - if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING) - == 0) - continue; - - /* Encryption not supported yet */ - if (enc->type != 0) - return GST_FLOW_ERROR; - - if (i + 1 >= encodings->len) - return GST_FLOW_ERROR; - - if (enc->comp_settings_length == 0) - continue; - - data = enc->comp_settings; - size = enc->comp_settings_length; - - if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo)) - return GST_FLOW_ERROR; - - g_free (enc->comp_settings); - - enc->comp_settings = data; - enc->comp_settings_length = size; - } - - return GST_FLOW_OK; -} - static GstFlowReturn gst_matroska_parse_read_track_encodings (GstMatroskaParse * parse, GstEbmlRead * ebml, GstMatroskaTrackContext * context) diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c index 9172c171d8..c1a2abc53f 100644 --- a/gst/matroska/matroska-read-common.c +++ b/gst/matroska/matroska-read-common.c @@ -23,8 +23,19 @@ #include "config.h" #endif +#include + +#ifdef HAVE_ZLIB +#include +#endif + +#ifdef HAVE_BZ2 +#include +#endif + +#include "lzo.h" + #include "ebml-read.h" -#include "matroska-ids.h" #include "matroska-read-common.h" GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug); @@ -38,6 +49,219 @@ GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug); GST_DEBUG_OBJECT (common, "Parsing " element " element " \ " finished with '%s'", gst_flow_get_name (ret)) +GstFlowReturn +gst_matroska_decode_content_encodings (GArray * encodings) +{ + gint i; + + if (encodings == NULL) + return GST_FLOW_OK; + + for (i = 0; i < encodings->len; i++) { + GstMatroskaTrackEncoding *enc = + &g_array_index (encodings, GstMatroskaTrackEncoding, i); + guint8 *data = NULL; + guint size; + + if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING) + == 0) + continue; + + /* Encryption not supported yet */ + if (enc->type != 0) + return GST_FLOW_ERROR; + + if (i + 1 >= encodings->len) + return GST_FLOW_ERROR; + + if (enc->comp_settings_length == 0) + continue; + + data = enc->comp_settings; + size = enc->comp_settings_length; + + if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo)) + return GST_FLOW_ERROR; + + g_free (enc->comp_settings); + + enc->comp_settings = data; + enc->comp_settings_length = size; + } + + return GST_FLOW_OK; +} + +gboolean +gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc, + guint8 ** data_out, guint * size_out, + GstMatroskaTrackCompressionAlgorithm algo) +{ + guint8 *new_data = NULL; + guint new_size = 0; + guint8 *data = *data_out; + guint size = *size_out; + gboolean ret = TRUE; + + if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) { +#ifdef HAVE_ZLIB + /* zlib encoded data */ + z_stream zstream; + guint orig_size; + int result; + + orig_size = size; + zstream.zalloc = (alloc_func) 0; + zstream.zfree = (free_func) 0; + zstream.opaque = (voidpf) 0; + if (inflateInit (&zstream) != Z_OK) { + GST_WARNING ("zlib initialization failed."); + ret = FALSE; + goto out; + } + zstream.next_in = (Bytef *) data; + zstream.avail_in = orig_size; + new_size = orig_size; + new_data = g_malloc (new_size); + zstream.avail_out = new_size; + zstream.next_out = (Bytef *) new_data; + + do { + result = inflate (&zstream, Z_NO_FLUSH); + if (result != Z_OK && result != Z_STREAM_END) { + GST_WARNING ("zlib decompression failed."); + g_free (new_data); + inflateEnd (&zstream); + break; + } + new_size += 4000; + new_data = g_realloc (new_data, new_size); + zstream.next_out = (Bytef *) (new_data + zstream.total_out); + zstream.avail_out += 4000; + } while (zstream.avail_in != 0 && result != Z_STREAM_END); + + if (result != Z_STREAM_END) { + ret = FALSE; + goto out; + } else { + new_size = zstream.total_out; + inflateEnd (&zstream); + } +#else + GST_WARNING ("zlib encoded tracks not supported."); + ret = FALSE; + goto out; +#endif + } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) { +#ifdef HAVE_BZ2 + /* bzip2 encoded data */ + bz_stream bzstream; + guint orig_size; + int result; + + bzstream.bzalloc = NULL; + bzstream.bzfree = NULL; + bzstream.opaque = NULL; + orig_size = size; + + if (BZ2_bzDecompressInit (&bzstream, 0, 0) != BZ_OK) { + GST_WARNING ("bzip2 initialization failed."); + ret = FALSE; + goto out; + } + + bzstream.next_in = (char *) data; + bzstream.avail_in = orig_size; + new_size = orig_size; + new_data = g_malloc (new_size); + bzstream.avail_out = new_size; + bzstream.next_out = (char *) new_data; + + do { + result = BZ2_bzDecompress (&bzstream); + if (result != BZ_OK && result != BZ_STREAM_END) { + GST_WARNING ("bzip2 decompression failed."); + g_free (new_data); + BZ2_bzDecompressEnd (&bzstream); + break; + } + new_size += 4000; + new_data = g_realloc (new_data, new_size); + bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32); + bzstream.avail_out += 4000; + } while (bzstream.avail_in != 0 && result != BZ_STREAM_END); + + if (result != BZ_STREAM_END) { + ret = FALSE; + goto out; + } else { + new_size = bzstream.total_out_lo32; + BZ2_bzDecompressEnd (&bzstream); + } +#else + GST_WARNING ("bzip2 encoded tracks not supported."); + ret = FALSE; + goto out; +#endif + } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) { + /* lzo encoded data */ + int result; + int orig_size, out_size; + + orig_size = size; + out_size = size; + new_size = size; + new_data = g_malloc (new_size); + + do { + orig_size = size; + out_size = new_size; + + result = lzo1x_decode (new_data, &out_size, data, &orig_size); + + if (orig_size > 0) { + new_size += 4000; + new_data = g_realloc (new_data, new_size); + } + } while (orig_size > 0 && result == LZO_OUTPUT_FULL); + + new_size -= out_size; + + if (result != LZO_OUTPUT_FULL) { + GST_WARNING ("lzo decompression failed"); + g_free (new_data); + + ret = FALSE; + goto out; + } + + } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) { + /* header stripped encoded data */ + if (enc->comp_settings_length > 0) { + new_data = g_malloc (size + enc->comp_settings_length); + new_size = size + enc->comp_settings_length; + + memcpy (new_data, enc->comp_settings, enc->comp_settings_length); + memcpy (new_data + enc->comp_settings_length, data, size); + } + } else { + GST_ERROR ("invalid compression algorithm %d", algo); + ret = FALSE; + } + +out: + + if (!ret) { + *data_out = NULL; + *size_out = 0; + } else { + *data_out = new_data; + *size_out = new_size; + } + + return ret; +} + static gint gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2) { diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h index a413f0b165..8093fcba78 100644 --- a/gst/matroska/matroska-read-common.h +++ b/gst/matroska/matroska-read-common.h @@ -25,6 +25,8 @@ #include #include +#include "matroska-ids.h" + G_BEGIN_DECLS typedef enum { @@ -60,6 +62,10 @@ typedef struct _GstMatroskaReadCommon { guint64 time_scale; } GstMatroskaReadCommon; +GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings); +gboolean gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc, + guint8 ** data_out, guint * size_out, + GstMatroskaTrackCompressionAlgorithm algo); GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common, GstEbmlRead * ebml); GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * From b316e2346cf31e6122e1244995fd0875580c7ae1 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 23 May 2011 20:46:04 +0300 Subject: [PATCH 25/28] matroska: fixed copyright headers https://bugzilla.gnome.org/show_bug.cgi?id=650877 --- gst/matroska/matroska-read-common.c | 3 +++ gst/matroska/matroska-read-common.h | 1 + 2 files changed, 4 insertions(+) diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c index c1a2abc53f..5729688570 100644 --- a/gst/matroska/matroska-read-common.c +++ b/gst/matroska/matroska-read-common.c @@ -1,4 +1,7 @@ /* GStreamer Matroska muxer/demuxer + * (c) 2003 Ronald Bultje + * (c) 2006 Tim-Philipp Müller + * (c) 2008 Sebastian Dröge * (c) 2011 Debarshi Ray * * matroska-read-common.c: shared by matroska file/stream demuxer and parser diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h index 8093fcba78..cbe7103232 100644 --- a/gst/matroska/matroska-read-common.h +++ b/gst/matroska/matroska-read-common.h @@ -1,4 +1,5 @@ /* GStreamer Matroska muxer/demuxer + * (c) 2003 Ronald Bultje * (c) 2011 Debarshi Ray * * matroska-read-common.h: shared by matroska file/stream demuxer and parser From 9c9585116cf49d2a2a1e13c12a17e2a09a729526 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sun, 4 Apr 2010 06:43:41 -0500 Subject: [PATCH 26/28] v4l2: add norm property Based on a patch by Guennadi Liakhovetski. v2: updates because I forgot to add GstTuner interface to v4l2sink v3: update to add all possible values to norm enum --- sys/v4l2/gstv4l2object.c | 108 +++++++++++++++++++++++++++++---------- sys/v4l2/gstv4l2object.h | 7 +-- sys/v4l2/gstv4l2sink.c | 14 ++++- sys/v4l2/gstv4l2tuner.c | 23 ++++++++- sys/v4l2/gstv4l2tuner.h | 5 ++ sys/v4l2/v4l2_calls.c | 3 ++ 6 files changed, 128 insertions(+), 32 deletions(-) diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index e2713fc251..29249f9b4d 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -56,7 +56,7 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); #define DEFAULT_PROP_DEVICE_NAME NULL #define DEFAULT_PROP_DEVICE_FD -1 #define DEFAULT_PROP_FLAGS 0 -#define DEFAULT_PROP_NORM NULL +#define DEFAULT_PROP_TV_NORM 0 #define DEFAULT_PROP_CHANNEL NULL #define DEFAULT_PROP_FREQUENCY 0 @@ -316,6 +316,58 @@ gst_v4l2_device_get_type (void) return v4l2_device_type; } +#define GST_TYPE_V4L2_TV_NORM (gst_v4l2_tv_norm_get_type ()) +static GType +gst_v4l2_tv_norm_get_type (void) +{ + static GType v4l2_tv_norm = 0; + + if (!v4l2_tv_norm) { + static const GEnumValue tv_norms[] = { + {0, "none", "none"}, + + {V4L2_STD_NTSC, "NTSC", "NTSC"}, + {V4L2_STD_NTSC_M, "NTSC-M", "NTSC-M"}, + {V4L2_STD_NTSC_M_JP, "NTSC-M-JP", "NTSC-M-JP"}, + {V4L2_STD_NTSC_M_KR, "NTSC-M-KR", "NTSC-M-KR"}, + {V4L2_STD_NTSC_443, "NTSC-443", "NTSC-443"}, + + {V4L2_STD_PAL, "PAL", "PAL"}, + {V4L2_STD_PAL_BG, "PAL-BG", "PAL-BG"}, + {V4L2_STD_PAL_B, "PAL-B", "PAL-B"}, + {V4L2_STD_PAL_B1, "PAL-B1", "PAL-B1"}, + {V4L2_STD_PAL_G, "PAL-G", "PAL-G"}, + {V4L2_STD_PAL_H, "PAL-H", "PAL-H"}, + {V4L2_STD_PAL_I, "PAL-I", "PAL-I"}, + {V4L2_STD_PAL_DK, "PAL-DK", "PAL-DK"}, + {V4L2_STD_PAL_D, "PAL-D", "PAL-D"}, + {V4L2_STD_PAL_D1, "PAL-D1", "PAL-D1"}, + {V4L2_STD_PAL_K, "PAL-K", "PAL-K"}, + {V4L2_STD_PAL_M, "PAL-M", "PAL-M"}, + {V4L2_STD_PAL_N, "PAL-N", "PAL-N"}, + {V4L2_STD_PAL_Nc, "PAL-Nc", "PAL-Nc"}, + {V4L2_STD_PAL_60, "PAL-60", "PAL-60"}, + + {V4L2_STD_SECAM, "SECAM", "SECAM"}, + {V4L2_STD_SECAM_B, "SECAM-B", "SECAM-B"}, + {V4L2_STD_SECAM_G, "SECAM-G", "SECAM-G"}, + {V4L2_STD_SECAM_H, "SECAM-H", "SECAM-H"}, + {V4L2_STD_SECAM_DK, "SECAM-DK", "SECAM-DK"}, + {V4L2_STD_SECAM_D, "SECAM-D", "SECAM-D"}, + {V4L2_STD_SECAM_K, "SECAM-K", "SECAM-K"}, + {V4L2_STD_SECAM_K1, "SECAM-K1", "SECAM-K1"}, + {V4L2_STD_SECAM_L, "SECAM-L", "SECAM-L"}, + {V4L2_STD_SECAM_LC, "SECAM-Lc", "SECAM-Lc"}, + + {0, NULL, NULL} + }; + + v4l2_tv_norm = g_enum_register_static ("V4L2_TV_norms", tv_norms); + } + + return v4l2_tv_norm; +} + void gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class, const char *default_device) @@ -384,6 +436,19 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class, "Hue or color balance", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + + /** + * GstV4l2Src:norm + * + * TV norm + * + * Since: 0.10.30 + */ + g_object_class_install_property (gobject_class, PROP_TV_NORM, + g_param_spec_enum ("norm", "TV norm", + "video standard", + GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } GstV4l2Object * @@ -440,9 +505,6 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object) if (v4l2object->channel) g_free (v4l2object->channel); - if (v4l2object->norm) - g_free (v4l2object->norm); - if (v4l2object->formats) { gst_v4l2_object_clear_format_list (v4l2object); } @@ -510,23 +572,10 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object, return TRUE; } break; -#if 0 - case PROP_NORM: - if (GST_V4L2_IS_OPEN (v4l2object)) { - GstTuner *tuner = GST_TUNER (v4l2object->element); - GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner, - (gchar *) g_value_get_string (value)); - - if (norm) { - /* like gst_tuner_set_norm (tuner, norm) - without g_object_notify */ - gst_v4l2_tuner_set_norm (v4l2object, norm); - } - } else { - g_free (v4l2object->norm); - v4l2object->norm = g_value_dup_string (value); - } + case PROP_TV_NORM: + v4l2object->tv_norm = g_value_get_enum (value); break; +#if 0 case PROP_CHANNEL: if (GST_V4L2_IS_OPEN (v4l2object)) { GstTuner *tuner = GST_TUNER (v4l2object->element); @@ -631,6 +680,9 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object, return TRUE; } break; + case PROP_TV_NORM: + g_value_set_enum (value, v4l2object->tv_norm); + break; default: return FALSE; break; @@ -650,16 +702,18 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object) tuner = GST_TUNER (v4l2object->element); - if (v4l2object->norm) - norm = gst_tuner_find_norm_by_name (tuner, v4l2object->norm); + if (v4l2object->tv_norm) + norm = gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm); + GST_DEBUG_OBJECT (v4l2object->element, "tv_norm=%d, norm=%p", + v4l2object->tv_norm, norm); if (norm) { gst_tuner_set_norm (tuner, norm); } else { norm = GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element))); if (norm) { - g_free (v4l2object->norm); - v4l2object->norm = g_strdup (norm->label); + v4l2object->tv_norm = + gst_v4l2_tuner_get_std_id_by_norm (v4l2object, norm); gst_tuner_norm_changed (tuner, norm); } } @@ -1887,13 +1941,15 @@ default_frame_sizes: } /* Since we can't get framerate directly, try to use the current norm */ - if (v4l2object->norm && v4l2object->norms) { + if (v4l2object->tv_norm && v4l2object->norms) { GList *norms; GstTunerNorm *norm = NULL; + GstTunerNorm *current = + gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm); for (norms = v4l2object->norms; norms != NULL; norms = norms->next) { norm = (GstTunerNorm *) norms->data; - if (!strcmp (norm->label, v4l2object->norm)) + if (!strcmp (norm->label, current->label)) break; } /* If it's possible, set framerate to that (discrete) value */ diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index a0dd41ce11..a7b590d9b9 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -108,7 +108,7 @@ struct _GstV4l2Object { GList *channels; /* properties */ - gchar *norm; + v4l2_std_id tv_norm; gchar *channel; gulong frequency; @@ -133,11 +133,12 @@ GType gst_v4l2_object_get_type (void); PROP_DEVICE, \ PROP_DEVICE_NAME, \ PROP_DEVICE_FD, \ - PROP_FLAGS, \ + PROP_FLAGS, \ PROP_BRIGHTNESS, \ PROP_CONTRAST, \ PROP_SATURATION, \ - PROP_HUE + PROP_HUE, \ + PROP_TV_NORM /* create/destroy */ GstV4l2Object * gst_v4l2_object_new (GstElement * element, diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c index fcf7e87327..8672a1dd87 100644 --- a/sys/v4l2/gstv4l2sink.c +++ b/sys/v4l2/gstv4l2sink.c @@ -55,6 +55,7 @@ #include "gstv4l2colorbalance.h" +#include "gstv4l2tuner.h" #ifdef HAVE_XVIDEO #include "gstv4l2xoverlay.h" #endif @@ -91,6 +92,7 @@ enum GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SinkClass, gst_v4l2sink); GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Sink, gst_v4l2sink); +GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Sink, gst_v4l2sink); #ifdef HAVE_XVIDEO GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Sink, gst_v4l2sink); #endif @@ -105,10 +107,12 @@ gst_v4l2sink_iface_supported (GstImplementsInterface * iface, GType iface_type) g_assert (iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_NAVIGATION || iface_type == GST_TYPE_COLOR_BALANCE || - iface_type == GST_TYPE_VIDEO_ORIENTATION); + iface_type == GST_TYPE_VIDEO_ORIENTATION || + iface_type == GST_TYPE_TUNER); #else g_assert (iface_type == GST_TYPE_COLOR_BALANCE || - iface_type == GST_TYPE_VIDEO_ORIENTATION); + iface_type == GST_TYPE_VIDEO_ORIENTATION || + iface_type == GST_TYPE_TUNER); #endif if (v4l2object->video_fd == -1) @@ -151,6 +155,11 @@ gst_v4l2sink_init_interfaces (GType type) NULL, NULL, }; + static const GInterfaceInfo v4l2_tuner_info = { + (GInterfaceInitFunc) gst_v4l2sink_tuner_interface_init, + NULL, + NULL, + }; #ifdef HAVE_XVIDEO static const GInterfaceInfo v4l2_xoverlay_info = { (GInterfaceInitFunc) gst_v4l2sink_xoverlay_interface_init, @@ -181,6 +190,7 @@ gst_v4l2sink_init_interfaces (GType type) g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info); + g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info); #ifdef HAVE_XVIDEO g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info); g_type_add_interface_static (type, diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c index c5f84426bd..a805396cac 100644 --- a/sys/v4l2/gstv4l2tuner.c +++ b/sys/v4l2/gstv4l2tuner.c @@ -237,7 +237,6 @@ gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm) GstTunerNorm * gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object) { - GList *item; v4l2_std_id norm; /* assert that we're opened and that we're using a known item */ @@ -245,6 +244,14 @@ gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object) gst_v4l2_get_norm (v4l2object, &norm); + return gst_v4l2_tuner_get_norm_by_std_id (v4l2object, norm); +} + +GstTunerNorm * +gst_v4l2_tuner_get_norm_by_std_id (GstV4l2Object * v4l2object, v4l2_std_id norm) +{ + GList *item; + for (item = v4l2object->norms; item != NULL; item = item->next) { if (norm & GST_V4L2_TUNER_NORM (item->data)->index) return (GstTunerNorm *) item->data; @@ -253,6 +260,20 @@ gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object) return NULL; } +v4l2_std_id +gst_v4l2_tuner_get_std_id_by_norm (GstV4l2Object * v4l2object, + GstTunerNorm * norm) +{ + GList *item; + + for (item = v4l2object->norms; item != NULL; item = item->next) { + if (norm == GST_TUNER_NORM (item->data)) + return GST_V4L2_TUNER_NORM (item->data)->index; + } + + return 0; +} + void gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, GstTunerChannel * channel, gulong frequency) diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h index bf9ff94da5..699ca87e10 100644 --- a/sys/v4l2/gstv4l2tuner.h +++ b/sys/v4l2/gstv4l2tuner.h @@ -94,6 +94,11 @@ void gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2o GstTunerNorm* gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object); gboolean gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm); +GstTunerNorm* gst_v4l2_tuner_get_norm_by_std_id (GstV4l2Object * v4l2object, + v4l2_std_id norm); +v4l2_std_id gst_v4l2_tuner_get_std_id_by_norm (GstV4l2Object * v4l2object, + GstTunerNorm * norm); + /* frequency */ void gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, GstTunerChannel * channel, diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index e9d306999f..3808d8e621 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -229,6 +229,9 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) standard.frameperiod.denominator, standard.frameperiod.numerator); v4l2norm->index = standard.id; + GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s", + (unsigned int) v4l2norm->index, norm->label); + v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm); } v4l2object->norms = g_list_reverse (v4l2object->norms); From f335fee99e3b6cddec30c784438ec1310c5fa171 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 24 May 2011 13:11:54 +0200 Subject: [PATCH 27/28] pcmadepay: allow variable sample rate --- gst/rtp/gstrtppcmadepay.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtp/gstrtppcmadepay.c b/gst/rtp/gstrtppcmadepay.c index 7dabc8052e..50c858a121 100644 --- a/gst/rtp/gstrtppcmadepay.c +++ b/gst/rtp/gstrtppcmadepay.c @@ -46,18 +46,18 @@ static GstStaticPadTemplate gst_rtp_pcma_depay_sink_template = GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " - "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\";" + "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMA\";" "application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", " - "clock-rate = (int) 8000") + "clock-rate = (int) [1, MAX ]") ); static GstStaticPadTemplate gst_rtp_pcma_depay_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-alaw, channels = (int) 1, rate = (int) 8000") + GST_STATIC_CAPS ("audio/x-alaw, channels = (int) 1, rate = (int) [1, MAX ]") ); static GstBuffer *gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, From 397dc60b711fcb9a818226d894938493158a463d Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 24 May 2011 13:12:19 +0200 Subject: [PATCH 28/28] pcmudepay: allow variable sample rate --- gst/rtp/gstrtppcmudepay.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gst/rtp/gstrtppcmudepay.c b/gst/rtp/gstrtppcmudepay.c index 0b7e56d673..395599b185 100644 --- a/gst/rtp/gstrtppcmudepay.c +++ b/gst/rtp/gstrtppcmudepay.c @@ -46,18 +46,19 @@ static GstStaticPadTemplate gst_rtp_pcmu_depay_sink_template = GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " - "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMU\";" + "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMU\";" "application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", " - "clock-rate = (int) 8000") + "clock-rate = (int) [1, MAX ]") ); static GstStaticPadTemplate gst_rtp_pcmu_depay_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-mulaw, channels = (int) 1, rate = (int) 8000") + GST_STATIC_CAPS ("audio/x-mulaw, " + "channels = (int) 1, rate = (int) [1, MAX ]") ); static GstBuffer *gst_rtp_pcmu_depay_process (GstBaseRTPDepayload * depayload,