From 4d55588e352fcdfc4b9c4c8e13f65fcc01d5058c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 13:19:24 +0100 Subject: [PATCH 01/24] deinterlace: Fix 'implicit conversion from enumeration type 'GstDeinterlaceFields' to different enumeration type 'GstDeinterlaceMode'' compiler warning --- gst/deinterlace/gstdeinterlace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index a79b836e00..dfb03ad1b4 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -1982,7 +1982,8 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf) self->fields = self->new_fields; if (self->new_mode != -1) self->mode = self->new_mode; - self->new_mode = self->new_fields = -1; + self->new_mode = -1; + self->new_fields = -1; self->reconfigure = FALSE; GST_OBJECT_UNLOCK (self); From dad2a52f62ba43488a42e8911ff549d4ecdb0fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 13:21:12 +0100 Subject: [PATCH 02/24] deinterlace: Fix 'variable 'oldbx' is uninitialized when used here' compiler warnings --- gst/deinterlace/tvtime/greedyh.asm | 4 ++-- gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/deinterlace/tvtime/greedyh.asm b/gst/deinterlace/tvtime/greedyh.asm index d87b9e392d..c710b4a1f2 100644 --- a/gst/deinterlace/tvtime/greedyh.asm +++ b/gst/deinterlace/tvtime/greedyh.asm @@ -43,7 +43,7 @@ FUNCT_NAME_YUY2 (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const gui gint64 MotionSense; gint64 i; glong LoopCtr; - glong oldbx; + glong oldbx = 0; gint64 QW256B; gint64 LastAvg = 0; //interp value from left qword @@ -262,7 +262,7 @@ FUNCT_NAME_UYVY (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const gui gint64 MotionSense; gint64 i; glong LoopCtr; - glong oldbx; + glong oldbx = 0; gint64 QW256B; gint64 LastAvg = 0; //interp value from left qword diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc index 9d6a490f50..275c7dd982 100644 --- a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc +++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc @@ -92,7 +92,7 @@ long Last8; int64_t Max_Vals = 0x0000000000000000ull; int64_t ShiftMask = 0xfefffefffefffeffull; - long oldbx; + long oldbx = 0; // pretend it's indented -->> __asm__ __volatile__ From 78079635a6a29812d8dfb88d30b298b64eb80d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 14:16:21 +0100 Subject: [PATCH 03/24] dvdepay: Fix 'comparison of unsigned expression >= 0 is always true' compiler warning This was an actual bug as it could've caused reading from invalid memory areas when the input is broken. --- gst/rtp/gstrtpdvdepay.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gst/rtp/gstrtpdvdepay.c b/gst/rtp/gstrtpdvdepay.c index 4098c395a7..43e6aa1745 100644 --- a/gst/rtp/gstrtpdvdepay.c +++ b/gst/rtp/gstrtpdvdepay.c @@ -336,12 +336,14 @@ gst_rtp_dv_depay_process (GstBaseRTPDepayload * base, GstBuffer * in) GST_LOG_OBJECT (dvdepay, "got block at location %d", location); } - /* get the byte offset of the dif block */ - offset = location * 80; + if (location != -1) { + /* get the byte offset of the dif block */ + offset = location * 80; - /* And copy it in, provided the location is sane. */ - if (offset >= 0 && offset <= dvdepay->frame_size - 80) - memcpy (GST_BUFFER_DATA (dvdepay->acc) + offset, payload, 80); + /* And copy it in, provided the location is sane. */ + if (offset <= dvdepay->frame_size - 80) + memcpy (GST_BUFFER_DATA (dvdepay->acc) + offset, payload, 80); + } payload += 80; payload_len -= 80; From f2e569cde89663cdf015466a848e092d3cf17149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 14:18:33 +0100 Subject: [PATCH 04/24] rtspsrc: Use correct enum for return values --- gst/rtsp/gstrtspsrc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index de142254d5..1b335b6e8d 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -3995,17 +3995,17 @@ no_protocols: ("Could not receive any UDP packets for %.4f seconds, maybe your " "firewall is blocking it. No other protocols to try.", gst_guint64_to_gdouble (src->udp_timeout / 1000000.0))); - return GST_FLOW_ERROR; + return GST_RTSP_ERROR; } open_failed: { GST_DEBUG_OBJECT (src, "open failed"); - return GST_FLOW_OK; + return GST_RTSP_OK; } play_failed: { GST_DEBUG_OBJECT (src, "play failed"); - return GST_FLOW_OK; + return GST_RTSP_OK; } } From 9d5e5ea55329748148a1cc16f08ade5376e5c02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 14:22:43 +0100 Subject: [PATCH 05/24] ximagesrc: Fix 'comparison of unsigned expression >= 0 is always true' This variable can never be below zero anyway. --- sys/ximage/gstximagesrc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index 36c0b44e78..974031295d 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -1074,8 +1074,7 @@ gst_ximage_src_get_caps (GstBaseSrc * bs) if (s->endx >= s->startx && s->endy >= s->starty) { /* this means user has put in values */ if (s->startx < xcontext->width && s->endx < xcontext->width && - s->starty < xcontext->height && s->endy < xcontext->height && - s->startx >= 0 && s->starty >= 0) { + s->starty < xcontext->height && s->endy < xcontext->height) { /* values are fine */ s->width = width = s->endx - s->startx + 1; s->height = height = s->endy - s->starty + 1; From 4101f87d1767c2f8b87d099a6212c0a0317af8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 6 Mar 2012 14:25:27 +0100 Subject: [PATCH 06/24] wavpack: Fix possible underflow of unsigned integer variable --- ext/wavpack/gstwavpackstreamreader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/wavpack/gstwavpackstreamreader.c b/ext/wavpack/gstwavpackstreamreader.c index 074a2e7d5d..da1fdc27bc 100644 --- a/ext/wavpack/gstwavpackstreamreader.c +++ b/ext/wavpack/gstwavpackstreamreader.c @@ -78,9 +78,10 @@ gst_wavpack_stream_reader_push_back_byte (void *id, int c) GST_DEBUG ("Pushing back one byte: 0x%x", c); + if (rid->position == 0) + return rid->position; + rid->position -= 1; - if (rid->position < 0) - rid->position = 0; return rid->position; } From a199ad90011d3faf853d5edf34b18aef48ea80d7 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 6 Mar 2012 15:58:20 +0100 Subject: [PATCH 07/24] speexdec: use base class tag handling helper ... so as to ensure these to be handled and sent at proper time. --- ext/speex/gstspeexdec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index e1d80b640a..5abce70b67 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -309,8 +309,9 @@ gst_speex_dec_parse_comments (GstSpeexDec * dec, GstBuffer * buf) GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list); - gst_element_found_tags_for_pad (GST_ELEMENT (dec), - GST_AUDIO_DECODER_SRC_PAD (dec), list); + gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dec), list, + GST_TAG_MERGE_REPLACE); + gst_tag_list_free (list); g_free (encoder); g_free (ver); From b13f63c2240476cef93fed6540fc4ae47c79adcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 9 Mar 2012 15:25:02 +0000 Subject: [PATCH 08/24] configure: fix autogen.sh warnings configure.ac:410: warning: AC_LANG_CONFTEST: no AC_LANG_SOURCE call detected in body --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 77a8bc4b57..c1c370ee1d 100644 --- a/configure.ac +++ b/configure.ac @@ -416,18 +416,18 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [ LDFLAGS="$LDFLAGS $DIRECTSOUND_LDFLAGS" LIBS="$LIBS -ldsound -ldxerr9 -luser32" AC_MSG_CHECKING(for DirectSound LDFLAGS) - AC_LINK_IFELSE([ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include - +]], [[ int main () { DXGetErrorString9 (0); DirectSoundCreate(NULL, NULL, NULL); return 0; -} +}]]) ], [HAVE_DIRECTSOUND="yes"], [HAVE_DIRECTSOUND="no"]) From e23264d57045ddbc90862391fc91e37bf15d9684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 9 Mar 2012 15:53:32 +0000 Subject: [PATCH 09/24] configure: fix use of AC_LANG_PROGRAM No need to include the int main () { } bits, the body is enough. --- configure.ac | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index c1c370ee1d..50b7794419 100644 --- a/configure.ac +++ b/configure.ac @@ -421,13 +421,9 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [ #include #include ]], [[ -int main () -{ DXGetErrorString9 (0); DirectSoundCreate(NULL, NULL, NULL); - - return 0; -}]]) +]]) ], [HAVE_DIRECTSOUND="yes"], [HAVE_DIRECTSOUND="no"]) From 3f4e4edaa2da3a5e5f7f8503181dbb85cc7fc095 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Mon, 12 Mar 2012 08:48:32 +0100 Subject: [PATCH 10/24] gst: Fix some query leaks --- gst/flv/gstflvmux.c | 7 +++---- gst/isomp4/gstqtmux.c | 1 + gst/matroska/matroska-mux.c | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index f2b9688cd2..c347ff05f1 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -140,10 +140,8 @@ gst_flv_mux_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - gst_element_class_add_static_pad_template (element_class, - &videosink_templ); - gst_element_class_add_static_pad_template (element_class, - &audiosink_templ); + gst_element_class_add_static_pad_template (element_class, &videosink_templ); + gst_element_class_add_static_pad_template (element_class, &audiosink_templ); gst_element_class_add_static_pad_template (element_class, &src_templ); gst_element_class_set_details_simple (element_class, "FLV muxer", "Codec/Muxer", @@ -1127,6 +1125,7 @@ gst_flv_mux_write_header (GstFlvMux * mux) /* FIXME 0.11: change to query not handled => seeking not supported */ GST_WARNING_OBJECT (mux, "downstream did not handle seeking query"); } + gst_query_unref (query); } header = gst_flv_mux_create_header (mux); diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 80fa5afbe4..ad2baf0e44 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -1635,6 +1635,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux) /* FIXME 0.11: change to query not handled => seeking not supported */ GST_WARNING_OBJECT (qtmux, "downstream did not handle seeking query"); } + gst_query_unref (query); } /* let downstream know we think in BYTES and expect to do seeking later on */ diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index fb86ef4983..168b2a9abe 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2376,6 +2376,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux) /* FIXME 0.11: change to query not handled => seeking not supported */ GST_WARNING_OBJECT (mux, "downstream did not handle seeking query"); } + gst_query_unref (query); } if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) { From 15d1d4066294749a2adcdd2671ec33ea589ce61c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Mar 2012 14:48:47 +0100 Subject: [PATCH 11/24] smpte: fix stride handling --- gst/smpte/gstsmpte.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/gst/smpte/gstsmpte.c b/gst/smpte/gstsmpte.c index 0579844405..0ce73b5cc4 100644 --- a/gst/smpte/gstsmpte.c +++ b/gst/smpte/gstsmpte.c @@ -408,8 +408,7 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, gint i, j; gint min, max; guint8 *in1u, *in1v, *in2u, *in2v, *outu, *outv; - gint lumsize = width * height; - gint chromsize = lumsize >> 2; + gint uoffset, voffset, ystr, ustr, vstr; if (border == 0) border++; @@ -417,12 +416,19 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, min = pos - border; max = pos; - in1u = in1 + lumsize; - in1v = in1u + chromsize; - in2u = in2 + lumsize; - in2v = in2u + chromsize; - outu = out + lumsize; - outv = outu + chromsize; + uoffset = I420_U_OFFSET (width, height); + voffset = I420_V_OFFSET (width, height); + + ystr = I420_Y_ROWSTRIDE (width); + ustr = I420_U_ROWSTRIDE (width); + vstr = I420_V_ROWSTRIDE (width); + + in1u = in1 + uoffset; + in1v = in1 + voffset; + in2u = in2 + uoffset; + in2v = in2 + voffset; + outu = out + uoffset; + outv = out + voffset; maskp = mask->data; @@ -431,12 +437,25 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, value = *maskp++; value = ((CLAMP (value, min, max) - min) << 8) / border; - *out++ = ((*in1++ * value) + (*in2++ * (256 - value))) >> 8; + out[j] = ((in1[j] * value) + (in2[j] * (256 - value))) >> 8; if (!(i & 1) && !(j & 1)) { - *outu++ = ((*in1u++ * value) + (*in2u++ * (256 - value))) >> 8; - *outv++ = ((*in1v++ * value) + (*in2v++ * (256 - value))) >> 8; + outu[j / 2] = + ((in1u[j / 2] * value) + (in2u[j / 2] * (256 - value))) >> 8; + outv[j / 2] = + ((in1v[j / 2] * value) + (in2v[j / 2] * (256 - value))) >> 8; } } + out += ystr; + in1 += ystr; + in2 += ystr; + if (!(i & 1)) { + outu += ustr; + in1u += ustr; + in2u += ustr; + outv += vstr; + in1v += vstr; + in2v += vstr; + } } } From b4756db358e4e359be2e233e41998520117e11cd Mon Sep 17 00:00:00 2001 From: Marc Leeman Date: Thu, 8 Mar 2012 17:07:51 +0100 Subject: [PATCH 12/24] gstrtspsrc: disable RTSP keep-alive on request --- gst/rtsp/gstrtspsrc.c | 33 +++++++++++++++++++++++++++++++++ gst/rtsp/gstrtspsrc.h | 1 + 2 files changed, 34 insertions(+) diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 1b335b6e8d..d344adf997 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -178,6 +178,7 @@ gst_rtsp_src_buffer_mode_get_type (void) #define DEFAULT_CONNECTION_SPEED 0 #define DEFAULT_NAT_METHOD GST_RTSP_NAT_DUMMY #define DEFAULT_DO_RTCP TRUE +#define DEFAULT_DO_RTSP_KEEP_ALIVE TRUE #define DEFAULT_PROXY NULL #define DEFAULT_RTP_BLOCKSIZE 0 #define DEFAULT_USER_ID NULL @@ -199,6 +200,7 @@ enum PROP_CONNECTION_SPEED, PROP_NAT_METHOD, PROP_DO_RTCP, + PROP_DO_RTSP_KEEP_ALIVE, PROP_PROXY, PROP_RTP_BLOCKSIZE, PROP_USER_ID, @@ -408,6 +410,20 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) "Send RTCP packets, disable for old incompatible server.", DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPSrc::do-rtsp-keep-alive + * + * Enable RTSP keep laive support. Some old server don't like RTSP + * keep alive and then this property needs to be set to FALSE. + * + * Since: 0.10.32 + */ + g_object_class_install_property (gobject_class, PROP_DO_RTSP_KEEP_ALIVE, + g_param_spec_boolean ("do-rtsp-keep-alive", "Do RTSP Keep Alive", + "Send RTSP keep alive packets, disable for old incompatible server.", + DEFAULT_DO_RTSP_KEEP_ALIVE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstRTSPSrc::proxy * @@ -526,6 +542,7 @@ gst_rtspsrc_init (GstRTSPSrc * src, GstRTSPSrcClass * g_class) src->connection_speed = DEFAULT_CONNECTION_SPEED; src->nat_method = DEFAULT_NAT_METHOD; src->do_rtcp = DEFAULT_DO_RTCP; + src->do_rtsp_keep_alive = DEFAULT_DO_RTSP_KEEP_ALIVE; gst_rtspsrc_set_proxy (src, DEFAULT_PROXY); src->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE; src->user_id = g_strdup (DEFAULT_USER_ID); @@ -692,6 +709,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value, case PROP_DO_RTCP: rtspsrc->do_rtcp = g_value_get_boolean (value); break; + case PROP_DO_RTSP_KEEP_ALIVE: + rtspsrc->do_rtsp_keep_alive = g_value_get_boolean (value); + break; case PROP_PROXY: gst_rtspsrc_set_proxy (rtspsrc, g_value_get_string (value)); break; @@ -782,6 +802,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DO_RTCP: g_value_set_boolean (value, rtspsrc->do_rtcp); break; + case PROP_DO_RTSP_KEEP_ALIVE: + g_value_set_boolean (value, rtspsrc->do_rtsp_keep_alive); + break; case PROP_PROXY: { gchar *str; @@ -3485,6 +3508,12 @@ gst_rtspsrc_send_keep_alive (GstRTSPSrc * src) GstRTSPMethod method; gchar *control; + if (src->do_rtsp_keep_alive == FALSE) { + GST_DEBUG_OBJECT (src, "do-rtsp-keep-alive is FALSE, not sending."); + gst_rtsp_connection_reset_timeout (src->conninfo.connection); + return GST_RTSP_OK; + } + GST_DEBUG_OBJECT (src, "creating server keep-alive"); /* find a method to use for keep-alive */ @@ -3836,7 +3865,11 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src) goto connect_error; continue; + case GST_RTSP_ENET: + GST_DEBUG_OBJECT (src, "An ethernet problem occured."); default: + GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), + ("Unhandled return value %d.", res)); goto receive_error; } diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index cf8f81c445..40857120e0 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -204,6 +204,7 @@ struct _GstRTSPSrc { guint connection_speed; GstRTSPNatMethod nat_method; gboolean do_rtcp; + gboolean do_rtsp_keep_alive; gchar *proxy_host; guint proxy_port; gchar *proxy_user; From 38372eb199fc38ce64d755ee4a0caeeb1c31446c Mon Sep 17 00:00:00 2001 From: Andrej Gelenberg Date: Wed, 7 Mar 2012 13:39:50 +0100 Subject: [PATCH 13/24] pngdec: add support for video/x-raw-gray formats pngdec can now decode gray 8- and 16-bit images without alpha channel direct to video/x-raw-gray format. 16-bit gray images have big-endian format, because it's native PNG endianness. Gray images with alpha channel still converted to RGBA. Signed-off-by: Andrej Gelenberg --- ext/libpng/gstpngdec.c | 59 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/ext/libpng/gstpngdec.c b/ext/libpng/gstpngdec.c index 4a2b5479f7..e10bdb7371 100644 --- a/ext/libpng/gstpngdec.c +++ b/ext/libpng/gstpngdec.c @@ -87,7 +87,8 @@ static GstStaticPadTemplate gst_pngdec_src_pad_template = GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";" - GST_VIDEO_CAPS_ARGB_64) + GST_VIDEO_CAPS_ARGB_64 ";" + GST_VIDEO_CAPS_GRAY8 ";" GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN")) ); static GstStaticPadTemplate gst_pngdec_sink_pad_template = @@ -371,15 +372,15 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) /* Get bits per channel */ bpc = png_get_bit_depth (pngdec->png, pngdec->info); - if (bpc > 8) { - /* Add alpha channel if 16-bit depth */ - png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); - png_set_swap (pngdec->png); - } /* Get Color type */ color_type = png_get_color_type (pngdec->png, pngdec->info); + /* Add alpha channel if 16-bit depth, but not for GRAY images */ + if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) { + png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); + png_set_swap (pngdec->png); + } #if 0 /* We used to have this HACK to reverse the outgoing bytes, but the problem * that originally required the hack seems to have been in ffmpegcolorspace's @@ -389,11 +390,16 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) png_set_bgr (pngdec->png); #endif - /* Gray scale converted to RGB and upscaled to 8 bits */ + /* Gray scale with alpha channel converted to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + GST_LOG_OBJECT (pngdec, + "converting grayscale png with alpha channel to RGB"); + png_set_gray_to_rgb (pngdec->png); + } + + /* Gray scale converted to upscaled to 8 bits */ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY)) { - GST_LOG_OBJECT (pngdec, "converting grayscale png to RGB"); - png_set_gray_to_rgb (pngdec->png); if (bpc < 8) { /* Convert to 8 bits */ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); #if PNG_LIBPNG_VER < 10400 @@ -430,9 +436,15 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) pngdec->bpp = 3 * bpc; break; case PNG_COLOR_TYPE_RGB_ALPHA: - GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 bits"); + GST_LOG_OBJECT (pngdec, + "we have an alpha channel, depth is 32 or 64 bits"); pngdec->bpp = 4 * bpc; break; + case PNG_COLOR_TYPE_GRAY: + GST_LOG_OBJECT (pngdec, + "We have an gray image, depth is 8 or 16 (be) bits"); + pngdec->bpp = bpc; + break; default: GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), ("pngdec does not support this color type")); @@ -440,11 +452,28 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) goto beach; } - caps = gst_caps_new_simple ("video/x-raw-rgb", - "width", G_TYPE_INT, pngdec->width, - "height", G_TYPE_INT, pngdec->height, - "bpp", G_TYPE_INT, pngdec->bpp, - "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); + if (pngdec->color_type == PNG_COLOR_TYPE_GRAY) { + if (pngdec->bpp < 16) { + caps = gst_caps_new_simple ("video/x-raw-gray", + "width", G_TYPE_INT, pngdec->width, + "height", G_TYPE_INT, pngdec->height, + "bpp", G_TYPE_INT, pngdec->bpp, + "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); + } else { + caps = gst_caps_new_simple ("video/x-raw-gray", + "width", G_TYPE_INT, pngdec->width, + "height", G_TYPE_INT, pngdec->height, + "bpp", G_TYPE_INT, pngdec->bpp, + "endianness", G_TYPE_INT, G_BIG_ENDIAN, + "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); + } + } else { + caps = gst_caps_new_simple ("video/x-raw-rgb", + "width", G_TYPE_INT, pngdec->width, + "height", G_TYPE_INT, pngdec->height, + "bpp", G_TYPE_INT, pngdec->bpp, + "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); + } templ = gst_static_pad_template_get (&gst_pngdec_src_pad_template); From ee1be9236f9874ddb54345888be791ccee0f8a3a Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Sat, 10 Mar 2012 13:44:08 +0000 Subject: [PATCH 14/24] matroskademux: only unlock pad when it was locked This fixes the mutex being unlocked too much and ending up allowing other threads when they should not. https://bugzilla.gnome.org/show_bug.cgi?id=671776 --- gst/matroska/matroska-demux.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 6e49baa429..ab75060731 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -1910,6 +1910,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GstMatroskaTrackContext *track = NULL; GstSegment seeksegment = { 0, }; gboolean update = TRUE; + gboolean pad_locked = FALSE; if (pad) track = gst_pad_get_element_private (pad); @@ -2011,6 +2012,7 @@ next: * forever. */ GST_DEBUG_OBJECT (demux, "Waiting for streaming to stop"); GST_PAD_STREAM_LOCK (demux->common.sinkpad); + pad_locked = TRUE; /* pull mode without index can do some scanning */ if (!demux->streaming && !entry) { @@ -2093,13 +2095,17 @@ exit: (GstTaskFunction) gst_matroska_demux_loop, demux->common.sinkpad); /* streaming can continue now */ - GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + if (pad_locked) { + GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + } return TRUE; seek_error: { - GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + if (pad_locked) { + GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + } GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Got a seek error")); return FALSE; } From 265a5bfa9bd356047df8db3c3f639f19255cc9d7 Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Mon, 12 Mar 2012 15:27:27 +0100 Subject: [PATCH 15/24] flacenc: generate seektables every 10 sec by default Since this is what the command line tool does as well, it seems like a better default. --- ext/flac/gstflacenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index c2eb333cb2..b4de217468 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -225,7 +225,7 @@ static const GstFlacEncParams flacenc_params[] = { #define DEFAULT_QUALITY 5 #define DEFAULT_PADDING 0 -#define DEFAULT_SEEKPOINTS 0 +#define DEFAULT_SEEKPOINTS -10 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ()) static GType From 9fb67668705ebc21827b0eb1f724d69d4ef66322 Mon Sep 17 00:00:00 2001 From: Andrej Gelenberg Date: Tue, 13 Mar 2012 23:08:38 +0100 Subject: [PATCH 16/24] pngenc: add support for 8- and 16-bit gray images Add support for direct encoding of 8- and 16-bit big endian gray images. https://bugzilla.gnome.org/show_bug.cgi?id=672025 --- ext/libpng/gstpngenc.c | 14 ++++++++++++-- ext/libpng/gstpngenc.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ext/libpng/gstpngenc.c b/ext/libpng/gstpngenc.c index 30986cdbb7..b30d04f649 100644 --- a/ext/libpng/gstpngenc.c +++ b/ext/libpng/gstpngenc.c @@ -66,7 +66,7 @@ static GstStaticPadTemplate pngenc_sink_template = GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";" - GST_VIDEO_CAPS_GRAY8) + GST_VIDEO_CAPS_GRAY8 ";" GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN")) ); /* static GstElementClass *parent_class = NULL; */ @@ -167,6 +167,7 @@ gst_pngenc_setcaps (GstPad * pad, GstCaps * caps) pngenc->png_color_type = PNG_COLOR_TYPE_RGB; break; case GST_VIDEO_FORMAT_GRAY8: + case GST_VIDEO_FORMAT_GRAY16_BE: pngenc->png_color_type = PNG_COLOR_TYPE_GRAY; break; default: @@ -174,6 +175,15 @@ gst_pngenc_setcaps (GstPad * pad, GstCaps * caps) goto done; } + switch (format) { + case GST_VIDEO_FORMAT_GRAY16_BE: + pngenc->depth = 16; + break; + default: /* GST_VIDEO_FORMAT_RGB and GST_VIDEO_FORMAT_GRAY8 */ + pngenc->depth = 8; + break; + } + if (G_UNLIKELY (pngenc->width < 16 || pngenc->width > 1000000 || pngenc->height < 16 || pngenc->height > 1000000)) { ret = FALSE; @@ -321,7 +331,7 @@ gst_pngenc_chain (GstPad * pad, GstBuffer * buf) pngenc->png_info_ptr, pngenc->width, pngenc->height, - 8, + pngenc->depth, pngenc->png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); diff --git a/ext/libpng/gstpngenc.h b/ext/libpng/gstpngenc.h index 792a7c90b6..1c521cac09 100644 --- a/ext/libpng/gstpngenc.h +++ b/ext/libpng/gstpngenc.h @@ -50,6 +50,7 @@ struct _GstPngEnc png_infop png_info_ptr; gint png_color_type; + gint depth; gint width; gint height; gint stride; From 053f33adc8bd1325c01ef373469dc116ec624346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 14 Jul 2011 16:23:49 -0400 Subject: [PATCH 17/24] rtph264depay: Make output in AVC stream format work even without complete sprop-parameter-set This allows outputting streams in AVC format even if the SPS/PPS are sent inside the RTP stream. https://bugzilla.gnome.org/show_bug.cgi?id=654850 --- gst/rtp/gstrtph264depay.c | 393 +++++++++++++++++++++++++++++--------- gst/rtp/gstrtph264depay.h | 5 + 2 files changed, 303 insertions(+), 95 deletions(-) diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c index 295ea31bd7..1a92dd205d 100644 --- a/gst/rtp/gstrtph264depay.c +++ b/gst/rtp/gstrtph264depay.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "gstrtph264depay.h" @@ -160,6 +161,10 @@ gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay, rtph264depay->picture_adapter = gst_adapter_new (); rtph264depay->byte_stream = DEFAULT_BYTE_STREAM; rtph264depay->merge = DEFAULT_ACCESS_UNIT; + rtph264depay->sps = g_ptr_array_new_with_free_func ( + (GDestroyNotify) gst_buffer_unref); + rtph264depay->pps = g_ptr_array_new_with_free_func ( + (GDestroyNotify) gst_buffer_unref); } static void @@ -172,6 +177,9 @@ gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay) rtph264depay->last_keyframe = FALSE; rtph264depay->last_ts = 0; rtph264depay->current_fu_type = 0; + rtph264depay->new_codec_data = FALSE; + g_ptr_array_set_size (rtph264depay->sps, 0); + g_ptr_array_set_size (rtph264depay->pps, 0); } static void @@ -187,6 +195,9 @@ gst_rtp_h264_depay_finalize (GObject * object) g_object_unref (rtph264depay->adapter); g_object_unref (rtph264depay->picture_adapter); + g_ptr_array_free (rtph264depay->sps, TRUE); + g_ptr_array_free (rtph264depay->pps, TRUE); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -291,17 +302,261 @@ gst_rtp_h264_depay_negotiate (GstRtpH264Depay * rtph264depay) } } +/* Stolen from bad/gst/mpegtsdemux/payloader_parsers.c */ +/* variable length Exp-Golomb parsing according to H.264 spec 9.1*/ +static gboolean +read_golomb (GstBitReader * br, guint32 * value) +{ + guint8 b, leading_zeros = -1; + *value = 1; + + for (b = 0; !b; leading_zeros++) { + if (!gst_bit_reader_get_bits_uint8 (br, &b, 1)) + return FALSE; + *value *= 2; + } + + *value = (*value >> 1) - 1; + if (leading_zeros > 0) { + guint32 tmp = 0; + if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros)) + return FALSE; + *value += tmp; + } + + return TRUE; +} + +static gboolean +parse_sps (GstBuffer * nal, guint32 * sps_id) +{ + GstBitReader br = GST_BIT_READER_INIT (GST_BUFFER_DATA (nal) + 4, + GST_BUFFER_SIZE (nal) - 4); + + if (GST_BUFFER_SIZE (nal) < 5) + return FALSE; + + if (!read_golomb (&br, sps_id)) + return FALSE; + + return TRUE; +} + +static gboolean +parse_pps (GstBuffer * nal, guint32 * sps_id, guint32 * pps_id) +{ + GstBitReader br = GST_BIT_READER_INIT (GST_BUFFER_DATA (nal) + 1, + GST_BUFFER_SIZE (nal) - 1); + + if (GST_BUFFER_SIZE (nal) < 2) + return FALSE; + + if (!read_golomb (&br, pps_id)) + return FALSE; + if (!read_golomb (&br, sps_id)) + return FALSE; + + return TRUE; +} + +static gboolean +gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay) +{ + gboolean res; + GstCaps *srccaps; + guchar level = 0; + guchar profile_compat = G_MAXUINT8; + + if (!rtph264depay->byte_stream && + (!rtph264depay->new_codec_data || + rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0)) + return TRUE; + + srccaps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, + rtph264depay->byte_stream ? "byte-stream" : "avc", + "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL); + + if (!rtph264depay->byte_stream) { + GstBuffer *codec_data; + guchar *data; + guint len; + guint i; + + /* start with 7 bytes header */ + len = 7; + /* count sps & pps */ + for (i = 0; i < rtph264depay->sps->len; i++) + len += 2 + GST_BUFFER_SIZE (g_ptr_array_index (rtph264depay->sps, i)); + for (i = 0; i < rtph264depay->pps->len; i++) + len += 2 + GST_BUFFER_SIZE (g_ptr_array_index (rtph264depay->pps, i)); + + codec_data = gst_buffer_new_and_alloc (len); + g_debug ("alloc_len: %u", len); + data = GST_BUFFER_DATA (codec_data); + + /* 8 bits version == 1 */ + *data++ = 1; + + /* According to: ISO/IEC 14496-15:2004(E) section 5.2.4.1 + * The level is the max level of all SPSes + * A profile compat bit can only be set if all SPSes include that bit + */ + for (i = 0; i < rtph264depay->sps->len; i++) { + guchar *nal = GST_BUFFER_DATA (g_ptr_array_index (rtph264depay->sps, i)); + + profile_compat &= nal[2]; + level = MAX (level, nal[3]); + } + + /* Assume all SPSes use the same profile, so extract from the first SPS */ + *data++ = GST_BUFFER_DATA (g_ptr_array_index (rtph264depay->sps, 0))[1]; + *data++ = profile_compat; + *data++ = level; + + /* 6 bits reserved | 2 bits lengthSizeMinusOn */ + *data++ = 0xff; + /* 3 bits reserved | 5 bits numOfSequenceParameterSets */ + *data++ = 0xe0 | (rtph264depay->sps->len & 0x1f); + + /* copy all SPS */ + for (i = 0; i < rtph264depay->sps->len; i++) { + GstBuffer *sps = g_ptr_array_index (rtph264depay->sps, i); + + GST_DEBUG_OBJECT (rtph264depay, "copy SPS %d of length %d", i, + GST_BUFFER_SIZE (sps)); + GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (sps)); + data += 2; + memcpy (data, GST_BUFFER_DATA (sps), GST_BUFFER_SIZE (sps)); + data += GST_BUFFER_SIZE (sps); + } + + /* 8 bits numOfPictureParameterSets */ + *data++ = rtph264depay->pps->len; + /* copy all PPS */ + for (i = 0; i < rtph264depay->pps->len; i++) { + GstBuffer *pps = g_ptr_array_index (rtph264depay->pps, i); + + GST_DEBUG_OBJECT (rtph264depay, "copy PPS %d of length %d", i, + GST_BUFFER_SIZE (pps)); + GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (pps)); + data += 2; + memcpy (data, GST_BUFFER_DATA (pps), GST_BUFFER_SIZE (pps)); + data += GST_BUFFER_SIZE (pps); + } + + GST_BUFFER_SIZE (codec_data) = data - GST_BUFFER_DATA (codec_data); + + gst_caps_set_simple (srccaps, + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + } + + res = gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (rtph264depay), + srccaps); + gst_caps_unref (srccaps); + + if (res) + rtph264depay->new_codec_data = FALSE; + + return res; +} + +static gboolean +gst_rtp_h264_add_sps_pps (GstRtpH264Depay * rtph264depay, GstBuffer * nal) +{ + guchar type = GST_BUFFER_DATA (nal)[0] & 0x1f; + guint i; + + if (type == 7) { + guint32 sps_id; + + if (!parse_sps (nal, &sps_id)) { + GST_WARNING_OBJECT (rtph264depay, "Invalid SPS," + " can't parse seq_parameter_set_id"); + goto drop; + } + + for (i = 0; i < rtph264depay->sps->len; i++) { + GstBuffer *sps = g_ptr_array_index (rtph264depay->sps, i); + guint32 tmp_sps_id; + + parse_sps (sps, &tmp_sps_id); + if (sps_id == tmp_sps_id) { + if (GST_BUFFER_SIZE (nal) == GST_BUFFER_SIZE (sps) && + memcmp (GST_BUFFER_DATA (nal), GST_BUFFER_DATA (sps), + GST_BUFFER_SIZE (sps)) == 0) { + GST_LOG_OBJECT (rtph264depay, "Unchanged SPS %u, not updating", + sps_id); + goto drop; + } else { + g_ptr_array_remove_index_fast (rtph264depay->sps, i); + g_ptr_array_add (rtph264depay->sps, nal); + GST_LOG_OBJECT (rtph264depay, "Modified SPS %u, replacing", sps_id); + goto done; + } + } + } + GST_LOG_OBJECT (rtph264depay, "Adding new SPS %u", sps_id); + g_ptr_array_add (rtph264depay->sps, nal); + } else if (type == 8) { + guint32 sps_id; + guint32 pps_id; + + if (!parse_pps (nal, &sps_id, &pps_id)) { + GST_WARNING_OBJECT (rtph264depay, "Invalid PPS," + " can't parse seq_parameter_set_id or pic_parameter_set_id"); + goto drop; + } + + for (i = 0; i < rtph264depay->pps->len; i++) { + GstBuffer *pps = g_ptr_array_index (rtph264depay->pps, i); + guint32 tmp_sps_id; + guint32 tmp_pps_id; + + parse_pps (pps, &tmp_sps_id, &tmp_pps_id); + if (sps_id == tmp_sps_id && pps_id == tmp_pps_id) { + if (GST_BUFFER_SIZE (nal) == GST_BUFFER_SIZE (pps) && + memcmp (GST_BUFFER_DATA (nal), GST_BUFFER_DATA (pps), + GST_BUFFER_SIZE (pps)) == 0) { + GST_LOG_OBJECT (rtph264depay, "Unchanged PPS %u:%u, not updating", + sps_id, pps_id); + goto drop; + } else { + g_ptr_array_remove_index_fast (rtph264depay->pps, i); + g_ptr_array_add (rtph264depay->pps, nal); + GST_LOG_OBJECT (rtph264depay, "Modified PPS %u:%u, replacing", + sps_id, pps_id); + goto done; + } + } + } + GST_LOG_OBJECT (rtph264depay, "Adding new PPS %u:%i", sps_id, pps_id); + g_ptr_array_add (rtph264depay->pps, nal); + } else { + goto drop; + } + +done: + rtph264depay->new_codec_data = TRUE; + + return TRUE; + +drop: + gst_buffer_unref (nal); + + return FALSE; +} + static gboolean gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) { - GstCaps *srccaps; gint clock_rate; GstStructure *structure = gst_caps_get_structure (caps, 0); GstRtpH264Depay *rtph264depay; - const gchar *ps, *profile; + const gchar *ps; GstBuffer *codec_data; guint8 *b64; - gboolean res; rtph264depay = GST_RTP_H264_DEPAY (depayload); @@ -309,12 +564,8 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) clock_rate = 90000; depayload->clock_rate = clock_rate; - srccaps = gst_caps_new_simple ("video/x-h264", NULL); - /* Base64 encoded, comma separated config NALs */ ps = gst_structure_get_string (structure, "sprop-parameter-sets"); - /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */ - profile = gst_structure_get_string (structure, "profile-level-id"); /* negotiate with downstream w.r.t. output format and alignment */ gst_rtp_h264_depay_negotiate (rtph264depay); @@ -364,123 +615,51 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) rtph264depay->codec_data = codec_data; } else if (!rtph264depay->byte_stream) { gchar **params; - guint8 **sps, **pps; - guint len, num_sps, num_pps; gint i; - guint8 *data; if (ps == NULL) goto incomplete_caps; params = g_strsplit (ps, ",", 0); - len = g_strv_length (params); - GST_DEBUG_OBJECT (depayload, "we have %d params", len); - - sps = g_new0 (guint8 *, len + 1); - pps = g_new0 (guint8 *, len + 1); - num_sps = num_pps = 0; + GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params)); /* start with 7 bytes header */ - len = 7; for (i = 0; params[i]; i++) { + GstBuffer *nal; gsize nal_len; - guint8 *nalp; guint save = 0; gint state = 0; nal_len = strlen (params[i]); - nalp = g_malloc (nal_len + 2); + nal = gst_buffer_new_and_alloc (nal_len); nal_len = - g_base64_decode_step (params[i], nal_len, nalp + 2, &state, &save); - nalp[0] = (nal_len >> 8) & 0xff; - nalp[1] = nal_len & 0xff; - len += nal_len + 2; + g_base64_decode_step (params[i], nal_len, GST_BUFFER_DATA (nal), + &state, &save); - /* copy to the right list */ - if ((nalp[2] & 0x1f) == 7) { - GST_DEBUG_OBJECT (depayload, "adding param %d as SPS %d", i, num_sps); - sps[num_sps++] = nalp; - } else { - GST_DEBUG_OBJECT (depayload, "adding param %d as PPS %d", i, num_pps); - pps[num_pps++] = nalp; - } + GST_BUFFER_SIZE (nal) = nal_len; + + GST_DEBUG_OBJECT (depayload, "adding param %d as %s", i, + ((GST_BUFFER_DATA (nal)[0] & 0x1f) == 7) ? "SPS" : "PPS"); + + gst_rtp_h264_add_sps_pps (rtph264depay, nal); } g_strfreev (params); - if (num_sps == 0 || (GST_READ_UINT16_BE (sps[0]) < 3) || num_pps == 0) { - g_strfreev ((gchar **) pps); - g_strfreev ((gchar **) sps); + if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0) goto incomplete_caps; - } - codec_data = gst_buffer_new_and_alloc (len); - data = GST_BUFFER_DATA (codec_data); - - /* 8 bits version == 1 */ - *data++ = 1; - if (profile) { - guint32 profile_id; - - /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */ - sscanf (profile, "%6x", &profile_id); - *data++ = (profile_id >> 16) & 0xff; - *data++ = (profile_id >> 8) & 0xff; - *data++ = profile_id & 0xff; - } else { - /* extract from SPS */ - *data++ = sps[0][3]; - *data++ = sps[0][4]; - *data++ = sps[0][5]; - } - /* 6 bits reserved | 2 bits lengthSizeMinusOn */ - *data++ = 0xff; - /* 3 bits reserved | 5 bits numOfSequenceParameterSets */ - *data++ = 0xe0 | (num_sps & 0x1f); - - /* copy all SPS */ - for (i = 0; sps[i]; i++) { - len = ((sps[i][0] << 8) | sps[i][1]) + 2; - GST_DEBUG_OBJECT (depayload, "copy SPS %d of length %d", i, len); - memcpy (data, sps[i], len); - g_free (sps[i]); - data += len; - } - g_free (sps); - /* 8 bits numOfPictureParameterSets */ - *data++ = num_pps; - /* copy all PPS */ - for (i = 0; pps[i]; i++) { - len = ((pps[i][0] << 8) | pps[i][1]) + 2; - GST_DEBUG_OBJECT (depayload, "copy PPS %d of length %d", i, len); - memcpy (data, pps[i], len); - g_free (pps[i]); - data += len; - } - g_free (pps); - GST_BUFFER_SIZE (codec_data) = data - GST_BUFFER_DATA (codec_data); - - gst_caps_set_simple (srccaps, - "codec_data", GST_TYPE_BUFFER, codec_data, NULL); - gst_buffer_unref (codec_data); } - gst_caps_set_simple (srccaps, "stream-format", G_TYPE_STRING, - rtph264depay->byte_stream ? "byte-stream" : "avc", - "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL); - - res = gst_pad_set_caps (depayload->srcpad, srccaps); - gst_caps_unref (srccaps); - - return res; + return gst_rtp_h264_set_src_caps (rtph264depay); /* ERRORS */ incomplete_caps: { - GST_DEBUG_OBJECT (depayload, "we have incomplete caps"); - gst_caps_unref (srccaps); - return FALSE; + GST_DEBUG_OBJECT (depayload, "we have incomplete caps," + " doing setcaps later"); + return TRUE; } } @@ -535,6 +714,30 @@ gst_rtp_h264_depay_handle_nal (GstRtpH264Depay * rtph264depay, GstBuffer * nal, out_keyframe = keyframe; out_timestamp = in_timestamp; + if (!rtph264depay->byte_stream) { + if (nal_type == 7 || nal_type == 8) { + gst_rtp_h264_add_sps_pps (rtph264depay, gst_buffer_create_sub (nal, 4, + GST_BUFFER_SIZE (nal) - 4)); + gst_buffer_unref (nal); + return NULL; + } else if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0) { + /* Down push down any buffer in non-bytestream mode if the SPS/PPS haven't + * go through yet + */ + gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload), + gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, + gst_structure_new ("GstForceKeyUnit", + "all-headers", G_TYPE_BOOLEAN, TRUE, NULL))); + gst_buffer_unref (nal); + return FALSE; + } + + if (rtph264depay->new_codec_data && + rtph264depay->sps->len > 0 && rtph264depay->pps->len > 0) + gst_rtp_h264_set_src_caps (rtph264depay); + } + + if (rtph264depay->merge) { gboolean start = FALSE, complete = FALSE; diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h index f50ffe6a37..fd2603f76f 100644 --- a/gst/rtp/gstrtph264depay.h +++ b/gst/rtp/gstrtph264depay.h @@ -61,6 +61,11 @@ struct _GstRtpH264Depay guint8 current_fu_type; GstClockTime fu_timestamp; gboolean fu_marker; + + /* misc */ + GPtrArray *sps; + GPtrArray *pps; + gboolean new_codec_data; }; struct _GstRtpH264DepayClass From 729a30c38b2aacfac9aa6454d7037e08c1416557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 17 Mar 2012 20:18:19 +0000 Subject: [PATCH 18/24] gdkpixbuf: add gdkpixbufoverlay element Still lacks features such as positioning or resizing, or animations, but it's usable already, and supports lots of formats. --- ext/gdk_pixbuf/Makefile.am | 4 +- ext/gdk_pixbuf/gstgdkpixbuf.c | 5 + ext/gdk_pixbuf/gstgdkpixbufoverlay.c | 352 +++++++++++++++++++++++++++ ext/gdk_pixbuf/gstgdkpixbufoverlay.h | 70 ++++++ 4 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 ext/gdk_pixbuf/gstgdkpixbufoverlay.c create mode 100644 ext/gdk_pixbuf/gstgdkpixbufoverlay.h diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am index cf5265c2e8..e5a1cb4bb3 100644 --- a/ext/gdk_pixbuf/Makefile.am +++ b/ext/gdk_pixbuf/Makefile.am @@ -1,6 +1,7 @@ plugin_LTLIBRARIES = libgstgdkpixbuf.la -libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c +libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c \ + gstgdkpixbufoverlay.c libgstgdkpixbuf_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ @@ -14,6 +15,7 @@ libgstgdkpixbuf_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ gstgdkpixbuf.h \ + gstgdkpixbufoverlay.c \ gstgdkpixbufsink.h \ pixbufscale.h \ gstgdkanimation.h diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index 0a09400b37..7b31d2d5f4 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -27,6 +27,7 @@ #include #include "gstgdkpixbuf.h" +#include "gstgdkpixbufoverlay.h" #include "gstgdkpixbufsink.h" #include "pixbufscale.h" @@ -537,6 +538,10 @@ plugin_init (GstPlugin * plugin) gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL); #endif + if (!gst_element_register (plugin, "gdkpixbufoverlay", GST_RANK_NONE, + GST_TYPE_GDK_PIXBUF_OVERLAY)) + return FALSE; + if (!gst_element_register (plugin, "gdkpixbufsink", GST_RANK_NONE, GST_TYPE_GDK_PIXBUF_SINK)) return FALSE; diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c new file mode 100644 index 0000000000..fcf712cff4 --- /dev/null +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -0,0 +1,352 @@ +/* GStreamer GdkPixbuf overlay + * Copyright (C) 2012 Tim-Philipp Müller + * + * 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., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ +/** + * SECTION:element-gdkpixbufoverlay + * + * The gdkpixbufoverlay element overlays an image loaded from file onto + * a video stream. + * + * + * Example launch line + * |[ + * gst-launch -v videotestsrc ! gdkpixbufoverlay location=image.png ! autovideosink + * ]| + * Overlays the image in image.png onto the test video picture produced by + * videotestsrc. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstgdkpixbufoverlay.h" + +GST_DEBUG_CATEGORY_STATIC (gdkpixbufoverlay_debug); +#define GST_CAT_DEFAULT gdkpixbufoverlay_debug + +static void gst_gdk_pixbuf_overlay_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_gdk_pixbuf_overlay_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_gdk_pixbuf_overlay_finalize (GObject * object); + +static gboolean gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans); +static gboolean gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans); +static GstFlowReturn +gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf); +static gboolean +gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps); + +enum +{ + PROP_0, + PROP_LOCATION +}; + +#define VIDEO_CAPS \ + GST_VIDEO_CAPS_BGRx ";" \ + GST_VIDEO_CAPS_RGB ";" \ + GST_VIDEO_CAPS_BGR ";" \ + GST_VIDEO_CAPS_RGBx ";" \ + GST_VIDEO_CAPS_xRGB ";" \ + GST_VIDEO_CAPS_xBGR ";" \ + GST_VIDEO_CAPS_RGBA ";" \ + GST_VIDEO_CAPS_BGRA ";" \ + GST_VIDEO_CAPS_ARGB ";" \ + GST_VIDEO_CAPS_ABGR ";" \ + GST_VIDEO_CAPS_YUV ("{I420, YV12, AYUV, YUY2, UYVY, v308, v210," \ + " v216, Y41B, Y42B, Y444, Y800, Y16, NV12, NV21, UYVP, A420," \ + " YUV9, IYU1}") + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS) + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS) + ); + +GST_BOILERPLATE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay, + GstVideoFilter, GST_TYPE_VIDEO_FILTER); + +static void +gst_gdk_pixbuf_overlay_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_static_pad_template (element_class, &sink_template); + gst_element_class_add_static_pad_template (element_class, &src_template); + + gst_element_class_set_details_simple (element_class, + "GdkPixbuf Overlay", "Filter/Effect/Video", + "Overlay an image onto a video stream", + "Tim-Philipp Müller "); +} + +static void +gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass) +{ + GstBaseTransformClass *basetrans_class = GST_BASE_TRANSFORM_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = gst_gdk_pixbuf_overlay_set_property; + gobject_class->get_property = gst_gdk_pixbuf_overlay_get_property; + gobject_class->finalize = gst_gdk_pixbuf_overlay_finalize; + + basetrans_class->start = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_start); + basetrans_class->stop = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_stop); + basetrans_class->set_caps = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_set_caps); + basetrans_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_transform_ip); + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "location", + "location of image file to overlay", "", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0, + "debug category for gdkpixbufoverlay element"); +} + +static void +gst_gdk_pixbuf_overlay_init (GstGdkPixbufOverlay * overlay, + GstGdkPixbufOverlayClass * overlay_class) +{ + /* nothing to do here for now */ +} + +void +gst_gdk_pixbuf_overlay_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + switch (property_id) { + case PROP_LOCATION: + g_free (overlay->location); + overlay->location = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_gdk_pixbuf_overlay_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + switch (property_id) { + case PROP_LOCATION: + g_value_set_string (value, overlay->location); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_gdk_pixbuf_overlay_finalize (GObject * object) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + g_free (overlay->location); + overlay->location = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_gdk_pixbuf_overlay_load_image (GstGdkPixbufOverlay * overlay, GError ** err) +{ + GdkPixbuf *pixbuf; + guint8 *pixels, *p; + gint width, height, stride, w, h; + + pixbuf = gdk_pixbuf_new_from_file (overlay->location, err); + + if (pixbuf == NULL) + return FALSE; + + if (!gdk_pixbuf_get_has_alpha (pixbuf)) { + GdkPixbuf *alpha_pixbuf; + + /* FIXME: we could do this much more efficiently ourselves below, but + * we're lazy for now */ + /* FIXME: perhaps expose substitute_color via properties */ + alpha_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); + g_object_unref (pixbuf); + pixbuf = alpha_pixbuf; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + /* the memory layout in GdkPixbuf is R-G-B-A, we want: + * - B-G-R-A on little-endian platforms + * - A-R-G-B on big-endian platforms + */ + for (h = 0; h < height; ++h) { + p = pixels + (h * stride); + for (w = 0; w < width; ++w) { + guint8 tmp; + + /* R-G-B-A ==> B-G-R-A */ + tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + + if (G_BYTE_ORDER == G_BIG_ENDIAN) { + /* B-G-R-A ==> A-R-G-B */ + /* we can probably assume sane alignment */ + *((guint32 *) p) = GUINT32_SWAP_LE_BE (*((guint32 *) p)); + } + + p += 4; + } + } + + overlay->pixels = gst_buffer_new (); + GST_BUFFER_DATA (overlay->pixels) = pixels; + /* assume we have row padding even for the last row */ + GST_BUFFER_SIZE (overlay->pixels) = height * stride; + /* transfer ownership of pixbuf to buffer */ + GST_BUFFER_MALLOCDATA (overlay->pixels) = (guint8 *) pixbuf; + GST_BUFFER_FREE_FUNC (overlay->pixels) = (GFreeFunc) g_object_unref; + + overlay->pixels_width = width; + overlay->pixels_height = height; + overlay->pixels_stride = stride; + + overlay->update_composition = TRUE; + + GST_INFO_OBJECT (overlay, "Loaded image, %d x %d", width, height); + return TRUE; +} + +static gboolean +gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GError *err = NULL; + + if (overlay->location != NULL) { + if (!gst_gdk_pixbuf_overlay_load_image (overlay, &err)) + goto error_loading_image; + + gst_base_transform_set_passthrough (trans, FALSE); + } else { + GST_WARNING_OBJECT (overlay, "no image location set, doing nothing"); + gst_base_transform_set_passthrough (trans, TRUE); + } + + return TRUE; + +/* ERRORS */ +error_loading_image: + { + GST_ELEMENT_ERROR (overlay, RESOURCE, OPEN_READ, + ("Could not load overlay image."), ("%s", err->message)); + g_error_free (err); + return FALSE; + } +} + +static gboolean +gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + + if (overlay->comp) { + gst_video_overlay_composition_unref (overlay->comp); + overlay->comp = NULL; + } + + gst_buffer_replace (&overlay->pixels, NULL); + + return TRUE; +} + +static gboolean +gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GstVideoFormat video_format; + int w, h; + + if (!gst_video_format_parse_caps (incaps, &video_format, &w, &h)) + return FALSE; + + overlay->format = video_format; + overlay->width = w; + overlay->height = h; + return TRUE; +} + +static void +gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay) +{ + GstVideoOverlayComposition *comp; + GstVideoOverlayRectangle *rect; + + /* FIXME: add properties for position and render width and height */ + rect = gst_video_overlay_rectangle_new_argb (overlay->pixels, + overlay->pixels_width, overlay->pixels_height, overlay->pixels_stride, + 0, 0, overlay->pixels_width, overlay->pixels_height, + GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE); + + comp = gst_video_overlay_composition_new (rect); + gst_video_overlay_rectangle_unref (rect); + + if (overlay->comp) + gst_video_overlay_composition_unref (overlay->comp); + overlay->comp = comp; +} + +static GstFlowReturn +gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf) +{ + GstGdkPixbufOverlay *overlay; + + overlay = GST_GDK_PIXBUF_OVERLAY (trans); + + if (G_UNLIKELY (overlay->update_composition)) { + gst_gdk_pixbuf_overlay_update_composition (overlay); + overlay->update_composition = FALSE; + } + + gst_video_overlay_composition_blend (overlay->comp, buf); + + return GST_FLOW_OK; +} diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h new file mode 100644 index 0000000000..d40d4dd797 --- /dev/null +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h @@ -0,0 +1,70 @@ +/* GStreamer GdkPixbuf overlay + * Copyright (C) 2012 Tim-Philipp Müller + * + * 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_GDK_PIXBUF_OVERLAY_H_ +#define _GST_GDK_PIXBUF_OVERLAY_H_ + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_GDK_PIXBUF_OVERLAY (gst_gdk_pixbuf_overlay_get_type()) +#define GST_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlay)) +#define GST_GDK_PIXBUF_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlayClass)) +#define GST_IS_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_OVERLAY)) +#define GST_IS_GDK_PIXBUF_OVERLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_OVERLAY)) + +typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay; +typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass; + +struct _GstGdkPixbufOverlay +{ + GstVideoFilter videofilter; + + GstVideoFormat format; + gint width; + gint height; + + gchar * location; + + GstBuffer * pixels; + guint pixels_width; + guint pixels_height; + guint pixels_stride; + + GstVideoOverlayComposition * comp; + + /* render position or dimension has changed */ + gboolean update_composition; +}; + +struct _GstGdkPixbufOverlayClass +{ + GstVideoFilterClass videofilter_class; +}; + +GType gst_gdk_pixbuf_overlay_get_type (void); + +G_END_DECLS + +#endif From fdb7ec12b46523a85197ea17c67ea69ed993d94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 17 Mar 2012 23:41:38 +0000 Subject: [PATCH 19/24] gdkpixbufoverlay: add properties for positioning and sizing --- ext/gdk_pixbuf/gstgdkpixbufoverlay.c | 144 +++++++++++++++++++++++++-- ext/gdk_pixbuf/gstgdkpixbufoverlay.h | 12 +++ 2 files changed, 150 insertions(+), 6 deletions(-) diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c index fcf712cff4..10bec38049 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -18,10 +18,20 @@ */ /** * SECTION:element-gdkpixbufoverlay + * @see_also: * * The gdkpixbufoverlay element overlays an image loaded from file onto * a video stream. * + * Changing the positioning or overlay width and height properties at runtime + * is supported, but it might be prudent to to protect the property setting + * code with GST_BASE_TRANSFORM_LOCK and GST_BASE_TRANSFORM_UNLOCK, as + * g_object_set() is not atomic for multiple properties passed in one go. + * + * Changing the image at runtime is currently not supported. + * + * Negative offsets are also not yet supported. + * * * Example launch line * |[ @@ -30,6 +40,8 @@ * Overlays the image in image.png onto the test video picture produced by * videotestsrc. * + * + * Since: 0.10.33 */ #ifdef HAVE_CONFIG_H @@ -60,7 +72,13 @@ gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, enum { PROP_0, - PROP_LOCATION + PROP_LOCATION, + PROP_OFFSET_X, + PROP_OFFSET_Y, + PROP_RELATIVE_X, + PROP_RELATIVE_Y, + PROP_OVERLAY_WIDTH, + PROP_OVERLAY_HEIGHT }; #define VIDEO_CAPS \ @@ -126,8 +144,36 @@ gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass) g_object_class_install_property (gobject_class, PROP_LOCATION, g_param_spec_string ("location", "location", - "location of image file to overlay", "", + "location of image file to overlay", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OFFSET_X, + g_param_spec_int ("offset-x", "X Offset", + "horizontal offset of overlay image in pixels from top-left corner " + "of video image", G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OFFSET_Y, + g_param_spec_int ("offset-y", "Y Offset", + "vertical offset of overlay image in pixels from top-left corner " + "of video image", G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RELATIVE_X, + g_param_spec_double ("relative-x", "Relative X Offset", + "horizontal offset of overlay image in fractions of video image " + "width, from top-left corner of video image", + 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RELATIVE_Y, + g_param_spec_double ("relative-y", "Relative Y Offset", + "vertical offset of overlay image in fractions of video image " + "height, from top-left corner of video image", + 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH, + g_param_spec_int ("overlay-width", "Overlay Width", + "width of overlay image in pixels (0 = same as overlay image)", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT, + g_param_spec_int ("overlay-height", "Overlay Height", + "height of overlay image in pixels (0 = same as overlay image)", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0, "debug category for gdkpixbufoverlay element"); @@ -137,7 +183,14 @@ static void gst_gdk_pixbuf_overlay_init (GstGdkPixbufOverlay * overlay, GstGdkPixbufOverlayClass * overlay_class) { - /* nothing to do here for now */ + overlay->offset_x = 0; + overlay->offset_y = 0; + + overlay->relative_x = 0.0; + overlay->relative_y = 0.0; + + overlay->overlay_width = 0; + overlay->overlay_height = 0; } void @@ -146,15 +199,43 @@ gst_gdk_pixbuf_overlay_set_property (GObject * object, guint property_id, { GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + GST_OBJECT_LOCK (overlay); + switch (property_id) { case PROP_LOCATION: g_free (overlay->location); overlay->location = g_value_dup_string (value); break; + case PROP_OFFSET_X: + overlay->offset_x = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_OFFSET_Y: + overlay->offset_y = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_RELATIVE_X: + overlay->relative_x = g_value_get_double (value); + overlay->update_composition = TRUE; + break; + case PROP_RELATIVE_Y: + overlay->relative_y = g_value_get_double (value); + overlay->update_composition = TRUE; + break; + case PROP_OVERLAY_WIDTH: + overlay->overlay_width = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_OVERLAY_HEIGHT: + overlay->overlay_height = g_value_get_int (value); + overlay->update_composition = TRUE; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } + + GST_OBJECT_UNLOCK (overlay); } void @@ -163,14 +244,36 @@ gst_gdk_pixbuf_overlay_get_property (GObject * object, guint property_id, { GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + GST_OBJECT_LOCK (overlay); + switch (property_id) { case PROP_LOCATION: g_value_set_string (value, overlay->location); break; + case PROP_OFFSET_X: + g_value_set_int (value, overlay->offset_x); + break; + case PROP_OFFSET_Y: + g_value_set_int (value, overlay->offset_y); + break; + case PROP_RELATIVE_X: + g_value_set_double (value, overlay->relative_x); + break; + case PROP_RELATIVE_Y: + g_value_set_double (value, overlay->relative_y); + break; + case PROP_OVERLAY_WIDTH: + g_value_set_int (value, overlay->overlay_width); + break; + case PROP_OVERLAY_HEIGHT: + g_value_set_int (value, overlay->overlay_height); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } + + GST_OBJECT_UNLOCK (overlay); } void @@ -319,12 +422,37 @@ gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay) { GstVideoOverlayComposition *comp; GstVideoOverlayRectangle *rect; + gint x, y, width, height; + + x = overlay->offset_x + (overlay->relative_x * overlay->pixels_width); + y = overlay->offset_y + (overlay->relative_y * overlay->pixels_height); + + /* FIXME: this should work, but seems to crash */ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + width = overlay->overlay_width; + if (width == 0) + width = overlay->pixels_width; + + height = overlay->overlay_height; + if (height == 0) + height = overlay->pixels_height; + + GST_DEBUG_OBJECT (overlay, "overlay image dimensions: %d x %d", + overlay->pixels_width, overlay->pixels_height); + GST_DEBUG_OBJECT (overlay, "properties: x,y: %d,%d (%g%%,%g%%) - WxH: %dx%d", + overlay->offset_x, overlay->offset_y, + overlay->relative_x * 100.0, overlay->relative_y * 100.0, + overlay->overlay_height, overlay->overlay_width); + GST_DEBUG_OBJECT (overlay, "overlay rendered: %d x %d @ %d,%d (onto %d x %d)", + width, height, x, y, overlay->width, overlay->height); - /* FIXME: add properties for position and render width and height */ rect = gst_video_overlay_rectangle_new_argb (overlay->pixels, overlay->pixels_width, overlay->pixels_height, overlay->pixels_stride, - 0, 0, overlay->pixels_width, overlay->pixels_height, - GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE); + x, y, width, height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE); comp = gst_video_overlay_composition_new (rect); gst_video_overlay_rectangle_unref (rect); @@ -341,11 +469,15 @@ gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf) overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GST_OBJECT_LOCK (overlay); + if (G_UNLIKELY (overlay->update_composition)) { gst_gdk_pixbuf_overlay_update_composition (overlay); overlay->update_composition = FALSE; } + GST_OBJECT_UNLOCK (overlay); + gst_video_overlay_composition_blend (overlay->comp, buf); return GST_FLOW_OK; diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h index d40d4dd797..51dc2cafce 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h @@ -41,12 +41,24 @@ struct _GstGdkPixbufOverlay { GstVideoFilter videofilter; + /* negotiated format */ GstVideoFormat format; gint width; gint height; + /* properties */ gchar * location; + gint offset_x; + gint offset_y; + + gdouble relative_x; + gdouble relative_y; + + gint overlay_width; + gint overlay_height; + + /* the loaded image */ GstBuffer * pixels; guint pixels_width; guint pixels_height; From a4860b3c01da88c25da8da60502ab87274bd563f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 18 Mar 2012 00:11:19 +0000 Subject: [PATCH 20/24] gdkpixbufoverlay: make most properties controllable and flag them as mutable-playing --- ext/gdk_pixbuf/Makefile.am | 2 + ext/gdk_pixbuf/gstgdkpixbuf.c | 3 ++ ext/gdk_pixbuf/gstgdkpixbufoverlay.c | 60 +++++++++++++++++++--------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am index e5a1cb4bb3..abd7d0b2df 100644 --- a/ext/gdk_pixbuf/Makefile.am +++ b/ext/gdk_pixbuf/Makefile.am @@ -4,10 +4,12 @@ libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c \ gstgdkpixbufoverlay.c libgstgdkpixbuf_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_CONTROLLER_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) $(GDK_PIXBUF_CFLAGS) libgstgdkpixbuf_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + $(GST_CONTROLLER_LIBS) \ $(GST_BASE_LIBS) \ $(GST_LIBS) $(GDK_PIXBUF_LIBS) libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index 7b31d2d5f4..5ed7a86733 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include @@ -549,6 +550,8 @@ plugin_init (GstPlugin * plugin) if (!pixbufscale_init (plugin)) return FALSE; + gst_controller_init (NULL, NULL); + /* plugin initialisation succeeded */ return TRUE; } diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c index 10bec38049..bd795e1bf1 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -49,6 +49,7 @@ #endif #include +#include #include "gstgdkpixbufoverlay.h" @@ -65,6 +66,8 @@ static gboolean gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans); static gboolean gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans); static GstFlowReturn gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf); +static void gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans, + GstBuffer * outbuf); static gboolean gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps); @@ -141,39 +144,49 @@ gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass) GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_set_caps); basetrans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_transform_ip); + basetrans_class->before_transform = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_before_transform); g_object_class_install_property (gobject_class, PROP_LOCATION, g_param_spec_string ("location", "location", - "location of image file to overlay", NULL, + "Location of image file to overlay", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_OFFSET_X, g_param_spec_int ("offset-x", "X Offset", - "horizontal offset of overlay image in pixels from top-left corner " + "Horizontal offset of overlay image in pixels from top-left corner " "of video image", G_MININT, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_OFFSET_Y, g_param_spec_int ("offset-y", "Y Offset", - "vertical offset of overlay image in pixels from top-left corner " + "Vertical offset of overlay image in pixels from top-left corner " "of video image", G_MININT, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RELATIVE_X, g_param_spec_double ("relative-x", "Relative X Offset", - "horizontal offset of overlay image in fractions of video image " - "width, from top-left corner of video image", - 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Horizontal offset of overlay image in fractions of video image " + "width, from top-left corner of video image", 0.0, 1.0, 0.0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RELATIVE_Y, g_param_spec_double ("relative-y", "Relative Y Offset", - "vertical offset of overlay image in fractions of video image " - "height, from top-left corner of video image", - 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Vertical offset of overlay image in fractions of video image " + "height, from top-left corner of video image", 0.0, 1.0, 0.0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH, g_param_spec_int ("overlay-width", "Overlay Width", - "width of overlay image in pixels (0 = same as overlay image)", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Width of overlay image in pixels (0 = same as overlay image)", 0, + G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT, g_param_spec_int ("overlay-height", "Overlay Height", - "height of overlay image in pixels (0 = same as overlay image)", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Height of overlay image in pixels (0 = same as overlay image)", 0, + G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0, "debug category for gdkpixbufoverlay element"); @@ -462,12 +475,23 @@ gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay) overlay->comp = comp; } +static void +gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans, + GstBuffer * outbuf) +{ + GstClockTime stream_time; + + stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (outbuf)); + + if (GST_CLOCK_TIME_IS_VALID (stream_time)) + gst_object_sync_values (G_OBJECT (trans), stream_time); +} + static GstFlowReturn gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { - GstGdkPixbufOverlay *overlay; - - overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); GST_OBJECT_LOCK (overlay); From e300675384f5a70f27508274201462714a2e4bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 17 Mar 2012 20:53:31 +0000 Subject: [PATCH 21/24] docs: update docs for new properties and add gdkpixbufoverlay element Somewhat at least. No idea why it doesn't pick up the description or example pipeline. --- docs/plugins/Makefile.am | 1 + .../gst-plugins-good-plugins-docs.sgml | 1 + .../gst-plugins-good-plugins-sections.txt | 14 +++ docs/plugins/gst-plugins-good-plugins.args | 86 ++++++++++++++++++- .../gst-plugins-good-plugins.hierarchy | 6 +- docs/plugins/inspect/plugin-audioparsers.xml | 21 +++++ docs/plugins/inspect/plugin-avi.xml | 2 +- docs/plugins/inspect/plugin-gdkpixbuf.xml | 21 +++++ docs/plugins/inspect/plugin-png.xml | 4 +- docs/plugins/inspect/plugin-wavpack.xml | 6 +- ext/gdk_pixbuf/gstgdkpixbufoverlay.c | 1 + ext/gdk_pixbuf/gstgdkpixbufoverlay.h | 5 ++ 12 files changed, 157 insertions(+), 11 deletions(-) diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 1fc2e07ff5..dc0a0fcb45 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -69,6 +69,7 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/gconf/gstgconfaudiosink.h \ $(top_srcdir)/ext/gconf/gstgconfvideosrc.h \ $(top_srcdir)/ext/gconf/gstgconfvideosink.h \ + $(top_srcdir)/ext/gdk_pixbuf/gstgdkpixbufoverlay.h \ $(top_srcdir)/ext/gdk_pixbuf/gstgdkpixbufsink.h \ $(top_srcdir)/ext/hal/gsthalaudiosink.h \ $(top_srcdir)/ext/hal/gsthalaudiosrc.h \ diff --git a/docs/plugins/gst-plugins-good-plugins-docs.sgml b/docs/plugins/gst-plugins-good-plugins-docs.sgml index 9f65e21eb9..2c7d08bd44 100644 --- a/docs/plugins/gst-plugins-good-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-good-plugins-docs.sgml @@ -85,6 +85,7 @@ + diff --git a/docs/plugins/gst-plugins-good-plugins-sections.txt b/docs/plugins/gst-plugins-good-plugins-sections.txt index 0f03971e71..e5f4c38908 100644 --- a/docs/plugins/gst-plugins-good-plugins-sections.txt +++ b/docs/plugins/gst-plugins-good-plugins-sections.txt @@ -983,6 +983,20 @@ GST_IS_GCONF_VIDEO_SINK_CLASS gst_gconf_video_sink_get_type +
+element-gdkpixbufoverlay +gdkpixbufoverlay +GstGdkPixbufOverlay + +GstGdkPixbufOverlayClass +GST_TYPE_GDK_PIXBUF_OVERLAY +GST_GDK_PIXBUF_OVERLAY +GST_GDK_PIXBUF_OVERLAY_CLASS +GST_IS_GDK_PIXBUF_OVERLAY +GST_IS_GDK_PIXBUF_OVERLAY_CLASS +gst_gdk_pixbuf_overlay_get_type +
+
element-gdkpixbufsink gdkpixbufsink diff --git a/docs/plugins/gst-plugins-good-plugins.args b/docs/plugins/gst-plugins-good-plugins.args index 593b00bc2f..65153bc35c 100644 --- a/docs/plugins/gst-plugins-good-plugins.args +++ b/docs/plugins/gst-plugins-good-plugins.args @@ -838,6 +838,16 @@ FALSE + +GstRTSPSrc::do-rtsp-keep-alive +gboolean + +rw +Do RTSP Keep Alive +Send RTSP keep alive packets, disable for old incompatible server. +TRUE + + GstRTPDec::skip gint @@ -1895,7 +1905,7 @@ rwx Seekpoints Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec). -0 +-10 @@ -21395,7 +21405,7 @@ rw Transport mode Jack transport behaviour of the client. -No transport support + @@ -21445,7 +21455,7 @@ rw Transport mode Jack transport behaviour of the client. -No transport support + @@ -22448,3 +22458,73 @@ FALSE + +GstGdkPixbufOverlay::location +gchar* + +rw +location +Location of image file to overlay. +NULL + + + +GstGdkPixbufOverlay::offset-x +gint + +rw +X Offset +Horizontal offset of overlay image in pixels from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::offset-y +gint + +rw +Y Offset +Vertical offset of overlay image in pixels from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::overlay-height +gint +>= 0 +rw +Overlay Height +Height of overlay image in pixels (0 = same as overlay image). +0 + + + +GstGdkPixbufOverlay::overlay-width +gint +>= 0 +rw +Overlay Width +Width of overlay image in pixels (0 = same as overlay image). +0 + + + +GstGdkPixbufOverlay::relative-x +gdouble +[0,1] +rw +Relative X Offset +Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::relative-y +gdouble +[0,1] +rw +Relative Y Offset +Vertical offset of overlay image in fractions of video image height, from top-left corner of video image. +0 + + diff --git a/docs/plugins/gst-plugins-good-plugins.hierarchy b/docs/plugins/gst-plugins-good-plugins.hierarchy index 350d02d420..9b6664095d 100644 --- a/docs/plugins/gst-plugins-good-plugins.hierarchy +++ b/docs/plugins/gst-plugins-good-plugins.hierarchy @@ -17,9 +17,11 @@ GObject GstAuParse GstAudioDecoder GstSpeexDec + GstWavpackDec GstAudioEncoder GstFlacEnc GstSpeexEnc + GstWavpackEnc GstAviDemux GstAviMux GstAviSubtitle @@ -30,6 +32,7 @@ GObject GstDcaParse GstFlacParse GstMpegAudioParse + GstWavpackParse2 GstBaseRTPDepayload GstRTPBVDepay GstRTPDVDepay @@ -178,6 +181,7 @@ GObject GstDiceTV GstEdgeTV GstGamma + GstGdkPixbufOverlay GstNavigationtest GstOpTV GstQuarkTV @@ -277,8 +281,6 @@ GObject GstVideoMixer2 GstWavEnc GstWavParse - GstWavpackDec - GstWavpackEnc GstWavpackParse GstY4mEncode GstPad diff --git a/docs/plugins/inspect/plugin-audioparsers.xml b/docs/plugins/inspect/plugin-audioparsers.xml index c5735a9bf6..764ebfa294 100644 --- a/docs/plugins/inspect/plugin-audioparsers.xml +++ b/docs/plugins/inspect/plugin-audioparsers.xml @@ -135,5 +135,26 @@ + + wavpackparse2 + Wavpack audio stream parser + Codec/Parser/Audio + Wavpack parser + Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + + sink + sink + always +
audio/x-wavpack
+
+ + src + source + always +
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true; audio/x-wavpack-correction, framed=(boolean)true
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-avi.xml b/docs/plugins/inspect/plugin-avi.xml index 49af23ace3..ca7769232b 100644 --- a/docs/plugins/inspect/plugin-avi.xml +++ b/docs/plugins/inspect/plugin-avi.xml @@ -53,7 +53,7 @@ audio_%d sink request -
audio/x-raw-int, endianness=(int)1234, signed=(boolean){ true, false }, width=(int){ 8, 16 }, depth=(int){ 8, 16 }, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/x-ac3, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/x-alaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-mulaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-wma, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ], wmaversion=(int)[ 1, 2 ]
+
audio/x-raw-int, endianness=(int)1234, signed=(boolean){ true, false }, width=(int){ 8, 16 }, depth=(int){ 8, 16 }, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ]; audio/x-ac3, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 6 ]; audio/x-alaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-mulaw, rate=(int)[ 1000, 48000 ], channels=(int)[ 1, 2 ]; audio/x-wma, rate=(int)[ 1000, 96000 ], channels=(int)[ 1, 2 ], wmaversion=(int)[ 1, 2 ]
video_%d diff --git a/docs/plugins/inspect/plugin-gdkpixbuf.xml b/docs/plugins/inspect/plugin-gdkpixbuf.xml index 10b8c5db7f..d8f54a122c 100644 --- a/docs/plugins/inspect/plugin-gdkpixbuf.xml +++ b/docs/plugins/inspect/plugin-gdkpixbuf.xml @@ -30,6 +30,27 @@ + + gdkpixbufoverlay + GdkPixbuf Overlay + Filter/Effect/Video + Overlay an image onto a video stream + Tim-Philipp Müller <tim centricular net> + + + sink + sink + always +
video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc){ I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, Y800, Y16 , NV12, NV21, UYVP, A420, YUV9, IYU1 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
+ + src + source + always +
video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc){ I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, Y800, Y16 , NV12, NV21, UYVP, A420, YUV9, IYU1 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
+
+
gdkpixbufscale GdkPixbuf image scaler diff --git a/docs/plugins/inspect/plugin-png.xml b/docs/plugins/inspect/plugin-png.xml index 291d33e506..704817d688 100644 --- a/docs/plugins/inspect/plugin-png.xml +++ b/docs/plugins/inspect/plugin-png.xml @@ -26,7 +26,7 @@ src source always -
video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)64, depth=(int)64, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)64, depth=(int)64, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
@@ -41,7 +41,7 @@ sink sink always -
video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
src diff --git a/docs/plugins/inspect/plugin-wavpack.xml b/docs/plugins/inspect/plugin-wavpack.xml index 8a489dc165..0d01ce7d4d 100644 --- a/docs/plugins/inspect/plugin-wavpack.xml +++ b/docs/plugins/inspect/plugin-wavpack.xml @@ -26,7 +26,7 @@ src source always -
audio/x-raw-int, width=(int)32, depth=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true
+
audio/x-raw-int, width=(int)8, depth=(int)8, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true; audio/x-raw-int, width=(int)16, depth=(int)16, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true; audio/x-raw-int, width=(int)32, depth=(int)32, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true
@@ -41,13 +41,13 @@ sink sink always -
audio/x-raw-int, width=(int)32, depth=(int)[ 1, 32 ], endianness=(int)1234, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], signed=(boolean)true
+
audio/x-raw-int, width=(int)32, depth=(int){ 24, 32 }, endianness=(int)1234, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], signed=(boolean)true
src source always -
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 2 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true
+
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true
wvcsrc diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c index bd795e1bf1..0e844f484b 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -16,6 +16,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, * Boston, MA 02110-1335, USA. */ + /** * SECTION:element-gdkpixbufoverlay * @see_also: diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h index 51dc2cafce..9c940909f4 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h @@ -37,6 +37,11 @@ G_BEGIN_DECLS typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay; typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass; +/** + * GstGdkPixbufOverlay: + * + * The opaque element instance structure. + */ struct _GstGdkPixbufOverlay { GstVideoFilter videofilter; From 19121249bd5dcfca440f276e2e05faf84245002c Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 16 Mar 2012 18:23:29 +0100 Subject: [PATCH 22/24] flacdec: improve error handling and resilience ... by noting that one occurred in the first place, and then appropriately ignoring some transient ones. --- ext/flac/gstflacdec.c | 37 +++++++++++++++++++++++++++++++++++-- ext/flac/gstflacdec.h | 2 ++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 10f8916c69..19a866cea8 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -542,6 +542,26 @@ gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples) } } +static gboolean +gst_flac_dec_handle_decoder_error (GstFlacDec * dec, gboolean msg) +{ + gboolean ret; + + dec->error_count++; + if (dec->error_count > 10) { + if (msg) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), (NULL)); + dec->last_flow = GST_FLOW_ERROR; + ret = TRUE; + } else { + GST_DEBUG_OBJECT (dec, "ignoring error for now at count %d", + dec->error_count); + ret = FALSE; + } + + return ret; +} + static void gst_flac_extract_picture_buffer (GstFlacDec * dec, const FLAC__StreamMetadata * metadata) @@ -672,8 +692,8 @@ gst_flac_dec_error_cb (const FLAC__StreamDecoder * d, break; } - GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status)); - dec->last_flow = GST_FLOW_ERROR; + if (gst_flac_dec_handle_decoder_error (dec, FALSE)) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status)); } static FLAC__StreamDecoderSeekStatus @@ -1023,6 +1043,9 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, g_assert_not_reached (); } + if (flacdec->error_count) + flacdec->error_count--; + if (!flacdec->seeking) { GST_DEBUG_OBJECT (flacdec, "pushing %d samples at offset %" G_GINT64_FORMAT " (%" GST_TIME_FORMAT " + %" GST_TIME_FORMAT ")", @@ -1503,6 +1526,15 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf) if (!FLAC__stream_decoder_process_single (dec->decoder)) { GST_DEBUG_OBJECT (dec, "process_single failed"); } + + if (FLAC__stream_decoder_get_state (dec->decoder) == + FLAC__STREAM_DECODER_ABORTED) { + GST_WARNING_OBJECT (dec, "Read callback caused internal abort"); + /* allow recovery */ + gst_adapter_clear (dec->adapter); + FLAC__stream_decoder_flush (dec->decoder); + gst_flac_dec_handle_decoder_error (dec, TRUE); + } } else { GST_DEBUG_OBJECT (dec, "don't have all headers yet"); } @@ -2154,6 +2186,7 @@ gst_flac_dec_change_state (GstElement * element, GstStateChange transition) flacdec->width = 0; flacdec->sample_rate = 0; gst_segment_init (&flacdec->segment, GST_FORMAT_DEFAULT); + flacdec->error_count = 0; break; default: break; diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h index 835bdbd8c0..f3882a2b09 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -88,6 +88,8 @@ struct _GstFlacDec { guint16 max_blocksize; gint64 cur_granulepos; /* only used in framed mode (flac-in-ogg) */ + + gint error_count; }; struct _GstFlacDecClass { From 58816039c2846b0781b64e448c4e9ec28a6a3586 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 19 Mar 2012 11:58:15 +0100 Subject: [PATCH 23/24] flacparse: avoid indefinite extended search for frame end if possible ... which is particularly useful if locked on to the wrong frame start and/or corrupt frame being crc checked. --- gst/audioparsers/gstflacparse.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 9cfdb98103..942914e100 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -691,6 +691,15 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, } } + /* so we searched to expected end and found nothing, + * give up on this frame (start) */ + if (flacparse->max_framesize && i > 2 * flacparse->max_framesize) { + GST_LOG_OBJECT (flacparse, + "could not determine valid frame end, discarding frame (start)"); + *ret = 1; + return FALSE; + } + need_more: max = flacparse->max_framesize + 16; if (max == 16) From 440d7034f09de014f96ec183cd59e2b43bcf75c7 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 19 Mar 2012 12:01:40 +0100 Subject: [PATCH 24/24] flacparse: perform additional frame crc check if applicable ... such as a frame header parsing throwing some suspicious warnings. So we can be a bit more convinced we determine the right frame end. --- gst/audioparsers/gstflacparse.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 942914e100..ed4e733eec 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -381,7 +381,8 @@ typedef enum static FrameHeaderCheckReturn gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, - const guint8 * data, guint size, gboolean set, guint16 * block_size_ret) + const guint8 * data, guint size, gboolean set, guint16 * block_size_ret, + gboolean * suspect) { GstBitReader reader = GST_BIT_READER_INIT (data, size); guint8 blocking_strategy; @@ -575,6 +576,8 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, /* TODO: can we know we're on the last frame, to avoid warning ? */ GST_WARNING_OBJECT (flacparse, "Block size is not constant"); block_size = flacparse->block_size; + if (suspect) + *suspect = TRUE; } } } @@ -623,6 +626,7 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, guint i, search_start, search_end; FrameHeaderCheckReturn header_ret; guint16 block_size; + gboolean suspect_start = FALSE, suspect_end = FALSE; buffer = frame->buffer; data = GST_BUFFER_DATA (buffer); @@ -633,7 +637,7 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, header_ret = gst_flac_parse_frame_header_is_valid (flacparse, data, size, TRUE, - &block_size); + &block_size, &suspect_start); if (header_ret == FRAME_HEADER_INVALID) { *ret = 0; return FALSE; @@ -653,16 +657,23 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, for (i = search_start; i < search_end; i++, remaining--) { if ((GST_READ_UINT16_BE (data + i) & 0xfffe) == 0xfff8) { + GST_LOG_OBJECT (flacparse, "possible frame end at offset %d", i); + suspect_end = FALSE; header_ret = gst_flac_parse_frame_header_is_valid (flacparse, data + i, remaining, - FALSE, NULL); + FALSE, NULL, &suspect_end); if (header_ret == FRAME_HEADER_VALID) { - if (flacparse->check_frame_checksums) { + if (flacparse->check_frame_checksums || suspect_start || suspect_end) { guint16 actual_crc = gst_flac_calculate_crc16 (data, i - 2); guint16 expected_crc = GST_READ_UINT16_BE (data + i - 2); - if (actual_crc != expected_crc) + GST_LOG_OBJECT (flacparse, + "checking checksum, frame suspect (%d, %d)", + suspect_start, suspect_end); + if (actual_crc != expected_crc) { + GST_DEBUG_OBJECT (flacparse, "checksum did not match"); continue; + } } *ret = i; flacparse->block_size = block_size; @@ -1322,7 +1333,7 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) flacparse->offset = GST_BUFFER_OFFSET (buffer); ret = gst_flac_parse_frame_header_is_valid (flacparse, - GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE, NULL); + GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE, NULL, NULL); if (ret != FRAME_HEADER_VALID) { GST_ERROR_OBJECT (flacparse, "Baseclass didn't provide a complete frame");