diff options
-rw-r--r-- | ext/ivorbis/Makefile.am | 4 | ||||
-rw-r--r-- | ext/ivorbis/vorbisdec.c | 19 | ||||
-rw-r--r-- | ext/mimic/gstmimdec.c | 8 | ||||
-rw-r--r-- | ext/mimic/gstmimenc.c | 331 | ||||
-rw-r--r-- | ext/mimic/gstmimenc.h | 7 | ||||
-rw-r--r-- | gst-libs/gst/video/Makefile.am | 2 | ||||
-rw-r--r-- | gst/mpegdemux/gstmpegdesc.h | 17 | ||||
-rw-r--r-- | gst/mpegdemux/mpegtspacketizer.c | 41 | ||||
-rw-r--r-- | gst/shapewipe/gstshapewipe.c | 45 |
9 files changed, 422 insertions, 52 deletions
diff --git a/ext/ivorbis/Makefile.am b/ext/ivorbis/Makefile.am index 9fbea14c..83db5eab 100644 --- a/ext/ivorbis/Makefile.am +++ b/ext/ivorbis/Makefile.am @@ -3,10 +3,10 @@ plugin_LTLIBRARIES = libgstivorbis.la libgstivorbis_la_SOURCES = vorbis.c vorbisfile.c vorbisdec.c libgstivorbis_la_CFLAGS = $(GST_CFLAGS) $(IVORBIS_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) libgstivorbis_la_LIBADD = $(IVORBIS_LIBS) \ - $(IVORBISFILE_LIBS) \ $(GST_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ - -lgstaudio-@GST_MAJORMINOR@ + -lgstaudio-@GST_MAJORMINOR@ \ + -lgsttag-@GST_MAJORMINOR@ libgstivorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstivorbis_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/ivorbis/vorbisdec.c b/ext/ivorbis/vorbisdec.c index 325c46a3..4502a773 100644 --- a/ext/ivorbis/vorbisdec.c +++ b/ext/ivorbis/vorbisdec.c @@ -651,23 +651,26 @@ channel_count_error: static GstFlowReturn vorbis_handle_comment_packet (GstIVorbisDec * vd, ogg_packet * packet) { -#if 0 guint bitrate = 0; gchar *encoder = NULL; - GstTagList *list; + GstTagList *list, *old_list; GstBuffer *buf; GST_DEBUG_OBJECT (vd, "parsing comment packet"); - buf = gst_buffer_new_and_alloc (packet->bytes); - GST_BUFFER_DATA (buf) = packet->packet; + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = packet->packet->buffer->data; + GST_BUFFER_SIZE (buf) = packet->packet->buffer->size; list = gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7, &encoder); + old_list = vd->taglist; vd->taglist = gst_tag_list_merge (vd->taglist, list, GST_TAG_MERGE_REPLACE); + if (old_list) + gst_tag_list_free (old_list); gst_tag_list_free (list); gst_buffer_unref (buf); @@ -683,18 +686,18 @@ vorbis_handle_comment_packet (GstIVorbisDec * vd, ogg_packet * packet) gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, vd->vi.version, GST_TAG_AUDIO_CODEC, "Vorbis", NULL); - if (vd->vi.bitrate_nominal > 0) { + if (vd->vi.bitrate_nominal > 0 && vd->vi.bitrate_nominal <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, (guint) vd->vi.bitrate_nominal, NULL); bitrate = vd->vi.bitrate_nominal; } - if (vd->vi.bitrate_upper > 0) { + if (vd->vi.bitrate_upper > 0 && vd->vi.bitrate_upper <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE, (guint) vd->vi.bitrate_upper, NULL); if (!bitrate) bitrate = vd->vi.bitrate_upper; } - if (vd->vi.bitrate_lower > 0) { + if (vd->vi.bitrate_lower > 0 && vd->vi.bitrate_lower <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL); if (!bitrate) @@ -715,7 +718,7 @@ vorbis_handle_comment_packet (GstIVorbisDec * vd, ogg_packet * packet) gst_element_post_message (GST_ELEMENT_CAST (vd), gst_message_new_tag (GST_OBJECT (vd), gst_tag_list_copy (vd->taglist))); } -#endif + return GST_FLOW_OK; } diff --git a/ext/mimic/gstmimdec.c b/ext/mimic/gstmimdec.c index c7f1ec87..1579bd41 100644 --- a/ext/mimic/gstmimdec.c +++ b/ext/mimic/gstmimdec.c @@ -172,7 +172,7 @@ gst_mimdec_chain (GstPad * pad, GstBuffer * in) (mimdec->have_header ? mimdec->payload_size : 24)) { if (!mimdec->have_header) { header = (guchar *) gst_adapter_peek (mimdec->adapter, 24); - header_size = GUINT16_FROM_LE (*(guint16 *) (header + 0)); + header_size = header[0]; if (header_size != 24) { GST_WARNING_OBJECT (mimdec, "invalid frame: header size %d incorrect", header_size); @@ -201,6 +201,12 @@ gst_mimdec_chain (GstPad * pad, GstBuffer * in) mimdec->have_header = TRUE; } + /* Check if its paused frame, drop it */ + if (mimdec->payload_size == 0) { + mimdec->have_header = FALSE; + continue; + } + if (gst_adapter_available (mimdec->adapter) < mimdec->payload_size) { goto out; } diff --git a/ext/mimic/gstmimenc.c b/ext/mimic/gstmimenc.c index a69ab2cc..84f34012 100644 --- a/ext/mimic/gstmimenc.c +++ b/ext/mimic/gstmimenc.c @@ -42,6 +42,15 @@ GST_DEBUG_CATEGORY (mimenc_debug); #define MAX_INTERFRAMES 15 + +enum +{ + PROP_0, + PROP_PAUSED_MODE, + PROP_LAST +}; + + static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -75,11 +84,17 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", static gboolean gst_mimenc_setcaps (GstPad * pad, GstCaps * caps); static GstFlowReturn gst_mimenc_chain (GstPad * pad, GstBuffer * in); static GstBuffer *gst_mimenc_create_tcp_header (GstMimEnc * mimenc, - guint32 payload_size, guint32 timestamp); + guint32 payload_size, GstClockTime timestamp, gboolean keyframe, + gboolean paused); +static gboolean gst_mimenc_event (GstPad * pad, GstEvent * event); static GstStateChangeReturn gst_mimenc_change_state (GstElement * element, GstStateChange transition); +static void gst_mimenc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_mimenc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); GST_BOILERPLATE (GstMimEnc, gst_mimenc, GstElement, GST_TYPE_ELEMENT); @@ -93,6 +108,16 @@ gst_mimenc_base_init (gpointer klass) "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>" }; GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = gst_mimenc_set_property; + gobject_class->get_property = gst_mimenc_get_property; + + g_object_class_install_property (gobject_class, PROP_PAUSED_MODE, + g_param_spec_boolean ("paused-mode", "Paused mode", + "If enabled, empty frames will be generated every 4 seconds" + " when no data is received", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); @@ -123,6 +148,7 @@ gst_mimenc_init (GstMimEnc * mimenc, GstMimEncClass * klass) gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->sinkpad); gst_pad_set_setcaps_function (mimenc->sinkpad, gst_mimenc_setcaps); gst_pad_set_chain_function (mimenc->sinkpad, gst_mimenc_chain); + gst_pad_set_event_function (mimenc->sinkpad, gst_mimenc_event); mimenc->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&src_factory), @@ -131,6 +157,8 @@ gst_mimenc_init (GstMimEnc * mimenc, GstMimEncClass * klass) mimenc->enc = NULL; + gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); + // TODO property to set resolution mimenc->res = MIMIC_RES_HIGH; mimenc->buffer_size = -1; @@ -139,6 +167,42 @@ gst_mimenc_init (GstMimEnc * mimenc, GstMimEncClass * klass) mimenc->frames = 0; } +static void +gst_mimenc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMimEnc *mimenc = GST_MIMENC (object); + + switch (prop_id) { + case PROP_PAUSED_MODE: + GST_OBJECT_LOCK (mimenc); + mimenc->paused_mode = g_value_get_boolean (value); + GST_OBJECT_UNLOCK (mimenc); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_mimenc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstMimEnc *mimenc = GST_MIMENC (object); + + switch (prop_id) { + case PROP_PAUSED_MODE: + GST_OBJECT_LOCK (mimenc); + g_value_set_boolean (value, mimenc->paused_mode); + GST_OBJECT_UNLOCK (mimenc); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static gboolean gst_mimenc_setcaps (GstPad * pad, GstCaps * caps) { @@ -196,6 +260,8 @@ gst_mimenc_chain (GstPad * pad, GstBuffer * in) gint buffer_size; GstBuffer *header = NULL; GstFlowReturn res = GST_FLOW_OK; + GstEvent *event = NULL; + gboolean keyframe; g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); mimenc = GST_MIMENC (gst_pad_get_parent (pad)); @@ -204,6 +270,14 @@ gst_mimenc_chain (GstPad * pad, GstBuffer * in) GST_OBJECT_LOCK (mimenc); + if (mimenc->segment.format == GST_FORMAT_UNDEFINED) { + GST_WARNING_OBJECT (mimenc, "No new-segment received," + " initializing segment with time 0..-1"); + gst_segment_init (&mimenc->segment, GST_FORMAT_TIME); + gst_segment_set_newsegment (&mimenc->segment, + FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); + } + if (mimenc->enc == NULL) { mimenc->enc = mimic_open (); if (mimenc->enc == NULL) { @@ -233,11 +307,14 @@ gst_mimenc_chain (GstPad * pad, GstBuffer * in) data = GST_BUFFER_DATA (buf); out_buf = gst_buffer_new_and_alloc (mimenc->buffer_size); - GST_BUFFER_TIMESTAMP (out_buf) = GST_BUFFER_TIMESTAMP (buf); + GST_BUFFER_TIMESTAMP (out_buf) = + gst_segment_to_running_time (&mimenc->segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buf)); + mimenc->last_buffer = GST_BUFFER_TIMESTAMP (out_buf); buffer_size = mimenc->buffer_size; + keyframe = (mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE; if (!mimic_encode_frame (mimenc->enc, data, GST_BUFFER_DATA (out_buf), - &buffer_size, - ((mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE))) { + &buffer_size, keyframe)) { GST_WARNING_OBJECT (mimenc, "mimic_encode_frame error\n"); gst_buffer_unref (out_buf); gst_buffer_unref (buf); @@ -252,23 +329,40 @@ gst_mimenc_chain (GstPad * pad, GstBuffer * in) // now let's create that tcp header header = gst_mimenc_create_tcp_header (mimenc, buffer_size, - GST_BUFFER_TIMESTAMP (buf) / GST_MSECOND); + GST_BUFFER_TIMESTAMP (out_buf), keyframe, FALSE); + + if (!header) { + gst_buffer_unref (out_buf); + GST_DEBUG_OBJECT (mimenc, "header not created succesfully"); + res = GST_FLOW_ERROR; + goto out_unlock; + } + + if (mimenc->need_newsegment) { + event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); + mimenc->need_newsegment = FALSE; + } GST_OBJECT_UNLOCK (mimenc); - if (header) { - res = gst_pad_push (mimenc->srcpad, header); - if (res != GST_FLOW_OK) { + if (event) { + if (!gst_pad_push_event (mimenc->srcpad, event)) { + res = GST_FLOW_ERROR; + GST_ERROR_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); + gst_buffer_unref (header); gst_buffer_unref (out_buf); goto out; } + } - res = gst_pad_push (mimenc->srcpad, out_buf); - } else { - GST_DEBUG_OBJECT (mimenc, "header not created succesfully"); - res = GST_FLOW_ERROR; + res = gst_pad_push (mimenc->srcpad, header); + if (res != GST_FLOW_OK) { + gst_buffer_unref (out_buf); + goto out; } + res = gst_pad_push (mimenc->srcpad, out_buf); + out: if (buf) gst_buffer_unref (buf); @@ -284,34 +378,191 @@ out_unlock: static GstBuffer * gst_mimenc_create_tcp_header (GstMimEnc * mimenc, guint32 payload_size, - guint32 timestamp) + GstClockTime timestamp, gboolean keyframe, gboolean paused) { // 24 bytes GstBuffer *buf_header = gst_buffer_new_and_alloc (24); guchar *p = (guchar *) GST_BUFFER_DATA (buf_header); + GST_BUFFER_TIMESTAMP (buf_header) = timestamp; + p[0] = 24; - *((guchar *) (p + 1)) = 0; + *((guchar *) (p + 1)) = paused ? 1 : 0; *((guint16 *) (p + 2)) = GUINT16_TO_LE (mimenc->width); *((guint16 *) (p + 4)) = GUINT16_TO_LE (mimenc->height); - *((guint16 *) (p + 6)) = 0; + *((guint16 *) (p + 6)) = keyframe ? 1 : 0; *((guint32 *) (p + 8)) = GUINT32_TO_LE (payload_size); *((guint32 *) (p + 12)) = GUINT32_TO_LE (GST_MAKE_FOURCC ('M', 'L', '2', '0')); *((guint32 *) (p + 16)) = 0; - *((guint32 *) (p + 20)) = timestamp; + *((guint32 *) (p + 20)) = timestamp / GST_MSECOND; return buf_header; } +static gboolean +gst_mimenc_event (GstPad * pad, GstEvent * event) +{ + GstMimEnc *mimenc = GST_MIMENC (gst_pad_get_parent (pad)); + gboolean ret = TRUE; + gboolean forward = TRUE; + + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time; + gboolean update; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, + &format, &start, &stop, &time); + + /* we need time for now */ + if (format != GST_FORMAT_TIME) + goto newseg_wrong_format; + + GST_DEBUG_OBJECT (mimenc, + "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT + ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, + update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), + GST_TIME_ARGS (time)); + + /* now configure the values, we need these to time the release of the + * buffers on the srcpad. */ + GST_OBJECT_LOCK (mimenc); + gst_segment_set_newsegment_full (&mimenc->segment, update, + rate, arate, format, start, stop, time); + GST_OBJECT_UNLOCK (mimenc); + forward = FALSE; + break; + + } + break; + case GST_EVENT_FLUSH_STOP: + GST_OBJECT_LOCK (mimenc); + gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); + mimenc->need_newsegment = TRUE; + GST_OBJECT_UNLOCK (mimenc); + break; + default: + break; + } + + if (forward) + ret = gst_pad_push_event (mimenc->srcpad, event); + else + gst_event_unref (event); + +done: + gst_object_unref (mimenc); + + return ret; + +newseg_wrong_format: + { + GST_DEBUG_OBJECT (mimenc, "received non TIME newsegment"); + gst_event_unref (event); + ret = FALSE; + goto done; + } +} + +static void +paused_mode_task (gpointer data) +{ + GstMimEnc *mimenc = GST_MIMENC (data); + GstClockTime now; + GstClockTimeDiff diff; + GstFlowReturn ret; + + if (!GST_ELEMENT_CLOCK (mimenc)) { + GST_ERROR_OBJECT (mimenc, "Element has no clock"); + gst_pad_pause_task (mimenc->srcpad); + return; + } + + GST_OBJECT_LOCK (mimenc); + + if (mimenc->stop_paused_mode) { + GST_OBJECT_UNLOCK (mimenc); + goto stop_task; + } + + now = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc)); + + diff = now - GST_ELEMENT_CAST (mimenc)->base_time - mimenc->last_buffer; + if (diff < 0) + diff = 0; + + if (diff > 3.95 * GST_SECOND) { + GstBuffer *buffer = gst_mimenc_create_tcp_header (mimenc, 0, + mimenc->last_buffer + 4 * GST_SECOND, FALSE, TRUE); + GstEvent *event = NULL; + + mimenc->last_buffer += 4 * GST_SECOND; + + if (mimenc->need_newsegment) { + event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); + mimenc->need_newsegment = FALSE; + } + + GST_OBJECT_UNLOCK (mimenc); + GST_LOG_OBJECT (mimenc, "Haven't had an incoming buffer in 4 seconds," + " sending out a pause frame"); + + if (event) { + if (!gst_pad_push_event (mimenc->srcpad, event)) { + GST_ERROR_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); + gst_buffer_unref (buffer); + goto stop_task; + } + } + ret = gst_pad_push (mimenc->srcpad, buffer); + if (ret < 0) { + GST_WARNING_OBJECT (mimenc, "Error pushing paused header: %s", + gst_flow_get_name (ret)); + goto stop_task; + } + } else { + GstClockTime next_stop; + GstClockID id; + + next_stop = now + (4 * GST_SECOND - MIN (diff, 4 * GST_SECOND)); + + id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (mimenc), next_stop); + + if (mimenc->stop_paused_mode) { + GST_OBJECT_UNLOCK (mimenc); + goto stop_task; + } + + mimenc->clock_id = id; + GST_OBJECT_UNLOCK (mimenc); + + gst_clock_id_wait (id, NULL); + + GST_OBJECT_LOCK (mimenc); + mimenc->clock_id = NULL; + GST_OBJECT_UNLOCK (mimenc); + } + return; + +stop_task: + + gst_pad_pause_task (mimenc->srcpad); +} + static GstStateChangeReturn gst_mimenc_change_state (GstElement * element, GstStateChange transition) { - GstMimEnc *mimenc; + GstMimEnc *mimenc = GST_MIMENC (element); + GstStateChangeReturn ret; + gboolean paused_mode; switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: - mimenc = GST_MIMENC (element); GST_OBJECT_LOCK (element); if (mimenc->enc != NULL) { mimic_close (mimenc->enc); @@ -322,9 +573,51 @@ gst_mimenc_change_state (GstElement * element, GstStateChange transition) GST_OBJECT_UNLOCK (element); break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_OBJECT_LOCK (mimenc); + gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); + mimenc->last_buffer = GST_CLOCK_TIME_NONE; + mimenc->need_newsegment = TRUE; + GST_OBJECT_UNLOCK (mimenc); + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_OBJECT_LOCK (mimenc); + if (mimenc->clock_id) + gst_clock_id_unschedule (mimenc->clock_id); + mimenc->stop_paused_mode = TRUE; + GST_OBJECT_UNLOCK (mimenc); + + gst_pad_pause_task (mimenc->srcpad); + + break; default: break; } - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_OBJECT_LOCK (mimenc); + mimenc->stop_paused_mode = FALSE; + if (mimenc->last_buffer == GST_CLOCK_TIME_NONE) + mimenc->last_buffer = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc)) + - GST_ELEMENT_CAST (mimenc)->base_time; + paused_mode = mimenc->paused_mode; + GST_OBJECT_UNLOCK (mimenc); + if (paused_mode) { + if (!gst_pad_start_task (mimenc->srcpad, paused_mode_task, mimenc)) { + ret = GST_STATE_CHANGE_FAILURE; + GST_ERROR_OBJECT (mimenc, "Can not start task"); + } + } + break; + default: + break; + } + + return ret; } diff --git a/ext/mimic/gstmimenc.h b/ext/mimic/gstmimenc.h index c21d714f..89cff46e 100644 --- a/ext/mimic/gstmimenc.h +++ b/ext/mimic/gstmimenc.h @@ -54,6 +54,13 @@ struct _GstMimEnc gint buffer_size; guint32 frames; guint16 height, width; + + gboolean paused_mode; + GstSegment segment; + gboolean need_newsegment; + GstClockTime last_buffer; + GstClockID clock_id; + gboolean stop_paused_mode; }; struct _GstMimEncClass diff --git a/gst-libs/gst/video/Makefile.am b/gst-libs/gst/video/Makefile.am index 6836a058..ab85d00f 100644 --- a/gst-libs/gst/video/Makefile.am +++ b/gst-libs/gst/video/Makefile.am @@ -19,6 +19,6 @@ libgstbasevideo_@GST_MAJORMINOR@include_HEADERS = \ gstbasevideoparse.h libgstbasevideo_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -DGST_USE_UNSTABLE_API -libgstbasevideo_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) +libgstbasevideo_@GST_MAJORMINOR@_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-@GST_MAJORMINOR@ libgstbasevideo_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) diff --git a/gst/mpegdemux/gstmpegdesc.h b/gst/mpegdemux/gstmpegdesc.h index 84b40009..71b74aa2 100644 --- a/gst/mpegdemux/gstmpegdesc.h +++ b/gst/mpegdemux/gstmpegdesc.h @@ -78,6 +78,7 @@ #define DESC_DIRAC_TC_PRIVATE 0xAC /* DVB tags */ +#define DESC_DVB_CAROUSEL_IDENTIFIER 0x13 #define DESC_DVB_NETWORK_NAME 0x40 #define DESC_DVB_SERVICE_LIST 0x41 #define DESC_DVB_STUFFING 0x42 @@ -302,6 +303,22 @@ #define DESC_DVB_CABLE_DELIVERY_SYSTEM_symbol_rate(desc) (desc + 9) #define DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_inner(desc) (desc[12] & 0x0F) +/* DVB Data Broadcast Descriptor */ +#define DESC_DVB_DATA_BROADCAST_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2)) +#define DESC_DVB_DATA_BROADCAST_component_tag(desc) (desc[4]) +#define DESC_DVB_DATA_BROADCAST_selector_length(desc) (desc[5]) +#define DESC_DVB_DATA_BROADCAST_selector(desc) (desc + 6) +#define DESC_DVB_DATA_BROADCAST_iso639_language_code(desc) (desc + 6 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) +#define DESC_DVB_DATA_BROADCAST_text_length(desc) (desc + 9 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) +#define DESC_DVB_DATA_BROADCAST_text(desc) (desc + 10 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) + +/* DVB Data Broadcast Id Descriptor */ +#define DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2)) +#define DESC_DVB_DATA_BROADCAST_ID_id_selector_byte(desc) (desc + 4) + +/* DVB Carousel Identifier Descriptor */ +#define DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id(desc) (GST_READ_UINT32_BE((desc) + 2)) + typedef struct { guint n_desc; guint8 data_length; diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c index c9fc325f..5ed71f0c 100644 --- a/gst/mpegdemux/mpegtspacketizer.c +++ b/gst/mpegdemux/mpegtspacketizer.c @@ -507,10 +507,48 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer * packetizer, GstMPEGDescriptor *desc = gst_mpeg_descriptor_parse (data, stream_info_length); if (desc != NULL) { + guint8 *desc_data; if (gst_mpeg_descriptor_find (desc, DESC_DVB_AC3)) { gst_structure_set (stream_info, "has-ac3", G_TYPE_BOOLEAN, TRUE, NULL); } + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_DATA_BROADCAST_ID); + if (desc_data) { + guint16 data_broadcast_id; + data_broadcast_id = + DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id (desc_data); + gst_structure_set (stream_info, "data-broadcast-id", G_TYPE_UINT, + data_broadcast_id, NULL); + } + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_DATA_BROADCAST); + if (desc_data) { + GstStructure *databroadcast_info; + guint16 data_broadcast_id; + guint8 component_tag; + data_broadcast_id = + DESC_DVB_DATA_BROADCAST_data_broadcast_id (desc_data); + component_tag = DESC_DVB_DATA_BROADCAST_component_tag (desc_data); + databroadcast_info = gst_structure_new ("data-broadcast", "id", + G_TYPE_UINT, data_broadcast_id, "component-tag", component_tag, + NULL); + gst_structure_set (stream_info, "data-broadcast", GST_TYPE_STRUCTURE, + databroadcast_info, NULL); + } + desc_data = + gst_mpeg_descriptor_find (desc, DESC_DVB_CAROUSEL_IDENTIFIER); + if (desc_data) { + guint32 carousel_id; + carousel_id = DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id (desc_data); + gst_structure_set (stream_info, "carousel-id", G_TYPE_UINT, + carousel_id, NULL); + } + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_STREAM_IDENTIFIER); + if (desc_data) { + guint8 component_tag; + component_tag = DESC_DVB_STREAM_IDENTIFIER_component_tag (desc_data); + gst_structure_set (stream_info, "component-tag", G_TYPE_UINT, + component_tag, NULL); + } gst_mpeg_descriptor_free (desc); } @@ -1874,9 +1912,6 @@ mpegts_packetizer_remove_stream (MpegTSPacketizer * packetizer, gint16 pid) GST_INFO ("Removing stream for PID %d", pid); g_hash_table_remove (packetizer->streams, GINT_TO_POINTER ((gint) pid)); - - g_object_unref (stream->section_adapter); - g_free (stream); } } diff --git a/gst/shapewipe/gstshapewipe.c b/gst/shapewipe/gstshapewipe.c index 655cfc50..6b209d0d 100644 --- a/gst/shapewipe/gstshapewipe.c +++ b/gst/shapewipe/gstshapewipe.c @@ -96,7 +96,8 @@ static GstStaticPadTemplate video_sink_pad_template = GST_STATIC_PAD_TEMPLATE ("video_sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB)); + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB " ; " + GST_VIDEO_CAPS_BGRA)); static GstStaticPadTemplate mask_sink_pad_template = GST_STATIC_PAD_TEMPLATE ("mask_sink", @@ -113,7 +114,8 @@ static GstStaticPadTemplate mask_sink_pad_template = static GstStaticPadTemplate src_pad_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB)); + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB " ; " + GST_VIDEO_CAPS_BGRA)); GST_DEBUG_CATEGORY_STATIC (gst_shape_wipe_debug); #define GST_CAT_DEFAULT gst_shape_wipe_debug @@ -808,9 +810,9 @@ gst_shape_wipe_blend_ayuv_##depth (GstShapeWipe * self, GstBuffer * inbuf, \ CREATE_AYUV_FUNCTIONS (16, 65536.0f); CREATE_AYUV_FUNCTIONS (8, 256.0f); -#define CREATE_ARGB_FUNCTIONS(depth, scale) \ +#define CREATE_ARGB_FUNCTIONS(depth, name, scale, a, r, g, b) \ static GstFlowReturn \ -gst_shape_wipe_blend_argb_##depth (GstShapeWipe * self, GstBuffer * inbuf, \ +gst_shape_wipe_blend_##name##_##depth (GstShapeWipe * self, GstBuffer * inbuf, \ GstBuffer * maskbuf, GstBuffer * outbuf) \ { \ const guint##depth *mask = (const guint##depth *) GST_BUFFER_DATA (maskbuf); \ @@ -838,22 +840,22 @@ gst_shape_wipe_blend_argb_##depth (GstShapeWipe * self, GstBuffer * inbuf, \ gfloat in = *mask / scale; \ \ if (in < low) { \ - output[0] = 0x00; /* A */ \ - output[1] = 0x00; /* R */ \ - output[2] = 0x00; /* G */ \ - output[3] = 0x00; /* B */ \ + output[a] = 0x00; /* A */ \ + output[r] = 0x00; /* R */ \ + output[g] = 0x00; /* G */ \ + output[b] = 0x00; /* B */ \ } else if (in >= high) { \ - output[0] = 0xff; /* A */ \ - output[1] = input[1]; /* R */ \ - output[2] = input[2]; /* G */ \ - output[3] = input[3]; /* B */ \ + output[a] = 0xff; /* A */ \ + output[r] = input[r]; /* R */ \ + output[g] = input[g]; /* G */ \ + output[b] = input[b]; /* B */ \ } else { \ gfloat val = 255.0f * ((in - low) / (high - low)); \ \ - output[0] = CLAMP (val, 0, 255); /* A */ \ - output[1] = input[1]; /* R */ \ - output[2] = input[2]; /* G */ \ - output[3] = input[3]; /* B */ \ + output[a] = CLAMP (val, 0, 255); /* A */ \ + output[r] = input[r]; /* R */ \ + output[g] = input[g]; /* G */ \ + output[b] = input[b]; /* B */ \ } \ \ mask++; \ @@ -866,8 +868,11 @@ gst_shape_wipe_blend_argb_##depth (GstShapeWipe * self, GstBuffer * inbuf, \ return GST_FLOW_OK; \ } -CREATE_ARGB_FUNCTIONS (16, 65536.0f); -CREATE_ARGB_FUNCTIONS (8, 256.0f); +CREATE_ARGB_FUNCTIONS (16, argb, 65536.0f, 0, 1, 2, 3); +CREATE_ARGB_FUNCTIONS (8, argb, 256.0f, 0, 1, 2, 3); + +CREATE_ARGB_FUNCTIONS (16, bgra, 65536.0f, 3, 2, 1, 0); +CREATE_ARGB_FUNCTIONS (8, bgra, 256.0f, 3, 2, 1, 0); static GstFlowReturn gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) @@ -937,6 +942,10 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) ret = gst_shape_wipe_blend_argb_16 (self, buffer, mask, outbuf); else if (self->fmt == GST_VIDEO_FORMAT_ARGB) ret = gst_shape_wipe_blend_argb_8 (self, buffer, mask, outbuf); + else if (self->fmt == GST_VIDEO_FORMAT_BGRA && self->mask_bpp == 16) + ret = gst_shape_wipe_blend_bgra_16 (self, buffer, mask, outbuf); + else if (self->fmt == GST_VIDEO_FORMAT_BGRA) + ret = gst_shape_wipe_blend_bgra_8 (self, buffer, mask, outbuf); else g_assert_not_reached (); |