From 8ef8daf4dbdbab23ff49757a6223c3a9bfba11d3 Mon Sep 17 00:00:00 2001 From: Vincent Genieux Date: Sun, 3 May 2009 17:21:22 +0100 Subject: mpegtsparse: make safe changing the program-numbers property dynamically Fixes #569437. --- gst/mpegdemux/mpegtsparse.c | 48 ++++++++++++++++++++++----------------------- gst/mpegdemux/mpegtsparse.h | 1 + 2 files changed, 25 insertions(+), 24 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index 3a2d647d..de4de35f 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -266,9 +266,11 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass) gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); parse->disposed = FALSE; + parse->need_sync_program_pads = FALSE; parse->packetizer = mpegts_packetizer_new (); parse->program_numbers = g_strdup (""); parse->pads_to_add = NULL; + parse->pads_to_remove = NULL; parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_program); parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal); @@ -422,22 +424,30 @@ mpegts_parse_remove_program (MpegTSParse * parse, gint program_number) } static void -mpegts_parse_sync_program_pads (MpegTSParse * parse, - GList * to_add, GList * to_remove) +mpegts_parse_sync_program_pads (MpegTSParse * parse) { GList *walk; - for (walk = to_remove; walk; walk = walk->next) + GST_INFO_OBJECT (parse, "begin sync pads"); + for (walk = parse->pads_to_remove; walk; walk = walk->next) gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); - for (walk = to_add; walk; walk = walk->next) + for (walk = parse->pads_to_add; walk; walk = walk->next) gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); - if (to_add) - g_list_free (to_add); + if (parse->pads_to_add) + g_list_free (parse->pads_to_add); + + if (parse->pads_to_remove) + g_list_free (parse->pads_to_remove); + + GST_OBJECT_LOCK (parse); + parse->pads_to_remove = NULL; + parse->pads_to_add = NULL; + parse->need_sync_program_pads = FALSE; + GST_OBJECT_UNLOCK (parse); - if (to_remove) - g_list_free (to_remove); + GST_INFO_OBJECT (parse, "end sync pads"); } @@ -493,9 +503,6 @@ static void mpegts_parse_reset_selected_programs (MpegTSParse * parse, gchar * program_numbers) { - GList *pads_to_add = NULL; - GList *pads_to_remove = NULL; - GST_OBJECT_LOCK (parse); if (parse->program_numbers) g_free (parse->program_numbers); @@ -526,13 +533,9 @@ mpegts_parse_reset_selected_programs (MpegTSParse * parse, g_hash_table_foreach (parse->programs, foreach_program_activate_or_deactivate, parse); - pads_to_add = parse->pads_to_add; - parse->pads_to_add = NULL; - pads_to_remove = parse->pads_to_remove; - parse->pads_to_remove = NULL; + if (parse->pads_to_remove || parse->pads_to_add) + parse->need_sync_program_pads = TRUE; GST_OBJECT_UNLOCK (parse); - - mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove); } static void @@ -850,8 +853,6 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) guint pid; MpegTSParseProgram *program; gint i; - GList *pads_to_add = NULL; - GList *pads_to_remove = NULL; const GValue *programs; gchar *dbg; @@ -942,13 +943,9 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) gst_structure_free (old_pat); } - pads_to_add = parse->pads_to_add; - parse->pads_to_add = NULL; - pads_to_remove = parse->pads_to_remove; - parse->pads_to_remove = NULL; GST_OBJECT_UNLOCK (parse); - mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove); + mpegts_parse_sync_program_pads (parse); } static void @@ -1226,6 +1223,9 @@ mpegts_parse_chain (GstPad * pad, GstBuffer * buf) mpegts_packetizer_clear_packet (parse->packetizer, &packet); } + if (parse->need_sync_program_pads) + mpegts_parse_sync_program_pads (parse); + gst_object_unref (parse); return res; } diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h index 34a78634..d4dc5b1e 100644 --- a/gst/mpegdemux/mpegtsparse.h +++ b/gst/mpegdemux/mpegtsparse.h @@ -61,6 +61,7 @@ struct _MpegTSParse { MpegTSPacketizer *packetizer; GHashTable *psi_pids; gboolean disposed; + gboolean need_sync_program_pads; }; struct _MpegTSParseClass { -- cgit v1.2.1 From e41401e3174b80b2e2ce4febf99f15e766dfc5c6 Mon Sep 17 00:00:00 2001 From: Vincent Genieux Date: Sun, 3 May 2009 17:42:44 +0100 Subject: mpegtsparse: Ignore subtable extension when parsing PAT Fixes #569673. --- gst/mpegdemux/mpegtspacketizer.c | 19 ++++++++++++++++++- gst/mpegdemux/mpegtspacketizer.h | 2 ++ gst/mpegdemux/mpegtsparse.c | 7 +++---- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c index 1abbf1fe..b986fa60 100644 --- a/gst/mpegdemux/mpegtspacketizer.c +++ b/gst/mpegdemux/mpegtspacketizer.c @@ -241,7 +241,8 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer * packetizer, data = GST_BUFFER_DATA (section->buffer); section->table_id = *data++; - if ((data[0] & 0x80) == 0) + /* if table_id is 0 (pat) then ignore the subtable extension */ + if ((data[0] & 0x80) == 0 || section->table_id == 0) section->subtable_extension = 0; else section->subtable_extension = GST_READ_UINT16_BE (data + 2); @@ -1844,6 +1845,22 @@ mpegts_packetizer_clear (MpegTSPacketizer * packetizer) gst_adapter_clear (packetizer->adapter); } +void +mpegts_packetizer_remove_stream (MpegTSPacketizer * packetizer, gint16 pid) +{ + MpegTSPacketizerStream *stream = + (MpegTSPacketizerStream *) g_hash_table_lookup (packetizer->streams, + GINT_TO_POINTER ((gint) pid)); + if (stream) { + 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); + } +} + MpegTSPacketizer * mpegts_packetizer_new () { diff --git a/gst/mpegdemux/mpegtspacketizer.h b/gst/mpegdemux/mpegtspacketizer.h index c54228af..97e15cf2 100644 --- a/gst/mpegdemux/mpegtspacketizer.h +++ b/gst/mpegdemux/mpegtspacketizer.h @@ -116,6 +116,8 @@ gboolean mpegts_packetizer_next_packet (MpegTSPacketizer *packetizer, MpegTSPacketizerPacket *packet); void mpegts_packetizer_clear_packet (MpegTSPacketizer *packetizer, MpegTSPacketizerPacket *packet); +void mpegts_packetizer_remove_stream(MpegTSPacketizer *packetizer, + gint16 pid); gboolean mpegts_packetizer_push_section (MpegTSPacketizer *packetzer, MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section); diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index de4de35f..614da36c 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -350,7 +350,7 @@ mpegts_parse_add_program (MpegTSParse * parse, program->pcr_pid = G_MAXUINT16; program->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_stream); - program->patcount = 1; + program->patcount = 0; program->selected = 0; program->active = FALSE; @@ -890,14 +890,12 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) g_hash_table_insert (parse->psi_pids, GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1)); } - - program->patcount += 1; } else { g_hash_table_insert (parse->psi_pids, GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1)); program = mpegts_parse_add_program (parse, program_number, pid); } - + program->patcount += 1; if (program->selected && !program->active) parse->pads_to_add = g_list_append (parse->pads_to_add, mpegts_parse_activate_program (parse, program)); @@ -938,6 +936,7 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) mpegts_parse_remove_program (parse, program_number); g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid)); + mpegts_packetizer_remove_stream (parse->packetizer, pid); } gst_structure_free (old_pat); -- cgit v1.2.1 From 179f5bb850d0df3841889d88e3ee7ee96cc914aa Mon Sep 17 00:00:00 2001 From: Zaheer Abbas Merali Date: Mon, 4 May 2009 22:09:05 +0100 Subject: mpegtsparse: Remember pids that are meant to be stream pids. Fixes #569781 --- gst/mpegdemux/mpegtsparse.c | 14 ++++++++++++++ gst/mpegdemux/mpegtsparse.h | 1 + 2 files changed, 15 insertions(+) (limited to 'gst') diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index 614da36c..976935f2 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -274,6 +274,7 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass) parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_program); parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal); + parse->pes_pids = g_hash_table_new (g_direct_hash, g_direct_equal); mpegts_parse_reset (parse); } @@ -303,6 +304,7 @@ mpegts_parse_finalize (GObject * object) } g_hash_table_destroy (parse->programs); g_hash_table_destroy (parse->psi_pids); + g_hash_table_destroy (parse->pes_pids); if (G_OBJECT_CLASS (parent_class)->finalize) G_OBJECT_CLASS (parent_class)->finalize (object); @@ -807,6 +809,10 @@ mpegts_parse_is_psi (MpegTSParse * parse, MpegTSPacketizerPacket * packet) if (g_hash_table_lookup (parse->psi_pids, GINT_TO_POINTER ((gint) packet->pid)) != NULL) retval = TRUE; + /* check is it is a pes pid */ + if (g_hash_table_lookup (parse->pes_pids, + GINT_TO_POINTER ((gint) packet->pid)) != NULL) + return FALSE; if (!retval) { if (packet->payload_unit_start_indicator) { table_id = *(packet->data); @@ -979,10 +985,13 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, gst_structure_get_uint (stream, "pid", &pid); gst_structure_get_uint (stream, "stream-type", &stream_type); mpegts_parse_program_remove_stream (parse, program, (guint16) pid); + g_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid)); } /* remove pcr stream */ mpegts_parse_program_remove_stream (parse, program, program->pcr_pid); + g_hash_table_remove (parse->pes_pids, + GINT_TO_POINTER ((gint) program->pcr_pid)); gst_structure_free (program->pmt_info); program->pmt_info = NULL; @@ -999,6 +1008,8 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, program->pmt_pid = pmt_pid; program->pcr_pid = pcr_pid; mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1); + g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pcr_pid), + GINT_TO_POINTER (1)); for (i = 0; i < gst_value_list_get_size (new_streams); ++i) { value = gst_value_list_get_value (new_streams, i); @@ -1008,6 +1019,9 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, gst_structure_get_uint (stream, "stream-type", &stream_type); mpegts_parse_program_add_stream (parse, program, (guint16) pid, (guint8) stream_type); + g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid), + GINT_TO_POINTER ((gint) 1)); + } GST_OBJECT_UNLOCK (parse); diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h index d4dc5b1e..36466b81 100644 --- a/gst/mpegdemux/mpegtsparse.h +++ b/gst/mpegdemux/mpegtsparse.h @@ -60,6 +60,7 @@ struct _MpegTSParse { GstStructure *pat; MpegTSPacketizer *packetizer; GHashTable *psi_pids; + GHashTable *pes_pids; gboolean disposed; gboolean need_sync_program_pads; }; -- cgit v1.2.1 From 46139253bcb1ddc32fc8987c194c40d9c622e993 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 5 May 2009 16:48:37 +0200 Subject: rtpssrcdemux: drop unexpected RTCP packets We usually only get SR packets in our chain function but if an invalid packet contains the SR packet after the RR packet, we must not fail but simply ignore the malformed packet. Fixes #581375 --- gst/rtpmanager/gstrtpssrcdemux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c index 64394c45..b9a279c2 100644 --- a/gst/rtpmanager/gstrtpssrcdemux.c +++ b/gst/rtpmanager/gstrtpssrcdemux.c @@ -483,7 +483,7 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf) NULL); break; default: - goto invalid_rtcp; + goto unexpected_rtcp; } GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc); @@ -511,6 +511,12 @@ invalid_rtcp: gst_buffer_unref (buf); return GST_FLOW_ERROR; } +unexpected_rtcp: + { + GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet"); + gst_buffer_unref (buf); + return GST_FLOW_OK; + } create_failed: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), -- cgit v1.2.1 From 9542d9e2513c0d88a8de65c7585e0d81b7249dda Mon Sep 17 00:00:00 2001 From: Arnout Vandecappelle Date: Tue, 5 May 2009 16:54:39 +0200 Subject: mpeg4videoparse: don't leak the config data Clear the config data when going to READY or when disposed. Fixes #581427 --- gst/mpeg4videoparse/mpeg4videoparse.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gst') diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c index 1efa28be..e0e28d0c 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.c +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -726,6 +726,10 @@ gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse) if (parse->adapter) { gst_adapter_clear (parse->adapter); } + if (parse->config != NULL) { + gst_buffer_unref (parse->config); + parse->config = NULL; + } parse->state = PARSE_NEED_START; parse->have_config = FALSE; @@ -760,6 +764,10 @@ gst_mpeg4vparse_dispose (GObject * object) g_object_unref (parse->adapter); parse->adapter = NULL; } + if (parse->config != NULL) { + gst_buffer_unref (parse->config); + parse->config = NULL; + } GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); } -- cgit v1.2.1 From 67dd3c11f47f1afd3508e3b45a3023ce9612fe67 Mon Sep 17 00:00:00 2001 From: Christian Schaller Date: Thu, 7 May 2009 17:53:42 +0100 Subject: Add ranks to various muxers and encoders in -bad --- gst/flv/gstflvdemux.c | 2 +- gst/mxf/mxf.c | 3 ++- gst/qtmux/gstqtmux.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'gst') diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index f31a22e8..5856e7ac 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -1311,7 +1311,7 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY, gst_flv_demux_get_type ()) || - !gst_element_register (plugin, "flvmux", GST_RANK_NONE, + !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY, gst_flv_mux_get_type ())) return FALSE; diff --git a/gst/mxf/mxf.c b/gst/mxf/mxf.c index c1a0a716..7469317c 100644 --- a/gst/mxf/mxf.c +++ b/gst/mxf/mxf.c @@ -71,7 +71,8 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "mxfdemux", GST_RANK_PRIMARY, GST_TYPE_MXF_DEMUX) || - !gst_element_register (plugin, "mxfmux", GST_RANK_NONE, GST_TYPE_MXF_MUX)) + !gst_element_register (plugin, "mxfmux", GST_RANK_PRIMARY, + GST_TYPE_MXF_MUX)) return FALSE; return TRUE; diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index f3e85f5c..b0df9d71 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -1886,7 +1886,7 @@ gst_qt_mux_register (GstPlugin * plugin) g_type_set_qdata (type, GST_QT_MUX_PARAMS_QDATA, (gpointer) params); g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info); - if (!gst_element_register (plugin, prop->name, GST_RANK_NONE, type)) + if (!gst_element_register (plugin, prop->name, GST_RANK_PRIMARY, type)) return FALSE; i++; -- cgit v1.2.1 From 8c57211bd29c7dc620892eefd3dacb06842d2df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 8 May 2009 15:39:24 +0200 Subject: deinterlace2: Add a disabled mode for passthrough operation Also allow to change the mode in PAUSED and PLAYING by updating the caps if necessary. --- gst/deinterlace2/gstdeinterlace2.c | 30 +++++++++++++++++++----------- gst/deinterlace2/gstdeinterlace2.h | 3 ++- 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'gst') diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c index b293b43e..42a69240 100644 --- a/gst/deinterlace2/gstdeinterlace2.c +++ b/gst/deinterlace2/gstdeinterlace2.c @@ -350,6 +350,7 @@ gst_deinterlace2_modes_get_type (void) static const GEnumValue modes_types[] = { {GST_DEINTERLACE2_MODE_AUTO, "Auto detection", "auto"}, {GST_DEINTERLACE2_MODE_INTERLACED, "Enfore deinterlacing", "interlaced"}, + {GST_DEINTERLACE2_MODE_DISABLED, "Run in passthrough mode", "disabled"}, {0, NULL, NULL}, }; @@ -729,14 +730,17 @@ gst_deinterlace2_set_property (GObject * object, guint prop_id, self = GST_DEINTERLACE2 (object); switch (prop_id) { - case PROP_MODE: - if (GST_STATE (self) >= GST_STATE_PAUSED) { - g_warning ("Setting the 'mode' property is only allowed in " - "states other than PAUSED and PLAYING"); - } else { - self->mode = g_value_get_enum (value); - } + case PROP_MODE:{ + gint oldmode; + + GST_OBJECT_LOCK (self); + oldmode = self->mode; + self->mode = g_value_get_enum (value); + if (self->mode != oldmode && GST_PAD_CAPS (self->srcpad)) + gst_deinterlace2_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad)); + GST_OBJECT_UNLOCK (self); break; + } case PROP_METHOD: gst_deinterlace2_set_method (self, g_value_get_enum (value)); break; @@ -925,7 +929,8 @@ gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf) self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad)); - if (!self->interlaced && self->mode != GST_DEINTERLACE2_MODE_INTERLACED) + if (self->mode == GST_DEINTERLACE2_MODE_DISABLED || (!self->interlaced + && self->mode != GST_DEINTERLACE2_MODE_INTERLACED)) return gst_pad_push (self->srcpad, buf); if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { @@ -1133,7 +1138,8 @@ gst_deinterlace2_getcaps (GstPad * pad) GST_OBJECT_UNLOCK (self); if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) && - self->fields == GST_DEINTERLACE2_ALL) { + self->fields == GST_DEINTERLACE2_ALL + && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { for (len = gst_caps_get_size (ret); len > 0; len--) { GstStructure *s = gst_caps_get_structure (ret, len - 1); const GValue *val; @@ -1269,7 +1275,8 @@ gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps) goto invalid_caps; if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) && - self->fields == GST_DEINTERLACE2_ALL) { + self->fields == GST_DEINTERLACE2_ALL + && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { gint fps_n = self->frame_rate_n, fps_d = self->frame_rate_d; if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad)) @@ -1418,7 +1425,8 @@ gst_deinterlace2_src_query (GstPad * pad, GstQuery * query) switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: - if (self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) { + if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) + && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { GstClockTime min, max; gboolean live; GstPad *peer; diff --git a/gst/deinterlace2/gstdeinterlace2.h b/gst/deinterlace2/gstdeinterlace2.h index de63f54e..7a08d411 100644 --- a/gst/deinterlace2/gstdeinterlace2.h +++ b/gst/deinterlace2/gstdeinterlace2.h @@ -189,7 +189,8 @@ typedef enum typedef enum { GST_DEINTERLACE2_MODE_AUTO, - GST_DEINTERLACE2_MODE_INTERLACED + GST_DEINTERLACE2_MODE_INTERLACED, + GST_DEINTERLACE2_MODE_DISABLED } GstDeinterlace2Mode; struct _GstDeinterlace2 -- cgit v1.2.1 From ff7b54e7da95a401665f8d7ae922155a32edac91 Mon Sep 17 00:00:00 2001 From: Zaheer Merali Date: Fri, 8 May 2009 18:24:28 +0100 Subject: mpegtsdemux: Add initial naive seeking support and fix duration query. Sync from gst-fluendo-mpegdemux and have seeking/duration query improvements in. No support however for wrapped around pcrs etc. but a start nonetheless. Also fix indentation issues. --- gst/mpegdemux/gstmpegtsdemux.c | 272 ++++++++++++++++++++++++++++++++++++----- gst/mpegdemux/gstmpegtsdemux.h | 186 +++++++++++++++------------- 2 files changed, 341 insertions(+), 117 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 4464cdf8..99a499a0 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -34,9 +34,9 @@ * * The Original Code is Fluendo MPEG Demuxer plugin. * - * The Initial Developer of the Original Code is Fluendo, S.L. - * Portions created by Fluendo, S.L. are Copyright (C) 2005 - * Fluendo, S.L. All Rights Reserved. + * The Initial Developer of the Original Code is Fluendo, S.A. + * Portions created by Fluendo, S.L. are Copyright (C) 2005,2006,2007,2008,2009 + * Fluendo, S.A. All Rights Reserved. * * Contributor(s): Wim Taymans */ @@ -126,6 +126,13 @@ enum PROP_M2TS }; +#define GSTTIME_TO_BYTES(time) \ + ((time != -1) ? gst_util_uint64_scale (MAX(0,(gint64) ((time))), \ + demux->bitrate, GST_SECOND) : -1) +#define BYTES_TO_GSTTIME(bytes) \ + ((bytes != -1) ? (gst_util_uint64_scale (bytes, GST_SECOND, \ + demux->bitrate)) : -1) + #define VIDEO_CAPS \ GST_STATIC_CAPS (\ "video/mpeg, " \ @@ -189,6 +196,7 @@ static void gst_mpegts_demux_get_property (GObject * object, guint prop_id, static gboolean gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID); static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer); static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps); @@ -327,7 +335,12 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux) demux->m2ts_mode = FALSE; demux->sync_lut = NULL; demux->sync_lut_len = 0; - + demux->bitrate = -1; + demux->num_packets = 0; + demux->pcr[0] = -1; + demux->pcr[1] = -1; + demux->cache_duration = GST_CLOCK_TIME_NONE; + demux->base_pts = GST_CLOCK_TIME_NONE; #ifdef USE_LIBOIL oil_init (); #endif @@ -668,6 +681,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, gst_caps_unref (caps); gst_pad_set_query_function (stream->pad, GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query)); + gst_pad_set_event_function (stream->pad, + GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_event)); g_free (name); return TRUE; @@ -730,7 +745,7 @@ gst_mpegts_demux_send_new_segment (GstMpegTSDemux * demux, } base_PCR = PCR_stream->base_PCR; - time = MPEGTIME_TO_GSTTIME (base_PCR); + demux->base_pts = time = MPEGTIME_TO_GSTTIME (base_PCR); GST_DEBUG_OBJECT (demux, "segment PTS to (%" G_GUINT64_FORMAT ") time: %" G_GUINT64_FORMAT, base_PCR, time); @@ -1680,7 +1695,13 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, "valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr, stream->last_PCR_difference); if (valid_pcr) { - + if (demux->pcr[0] == -1) { + demux->pcr[0] = pcr; + demux->num_packets = 0; + } /* Considering a difference of 1 sec ie 90000 ticks */ + else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { + demux->pcr[1] = pcr; + } stream->last_PCR = pcr; if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) { @@ -1955,15 +1976,20 @@ gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID) } static FORCE_INLINE GstFlowReturn -gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream) +gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream, gboolean discard) { GstFlowReturn ret = GST_FLOW_OK; if (stream->pes_buffer) { - GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used; - ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer); - if (ret == GST_FLOW_LOST_SYNC) + if (discard) { + gst_buffer_unref (stream->pes_buffer); stream->pes_buffer_in_sync = FALSE; + } else { + GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used; + ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer); + if (ret == GST_FLOW_LOST_SYNC) + stream->pes_buffer_in_sync = FALSE; + } stream->pes_buffer = NULL; } return ret; @@ -1985,7 +2011,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream, if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1)) stream->pes_buffer_size <<= 1; - ret = gst_mpegts_stream_pes_buffer_flush (stream); + ret = gst_mpegts_stream_pes_buffer_flush (stream, FALSE); if (ret == GST_FLOW_LOST_SYNC) goto done; } @@ -2010,7 +2036,7 @@ done: } static FORCE_INLINE GstFlowReturn -gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux) +gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux, gboolean discard) { gint i; GstFlowReturn ret = GST_FLOW_OK; @@ -2018,7 +2044,7 @@ gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux) for (i = 0; i < MPEGTS_MAX_PID + 1; i++) { GstMpegTSStream *stream = demux->streams[i]; if (stream && stream->pad) { - gst_mpegts_stream_pes_buffer_flush (stream); + gst_mpegts_stream_pes_buffer_flush (stream, discard); stream->pes_buffer_in_sync = FALSE; } } @@ -2233,7 +2259,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, "bytes of %u bytes in the PES buffer", PID, stream->pes_buffer_used, stream->pes_buffer_size); /* Flush buffered PES data */ - gst_mpegts_stream_pes_buffer_flush (stream); + gst_mpegts_stream_pes_buffer_flush (stream, FALSE); gst_pes_filter_drain (&stream->filter); /* Resize the buffer to half if no overflow detected and * had been used less than half of it */ @@ -2319,11 +2345,137 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, ret = gst_mpegts_demux_parse_stream (demux, stream, data, MPEGTS_NORMAL_TS_PACKETSIZE - 1); + if (demux->pcr[1] != -1 && demux->bitrate == -1) { + GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GINT64_FORMAT + ", demux->num_packets %" G_GUINT64_FORMAT, + demux->pcr[1] - demux->pcr[0], demux->num_packets); + demux->bitrate = gst_util_uint64_scale (GST_SECOND, + MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets, + MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])); + GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT + " bytes per second", demux->bitrate); + } + demux->num_packets++; return ret; /* ERRORS */ } +static gboolean +gst_mpegts_demux_handle_seek_push (GstMpegTSDemux * demux, GstEvent * event) +{ + gboolean res = FALSE; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop, bstart, bstop; + GstEvent *bevent; + + gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, + &stop_type, &stop); + + GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop)); + + if (format == GST_FORMAT_BYTES) { + GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format); + goto beach; + } + + GST_DEBUG_OBJECT (demux, "seek - trying directly upstream first"); + + /* first try original format seek */ + res = gst_pad_push_event (demux->sinkpad, gst_event_ref (event)); + if (res == TRUE) + goto beach; + GST_DEBUG_OBJECT (demux, "seek - no upstream"); + + if (format != GST_FORMAT_TIME) { + /* From here down, we only support time based seeks */ + GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format); + goto beach; + } + + /* We need to convert to byte based seek and we need a scr_rate for that. */ + if (demux->bitrate == -1) { + GST_DEBUG_OBJECT (demux, "seek not possible, no bitrate"); + goto beach; + } + + GST_DEBUG_OBJECT (demux, "try with bitrate"); + + bstart = GSTTIME_TO_BYTES (start); + bstop = GSTTIME_TO_BYTES (stop); + + GST_DEBUG_OBJECT (demux, "in bytes bstart %" G_GINT64_FORMAT " bstop %" + G_GINT64_FORMAT, bstart, bstop); + bevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, + bstart, stop_type, bstop); + + res = gst_pad_push_event (demux->sinkpad, bevent); + +beach: + gst_event_unref (event); + return res; +} + +static gboolean +gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event) +{ + GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad)); + gboolean res = FALSE; + + GST_DEBUG_OBJECT (demux, "got event %s", + gst_event_type_get_name (GST_EVENT_TYPE (event))); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + res = gst_mpegts_demux_handle_seek_push (demux, event); + break; + default: + res = gst_pad_push_event (demux->sinkpad, event); + break; + } + + gst_object_unref (demux); + + return res; +} + +static void +gst_mpegts_demux_flush (GstMpegTSDemux * demux, gboolean discard) +{ + GstMpegTSStream *PCR_stream; + GstMpegTSStream *PMT_stream; + + GST_DEBUG_OBJECT (demux, "flushing MPEG TS demuxer (discard %d)", discard); + + /* Start by flushing internal buffers */ + gst_mpegts_demux_pes_buffer_flush (demux, discard); + + /* Clear adapter */ + gst_adapter_clear (demux->adapter); + + /* Try resetting the last_PCR value as we will have a discont */ + if (demux->current_PMT == 0) + goto beach; + + PMT_stream = demux->streams[demux->current_PMT]; + if (PMT_stream == NULL) + goto beach; + + PCR_stream = demux->streams[PMT_stream->PMT.PCR_PID]; + if (PCR_stream == NULL) + goto beach; + + PCR_stream->last_PCR = -1; + +beach: + return; +} + static gboolean gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event) { @@ -2347,7 +2499,7 @@ static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) { GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad)); - gboolean res; + gboolean res = FALSE; GST_DEBUG_OBJECT (demux, "got event %s", gst_event_type_get_name (GST_EVENT_TYPE (event))); @@ -2358,11 +2510,11 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) break; case GST_EVENT_FLUSH_STOP: gst_adapter_clear (demux->adapter); + gst_mpegts_demux_flush (demux, TRUE); res = gst_mpegts_demux_send_event (demux, event); break; case GST_EVENT_EOS: - /* Flush buffered PES data */ - gst_mpegts_demux_pes_buffer_flush (demux); + gst_mpegts_demux_flush (demux, FALSE); /* Send the EOS event on each stream */ if (!(res = gst_mpegts_demux_send_event (demux, event))) { /* we have no streams */ @@ -2371,15 +2523,46 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) } break; case GST_EVENT_NEWSEGMENT: - res = gst_mpegts_demux_send_event (demux, event); + { + gboolean update; + gdouble rate; + GstFormat format; + gint64 start, stop, time; + + gst_event_parse_new_segment (event, &update, &rate, &format, + &start, &stop, &time); + + gst_event_unref (event); + GST_INFO_OBJECT (demux, "received new segment: rate %g " + "format %d, start: %" G_GINT64_FORMAT ", stop: %" G_GINT64_FORMAT + ", time: %" G_GINT64_FORMAT, rate, format, start, stop, time); + if (format == GST_FORMAT_BYTES && demux->bitrate != -1) { + gint64 tstart = 0, tstop = 0, pos = 0; + + if (demux->base_pts != GST_CLOCK_TIME_NONE) { + tstart = tstop = demux->base_pts; + } + tstart += BYTES_TO_GSTTIME (start); + tstop += BYTES_TO_GSTTIME (stop); + pos = BYTES_TO_GSTTIME (time); + + event = gst_event_new_new_segment (update, rate, + GST_FORMAT_TIME, tstart, tstop, pos); + GST_DEBUG_OBJECT (demux, "pushing time newsegment from %" + GST_TIME_FORMAT " to %" GST_TIME_FORMAT " pos %" GST_TIME_FORMAT, + GST_TIME_ARGS (tstart), GST_TIME_ARGS (tstop), GST_TIME_ARGS (pos)); + + res = gst_mpegts_demux_send_event (demux, event); + } break; + } default: res = gst_mpegts_demux_send_event (demux, event); break; } gst_object_unref (demux); - return TRUE; + return res; } static gboolean @@ -2455,21 +2638,54 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query) case GST_QUERY_DURATION: { GstFormat format; - gint64 duration; + GstPad *peer; - gst_query_parse_duration (query, &format, &duration); + gst_query_parse_duration (query, &format, NULL); - if (format == GST_FORMAT_BYTES) { - res = FALSE; - } else { - res = gst_pad_query_default (pad, query); + /* Try query upstream first */ + peer = gst_pad_get_peer (demux->sinkpad); + if (peer) { + res = gst_pad_query (peer, query); + /* Try doing something with that query if it failed */ + if (!res && format == GST_FORMAT_TIME && demux->bitrate != -1) { + /* Try using cache first */ + if (GST_CLOCK_TIME_IS_VALID (demux->cache_duration)) { + GST_LOG_OBJECT (demux, "replying duration query from cache %" + GST_TIME_FORMAT, GST_TIME_ARGS (demux->cache_duration)); + gst_query_set_duration (query, GST_FORMAT_TIME, + demux->cache_duration); + res = TRUE; + } else { /* Query upstream and approximate */ + GstQuery *bquery = gst_query_new_duration (GST_FORMAT_BYTES); + gint64 duration = 0; + + /* Query peer for duration in bytes */ + res = gst_pad_query (peer, bquery); + if (res) { + /* Convert to time format */ + gst_query_parse_duration (bquery, &format, &duration); + GST_DEBUG_OBJECT (demux, "query on peer pad reported bytes %" + G_GUINT64_FORMAT, duration); + demux->cache_duration = BYTES_TO_GSTTIME (duration); + GST_DEBUG_OBJECT (demux, "converted to time %" GST_TIME_FORMAT, + GST_TIME_ARGS (demux->cache_duration)); + gst_query_set_duration (query, GST_FORMAT_TIME, + demux->cache_duration); + } + gst_query_unref (bquery); + } + } else { + GST_WARNING_OBJECT (demux, "unsupported query format or no bitrate " + "yet to approximate duration from bytes"); + } + gst_object_unref (peer); } - break; } default: res = gst_pad_query_default (pad, query); } + gst_object_unref (demux); return res; } @@ -2554,9 +2770,7 @@ gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer) guint sync_count; if (GST_BUFFER_IS_DISCONT (buffer)) { - /* Flush buffered PES data */ - gst_mpegts_demux_pes_buffer_flush (demux); - gst_adapter_clear (demux->adapter); + gst_mpegts_demux_flush (demux, FALSE); } /* first push the new buffer into the adapter */ gst_adapter_push (demux->adapter, buffer); diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index 8a4ca3d2..c4a907a5 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -34,9 +34,9 @@ * * The Original Code is Fluendo MPEG Demuxer plugin. * - * The Initial Developer of the Original Code is Fluendo, S.L. - * Portions created by Fluendo, S.L. are Copyright (C) 2005 - * Fluendo, S.L. All Rights Reserved. + * The Initial Developer of the Original Code is Fluendo, S.A. + * Portions created by Fluendo, S.A. are Copyright (C) 2005,2006,2007,2008,2009 + * Fluendo, S.A. All Rights Reserved. * * Contributor(s): Wim Taymans */ @@ -52,18 +52,14 @@ #include "gstsectionfilter.h" G_BEGIN_DECLS - #define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024 #define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024 - #define MPEGTS_MAX_PID 0x1fff #define MPEGTS_NORMAL_TS_PACKETSIZE 188 #define MPEGTS_M2TS_TS_PACKETSIZE 192 - #define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \ (((data)[1] & 0x80) == 0x00) && \ (((data)[3] & 0x10) == 0x10)) - #define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type()) #define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux)) @@ -75,7 +71,6 @@ G_BEGIN_DECLS GST_TYPE_MPEGTS_DEMUX)) #define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\ GST_TYPE_MPEGTS_DEMUX)) - typedef struct _GstMpegTSStream GstMpegTSStream; typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry; typedef struct _GstMpegTSPMT GstMpegTSPMT; @@ -84,142 +79,157 @@ typedef struct _GstMpegTSPAT GstMpegTSPAT; typedef struct _GstMpegTSDemux GstMpegTSDemux; typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass; -struct _GstMpegTSPMTEntry { - guint16 PID; +struct _GstMpegTSPMTEntry +{ + guint16 PID; }; -struct _GstMpegTSPMT { - guint16 program_number; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; - guint16 PCR_PID; - guint16 program_info_length; - GstMPEGDescriptor * program_info; - - GArray * entries; +struct _GstMpegTSPMT +{ + guint16 program_number; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; + guint16 PCR_PID; + guint16 program_info_length; + GstMPEGDescriptor *program_info; + + GArray *entries; }; -struct _GstMpegTSPATEntry { - guint16 program_number; - guint16 PID; +struct _GstMpegTSPATEntry +{ + guint16 program_number; + guint16 PID; }; -struct _GstMpegTSPAT { - guint16 transport_stream_id; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; +struct _GstMpegTSPAT +{ + guint16 transport_stream_id; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; - GArray * entries; + GArray *entries; }; -typedef enum _MpegTsStreamFlags { +typedef enum _MpegTsStreamFlags +{ MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01, MPEGTS_STREAM_FLAG_PMT_VALID = 0x02, - MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 + MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 } MpegTsStreamFlags; /* Information associated to a single MPEG stream. */ -struct _GstMpegTSStream { - GstMpegTSDemux * demux; +struct _GstMpegTSStream +{ + GstMpegTSDemux *demux; - MpegTsStreamFlags flags; + MpegTsStreamFlags flags; /* PID and type */ - guint16 PID; - guint8 PID_type; + guint16 PID; + guint8 PID_type; /* adaptation_field data */ - guint64 last_PCR; - guint64 base_PCR; - guint64 last_OPCR; - guint64 last_PCR_difference; - gboolean discont_PCR; - GstClockTimeDiff discont_difference; + guint64 last_PCR; + guint64 base_PCR; + guint64 last_OPCR; + guint64 last_PCR_difference; + gboolean discont_PCR; + GstClockTimeDiff discont_difference; /* for PAT streams */ - GstMpegTSPAT PAT; + GstMpegTSPAT PAT; /* for PMT streams */ - GstMpegTSPMT PMT; + GstMpegTSPMT PMT; /* for CA streams */ /* for PAT, PMT, CA and private streams */ - GstSectionFilter section_filter; + GstSectionFilter section_filter; /* for PES streams */ - guint8 id; - guint8 stream_type; - GstBuffer * pes_buffer; - guint32 pes_buffer_size; - guint32 pes_buffer_used; - gboolean pes_buffer_overflow; - gboolean pes_buffer_in_sync; - GstPESFilter filter; - GstPad * pad; - GstFlowReturn last_ret; + guint8 id; + guint8 stream_type; + GstBuffer *pes_buffer; + guint32 pes_buffer_size; + guint32 pes_buffer_used; + gboolean pes_buffer_overflow; + gboolean pes_buffer_in_sync; + GstPESFilter filter; + GstPad *pad; + GstFlowReturn last_ret; GstMPEGDescriptor *ES_info; /* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */ - GstClockTimeDiff base_time; - GstClockTime last_time; + GstClockTimeDiff base_time; + GstClockTime last_time; /* pid of PMT that this stream belongs to */ - guint16 PMT_pid; + guint16 PMT_pid; }; -struct _GstMpegTSDemux { - GstElement parent; +struct _GstMpegTSDemux +{ + GstElement parent; /* properties */ - gboolean check_crc; + gboolean check_crc; /* sink pad and adapter */ - GstPad * sinkpad; - GstAdapter * adapter; - guint8 ** sync_lut; - guint sync_lut_len; + GstPad *sinkpad; + GstAdapter *adapter; + guint8 **sync_lut; + guint sync_lut_len; /* current PMT PID */ - guint16 current_PMT; + guint16 current_PMT; /* Array of MPEGTS_MAX_PID + 1 stream entries */ - GstMpegTSStream ** streams; + GstMpegTSStream **streams; /* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */ - gboolean pmts_checked[MPEGTS_MAX_PID + 1]; - + gboolean pmts_checked[MPEGTS_MAX_PID + 1]; + /* Array of Elementary Stream pids for ts with PMT */ - guint16 * elementary_pids; - guint nb_elementary_pids; + guint16 *elementary_pids; + guint nb_elementary_pids; /* Program number to use */ - gint program_number; + gint program_number; /* indicates that we need to close our pad group, because we've added * at least one pad */ - gboolean need_no_more_pads; - guint16 packetsize; - gboolean m2ts_mode; + gboolean need_no_more_pads; + guint16 packetsize; + gboolean m2ts_mode; /* clocking */ - GstClock * clock; - GstClockTime clock_base; + GstClock *clock; + GstClockTime clock_base; + /* Additional information required for seeking */ + guint64 num_packets; + gint64 bitrate; + /* Two PCRs observations to calculate bitrate */ + gint64 pcr[2]; + GstClockTime cache_duration; + /* Cached base_PCR in GStreamer time. */ + GstClockTime base_pts; }; -struct _GstMpegTSDemuxClass { - GstElementClass parent_class; +struct _GstMpegTSDemuxClass +{ + GstElementClass parent_class; - GstPadTemplate * sink_template; - GstPadTemplate * video_template; - GstPadTemplate * audio_template; - GstPadTemplate * private_template; + GstPadTemplate *sink_template; + GstPadTemplate *video_template; + GstPadTemplate *audio_template; + GstPadTemplate *private_template; }; -GType gst_mpegts_demux_get_type (void); +GType gst_mpegts_demux_get_type (void); -gboolean gst_mpegts_demux_plugin_init (GstPlugin *plugin); +gboolean gst_mpegts_demux_plugin_init (GstPlugin * plugin); G_END_DECLS - #endif /* __GST_MPEGTS_DEMUX_H__ */ -- cgit v1.2.1 From 8692ae2a9d0c0bca938d3b7883e3f10adde8d9fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 9 May 2009 15:48:01 +0200 Subject: mxfmux: Don't unref NULL buffers if pushing a buffer after the first failed --- gst/mxf/mxfmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c index 3ca60a4e..a63172f2 100644 --- a/gst/mxf/mxfmux.c +++ b/gst/mxf/mxfmux.c @@ -1006,7 +1006,7 @@ gst_mxf_mux_write_header_metadata (GstMXFMux * mux) if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) { GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s", gst_flow_get_name (ret)); - g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); + g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL); g_list_free (buffers); return ret; } -- cgit v1.2.1 From 18f8c9b0b4057ceaab867d9c36349362458f997a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 9 May 2009 15:48:41 +0200 Subject: mxfmux: Fix EOS logic again --- gst/mxf/mxfmux.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gst') diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c index a63172f2..8aaa014e 100644 --- a/gst/mxf/mxfmux.c +++ b/gst/mxf/mxfmux.c @@ -1150,10 +1150,11 @@ gst_mxf_mux_handle_eos (GstMXFMux * mux) best = cpad; break; } - } else if (have_data && !l->next) { + } + + if (have_data && !l->next) { mux->last_gc_position++; mux->last_gc_timestamp = next_gc_timestamp; - have_data = FALSE; best = NULL; break; } -- cgit v1.2.1 From d09515b49f6c3ddc7969bd12cdb2c40239ba087c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 9 May 2009 15:48:54 +0200 Subject: mxfmux: Write metadata items in reference order This ensures that the metadata items are always written in the same order and that first comes the preface, then the identification linked from the preface, ... Some demuxers can't handle files where the metadata items are in random order. --- gst/mxf/mxfmux.c | 98 +++++++++++++++++++++++++++++++++++++++++++------------- gst/mxf/mxfmux.h | 1 + 2 files changed, 76 insertions(+), 23 deletions(-) (limited to 'gst') diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c index 8aaa014e..7fa7a5fa 100644 --- a/gst/mxf/mxfmux.c +++ b/gst/mxf/mxfmux.c @@ -163,6 +163,8 @@ gst_mxf_mux_finalize (GObject * object) if (mux->metadata) { g_hash_table_destroy (mux->metadata); mux->metadata = NULL; + g_list_free (mux->metadata_list); + mux->metadata_list = NULL; } gst_object_unref (mux->collect); @@ -216,6 +218,8 @@ gst_mxf_mux_reset (GstMXFMux * mux) if (mux->metadata) { g_hash_table_destroy (mux->metadata); mux->preface = NULL; + g_list_free (mux->metadata_list); + mux->metadata_list = NULL; } mux->metadata = mxf_metadata_hash_table_new (); @@ -280,6 +284,7 @@ gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps) gboolean ret = TRUE; MXFUUID d_instance_uid = { {0,} }; MXFMetadataFileDescriptor *old_descriptor = cpad->descriptor; + GList *l; GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps); @@ -309,6 +314,19 @@ gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps) memcpy (&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, &d_instance_uid, 16); + if (old_descriptor) { + for (l = mux->metadata_list; l; l = l->next) { + MXFMetadataBase *tmp = l->data; + + if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) { + l->data = cpad->descriptor; + break; + } + } + } else { + mux->metadata_list = g_list_prepend (mux->metadata_list, cpad->descriptor); + } + g_hash_table_replace (mux->metadata, &MXF_METADATA_BASE (cpad->descriptor)->instance_uid, cpad->descriptor); @@ -449,6 +467,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface); + mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface); mxf_timestamp_set_now (&mux->preface->last_modified_date); mux->preface->version = 258; @@ -505,6 +524,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (identification)->instance_uid, identification); + mux->metadata_list = g_list_prepend (mux->metadata_list, identification); mxf_uuid_init (&identification->this_generation_uid, NULL); @@ -561,6 +581,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage); + mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage); cstorage->n_packages = 2; cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2); @@ -576,6 +597,8 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid, cstorage->packages[1]); + mux->metadata_list = + g_list_prepend (mux->metadata_list, cstorage->packages[1]); p = (MXFMetadataSourcePackage *) cstorage->packages[1]; mxf_umid_init (&p->parent.package_uid); @@ -601,6 +624,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (d)->instance_uid, d); + mux->metadata_list = g_list_prepend (mux->metadata_list, d); } /* Tracks */ @@ -621,6 +645,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (track)->instance_uid, track); + mux->metadata_list = g_list_prepend (mux->metadata_list, track); track->parent.track_id = n + 1; track->parent.track_number = @@ -637,6 +662,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (sequence)->instance_uid, sequence); + mux->metadata_list = g_list_prepend (mux->metadata_list, sequence); memcpy (&sequence->data_definition, &cpad->writer->data_definition, 16); @@ -653,6 +679,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (clip)->instance_uid, clip); + mux->metadata_list = g_list_prepend (mux->metadata_list, clip); memcpy (&clip->parent.data_definition, &sequence->data_definition, 16); @@ -687,6 +714,8 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid, cstorage->packages[0]); + mux->metadata_list = + g_list_prepend (mux->metadata_list, cstorage->packages[0]); p = (MXFMetadataMaterialPackage *) cstorage->packages[0]; mxf_umid_init (&p->package_uid); @@ -724,6 +753,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (track)->instance_uid, track); + mux->metadata_list = g_list_prepend (mux->metadata_list, track); track->parent.track_id = n + 1; track->parent.track_number = 0; @@ -757,6 +787,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (sequence)->instance_uid, sequence); + mux->metadata_list = g_list_prepend (mux->metadata_list, sequence); memcpy (&sequence->data_definition, &cpad->writer->data_definition, 16); @@ -772,6 +803,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (clip)->instance_uid, clip); + mux->metadata_list = g_list_prepend (mux->metadata_list, clip); memcpy (&clip->parent.data_definition, &sequence->data_definition, 16); @@ -798,6 +830,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (track)->instance_uid, track); + mux->metadata_list = g_list_prepend (mux->metadata_list, track); track->parent.track_id = n + 1; track->parent.track_number = 0; @@ -811,6 +844,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (sequence)->instance_uid, sequence); + mux->metadata_list = g_list_prepend (mux->metadata_list, sequence); memcpy (&sequence->data_definition, mxf_metadata_track_identifier_get @@ -828,6 +862,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) mux->metadata); g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (component)->instance_uid, component); + mux->metadata_list = g_list_prepend (mux->metadata_list, component); memcpy (&component->parent.data_definition, &sequence->data_definition, 16); @@ -884,6 +919,9 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) g_hash_table_insert (mux->metadata, &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid, cstorage->essence_container_data[0]); + mux->metadata_list = + g_list_prepend (mux->metadata_list, + cstorage->essence_container_data[0]); cstorage->essence_container_data[0]->linked_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]); @@ -891,6 +929,41 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) cstorage->essence_container_data[0]->body_sid = 1; } + /* Sort descriptors at the correct places */ + { + GList *l; + GList *descriptors; + + for (l = mux->metadata_list; l; l = l->next) { + MXFMetadataBase *m = l->data; + + if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m) + && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) { + descriptors = l; + l->prev->next = NULL; + l->prev = NULL; + break; + } + } + + for (l = mux->metadata_list; l; l = l->next) { + MXFMetadataBase *m = l->data; + GList *s; + + if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) || + MXF_IS_METADATA_SOURCE_PACKAGE (m)) { + s = l->prev; + l->prev = g_list_last (descriptors); + s->next = descriptors; + descriptors->prev = s; + l->prev->next = l; + break; + } + } + } + + mux->metadata_list = g_list_reverse (mux->metadata_list); + return ret; } @@ -953,38 +1026,17 @@ gst_mxf_mux_write_header_metadata (GstMXFMux * mux) GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf; GList *buffers = NULL; -#if GLIB_CHECK_VERSION (2, 16, 0) - GHashTableIter iter; -#else - GList *values; -#endif - MXFMetadataBase *m; GList *l; + MXFMetadataBase *m; guint64 header_byte_count = 0; - buf = - mxf_metadata_base_to_buffer (MXF_METADATA_BASE (mux->preface), - &mux->primer); - header_byte_count += GST_BUFFER_SIZE (buf); - buffers = g_list_prepend (buffers, buf); - -#if GLIB_CHECK_VERSION (2, 16, 0) - g_hash_table_iter_init (&iter, mux->metadata); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) { -#else - values = g_hash_table_get_values (mux->metadata); - for (l = values; l; l = l->next) { + for (l = mux->metadata_list; l; l = l->next) { m = l->data; -#endif buf = mxf_metadata_base_to_buffer (m, &mux->primer); header_byte_count += GST_BUFFER_SIZE (buf); buffers = g_list_prepend (buffers, buf); } -#if !GLIB_CHECK_VERSION (2, 16, 0) - g_list_free (values); -#endif - buffers = g_list_reverse (buffers); buf = mxf_primer_pack_to_buffer (&mux->primer); header_byte_count += GST_BUFFER_SIZE (buf); diff --git a/gst/mxf/mxfmux.h b/gst/mxf/mxfmux.h index c8fd0b09..94330c46 100644 --- a/gst/mxf/mxfmux.h +++ b/gst/mxf/mxfmux.h @@ -85,6 +85,7 @@ typedef struct _GstMXFMux { MXFPrimerPack primer; GHashTable *metadata; + GList *metadata_list; MXFMetadataPreface *preface; MXFFraction min_edit_rate; -- cgit v1.2.1 From 6451febd143e8d214718c6d0e1b2355f52806b50 Mon Sep 17 00:00:00 2001 From: Tristan Matthews Date: Sun, 10 May 2009 10:40:36 +0200 Subject: mxfmux: Fix uninitialized variable compiler warning This will always be set to something but gcc didn't detect this. Fixes bug #582013. --- gst/mxf/mxfmux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c index 7fa7a5fa..fdc1bc61 100644 --- a/gst/mxf/mxfmux.c +++ b/gst/mxf/mxfmux.c @@ -932,7 +932,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) /* Sort descriptors at the correct places */ { GList *l; - GList *descriptors; + GList *descriptors = NULL; for (l = mux->metadata_list; l; l = l->next) { MXFMetadataBase *m = l->data; @@ -946,6 +946,8 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux) } } + g_assert (descriptors != NULL); + for (l = mux->metadata_list; l; l = l->next) { MXFMetadataBase *m = l->data; GList *s; -- cgit v1.2.1 From 29d53b22f9934d3d2a6751be91c88caa320efda4 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Sun, 10 May 2009 21:21:36 +0200 Subject: gppmux: Add MPEG-4 part 2 to supported formats. Fixes #581593. --- gst/qtmux/gstqtmuxmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/qtmux/gstqtmuxmap.c b/gst/qtmux/gstqtmuxmap.c index a4972661..11913670 100644 --- a/gst/qtmux/gstqtmuxmap.c +++ b/gst/qtmux/gstqtmuxmap.c @@ -174,7 +174,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { "3GPP", "GstGPPMux", GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"), - GST_STATIC_CAPS (H263_CAPS "; " H264_CAPS), + GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS), GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS) } , -- cgit v1.2.1 From 5aa3358f3b8604c8daf830847c77744824f53068 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 9 May 2009 09:57:47 +0200 Subject: mpegtsdemux: Revert indentation and comment header file. One shouldn't run gst-indent on .h files, in this case it was un-beautifying the indentation :) --- gst/mpegdemux/gstmpegtsdemux.h | 191 +++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 93 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index c4a907a5..2e2a8e63 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -52,14 +52,18 @@ #include "gstsectionfilter.h" G_BEGIN_DECLS + #define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024 #define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024 + #define MPEGTS_MAX_PID 0x1fff #define MPEGTS_NORMAL_TS_PACKETSIZE 188 #define MPEGTS_M2TS_TS_PACKETSIZE 192 + #define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \ (((data)[1] & 0x80) == 0x00) && \ (((data)[3] & 0x10) == 0x10)) + #define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type()) #define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux)) @@ -71,6 +75,7 @@ G_BEGIN_DECLS GST_TYPE_MPEGTS_DEMUX)) #define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\ GST_TYPE_MPEGTS_DEMUX)) + typedef struct _GstMpegTSStream GstMpegTSStream; typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry; typedef struct _GstMpegTSPMT GstMpegTSPMT; @@ -79,157 +84,157 @@ typedef struct _GstMpegTSPAT GstMpegTSPAT; typedef struct _GstMpegTSDemux GstMpegTSDemux; typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass; -struct _GstMpegTSPMTEntry -{ - guint16 PID; +struct _GstMpegTSPMTEntry { + guint16 PID; }; -struct _GstMpegTSPMT -{ - guint16 program_number; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; - guint16 PCR_PID; - guint16 program_info_length; - GstMPEGDescriptor *program_info; - - GArray *entries; +struct _GstMpegTSPMT { + guint16 program_number; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; + guint16 PCR_PID; + guint16 program_info_length; + GstMPEGDescriptor * program_info; + + GArray * entries; }; -struct _GstMpegTSPATEntry -{ - guint16 program_number; - guint16 PID; +struct _GstMpegTSPATEntry { + guint16 program_number; + guint16 PID; }; -struct _GstMpegTSPAT -{ - guint16 transport_stream_id; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; +struct _GstMpegTSPAT { + guint16 transport_stream_id; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; - GArray *entries; + GArray * entries; }; -typedef enum _MpegTsStreamFlags -{ +typedef enum _MpegTsStreamFlags { MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01, MPEGTS_STREAM_FLAG_PMT_VALID = 0x02, - MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 + MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 } MpegTsStreamFlags; /* Information associated to a single MPEG stream. */ -struct _GstMpegTSStream -{ - GstMpegTSDemux *demux; +struct _GstMpegTSStream { + GstMpegTSDemux * demux; - MpegTsStreamFlags flags; + MpegTsStreamFlags flags; /* PID and type */ - guint16 PID; - guint8 PID_type; + guint16 PID; + guint8 PID_type; /* adaptation_field data */ - guint64 last_PCR; - guint64 base_PCR; - guint64 last_OPCR; - guint64 last_PCR_difference; - gboolean discont_PCR; - GstClockTimeDiff discont_difference; + guint64 last_PCR; + guint64 base_PCR; + guint64 last_OPCR; + guint64 last_PCR_difference; + gboolean discont_PCR; + GstClockTimeDiff discont_difference; /* for PAT streams */ - GstMpegTSPAT PAT; + GstMpegTSPAT PAT; /* for PMT streams */ - GstMpegTSPMT PMT; + GstMpegTSPMT PMT; /* for CA streams */ /* for PAT, PMT, CA and private streams */ - GstSectionFilter section_filter; + GstSectionFilter section_filter; /* for PES streams */ - guint8 id; - guint8 stream_type; - GstBuffer *pes_buffer; - guint32 pes_buffer_size; - guint32 pes_buffer_used; - gboolean pes_buffer_overflow; - gboolean pes_buffer_in_sync; - GstPESFilter filter; - GstPad *pad; - GstFlowReturn last_ret; + guint8 id; + guint8 stream_type; + GstBuffer * pes_buffer; + guint32 pes_buffer_size; + guint32 pes_buffer_used; + gboolean pes_buffer_overflow; + gboolean pes_buffer_in_sync; + GstPESFilter filter; + GstPad * pad; + GstFlowReturn last_ret; GstMPEGDescriptor *ES_info; /* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */ - GstClockTimeDiff base_time; - GstClockTime last_time; + GstClockTimeDiff base_time; + GstClockTime last_time; /* pid of PMT that this stream belongs to */ - guint16 PMT_pid; + guint16 PMT_pid; }; -struct _GstMpegTSDemux -{ - GstElement parent; +struct _GstMpegTSDemux { + GstElement parent; /* properties */ - gboolean check_crc; + gboolean check_crc; /* sink pad and adapter */ - GstPad *sinkpad; - GstAdapter *adapter; - guint8 **sync_lut; - guint sync_lut_len; + GstPad * sinkpad; + GstAdapter * adapter; + guint8 ** sync_lut; + guint sync_lut_len; /* current PMT PID */ - guint16 current_PMT; + guint16 current_PMT; /* Array of MPEGTS_MAX_PID + 1 stream entries */ - GstMpegTSStream **streams; + GstMpegTSStream ** streams; /* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */ - gboolean pmts_checked[MPEGTS_MAX_PID + 1]; - + gboolean pmts_checked[MPEGTS_MAX_PID + 1]; + /* Array of Elementary Stream pids for ts with PMT */ - guint16 *elementary_pids; - guint nb_elementary_pids; + guint16 * elementary_pids; + guint nb_elementary_pids; /* Program number to use */ - gint program_number; + gint program_number; /* indicates that we need to close our pad group, because we've added * at least one pad */ - gboolean need_no_more_pads; - guint16 packetsize; - gboolean m2ts_mode; + gboolean need_no_more_pads; + guint16 packetsize; + gboolean m2ts_mode; /* clocking */ - GstClock *clock; - GstClockTime clock_base; - /* Additional information required for seeking */ - guint64 num_packets; - gint64 bitrate; + GstClock * clock; + GstClockTime clock_base; + + /* Additional information required for seeking. + * num_packets: Number of packets outputted + * bitrate: estimated bitrate (based on pcr and num_packets */ + guint64 num_packets; + gint64 bitrate; + /* Two PCRs observations to calculate bitrate */ - gint64 pcr[2]; - GstClockTime cache_duration; + gint64 pcr[2]; + + /* Cached duration estimation */ + GstClockTime cache_duration; + /* Cached base_PCR in GStreamer time. */ - GstClockTime base_pts; + GstClockTime base_pts; }; -struct _GstMpegTSDemuxClass -{ - GstElementClass parent_class; +struct _GstMpegTSDemuxClass { + GstElementClass parent_class; - GstPadTemplate *sink_template; - GstPadTemplate *video_template; - GstPadTemplate *audio_template; - GstPadTemplate *private_template; + GstPadTemplate * sink_template; + GstPadTemplate * video_template; + GstPadTemplate * audio_template; + GstPadTemplate * private_template; }; -GType gst_mpegts_demux_get_type (void); +GType gst_mpegts_demux_get_type (void); -gboolean gst_mpegts_demux_plugin_init (GstPlugin * plugin); +gboolean gst_mpegts_demux_plugin_init (GstPlugin *plugin); G_END_DECLS + #endif /* __GST_MPEGTS_DEMUX_H__ */ -- cgit v1.2.1 From 432dd98321f011582e17043470d1e4639c880155 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:40:46 +0200 Subject: mpegtsdemux: Change debugging levels for very frequent messages. This allows debugging with mpegtsdemux:4 while being able to track what's going on (and avoid taking up as much cpu for debugging as for the actual demuxing process). --- gst/mpegdemux/gstmpegtsdemux.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 99a499a0..213a4a22 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -843,7 +843,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, demux = stream->demux; srcpad = stream->pad; - GST_LOG_OBJECT (demux, "got data on PID 0x%04x", stream->PID); + GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x", stream->PID); if (first && filter->pts != -1) { pts = filter->pts; @@ -947,7 +947,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, pts = -1; } - GST_LOG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %" + GST_DEBUG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %" GST_TIME_FORMAT " on buffer %p first buffer: %d base_time: %" GST_TIME_FORMAT, pts, GST_TIME_ARGS (time), buffer, first, GST_TIME_ARGS (stream->base_time)); @@ -996,7 +996,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, gst_mpegts_demux_send_new_segment (demux, stream, pts); } - GST_DEBUG_OBJECT (demux, "pushing buffer"); + GST_DEBUG_OBJECT (srcpad, "pushing buffer"); gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad)); ret = gst_pad_push (srcpad, buffer); ret = gst_mpegts_demux_combine_flows (demux, stream, ret); @@ -1199,16 +1199,16 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream, if (gst_mpegts_demux_calc_crc32 (data - 3, datalen) != 0) goto wrong_crc; - GST_DEBUG_OBJECT (demux, "PMT section_length: %d", datalen - 3); + GST_LOG_OBJECT (demux, "PMT section_length: %d", datalen - 3); PMT = &stream->PMT; /* check if version number changed */ version_number = (data[2] & 0x3e) >> 1; - GST_DEBUG_OBJECT (demux, "PMT version_number: %d", version_number); + GST_LOG_OBJECT (demux, "PMT version_number: %d", version_number); current_next_indicator = (data[2] & 0x01); - GST_DEBUG_OBJECT (demux, "PMT current_next_indicator %d", + GST_LOG_OBJECT (demux, "PMT current_next_indicator %d", current_next_indicator); if (current_next_indicator == 0) goto not_yet_applicable; @@ -1574,7 +1574,7 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, if (length > 0) { guint8 flags = *data++; - GST_DEBUG_OBJECT (demux, "flags 0x%02x", flags); + GST_LOG_OBJECT (demux, "flags 0x%02x", flags); /* discontinuity flag */ if (flags & 0x80) { GST_DEBUG_OBJECT (demux, "discontinuity flag set"); @@ -1593,9 +1593,12 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, pcr_ext = (pcr2 & 0x01ff); if (pcr_ext) pcr = (pcr * 300 + pcr_ext % 300) / 300; - GST_DEBUG_OBJECT (demux, "have PCR %" G_GUINT64_FORMAT " on PID 0x%04x " - "and last pcr is %" G_GUINT64_FORMAT, - pcr, stream->PID, stream->last_PCR); + GST_DEBUG_OBJECT (demux, + "have PCR %" G_GUINT64_FORMAT "(%" GST_TIME_FORMAT ") on PID 0x%04x " + "and last pcr is %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", pcr, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pcr)), stream->PID, + stream->last_PCR, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (stream->last_PCR))); /* pcr has been converted into units of 90Khz ticks * so assume discont if last pcr was > 900000 (10 second) lower */ if (stream->last_PCR != -1 && @@ -2119,7 +2122,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, data += 3; datalen -= 3; - GST_DEBUG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u", + GST_LOG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u", adaptation_field_control, payload_unit_start_indicator, PID, datalen); ret = GST_FLOW_OK; @@ -2141,13 +2144,12 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, data += consumed; datalen -= consumed; - GST_DEBUG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen); + GST_LOG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen); } /* If this packet has a payload, handle it */ if (adaptation_field_control & 0x1) { - GST_DEBUG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, - PID); + GST_LOG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, PID); /* For unknown streams, check if the PID is in the partial PIDs * list as an elementary stream and override the type if so -- cgit v1.2.1 From bc062b9acf1232ee5643dd7976741c7a47378cd6 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:58:58 +0200 Subject: mpegtsdemux: Only take PCR from the active stream for bitrate estimation. --- gst/mpegdemux/gstmpegtsdemux.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 213a4a22..f07e1743 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -1694,16 +1694,23 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, } stream->last_PCR_difference = pcr - stream->last_PCR; } + GST_DEBUG_OBJECT (demux, "valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr, stream->last_PCR_difference); if (valid_pcr) { - if (demux->pcr[0] == -1) { - demux->pcr[0] = pcr; - demux->num_packets = 0; - } /* Considering a difference of 1 sec ie 90000 ticks */ - else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { - demux->pcr[1] = pcr; + GstMpegTSStream *PMT_stream = demux->streams[demux->current_PMT]; + + if (PMT_stream && PMT_stream->PMT.PCR_PID == stream->PID) { + if (demux->pcr[0] == -1) { + GST_DEBUG ("RECORDING pcr[0]:%" G_GUINT64_FORMAT, pcr); + demux->pcr[0] = pcr; + demux->num_packets = 0; + } /* Considering a difference of 1 sec ie 90000 ticks */ + else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { + GST_DEBUG ("RECORDING pcr[1]:%" G_GUINT64_FORMAT, pcr); + demux->pcr[1] = pcr; + } } stream->last_PCR = pcr; -- cgit v1.2.1 From f9dfc44a67320b6f73bb34e05ec80e67e9c8c087 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:59:20 +0200 Subject: mpegtsdemux: Protect bitrate estimation against bogus values. If the estimated bitrate is lower than 188 bytes, there's most likely something completely wrong with the two samples. If that happens, force recalculation. Use guint64 for observation PCR, I saw cases where it would overflow. --- gst/mpegdemux/gstmpegtsdemux.c | 21 +++++++++++++++++---- gst/mpegdemux/gstmpegtsdemux.h | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index f07e1743..cad385d0 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -2355,14 +2355,27 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, MPEGTS_NORMAL_TS_PACKETSIZE - 1); if (demux->pcr[1] != -1 && demux->bitrate == -1) { - GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GINT64_FORMAT + guint64 bitrate; + GST_DEBUG_OBJECT (demux, "pcr[0]:%" G_GUINT64_FORMAT, demux->pcr[0]); + GST_DEBUG_OBJECT (demux, "pcr[1]:%" G_GUINT64_FORMAT, demux->pcr[1]); + GST_DEBUG_OBJECT (demux, "diff in time %" GST_TIME_FORMAT, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0]))); + GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GUINT64_FORMAT ", demux->num_packets %" G_GUINT64_FORMAT, demux->pcr[1] - demux->pcr[0], demux->num_packets); - demux->bitrate = gst_util_uint64_scale (GST_SECOND, + bitrate = gst_util_uint64_scale (GST_SECOND, MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets, MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])); - GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT - " bytes per second", demux->bitrate); + /* somehow... I doubt a bitrate below one packet per second is valid */ + if (bitrate > MPEGTS_NORMAL_TS_PACKETSIZE - 1) { + demux->bitrate = bitrate; + GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT + " bytes per second", demux->bitrate); + } else { + GST_WARNING_OBJECT (demux, "Couldn't compute valid bitrate, recomputing"); + demux->pcr[0] = demux->pcr[1] = -1; + demux->num_packets = -1; + } } demux->num_packets++; return ret; diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index 2e2a8e63..dad2b023 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -213,7 +213,7 @@ struct _GstMpegTSDemux { gint64 bitrate; /* Two PCRs observations to calculate bitrate */ - gint64 pcr[2]; + guint64 pcr[2]; /* Cached duration estimation */ GstClockTime cache_duration; -- cgit v1.2.1 From 571a7746fcf18fba066779a43c23683a9d554051 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 17:40:48 +0100 Subject: dvdspu: Add a guard when we don't have any subpicture buffer to render --- gst/dvdspu/gstdvdspu-render.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gst') diff --git a/gst/dvdspu/gstdvdspu-render.c b/gst/dvdspu/gstdvdspu-render.c index e3bae8b6..a8dadee2 100644 --- a/gst/dvdspu/gstdvdspu-render.c +++ b/gst/dvdspu/gstdvdspu-render.c @@ -400,6 +400,8 @@ gst_dvd_spu_render_spu (GstDVDSpu * dvdspu, GstBuffer * buf) gint y, last_y; /* Set up our initial state */ + if (G_UNLIKELY (state->pix_buf == NULL)) + return; /* Store the start of each plane */ planes[0] = GST_BUFFER_DATA (buf); -- cgit v1.2.1 From 513367a88cb5875c92418f9c2a93b0f3f19ab99a Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 17:42:12 +0100 Subject: dvdspu: Always push a frame at the start of a still frame, and fix a leak. Make sure to push the frame for a still frame, with discont = true and timestamp=none, so that it gets displayed by the sink. Also, don't leak each rendered video frame during still menus. --- gst/dvdspu/gstdvdspu.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'gst') diff --git a/gst/dvdspu/gstdvdspu.c b/gst/dvdspu/gstdvdspu.c index 3b4c1a0c..50b6b603 100644 --- a/gst/dvdspu/gstdvdspu.c +++ b/gst/dvdspu/gstdvdspu.c @@ -94,7 +94,7 @@ static GstFlowReturn gst_dvd_spu_video_chain (GstPad * pad, GstBuffer * buf); static gboolean gst_dvd_spu_video_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_dvd_spu_buffer_alloc (GstPad * sinkpad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); -static void gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu); +static void gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu, gboolean force); static void gst_dvd_spu_check_still_updates (GstDVDSpu * dvdspu); static GstFlowReturn gst_dvd_spu_subpic_chain (GstPad * pad, GstBuffer * buf); @@ -429,7 +429,7 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event) /* And re-draw the still frame to make sure it appears on * screen, otherwise the last frame might have been discarded * by QoS */ - gst_dvd_spu_redraw_still (dvdspu); + gst_dvd_spu_redraw_still (dvdspu, TRUE); } else state->flags &= ~(SPU_STATE_STILL_FRAME); DVD_SPU_UNLOCK (dvdspu); @@ -633,15 +633,17 @@ no_ref_frame: /* With SPU LOCK */ static void -gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu) +gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu, gboolean force) { /* If we have an active SPU command set and a reference frame, copy the * frame, redraw the SPU and store it as the pending frame for output */ if (dvdspu->ref_frame) { - if ((dvdspu->spu_state.flags & SPU_STATE_FORCED_DSP) || - ((dvdspu->spu_state.flags & SPU_STATE_FORCED_ONLY) == 0 && - (dvdspu->spu_state.flags & SPU_STATE_DISPLAY))) { - GstBuffer *buf = gst_buffer_copy (dvdspu->ref_frame); + gboolean redraw = (dvdspu->spu_state.flags & SPU_STATE_FORCED_DSP); + redraw |= (dvdspu->spu_state.flags & SPU_STATE_FORCED_ONLY) == 0 && + (dvdspu->spu_state.flags & SPU_STATE_DISPLAY); + + if (redraw) { + GstBuffer *buf = gst_buffer_ref (dvdspu->ref_frame); buf = gst_buffer_make_writable (buf); @@ -654,9 +656,21 @@ gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu) /* Render the SPU overlay onto the buffer */ gst_dvd_spu_render_spu (dvdspu, buf); gst_buffer_replace (&dvdspu->pending_frame, buf); + gst_buffer_unref (buf); + } else if (force) { + /* Simply output the reference frame */ + GstBuffer *buf = gst_buffer_ref (dvdspu->ref_frame); + buf = gst_buffer_make_metadata_writable (buf); + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE; + + GST_DEBUG_OBJECT (dvdspu, "Pushing reference frame at start of still"); + + gst_buffer_replace (&dvdspu->pending_frame, buf); + gst_buffer_unref (buf); } else { - GST_LOG_OBJECT (dvdspu, - "Redraw due to Still Frame skipped - no SPU to draw"); + GST_LOG_OBJECT (dvdspu, "Redraw due to Still Frame skipped"); } } else { GST_LOG_OBJECT (dvdspu, "Not redrawing still frame - no ref frame"); @@ -1000,7 +1014,7 @@ gst_dvd_spu_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event) } if (hl_change && (state->flags & SPU_STATE_STILL_FRAME)) { - gst_dvd_spu_redraw_still (dvdspu); + gst_dvd_spu_redraw_still (dvdspu, FALSE); } gst_event_unref (event); -- cgit v1.2.1 From ad1f7e6ed3848e5ece2e796ef9dc356485d19e56 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 11 May 2009 11:04:25 +0100 Subject: dvdspu: Make the debugging output a bit clearer. Display more info about custom DVD events in the debug messages. --- gst/dvdspu/gstdvdspu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'gst') diff --git a/gst/dvdspu/gstdvdspu.c b/gst/dvdspu/gstdvdspu.c index 50b6b603..82048529 100644 --- a/gst/dvdspu/gstdvdspu.c +++ b/gst/dvdspu/gstdvdspu.c @@ -413,13 +413,14 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event) break; } - GST_DEBUG_OBJECT (dvdspu, - "DVD event of type %s on video pad", event_type); - if (strcmp (event_type, "dvd-still") == 0) { gboolean in_still; if (gst_structure_get_boolean (structure, "still-state", &in_still)) { + GST_DEBUG_OBJECT (dvdspu, + "DVD event of type %s on video pad: in-still = %d", event_type, + in_still); + DVD_SPU_LOCK (dvdspu); if (in_still) { state->flags |= SPU_STATE_STILL_FRAME; @@ -430,14 +431,18 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event) * screen, otherwise the last frame might have been discarded * by QoS */ gst_dvd_spu_redraw_still (dvdspu, TRUE); - } else + } else { state->flags &= ~(SPU_STATE_STILL_FRAME); + } DVD_SPU_UNLOCK (dvdspu); } gst_event_unref (event); res = TRUE; - } else + } else { + GST_DEBUG_OBJECT (dvdspu, + "DVD event of type %s on video pad", event_type); res = gst_pad_event_default (pad, event); + } break; } case GST_EVENT_NEWSEGMENT: -- cgit v1.2.1 From 8c135666245e846f91cfd266a47e424dd79ac0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 12 May 2009 21:50:12 +0200 Subject: Moved 'flv' from -bad to -good --- gst/flv/Makefile.am | 9 - gst/flv/gstflvdemux.c | 1323 ------------------------------------------------- gst/flv/gstflvdemux.h | 130 ----- gst/flv/gstflvmux.c | 1040 -------------------------------------- gst/flv/gstflvmux.h | 89 ---- gst/flv/gstflvparse.c | 1283 ----------------------------------------------- gst/flv/gstflvparse.h | 42 -- 7 files changed, 3916 deletions(-) delete mode 100644 gst/flv/Makefile.am delete mode 100644 gst/flv/gstflvdemux.c delete mode 100644 gst/flv/gstflvdemux.h delete mode 100644 gst/flv/gstflvmux.c delete mode 100644 gst/flv/gstflvmux.h delete mode 100644 gst/flv/gstflvparse.c delete mode 100644 gst/flv/gstflvparse.h (limited to 'gst') diff --git a/gst/flv/Makefile.am b/gst/flv/Makefile.am deleted file mode 100644 index 6e1a58b2..00000000 --- a/gst/flv/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -plugin_LTLIBRARIES = libgstflv.la - -libgstflv_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) -libgstflv_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) -libgstflv_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS} -libgstflv_la_SOURCES = gstflvdemux.c gstflvparse.c gstflvmux.c -libgstflv_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstflvdemux.h gstflvparse.h gstflvmux.h diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c deleted file mode 100644 index 5856e7ac..00000000 --- a/gst/flv/gstflvdemux.c +++ /dev/null @@ -1,1323 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Julien Moutte - * - * 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. - */ - -/** - * SECTION:element-flvdemux - * - * flvdemux demuxes an FLV file into the different contained streams. - * - * - * Example launch line - * |[ - * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink - * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstflvdemux.h" -#include "gstflvparse.h" -#include "gstflvmux.h" - -#include - -static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-flv") - ); - -static GstStaticPadTemplate audio_src_template = -GST_STATIC_PAD_TEMPLATE ("audio", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate video_src_template = -GST_STATIC_PAD_TEMPLATE ("video", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -GST_DEBUG_CATEGORY (flvdemux_debug); -#define GST_CAT_DEFAULT flvdemux_debug - -GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT); - -/* 9 bytes of header + 4 bytes of first previous tag size */ -#define FLV_HEADER_SIZE 13 -/* 1 byte of tag type + 3 bytes of tag data size */ -#define FLV_TAG_TYPE_SIZE 4 - -static void -gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont) -{ - GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer"); - - gst_adapter_clear (demux->adapter); - - demux->audio_need_discont = TRUE; - demux->video_need_discont = TRUE; - - demux->flushing = FALSE; - - /* Only in push mode */ - if (!demux->random_access) { - /* After a flush we expect a tag_type */ - demux->state = FLV_STATE_TAG_TYPE; - /* We reset the offset and will get one from first push */ - demux->offset = 0; - } -} - -static void -gst_flv_demux_cleanup (GstFLVDemux * demux) -{ - GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer"); - - demux->state = FLV_STATE_HEADER; - - demux->flushing = FALSE; - demux->need_header = TRUE; - demux->audio_need_segment = TRUE; - demux->video_need_segment = TRUE; - demux->audio_need_discont = TRUE; - demux->video_need_discont = TRUE; - - /* By default we consider them as linked */ - demux->audio_linked = TRUE; - demux->video_linked = TRUE; - - demux->has_audio = FALSE; - demux->has_video = FALSE; - demux->push_tags = FALSE; - demux->got_par = FALSE; - - gst_segment_init (&demux->segment, GST_FORMAT_TIME); - - demux->w = demux->h = 0; - demux->par_x = demux->par_y = 1; - demux->video_offset = 0; - demux->audio_offset = 0; - demux->offset = demux->cur_tag_offset = 0; - demux->tag_size = demux->tag_data_size = 0; - demux->duration = GST_CLOCK_TIME_NONE; - - if (demux->new_seg_event) { - gst_event_unref (demux->new_seg_event); - demux->new_seg_event = NULL; - } - - if (demux->close_seg_event) { - gst_event_unref (demux->close_seg_event); - demux->close_seg_event = NULL; - } - - gst_adapter_clear (demux->adapter); - - if (demux->audio_codec_data) { - gst_buffer_unref (demux->audio_codec_data); - demux->audio_codec_data = NULL; - } - - if (demux->video_codec_data) { - gst_buffer_unref (demux->video_codec_data); - demux->video_codec_data = NULL; - } - - if (demux->audio_pad) { - gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad); - gst_object_unref (demux->audio_pad); - demux->audio_pad = NULL; - } - - if (demux->video_pad) { - gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad); - gst_object_unref (demux->video_pad); - demux->video_pad = NULL; - } - - if (demux->times) { - g_array_free (demux->times, TRUE); - demux->times = NULL; - } - - if (demux->filepositions) { - g_array_free (demux->filepositions, TRUE); - demux->filepositions = NULL; - } -} - -static GstFlowReturn -gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstFLVDemux *demux = NULL; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %" - G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); - - if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) { - GST_DEBUG_OBJECT (demux, "beginning of file, expect header"); - demux->state = FLV_STATE_HEADER; - demux->offset = 0; - } - - if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) { - GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's"); - demux->offset = GST_BUFFER_OFFSET (buffer); - } - - gst_adapter_push (demux->adapter, buffer); - -parse: - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked - || demux->video_linked)) { - ret = GST_FLOW_OK; - } else { - GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret)); - goto beach; - } - } - - if (G_UNLIKELY (demux->flushing)) { - GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop"); - ret = GST_FLOW_WRONG_STATE; - goto beach; - } - - switch (demux->state) { - case FLV_STATE_HEADER: - { - if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) { - GstBuffer *buffer; - - buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE); - - ret = gst_flv_parse_header (demux, buffer); - - gst_buffer_unref (buffer); - demux->offset += FLV_HEADER_SIZE; - - demux->state = FLV_STATE_TAG_TYPE; - goto parse; - } else { - goto beach; - } - } - case FLV_STATE_TAG_TYPE: - { - if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) { - GstBuffer *buffer; - - /* Remember the tag offset in bytes */ - demux->cur_tag_offset = demux->offset; - - buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE); - - ret = gst_flv_parse_tag_type (demux, buffer); - - gst_buffer_unref (buffer); - demux->offset += FLV_TAG_TYPE_SIZE; - - goto parse; - } else { - goto beach; - } - } - case FLV_STATE_TAG_VIDEO: - { - if (gst_adapter_available (demux->adapter) >= demux->tag_size) { - GstBuffer *buffer; - - buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size); - - ret = gst_flv_parse_tag_video (demux, buffer); - - gst_buffer_unref (buffer); - demux->offset += demux->tag_size; - - demux->state = FLV_STATE_TAG_TYPE; - goto parse; - } else { - goto beach; - } - } - case FLV_STATE_TAG_AUDIO: - { - if (gst_adapter_available (demux->adapter) >= demux->tag_size) { - GstBuffer *buffer; - - buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size); - - ret = gst_flv_parse_tag_audio (demux, buffer); - - gst_buffer_unref (buffer); - demux->offset += demux->tag_size; - - demux->state = FLV_STATE_TAG_TYPE; - goto parse; - } else { - goto beach; - } - } - case FLV_STATE_TAG_SCRIPT: - { - if (gst_adapter_available (demux->adapter) >= demux->tag_size) { - GstBuffer *buffer; - - buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size); - - ret = gst_flv_parse_tag_script (demux, buffer); - - gst_buffer_unref (buffer); - demux->offset += demux->tag_size; - - demux->state = FLV_STATE_TAG_TYPE; - goto parse; - } else { - goto beach; - } - } - default: - GST_DEBUG_OBJECT (demux, "unexpected demuxer state"); - } - -beach: - if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) { - /* If either audio or video is linked we return GST_FLOW_OK */ - if (demux->audio_linked || demux->video_linked) { - ret = GST_FLOW_OK; - } - } - - gst_object_unref (demux); - - return ret; -} - -static GstFlowReturn -gst_flv_demux_pull_range (GstFLVDemux * demux, GstPad * pad, guint64 offset, - guint size, GstBuffer ** buffer) -{ - GstFlowReturn ret; - - ret = gst_pad_pull_range (pad, offset, size, buffer); - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - GST_WARNING_OBJECT (demux, - "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s", - size, offset, gst_flow_get_name (ret)); - *buffer = NULL; - return ret; - } - - if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) { - GST_WARNING_OBJECT (demux, - "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (*buffer), size, offset); - gst_buffer_unref (*buffer); - ret = GST_FLOW_UNEXPECTED; - *buffer = NULL; - return ret; - } - - return ret; -} - -static GstFlowReturn -gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux) -{ - GstBuffer *buffer = NULL; - GstFlowReturn ret = GST_FLOW_OK; - - /* Store tag offset */ - demux->cur_tag_offset = demux->offset; - - /* Get the first 4 bytes to identify tag type and size */ - if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset, - FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK)) - goto beach; - - /* Identify tag type */ - ret = gst_flv_parse_tag_type (demux, buffer); - - gst_buffer_unref (buffer); - - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto beach; - - /* Jump over tag type + size */ - demux->offset += FLV_TAG_TYPE_SIZE; - - /* Pull the whole tag */ - if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset, - demux->tag_size, &buffer)) != GST_FLOW_OK)) - goto beach; - - switch (demux->state) { - case FLV_STATE_TAG_VIDEO: - ret = gst_flv_parse_tag_video (demux, buffer); - break; - case FLV_STATE_TAG_AUDIO: - ret = gst_flv_parse_tag_audio (demux, buffer); - break; - case FLV_STATE_TAG_SCRIPT: - ret = gst_flv_parse_tag_script (demux, buffer); - break; - default: - GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state); - } - - gst_buffer_unref (buffer); - - /* Jump over that part we've just parsed */ - demux->offset += demux->tag_size; - - /* Make sure we reinitialize the tag size */ - demux->tag_size = 0; - - /* Ready for the next tag */ - demux->state = FLV_STATE_TAG_TYPE; - - if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) { - /* If either audio or video is linked we return GST_FLOW_OK */ - if (demux->audio_linked || demux->video_linked) { - ret = GST_FLOW_OK; - } else { - GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and " - "neither video nor audio are linked"); - } - } - -beach: - return ret; -} - -static GstFlowReturn -gst_flv_demux_pull_header (GstPad * pad, GstFLVDemux * demux) -{ - GstBuffer *buffer = NULL; - GstFlowReturn ret = GST_FLOW_OK; - - /* Get the first 9 bytes */ - if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset, - FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK)) - goto beach; - - ret = gst_flv_parse_header (demux, buffer); - - gst_buffer_unref (buffer); - - /* Jump over the header now */ - demux->offset += FLV_HEADER_SIZE; - demux->state = FLV_STATE_TAG_TYPE; - -beach: - return ret; -} - -static GstFlowReturn -gst_flv_demux_seek_to_prev_keyframe (GstFLVDemux * demux) -{ - return GST_FLOW_OK; -} - -static gboolean -gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event) -{ - gboolean ret = TRUE; - - if (demux->audio_pad) - ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event)); - - if (demux->video_pad) - ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event)); - - gst_event_unref (event); - - return ret; -} - -static void -gst_flv_demux_create_index (GstFLVDemux * demux) -{ - gint64 size; - GstFormat fmt = GST_FORMAT_BYTES; - size_t tag_size; - guint64 old_offset; - GstBuffer *buffer; - GstFlowReturn ret; - - if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) || - fmt != GST_FORMAT_BYTES) - return; - - old_offset = demux->offset; - - while ((ret = - gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12, - &buffer)) == GST_FLOW_OK) { - if (gst_flv_parse_tag_timestamp (demux, buffer, - &tag_size) == GST_CLOCK_TIME_NONE) { - gst_buffer_unref (buffer); - break; - } - - gst_buffer_unref (buffer); - demux->offset += tag_size; - } - - demux->offset = old_offset; -} - -static void -gst_flv_demux_loop (GstPad * pad) -{ - GstFLVDemux *demux = NULL; - GstFlowReturn ret = GST_FLOW_OK; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (pad)); - - if (demux->segment.rate >= 0) { - /* pull in data */ - switch (demux->state) { - case FLV_STATE_TAG_TYPE: - ret = gst_flv_demux_pull_tag (pad, demux); - break; - case FLV_STATE_DONE: - ret = GST_FLOW_UNEXPECTED; - break; - default: - ret = gst_flv_demux_pull_header (pad, demux); - if (ret == GST_FLOW_OK) - gst_flv_demux_create_index (demux); - - } - - /* pause if something went wrong */ - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto pause; - - /* check EOS condition */ - if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) && - (demux->segment.stop != -1) && - (demux->segment.last_stop >= demux->segment.stop)) { - ret = GST_FLOW_UNEXPECTED; - goto pause; - } - } else { /* Reverse playback */ - /* pull in data */ - switch (demux->state) { - case FLV_STATE_TAG_TYPE: - ret = gst_flv_demux_pull_tag (pad, demux); - /* When packet parsing returns UNEXPECTED that means we ve reached the - point where we want to go to the previous keyframe. This is either - the last FLV tag or the keyframe we used last time */ - if (ret == GST_FLOW_UNEXPECTED) { - ret = gst_flv_demux_seek_to_prev_keyframe (demux); - demux->state = FLV_STATE_TAG_TYPE; - } - break; - default: - ret = gst_flv_demux_pull_header (pad, demux); - if (ret == GST_FLOW_OK) - gst_flv_demux_create_index (demux); - } - - /* pause if something went wrong */ - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto pause; - - /* check EOS condition */ - if (demux->segment.last_stop <= demux->segment.start) { - ret = GST_FLOW_UNEXPECTED; - goto pause; - } - } - - gst_object_unref (demux); - - return; - -pause: - { - const gchar *reason = gst_flow_get_name (ret); - - GST_LOG_OBJECT (demux, "pausing task, reason %s", reason); - gst_pad_pause_task (pad); - - if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { - if (ret == GST_FLOW_UNEXPECTED) { - /* perform EOS logic */ - gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); - if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gint64 stop; - - /* for segment playback we need to post when (in stream time) - * we stopped, this is either stop (when set) or the duration. */ - if ((stop = demux->segment.stop) == -1) - stop = demux->segment.duration; - - if (demux->segment.rate >= 0) { - GST_LOG_OBJECT (demux, "Sending segment done, at end of segment"); - gst_element_post_message (GST_ELEMENT_CAST (demux), - gst_message_new_segment_done (GST_OBJECT_CAST (demux), - GST_FORMAT_TIME, stop)); - } else { /* Reverse playback */ - GST_LOG_OBJECT (demux, "Sending segment done, at beginning of " - "segment"); - gst_element_post_message (GST_ELEMENT_CAST (demux), - gst_message_new_segment_done (GST_OBJECT_CAST (demux), - GST_FORMAT_TIME, demux->segment.start)); - } - } else { - /* normal playback, send EOS to all linked pads */ - gst_element_no_more_pads (GST_ELEMENT (demux)); - GST_LOG_OBJECT (demux, "Sending EOS, at end of stream"); - if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ())) - GST_WARNING_OBJECT (demux, "failed pushing EOS on streams"); - } - } else { - GST_ELEMENT_ERROR (demux, STREAM, FAILED, - ("Internal data stream error."), - ("stream stopped, reason %s", reason)); - gst_flv_demux_push_src_event (demux, gst_event_new_eos ()); - } - } - gst_object_unref (demux); - return; - } -} - -static guint64 -gst_flv_demux_find_offset (GstFLVDemux * demux, GstSegment * segment) -{ - gint64 bytes = 0; - gint64 time = 0; - GstIndexEntry *entry; - - g_return_val_if_fail (segment != NULL, 0); - - time = segment->start; - - if (demux->index) { - /* Let's check if we have an index entry for that seek time */ - entry = gst_index_get_assoc_entry (demux->index, demux->index_id, - GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT, - GST_FORMAT_TIME, time); - - if (entry) { - gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes); - gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time); - - GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT - " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT, - GST_TIME_ARGS (segment->start), GST_TIME_ARGS (time), bytes); - - /* Key frame seeking */ - if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) { - /* Adjust the segment so that the keyframe fits in */ - if (time < segment->start) { - segment->start = segment->time = time; - } - segment->last_stop = time; - } - } else { - GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT, - GST_TIME_ARGS (segment->start)); - } - } - - return bytes; -} - -static gboolean -gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event) -{ - GstFormat format; - GstSeekFlags flags; - GstSeekType start_type, stop_type; - gint64 start, stop; - gdouble rate; - gboolean update, flush, keyframe, ret; - GstSegment seeksegment; - - gst_event_parse_seek (event, &rate, &format, &flags, - &start_type, &start, &stop_type, &stop); - - if (format != GST_FORMAT_TIME) - goto wrong_format; - - flush = !!(flags & GST_SEEK_FLAG_FLUSH); - keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); - - /* Work on a copy until we are sure the seek succeeded. */ - memcpy (&seeksegment, &demux->segment, sizeof (GstSegment)); - - GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT, - &demux->segment); - - /* Apply the seek to our segment */ - gst_segment_set_seek (&seeksegment, rate, format, flags, - start_type, start, stop_type, stop, &update); - - GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT, - &seeksegment); - - if (flush || seeksegment.last_stop != demux->segment.last_stop) { - /* Do the actual seeking */ - guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment); - - GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %" - G_GUINT64_FORMAT, offset); - ret = gst_pad_push_event (demux->sinkpad, - gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES, - seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, - offset, GST_SEEK_TYPE_NONE, 0)); - if (G_UNLIKELY (!ret)) { - GST_WARNING_OBJECT (demux, "upstream seek failed"); - } - - /* Tell all the stream we moved to a different position (discont) */ - demux->audio_need_discont = TRUE; - demux->video_need_discont = TRUE; - } else { - ret = TRUE; - } - - if (ret) { - /* Ok seek succeeded, take the newly configured segment */ - memcpy (&demux->segment, &seeksegment, sizeof (GstSegment)); - - /* Tell all the stream a new segment is needed */ - demux->audio_need_segment = TRUE; - demux->video_need_segment = TRUE; - /* Clean any potential newsegment event kept for the streams. The first - * stream needing a new segment will create a new one. */ - if (G_UNLIKELY (demux->new_seg_event)) { - gst_event_unref (demux->new_seg_event); - demux->new_seg_event = NULL; - } - gst_event_unref (event); - } else { - ret = gst_pad_push_event (demux->sinkpad, event); - } - - return ret; - -/* ERRORS */ -wrong_format: - { - GST_WARNING_OBJECT (demux, "we only support seeking in TIME format"); - return gst_pad_push_event (demux->sinkpad, event); - } -} - -static gboolean -gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event) -{ - GstFormat format; - GstSeekFlags flags; - GstSeekType start_type, stop_type; - gint64 start, stop; - gdouble rate; - gboolean update, flush, keyframe, ret; - GstSegment seeksegment; - - gst_event_parse_seek (event, &rate, &format, &flags, - &start_type, &start, &stop_type, &stop); - - gst_event_unref (event); - - if (format != GST_FORMAT_TIME) - goto wrong_format; - - flush = !!(flags & GST_SEEK_FLAG_FLUSH); - keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); - - if (flush) { - /* Flush start up and downstream to make sure data flow and loops are - idle */ - gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ()); - gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ()); - } else { - /* Pause the pulling task */ - gst_pad_pause_task (demux->sinkpad); - } - - /* Take the stream lock */ - GST_PAD_STREAM_LOCK (demux->sinkpad); - - if (flush) { - /* Stop flushing upstream we need to pull */ - gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); - } - - /* Work on a copy until we are sure the seek succeeded. */ - memcpy (&seeksegment, &demux->segment, sizeof (GstSegment)); - - GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT, - &demux->segment); - - /* Apply the seek to our segment */ - gst_segment_set_seek (&seeksegment, rate, format, flags, - start_type, start, stop_type, stop, &update); - - GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT, - &seeksegment); - - if (flush || seeksegment.last_stop != demux->segment.last_stop) { - /* Do the actual seeking */ - demux->offset = gst_flv_demux_find_offset (demux, &seeksegment); - - /* Tell all the stream we moved to a different position (discont) */ - demux->audio_need_discont = TRUE; - demux->video_need_discont = TRUE; - - /* If we seeked at the beginning of the file parse the header again */ - if (G_UNLIKELY (!demux->offset)) { - demux->state = FLV_STATE_HEADER; - } else { /* or parse a tag */ - demux->state = FLV_STATE_TAG_TYPE; - } - ret = TRUE; - } else { - ret = TRUE; - } - - if (G_UNLIKELY (demux->close_seg_event)) { - gst_event_unref (demux->close_seg_event); - demux->close_seg_event = NULL; - } - - if (flush) { - /* Stop flushing, the sinks are at time 0 now */ - gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ()); - } else { - GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT, - &demux->segment); - - /* Close the current segment for a linear playback */ - if (demux->segment.rate >= 0) { - /* for forward playback, we played from start to last_stop */ - demux->close_seg_event = gst_event_new_new_segment (TRUE, - demux->segment.rate, demux->segment.format, - demux->segment.start, demux->segment.last_stop, demux->segment.time); - } else { - gint64 stop; - - if ((stop = demux->segment.stop) == -1) - stop = demux->segment.duration; - - /* for reverse playback, we played from stop to last_stop. */ - demux->close_seg_event = gst_event_new_new_segment (TRUE, - demux->segment.rate, demux->segment.format, - demux->segment.last_stop, stop, demux->segment.last_stop); - } - } - - if (ret) { - /* Ok seek succeeded, take the newly configured segment */ - memcpy (&demux->segment, &seeksegment, sizeof (GstSegment)); - - /* Notify about the start of a new segment */ - if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gst_element_post_message (GST_ELEMENT (demux), - gst_message_new_segment_start (GST_OBJECT (demux), - demux->segment.format, demux->segment.last_stop)); - } - - /* Tell all the stream a new segment is needed */ - demux->audio_need_segment = TRUE; - demux->video_need_segment = TRUE; - /* Clean any potential newsegment event kept for the streams. The first - * stream needing a new segment will create a new one. */ - if (G_UNLIKELY (demux->new_seg_event)) { - gst_event_unref (demux->new_seg_event); - demux->new_seg_event = NULL; - } - } - - gst_pad_start_task (demux->sinkpad, - (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad); - - GST_PAD_STREAM_UNLOCK (demux->sinkpad); - - return ret; - - /* ERRORS */ -wrong_format: - { - GST_WARNING_OBJECT (demux, "we only support seeking in TIME format"); - return FALSE; - } -} - -/* If we can pull that's prefered */ -static gboolean -gst_flv_demux_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) { - return gst_pad_activate_pull (sinkpad, TRUE); - } else { - return gst_pad_activate_push (sinkpad, TRUE); - } -} - -/* This function gets called when we activate ourselves in push mode. - * We cannot seek (ourselves) in the stream */ -static gboolean -gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active) -{ - GstFLVDemux *demux; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad)); - - demux->random_access = FALSE; - - gst_object_unref (demux); - - return TRUE; -} - -/* this function gets called when we activate ourselves in pull mode. - * We can perform random access to the resource and we start a task - * to start reading */ -static gboolean -gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - GstFLVDemux *demux; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad)); - - if (active) { - demux->random_access = TRUE; - gst_object_unref (demux); - return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop, - sinkpad); - } else { - demux->random_access = FALSE; - gst_object_unref (demux); - return gst_pad_stop_task (sinkpad); - } -} - -static gboolean -gst_flv_demux_sink_event (GstPad * pad, GstEvent * event) -{ - GstFLVDemux *demux; - gboolean ret = FALSE; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - GST_DEBUG_OBJECT (demux, "trying to force chain function to exit"); - demux->flushing = TRUE; - ret = gst_flv_demux_push_src_event (demux, event); - break; - case GST_EVENT_FLUSH_STOP: - GST_DEBUG_OBJECT (demux, "flushing FLV demuxer"); - gst_flv_demux_flush (demux, TRUE); - ret = gst_flv_demux_push_src_event (demux, event); - break; - case GST_EVENT_EOS: - GST_DEBUG_OBJECT (demux, "received EOS"); - if (demux->index) { - GST_DEBUG_OBJECT (demux, "committing index"); - gst_index_commit (demux->index, demux->index_id); - } - gst_element_no_more_pads (GST_ELEMENT (demux)); - if (!gst_flv_demux_push_src_event (demux, event)) - GST_WARNING_OBJECT (demux, "failed pushing EOS on streams"); - ret = TRUE; - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate; - gint64 start, stop, time; - gboolean update; - - GST_DEBUG_OBJECT (demux, "received new segment"); - - gst_event_parse_new_segment (event, &update, &rate, &format, &start, - &stop, &time); - - if (format == GST_FORMAT_TIME) { - /* time segment, this is perfect, copy over the values. */ - gst_segment_set_newsegment (&demux->segment, update, rate, format, - start, stop, time); - - GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT, - &demux->segment); - - /* and forward */ - ret = gst_flv_demux_push_src_event (demux, event); - } else { - /* non-time format */ - demux->audio_need_segment = TRUE; - demux->video_need_segment = TRUE; - ret = TRUE; - gst_event_unref (event); - } - break; - } - default: - ret = gst_flv_demux_push_src_event (demux, event); - break; - } - - gst_object_unref (demux); - - return ret; -} - -gboolean -gst_flv_demux_src_event (GstPad * pad, GstEvent * event) -{ - GstFLVDemux *demux; - gboolean ret = FALSE; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - if (demux->random_access) { - ret = gst_flv_demux_handle_seek_pull (demux, event); - } else { - ret = gst_flv_demux_handle_seek_push (demux, event); - } - break; - default: - ret = gst_pad_push_event (demux->sinkpad, event); - break; - } - - gst_object_unref (demux); - - return ret; -} - -gboolean -gst_flv_demux_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstFLVDemux *demux; - - demux = GST_FLV_DEMUX (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_DURATION: - { - GstFormat format; - - gst_query_parse_duration (query, &format, NULL); - - /* duration is time only */ - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (demux, "duration query only supported for time " - "format"); - res = FALSE; - goto beach; - } - - GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT, - GST_TIME_ARGS (demux->duration)); - - gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration); - - break; - } - case GST_QUERY_POSITION: - { - GstFormat format; - - gst_query_parse_position (query, &format, NULL); - - /* position is time only */ - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (demux, "position query only supported for time " - "format"); - res = FALSE; - goto beach; - } - - GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT, - GST_TIME_ARGS (demux->segment.last_stop)); - - gst_query_set_duration (query, GST_FORMAT_TIME, demux->segment.last_stop); - - break; - } - - case GST_QUERY_LATENCY: - default: - { - GstPad *peer; - - if ((peer = gst_pad_get_peer (demux->sinkpad))) { - /* query latency on peer pad */ - res = gst_pad_query (peer, query); - gst_object_unref (peer); - } else { - /* no peer, we don't know */ - res = FALSE; - } - break; - } - } - -beach: - gst_object_unref (demux); - - return res; -} - -static GstStateChangeReturn -gst_flv_demux_change_state (GstElement * element, GstStateChange transition) -{ - GstFLVDemux *demux; - GstStateChangeReturn ret; - - demux = GST_FLV_DEMUX (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - /* If this is our own index destroy it as the - * old entries might be wrong for the new stream */ - if (demux->own_index) { - gst_object_unref (demux->index); - demux->index = NULL; - demux->own_index = FALSE; - } - - /* If no index was created, generate one */ - if (G_UNLIKELY (!demux->index)) { - GST_DEBUG_OBJECT (demux, "no index provided creating our own"); - - demux->index = gst_index_factory_make ("memindex"); - - gst_index_get_writer_id (demux->index, GST_OBJECT (demux), - &demux->index_id); - demux->own_index = TRUE; - } - gst_flv_demux_cleanup (demux); - break; - default: - break; - } - - 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_READY: - gst_flv_demux_cleanup (demux); - break; - default: - break; - } - - return ret; -} - -static void -gst_flv_demux_set_index (GstElement * element, GstIndex * index) -{ - GstFLVDemux *demux = GST_FLV_DEMUX (element); - - GST_OBJECT_LOCK (demux); - if (demux->index) - gst_object_unref (demux->index); - demux->index = gst_object_ref (index); - GST_OBJECT_UNLOCK (demux); - - gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id); - demux->own_index = FALSE; -} - -static GstIndex * -gst_flv_demux_get_index (GstElement * element) -{ - GstIndex *result = NULL; - - GstFLVDemux *demux = GST_FLV_DEMUX (element); - - GST_OBJECT_LOCK (demux); - if (demux->index) - result = gst_object_ref (demux->index); - GST_OBJECT_UNLOCK (demux); - - return result; -} - -static void -gst_flv_demux_dispose (GObject * object) -{ - GstFLVDemux *demux = GST_FLV_DEMUX (object); - - GST_DEBUG_OBJECT (demux, "disposing FLV demuxer"); - - if (demux->adapter) { - gst_adapter_clear (demux->adapter); - g_object_unref (demux->adapter); - demux->adapter = NULL; - } - - if (demux->taglist) { - gst_tag_list_free (demux->taglist); - demux->taglist = NULL; - } - - if (demux->new_seg_event) { - gst_event_unref (demux->new_seg_event); - demux->new_seg_event = NULL; - } - - if (demux->close_seg_event) { - gst_event_unref (demux->close_seg_event); - demux->close_seg_event = NULL; - } - - if (demux->audio_codec_data) { - gst_buffer_unref (demux->audio_codec_data); - demux->audio_codec_data = NULL; - } - - if (demux->video_codec_data) { - gst_buffer_unref (demux->video_codec_data); - demux->video_codec_data = NULL; - } - - if (demux->audio_pad) { - gst_object_unref (demux->audio_pad); - demux->audio_pad = NULL; - } - - if (demux->video_pad) { - gst_object_unref (demux->video_pad); - demux->video_pad = NULL; - } - - if (demux->index) { - gst_object_unref (demux->index); - demux->index = NULL; - } - - if (demux->times) { - g_array_free (demux->times, TRUE); - demux->times = NULL; - } - - if (demux->filepositions) { - g_array_free (demux->filepositions, TRUE); - demux->filepositions = NULL; - } - - GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); -} - -static void -gst_flv_demux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&flv_sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&audio_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&video_src_template)); - gst_element_class_set_details_simple (element_class, "FLV Demuxer", - "Codec/Demuxer", - "Demux FLV feeds into digital streams", - "Julien Moutte "); -} - -static void -gst_flv_demux_class_init (GstFLVDemuxClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_flv_demux_dispose); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_flv_demux_change_state); - gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index); - gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index); -} - -static void -gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class) -{ - demux->sinkpad = - gst_pad_new_from_static_template (&flv_sink_template, "sink"); - - gst_pad_set_event_function (demux->sinkpad, - GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event)); - gst_pad_set_chain_function (demux->sinkpad, - GST_DEBUG_FUNCPTR (gst_flv_demux_chain)); - gst_pad_set_activate_function (demux->sinkpad, - GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate)); - gst_pad_set_activatepull_function (demux->sinkpad, - GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull)); - gst_pad_set_activatepush_function (demux->sinkpad, - GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push)); - - gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); - - demux->adapter = gst_adapter_new (); - demux->taglist = gst_tag_list_new (); - gst_segment_init (&demux->segment, GST_FORMAT_TIME); - - demux->own_index = FALSE; - - gst_flv_demux_cleanup (demux); -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer"); - - if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY, - gst_flv_demux_get_type ()) || - !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY, - gst_flv_mux_get_type ())) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - "flv", "FLV muxing and demuxing plugin", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h deleted file mode 100644 index 72c0bcd4..00000000 --- a/gst/flv/gstflvdemux.h +++ /dev/null @@ -1,130 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Julien Moutte - * - * 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 __FLV_DEMUX_H__ -#define __FLV_DEMUX_H__ - -#include -#include - -G_BEGIN_DECLS -#define GST_TYPE_FLV_DEMUX \ - (gst_flv_demux_get_type()) -#define GST_FLV_DEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLV_DEMUX,GstFLVDemux)) -#define GST_FLV_DEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLV_DEMUX,GstFLVDemuxClass)) -#define GST_IS_FLV_DEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLV_DEMUX)) -#define GST_IS_FLV_DEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLV_DEMUX)) -typedef struct _GstFLVDemux GstFLVDemux; -typedef struct _GstFLVDemuxClass GstFLVDemuxClass; - -typedef enum -{ - FLV_STATE_HEADER, - FLV_STATE_TAG_TYPE, - FLV_STATE_TAG_VIDEO, - FLV_STATE_TAG_AUDIO, - FLV_STATE_TAG_SCRIPT, - FLV_STATE_DONE, - FLV_STATE_NONE -} GstFLVDemuxState; - -struct _GstFLVDemux -{ - GstElement element; - - GstPad *sinkpad; - - GstPad *audio_pad; - GstPad *video_pad; - - /* */ - - GstIndex *index; - gint index_id; - gboolean own_index; - - GArray * times; - GArray * filepositions; - - GstAdapter *adapter; - - GstSegment segment; - - GstEvent *close_seg_event; - GstEvent *new_seg_event; - - GstTagList *taglist; - - GstFLVDemuxState state; - - guint64 offset; - guint64 cur_tag_offset; - GstClockTime duration; - guint64 tag_size; - guint64 tag_data_size; - - /* Audio infos */ - guint16 rate; - guint16 channels; - guint16 width; - guint16 audio_codec_tag; - guint64 audio_offset; - gboolean audio_need_discont; - gboolean audio_need_segment; - gboolean audio_linked; - GstBuffer * audio_codec_data; - - /* Video infos */ - guint32 w; - guint32 h; - guint32 par_x; - guint32 par_y; - guint16 video_codec_tag; - guint64 video_offset; - gboolean video_need_discont; - gboolean video_need_segment; - gboolean video_linked; - gboolean got_par; - GstBuffer * video_codec_data; - - gboolean random_access; - gboolean need_header; - gboolean has_audio; - gboolean has_video; - gboolean push_tags; - gboolean strict; - gboolean flushing; -}; - -struct _GstFLVDemuxClass -{ - GstElementClass parent_class; -}; - -GType gst_flv_demux_get_type (void); - -gboolean gst_flv_demux_query (GstPad * pad, GstQuery * query); -gboolean gst_flv_demux_src_event (GstPad * pad, GstEvent * event); - -G_END_DECLS -#endif /* __FLV_DEMUX_H__ */ diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c deleted file mode 100644 index dd27276a..00000000 --- a/gst/flv/gstflvmux.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* GStreamer - * - * Copyright (c) 2008 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-flvmux - * - * flvmux muxes different streams into an FLV file. - * - * - * Example launch line - * |[ - * gst-launch -v filesrc location=/path/to/audio ! decodebin2 ! queue ! flvmux name=m ! filesink location=file.flv filesrc location=/path/to/video ! decodebin2 ! queue ! m. - * ]| This pipeline muxes an audio and video file into a single FLV file. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "gstflvmux.h" - -GST_DEBUG_CATEGORY_STATIC (flvmux_debug); -#define GST_CAT_DEFAULT flvmux_debug - -static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-flv") - ); - -static GstStaticPadTemplate videosink_templ = GST_STATIC_PAD_TEMPLATE ("video", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS ("video/x-flash-video; " - "video/x-flash-screen; " - "video/x-vp6-flash; " "video/x-vp6-alpha; " "video/x-h264;") - ); - -static GstStaticPadTemplate audiosink_templ = GST_STATIC_PAD_TEMPLATE ("audio", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS - ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; " - "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; " - "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; " - "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; " - "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 8, depth = (int) 8, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) FALSE; " - "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 16, depth = (int) 16, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) TRUE; " - "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; " - "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; " - "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };") - ); - -#define _do_init(type) \ - G_STMT_START{ \ - static const GInterfaceInfo tag_setter_info = { \ - NULL, \ - NULL, \ - NULL \ - }; \ - g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \ - &tag_setter_info); \ - }G_STMT_END - -GST_BOILERPLATE_FULL (GstFlvMux, gst_flv_mux, GstElement, GST_TYPE_ELEMENT, - _do_init); - -static void gst_flv_mux_finalize (GObject * object); -static GstFlowReturn -gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data); - -static gboolean gst_flv_mux_handle_src_event (GstPad * pad, GstEvent * event); -static GstPad *gst_flv_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name); -static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad); - -static GstStateChangeReturn -gst_flv_mux_change_state (GstElement * element, GstStateChange transition); - -static void gst_flv_mux_reset (GstElement * element); - -static void -gst_flv_mux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&videosink_templ)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&audiosink_templ)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_templ)); - gst_element_class_set_details_simple (element_class, "FLV muxer", - "Codec/Muxer", - "Muxes video/audio streams into a FLV stream", - "Sebastian Dröge "); - - GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer"); -} - -static void -gst_flv_mux_class_init (GstFlvMuxClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer"); - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->finalize = gst_flv_mux_finalize; - - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flv_mux_change_state); - gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (gst_flv_mux_request_new_pad); - gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_flv_mux_release_pad); -} - -static void -gst_flv_mux_init (GstFlvMux * mux, GstFlvMuxClass * g_class) -{ - mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src"); - gst_pad_set_event_function (mux->srcpad, gst_flv_mux_handle_src_event); - gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad); - - mux->collect = gst_collect_pads_new (); - gst_collect_pads_set_function (mux->collect, - (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_flv_mux_collected), mux); - - gst_flv_mux_reset (GST_ELEMENT (mux)); -} - -static void -gst_flv_mux_finalize (GObject * object) -{ - GstFlvMux *mux = GST_FLV_MUX (object); - - gst_object_unref (mux->collect); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_flv_mux_reset (GstElement * element) -{ - GstFlvMux *mux = GST_FLV_MUX (element); - GSList *sl; - - while ((sl = mux->collect->data) != NULL) { - GstFlvPad *cpad = (GstFlvPad *) sl->data; - - if (cpad->audio_codec_data) - gst_buffer_unref (cpad->audio_codec_data); - if (cpad->video_codec_data) - gst_buffer_unref (cpad->video_codec_data); - - gst_collect_pads_remove_pad (mux->collect, cpad->collect.pad); - } - - if (mux->tags) - gst_tag_list_free (mux->tags); - mux->tags = NULL; - - mux->state = GST_FLV_MUX_STATE_HEADER; -} - -static gboolean -gst_flv_mux_handle_src_event (GstPad * pad, GstEvent * event) -{ - GstEventType type; - - type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; - - switch (type) { - case GST_EVENT_SEEK: - /* disable seeking for now */ - return FALSE; - default: - break; - } - - return gst_pad_event_default (pad, event); -} - -static gboolean -gst_flv_mux_handle_sink_event (GstPad * pad, GstEvent * event) -{ - GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad)); - gboolean ret = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_TAG:{ - GstTagList *tags; - - if (!mux->tags) - mux->tags = gst_tag_list_new (); - - gst_event_parse_tag (event, &tags); - if (tags) { - gst_tag_list_insert (mux->tags, tags, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux))); - } - - break; - } - case GST_EVENT_NEWSEGMENT: - /* We don't support NEWSEGMENT events */ - ret = FALSE; - gst_event_unref (event); - break; - default: - break; - } - - /* now GstCollectPads can take care of the rest, e.g. EOS */ - if (ret) - ret = mux->collect_event (pad, event); - gst_object_unref (mux); - - return ret; -} - -static gboolean -gst_flv_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps) -{ - GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad)); - GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad); - gboolean ret = TRUE; - GstStructure *s; - - s = gst_caps_get_structure (caps, 0); - - if (strcmp (gst_structure_get_name (s), "video/x-flash-video") == 0) { - cpad->video_codec = 2; - } else if (strcmp (gst_structure_get_name (s), "video/x-flash-screen") == 0) { - cpad->video_codec = 3; - } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-flash") == 0) { - cpad->video_codec = 4; - } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-alpha") == 0) { - cpad->video_codec = 5; - } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) { - cpad->video_codec = 7; - } else { - ret = FALSE; - } - - if (ret && gst_structure_has_field (s, "codec_data")) { - const GValue *val = gst_structure_get_value (s, "codec_data"); - - if (val) { - cpad->video_codec_data = gst_buffer_ref (gst_value_get_buffer (val)); - cpad->sent_codec_data = FALSE; - } else { - cpad->sent_codec_data = TRUE; - } - } else { - cpad->sent_codec_data = TRUE; - } - - gst_object_unref (mux); - - return ret; -} - -static gboolean -gst_flv_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) -{ - GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad)); - GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad); - gboolean ret = TRUE; - GstStructure *s; - - s = gst_caps_get_structure (caps, 0); - - if (strcmp (gst_structure_get_name (s), "audio/x-adpcm") == 0) { - const gchar *layout = gst_structure_get_string (s, "layout"); - if (layout && strcmp (layout, "swf") == 0) { - cpad->audio_codec = 1; - } else { - ret = FALSE; - } - } else if (strcmp (gst_structure_get_name (s), "audio/mpeg") == 0) { - gint mpegversion; - - if (gst_structure_get_int (s, "mpegversion", &mpegversion)) { - if (mpegversion == 1) { - gint layer; - - if (gst_structure_get_int (s, "layer", &layer) && layer == 3) { - gint rate; - - if (gst_structure_get_int (s, "rate", &rate) && rate == 8000) - cpad->audio_codec = 14; - else - cpad->audio_codec = 2; - } else { - ret = FALSE; - } - } else if (mpegversion == 4) { - cpad->audio_codec = 10; - } else { - ret = FALSE; - } - } else { - ret = FALSE; - } - } else if (strcmp (gst_structure_get_name (s), "audio/x-nellymoser") == 0) { - gint rate, channels; - - if (gst_structure_get_int (s, "rate", &rate) - && gst_structure_get_int (s, "channels", &channels)) { - if (channels == 1 && rate == 16000) - cpad->audio_codec = 4; - else if (channels == 1 && rate == 8000) - cpad->audio_codec = 5; - } else { - cpad->audio_codec = 6; - } - } else if (strcmp (gst_structure_get_name (s), "audio/x-raw-int") == 0) { - gint endianness; - - if (gst_structure_get_int (s, "endianness", &endianness) - && endianness == G_LITTLE_ENDIAN) - cpad->audio_codec = 3; - else - ret = FALSE; - } else if (strcmp (gst_structure_get_name (s), "audio/x-alaw") == 0) { - cpad->audio_codec = 7; - } else if (strcmp (gst_structure_get_name (s), "audio/x-mulaw") == 0) { - cpad->audio_codec = 8; - } else if (strcmp (gst_structure_get_name (s), "audio/x-speex") == 0) { - cpad->audio_codec = 11; - } else { - ret = FALSE; - } - - if (ret) { - gint rate, channels, width; - - if (gst_structure_get_int (s, "rate", &rate)) { - if (cpad->audio_codec == 10) - cpad->rate = 3; - else if (rate == 5512) - cpad->rate = 0; - else if (rate == 11025) - cpad->rate = 1; - else if (rate == 22050) - cpad->rate = 2; - else if (rate == 44100) - cpad->rate = 3; - else if (rate == 8000 && (cpad->audio_codec == 5 - || cpad->audio_codec == 14)) - cpad->rate = 0; - else if (rate == 16000 && cpad->audio_codec == 4) - cpad->rate = 0; - else - ret = FALSE; - } else if (cpad->audio_codec == 10) { - cpad->rate = 3; - } else { - ret = FALSE; - } - - if (gst_structure_get_int (s, "channels", &channels)) { - if (cpad->audio_codec == 4 || cpad->audio_codec == 5 - || cpad->audio_codec == 6) - cpad->channels = 0; - else if (cpad->audio_codec == 10) - cpad->channels = 1; - else if (channels == 1) - cpad->channels = 0; - else if (channels == 2) - cpad->channels = 1; - else - ret = FALSE; - } else if (cpad->audio_codec == 4 || cpad->audio_codec == 5 - || cpad->audio_codec == 6) { - cpad->channels = 0; - } else if (cpad->audio_codec == 10) { - cpad->channels = 1; - } else { - ret = FALSE; - } - - if (gst_structure_get_int (s, "width", &width)) { - if (cpad->audio_codec != 3) - cpad->width = 1; - else if (width == 8) - cpad->width = 0; - else if (width == 16) - cpad->width = 1; - else - ret = FALSE; - } else if (cpad->audio_codec != 3) { - cpad->width = 1; - } else { - ret = FALSE; - } - } - - if (ret && gst_structure_has_field (s, "codec_data")) { - const GValue *val = gst_structure_get_value (s, "codec_data"); - - if (val) { - cpad->audio_codec_data = gst_buffer_ref (gst_value_get_buffer (val)); - cpad->sent_codec_data = FALSE; - } else { - cpad->sent_codec_data = TRUE; - } - } else { - cpad->sent_codec_data = TRUE; - } - - gst_object_unref (mux); - - return ret; -} - -static GstPad * -gst_flv_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * pad_name) -{ - GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); - GstFlvMux *mux = GST_FLV_MUX (element); - GstFlvPad *cpad; - GstPad *pad = NULL; - const gchar *name = NULL; - GstPadSetCapsFunction setcapsfunc = NULL; - gboolean video; - - if (mux->state != GST_FLV_MUX_STATE_HEADER) { - GST_WARNING_OBJECT (mux, "Can't request pads after writing header"); - return NULL; - } - - if (templ == gst_element_class_get_pad_template (klass, "audio")) { - if (mux->have_audio) { - GST_WARNING_OBJECT (mux, "Already have an audio pad"); - return NULL; - } - mux->have_audio = TRUE; - name = "audio"; - video = FALSE; - setcapsfunc = GST_DEBUG_FUNCPTR (gst_flv_mux_audio_pad_setcaps); - } else if (templ == gst_element_class_get_pad_template (klass, "video")) { - if (mux->have_video) { - GST_WARNING_OBJECT (mux, "Already have a video pad"); - return NULL; - } - mux->have_video = TRUE; - name = "video"; - video = TRUE; - setcapsfunc = GST_DEBUG_FUNCPTR (gst_flv_mux_video_pad_setcaps); - } else { - GST_WARNING_OBJECT (mux, "Invalid template"); - return NULL; - } - - pad = gst_pad_new_from_template (templ, name); - cpad = (GstFlvPad *) - gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstFlvPad)); - - cpad->video = video; - - cpad->audio_codec = G_MAXUINT; - cpad->rate = G_MAXUINT; - cpad->width = G_MAXUINT; - cpad->channels = G_MAXUINT; - cpad->audio_codec_data = NULL; - - cpad->video_codec = G_MAXUINT; - cpad->video_codec_data = NULL; - - cpad->sent_codec_data = FALSE; - - cpad->last_timestamp = 0; - - /* FIXME: hacked way to override/extend the event function of - * GstCollectPads; because it sets its own event function giving the - * element no access to events. - */ - mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad); - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_flv_mux_handle_sink_event)); - - gst_pad_set_setcaps_function (pad, setcapsfunc); - gst_pad_set_active (pad, TRUE); - gst_element_add_pad (element, pad); - - return pad; -} - -static void -gst_flv_mux_release_pad (GstElement * element, GstPad * pad) -{ - GstFlvMux *mux = GST_FLV_MUX (GST_PAD_PARENT (pad)); - GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad); - - if (cpad && cpad->audio_codec_data) - gst_buffer_unref (cpad->audio_codec_data); - if (cpad && cpad->video_codec_data) - gst_buffer_unref (cpad->video_codec_data); - - gst_collect_pads_remove_pad (mux->collect, pad); - gst_element_remove_pad (element, pad); -} - -static GstFlowReturn -gst_flv_mux_write_metadata (GstFlvMux * mux) -{ - GstTagList *merged_tags; - const GstTagList *user_tags; - GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *script_tag, *tmp; - guint8 *data; - gint i, n_tags, tags_written = 0; - - user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux)); - GST_DEBUG_OBJECT (mux, "upstream tags = %" GST_PTR_FORMAT, mux->tags); - GST_DEBUG_OBJECT (mux, "user-set tags = %" GST_PTR_FORMAT, user_tags); - - merged_tags = gst_tag_list_merge (user_tags, mux->tags, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux))); - - GST_DEBUG_OBJECT (mux, "merged tags = %" GST_PTR_FORMAT, merged_tags); - - script_tag = gst_buffer_new_and_alloc (11); - data = GST_BUFFER_DATA (script_tag); - - data[0] = 18; - - /* Data size, unknown for now */ - data[1] = 0; - data[2] = 0; - data[3] = 0; - - /* Timestamp */ - data[4] = data[5] = data[6] = data[7] = 0; - - /* Stream ID */ - data[8] = data[9] = data[10] = 0; - - tmp = gst_buffer_new_and_alloc (13); - data = GST_BUFFER_DATA (tmp); - data[0] = 2; /* string */ - data[1] = 0; - data[2] = 0x0a; /* length 10 */ - memcpy (&data[3], "onMetaData", sizeof ("onMetaData")); - - script_tag = gst_buffer_join (script_tag, tmp); - - n_tags = - (merged_tags) ? gst_structure_n_fields ((GstStructure *) merged_tags) : 0; - tmp = gst_buffer_new_and_alloc (5); - data = GST_BUFFER_DATA (tmp); - data[0] = 8; /* ECMA array */ - GST_WRITE_UINT32_BE (data + 1, n_tags); - script_tag = gst_buffer_join (script_tag, tmp); - - for (i = 0; merged_tags && i < n_tags; i++) { - const gchar *tag_name = - gst_structure_nth_field_name ((const GstStructure *) merged_tags, i); - if (!strcmp (tag_name, GST_TAG_DURATION)) { - gdouble d; - guint64 dur; - - if (!gst_tag_list_get_uint64 (merged_tags, GST_TAG_DURATION, &dur)) - continue; - - d = gst_guint64_to_gdouble (dur); - d /= (gdouble) GST_SECOND; - - tmp = gst_buffer_new_and_alloc (2 + 8 + 1 + 8); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 8 bytes name */ - data[1] = 8; - memcpy (&data[2], "duration", sizeof ("duration")); - data[10] = 0; /* double */ - GST_WRITE_DOUBLE_BE (data + 11, d); - script_tag = gst_buffer_join (script_tag, tmp); - tags_written++; - } else if (!strcmp (tag_name, GST_TAG_ARTIST) || - !strcmp (tag_name, GST_TAG_TITLE)) { - gchar *s; - const gchar *t; - - if (!strcmp (tag_name, GST_TAG_ARTIST)) - t = "creator"; - else if (!strcmp (tag_name, GST_TAG_TITLE)) - t = "title"; - - if (!gst_tag_list_get_string (merged_tags, tag_name, &s)) - continue; - - tmp = gst_buffer_new_and_alloc (2 + strlen (t) + 1 + 2 + strlen (s)); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* tag name length */ - data[1] = strlen (t); - memcpy (&data[2], t, strlen (t)); - data[2 + strlen (t)] = 2; /* string */ - data[3 + strlen (t)] = (strlen (s) >> 8) & 0xff; - data[4 + strlen (t)] = (strlen (s)) & 0xff; - memcpy (&data[5 + strlen (t)], s, strlen (s)); - script_tag = gst_buffer_join (script_tag, tmp); - - g_free (s); - tags_written++; - } - } - - if (mux->have_video) { - GstPad *video_pad = NULL; - GSList *l = mux->collect->data; - - for (; l; l = l->next) { - GstFlvPad *cpad = l->data; - if (cpad && cpad->video) { - video_pad = cpad->collect.pad; - break; - } - } - - if (video_pad && GST_PAD_CAPS (video_pad)) { - GstStructure *s = gst_caps_get_structure (GST_PAD_CAPS (video_pad), 0); - gint par_x, par_y; - - if (gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_x, &par_y)) { - gdouble d; - - d = par_x; - tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 8); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 12 bytes name */ - data[1] = 12; - memcpy (&data[2], "AspectRatioX", sizeof ("AspectRatioX")); - data[14] = 0; /* double */ - GST_WRITE_DOUBLE_BE (data + 15, d); - script_tag = gst_buffer_join (script_tag, tmp); - tags_written++; - - d = par_y; - tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 8); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 12 bytes name */ - data[1] = 12; - memcpy (&data[2], "AspectRatioY", sizeof ("AspectRatioY")); - data[14] = 0; /* double */ - GST_WRITE_DOUBLE_BE (data + 15, d); - script_tag = gst_buffer_join (script_tag, tmp); - tags_written++; - } - } - } - - { - const gchar *s = "GStreamer FLV muxer"; - - tmp = gst_buffer_new_and_alloc (2 + 15 + 1 + 2 + strlen (s)); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 15 bytes name */ - data[1] = 15; - memcpy (&data[2], "metadatacreator", sizeof ("metadatacreator")); - data[17] = 2; /* string */ - data[18] = (strlen (s) >> 8) & 0xff; - data[19] = (strlen (s)) & 0xff; - memcpy (&data[20], s, strlen (s)); - script_tag = gst_buffer_join (script_tag, tmp); - - tags_written++; - } - - { - GTimeVal tv = { 0, }; - time_t secs; - struct tm *tm; - gchar *s; - static const gchar *weekdays[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const gchar *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", - "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - g_get_current_time (&tv); - secs = tv.tv_sec; - tm = gmtime (&secs); - - s = g_strdup_printf ("%s %s %d %d:%d:%d %d", weekdays[tm->tm_wday], - months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_year + 1900); - - tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 2 + strlen (s)); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 12 bytes name */ - data[1] = 12; - memcpy (&data[2], "creationdate", sizeof ("creationdate")); - data[14] = 2; /* string */ - data[15] = (strlen (s) >> 8) & 0xff; - data[16] = (strlen (s)) & 0xff; - memcpy (&data[17], s, strlen (s)); - script_tag = gst_buffer_join (script_tag, tmp); - - g_free (s); - tags_written++; - } - - tmp = gst_buffer_new_and_alloc (2 + 0 + 1); - data = GST_BUFFER_DATA (tmp); - data[0] = 0; /* 0 byte size */ - data[1] = 0; - data[2] = 9; /* end marker */ - script_tag = gst_buffer_join (script_tag, tmp); - tags_written++; - - - tmp = gst_buffer_new_and_alloc (4); - data = GST_BUFFER_DATA (tmp); - GST_WRITE_UINT32_BE (data, GST_BUFFER_SIZE (script_tag)); - script_tag = gst_buffer_join (script_tag, tmp); - - data = GST_BUFFER_DATA (script_tag); - data[1] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 16) & 0xff; - data[2] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 8) & 0xff; - data[3] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 0) & 0xff; - - GST_WRITE_UINT32_BE (data + 11 + 13 + 1, tags_written); - - gst_buffer_set_caps (script_tag, GST_PAD_CAPS (mux->srcpad)); - ret = gst_pad_push (mux->srcpad, script_tag); - - if (merged_tags) - gst_tag_list_free (merged_tags); - - return ret; -} - -static GstFlowReturn -gst_flv_mux_write_header (GstFlvMux * mux) -{ - GstBuffer *header = gst_buffer_new_and_alloc (9 + 4); - guint8 *data = GST_BUFFER_DATA (header); - GstFlowReturn ret; - - if (GST_PAD_CAPS (mux->srcpad) == NULL) { - GstCaps *caps = gst_caps_new_simple ("video/x-flv", NULL); - - gst_pad_set_caps (mux->srcpad, caps); - gst_caps_unref (caps); - } - gst_buffer_set_caps (header, GST_PAD_CAPS (mux->srcpad)); - - data[0] = 'F'; - data[1] = 'L'; - data[2] = 'V'; - data[3] = 0x01; /* Version */ - - data[4] = (mux->have_audio << 2) | mux->have_video; /* flags */ - GST_WRITE_UINT32_BE (data + 5, 9); /* data offset */ - - GST_WRITE_UINT32_BE (data + 9, 0); /* previous tag size */ - - ret = gst_pad_push (mux->srcpad, header); - if (ret != GST_FLOW_OK) - return ret; - - return gst_flv_mux_write_metadata (mux); -} - -static GstFlowReturn -gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvPad * cpad) -{ - GstBuffer *tag; - guint8 *data; - guint size; - GstBuffer *buffer = - gst_collect_pads_pop (mux->collect, (GstCollectData *) cpad); - guint32 timestamp = - (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) ? GST_BUFFER_TIMESTAMP (buffer) / - GST_MSECOND : cpad->last_timestamp / GST_MSECOND; - gboolean second_run = FALSE; - GstFlowReturn ret; - -next: - size = 11; - if (cpad->video) { - size += 1; - if (cpad->video_codec == 7 && !cpad->sent_codec_data) - size += 4 + GST_BUFFER_SIZE (cpad->video_codec_data); - else if (cpad->video_codec == 7) - size += 4 + GST_BUFFER_SIZE (buffer); - else - size += GST_BUFFER_SIZE (buffer); - } else { - size += 1; - if (cpad->audio_codec == 10 && !cpad->sent_codec_data) - size += 1 + GST_BUFFER_SIZE (cpad->audio_codec_data); - else if (cpad->audio_codec == 10) - size += 1 + GST_BUFFER_SIZE (buffer); - else - size += GST_BUFFER_SIZE (buffer); - } - size += 4; - - tag = gst_buffer_new_and_alloc (size); - data = GST_BUFFER_DATA (tag); - memset (data, 0, size); - - data[0] = (cpad->video) ? 9 : 8; - - data[1] = ((size - 11 - 4) >> 16) & 0xff; - data[2] = ((size - 11 - 4) >> 8) & 0xff; - data[3] = ((size - 11 - 4) >> 0) & 0xff; - - data[4] = (timestamp >> 16) & 0xff; - data[5] = (timestamp >> 8) & 0xff; - data[6] = (timestamp >> 0) & 0xff; - data[7] = (timestamp >> 24) & 0xff; - - data[8] = data[9] = data[10] = 0; - - if (cpad->video) { - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) - data[11] |= 2 << 4; - else - data[11] |= 1 << 4; - - data[11] |= cpad->video_codec & 0x0f; - - if (cpad->video_codec == 7 && !cpad->sent_codec_data) { - data[12] = 0; - data[13] = data[14] = data[15] = 0; - - memcpy (data + 11 + 1 + 4, GST_BUFFER_DATA (cpad->video_codec_data), - GST_BUFFER_SIZE (cpad->video_codec_data)); - second_run = TRUE; - } else if (cpad->video_codec == 7) { - data[12] = 1; - - /* FIXME: what to do about composition time */ - data[13] = data[14] = data[15] = 0; - - memcpy (data + 11 + 1 + 4, GST_BUFFER_DATA (buffer), - GST_BUFFER_SIZE (buffer)); - } else { - memcpy (data + 11 + 1, GST_BUFFER_DATA (buffer), - GST_BUFFER_SIZE (buffer)); - } - } else { - data[11] |= (cpad->audio_codec << 4) & 0xf0; - data[11] |= (cpad->rate << 2) & 0x0c; - data[11] |= (cpad->width << 1) & 0x02; - data[11] |= (cpad->channels << 0) & 0x01; - - if (cpad->audio_codec == 10 && !cpad->sent_codec_data) { - data[12] = 0; - - memcpy (data + 11 + 1 + 1, GST_BUFFER_DATA (cpad->audio_codec_data), - GST_BUFFER_SIZE (cpad->audio_codec_data)); - second_run = TRUE; - } else if (cpad->audio_codec == 10) { - data[12] = 1; - - memcpy (data + 11 + 1 + 1, GST_BUFFER_DATA (buffer), - GST_BUFFER_SIZE (buffer)); - } else { - memcpy (data + 11 + 1, GST_BUFFER_DATA (buffer), - GST_BUFFER_SIZE (buffer)); - } - } - - GST_WRITE_UINT32_BE (data + size - 4, size - 4); - - gst_buffer_set_caps (tag, GST_PAD_CAPS (mux->srcpad)); - - if (second_run) { - second_run = FALSE; - cpad->sent_codec_data = TRUE; - - ret = gst_pad_push (mux->srcpad, tag); - if (ret != GST_FLOW_OK) { - gst_buffer_unref (buffer); - return ret; - } - - cpad->last_timestamp = timestamp; - - tag = NULL; - goto next; - } - - gst_buffer_copy_metadata (tag, buffer, GST_BUFFER_COPY_TIMESTAMPS); - GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) = - GST_BUFFER_OFFSET_NONE; - - gst_buffer_unref (buffer); - - ret = gst_pad_push (mux->srcpad, tag); - - if (ret == GST_FLOW_OK) - cpad->last_timestamp = timestamp; - - return ret; -} - -static GstFlowReturn -gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data) -{ - GstFlvMux *mux = GST_FLV_MUX (user_data); - GstFlvPad *best; - GstClockTime best_time; - GstFlowReturn ret; - GSList *sl; - gboolean eos = TRUE; - - if (mux->state == GST_FLV_MUX_STATE_HEADER) { - if (mux->collect->data == NULL) { - GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL), - ("No input streams configured")); - return GST_FLOW_ERROR; - } - - if (gst_pad_push_event (mux->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0))) - ret = gst_flv_mux_write_header (mux); - else - ret = GST_FLOW_ERROR; - - if (ret != GST_FLOW_OK) - return ret; - mux->state = GST_FLV_MUX_STATE_DATA; - } - - best = NULL; - best_time = GST_CLOCK_TIME_NONE; - for (sl = mux->collect->data; sl; sl = sl->next) { - GstFlvPad *cpad = sl->data; - GstBuffer *buffer = gst_collect_pads_peek (pads, (GstCollectData *) cpad); - GstClockTime time; - - if (!buffer) - continue; - - eos = FALSE; - - time = GST_BUFFER_TIMESTAMP (buffer); - gst_buffer_unref (buffer); - - /* Use buffers without valid timestamp first */ - if (!GST_CLOCK_TIME_IS_VALID (time)) { - GST_WARNING_OBJECT (pads, "Buffer without valid timestamp"); - - best_time = cpad->last_timestamp; - best = cpad; - break; - } - - - if (best == NULL || (GST_CLOCK_TIME_IS_VALID (best_time) - && time < best_time)) { - best = cpad; - best_time = time; - } - } - - if (GST_CLOCK_TIME_IS_VALID (best_time) - && best_time / GST_MSECOND > G_MAXUINT32) { - GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS"); - eos = TRUE; - } - - if (!eos && best) { - return gst_flv_mux_write_buffer (mux, best); - } else if (eos) { - gst_pad_push_event (mux->srcpad, gst_event_new_eos ()); - return GST_FLOW_UNEXPECTED; - } else { - return GST_FLOW_OK; - } -} - -static GstStateChangeReturn -gst_flv_mux_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstFlvMux *mux = GST_FLV_MUX (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_collect_pads_start (mux->collect); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_collect_pads_stop (mux->collect); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_flv_mux_reset (GST_ELEMENT (mux)); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} diff --git a/gst/flv/gstflvmux.h b/gst/flv/gstflvmux.h deleted file mode 100644 index 02df089d..00000000 --- a/gst/flv/gstflvmux.h +++ /dev/null @@ -1,89 +0,0 @@ -/* GStreamer - * - * Copyright (c) 2008 Sebastian Dröge - * - * 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_FLV_MUX_H__ -#define __GST_FLV_MUX_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_FLV_MUX \ - (gst_flv_mux_get_type ()) -#define GST_FLV_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FLV_MUX, GstFlvMux)) -#define GST_FLV_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FLV_MUX, GstFlvMuxClass)) -#define GST_IS_FLV_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FLV_MUX)) -#define GST_IS_FLV_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FLV_MUX)) - -typedef struct -{ - GstCollectData collect; - - gboolean video; - - guint audio_codec; - guint rate; - guint width; - guint channels; - GstBuffer *audio_codec_data; - - guint video_codec; - GstBuffer *video_codec_data; - - gboolean sent_codec_data; - GstClockTime last_timestamp; -} GstFlvPad; - -typedef enum -{ - GST_FLV_MUX_STATE_HEADER, - GST_FLV_MUX_STATE_DATA -} GstFlvMuxState; - -typedef struct _GstFlvMux { - GstElement element; - - GstPad *srcpad; - GstCollectPads *collect; - - /* */ - GstPadEventFunction collect_event; - - GstFlvMuxState state; - gboolean have_audio; - gboolean have_video; - - GstTagList *tags; -} GstFlvMux; - -typedef struct _GstFlvMuxClass { - GstElementClass parent; -} GstFlvMuxClass; - -GType gst_flv_mux_get_type (void); - -G_END_DECLS - -#endif /* __GST_FLV_MUX_H__ */ diff --git a/gst/flv/gstflvparse.c b/gst/flv/gstflvparse.c deleted file mode 100644 index 59446512..00000000 --- a/gst/flv/gstflvparse.c +++ /dev/null @@ -1,1283 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Julien Moutte - * - * 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. - */ - -#include "gstflvparse.h" - -#include - -#include - -GST_DEBUG_CATEGORY_EXTERN (flvdemux_debug); -#define GST_CAT_DEFAULT flvdemux_debug - -static gchar * -FLV_GET_STRING (GstByteReader * reader) -{ - guint16 string_size = 0; - gchar *string = NULL; - const guint8 *str; - - g_return_val_if_fail (reader != NULL, NULL); - - if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size))) - return NULL; - - if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader))) - return NULL; - - string = g_try_malloc0 (string_size + 1); - if (G_UNLIKELY (!string)) { - return NULL; - } - - if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) { - g_free (string); - return NULL; - } - - memcpy (string, str, string_size); - if (!g_utf8_validate (string, string_size, NULL)) { - g_free (string); - return NULL; - } - - return string; -} - -static const GstQueryType * -gst_flv_demux_query_types (GstPad * pad) -{ - static const GstQueryType query_types[] = { - GST_QUERY_DURATION, - 0 - }; - - return query_types; -} - -static void -parse_flv_date_string (GDate * date, const gchar * s) -{ - g_date_set_parse (date, s); - if (g_date_valid (date)) - return; - - /* "Fri Oct 15 15:13:16 2004" needs to be parsed */ - { - static const gchar *months[] = { - "Jan", "Feb", "Mar", "Apr", - "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" - }; - gchar **tokens = g_strsplit (s, " ", -1); - guint64 d; - gchar *endptr; - gint i; - - if (g_strv_length (tokens) != 5) - goto out; - - if (strlen (tokens[1]) != 3) - goto out; - for (i = 0; i < 12; i++) { - if (!strcmp (tokens[1], months[i])) { - break; - } - } - if (i == 12) - goto out; - g_date_set_month (date, i + 1); - - d = g_ascii_strtoull (tokens[2], &endptr, 10); - if (d == 0 && *endptr != '\0') - goto out; - - g_date_set_day (date, d); - - d = g_ascii_strtoull (tokens[4], &endptr, 10); - if (d == 0 && *endptr != '\0') - goto out; - - g_date_set_year (date, d); - - out: - if (tokens) - g_strfreev (tokens); - } -} - -static gboolean -gst_flv_parse_metadata_item (GstFLVDemux * demux, GstByteReader * reader, - gboolean * end_marker) -{ - gchar *tag_name = NULL; - guint8 tag_type = 0; - - /* Initialize the end_marker flag to FALSE */ - *end_marker = FALSE; - - /* Name of the tag */ - tag_name = FLV_GET_STRING (reader); - if (G_UNLIKELY (!tag_name)) { - GST_WARNING_OBJECT (demux, "failed reading tag name"); - return FALSE; - } - - /* What kind of object is that */ - if (!gst_byte_reader_get_uint8 (reader, &tag_type)) - goto error; - - GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type); - - switch (tag_type) { - case 0: // Double - { /* Use a union to read the uint64 and then as a double */ - gdouble d; - - if (!gst_byte_reader_get_float64_be (reader, &d)) - goto error; - - GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d); - - if (!strcmp (tag_name, "duration")) { - demux->duration = d * GST_SECOND; - - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_DURATION, demux->duration, NULL); - } else if (!strcmp (tag_name, "AspectRatioX")) { - demux->par_x = d; - demux->got_par = TRUE; - } else if (!strcmp (tag_name, "AspectRatioY")) { - demux->par_y = d; - demux->got_par = TRUE; - } else { - GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name); - } - - break; - } - case 1: // Boolean - { - guint8 b; - - if (!gst_byte_reader_get_uint8 (reader, &b)) - goto error; - - GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b); - - GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name); - - break; - } - case 2: // String - { - gchar *s = NULL; - - s = FLV_GET_STRING (reader); - if (s == NULL) - goto error; - - GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s); - - if (!strcmp (tag_name, "creationdate")) { - GDate *date = g_date_new (); - - parse_flv_date_string (date, s); - if (!g_date_valid (date)) { - GST_DEBUG_OBJECT (demux, "Failed to parse string as date"); - } else { - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_DATE, date, NULL); - } - g_date_free (date); - } else if (!strcmp (tag_name, "creator")) { - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_ARTIST, s, NULL); - } else if (!strcmp (tag_name, "title")) { - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_TITLE, s, NULL); - } else if (!strcmp (tag_name, "metadatacreator")) { - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_ENCODER, s, NULL); - } else { - GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name); - } - - g_free (s); - - break; - } - case 3: // Object - { - gboolean end_of_object_marker = FALSE; - - while (!end_of_object_marker) { - gboolean ok = - gst_flv_parse_metadata_item (demux, reader, &end_of_object_marker); - - if (G_UNLIKELY (!ok)) { - GST_WARNING_OBJECT (demux, "failed reading a tag, skipping"); - goto error; - } - } - - break; - } - case 8: // ECMA array - { - guint32 nb_elems; - gboolean end_of_object_marker = FALSE; - - if (!gst_byte_reader_get_uint32_be (reader, &nb_elems)) - goto error; - - GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array", - nb_elems); - - while (!end_of_object_marker) { - gboolean ok = - gst_flv_parse_metadata_item (demux, reader, &end_of_object_marker); - - if (G_UNLIKELY (!ok)) { - GST_WARNING_OBJECT (demux, "failed reading a tag, skipping"); - goto error; - } - } - - break; - } - case 9: // End marker - { - GST_DEBUG_OBJECT (demux, "end marker ?"); - if (tag_name[0] == '\0') { - - GST_DEBUG_OBJECT (demux, "end marker detected"); - - *end_marker = TRUE; - } - - break; - } - case 10: // Array - { - guint32 nb_elems; - - if (!gst_byte_reader_get_uint32_be (reader, &nb_elems)) - goto error; - - GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems); - - if (!strcmp (tag_name, "times")) { - if (demux->times) { - g_array_free (demux->times, TRUE); - } - demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble)); - } else if (!strcmp (tag_name, "filepositions")) { - if (demux->filepositions) { - g_array_free (demux->filepositions, TRUE); - } - demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble)); - } - - while (nb_elems--) { - guint8 elem_type; - - if (!gst_byte_reader_get_uint8 (reader, &elem_type)) - goto error; - - switch (elem_type) { - case 0: - { - gdouble d; - - if (!gst_byte_reader_get_float64_be (reader, &d)) - goto error; - - GST_DEBUG_OBJECT (demux, "element is a double %f", d); - - if (!strcmp (tag_name, "times") && demux->times) { - g_array_append_val (demux->times, d); - } else if (!strcmp (tag_name, "filepositions") && - demux->filepositions) { - g_array_append_val (demux->filepositions, d); - } - break; - } - default: - GST_WARNING_OBJECT (demux, "unsupported array element type %d", - elem_type); - } - } - - break; - } - case 11: // Date - { - gdouble d; - gint16 i; - - if (!gst_byte_reader_get_float64_be (reader, &d)) - goto error; - - if (!gst_byte_reader_get_int16_be (reader, &i)) - goto error; - - GST_DEBUG_OBJECT (demux, - "%s => (date as a double) %f, timezone offset %d", tag_name, d, i); - - GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name); - - break; - } - default: - GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type); - } - - g_free (tag_name); - - return TRUE; - -error: - g_free (tag_name); - - return FALSE; -} - -GstFlowReturn -gst_flv_parse_tag_script (GstFLVDemux * demux, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer); - guint8 type; - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 7, GST_FLOW_ERROR); - - gst_byte_reader_skip (&reader, 7); - - GST_LOG_OBJECT (demux, "parsing a script tag"); - - if (!gst_byte_reader_get_uint8 (&reader, &type)) - return GST_FLOW_OK; - - /* Must be string */ - if (type == 2) { - gchar *function_name; - guint i; - - function_name = FLV_GET_STRING (&reader); - - GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name)); - - if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) { - guint32 nb_elems = 0; - gboolean end_marker = FALSE; - - GST_DEBUG_OBJECT (demux, "we have a metadata script object"); - - /* Next type must be a ECMA array */ - if (!gst_byte_reader_get_uint8 (&reader, &type) || type != 8) { - g_free (function_name); - return GST_FLOW_OK; - } - - if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) { - g_free (function_name); - return GST_FLOW_OK; - } - - GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array", - nb_elems); - - while (nb_elems-- && !end_marker) { - gboolean ok = gst_flv_parse_metadata_item (demux, &reader, &end_marker); - - if (G_UNLIKELY (!ok)) { - GST_WARNING_OBJECT (demux, "failed reading a tag, skipping"); - break; - } - } - - demux->push_tags = TRUE; - } - - g_free (function_name); - - if (demux->index && demux->times && demux->filepositions - && !demux->random_access) { - /* If an index was found and we're in push mode, insert associations */ - for (i = 0; i < MIN (demux->times->len, demux->filepositions->len); i++) { - guint64 time, fileposition; - - time = g_array_index (demux->times, gdouble, i) * GST_SECOND; - fileposition = g_array_index (demux->filepositions, gdouble, i); - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (time), fileposition); - gst_index_add_association (demux->index, demux->index_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time, - GST_FORMAT_BYTES, fileposition, NULL); - } - } - } - - return ret; -} - -static gboolean -gst_flv_parse_audio_negotiate (GstFLVDemux * demux, guint32 codec_tag, - guint32 rate, guint32 channels, guint32 width) -{ - GstCaps *caps = NULL; - gchar *codec_name = NULL; - gboolean ret = FALSE; - - switch (codec_tag) { - case 1: - caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING, - "swf", NULL); - codec_name = "Shockwave ADPCM"; - break; - case 2: - case 14: - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, - "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - codec_name = "MPEG 1 Audio, Layer 3 (MP3)"; - break; - case 0: - case 3: - /* Assuming little endian for 0 (aka endianness of the - * system on which the file was created) as most people - * are probably using little endian machines */ - caps = gst_caps_new_simple ("audio/x-raw-int", - "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, - "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE, - "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL); - codec_name = "Raw Audio"; - break; - case 4: - case 5: - case 6: - caps = gst_caps_new_simple ("audio/x-nellymoser", NULL); - codec_name = "Nellymoser ASAO"; - break; - case 10: - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL); - codec_name = "AAC"; - break; - case 7: - caps = gst_caps_new_simple ("audio/x-alaw", NULL); - codec_name = "A-Law"; - break; - case 8: - caps = gst_caps_new_simple ("audio/x-mulaw", NULL); - codec_name = "Mu-Law"; - break; - case 11: - caps = gst_caps_new_simple ("audio/x-speex", NULL); - codec_name = "Speex"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for audio pad"); - goto beach; - } - - gst_caps_set_simple (caps, - "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); - - if (demux->audio_codec_data) { - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, - demux->audio_codec_data, NULL); - } - - ret = gst_pad_set_caps (demux->audio_pad, caps); - - if (G_LIKELY (ret)) { - /* Store the caps we have set */ - demux->audio_codec_tag = codec_tag; - demux->rate = rate; - demux->channels = channels; - demux->width = width; - - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec_name, NULL); - } - - GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %" - GST_PTR_FORMAT, caps); - } else { - GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %" - GST_PTR_FORMAT, caps); - } - - gst_caps_unref (caps); - -beach: - return ret; -} - -GstFlowReturn -gst_flv_parse_tag_audio (GstFLVDemux * demux, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1; - guint32 codec_data = 0, pts_ext = 0; - guint8 flags = 0; - guint8 *data = GST_BUFFER_DATA (buffer); - GstBuffer *outbuf; - - GST_LOG_OBJECT (demux, "parsing an audio tag"); - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size, - GST_FLOW_ERROR); - - GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1], - data[2], data[3]); - - /* Grab information about audio tag */ - pts = GST_READ_UINT24_BE (data); - /* read the pts extension to 32 bits integer */ - pts_ext = GST_READ_UINT8 (data + 3); - /* Combine them */ - pts |= pts_ext << 24; - - if (GST_BUFFER_SIZE (buffer) < 12) { - GST_ERROR_OBJECT (demux, "Too small tag size"); - return GST_FLOW_ERROR; - } - - /* Skip the stream id and go directly to the flags */ - flags = GST_READ_UINT8 (data + 7); - - /* Channels */ - if (flags & 0x01) { - channels = 2; - } - /* Width */ - if (flags & 0x02) { - width = 16; - } - /* Sampling rate */ - if ((flags & 0x0C) == 0x0C) { - rate = 44100; - } else if ((flags & 0x0C) == 0x08) { - rate = 22050; - } else if ((flags & 0x0C) == 0x04) { - rate = 11025; - } - /* Codec tag */ - codec_tag = flags >> 4; - if (codec_tag == 10) { /* AAC has an extra byte for packet type */ - codec_data = 2; - } else { - codec_data = 1; - } - - /* codec tags with special rates */ - if (codec_tag == 5 || codec_tag == 14) - rate = 8000; - else if (codec_tag == 4) - rate = 16000; - - GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, " - "%d bits width, codec tag %u (flags %02X)", channels, rate, width, - codec_tag, flags); - - /* If we don't have our audio pad created, then create it. */ - if (G_UNLIKELY (!demux->audio_pad)) { - - demux->audio_pad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio"); - if (G_UNLIKELY (!demux->audio_pad)) { - GST_WARNING_OBJECT (demux, "failed creating audio pad"); - ret = GST_FLOW_ERROR; - goto beach; - } - - /* Negotiate caps */ - if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, - width)) { - gst_object_unref (demux->audio_pad); - demux->audio_pad = NULL; - ret = GST_FLOW_ERROR; - goto beach; - } - - GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT, - GST_PAD_CAPS (demux->audio_pad)); - - /* Set functions on the pad */ - gst_pad_set_query_type_function (demux->audio_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_query_types)); - gst_pad_set_query_function (demux->audio_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_query)); - gst_pad_set_event_function (demux->audio_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_src_event)); - - gst_pad_use_fixed_caps (demux->audio_pad); - - /* Make it active */ - gst_pad_set_active (demux->audio_pad, TRUE); - - /* We need to set caps before adding */ - gst_element_add_pad (GST_ELEMENT (demux), - gst_object_ref (demux->audio_pad)); - - /* We only emit no more pads when we have audio and video. Indeed we can - * not trust the FLV header to tell us if there will be only audio or - * only video and we would just break discovery of some files */ - if (demux->audio_pad && demux->video_pad) { - GST_DEBUG_OBJECT (demux, "emitting no more pads"); - gst_element_no_more_pads (GST_ELEMENT (demux)); - } - } - - /* Check if caps have changed */ - if (G_UNLIKELY (rate != demux->rate || channels != demux->channels || - codec_tag != demux->audio_codec_tag || width != demux->width)) { - GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps"); - - /* Negotiate caps */ - if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, - width)) { - ret = GST_FLOW_ERROR; - goto beach; - } - } - - /* Push taglist if present */ - if ((demux->has_audio && !demux->audio_pad) && - (demux->has_video && !demux->video_pad)) { - GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up " - "before we can push tags"); - } else { - if (demux->taglist && demux->push_tags) { - GST_DEBUG_OBJECT (demux, "pushing tags out"); - gst_element_found_tags (GST_ELEMENT (demux), demux->taglist); - demux->taglist = gst_tag_list_new (); - demux->push_tags = FALSE; - } - } - - /* Check if we have anything to push */ - if (demux->tag_data_size <= codec_data) { - GST_LOG_OBJECT (demux, "Nothing left in this tag, returning"); - goto beach; - } - - /* Create buffer from pad */ - outbuf = - gst_buffer_create_sub (buffer, 7 + codec_data, - demux->tag_data_size - codec_data); - - if (demux->audio_codec_tag == 10) { - guint8 aac_packet_type = GST_READ_UINT8 (data + 8); - - switch (aac_packet_type) { - case 0: - { - /* AudioSpecificConfic data */ - GST_LOG_OBJECT (demux, "got an AAC codec data packet"); - if (demux->audio_codec_data) { - gst_buffer_unref (demux->audio_codec_data); - } - demux->audio_codec_data = outbuf; - /* Use that buffer data in the caps */ - gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width); - goto beach; - break; - } - case 1: - /* AAC raw packet */ - GST_LOG_OBJECT (demux, "got a raw AAC audio packet"); - break; - default: - GST_WARNING_OBJECT (demux, "invalid AAC packet type %u", - aac_packet_type); - } - } - - /* Fill buffer with data */ - GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND; - GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++; - GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->audio_pad)); - - if (demux->duration == GST_CLOCK_TIME_NONE || - demux->duration < GST_BUFFER_TIMESTAMP (outbuf)) - demux->duration = GST_BUFFER_TIMESTAMP (outbuf); - - /* Only add audio frames to the index if we have no video - * and if we don't have random access */ - if (!demux->has_video && demux->index && !demux->random_access) { - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - demux->cur_tag_offset); - gst_index_add_association (demux->index, demux->index_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), - GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); - } - - if (G_UNLIKELY (demux->audio_need_discont)) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - demux->audio_need_discont = FALSE; - } - - gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (outbuf)); - - /* Do we need a newsegment event ? */ - if (G_UNLIKELY (demux->audio_need_segment)) { - if (demux->close_seg_event) - gst_pad_push_event (demux->audio_pad, - gst_event_ref (demux->close_seg_event)); - - if (!demux->new_seg_event) { - GST_DEBUG_OBJECT (demux, "pushing newsegment from %" - GST_TIME_FORMAT " to %" GST_TIME_FORMAT, - GST_TIME_ARGS (demux->segment.last_stop), - GST_TIME_ARGS (demux->segment.stop)); - demux->new_seg_event = - gst_event_new_new_segment (FALSE, demux->segment.rate, - demux->segment.format, demux->segment.last_stop, - demux->segment.stop, demux->segment.last_stop); - } else { - GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event"); - } - - gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event)); - - demux->audio_need_segment = FALSE; - } - - GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT - " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf)); - - /* Push downstream */ - ret = gst_pad_push (demux->audio_pad, outbuf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT - " bytes audio buffer: %s", demux->tag_data_size, - gst_flow_get_name (ret)); - if (ret == GST_FLOW_NOT_LINKED) { - demux->audio_linked = FALSE; - } - goto beach; - } - - demux->audio_linked = TRUE; - -beach: - return ret; -} - -static gboolean -gst_flv_parse_video_negotiate (GstFLVDemux * demux, guint32 codec_tag) -{ - gboolean ret = FALSE; - GstCaps *caps = NULL; - gchar *codec_name = NULL; - - /* Generate caps for that pad */ - switch (codec_tag) { - case 2: - caps = gst_caps_new_simple ("video/x-flash-video", NULL); - codec_name = "Sorenson Video"; - break; - case 3: - caps = gst_caps_new_simple ("video/x-flash-screen", NULL); - codec_name = "Flash Screen Video"; - case 4: - caps = gst_caps_new_simple ("video/x-vp6-flash", NULL); - codec_name = "On2 VP6 Video"; - break; - case 5: - caps = gst_caps_new_simple ("video/x-vp6-alpha", NULL); - codec_name = "On2 VP6 Video with alpha channel"; - break; - case 7: - caps = gst_caps_new_simple ("video/x-h264", NULL); - codec_name = "H.264/AVC Video"; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag); - } - - if (G_UNLIKELY (!caps)) { - GST_WARNING_OBJECT (demux, "failed creating caps for video pad"); - goto beach; - } - - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - demux->par_x, demux->par_y, NULL); - - if (demux->video_codec_data) { - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, - demux->video_codec_data, NULL); - } - - ret = gst_pad_set_caps (demux->video_pad, caps); - - if (G_LIKELY (ret)) { - /* Store the caps we have set */ - demux->video_codec_tag = codec_tag; - - if (codec_name) { - if (demux->taglist == NULL) - demux->taglist = gst_tag_list_new (); - gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_VIDEO_CODEC, codec_name, NULL); - } - - GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %" - GST_PTR_FORMAT, caps); - } else { - GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %" - GST_PTR_FORMAT, caps); - } - - gst_caps_unref (caps); - -beach: - return ret; -} - -GstFlowReturn -gst_flv_parse_tag_video (GstFLVDemux * demux, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint32 pts = 0, codec_data = 1, pts_ext = 0; - gboolean keyframe = FALSE; - guint8 flags = 0, codec_tag = 0; - guint8 *data = GST_BUFFER_DATA (buffer); - GstBuffer *outbuf; - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size, - GST_FLOW_ERROR); - - GST_LOG_OBJECT (demux, "parsing a video tag"); - - GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1], - data[2], data[3]); - - /* Grab information about video tag */ - pts = GST_READ_UINT24_BE (data); - /* read the pts extension to 32 bits integer */ - pts_ext = GST_READ_UINT8 (data + 3); - /* Combine them */ - pts |= pts_ext << 24; - - if (GST_BUFFER_SIZE (buffer) < 12) { - GST_ERROR_OBJECT (demux, "Too small tag size"); - return GST_FLOW_ERROR; - } - - /* Skip the stream id and go directly to the flags */ - flags = GST_READ_UINT8 (data + 7); - - /* Keyframe */ - if ((flags >> 4) == 1) { - keyframe = TRUE; - } - /* Codec tag */ - codec_tag = flags & 0x0F; - if (codec_tag == 4 || codec_tag == 5) { - codec_data = 2; - } else if (codec_tag == 7) { - codec_data = 5; - } - - GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) " - "(flags %02X)", codec_tag, keyframe, flags); - - /* If we don't have our video pad created, then create it. */ - if (G_UNLIKELY (!demux->video_pad)) { - demux->video_pad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_GET_CLASS (demux), "video"), "video"); - if (G_UNLIKELY (!demux->video_pad)) { - GST_WARNING_OBJECT (demux, "failed creating video pad"); - ret = GST_FLOW_ERROR; - goto beach; - } - - if (!gst_flv_parse_video_negotiate (demux, codec_tag)) { - gst_object_unref (demux->video_pad); - demux->video_pad = NULL; - ret = GST_FLOW_ERROR; - goto beach; - } - - /* When we ve set pixel-aspect-ratio we use that boolean to detect a - * metadata tag that would come later and trigger a caps change */ - demux->got_par = FALSE; - - GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT, - GST_PAD_CAPS (demux->video_pad)); - - /* Set functions on the pad */ - gst_pad_set_query_type_function (demux->video_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_query_types)); - gst_pad_set_query_function (demux->video_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_query)); - gst_pad_set_event_function (demux->video_pad, - GST_DEBUG_FUNCPTR (gst_flv_demux_src_event)); - - gst_pad_use_fixed_caps (demux->video_pad); - - /* Make it active */ - gst_pad_set_active (demux->video_pad, TRUE); - - /* We need to set caps before adding */ - gst_element_add_pad (GST_ELEMENT (demux), - gst_object_ref (demux->video_pad)); - - /* We only emit no more pads when we have audio and video. Indeed we can - * not trust the FLV header to tell us if there will be only audio or - * only video and we would just break discovery of some files */ - if (demux->audio_pad && demux->video_pad) { - GST_DEBUG_OBJECT (demux, "emitting no more pads"); - gst_element_no_more_pads (GST_ELEMENT (demux)); - } - } - - /* Check if caps have changed */ - if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) { - - GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps"); - - if (!gst_flv_parse_video_negotiate (demux, codec_tag)) { - ret = GST_FLOW_ERROR; - goto beach; - } - - /* When we ve set pixel-aspect-ratio we use that boolean to detect a - * metadata tag that would come later and trigger a caps change */ - demux->got_par = FALSE; - } - - /* Push taglist if present */ - if ((demux->has_audio && !demux->audio_pad) && - (demux->has_video && !demux->video_pad)) { - GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up " - "before we can push tags"); - } else { - if (demux->taglist && demux->push_tags) { - GST_DEBUG_OBJECT (demux, "pushing tags out"); - gst_element_found_tags (GST_ELEMENT (demux), demux->taglist); - demux->taglist = gst_tag_list_new (); - demux->push_tags = FALSE; - } - } - - /* Check if we have anything to push */ - if (demux->tag_data_size <= codec_data) { - GST_LOG_OBJECT (demux, "Nothing left in this tag, returning"); - goto beach; - } - - /* Create buffer from pad */ - outbuf = - gst_buffer_create_sub (buffer, 7 + codec_data, - demux->tag_data_size - codec_data); - - if (demux->video_codec_tag == 7) { - guint8 avc_packet_type = GST_READ_UINT8 (data + 8); - - switch (avc_packet_type) { - case 0: - { - /* AVCDecoderConfigurationRecord data */ - GST_LOG_OBJECT (demux, "got an H.264 codec data packet"); - if (demux->video_codec_data) { - gst_buffer_unref (demux->video_codec_data); - } - demux->video_codec_data = outbuf; - /* Use that buffer data in the caps */ - gst_flv_parse_video_negotiate (demux, codec_tag); - goto beach; - break; - } - case 1: - /* H.264 NALU packet */ - GST_LOG_OBJECT (demux, "got a H.264 NALU audio packet"); - break; - default: - GST_WARNING_OBJECT (demux, "invalid AAC packet type %u", - avc_packet_type); - } - } - - /* Fill buffer with data */ - GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND; - GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (outbuf) = demux->video_offset++; - GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset; - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->video_pad)); - - if (demux->duration == GST_CLOCK_TIME_NONE || - demux->duration < GST_BUFFER_TIMESTAMP (outbuf)) - demux->duration = GST_BUFFER_TIMESTAMP (outbuf); - - if (!keyframe) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - if (demux->index && !demux->random_access) { - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - demux->cur_tag_offset); - gst_index_add_association (demux->index, demux->index_id, - GST_ASSOCIATION_FLAG_NONE, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), - GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); - } - } else { - if (demux->index && !demux->random_access) { - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - demux->cur_tag_offset); - gst_index_add_association (demux->index, demux->index_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), - GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); - } - } - - if (G_UNLIKELY (demux->video_need_discont)) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - demux->video_need_discont = FALSE; - } - - gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (outbuf)); - - /* Do we need a newsegment event ? */ - if (G_UNLIKELY (demux->video_need_segment)) { - if (demux->close_seg_event) - gst_pad_push_event (demux->video_pad, - gst_event_ref (demux->close_seg_event)); - - if (!demux->new_seg_event) { - GST_DEBUG_OBJECT (demux, "pushing newsegment from %" - GST_TIME_FORMAT " to %" GST_TIME_FORMAT, - GST_TIME_ARGS (demux->segment.last_stop), - GST_TIME_ARGS (demux->segment.stop)); - demux->new_seg_event = - gst_event_new_new_segment (FALSE, demux->segment.rate, - demux->segment.format, demux->segment.last_stop, - demux->segment.stop, demux->segment.last_stop); - } else { - GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event"); - } - - gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event)); - - demux->video_need_segment = FALSE; - } - - GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT - " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT - ", keyframe (%d)", GST_BUFFER_SIZE (outbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf), - keyframe); - - /* Push downstream */ - ret = gst_pad_push (demux->video_pad, outbuf); - - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT - " bytes video buffer: %s", demux->tag_data_size, - gst_flow_get_name (ret)); - if (ret == GST_FLOW_NOT_LINKED) { - demux->video_linked = FALSE; - } - goto beach; - } - - demux->video_linked = TRUE; - -beach: - return ret; -} - -GstClockTime -gst_flv_parse_tag_timestamp (GstFLVDemux * demux, GstBuffer * buffer, - size_t * tag_size) -{ - guint32 pts = 0, pts_ext = 0; - guint32 tag_data_size; - guint8 type; - gboolean keyframe = TRUE; - GstClockTime ret; - guint8 *data = GST_BUFFER_DATA (buffer); - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 12, GST_CLOCK_TIME_NONE); - - type = data[0]; - - if (type != 9 && type != 8 && type != 18) { - GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]); - return GST_CLOCK_TIME_NONE; - } - - if (type == 9) - demux->has_video = TRUE; - else if (type == 8) - demux->has_audio = TRUE; - - tag_data_size = GST_READ_UINT24_BE (data + 1); - - if (GST_BUFFER_SIZE (buffer) >= tag_data_size + 11 + 4) { - if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) { - GST_WARNING_OBJECT (demux, "Invalid tag size"); - return GST_CLOCK_TIME_NONE; - } - } - - if (tag_size) - *tag_size = tag_data_size + 11 + 4; - - data += 4; - - GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1], - data[2], data[3]); - - /* Grab timestamp of tag tag */ - pts = GST_READ_UINT24_BE (data); - /* read the pts extension to 32 bits integer */ - pts_ext = GST_READ_UINT8 (data + 3); - /* Combine them */ - pts |= pts_ext << 24; - - if (type == 9) { - data += 7; - - keyframe = ((data[0] >> 4) == 1); - } - - ret = pts * GST_MSECOND; - - if (demux->index && (type == 9 || (type == 8 && !demux->has_video))) { - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (ret), demux->offset); - gst_index_add_association (demux->index, demux->index_id, - (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE, - GST_FORMAT_TIME, ret, GST_FORMAT_BYTES, demux->offset, NULL); - } - - if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret) - demux->duration = ret; - - return ret; -} - -GstFlowReturn -gst_flv_parse_tag_type (GstFLVDemux * demux, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint8 tag_type = 0; - guint8 *data = GST_BUFFER_DATA (buffer); - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 4, GST_FLOW_ERROR); - - tag_type = data[0]; - - switch (tag_type) { - case 9: - demux->state = FLV_STATE_TAG_VIDEO; - demux->has_video = TRUE; - break; - case 8: - demux->state = FLV_STATE_TAG_AUDIO; - demux->has_audio = TRUE; - break; - case 18: - demux->state = FLV_STATE_TAG_SCRIPT; - break; - default: - GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type); - } - - /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size + - * 4 bytes of previous tag size */ - demux->tag_data_size = GST_READ_UINT24_BE (data + 1); - demux->tag_size = demux->tag_data_size + 11; - - GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT, - demux->tag_data_size); - - return ret; -} - -GstFlowReturn -gst_flv_parse_header (GstFLVDemux * demux, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint8 *data = GST_BUFFER_DATA (buffer); - - g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 9, GST_FLOW_ERROR); - - /* Check for the FLV tag */ - if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') { - GST_DEBUG_OBJECT (demux, "FLV header detected"); - } else { - if (G_UNLIKELY (demux->strict)) { - GST_WARNING_OBJECT (demux, "invalid header tag detected"); - ret = GST_FLOW_UNEXPECTED; - goto beach; - } - } - - /* Jump over the 4 first bytes */ - data += 4; - - /* Now look at audio/video flags */ - { - guint8 flags = data[0]; - - demux->has_video = demux->has_audio = FALSE; - - if (flags & 1) { - GST_DEBUG_OBJECT (demux, "there is a video stream"); - demux->has_video = TRUE; - } - if (flags & 4) { - GST_DEBUG_OBJECT (demux, "there is an audio stream"); - demux->has_audio = TRUE; - } - } - - /* We don't care about the rest */ - demux->need_header = FALSE; - -beach: - return ret; -} diff --git a/gst/flv/gstflvparse.h b/gst/flv/gstflvparse.h deleted file mode 100644 index 203d30de..00000000 --- a/gst/flv/gstflvparse.h +++ /dev/null @@ -1,42 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Julien Moutte - * - * 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 __FLV_PARSE_H__ -#define __FLV_PARSE_H__ - -#include "gstflvdemux.h" - -G_BEGIN_DECLS - - -GstFlowReturn gst_flv_parse_tag_script (GstFLVDemux * demux, - GstBuffer *buffer); - -GstFlowReturn gst_flv_parse_tag_audio (GstFLVDemux * demux, GstBuffer *buffer); - -GstFlowReturn gst_flv_parse_tag_video (GstFLVDemux * demux, GstBuffer *buffer); - -GstFlowReturn gst_flv_parse_tag_type (GstFLVDemux * demux, GstBuffer *buffer); - -GstFlowReturn gst_flv_parse_header (GstFLVDemux * demux, GstBuffer *buffer); - -GstClockTime gst_flv_parse_tag_timestamp (GstFLVDemux *demux, GstBuffer *buffer, size_t *tag_data_size); - -G_END_DECLS -#endif /* __FLV_PARSE_H__ */ -- cgit v1.2.1 From 453794d38315c2491ddc2ced3cc867bdafb910d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 13 May 2009 10:47:23 +0200 Subject: Moved 'deinterlace2' from -bad to -good And remove old deinterlace plugin as deinterlace2 will be called deinterlace in -good. --- gst/deinterlace/.gitignore | 7 - gst/deinterlace/Makefile.am | 12 - gst/deinterlace/deinterlace.vcproj | 148 -- gst/deinterlace/gstdeinterlace.c | 514 ------- gst/deinterlace/gstdeinterlace.h | 74 - gst/deinterlace2/Makefile.am | 48 - gst/deinterlace2/gstdeinterlace2.c | 1517 -------------------- gst/deinterlace2/gstdeinterlace2.h | 259 ---- gst/deinterlace2/tvtime/greedy.c | 488 ------- gst/deinterlace2/tvtime/greedyh.asm | 250 ---- gst/deinterlace2/tvtime/greedyh.c | 420 ------ gst/deinterlace2/tvtime/greedyhmacros.h | 75 - gst/deinterlace2/tvtime/linear.c | 214 --- gst/deinterlace2/tvtime/linearblend.c | 231 --- gst/deinterlace2/tvtime/mmx.h | 723 ---------- gst/deinterlace2/tvtime/plugins.h | 54 - gst/deinterlace2/tvtime/scalerbob.c | 74 - gst/deinterlace2/tvtime/sse.h | 992 ------------- gst/deinterlace2/tvtime/tomsmocomp.c | 211 --- .../tvtime/tomsmocomp/SearchLoop0A.inc | 15 - .../tvtime/tomsmocomp/SearchLoopBottom.inc | 174 --- .../tvtime/tomsmocomp/SearchLoopEdgeA.inc | 11 - .../tvtime/tomsmocomp/SearchLoopEdgeA8.inc | 12 - .../tvtime/tomsmocomp/SearchLoopOddA.inc | 10 - .../tvtime/tomsmocomp/SearchLoopOddA2.inc | 5 - .../tvtime/tomsmocomp/SearchLoopOddA6.inc | 11 - .../tvtime/tomsmocomp/SearchLoopOddAH.inc | 10 - .../tvtime/tomsmocomp/SearchLoopOddAH2.inc | 5 - .../tvtime/tomsmocomp/SearchLoopTop.inc | 254 ---- .../tvtime/tomsmocomp/SearchLoopVA.inc | 6 - .../tvtime/tomsmocomp/SearchLoopVAH.inc | 6 - gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc | 435 ------ .../tvtime/tomsmocomp/TomsMoCompAll.inc | 241 ---- .../tvtime/tomsmocomp/TomsMoCompAll2.inc | 243 ---- gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc | 286 ---- .../tvtime/tomsmocomp/tomsmocompmacros.h | 164 --- gst/deinterlace2/tvtime/vfir.c | 187 --- gst/deinterlace2/tvtime/weave.c | 82 -- gst/deinterlace2/tvtime/weavebff.c | 88 -- gst/deinterlace2/tvtime/weavetff.c | 88 -- gst/deinterlace2/tvtime/x86-64_macros.inc | 82 -- 41 files changed, 8726 deletions(-) delete mode 100644 gst/deinterlace/.gitignore delete mode 100644 gst/deinterlace/Makefile.am delete mode 100644 gst/deinterlace/deinterlace.vcproj delete mode 100644 gst/deinterlace/gstdeinterlace.c delete mode 100644 gst/deinterlace/gstdeinterlace.h delete mode 100644 gst/deinterlace2/Makefile.am delete mode 100644 gst/deinterlace2/gstdeinterlace2.c delete mode 100644 gst/deinterlace2/gstdeinterlace2.h delete mode 100644 gst/deinterlace2/tvtime/greedy.c delete mode 100644 gst/deinterlace2/tvtime/greedyh.asm delete mode 100644 gst/deinterlace2/tvtime/greedyh.c delete mode 100644 gst/deinterlace2/tvtime/greedyhmacros.h delete mode 100644 gst/deinterlace2/tvtime/linear.c delete mode 100644 gst/deinterlace2/tvtime/linearblend.c delete mode 100644 gst/deinterlace2/tvtime/mmx.h delete mode 100644 gst/deinterlace2/tvtime/plugins.h delete mode 100644 gst/deinterlace2/tvtime/scalerbob.c delete mode 100644 gst/deinterlace2/tvtime/sse.h delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp.c delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc delete mode 100644 gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h delete mode 100644 gst/deinterlace2/tvtime/vfir.c delete mode 100644 gst/deinterlace2/tvtime/weave.c delete mode 100644 gst/deinterlace2/tvtime/weavebff.c delete mode 100644 gst/deinterlace2/tvtime/weavetff.c delete mode 100644 gst/deinterlace2/tvtime/x86-64_macros.inc (limited to 'gst') diff --git a/gst/deinterlace/.gitignore b/gst/deinterlace/.gitignore deleted file mode 100644 index 08f5ed37..00000000 --- a/gst/deinterlace/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -Makefile -Makefile.in -*.o -*.lo -*.la -.deps -.libs diff --git a/gst/deinterlace/Makefile.am b/gst/deinterlace/Makefile.am deleted file mode 100644 index 3d842d01..00000000 --- a/gst/deinterlace/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -plugin_LTLIBRARIES = libgstdeinterlace.la - -libgstdeinterlace_la_SOURCES = gstdeinterlace.c -libgstdeinterlace_la_CFLAGS = \ - $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -libgstdeinterlace_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS) -libgstdeinterlace_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstdeinterlace_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstdeinterlace.h - diff --git a/gst/deinterlace/deinterlace.vcproj b/gst/deinterlace/deinterlace.vcproj deleted file mode 100644 index 200d88ee..00000000 --- a/gst/deinterlace/deinterlace.vcproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c deleted file mode 100644 index b2a25afe..00000000 --- a/gst/deinterlace/gstdeinterlace.c +++ /dev/null @@ -1,514 +0,0 @@ -/* GStreamer simple deinterlacing plugin - * Copyright (C) 1999 Erik Walthinsen - * Copyright (C) 2006-2008 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. - */ -/* based on the Area Based Deinterlacer (for RGB frames) */ -/* (a VirtualDub filter) from Gunnar Thalin */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstdeinterlace.h" -#include - -/** - * SECTION:element-deinterlace - * - * Adaptively deinterlaces video frames by detecting interlacing artifacts. - * An edge detection matrix is used, with a threshold value. Pixels detected - * as 'interlaced' are replaced with pixels blended from the pixels above and - * below. - * - * - * Example launch line - * |[ - * gst-launch -v videotestsrc ! deinterlace ! ffmpegcolorspace ! xvimagesink - * ]| - * - */ - -GST_DEBUG_CATEGORY_STATIC (deinterlace_debug); -#define GST_CAT_DEFAULT deinterlace_debug - -#define DEFAULT_DI_AREA_ONLY FALSE -#define DEFAULT_NI_AREA_ONLY FALSE -#define DEFAULT_BLEND FALSE -#define DEFAULT_DEINTERLACE TRUE -#define DEFAULT_THRESHOLD 20 -#define DEFAULT_EDGE_DETECT 25 - -enum -{ - ARG_0, - ARG_DI_ONLY, - ARG_NI_ONLY, - ARG_BLEND, - ARG_THRESHOLD, - ARG_EDGE_DETECT, - ARG_DEINTERLACE -}; - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, Y42B }")) - ); - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, Y42B }")) - ); - -GST_BOILERPLATE (GstDeinterlace, gst_deinterlace, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM); - -static void gst_deinterlace_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_deinterlace_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static GstFlowReturn gst_deinterlace_transform_ip (GstBaseTransform * trans, - GstBuffer * buf); -static gboolean gst_deinterlace_stop (GstBaseTransform * trans); -static gboolean gst_deinterlace_set_caps (GstBaseTransform * trans, - GstCaps * incaps, GstCaps * outcaps); -static GstCaps *gst_deinterlace_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * incaps); - -static void -gst_deinterlace_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); - - gst_element_class_set_details_simple (element_class, "Deinterlace", - "Filter/Effect/Video", "Deinterlace video", - "Wim Taymans "); -} - -static void -gst_deinterlace_class_init (GstDeinterlaceClass * klass) -{ - GObjectClass *gobject_class; - GstBaseTransformClass *basetransform_class; - - gobject_class = (GObjectClass *) klass; - basetransform_class = (GstBaseTransformClass *) klass; - - gobject_class->set_property = gst_deinterlace_set_property; - gobject_class->get_property = gst_deinterlace_get_property; - - /** - * GstDeinterlace:deinterlace: - * - * Turn processing on/off. When false, no modification of the - * video frames occurs and they pass through intact. - */ - g_object_class_install_property (gobject_class, ARG_DEINTERLACE, - g_param_spec_boolean ("deinterlace", "deinterlace", - "turn deinterlacing on/off", DEFAULT_DEINTERLACE, G_PARAM_READWRITE)); - /** - * GstDeinterlace:di-area-only: - * - * When set to true, only areas affected by the deinterlacing are output, - * making it easy to see which regions are being modified. - * - * See Also: #GstDeinterlace:ni-area-only - */ - g_object_class_install_property (gobject_class, ARG_DI_ONLY, - g_param_spec_boolean ("di-area-only", "di-area-only", - "displays deinterlaced areas only", DEFAULT_DI_AREA_ONLY, - G_PARAM_READWRITE)); - /** - * GstDeinterlace:ni-area-only: - * - * When set to true, only areas unaffected by the deinterlacing are output, - * making it easy to see which regions are being preserved intact. - * - * See Also: #GstDeinterlace:di-area-only - */ - g_object_class_install_property (gobject_class, ARG_NI_ONLY, - g_param_spec_boolean ("ni-area-only", "ni-area-only", - "displays non-interlaced areas only", DEFAULT_DI_AREA_ONLY, - G_PARAM_READWRITE)); - /** - * GstDeinterlace:blend: - * - * Change the blending for pixels which are detected as - * 'interlacing artifacts'. When true, the output pixel is a weighted - * average (1,2,1) of the pixel and the pixels above and below it. - * When false, the odd field lines are preserved, and the even field lines - * are averaged from the surrounding pixels above and below (the odd field). - */ - g_object_class_install_property (gobject_class, ARG_BLEND, - g_param_spec_boolean ("blend", "blend", "blend", DEFAULT_BLEND, - G_PARAM_READWRITE)); - /** - * GstDeinterlace:threshold: - * - * Affects the threshold of the edge-detection function used for detecting - * interlacing artifacts. - */ - g_object_class_install_property (gobject_class, ARG_THRESHOLD, - g_param_spec_int ("threshold", "Edge-detection threshold", - "Threshold value for the interlacing artifacts in the output " - "of the edge detection", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); - /** - * GstDeinterlace:edge-detect: - * - * Affects the weighting of the edge-detection function used for detecting - * interlacing artifacts. - */ - g_object_class_install_property (gobject_class, ARG_EDGE_DETECT, - g_param_spec_int ("edge-detect", "edge detection weighting", - "Weighting value used for calculating the edge detection matrix", - G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); - - basetransform_class->transform_ip = - GST_DEBUG_FUNCPTR (gst_deinterlace_transform_ip); - basetransform_class->transform_caps = - GST_DEBUG_FUNCPTR (gst_deinterlace_transform_caps); - basetransform_class->stop = GST_DEBUG_FUNCPTR (gst_deinterlace_stop); - basetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_deinterlace_set_caps); -} - -static void -gst_deinterlace_init (GstDeinterlace * filter, GstDeinterlaceClass * klass) -{ - filter->show_deinterlaced_area_only = DEFAULT_DI_AREA_ONLY; - filter->show_noninterlaced_area_only = DEFAULT_NI_AREA_ONLY; - filter->blend = DEFAULT_BLEND; - filter->deinterlace = DEFAULT_DEINTERLACE; - filter->threshold = DEFAULT_THRESHOLD; - filter->edge_detect = DEFAULT_EDGE_DETECT; - /*filter->threshold_blend = 0; */ - - filter->src = NULL; - filter->picsize = 0; -} - -static gboolean -gst_deinterlace_stop (GstBaseTransform * trans) -{ - GstDeinterlace *filter; - - filter = GST_DEINTERLACE (trans); - - g_free (filter->src); - filter->src = NULL; - filter->picsize = 0; - filter->width = 0; - filter->height = 0; - - return TRUE; -} - -static GstCaps * -gst_deinterlace_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * incaps) -{ - return gst_caps_ref (incaps); -} - -static gboolean -gst_deinterlace_set_caps (GstBaseTransform * trans, GstCaps * incaps, - GstCaps * outcaps) -{ - GstDeinterlace *filter; - GstVideoFormat fmt; - GstStructure *s; - guint32 fourcc; - gint picsize, w, h; - - filter = GST_DEINTERLACE (trans); - - g_assert (gst_caps_is_equal_fixed (incaps, outcaps)); - - s = gst_caps_get_structure (incaps, 0); - if (!gst_structure_get_int (s, "width", &w) || - !gst_structure_get_int (s, "height", &h) || - !gst_structure_get_fourcc (s, "format", &fourcc)) { - return FALSE; - } - - filter->width = w; - filter->height = h; - filter->fourcc = fourcc; - - GST_DEBUG_OBJECT (filter, "width x height = %d x %d, fourcc: %" - GST_FOURCC_FORMAT, w, h, GST_FOURCC_ARGS (fourcc)); - - fmt = gst_video_format_from_fourcc (fourcc); - - filter->y_stride = gst_video_format_get_row_stride (fmt, 0, w); - filter->u_stride = gst_video_format_get_row_stride (fmt, 1, w); - filter->v_stride = gst_video_format_get_row_stride (fmt, 2, w); - - filter->uv_height = gst_video_format_get_component_height (fmt, 1, h); - - filter->y_off = gst_video_format_get_component_offset (fmt, 0, w, h); - filter->u_off = gst_video_format_get_component_offset (fmt, 1, w, h); - filter->v_off = gst_video_format_get_component_offset (fmt, 2, w, h); - - picsize = gst_video_format_get_size (fmt, w, h); - - if (filter->picsize != picsize) { - filter->picsize = picsize; - g_free (filter->src); /* free + alloc avoids memcpy */ - filter->src = g_malloc0 (filter->picsize); - GST_LOG_OBJECT (filter, "temp buffer size %d", filter->picsize); - } - - return TRUE; -} - -static GstFlowReturn -gst_deinterlace_transform_ip (GstBaseTransform * trans, GstBuffer * buf) -{ - GstDeinterlace *filter; - gboolean bShowDeinterlacedAreaOnly; - gboolean bShowNoninterlacedAreaOnly; - gint y0, y1, y2, y3; - guchar *psrc1, *pdst1, *yuvptr, *src; - gint iInterlaceValue0, iInterlaceValue1, iInterlaceValue2; - gint x, y, p; - gint y_line; - guchar *y_dst, *y_src; - guchar fill_value; - gboolean bBlend; - gboolean bDeinterlace; - gint iThreshold; - gint iEdgeDetect; - gint width, height; - - /* g_assert (gst_buffer_is_writable (buf)); */ - - filter = GST_DEINTERLACE (trans); - - GST_OBJECT_LOCK (filter); - bBlend = filter->blend; - bDeinterlace = filter->deinterlace; - iThreshold = filter->threshold; - iEdgeDetect = filter->edge_detect; - bShowDeinterlacedAreaOnly = filter->show_deinterlaced_area_only; - bShowNoninterlacedAreaOnly = filter->show_noninterlaced_area_only; - GST_OBJECT_UNLOCK (filter); - - src = filter->src; - yuvptr = GST_BUFFER_DATA (buf); - - memcpy (filter->src, yuvptr, filter->picsize); - - - iThreshold = iThreshold * iThreshold * 4; - /* We don't want an integer overflow in the interlace calculation. */ - if (iEdgeDetect > 180) - iEdgeDetect = 180; - iEdgeDetect = iEdgeDetect * iEdgeDetect; - - for (p = 0; p < 3; p++) { - switch (p) { - case 0: - y_dst = yuvptr + filter->y_off; /* dst y pointer */ - y_line = filter->y_stride; - y_src = src + filter->y_off; - width = filter->width; - height = filter->height; - fill_value = 0; - break; - case 1: - y_dst = yuvptr + filter->u_off; /* dst U pointer */ - y_line = filter->u_stride; - y_src = src + filter->u_off; - width = filter->width / 2; - height = filter->uv_height; - fill_value = 128; - break; - case 2: - y_dst = yuvptr + filter->v_off; /* dst V pointer */ - y_line = filter->v_stride; - y_src = src + filter->v_off; - width = filter->width / 2; - height = filter->uv_height; - fill_value = 128; - break; - default: - g_assert_not_reached (); - break; - } - - for (x = 0; x < width; x++) { - pdst1 = y_dst + x; - psrc1 = y_src + x; - iInterlaceValue1 = iInterlaceValue2 = 0; - - for (y = 0; y < height; y++, psrc1 += y_line, pdst1 += y_line) { - /* current line is 1 */ - y0 = y1 = y2 = y3 = *psrc1; - if (y > 0) - y0 = *(psrc1 - y_line); - if (y < (height - 1)) - y2 = *(psrc1 + y_line); - if (y < (height - 2)) - y3 = *(psrc1 + 2 * y_line); - - iInterlaceValue0 = iInterlaceValue1; - iInterlaceValue1 = iInterlaceValue2; - - if (y < height - 1) - iInterlaceValue2 = - (ABS (y1 - y2) * ABS (y3 - y2) - ((iEdgeDetect * (y1 - y3) * (y1 - - y3)) >> 12)) * 10; - else - iInterlaceValue2 = 0; - - if ((iInterlaceValue0 + 2 * iInterlaceValue1 + iInterlaceValue2 > - iThreshold) && (y > 0)) { - if (bShowNoninterlacedAreaOnly) { - *pdst1 = fill_value; /* blank the point and so the interlac area */ - } else { - if (bDeinterlace) { - if (bBlend) { - *pdst1 = (unsigned char) ((y0 + 2 * y1 + y2) >> 2); - } else { - /* this method seems to work better than blending if the */ - /* quality is pretty bad and the half pics don't fit together */ - if ((y % 2) == 1) { /* if odd simply copy the value */ - *pdst1 = *psrc1; - } else { /* if even interpolate the line (upper + lower)/2 */ - *pdst1 = (unsigned char) ((y0 + y2) >> 1); - } - } - } else { - *pdst1 = *psrc1; - } - } - - } else { - /* so we went below the treshold and therefore we don't have to */ - /* change anything */ - if (bShowDeinterlacedAreaOnly) { - /* this is for testing to see how we should tune the treshhold */ - /* and shows as the things that haven't change because the */ - /* threshold was to low?? (or shows that everything is ok :-) */ - *pdst1 = fill_value; /* blank the point and so the non-interlac area */ - } else { - *pdst1 = *psrc1; - } - } - } - } - } - - return GST_FLOW_OK; -} - -static void -gst_deinterlace_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDeinterlace *filter; - - filter = GST_DEINTERLACE (object); - - GST_OBJECT_LOCK (filter); - switch (prop_id) { - case ARG_DEINTERLACE: - filter->deinterlace = g_value_get_boolean (value); - break; - case ARG_DI_ONLY: - filter->show_deinterlaced_area_only = g_value_get_boolean (value); - break; - case ARG_NI_ONLY: - filter->show_noninterlaced_area_only = g_value_get_boolean (value); - break; - case ARG_BLEND: - filter->blend = g_value_get_boolean (value); - break; - case ARG_THRESHOLD: - filter->threshold = g_value_get_int (value); - break; - case ARG_EDGE_DETECT: - filter->edge_detect = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (filter); -} - -static void -gst_deinterlace_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstDeinterlace *filter; - - filter = GST_DEINTERLACE (object); - - GST_OBJECT_LOCK (filter); - switch (prop_id) { - case ARG_DEINTERLACE: - g_value_set_boolean (value, filter->deinterlace); - break; - case ARG_DI_ONLY: - g_value_set_boolean (value, filter->show_deinterlaced_area_only); - break; - case ARG_NI_ONLY: - g_value_set_boolean (value, filter->show_noninterlaced_area_only); - break; - case ARG_BLEND: - g_value_set_boolean (value, filter->blend); - break; - case ARG_THRESHOLD: - g_value_set_int (value, filter->threshold); - break; - case ARG_EDGE_DETECT: - g_value_set_int (value, filter->edge_detect); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (filter); -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, - "deinterlace element"); - - if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE, - gst_deinterlace_get_type ())) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "gstinterlace", - "Deinterlace video", plugin_init, PACKAGE_VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN); diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h deleted file mode 100644 index faa8e811..00000000 --- a/gst/deinterlace/gstdeinterlace.h +++ /dev/null @@ -1,74 +0,0 @@ -/* GStreamer simple deinterlacing plugin - * Copyright (C) 1999 Erik Walthinsen - * Copyright (C) 2006 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_DEINTERLACE_H__ -#define __GST_DEINTERLACE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_DEINTERLACE (gst_deinterlace_get_type()) -#define GST_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE,GstDeinterlace)) -#define GST_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE,GstDeinterlaceClass)) -#define GST_IS_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE)) -#define GST_IS_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE)) - -typedef struct _GstDeinterlace GstDeinterlace; -typedef struct _GstDeinterlaceClass GstDeinterlaceClass; - -struct _GstDeinterlace { - GstBaseTransform basetransform; - - /*< private >*/ - gint width; - gint height; - gint uv_height; - guint32 fourcc; - - gboolean show_deinterlaced_area_only; - gboolean show_noninterlaced_area_only; - gboolean blend; - gboolean deinterlace; - gint threshold_blend; /* here we start blending */ - gint threshold; /* here we start interpolating TODO FIXME */ - gint edge_detect; - - gint picsize; - gint y_stride; - gint u_stride; - gint v_stride; - gint y_off; - gint u_off; - gint v_off; - - guchar *src; -}; - -struct _GstDeinterlaceClass { - GstBaseTransformClass basetransformclass; -}; - -GType gst_deinterlace_get_type (void); - -G_END_DECLS - -#endif /* __GST_DEINTERLACE_H__ */ diff --git a/gst/deinterlace2/Makefile.am b/gst/deinterlace2/Makefile.am deleted file mode 100644 index 1de59919..00000000 --- a/gst/deinterlace2/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -plugin_LTLIBRARIES = libgstdeinterlace2.la - -libgstdeinterlace2_la_SOURCES = \ - gstdeinterlace2.c \ - tvtime/greedy.c \ - tvtime/greedyh.c \ - tvtime/vfir.c \ - tvtime/tomsmocomp.c \ - tvtime/weavetff.c \ - tvtime/weavebff.c \ - tvtime/weave.c \ - tvtime/linear.c \ - tvtime/linearblend.c \ - tvtime/scalerbob.c - -libgstdeinterlace2_la_CFLAGS = $(GST_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(LIBOIL_CFLAGS) -libgstdeinterlace2_la_LIBADD = $(GST_LIBS) \ - $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(LIBOIL_LIBS) -libgstdeinterlace2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstdeinterlace2_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = \ - gstdeinterlace2.h \ - tvtime/mmx.h \ - tvtime/sse.h \ - tvtime/greedyh.asm \ - tvtime/greedyhmacros.h \ - tvtime/plugins.h \ - tvtime/x86-64_macros.inc \ - tvtime/tomsmocomp/SearchLoop0A.inc \ - tvtime/tomsmocomp/SearchLoopBottom.inc \ - tvtime/tomsmocomp/SearchLoopEdgeA8.inc \ - tvtime/tomsmocomp/SearchLoopEdgeA.inc \ - tvtime/tomsmocomp/SearchLoopOddA2.inc \ - tvtime/tomsmocomp/SearchLoopOddA6.inc \ - tvtime/tomsmocomp/SearchLoopOddAH2.inc \ - tvtime/tomsmocomp/SearchLoopOddAH.inc \ - tvtime/tomsmocomp/SearchLoopOddA.inc \ - tvtime/tomsmocomp/SearchLoopTop.inc \ - tvtime/tomsmocomp/SearchLoopVAH.inc \ - tvtime/tomsmocomp/SearchLoopVA.inc \ - tvtime/tomsmocomp/StrangeBob.inc \ - tvtime/tomsmocomp/TomsMoCompAll2.inc \ - tvtime/tomsmocomp/TomsMoCompAll.inc \ - tvtime/tomsmocomp/tomsmocompmacros.h \ - tvtime/tomsmocomp/WierdBob.inc - diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c deleted file mode 100644 index 42a69240..00000000 --- a/gst/deinterlace2/gstdeinterlace2.c +++ /dev/null @@ -1,1517 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2005 Martin Eikermann - * Copyright (C) 2008-2009 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-deinterlace2 - * - * deinterlace2 deinterlaces interlaced video frames to progressive video frames. - * For this different algorithms can be selected which will be described later. - * - * - * Example launch line - * |[ - * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace2 ! ffmpegcolorspace ! autovideosink - * ]| This pipeline deinterlaces a video file with the default deinterlacing options. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include "gstdeinterlace2.h" -#include "tvtime/plugins.h" - -#include - -GST_DEBUG_CATEGORY_STATIC (deinterlace2_debug); -#define GST_CAT_DEFAULT (deinterlace2_debug) - -/* Object signals and args */ -enum -{ - LAST_SIGNAL -}; - -/* Properties */ - -#define DEFAULT_MODE GST_DEINTERLACE2_MODE_INTERLACED -#define DEFAULT_METHOD GST_DEINTERLACE2_GREEDY_H -#define DEFAULT_FIELDS GST_DEINTERLACE2_ALL -#define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE2_LAYOUT_AUTO - -enum -{ - PROP_0, - PROP_MODE, - PROP_METHOD, - PROP_FIELDS, - PROP_FIELD_LAYOUT, - PROP_LAST -}; - -G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT); - -static void -gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass) -{ - -} - -static void -gst_deinterlace_method_init (GstDeinterlaceMethod * self) -{ - -} - -static void -gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, GstBuffer * outbuf) -{ - GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self); - - klass->deinterlace_frame (self, parent, outbuf); -} - -static gint -gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self) -{ - GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self); - - return klass->fields_required; -} - -static gint -gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self) -{ - GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self); - - return klass->latency; -} - - -G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method, - GST_TYPE_DEINTERLACE_METHOD); - -static void -gst_deinterlace_simple_method_interpolate_scanline (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m1, parent->row_stride); -} - -static void -gst_deinterlace_simple_method_copy_scanline (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m0, parent->row_stride); -} - -static void -gst_deinterlace_simple_method_deinterlace_frame (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, GstBuffer * outbuf) -{ - GstDeinterlaceSimpleMethodClass *dsm_class = - GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self); - GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self); - GstDeinterlaceScanlineData scanlines; - guint8 *out = GST_BUFFER_DATA (outbuf); - guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL; - gint cur_field_idx = parent->history_count - dm_class->fields_required; - guint cur_field_flags = parent->field_history[cur_field_idx].flags; - gint line; - - field0 = GST_BUFFER_DATA (parent->field_history[cur_field_idx].buf); - - g_assert (dm_class->fields_required <= 4); - - if (dm_class->fields_required >= 2) - field1 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 1].buf); - if (dm_class->fields_required >= 3) - field2 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 2].buf); - if (dm_class->fields_required >= 4) - field3 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 3].buf); - - - if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) { - /* double the first scanline of the bottom field */ - oil_memcpy (out, field0, parent->row_stride); - out += parent->row_stride; - } - - oil_memcpy (out, field0, parent->row_stride); - out += parent->row_stride; - - for (line = 2; line <= parent->field_height; line++) { - - memset (&scanlines, 0, sizeof (scanlines)); - scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM); - - /* interp. scanline */ - scanlines.t0 = field0; - scanlines.b0 = field0 + parent->field_stride; - - if (field1 != NULL) { - scanlines.tt1 = field1; - scanlines.m1 = field1 + parent->field_stride; - scanlines.bb1 = field1 + parent->field_stride * 2; - field1 += parent->field_stride; - } - - if (field2 != NULL) { - scanlines.t2 = field2; - scanlines.b2 = field2 + parent->field_stride; - } - - if (field3 != NULL) { - scanlines.tt3 = field3; - scanlines.m3 = field3 + parent->field_stride; - scanlines.bb3 = field3 + parent->field_stride * 2; - field3 += parent->field_stride; - } - - /* set valid data for corner cases */ - if (line == 2) { - scanlines.tt1 = scanlines.bb1; - scanlines.tt3 = scanlines.bb3; - } else if (line == parent->field_height) { - scanlines.bb1 = scanlines.tt1; - scanlines.bb3 = scanlines.tt3; - } - - dsm_class->interpolate_scanline (self, parent, out, &scanlines, - parent->frame_width); - out += parent->row_stride; - - memset (&scanlines, 0, sizeof (scanlines)); - scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM); - - /* copy a scanline */ - scanlines.tt0 = field0; - scanlines.m0 = field0 + parent->field_stride; - scanlines.bb0 = field0 + parent->field_stride * 2; - field0 += parent->field_stride; - - if (field1 != NULL) { - scanlines.t1 = field1; - scanlines.b1 = field1 + parent->field_stride; - } - - if (field2 != NULL) { - scanlines.tt2 = field2; - scanlines.m2 = field2 + parent->field_stride; - scanlines.bb2 = field2 + parent->field_stride * 2; - field2 += parent->field_stride; - } - - if (field3 != NULL) { - scanlines.t3 = field3; - scanlines.b3 = field3 + parent->field_stride; - } - - /* set valid data for corner cases */ - if (line == parent->field_height) { - scanlines.bb0 = scanlines.tt0; - scanlines.b1 = scanlines.t1; - scanlines.bb2 = scanlines.tt2; - scanlines.b3 = scanlines.t3; - } - - dsm_class->copy_scanline (self, parent, out, &scanlines, - parent->frame_width); - out += parent->row_stride; - } - - if (cur_field_flags == PICTURE_INTERLACED_TOP) { - /* double the last scanline of the top field */ - oil_memcpy (out, field0, parent->row_stride); - } -} - -static void -gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass * - klass) -{ - GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass; - - dm_class->deinterlace_frame = gst_deinterlace_simple_method_deinterlace_frame; - dm_class->fields_required = 2; - - klass->interpolate_scanline = - gst_deinterlace_simple_method_interpolate_scanline; - klass->copy_scanline = gst_deinterlace_simple_method_copy_scanline; -} - -static void -gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self) -{ -} - -#define GST_TYPE_DEINTERLACE2_METHODS (gst_deinterlace2_methods_get_type ()) -static GType -gst_deinterlace2_methods_get_type (void) -{ - static GType deinterlace2_methods_type = 0; - - static const GEnumValue methods_types[] = { - {GST_DEINTERLACE2_TOMSMOCOMP, "Motion Adaptive: Motion Search", - "tomsmocomp"}, - {GST_DEINTERLACE2_GREEDY_H, "Motion Adaptive: Advanced Detection", - "greedyh"}, - {GST_DEINTERLACE2_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"}, - {GST_DEINTERLACE2_VFIR, "Blur Vertical", "vfir"}, - {GST_DEINTERLACE2_LINEAR, "Television: Full resolution", "linear"}, - {GST_DEINTERLACE2_LINEAR_BLEND, "Blur: Temporal", "linearblend"}, - {GST_DEINTERLACE2_SCALER_BOB, "Double lines", "scalerbob"}, - {GST_DEINTERLACE2_WEAVE, "Weave", "weave"}, - {GST_DEINTERLACE2_WEAVE_TFF, "Progressive: Top Field First", "weavetff"}, - {GST_DEINTERLACE2_WEAVE_BFF, "Progressive: Bottom Field First", "weavebff"}, - {0, NULL, NULL}, - }; - - if (!deinterlace2_methods_type) { - deinterlace2_methods_type = - g_enum_register_static ("GstDeinterlace2Methods", methods_types); - } - return deinterlace2_methods_type; -} - -#define GST_TYPE_DEINTERLACE2_FIELDS (gst_deinterlace2_fields_get_type ()) -static GType -gst_deinterlace2_fields_get_type (void) -{ - static GType deinterlace2_fields_type = 0; - - static const GEnumValue fields_types[] = { - {GST_DEINTERLACE2_ALL, "All fields", "all"}, - {GST_DEINTERLACE2_TF, "Top fields only", "top"}, - {GST_DEINTERLACE2_BF, "Bottom fields only", "bottom"}, - {0, NULL, NULL}, - }; - - if (!deinterlace2_fields_type) { - deinterlace2_fields_type = - g_enum_register_static ("GstDeinterlace2Fields", fields_types); - } - return deinterlace2_fields_type; -} - -#define GST_TYPE_DEINTERLACE2_FIELD_LAYOUT (gst_deinterlace2_field_layout_get_type ()) -static GType -gst_deinterlace2_field_layout_get_type (void) -{ - static GType deinterlace2_field_layout_type = 0; - - static const GEnumValue field_layout_types[] = { - {GST_DEINTERLACE2_LAYOUT_AUTO, "Auto detection", "auto"}, - {GST_DEINTERLACE2_LAYOUT_TFF, "Top field first", "tff"}, - {GST_DEINTERLACE2_LAYOUT_BFF, "Bottom field first", "bff"}, - {0, NULL, NULL}, - }; - - if (!deinterlace2_field_layout_type) { - deinterlace2_field_layout_type = - g_enum_register_static ("GstDeinterlace2FieldLayout", - field_layout_types); - } - return deinterlace2_field_layout_type; -} - -#define GST_TYPE_DEINTERLACE2_MODES (gst_deinterlace2_modes_get_type ()) -static GType -gst_deinterlace2_modes_get_type (void) -{ - static GType deinterlace2_modes_type = 0; - - static const GEnumValue modes_types[] = { - {GST_DEINTERLACE2_MODE_AUTO, "Auto detection", "auto"}, - {GST_DEINTERLACE2_MODE_INTERLACED, "Enfore deinterlacing", "interlaced"}, - {GST_DEINTERLACE2_MODE_DISABLED, "Run in passthrough mode", "disabled"}, - {0, NULL, NULL}, - }; - - if (!deinterlace2_modes_type) { - deinterlace2_modes_type = - g_enum_register_static ("GstDeinterlace2Modes", modes_types); - } - return deinterlace2_modes_type; -} - -static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";" - GST_VIDEO_CAPS_YUV ("YVYU")) - ); - -static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";" - GST_VIDEO_CAPS_YUV ("YVYU")) - ); - -static void gst_deinterlace2_finalize (GObject * self); -static void gst_deinterlace2_set_property (GObject * self, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_deinterlace2_get_property (GObject * self, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstCaps *gst_deinterlace2_getcaps (GstPad * pad); -static gboolean gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn gst_deinterlace2_change_state (GstElement * element, - GstStateChange transition); - -static gboolean gst_deinterlace2_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query); -static const GstQueryType *gst_deinterlace2_src_query_types (GstPad * pad); - -static void gst_deinterlace2_reset (GstDeinterlace2 * self); - -static void gst_deinterlace2_child_proxy_interface_init (gpointer g_iface, - gpointer iface_data); - -static void -_do_init (GType object_type) -{ - const GInterfaceInfo child_proxy_interface_info = { - (GInterfaceInitFunc) gst_deinterlace2_child_proxy_interface_init, - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY, - &child_proxy_interface_info); -} - -GST_BOILERPLATE_FULL (GstDeinterlace2, gst_deinterlace2, GstElement, - GST_TYPE_ELEMENT, _do_init); - -static void -gst_deinterlace2_set_method (GstDeinterlace2 * self, - GstDeinterlace2Methods method) -{ - - if (self->method) { - gst_child_proxy_child_removed (GST_OBJECT (self), - GST_OBJECT (self->method)); - gst_object_unparent (GST_OBJECT (self->method)); - self->method = NULL; - } - - switch (method) { - case GST_DEINTERLACE2_TOMSMOCOMP: - self->method = g_object_new (GST_TYPE_DEINTERLACE_TOMSMOCOMP, NULL); - break; - case GST_DEINTERLACE2_GREEDY_H: - self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_H, NULL); - break; - case GST_DEINTERLACE2_GREEDY_L: - self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_L, NULL); - break; - case GST_DEINTERLACE2_VFIR: - self->method = g_object_new (GST_TYPE_DEINTERLACE_VFIR, NULL); - break; - case GST_DEINTERLACE2_LINEAR: - self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR, NULL); - break; - case GST_DEINTERLACE2_LINEAR_BLEND: - self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR_BLEND, NULL); - break; - case GST_DEINTERLACE2_SCALER_BOB: - self->method = g_object_new (GST_TYPE_DEINTERLACE_SCALER_BOB, NULL); - break; - case GST_DEINTERLACE2_WEAVE: - self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE, NULL); - break; - case GST_DEINTERLACE2_WEAVE_TFF: - self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_TFF, NULL); - break; - case GST_DEINTERLACE2_WEAVE_BFF: - self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_BFF, NULL); - break; - default: - GST_WARNING_OBJECT (self, "Invalid Deinterlacer Method"); - return; - } - - self->method_id = method; - - gst_object_set_name (GST_OBJECT (self->method), "method"); - gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self)); - gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method)); -} - -static void -gst_deinterlace2_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_templ)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_templ)); - - gst_element_class_set_details_simple (element_class, - "Deinterlacer", - "Filter/Video", - "Deinterlace Methods ported from DScaler/TvTime", - "Martin Eikermann , " - "Sebastian Dröge "); -} - -static void -gst_deinterlace2_class_init (GstDeinterlace2Class * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - - GstElementClass *element_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_deinterlace2_set_property; - gobject_class->get_property = gst_deinterlace2_get_property; - gobject_class->finalize = gst_deinterlace2_finalize; - - /** - * GstDeinterlace2:mode - * - * This selects whether the deinterlacing methods should - * always be applied or if they should only be applied - * on content that has the "interlaced" flag on the caps. - * - */ - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", - "Mode", - "Deinterlace Mode", - GST_TYPE_DEINTERLACE2_MODES, - DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - /** - * GstDeinterlace2:method - * - * Selects the different deinterlacing algorithms that can be used. - * These provide different quality and CPU usage. - * - * Some methods provide parameters which can be set by getting - * the "method" child via the #GstChildProxy interface and - * setting the appropiate properties on it. - * - * - * - * - * tomsmocomp - * Motion Adaptive: Motion Search - * - * - * - * - * greedyh - * Motion Adaptive: Advanced Detection - * - * - * - * - * greedyl - * Motion Adaptive: Simple Detection - * - * - * - * - * vfir - * Blur vertical - * - * - * - * - * linear - * Linear interpolation - * - * - * - * - * linearblend - * Linear interpolation in time domain - * - * - * - * - * scalerbob - * Double lines - * - * - * - * - * weave - * Weave - * - * - * - * - * weavetff - * Progressive: Top Field First - * - * - * - * - * weavebff - * Progressive: Bottom Field First - * - * - * - */ - g_object_class_install_property (gobject_class, PROP_METHOD, - g_param_spec_enum ("method", - "Method", - "Deinterlace Method", - GST_TYPE_DEINTERLACE2_METHODS, - DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - /** - * GstDeinterlace2:fields - * - * This selects which fields should be output. If "all" is selected - * the output framerate will be double. - * - */ - g_object_class_install_property (gobject_class, PROP_FIELDS, - g_param_spec_enum ("fields", - "fields", - "Fields to use for deinterlacing", - GST_TYPE_DEINTERLACE2_FIELDS, - DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - /** - * GstDeinterlace2:layout - * - * This selects which fields is the first in time. - * - */ - g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT, - g_param_spec_enum ("tff", - "tff", - "Deinterlace top field first", - GST_TYPE_DEINTERLACE2_FIELD_LAYOUT, - DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_deinterlace2_change_state); -} - -static GstObject * -gst_deinterlace2_child_proxy_get_child_by_index (GstChildProxy * child_proxy, - guint index) -{ - GstDeinterlace2 *self = GST_DEINTERLACE2 (child_proxy); - - g_return_val_if_fail (index == 0, NULL); - - return gst_object_ref (self->method); -} - -static guint -gst_deinterlace2_child_proxy_get_children_count (GstChildProxy * child_proxy) -{ - return 1; -} - -static void -gst_deinterlace2_child_proxy_interface_init (gpointer g_iface, - gpointer iface_data) -{ - GstChildProxyInterface *iface = g_iface; - - iface->get_child_by_index = gst_deinterlace2_child_proxy_get_child_by_index; - iface->get_children_count = gst_deinterlace2_child_proxy_get_children_count; -} - -static void -gst_deinterlace2_init (GstDeinterlace2 * self, GstDeinterlace2Class * klass) -{ - self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); - gst_pad_set_chain_function (self->sinkpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_chain)); - gst_pad_set_event_function (self->sinkpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_sink_event)); - gst_pad_set_setcaps_function (self->sinkpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps)); - gst_pad_set_getcaps_function (self->sinkpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps)); - gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); - - self->srcpad = gst_pad_new_from_static_template (&src_templ, "src"); - gst_pad_set_event_function (self->srcpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_src_event)); - gst_pad_set_query_type_function (self->srcpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query_types)); - gst_pad_set_query_function (self->srcpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query)); - gst_pad_set_setcaps_function (self->srcpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps)); - gst_pad_set_getcaps_function (self->srcpad, - GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps)); - gst_element_add_pad (GST_ELEMENT (self), self->srcpad); - - gst_element_no_more_pads (GST_ELEMENT (self)); - - self->mode = DEFAULT_MODE; - gst_deinterlace2_set_method (self, DEFAULT_METHOD); - self->fields = DEFAULT_FIELDS; - self->field_layout = DEFAULT_FIELD_LAYOUT; - - gst_deinterlace2_reset (self); -} - -static void -gst_deinterlace2_reset_history (GstDeinterlace2 * self) -{ - gint i; - - for (i = 0; i < self->history_count; i++) { - if (self->field_history[i].buf) { - gst_buffer_unref (self->field_history[i].buf); - self->field_history[i].buf = NULL; - } - } - memset (self->field_history, 0, MAX_FIELD_HISTORY * sizeof (GstPicture)); - self->history_count = 0; -} - -static void -gst_deinterlace2_reset (GstDeinterlace2 * self) -{ - self->row_stride = 0; - self->frame_width = 0; - self->frame_height = 0; - self->frame_rate_n = 0; - self->frame_rate_d = 0; - self->field_height = 0; - self->field_stride = 0; - - gst_deinterlace2_reset_history (self); -} - -static void -gst_deinterlace2_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDeinterlace2 *self; - - g_return_if_fail (GST_IS_DEINTERLACE2 (object)); - self = GST_DEINTERLACE2 (object); - - switch (prop_id) { - case PROP_MODE:{ - gint oldmode; - - GST_OBJECT_LOCK (self); - oldmode = self->mode; - self->mode = g_value_get_enum (value); - if (self->mode != oldmode && GST_PAD_CAPS (self->srcpad)) - gst_deinterlace2_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad)); - GST_OBJECT_UNLOCK (self); - break; - } - case PROP_METHOD: - gst_deinterlace2_set_method (self, g_value_get_enum (value)); - break; - case PROP_FIELDS:{ - gint oldfields; - - GST_OBJECT_LOCK (self); - oldfields = self->fields; - self->fields = g_value_get_enum (value); - if (self->fields != oldfields && GST_PAD_CAPS (self->srcpad)) - gst_deinterlace2_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad)); - GST_OBJECT_UNLOCK (self); - break; - } - case PROP_FIELD_LAYOUT: - self->field_layout = g_value_get_enum (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); - } - -} - -static void -gst_deinterlace2_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDeinterlace2 *self; - - g_return_if_fail (GST_IS_DEINTERLACE2 (object)); - self = GST_DEINTERLACE2 (object); - - switch (prop_id) { - case PROP_MODE: - g_value_set_enum (value, self->mode); - break; - case PROP_METHOD: - g_value_set_enum (value, self->method_id); - break; - case PROP_FIELDS: - g_value_set_enum (value, self->fields); - break; - case PROP_FIELD_LAYOUT: - g_value_set_enum (value, self->field_layout); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); - } -} - -static void -gst_deinterlace2_finalize (GObject * object) -{ - GstDeinterlace2 *self = GST_DEINTERLACE2 (object); - - gst_deinterlace2_reset (self); - - if (self->method) { - gst_object_unparent (GST_OBJECT (self->method)); - self->method = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static GstBuffer * -gst_deinterlace2_pop_history (GstDeinterlace2 * self) -{ - GstBuffer *buffer = NULL; - - g_assert (self->history_count > 0); - - buffer = self->field_history[self->history_count - 1].buf; - - self->history_count--; - GST_DEBUG_OBJECT (self, "pop, size(history): %d", self->history_count); - - return buffer; -} - -#if 0 -static GstBuffer * -gst_deinterlace2_head_history (GstDeinterlace2 * self) -{ - return self->field_history[self->history_count - 1].buf; -} -#endif - - -/* invariant: field with smallest timestamp is self->field_history[self->history_count-1] - -*/ - -static void -gst_deinterlace2_push_history (GstDeinterlace2 * self, GstBuffer * buffer) -{ - int i = 1; - GstClockTime timestamp; - GstDeinterlace2FieldLayout field_layout = self->field_layout; - gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF); - gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF); - gboolean onefield = - GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD); - GstBuffer *field1, *field2; - guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3; - gint field1_flags, field2_flags; - - g_assert (self->history_count < MAX_FIELD_HISTORY - fields_to_push); - - for (i = MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) { - self->field_history[i].buf = self->field_history[i - fields_to_push].buf; - self->field_history[i].flags = - self->field_history[i - fields_to_push].flags; - } - - if (field_layout == GST_DEINTERLACE2_LAYOUT_AUTO) { - if (!self->interlaced) { - GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF"); - field_layout = GST_DEINTERLACE2_LAYOUT_TFF; - } else if (tff) { - field_layout = GST_DEINTERLACE2_LAYOUT_TFF; - } else { - field_layout = GST_DEINTERLACE2_LAYOUT_BFF; - } - } - - if (field_layout == GST_DEINTERLACE2_LAYOUT_TFF) { - GST_DEBUG_OBJECT (self, "Top field first"); - field1 = gst_buffer_ref (buffer); - field1_flags = PICTURE_INTERLACED_TOP; - field2 = gst_buffer_create_sub (buffer, self->row_stride, - GST_BUFFER_SIZE (buffer) - self->row_stride); - field2_flags = PICTURE_INTERLACED_BOTTOM; - } else { - GST_DEBUG_OBJECT (self, "Bottom field first"); - field1 = gst_buffer_create_sub (buffer, self->row_stride, - GST_BUFFER_SIZE (buffer) - self->row_stride); - field1_flags = PICTURE_INTERLACED_BOTTOM; - field2 = gst_buffer_ref (buffer); - field2_flags = PICTURE_INTERLACED_TOP; - } - - /* Timestamps are assigned to the field buffers under the assumption that - the timestamp of the buffer equals the first fields timestamp */ - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - GST_BUFFER_TIMESTAMP (field1) = timestamp; - GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration; - if (repeated) - GST_BUFFER_TIMESTAMP (field2) += self->field_duration; - - if (repeated) { - self->field_history[0].buf = field2; - self->field_history[0].flags = field2_flags; - self->field_history[1].buf = gst_buffer_ref (field1); - GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration; - self->field_history[1].flags = field1_flags; - self->field_history[2].buf = field1; - self->field_history[2].flags = field1_flags; - } else if (!onefield) { - self->field_history[0].buf = field2; - self->field_history[0].flags = field2_flags; - self->field_history[1].buf = field1; - self->field_history[1].flags = field1_flags; - } else { /* onefield */ - self->field_history[0].buf = field1; - self->field_history[0].flags = field1_flags; - gst_buffer_unref (field2); - } - - self->history_count += fields_to_push; - GST_DEBUG_OBJECT (self, "push, size(history): %d", self->history_count); - - gst_buffer_unref (buffer); -} - -static GstFlowReturn -gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf) -{ - GstDeinterlace2 *self = NULL; - GstClockTime timestamp; - GstFlowReturn ret = GST_FLOW_OK; - gint fields_required = 0; - gint cur_field_idx = 0; - GstBuffer *outbuf; - - self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad)); - - if (self->mode == GST_DEINTERLACE2_MODE_DISABLED || (!self->interlaced - && self->mode != GST_DEINTERLACE2_MODE_INTERLACED)) - return gst_pad_push (self->srcpad, buf); - - if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { - GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history"); - gst_deinterlace2_reset_history (self); - } - - gst_deinterlace2_push_history (self, buf); - buf = NULL; - - fields_required = gst_deinterlace_method_get_fields_required (self->method); - - /* Not enough fields in the history */ - if (self->history_count < fields_required + 1) { - /* TODO: do bob or just forward frame */ - GST_DEBUG_OBJECT (self, "HistoryCount=%d", self->history_count); - return GST_FLOW_OK; - } - - while (self->history_count >= fields_required) { - if (self->fields == GST_DEINTERLACE2_ALL) - GST_DEBUG_OBJECT (self, "All fields"); - if (self->fields == GST_DEINTERLACE2_TF) - GST_DEBUG_OBJECT (self, "Top fields"); - if (self->fields == GST_DEINTERLACE2_BF) - GST_DEBUG_OBJECT (self, "Bottom fields"); - - cur_field_idx = self->history_count - fields_required; - - if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP - && self->fields == GST_DEINTERLACE2_TF) || - self->fields == GST_DEINTERLACE2_ALL) { - GST_DEBUG_OBJECT (self, "deinterlacing top field"); - - /* create new buffer */ - ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, - GST_BUFFER_OFFSET_NONE, self->frame_size, - GST_PAD_CAPS (self->srcpad), &outbuf); - if (ret != GST_FLOW_OK) - return ret; - - /* do magic calculus */ - gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf); - - g_assert (self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method) >= 0); - buf = - self->field_history[self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method)].buf; - timestamp = GST_BUFFER_TIMESTAMP (buf); - - gst_buffer_unref (gst_deinterlace2_pop_history (self)); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - if (self->fields == GST_DEINTERLACE2_ALL) - GST_BUFFER_DURATION (outbuf) = self->field_duration; - else - GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration; - - ret = gst_pad_push (self->srcpad, outbuf); - outbuf = NULL; - if (ret != GST_FLOW_OK) - return ret; - } - /* no calculation done: remove excess field */ - else if (self->field_history[cur_field_idx].flags == - PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_BF) { - GST_DEBUG_OBJECT (self, "Removing unused top field"); - gst_buffer_unref (gst_deinterlace2_pop_history (self)); - } - - cur_field_idx = self->history_count - fields_required; - if (self->history_count < fields_required) - break; - - /* deinterlace bottom_field */ - if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM - && self->fields == GST_DEINTERLACE2_BF) || - self->fields == GST_DEINTERLACE2_ALL) { - GST_DEBUG_OBJECT (self, "deinterlacing bottom field"); - - /* create new buffer */ - ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, - GST_BUFFER_OFFSET_NONE, self->frame_size, - GST_PAD_CAPS (self->srcpad), &outbuf); - if (ret != GST_FLOW_OK) - return ret; - - /* do magic calculus */ - gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf); - - g_assert (self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method) >= 0); - buf = - self->field_history[self->history_count - 1 - - gst_deinterlace_method_get_latency (self->method)].buf; - timestamp = GST_BUFFER_TIMESTAMP (buf); - - gst_buffer_unref (gst_deinterlace2_pop_history (self)); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - if (self->fields == GST_DEINTERLACE2_ALL) - GST_BUFFER_DURATION (outbuf) = self->field_duration; - else - GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration; - - ret = gst_pad_push (self->srcpad, outbuf); - outbuf = NULL; - - if (ret != GST_FLOW_OK) - return ret; - } - /* no calculation done: remove excess field */ - else if (self->field_history[cur_field_idx].flags == - PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_TF) { - GST_DEBUG_OBJECT (self, "Removing unused bottom field"); - gst_buffer_unref (gst_deinterlace2_pop_history (self)); - } - } - - GST_DEBUG_OBJECT (self, "----chain end ----\n\n"); - - return ret; -} - -static gint -gst_greatest_common_divisor (gint a, gint b) -{ - while (b != 0) { - int temp = a; - - a = b; - b = temp % b; - } - - return ABS (a); -} - -static gboolean -gst_fraction_double (gint * n_out, gint * d_out, gboolean half) -{ - gint n, d, gcd; - - n = *n_out; - d = *d_out; - - if (d == 0) - return FALSE; - - if (n == 0 || (n == G_MAXINT && d == 1)) - return TRUE; - - gcd = gst_greatest_common_divisor (n, d); - n /= gcd; - d /= gcd; - - if (!half) { - if (G_MAXINT / 2 >= ABS (n)) { - n *= 2; - } else if (d >= 2) { - d /= 2; - } else { - return FALSE; - } - } else { - if (G_MAXINT / 2 >= ABS (d)) { - d *= 2; - } else if (n >= 2) { - n /= 2; - } else { - return FALSE; - } - } - - *n_out = n; - *d_out = d; - - return TRUE; -} - -static GstCaps * -gst_deinterlace2_getcaps (GstPad * pad) -{ - GstCaps *ret; - GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); - GstPad *otherpad; - gint len; - const GstCaps *ourcaps; - GstCaps *peercaps; - - GST_OBJECT_LOCK (self); - - otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad; - - ourcaps = gst_pad_get_pad_template_caps (pad); - peercaps = gst_pad_peer_get_caps (otherpad); - - if (peercaps) { - ret = gst_caps_intersect (ourcaps, peercaps); - gst_caps_unref (peercaps); - } else { - ret = gst_caps_copy (ourcaps); - } - - GST_OBJECT_UNLOCK (self); - - if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) && - self->fields == GST_DEINTERLACE2_ALL - && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { - for (len = gst_caps_get_size (ret); len > 0; len--) { - GstStructure *s = gst_caps_get_structure (ret, len - 1); - const GValue *val; - - val = gst_structure_get_value (s, "framerate"); - if (!val) - continue; - - if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) { - gint n, d; - - n = gst_value_get_fraction_numerator (val); - d = gst_value_get_fraction_denominator (val); - - if (!gst_fraction_double (&n, &d, pad != self->srcpad)) { - goto error; - } - - gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL); - } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) { - const GValue *min, *max; - GValue nrange = { 0, }, nmin = { - 0,}, nmax = { - 0,}; - gint n, d; - - g_value_init (&nrange, GST_TYPE_FRACTION_RANGE); - g_value_init (&nmin, GST_TYPE_FRACTION); - g_value_init (&nmax, GST_TYPE_FRACTION); - - min = gst_value_get_fraction_range_min (val); - max = gst_value_get_fraction_range_max (val); - - n = gst_value_get_fraction_numerator (min); - d = gst_value_get_fraction_denominator (min); - - if (!gst_fraction_double (&n, &d, pad != self->srcpad)) { - g_value_unset (&nrange); - g_value_unset (&nmax); - g_value_unset (&nmin); - goto error; - } - - gst_value_set_fraction (&nmin, n, d); - - n = gst_value_get_fraction_numerator (max); - d = gst_value_get_fraction_denominator (max); - - if (!gst_fraction_double (&n, &d, pad != self->srcpad)) { - g_value_unset (&nrange); - g_value_unset (&nmax); - g_value_unset (&nmin); - goto error; - } - - gst_value_set_fraction (&nmax, n, d); - gst_value_set_fraction_range (&nrange, &nmin, &nmax); - - gst_structure_set_value (s, "framerate", &nrange); - - g_value_unset (&nmin); - g_value_unset (&nmax); - g_value_unset (&nrange); - } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) { - const GValue *lval; - GValue nlist = { 0, }; - GValue nval = { 0, }; - gint i; - - g_value_init (&nlist, GST_TYPE_LIST); - for (i = gst_value_list_get_size (val); i > 0; i--) { - gint n, d; - - lval = gst_value_list_get_value (val, i); - - if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION) - continue; - - n = gst_value_get_fraction_numerator (lval); - d = gst_value_get_fraction_denominator (lval); - - /* Double/Half the framerate but if this fails simply - * skip this value from the list */ - if (!gst_fraction_double (&n, &d, pad != self->srcpad)) { - continue; - } - - g_value_init (&nval, GST_TYPE_FRACTION); - - gst_value_set_fraction (&nval, n, d); - gst_value_list_append_value (&nlist, &nval); - g_value_unset (&nval); - } - gst_structure_set_value (s, "framerate", &nlist); - g_value_unset (&nlist); - } - } - } - - GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); - - return ret; - -error: - GST_ERROR_OBJECT (pad, "Unable to transform peer caps"); - gst_caps_unref (ret); - return NULL; -} - -static gboolean -gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps) -{ - gboolean res = TRUE; - GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); - GstPad *otherpad; - GstStructure *structure; - GstVideoFormat fmt; - guint32 fourcc; - GstCaps *othercaps; - - otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad; - - structure = gst_caps_get_structure (caps, 0); - - res = gst_structure_get_int (structure, "width", &self->frame_width); - res &= gst_structure_get_int (structure, "height", &self->frame_height); - res &= - gst_structure_get_fraction (structure, "framerate", &self->frame_rate_n, - &self->frame_rate_d); - res &= gst_structure_get_fourcc (structure, "format", &fourcc); - res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced); - if (!res) - goto invalid_caps; - - if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) && - self->fields == GST_DEINTERLACE2_ALL - && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { - gint fps_n = self->frame_rate_n, fps_d = self->frame_rate_d; - - if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad)) - goto invalid_caps; - - othercaps = gst_caps_copy (caps); - - gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n, - fps_d, NULL); - } else { - othercaps = gst_caps_ref (caps); - } - - if (!gst_pad_set_caps (otherpad, othercaps)) - goto caps_not_accepted; - gst_caps_unref (othercaps); - - self->field_height = self->frame_height / 2; - - fmt = gst_video_format_from_fourcc (fourcc); - - /* TODO: only true if fields are subbuffers of interlaced frames, - change when the buffer-fields concept has landed */ - self->field_stride = - gst_video_format_get_row_stride (fmt, 0, self->frame_width) * 2; - - /* in bytes */ - self->row_stride = - gst_video_format_get_row_stride (fmt, 0, self->frame_width); - self->frame_size = - gst_video_format_get_size (fmt, self->frame_width, self->frame_height); - - if (self->fields == GST_DEINTERLACE2_ALL && otherpad == self->srcpad) - self->field_duration = - gst_util_uint64_scale (GST_SECOND, self->frame_rate_d, - self->frame_rate_n); - else - self->field_duration = - gst_util_uint64_scale (GST_SECOND, self->frame_rate_d, - 2 * self->frame_rate_n); - - GST_DEBUG_OBJECT (self, "Set caps: %" GST_PTR_FORMAT, caps); - -done: - - gst_object_unref (self); - return res; - -invalid_caps: - res = FALSE; - GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps); - goto done; - -caps_not_accepted: - res = FALSE; - GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps); - gst_caps_unref (othercaps); - goto done; -} - -static gboolean -gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP: - case GST_EVENT_EOS: - case GST_EVENT_NEWSEGMENT: - gst_deinterlace2_reset_history (self); - - /* fall through */ - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (self); - return res; -} - -static GstStateChangeReturn -gst_deinterlace2_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstDeinterlace2 *self = GST_DEINTERLACE2 (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_deinterlace2_reset (self); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - default: - break; - } - - return ret; -} - -static gboolean -gst_deinterlace2_src_event (GstPad * pad, GstEvent * event) -{ - GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); - gboolean res; - - GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (self); - - return res; -} - -static gboolean -gst_deinterlace2_src_query (GstPad * pad, GstQuery * query) -{ - GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad)); - gboolean res = FALSE; - - GST_LOG_OBJECT (self, "%s query", GST_QUERY_TYPE_NAME (query)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) - && self->mode != GST_DEINTERLACE2_MODE_DISABLED) { - GstClockTime min, max; - gboolean live; - GstPad *peer; - - if ((peer = gst_pad_get_peer (self->sinkpad))) { - if ((res = gst_pad_query (peer, query))) { - GstClockTime latency; - gint fields_required = 0; - gint method_latency = 0; - - if (self->method) { - fields_required = - gst_deinterlace_method_get_fields_required (self->method); - method_latency = - gst_deinterlace_method_get_latency (self->method); - } - - gst_query_parse_latency (query, &live, &min, &max); - - GST_DEBUG_OBJECT (self, "Peer latency: min %" - GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min), GST_TIME_ARGS (max)); - - /* add our own latency */ - latency = (fields_required + method_latency) * self->field_duration; - - GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT - ", max %" GST_TIME_FORMAT, - GST_TIME_ARGS (latency), GST_TIME_ARGS (latency)); - - min += latency; - if (max != GST_CLOCK_TIME_NONE) - max += latency; - else - max = latency; - - GST_DEBUG_OBJECT (self, "Calculated total latency : min %" - GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min), GST_TIME_ARGS (max)); - - gst_query_set_latency (query, live, min, max); - } - gst_object_unref (peer); - } else { - res = gst_pad_query_default (pad, query); - } - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (self); - return res; -} - -static const GstQueryType * -gst_deinterlace2_src_query_types (GstPad * pad) -{ - static const GstQueryType types[] = { - GST_QUERY_LATENCY, - GST_QUERY_NONE - }; - return types; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (deinterlace2_debug, "deinterlace2", 0, - "Deinterlacer"); - - oil_init (); - - if (!gst_element_register (plugin, "deinterlace2", GST_RANK_NONE, - GST_TYPE_DEINTERLACE2)) { - return FALSE; - } - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "deinterlace2", - "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN); diff --git a/gst/deinterlace2/gstdeinterlace2.h b/gst/deinterlace2/gstdeinterlace2.h deleted file mode 100644 index 7a08d411..00000000 --- a/gst/deinterlace2/gstdeinterlace2.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2005 Martin Eikermann - * Copyright (C) 2008-2009 Sebastian Dröge - * - * 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_DEINTERLACE_2_H__ -#define __GST_DEINTERLACE_2_H__ - -#include -#include -#include -#include -#include - -#ifdef HAVE_GCC_ASM -#if defined(HAVE_CPU_I386) || defined(HAVE_CPU_X86_64) -#define BUILD_X86_ASM -#endif -#endif - -G_BEGIN_DECLS - -#define GST_TYPE_DEINTERLACE2 \ - (gst_deinterlace2_get_type()) -#define GST_DEINTERLACE2(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE2,GstDeinterlace2)) -#define GST_DEINTERLACE2_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE2,GstDeinterlace2)) -#define GST_IS_DEINTERLACE2(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE2)) -#define GST_IS_DEINTERLACE2_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE2)) - -typedef struct _GstDeinterlace2 GstDeinterlace2; -typedef struct _GstDeinterlace2Class GstDeinterlace2Class; - -#define GST_TYPE_DEINTERLACE_METHOD (gst_deinterlace_method_get_type ()) -#define GST_IS_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD)) -#define GST_IS_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD)) -#define GST_DEINTERLACE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass)) -#define GST_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethod)) -#define GST_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass)) -#define GST_DEINTERLACE_METHOD_CAST(obj) ((GstDeinterlaceMethod*)(obj)) - -typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod; -typedef struct _GstDeinterlaceMethodClass GstDeinterlaceMethodClass; - -/* - * This structure defines the deinterlacer plugin. - */ - -struct _GstDeinterlaceMethod { - GstObject parent; -}; - -struct _GstDeinterlaceMethodClass { - GstObjectClass parent_class; - guint fields_required; - guint latency; - - void (*deinterlace_frame) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, GstBuffer *outbuf); - - const gchar *name; - const gchar *nick; -}; - -GType gst_deinterlace_method_get_type (void); - -#define GST_TYPE_DEINTERLACE_SIMPLE_METHOD (gst_deinterlace_simple_method_get_type ()) -#define GST_IS_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD)) -#define GST_IS_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD)) -#define GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass)) -#define GST_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethod)) -#define GST_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass)) -#define GST_DEINTERLACE_SIMPLE_METHOD_CAST(obj) ((GstDeinterlaceSimpleMethod*)(obj)) - -typedef struct _GstDeinterlaceSimpleMethod GstDeinterlaceSimpleMethod; -typedef struct _GstDeinterlaceSimpleMethodClass GstDeinterlaceSimpleMethodClass; -typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData; - -/* - * This structure defines the simple deinterlacer plugin. - */ - -struct _GstDeinterlaceScanlineData { - guint8 *tt0, *t0, *m0, *b0, *bb0; - guint8 *tt1, *t1, *m1, *b1, *bb1; - guint8 *tt2, *t2, *m2, *b2, *bb2; - guint8 *tt3, *t3, *m3, *b3, *bb3; - gboolean bottom_field; -}; - -/** - * For interpolate_scanline the input is: - * - * | t-3 t-2 t-1 t - * | Field 3 | Field 2 | Field 1 | Field 0 | - * | TT3 | | TT1 | | - * | | T2 | | T0 | - * | M3 | | M1 | | - * | | B2 | | B0 | - * | BB3 | | BB1 | | - * - * For copy_scanline the input is: - * - * | t-3 t-2 t-1 t - * | Field 3 | Field 2 | Field 1 | Field 0 | - * | | TT2 | | TT0 | - * | T3 | | T1 | | - * | | M2 | | M0 | - * | B3 | | B1 | | - * | | BB2 | | BB0 | - * - * All other values are NULL. - */ - -struct _GstDeinterlaceSimpleMethod { - GstDeinterlaceMethod parent; -}; - -struct _GstDeinterlaceSimpleMethodClass { - GstDeinterlaceMethodClass parent_class; - - void (*interpolate_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); - void (*copy_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); -}; - -GType gst_deinterlace_simple_method_get_type (void); - - -#define MAX_FIELD_HISTORY 10 - -#define PICTURE_PROGRESSIVE 0 -#define PICTURE_INTERLACED_BOTTOM 1 -#define PICTURE_INTERLACED_TOP 2 -#define PICTURE_INTERLACED_MASK (PICTURE_INTERLACED_BOTTOM | PICTURE_INTERLACED_TOP) - -typedef struct -{ - /* pointer to the start of data for this field */ - GstBuffer *buf; - /* see PICTURE_ flags */ - guint flags; -} GstPicture; - -typedef enum -{ - GST_DEINTERLACE2_TOMSMOCOMP, - GST_DEINTERLACE2_GREEDY_H, - GST_DEINTERLACE2_GREEDY_L, - GST_DEINTERLACE2_VFIR, - GST_DEINTERLACE2_LINEAR, - GST_DEINTERLACE2_LINEAR_BLEND, - GST_DEINTERLACE2_SCALER_BOB, - GST_DEINTERLACE2_WEAVE, - GST_DEINTERLACE2_WEAVE_TFF, - GST_DEINTERLACE2_WEAVE_BFF -} GstDeinterlace2Methods; - -typedef enum -{ - GST_DEINTERLACE2_ALL, /* All (missing data is interp.) */ - GST_DEINTERLACE2_TF, /* Top Fields Only */ - GST_DEINTERLACE2_BF /* Bottom Fields Only */ -} GstDeinterlace2Fields; - -typedef enum -{ - GST_DEINTERLACE2_LAYOUT_AUTO, - GST_DEINTERLACE2_LAYOUT_TFF, - GST_DEINTERLACE2_LAYOUT_BFF -} GstDeinterlace2FieldLayout; - -typedef enum { - GST_DEINTERLACE2_MODE_AUTO, - GST_DEINTERLACE2_MODE_INTERLACED, - GST_DEINTERLACE2_MODE_DISABLED -} GstDeinterlace2Mode; - -struct _GstDeinterlace2 -{ - GstElement parent; - - GstPad *srcpad, *sinkpad; - - /* */ - - GstDeinterlace2Mode mode; - - GstDeinterlace2FieldLayout field_layout; - - guint frame_size; - gint frame_rate_n, frame_rate_d; - gboolean interlaced; - - /* Duration of one field */ - GstClockTime field_duration; - - GstDeinterlace2Fields fields; - - GstDeinterlace2Methods method_id; - GstDeinterlaceMethod *method; - - /* The most recent pictures - PictureHistory[0] is always the most recent. - Pointers are NULL if the picture in question isn't valid, e.g. because - the program just started or a picture was skipped. - */ - GstPicture field_history[MAX_FIELD_HISTORY]; - guint history_count; - - /* Number of bytes of actual data in each scanline. May be less than - OverlayPitch since the overlay's scanlines might have alignment - requirements. Generally equal to FrameWidth * 2. - */ - guint row_stride; - - /* Number of pixels in each scanline. */ - gint frame_width; - - /* Number of scanlines per frame. */ - gint frame_height; - - /* Number of scanlines per field. FrameHeight / 2, mostly for - cleanliness so we don't have to keep dividing FrameHeight by 2. - */ - gint field_height; - - /* distance between lines in image - need not match the pixel width - */ - guint field_stride; -}; - -struct _GstDeinterlace2Class -{ - GstElementClass parent_class; -}; - -GType gst_deinterlace2_get_type (void); - -G_END_DECLS -#endif /* __GST_DEINTERLACE_2_H__ */ diff --git a/gst/deinterlace2/tvtime/greedy.c b/gst/deinterlace2/tvtime/greedy.c deleted file mode 100644 index 7d4e4b3a..00000000 --- a/gst/deinterlace2/tvtime/greedy.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * - * GStreamer - * Copyright (c) 2000 Tom Barry All rights reserved. - * mmx.h port copyright (c) 2002 Billy Biggs . - * - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - -/* - * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry - * and Billy Biggs. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" - -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_GREEDY_L(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L)) -#define GST_IS_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L)) -#define GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass)) -#define GST_DEINTERLACE_METHOD_GREEDY_L(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyL)) -#define GST_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass)) -#define GST_DEINTERLACE_METHOD_GREEDY_L_CAST(obj) ((GstDeinterlaceMethodGreedyL*)(obj)) - -GType gst_deinterlace_method_greedy_l_get_type (void); - -typedef struct -{ - GstDeinterlaceMethod parent; - - guint max_comb; -} GstDeinterlaceMethodGreedyL; - -typedef struct -{ - GstDeinterlaceMethodClass parent_class; - void (*scanline) (GstDeinterlaceMethodGreedyL * self, uint8_t * L2, - uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size); -} GstDeinterlaceMethodGreedyLClass; - -// This is a simple lightweight DeInterlace method that uses little CPU time -// but gives very good results for low or intermedite motion. -// It defers frames by one field, but that does not seem to produce noticeable -// lip sync problems. -// -// The method used is to take either the older or newer weave pixel depending -// upon which give the smaller comb factor, and then clip to avoid large damage -// when wrong. -// -// I'd intended this to be part of a larger more elaborate method added to -// Blended Clip but this give too good results for the CPU to ignore here. - -static inline void -deinterlace_greedy_packed422_scanline_c (GstDeinterlaceMethodGreedyL * self, - uint8_t * m0, uint8_t * t1, - uint8_t * b1, uint8_t * m2, uint8_t * output, int width) -{ - int avg, l2_diff, lp2_diff, max, min, best; - guint max_comb = self->max_comb; - - // L2 == m0 - // L1 == t1 - // L3 == b1 - // LP2 == m2 - - while (width--) { - avg = (*t1 + *b1) / 2; - - l2_diff = ABS (*m0 - avg); - lp2_diff = ABS (*m2 - avg); - - if (l2_diff > lp2_diff) - best = *m2; - else - best = *m0; - - max = MAX (*t1, *b1); - min = MIN (*t1, *b1); - - if (max < 256 - max_comb) - max += max_comb; - else - max = 255; - - if (min > max_comb) - min -= max_comb; - else - min = 0; - - *output = CLAMP (best, min, max); - - // Advance to the next set of pixels. - output += 1; - m0 += 1; - t1 += 1; - b1 += 1; - m2 += 1; - } -} - -#ifdef BUILD_X86_ASM -#include "mmx.h" -static void -deinterlace_greedy_packed422_scanline_mmx (GstDeinterlaceMethodGreedyL * self, - uint8_t * m0, uint8_t * t1, - uint8_t * b1, uint8_t * m2, uint8_t * output, int width) -{ - mmx_t MaxComb; - mmx_t ShiftMask; - - // How badly do we let it weave? 0-255 - MaxComb.ub[0] = self->max_comb; - MaxComb.ub[1] = self->max_comb; - MaxComb.ub[2] = self->max_comb; - MaxComb.ub[3] = self->max_comb; - MaxComb.ub[4] = self->max_comb; - MaxComb.ub[5] = self->max_comb; - MaxComb.ub[6] = self->max_comb; - MaxComb.ub[7] = self->max_comb; - - ShiftMask.ub[0] = 0x7f; - ShiftMask.ub[1] = 0x7f; - ShiftMask.ub[2] = 0x7f; - ShiftMask.ub[3] = 0x7f; - ShiftMask.ub[4] = 0x7f; - ShiftMask.ub[5] = 0x7f; - ShiftMask.ub[6] = 0x7f; - ShiftMask.ub[7] = 0x7f; - - // L2 == m0 - // L1 == t1 - // L3 == b1 - // LP2 == m2 - - movq_m2r (MaxComb, mm6); - - for (; width > 7; width -= 8) { - movq_m2r (*t1, mm1); // L1 - movq_m2r (*m0, mm2); // L2 - movq_m2r (*b1, mm3); // L3 - movq_m2r (*m2, mm0); // LP2 - - // average L1 and L3 leave result in mm4 - movq_r2r (mm1, mm4); // L1 - movq_r2r (mm3, mm5); // L3 - psrlw_i2r (1, mm4); // L1/2 - pand_m2r (ShiftMask, mm4); - psrlw_i2r (1, mm5); // L3/2 - pand_m2r (ShiftMask, mm5); - paddusb_r2r (mm5, mm4); // (L1 + L3) / 2 - - // get abs value of possible L2 comb - movq_r2r (mm2, mm7); // L2 - psubusb_r2r (mm4, mm7); // L2 - avg - movq_r2r (mm4, mm5); // avg - psubusb_r2r (mm2, mm5); // avg - L2 - por_r2r (mm7, mm5); // abs(avg-L2) - - // get abs value of possible LP2 comb - movq_r2r (mm0, mm7); // LP2 - psubusb_r2r (mm4, mm7); // LP2 - avg - psubusb_r2r (mm0, mm4); // avg - LP2 - por_r2r (mm7, mm4); // abs(avg-LP2) - - // use L2 or LP2 depending upon which makes smaller comb - psubusb_r2r (mm5, mm4); // see if it goes to zero - psubusb_r2r (mm5, mm5); // 0 - pcmpeqb_r2r (mm5, mm4); // if (mm4=0) then FF else 0 - pcmpeqb_r2r (mm4, mm5); // opposite of mm4 - - // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55 - pand_r2r (mm2, mm5); // use L2 if mm5 == ff, else 0 - pand_r2r (mm0, mm4); // use LP2 if mm4 = ff, else 0 - por_r2r (mm5, mm4); // may the best win - - // Now lets clip our chosen value to be not outside of the range - // of the high/low range L1-L3 by more than abs(L1-L3) - // This allows some comb but limits the damages and also allows more - // detail than a boring oversmoothed clip. - - movq_r2r (mm1, mm2); // copy L1 - psubusb_r2r (mm3, mm2); // - L3, with saturation - paddusb_r2r (mm3, mm2); // now = Max(L1,L3) - - pcmpeqb_r2r (mm7, mm7); // all ffffffff - psubusb_r2r (mm1, mm7); // - L1 - paddusb_r2r (mm7, mm3); // add, may sat at fff.. - psubusb_r2r (mm7, mm3); // now = Min(L1,L3) - - // allow the value to be above the high or below the low by amt of MaxComb - paddusb_r2r (mm6, mm2); // increase max by diff - psubusb_r2r (mm6, mm3); // lower min by diff - - psubusb_r2r (mm3, mm4); // best - Min - paddusb_r2r (mm3, mm4); // now = Max(best,Min(L1,L3) - - pcmpeqb_r2r (mm7, mm7); // all ffffffff - psubusb_r2r (mm4, mm7); // - Max(best,Min(best,L3) - paddusb_r2r (mm7, mm2); // add may sat at FFF.. - psubusb_r2r (mm7, mm2); // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped - - movq_r2m (mm2, *output); // move in our clipped best - - // Advance to the next set of pixels. - output += 8; - m0 += 8; - t1 += 8; - b1 += 8; - m2 += 8; - } - emms (); - if (width > 0) - deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output, - width); -} - -#include "sse.h" - -static void -deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlaceMethodGreedyL * - self, uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2, - uint8_t * output, int width) -{ - mmx_t MaxComb; - - // How badly do we let it weave? 0-255 - MaxComb.ub[0] = self->max_comb; - MaxComb.ub[1] = self->max_comb; - MaxComb.ub[2] = self->max_comb; - MaxComb.ub[3] = self->max_comb; - MaxComb.ub[4] = self->max_comb; - MaxComb.ub[5] = self->max_comb; - MaxComb.ub[6] = self->max_comb; - MaxComb.ub[7] = self->max_comb; - - // L2 == m0 - // L1 == t1 - // L3 == b1 - // LP2 == m2 - - movq_m2r (MaxComb, mm6); - - for (; width > 7; width -= 8) { - movq_m2r (*t1, mm1); // L1 - movq_m2r (*m0, mm2); // L2 - movq_m2r (*b1, mm3); // L3 - movq_m2r (*m2, mm0); // LP2 - - // average L1 and L3 leave result in mm4 - movq_r2r (mm1, mm4); // L1 - pavgb_r2r (mm3, mm4); // (L1 + L3)/2 - - // get abs value of possible L2 comb - movq_r2r (mm2, mm7); // L2 - psubusb_r2r (mm4, mm7); // L2 - avg - movq_r2r (mm4, mm5); // avg - psubusb_r2r (mm2, mm5); // avg - L2 - por_r2r (mm7, mm5); // abs(avg-L2) - - // get abs value of possible LP2 comb - movq_r2r (mm0, mm7); // LP2 - psubusb_r2r (mm4, mm7); // LP2 - avg - psubusb_r2r (mm0, mm4); // avg - LP2 - por_r2r (mm7, mm4); // abs(avg-LP2) - - // use L2 or LP2 depending upon which makes smaller comb - psubusb_r2r (mm5, mm4); // see if it goes to zero - pxor_r2r (mm5, mm5); // 0 - pcmpeqb_r2r (mm5, mm4); // if (mm4=0) then FF else 0 - pcmpeqb_r2r (mm4, mm5); // opposite of mm4 - - // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55 - pand_r2r (mm2, mm5); // use L2 if mm5 == ff, else 0 - pand_r2r (mm0, mm4); // use LP2 if mm4 = ff, else 0 - por_r2r (mm5, mm4); // may the best win - - // Now lets clip our chosen value to be not outside of the range - // of the high/low range L1-L3 by more than abs(L1-L3) - // This allows some comb but limits the damages and also allows more - // detail than a boring oversmoothed clip. - - movq_r2r (mm1, mm2); // copy L1 - pmaxub_r2r (mm3, mm2); // now = Max(L1,L3) - - pminub_r2r (mm1, mm3); // now = Min(L1,L3) - - // allow the value to be above the high or below the low by amt of MaxComb - paddusb_r2r (mm6, mm2); // increase max by diff - psubusb_r2r (mm6, mm3); // lower min by diff - - - pmaxub_r2r (mm3, mm4); // now = Max(best,Min(L1,L3) - pminub_r2r (mm4, mm2); // now = Min( Max(best, Min(L1,L3)), L2 )=L2 clipped - - movq_r2m (mm2, *output); // move in our clipped best - - // Advance to the next set of pixels. - output += 8; - m0 += 8; - t1 += 8; - b1 += 8; - m2 += 8; - } - emms (); - - if (width > 0) - deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output, - width); -} - -#endif - -static void -deinterlace_frame_di_greedy (GstDeinterlaceMethod * d_method, - GstDeinterlace2 * object, GstBuffer * outbuf) -{ - GstDeinterlaceMethodGreedyL *self = - GST_DEINTERLACE_METHOD_GREEDY_L (d_method); - GstDeinterlaceMethodGreedyLClass *klass = - GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS (self); - int InfoIsOdd = 0; - int Line; - unsigned int Pitch = object->field_stride; - unsigned char *L1; // ptr to Line1, of 3 - unsigned char *L2; // ptr to Line2, the weave line - unsigned char *L3; // ptr to Line3 - - unsigned char *L2P; // ptr to prev Line2 - unsigned char *Dest = GST_BUFFER_DATA (outbuf); - - // copy first even line no matter what, and the first odd line if we're - // processing an EVEN field. (note diff from other deint rtns.) - - if (object->field_history[object->history_count - 1].flags == - PICTURE_INTERLACED_BOTTOM) { - InfoIsOdd = 1; - - L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); - L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf); - L3 = L1 + Pitch; - L2P = - GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf); - - // copy first even line - oil_memcpy (Dest, L1, object->row_stride); - Dest += object->row_stride; - } else { - InfoIsOdd = 0; - L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); - L2 = GST_BUFFER_DATA (object->field_history[object->history_count - - 1].buf) + Pitch; - L3 = L1 + Pitch; - L2P = - GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) + - Pitch; - - // copy first even line - oil_memcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf), - object->row_stride); - Dest += object->row_stride; - // then first odd line - oil_memcpy (Dest, L1, object->row_stride); - Dest += object->row_stride; - } - - for (Line = 0; Line < (object->field_height - 1); ++Line) { - klass->scanline (self, L2, L1, L3, L2P, Dest, object->row_stride); - Dest += object->row_stride; - oil_memcpy (Dest, L3, object->row_stride); - Dest += object->row_stride; - - L1 += Pitch; - L2 += Pitch; - L3 += Pitch; - L2P += Pitch; - } - - if (InfoIsOdd) { - oil_memcpy (Dest, L2, object->row_stride); - } -} - - -G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l, - GST_TYPE_DEINTERLACE_METHOD); - -enum -{ - ARG_0, - ARG_MAX_COMB -}; - -static void -gst_deinterlace_method_greedy_l_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object); - - switch (prop_id) { - case ARG_MAX_COMB: - self->max_comb = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gst_deinterlace_method_greedy_l_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object); - - switch (prop_id) { - case ARG_MAX_COMB: - g_value_set_uint (value, self->max_comb); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass * - klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GObjectClass *gobject_class = (GObjectClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - gobject_class->set_property = gst_deinterlace_method_greedy_l_set_property; - gobject_class->get_property = gst_deinterlace_method_greedy_l_get_property; - - g_object_class_install_property (gobject_class, ARG_MAX_COMB, - g_param_spec_uint ("max-comb", - "Max comb", - "Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - dim_class->fields_required = 4; - dim_class->deinterlace_frame = deinterlace_frame_di_greedy; - dim_class->name = "Motion Adaptive: Simple Detection"; - dim_class->nick = "greedyl"; - dim_class->latency = 1; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { - klass->scanline = deinterlace_greedy_packed422_scanline_mmxext; - } else if (cpu_flags & OIL_IMPL_FLAG_MMX) { - klass->scanline = deinterlace_greedy_packed422_scanline_mmx; - } else { - klass->scanline = deinterlace_greedy_packed422_scanline_c; - } -#else - klass->scanline = deinterlace_greedy_packed422_scanline_c; -#endif -} - -static void -gst_deinterlace_method_greedy_l_init (GstDeinterlaceMethodGreedyL * self) -{ - self->max_comb = 15; -} diff --git a/gst/deinterlace2/tvtime/greedyh.asm b/gst/deinterlace2/tvtime/greedyh.asm deleted file mode 100644 index 86e97c58..00000000 --- a/gst/deinterlace2/tvtime/greedyh.asm +++ /dev/null @@ -1,250 +0,0 @@ -/* - * - * GStreamer - * Copyright (c) 2001 Tom Barry. All rights reserved. - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - - -/* - * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - - -#include "x86-64_macros.inc" - -void -FUNCT_NAME (GstDeinterlaceMethodGreedyH *self, uint8_t * L1, uint8_t * L2, uint8_t * L3, uint8_t * L2P, - uint8_t * Dest, int size) -{ - - // in tight loop some vars are accessed faster in local storage - int64_t YMask = 0x00ff00ff00ff00ffull; // to keep only luma - int64_t UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma - int64_t ShiftMask = 0xfefefefefefefefeull; // to avoid shifting chroma to luma - int64_t QW256 = 0x0100010001000100ull; // 4 256's - int64_t MaxComb; - int64_t MotionThreshold; - int64_t MotionSense; - int64_t i; - long LoopCtr; - long oldbx; - - int64_t QW256B; - int64_t LastAvg = 0; //interp value from left qword - - // FIXME: Use C implementation if the width is not a multiple of 4 - // Do something more optimal later - if (size % 8 != 0) - greedyDScaler_C (self, L1, L2, L3, L2P, Dest, size); - - // Set up our two parms that are actually evaluated for each pixel - i = self->max_comb; - MaxComb = - i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i; - - i = self->motion_threshold; // scale to range of 0-257 - MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask; - - i = self->motion_sense; // scale to range of 0-257 - MotionSense = i << 48 | i << 32 | i << 16 | i; - - i = 0xffffffff - 256; - QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct. - - LoopCtr = size / 8 - 1; // there are LineLength / 8 qwords per line but do 1 less, adj at end of loop - - // For ease of reading, the comments below assume that we're operating on an odd - // field (i.e., that InfoIsOdd is true). Assume the obvious for even lines.. - __asm__ __volatile__ ( - // save ebx (-fPIC) - MOVX " %%" XBX ", %[oldbx]\n\t" - MOVX " %[L1], %%" XAX "\n\t" - LEAX " 8(%%" XAX "), %%" XBX "\n\t" // next qword needed by DJR - MOVX " %[L3], %%" XCX "\n\t" - SUBX " %%" XAX ", %%" XCX "\n\t" // carry L3 addr as an offset - MOVX " %[L2P], %%" XDX "\n\t" - MOVX " %[L2], %%" XSI "\n\t" - MOVX " %[Dest], %%" XDI "\n\t" // DL1 if Odd or DL2 if Even - - ".align 8\n\t" - "1:\n\t" - "movq (%%" XSI "), %%mm0\n\t" // L2 - the newest weave pixel value - "movq (%%" XAX "), %%mm1\n\t" // L1 - the top pixel - "movq (%%" XDX "), %%mm2\n\t" // L2P - the prev weave pixel - "movq (%%" XAX ", %%" XCX "), %%mm3\n\t" // L3, next odd row - "movq %%mm1, %%mm6\n\t" // L1 - get simple single pixel interp - - // pavgb mm6, mm3 // use macro below - V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]") - - // DJR - Diagonal Jaggie Reduction - // In the event that we are going to use an average (Bob) pixel we do not want a jagged - // stair step effect. To combat this we avg in the 2 horizontally adjacen pixels into the - // interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels. - - "movq %[LastAvg], %%mm4\n\t" // the bob value from prev qword in row - "movq %%mm6, %[LastAvg]\n\t" // save for next pass - "psrlq $48, %%mm4\n\t" // right justify 1 pixel - "movq %%mm6, %%mm7\n\t" // copy of simple bob pixel - "psllq $16, %%mm7\n\t" // left justify 3 pixels - "por %%mm7, %%mm4\n\t" // and combine - "movq (%%" XBX "), %%mm5\n\t" // next horiz qword from L1 - // pavgb mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below - - V_PAVGB ("%%mm5", "(%%" XBX ",%%" XCX ")", "%%mm7", "%[ShiftMask]") - "psllq $48, %%mm5\n\t" // left just 1 pixel - "movq %%mm6, %%mm7\n\t" // another copy of simple bob pixel - "psrlq $16, %%mm7\n\t" // right just 3 pixels - "por %%mm7, %%mm5\n\t" // combine - // pavgb mm4, mm5 // avg of forward and prev by 1 pixel, use macro - V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]") // mm5 gets modified if MMX - // pavgb mm6, mm4 // avg of center and surround interp vals, use macro - V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]") - - // Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors. -#ifndef IS_MMX - // pavgb mm4, mm6 // 1/4 center, 3/4 adjacent - V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]") - // pavgb mm6, mm4 // 3/8 center, 5/8 adjacent - V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]") -#endif - - // get abs value of possible L2 comb - "movq %%mm6, %%mm4\n\t" // work copy of interp val - "movq %%mm2, %%mm7\n\t" // L2 - "psubusb %%mm4, %%mm7\n\t" // L2 - avg - "movq %%mm4, %%mm5\n\t" // avg - "psubusb %%mm2, %%mm5\n\t" // avg - L2 - "por %%mm7, %%mm5\n\t" // abs(avg-L2) - - // get abs value of possible L2P comb - "movq %%mm0, %%mm7\n\t" // L2P - "psubusb %%mm4, %%mm7\n\t" // L2P - avg - "psubusb %%mm0, %%mm4\n\t" // avg - L2P - "por %%mm7, %%mm4\n\t" // abs(avg-L2P) - - // use L2 or L2P depending upon which makes smaller comb - "psubusb %%mm5, %%mm4\n\t" // see if it goes to zero - "psubusb %%mm5, %%mm5\n\t" // 0 - "pcmpeqb %%mm5, %%mm4\n\t" // if (mm4=0) then FF else 0 - "pcmpeqb %%mm4, %%mm5\n\t" // opposite of mm4 - - // if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55 - "pand %%mm2, %%mm5\n\t" // use L2 if mm5 == ff, else 0 - "pand %%mm0, %%mm4\n\t" // use L2P if mm4 = ff, else 0 - "por %%mm5, %%mm4\n\t" // may the best win - - // Inventory: at this point we have the following values: - // mm0 = L2P (or L2) - // mm1 = L1 - // mm2 = L2 (or L2P) - // mm3 = L3 - // mm4 = the best of L2,L2P weave pixel, base upon comb - // mm6 = the avg interpolated value, if we need to use it - // Let's measure movement, as how much the weave pixel has changed - - "movq %%mm2, %%mm7\n\t" - "psubusb %%mm0, %%mm2\n\t" - "psubusb %%mm7, %%mm0\n\t" - "por %%mm2, %%mm0\n\t" // abs value of change, used later - - // Now lets clip our chosen value to be not outside of the range - // of the high/low range L1-L3 by more than MaxComb. - // This allows some comb but limits the damages and also allows more - // detail than a boring oversmoothed clip. - - "movq %%mm1, %%mm2\n\t" // copy L1 - // pmaxub mm2, mm3 // use macro - V_PMAXUB ("%%mm2", "%%mm3") // now = Max(L1,L3) - "movq %%mm1, %%mm5\n\t" // copy L1 - // pminub mm5, mm3 // now = Min(L1,L3), use macro - V_PMINUB ("%%mm5", "%%mm3", "%%mm7") - - // allow the value to be above the high or below the low by amt of MaxComb - "psubusb %[MaxComb], %%mm5\n\t" // lower min by diff - "paddusb %[MaxComb], %%mm2\n\t" // increase max by diff - // pmaxub mm4, mm5 // now = Max(best,Min(L1,L3) use macro - V_PMAXUB ("%%mm4", "%%mm5") - // pminub mm4, mm2 // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped - V_PMINUB ("%%mm4", "%%mm2", "%%mm7") - - // Blend weave pixel with bob pixel, depending on motion val in mm0 - "psubusb %[MotionThreshold], %%mm0\n\t" // test Threshold, clear chroma change >>>?? - "pmullw %[MotionSense], %%mm0\n\t" // mul by user factor, keep low 16 bits - "movq %[QW256], %%mm7\n\t" -#ifdef IS_MMXEXT - "pminsw %%mm7, %%mm0\n\t" // max = 256 -#else - "paddusw %[QW256B], %%mm0\n\t" // add, may sat at fff.. - "psubusw %[QW256B], %%mm0\n\t" // now = Min(L1,256) -#endif - "psubusw %%mm0, %%mm7\n\t" // so the 2 sum to 256, weighted avg - "movq %%mm4, %%mm2\n\t" // save weave chroma info before trashing - "pand %[YMask], %%mm4\n\t" // keep only luma from calc'd value - "pmullw %%mm7, %%mm4\n\t" // use more weave for less motion - "pand %[YMask], %%mm6\n\t" // keep only luma from calc'd value - "pmullw %%mm0, %%mm6\n\t" // use more bob for large motion - "paddusw %%mm6, %%mm4\n\t" // combine - "psrlw $8, %%mm4\n\t" // div by 256 to get weighted avg - // chroma comes from weave pixel - "pand %[UVMask], %%mm2\n\t" // keep chroma - "por %%mm4, %%mm2\n\t" // and combine - V_MOVNTQ ("(%%" XDI ")", "%%mm2") // move in our clipped best, use macro - // bump ptrs and loop - LEAX " 8(%%" XAX "), %%" XAX "\n\t" - LEAX " 8(%%" XBX "), %%" XBX "\n\t" - LEAX " 8(%%" XDX "), %%" XDX "\n\t" - LEAX " 8(%%" XDI "), %%" XDI "\n\t" - LEAX " 8(%%" XSI "), %%" XSI "\n\t" - DECX " %[LoopCtr]\n\t" - - "jg 1b\n\t" // loop if not to last line - // note P-III default assumes backward branches taken - "jl 1f\n\t" // done - MOVX " %%" XAX ", %%" XBX "\n\t" // sharpness lookahead 1 byte only, be wrong on 1 - "jmp 1b\n\t" - - "1:\n\t" - MOVX " %[oldbx], %%" XBX "\n\t" - "emms\n\t": /* no outputs */ - - :[LastAvg] "m" (LastAvg), - [L1] "m" (L1), - [L3] "m" (L3), - [L2P] "m" (L2P), - [L2] "m" (L2), - [Dest] "m" (Dest), - [ShiftMask] "m" (ShiftMask), - [MaxComb] "m" (MaxComb), - [MotionThreshold] "m" (MotionThreshold), - [MotionSense] "m" (MotionSense), - [QW256B] "m" (QW256B), - [YMask] "m" (YMask), - [UVMask] "m" (UVMask), - [LoopCtr] "m" (LoopCtr), - [QW256] "m" (QW256), - [oldbx] "m" (oldbx) - : XAX, XCX, XDX, XSI, XDI, - "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", -#ifdef __MMX__ - "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", -#endif - "memory", "cc"); -} diff --git a/gst/deinterlace2/tvtime/greedyh.c b/gst/deinterlace2/tvtime/greedyh.c deleted file mode 100644 index a5aafd18..00000000 --- a/gst/deinterlace2/tvtime/greedyh.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * - * GStreamer - * Copyright (C) 2004 Billy Biggs - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - -/* - * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "greedyhmacros.h" - -#include -#include "_stdint.h" -#include - -#include "gst/gst.h" -#include "plugins.h" -#include "gstdeinterlace2.h" - -#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H)) -#define GST_IS_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H)) -#define GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass)) -#define GST_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyH)) -#define GST_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass)) -#define GST_DEINTERLACE_METHOD_GREEDY_H_CAST(obj) ((GstDeinterlaceMethodGreedyH*)(obj)) - -GType gst_deinterlace_method_greedy_h_get_type (void); - -typedef struct -{ - GstDeinterlaceMethod parent; - - guint max_comb, motion_threshold, motion_sense; -} GstDeinterlaceMethodGreedyH; - -typedef struct -{ - GstDeinterlaceMethodClass parent_class; - void (*scanline) (GstDeinterlaceMethodGreedyH * self, uint8_t * L2, - uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size); -} GstDeinterlaceMethodGreedyHClass; - -void -greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2, - uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size) -{ - int Pos; - uint8_t l1_l, l1_1_l, l3_l, l3_1_l; - uint8_t l1_c, l1_1_c, l3_c, l3_1_c; - uint8_t avg_l, avg_c, avg_l_1, avg_c_1; - uint8_t avg_l__1 = 0, avg_c__1 = 0; - uint8_t avg_s_l, avg_s_c; - uint8_t avg_sc_l, avg_sc_c; - uint8_t best_l, best_c; - uint16_t mov_l; - uint8_t out_l, out_c; - uint8_t l2_l, l2_c, lp2_l, lp2_c; - uint8_t l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff; - uint8_t min_l, min_c, max_l, max_c; - guint max_comb = self->max_comb; - guint motion_sense = self->motion_sense; - guint motion_threshold = self->motion_threshold; - - for (Pos = 0; Pos < size; Pos += 2) { - l1_l = L1[0]; - l1_c = L1[1]; - l3_l = L3[0]; - l3_c = L3[1]; - - if (Pos == size - 1) { - l1_1_l = l1_l; - l1_1_c = l1_c; - l3_1_l = l3_l; - l3_1_c = l3_c; - } else { - l1_1_l = L1[2]; - l1_1_c = L1[3]; - l3_1_l = L3[2]; - l3_1_c = L3[3]; - } - - /* Average of L1 and L3 */ - avg_l = (l1_l + l3_l) / 2; - avg_c = (l1_c + l3_c) / 2; - - if (Pos == 0) { - avg_l__1 = avg_l; - avg_c__1 = avg_c; - } - - /* Average of next L1 and next L3 */ - avg_l_1 = (l1_1_l + l3_1_l) / 2; - avg_c_1 = (l1_1_c + l3_1_c) / 2; - - /* Calculate average of one pixel forward and previous */ - avg_s_l = (avg_l__1 + avg_l_1) / 2; - avg_s_c = (avg_c__1 + avg_c_1) / 2; - - /* Calculate average of center and surrounding pixels */ - avg_sc_l = (avg_l + avg_s_l) / 2; - avg_sc_c = (avg_c + avg_s_c) / 2; - - /* move forward */ - avg_l__1 = avg_l; - avg_c__1 = avg_c; - - /* Get best L2/L2P, i.e. least diff from above average */ - l2_l = L2[0]; - l2_c = L2[1]; - lp2_l = L2P[0]; - lp2_c = L2P[1]; - - l2_l_diff = ABS (l2_l - avg_sc_l); - l2_c_diff = ABS (l2_c - avg_sc_c); - - lp2_l_diff = ABS (lp2_l - avg_sc_l); - lp2_c_diff = ABS (lp2_c - avg_sc_c); - - if (l2_l_diff > lp2_l_diff) - best_l = lp2_l; - else - best_l = l2_l; - - if (l2_c_diff > lp2_c_diff) - best_c = lp2_c; - else - best_c = l2_c; - - /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */ - max_l = MAX (l1_l, l3_l); - min_l = MIN (l1_l, l3_l); - - if (max_l < 256 - max_comb) - max_l += max_comb; - else - max_l = 255; - - if (min_l > max_comb) - min_l -= max_comb; - else - min_l = 0; - - max_c = MAX (l1_c, l3_c); - min_c = MIN (l1_c, l3_c); - - if (max_c < 256 - max_comb) - max_c += max_comb; - else - max_c = 255; - - if (min_c > max_comb) - min_c -= max_comb; - else - min_c = 0; - - out_l = CLAMP (best_l, min_l, max_l); - out_c = CLAMP (best_c, min_c, max_c); - - /* Do motion compensation for luma, i.e. how much - * the weave pixel differs */ - mov_l = ABS (l2_l - lp2_l); - if (mov_l > motion_threshold) - mov_l -= motion_threshold; - else - mov_l = 0; - - mov_l = mov_l * motion_sense; - if (mov_l > 256) - mov_l = 256; - - /* Weighted sum on clipped weave pixel and average */ - out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256; - - Dest[0] = out_l; - Dest[1] = out_c; - - Dest += 2; - L1 += 2; - L2 += 2; - L3 += 2; - L2P += 2; - } -} - -#ifdef BUILD_X86_ASM - -#define IS_MMXEXT -#define SIMD_TYPE MMXEXT -#define FUNCT_NAME greedyDScaler_MMXEXT -#include "greedyh.asm" -#undef SIMD_TYPE -#undef IS_MMXEXT -#undef FUNCT_NAME - -#define IS_3DNOW -#define SIMD_TYPE 3DNOW -#define FUNCT_NAME greedyDScaler_3DNOW -#include "greedyh.asm" -#undef SIMD_TYPE -#undef IS_3DNOW -#undef FUNCT_NAME - -#define IS_MMX -#define SIMD_TYPE MMX -#define FUNCT_NAME greedyDScaler_MMX -#include "greedyh.asm" -#undef SIMD_TYPE -#undef IS_MMX -#undef FUNCT_NAME - -#endif - -static void -deinterlace_frame_di_greedyh (GstDeinterlaceMethod * d_method, - GstDeinterlace2 * object, GstBuffer * outbuf) -{ - GstDeinterlaceMethodGreedyH *self = - GST_DEINTERLACE_METHOD_GREEDY_H (d_method); - GstDeinterlaceMethodGreedyHClass *klass = - GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); - int InfoIsOdd = 0; - int Line; - unsigned int Pitch = object->field_stride; - - unsigned char *L1; // ptr to Line1, of 3 - unsigned char *L2; // ptr to Line2, the weave line - unsigned char *L3; // ptr to Line3 - - unsigned char *L2P; // ptr to prev Line2 - unsigned char *Dest = GST_BUFFER_DATA (outbuf); - - // copy first even line no matter what, and the first odd line if we're - // processing an EVEN field. (note diff from other deint rtns.) - - if (object->field_history[object->history_count - 1].flags == - PICTURE_INTERLACED_BOTTOM) { - InfoIsOdd = 1; - - L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); - L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf); - L3 = L1 + Pitch; - L2P = - GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf); - - // copy first even line - oil_memcpy (Dest, L1, object->row_stride); - Dest += object->row_stride; - } else { - InfoIsOdd = 0; - L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); - L2 = GST_BUFFER_DATA (object->field_history[object->history_count - - 1].buf) + Pitch; - L3 = L1 + Pitch; - L2P = - GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) + - Pitch; - - // copy first even line - oil_memcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf), - object->row_stride); - Dest += object->row_stride; - // then first odd line - oil_memcpy (Dest, L1, object->row_stride); - Dest += object->row_stride; - } - - for (Line = 0; Line < (object->field_height - 1); ++Line) { - klass->scanline (self, L1, L2, L3, L2P, Dest, object->row_stride); - Dest += object->row_stride; - oil_memcpy (Dest, L3, object->row_stride); - Dest += object->row_stride; - - L1 += Pitch; - L2 += Pitch; - L3 += Pitch; - L2P += Pitch; - } - - if (InfoIsOdd) { - oil_memcpy (Dest, L2, object->row_stride); - } -} - -G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h, - GST_TYPE_DEINTERLACE_METHOD); - -enum -{ - ARG_0, - ARG_MAX_COMB, - ARG_MOTION_THRESHOLD, - ARG_MOTION_SENSE -}; - -static void -gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object); - - switch (prop_id) { - case ARG_MAX_COMB: - self->max_comb = g_value_get_uint (value); - break; - case ARG_MOTION_THRESHOLD: - self->motion_threshold = g_value_get_uint (value); - break; - case ARG_MOTION_SENSE: - self->motion_sense = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object); - - switch (prop_id) { - case ARG_MAX_COMB: - g_value_set_uint (value, self->max_comb); - break; - case ARG_MOTION_THRESHOLD: - g_value_set_uint (value, self->motion_threshold); - break; - case ARG_MOTION_SENSE: - g_value_set_uint (value, self->motion_sense); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass * - klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GObjectClass *gobject_class = (GObjectClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property; - gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property; - - g_object_class_install_property (gobject_class, ARG_MAX_COMB, - g_param_spec_uint ("max-comb", - "Max comb", - "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - g_object_class_install_property (gobject_class, ARG_MOTION_THRESHOLD, - g_param_spec_uint ("motion-threshold", - "Motion Threshold", - "Motion Threshold", - 0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - g_object_class_install_property (gobject_class, ARG_MOTION_SENSE, - g_param_spec_uint ("motion-sense", - "Motion Sense", - "Motion Sense", - 0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - dim_class->fields_required = 4; - dim_class->deinterlace_frame = deinterlace_frame_di_greedyh; - dim_class->name = "Motion Adaptive: Advanced Detection"; - dim_class->nick = "greedyh"; - dim_class->latency = 1; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { - klass->scanline = greedyDScaler_MMXEXT; - } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) { - klass->scanline = greedyDScaler_3DNOW; - } else if (cpu_flags & OIL_IMPL_FLAG_MMX) { - klass->scanline = greedyDScaler_MMX; - } else { - klass->scanline = greedyDScaler_C; - } -#else - klass->scanline = greedyDScaler_C; -#endif -} - -static void -gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self) -{ - self->max_comb = 5; - self->motion_threshold = 25; - self->motion_sense = 30; -} diff --git a/gst/deinterlace2/tvtime/greedyhmacros.h b/gst/deinterlace2/tvtime/greedyhmacros.h deleted file mode 100644 index 0386c28e..00000000 --- a/gst/deinterlace2/tvtime/greedyhmacros.h +++ /dev/null @@ -1,75 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2001 Tom Barry. All rights reserved. -///////////////////////////////////////////////////////////////////////////// -// -// This file is subject to the terms of the GNU General Public License as -// published by the Free Software Foundation. A copy of this license is -// included with this software distribution in the file COPYING. If you -// do not have a copy, you may obtain a copy by writing to the Free -// Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -// -// This software 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 General Public License for more details -// -///////////////////////////////////////////////////////////////////////////// - -// Define a few macros for CPU dependent instructions. -// I suspect I don't really understand how the C macro preprocessor works but -// this seems to get the job done. // TRB 7/01 - -// BEFORE USING THESE YOU MUST SET: - -// #define SIMD_TYPE MMXEXT (or MMX or 3DNOW) - -// some macros for pavgb instruction -// V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it - -#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \ - "movq "mmr2", "mmrw"\n\t" \ - "pand "smask", "mmrw"\n\t" \ - "psrlw $1, "mmrw"\n\t" \ - "pand "smask", "mmr1"\n\t" \ - "psrlw $1, "mmr1"\n\t" \ - "paddusb "mmrw", "mmr1"\n\t" -#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask) "pavgb "mmr2", "mmr1"\n\t" -#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask) "pavgusb "mmr2", "mmr1"\n\t" -#define V_PAVGB(mmr1, mmr2, mmrw, smask) V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE) -#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) -#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask) - -// some macros for pmaxub instruction -#define V_PMAXUB_MMX(mmr1, mmr2) \ - "psubusb "mmr2", "mmr1"\n\t" \ - "paddusb "mmr2", "mmr1"\n\t" -#define V_PMAXUB_MMXEXT(mmr1, mmr2) "pmaxub "mmr2", "mmr1"\n\t" -#define V_PMAXUB_3DNOW(mmr1, mmr2) V_PMAXUB_MMX(mmr1, mmr2) // use MMX version -#define V_PMAXUB(mmr1, mmr2) V_PMAXUB2(mmr1, mmr2, SIMD_TYPE) -#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type) -#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2) - -// some macros for pminub instruction -// V_PMINUB(mmr1, mmr2, mmr work register) mmr2 may NOT = mmrw -#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \ - "pcmpeqb "mmrw", "mmrw"\n\t" \ - "psubusb "mmr2", "mmrw"\n\t" \ - "paddusb "mmrw", "mmr1"\n\t" \ - "psubusb "mmrw", "mmr1"\n\t" -#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw) "pminub "mmr2", "mmr1"\n\t" -#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw) V_PMINUB_MMX(mmr1, mmr2, mmrw) // use MMX version -#define V_PMINUB(mmr1, mmr2, mmrw) V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE) -#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type) -#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw) - -// some macros for movntq instruction -// V_MOVNTQ(mmr1, mmr2) -#define V_MOVNTQ_MMX(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ_3DNOW(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ_MMXEXT(mmr1, mmr2) "movntq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ(mmr1, mmr2) V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE) -#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type) -#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2) - -// end of macros - diff --git a/gst/deinterlace2/tvtime/linear.c b/gst/deinterlace2/tvtime/linear.c deleted file mode 100644 index 42403e49..00000000 --- a/gst/deinterlace2/tvtime/linear.c +++ /dev/null @@ -1,214 +0,0 @@ -/** - * Copyright (C) 2002 Billy Biggs . - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_LINEAR (gst_deinterlace_method_linear_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_LINEAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR)) -#define GST_IS_DEINTERLACE_METHOD_LINEAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR)) -#define GST_DEINTERLACE_METHOD_LINEAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass)) -#define GST_DEINTERLACE_METHOD_LINEAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinear)) -#define GST_DEINTERLACE_METHOD_LINEAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass)) -#define GST_DEINTERLACE_METHOD_LINEAR_CAST(obj) ((GstDeinterlaceMethodLinear*)(obj)) - -GType gst_deinterlace_method_linear_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinear; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearClass; - -static void -deinterlace_scanline_linear_c (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - gint i; - - width *= 2; - for (i = 0; i < width; i++) - out[i] = (scanlines->t0[i] + scanlines->b0[i]) / 2; -} - -#ifdef BUILD_X86_ASM -#include "mmx.h" -static void -deinterlace_scanline_linear_mmx (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - const mmx_t shiftmask = { 0xfefffefffefffeffULL }; /* To avoid shifting chroma to luma. */ - int i; - guint8 *bot = scanlines->b0, *top = scanlines->t0; - - for (i = width / 16; i; --i) { - movq_m2r (*bot, mm0); - movq_m2r (*top, mm1); - movq_m2r (*(bot + 8), mm2); - movq_m2r (*(top + 8), mm3); - movq_m2r (*(bot + 16), mm4); - movq_m2r (*(top + 16), mm5); - movq_m2r (*(bot + 24), mm6); - movq_m2r (*(top + 24), mm7); - pand_m2r (shiftmask, mm0); - pand_m2r (shiftmask, mm1); - pand_m2r (shiftmask, mm2); - pand_m2r (shiftmask, mm3); - pand_m2r (shiftmask, mm4); - pand_m2r (shiftmask, mm5); - pand_m2r (shiftmask, mm6); - pand_m2r (shiftmask, mm7); - psrlw_i2r (1, mm0); - psrlw_i2r (1, mm1); - psrlw_i2r (1, mm2); - psrlw_i2r (1, mm3); - psrlw_i2r (1, mm4); - psrlw_i2r (1, mm5); - psrlw_i2r (1, mm6); - psrlw_i2r (1, mm7); - paddb_r2r (mm1, mm0); - paddb_r2r (mm3, mm2); - paddb_r2r (mm5, mm4); - paddb_r2r (mm7, mm6); - movq_r2m (mm0, *out); - movq_r2m (mm2, *(out + 8)); - movq_r2m (mm4, *(out + 16)); - movq_r2m (mm6, *(out + 24)); - out += 32; - top += 32; - bot += 32; - } - width = (width & 0xf); - - for (i = width / 4; i; --i) { - movq_m2r (*bot, mm0); - movq_m2r (*top, mm1); - pand_m2r (shiftmask, mm0); - pand_m2r (shiftmask, mm1); - psrlw_i2r (1, mm0); - psrlw_i2r (1, mm1); - paddb_r2r (mm1, mm0); - movq_r2m (mm0, *out); - out += 8; - top += 8; - bot += 8; - } - width = width & 0x7; - - /* Handle last few pixels. */ - for (i = width * 2; i; --i) { - *out++ = ((*top++) + (*bot++)) >> 1; - } - - emms (); -} - -#include "sse.h" -static void -deinterlace_scanline_linear_mmxext (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - gint i; - guint8 *bot = scanlines->b0, *top = scanlines->t0; - - for (i = width / 16; i; --i) { - movq_m2r (*bot, mm0); - movq_m2r (*top, mm1); - movq_m2r (*(bot + 8), mm2); - movq_m2r (*(top + 8), mm3); - movq_m2r (*(bot + 16), mm4); - movq_m2r (*(top + 16), mm5); - movq_m2r (*(bot + 24), mm6); - movq_m2r (*(top + 24), mm7); - pavgb_r2r (mm1, mm0); - pavgb_r2r (mm3, mm2); - pavgb_r2r (mm5, mm4); - pavgb_r2r (mm7, mm6); - movntq_r2m (mm0, *out); - movntq_r2m (mm2, *(out + 8)); - movntq_r2m (mm4, *(out + 16)); - movntq_r2m (mm6, *(out + 24)); - out += 32; - top += 32; - bot += 32; - } - width = (width & 0xf); - - for (i = width / 4; i; --i) { - movq_m2r (*bot, mm0); - movq_m2r (*top, mm1); - pavgb_r2r (mm1, mm0); - movntq_r2m (mm0, *out); - out += 8; - top += 8; - bot += 8; - } - width = width & 0x7; - - /* Handle last few pixels. */ - for (i = width * 2; i; --i) { - *out++ = ((*top++) + (*bot++)) >> 1; - } - - emms (); -} - -#endif - -G_DEFINE_TYPE (GstDeinterlaceMethodLinear, gst_deinterlace_method_linear, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_linear_class_init (GstDeinterlaceMethodLinearClass * - klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - dim_class->fields_required = 1; - dim_class->name = "Television: Full resolution"; - dim_class->nick = "linear"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_linear_c; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { - dism_class->interpolate_scanline = deinterlace_scanline_linear_mmxext; - } else if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { - dism_class->interpolate_scanline = deinterlace_scanline_linear_mmx; - } -#endif -} - -static void -gst_deinterlace_method_linear_init (GstDeinterlaceMethodLinear * self) -{ -} diff --git a/gst/deinterlace2/tvtime/linearblend.c b/gst/deinterlace2/tvtime/linearblend.c deleted file mode 100644 index c25c4d0e..00000000 --- a/gst/deinterlace2/tvtime/linearblend.c +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Linear blend deinterlacing plugin. The idea for this algorithm came - * from the linear blend deinterlacer which originated in the mplayer - * sources. - * - * Copyright (C) 2002 Billy Biggs . - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND)) -#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND)) -#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass)) -#define GST_DEINTERLACE_METHOD_LINEAR_BLEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlend)) -#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass)) -#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CAST(obj) ((GstDeinterlaceMethodLinearBlend*)(obj)) - -GType gst_deinterlace_method_linear_blend_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinearBlend; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearBlendClass; - - -static inline void -deinterlace_scanline_linear_blend_c (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - guint8 *t0 = scanlines->t0; - guint8 *b0 = scanlines->b0; - guint8 *m1 = scanlines->m1; - - width *= 2; - - while (width--) { - *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2; - } -} - -static inline void -deinterlace_scanline_linear_blend2_c (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - guint8 *m0 = scanlines->m0; - guint8 *t1 = scanlines->t1; - guint8 *b1 = scanlines->b1; - - width *= 2; - while (width--) { - *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2; - } -} - -#ifdef BUILD_X86_ASM -#include "mmx.h" -static inline void -deinterlace_scanline_linear_blend_mmx (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - guint8 *t0 = scanlines->t0; - guint8 *b0 = scanlines->b0; - guint8 *m1 = scanlines->m1; - gint i; - - // Get width in bytes. - width *= 2; - i = width / 8; - width -= i * 8; - - pxor_r2r (mm7, mm7); - while (i--) { - movd_m2r (*t0, mm0); - movd_m2r (*b0, mm1); - movd_m2r (*m1, mm2); - - movd_m2r (*(t0 + 4), mm3); - movd_m2r (*(b0 + 4), mm4); - movd_m2r (*(m1 + 4), mm5); - - punpcklbw_r2r (mm7, mm0); - punpcklbw_r2r (mm7, mm1); - punpcklbw_r2r (mm7, mm2); - - punpcklbw_r2r (mm7, mm3); - punpcklbw_r2r (mm7, mm4); - punpcklbw_r2r (mm7, mm5); - - psllw_i2r (1, mm2); - psllw_i2r (1, mm5); - paddw_r2r (mm0, mm2); - paddw_r2r (mm3, mm5); - paddw_r2r (mm1, mm2); - paddw_r2r (mm4, mm5); - psrlw_i2r (2, mm2); - psrlw_i2r (2, mm5); - packuswb_r2r (mm2, mm2); - packuswb_r2r (mm5, mm5); - - movd_r2m (mm2, *out); - movd_r2m (mm5, *(out + 4)); - out += 8; - t0 += 8; - b0 += 8; - m1 += 8; - } - while (width--) { - *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2; - } - emms (); -} - -static inline void -deinterlace_scanline_linear_blend2_mmx (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - guint8 *m0 = scanlines->m0; - guint8 *t1 = scanlines->t1; - guint8 *b1 = scanlines->b1; - gint i; - - // Get width in bytes. - width *= 2; - i = width / 8; - width -= i * 8; - - pxor_r2r (mm7, mm7); - while (i--) { - movd_m2r (*t1, mm0); - movd_m2r (*b1, mm1); - movd_m2r (*m0, mm2); - - movd_m2r (*(t1 + 4), mm3); - movd_m2r (*(b1 + 4), mm4); - movd_m2r (*(m0 + 4), mm5); - - punpcklbw_r2r (mm7, mm0); - punpcklbw_r2r (mm7, mm1); - punpcklbw_r2r (mm7, mm2); - - punpcklbw_r2r (mm7, mm3); - punpcklbw_r2r (mm7, mm4); - punpcklbw_r2r (mm7, mm5); - - psllw_i2r (1, mm2); - psllw_i2r (1, mm5); - paddw_r2r (mm0, mm2); - paddw_r2r (mm3, mm5); - paddw_r2r (mm1, mm2); - paddw_r2r (mm4, mm5); - psrlw_i2r (2, mm2); - psrlw_i2r (2, mm5); - packuswb_r2r (mm2, mm2); - packuswb_r2r (mm5, mm5); - - movd_r2m (mm2, *out); - movd_r2m (mm5, *(out + 4)); - out += 8; - t1 += 8; - b1 += 8; - m0 += 8; - } - while (width--) { - *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2; - } - emms (); -} - -#endif - -G_DEFINE_TYPE (GstDeinterlaceMethodLinearBlend, - gst_deinterlace_method_linear_blend, GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void - gst_deinterlace_method_linear_blend_class_init - (GstDeinterlaceMethodLinearBlendClass * klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - dim_class->fields_required = 2; - dim_class->name = "Blur: Temporal"; - dim_class->nick = "linearblend"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_c; - dism_class->copy_scanline = deinterlace_scanline_linear_blend2_c; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMX) { - dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_mmx; - dism_class->copy_scanline = deinterlace_scanline_linear_blend2_mmx; - } -#endif -} - -static void -gst_deinterlace_method_linear_blend_init (GstDeinterlaceMethodLinearBlend * - self) -{ -} diff --git a/gst/deinterlace2/tvtime/mmx.h b/gst/deinterlace2/tvtime/mmx.h deleted file mode 100644 index 3627e61b..00000000 --- a/gst/deinterlace2/tvtime/mmx.h +++ /dev/null @@ -1,723 +0,0 @@ -/* mmx.h - - MultiMedia eXtensions GCC interface library for IA32. - - To use this library, simply include this header file - and compile with GCC. You MUST have inlining enabled - in order for mmx_ok() to work; this can be done by - simply using -O on the GCC command line. - - Compiling with -DMMX_TRACE will cause detailed trace - output to be sent to stderr for each mmx operation. - This adds lots of code, and obviously slows execution to - a crawl, but can be very useful for debugging. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT - LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR ANY PARTICULAR PURPOSE. - - 1997-98 by H. Dietz and R. Fisher - - History: - 97-98* R.Fisher Early versions - 980501 R.Fisher Original Release - 980611* H.Dietz Rewrite, correctly implementing inlines, and - R.Fisher including direct register accesses. - 980616 R.Fisher Release of 980611 as 980616. - 980714 R.Fisher Minor corrections to Makefile, etc. - 980715 R.Fisher mmx_ok() now prevents optimizer from using - clobbered values. - mmx_ok() now checks if cpuid instruction is - available before trying to use it. - 980726* R.Fisher mm_support() searches for AMD 3DNow, Cyrix - Extended MMX, and standard MMX. It returns a - value which is positive if any of these are - supported, and can be masked with constants to - see which. mmx_ok() is now a call to this - 980726* R.Fisher Added i2r support for shift functions - 980919 R.Fisher Fixed AMD extended feature recognition bug. - 980921 R.Fisher Added definition/check for _MMX_H. - Added "float s[2]" to mmx_t for use with - 3DNow and EMMX. So same mmx_t can be used. - 981013 R.Fisher Fixed cpuid function 1 bug (looked at wrong reg) - Fixed psllq_i2r error in mmxtest.c - - * Unreleased (internal or interim) versions - - Notes: - It appears that the latest gas has the pand problem fixed, therefore - I'll undefine BROKEN_PAND by default. - String compares may be quicker than the multiple test/jumps in vendor - test sequence in mmx_ok(), but I'm not concerned with that right now. - - Acknowledgments: - Jussi Laako for pointing out the errors ultimately found to be - connected to the failure to notify the optimizer of clobbered values. - Roger Hardiman for reminding us that CPUID isn't everywhere, and that - someone may actually try to use this on a machine without CPUID. - Also for suggesting code for checking this. - Robert Dale for pointing out the AMD recognition bug. - Jimmy Mayfield and Carl Witty for pointing out the Intel recognition - bug. - Carl Witty for pointing out the psllq_i2r test bug. -*/ - -#ifndef _MMX_H -#define _MMX_H - -/*#define MMX_TRACE */ - -/* Warning: at this writing, the version of GAS packaged - with most Linux distributions does not handle the - parallel AND operation mnemonic correctly. If the - symbol BROKEN_PAND is defined, a slower alternative - coding will be used. If execution of mmxtest results - in an illegal instruction fault, define this symbol. -*/ -#undef BROKEN_PAND - - -/* The type of an value that fits in an MMX register - (note that long long constant values MUST be suffixed - by LL and unsigned long long values by ULL, lest - they be truncated by the compiler) -*/ -typedef union { - long long q; /* Quadword (64-bit) value */ - unsigned long long uq; /* Unsigned Quadword */ - int d[2]; /* 2 Doubleword (32-bit) values */ - unsigned int ud[2]; /* 2 Unsigned Doubleword */ - short w[4]; /* 4 Word (16-bit) values */ - unsigned short uw[4]; /* 4 Unsigned Word */ - char b[8]; /* 8 Byte (8-bit) values */ - unsigned char ub[8]; /* 8 Unsigned Byte */ - float s[2]; /* Single-precision (32-bit) value */ -} mmx_t; - - -/* Function to test if multimedia instructions are supported... -*/ -inline extern int -mm_support(void) -{ - /* Returns 1 if MMX instructions are supported, - 3 if Cyrix MMX and Extended MMX instructions are supported - 5 if AMD MMX and 3DNow! instructions are supported - 0 if hardware does not support any of these - */ - register int rval = 0; - - __asm__ __volatile__ ( - /* See if CPUID instruction is supported ... */ - /* ... Get copies of EFLAGS into eax and ecx */ - "pushf\n\t" - "popl %%eax\n\t" - "movl %%eax, %%ecx\n\t" - - /* ... Toggle the ID bit in one copy and store */ - /* to the EFLAGS reg */ - "xorl $0x200000, %%eax\n\t" - "push %%eax\n\t" - "popf\n\t" - - /* ... Get the (hopefully modified) EFLAGS */ - "pushf\n\t" - "popl %%eax\n\t" - - /* ... Compare and test result */ - "xorl %%eax, %%ecx\n\t" - "testl $0x200000, %%ecx\n\t" - "jz NotSupported1\n\t" /* Nothing supported */ - - - /* Get standard CPUID information, and - go to a specific vendor section */ - "movl $0, %%eax\n\t" - "cpuid\n\t" - - /* Check for Intel */ - "cmpl $0x756e6547, %%ebx\n\t" - "jne TryAMD\n\t" - "cmpl $0x49656e69, %%edx\n\t" - "jne TryAMD\n\t" - "cmpl $0x6c65746e, %%ecx\n" - "jne TryAMD\n\t" - "jmp Intel\n\t" - - /* Check for AMD */ - "\nTryAMD:\n\t" - "cmpl $0x68747541, %%ebx\n\t" - "jne TryCyrix\n\t" - "cmpl $0x69746e65, %%edx\n\t" - "jne TryCyrix\n\t" - "cmpl $0x444d4163, %%ecx\n" - "jne TryCyrix\n\t" - "jmp AMD\n\t" - - /* Check for Cyrix */ - "\nTryCyrix:\n\t" - "cmpl $0x69727943, %%ebx\n\t" - "jne NotSupported2\n\t" - "cmpl $0x736e4978, %%edx\n\t" - "jne NotSupported3\n\t" - "cmpl $0x64616574, %%ecx\n\t" - "jne NotSupported4\n\t" - /* Drop through to Cyrix... */ - - - /* Cyrix Section */ - /* See if extended CPUID is supported */ - "movl $0x80000000, %%eax\n\t" - "cpuid\n\t" - "cmpl $0x80000000, %%eax\n\t" - "jl MMXtest\n\t" /* Try standard CPUID instead */ - - /* Extended CPUID supported, so get extended features */ - "movl $0x80000001, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%eax\n\t" /* Test for MMX */ - "jz NotSupported5\n\t" /* MMX not supported */ - "testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */ - "jnz EMMXSupported\n\t" - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\n" - "EMMXSupported:\n\t" - "movl $3, %0:\n\n\t" /* EMMX and MMX Supported */ - "jmp Return\n\t" - - - /* AMD Section */ - "AMD:\n\t" - - /* See if extended CPUID is supported */ - "movl $0x80000000, %%eax\n\t" - "cpuid\n\t" - "cmpl $0x80000000, %%eax\n\t" - "jl MMXtest\n\t" /* Try standard CPUID instead */ - - /* Extended CPUID supported, so get extended features */ - "movl $0x80000001, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%edx\n\t" /* Test for MMX */ - "jz NotSupported6\n\t" /* MMX not supported */ - "testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */ - "jnz ThreeDNowSupported\n\t" - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\n" - "ThreeDNowSupported:\n\t" - "movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */ - "jmp Return\n\t" - - - /* Intel Section */ - "Intel:\n\t" - - /* Check for MMX */ - "MMXtest:\n\t" - "movl $1, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%edx\n\t" /* Test for MMX */ - "jz NotSupported7\n\t" /* MMX Not supported */ - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\t" - - /* Nothing supported */ - "\nNotSupported1:\n\t" - "#movl $101, %0:\n\n\t" - "\nNotSupported2:\n\t" - "#movl $102, %0:\n\n\t" - "\nNotSupported3:\n\t" - "#movl $103, %0:\n\n\t" - "\nNotSupported4:\n\t" - "#movl $104, %0:\n\n\t" - "\nNotSupported5:\n\t" - "#movl $105, %0:\n\n\t" - "\nNotSupported6:\n\t" - "#movl $106, %0:\n\n\t" - "\nNotSupported7:\n\t" - "#movl $107, %0:\n\n\t" - "movl $0, %0:\n\n\t" - - "Return:\n\t" - : "=a" (rval) - : /* no input */ - : "eax", "ebx", "ecx", "edx" - ); - - /* Return */ - return(rval); -} - -/* Function to test if mmx instructions are supported... -*/ -inline extern int -mmx_ok(void) -{ - /* Returns 1 if MMX instructions are supported, 0 otherwise */ - return ( mm_support() & 0x1 ); -} - - -/* Helper functions for the instruction macros that follow... - (note that memory-to-register, m2r, instructions are nearly - as efficient as register-to-register, r2r, instructions; - however, memory-to-memory instructions are really simulated - as a convenience, and are only 1/3 as efficient) -*/ -#ifdef MMX_TRACE - -/* Include the stuff for printing a trace to stderr... -*/ - -#include - -#define mmx_i2r(op, imm, reg) \ - { \ - mmx_t mmx_trace; \ - mmx_trace = (imm); \ - fprintf(stderr, #op "_i2r(" #imm "=0x%016llx, ", mmx_trace.q); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (imm)); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \ - } - -#define mmx_m2r(op, mem, reg) \ - { \ - mmx_t mmx_trace; \ - mmx_trace = (mem); \ - fprintf(stderr, #op "_m2r(" #mem "=0x%016llx, ", mmx_trace.q); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (mem)); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \ - } - -#define mmx_r2m(op, reg, mem) \ - { \ - mmx_t mmx_trace; \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #op "_r2m(" #reg "=0x%016llx, ", mmx_trace.q); \ - mmx_trace = (mem); \ - fprintf(stderr, #mem "=0x%016llx) => ", mmx_trace.q); \ - __asm__ __volatile__ (#op " %%" #reg ", %0" \ - : "=X" (mem) \ - : /* nothing */ ); \ - mmx_trace = (mem); \ - fprintf(stderr, #mem "=0x%016llx\n", mmx_trace.q); \ - } - -#define mmx_r2r(op, regs, regd) \ - { \ - mmx_t mmx_trace; \ - __asm__ __volatile__ ("movq %%" #regs ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #op "_r2r(" #regs "=0x%016llx, ", mmx_trace.q); \ - __asm__ __volatile__ ("movq %%" #regd ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #regd "=0x%016llx) => ", mmx_trace.q); \ - __asm__ __volatile__ (#op " %" #regs ", %" #regd); \ - __asm__ __volatile__ ("movq %%" #regd ", %0" \ - : "=X" (mmx_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #regd "=0x%016llx\n", mmx_trace.q); \ - } - -#define mmx_m2m(op, mems, memd) \ - { \ - mmx_t mmx_trace; \ - mmx_trace = (mems); \ - fprintf(stderr, #op "_m2m(" #mems "=0x%016llx, ", mmx_trace.q); \ - mmx_trace = (memd); \ - fprintf(stderr, #memd "=0x%016llx) => ", mmx_trace.q); \ - __asm__ __volatile__ ("movq %0, %%mm0\n\t" \ - #op " %1, %%mm0\n\t" \ - "movq %%mm0, %0" \ - : "=X" (memd) \ - : "X" (mems)); \ - mmx_trace = (memd); \ - fprintf(stderr, #memd "=0x%016llx\n", mmx_trace.q); \ - } - -#else - -/* These macros are a lot simpler without the tracing... -*/ - -#define mmx_i2r(op, imm, reg) \ - __asm__ __volatile__ (#op " $" #imm ", %%" #reg \ - : /* nothing */ \ - : /* nothing */); - -#define mmx_m2r(op, mem, reg) \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "m" (mem)) - -#define mmx_r2m(op, reg, mem) \ - __asm__ __volatile__ (#op " %%" #reg ", %0" \ - : "=m" (mem) \ - : /* nothing */ ) - -#define mmx_r2r(op, regs, regd) \ - __asm__ __volatile__ (#op " %" #regs ", %" #regd) - -#define mmx_m2m(op, mems, memd) \ - __asm__ __volatile__ ("movq %0, %%mm0\n\t" \ - #op " %1, %%mm0\n\t" \ - "movq %%mm0, %0" \ - : "=m" (memd) \ - : "m" (mems)) - -#endif - - -/* 1x64 MOVe Quadword - (this is both a load and a store... - in fact, it is the only way to store) -*/ -#define movq_m2r(var, reg) mmx_m2r(movq, var, reg) -#define movq_r2m(reg, var) mmx_r2m(movq, reg, var) -#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd) -#define movq(vars, vard) \ - __asm__ __volatile__ ("movq %1, %%mm0\n\t" \ - "movq %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* 1x32 MOVe Doubleword - (like movq, this is both load and store... - but is most useful for moving things between - mmx registers and ordinary registers) -*/ -#define movd_m2r(var, reg) mmx_m2r(movd, var, reg) -#define movd_r2m(reg, var) mmx_r2m(movd, reg, var) -#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd) -#define movd(vars, vard) \ - __asm__ __volatile__ ("movd %1, %%mm0\n\t" \ - "movd %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* 2x32, 4x16, and 8x8 Parallel ADDs -*/ -#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg) -#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd) -#define paddd(vars, vard) mmx_m2m(paddd, vars, vard) - -#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg) -#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd) -#define paddw(vars, vard) mmx_m2m(paddw, vars, vard) - -#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg) -#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd) -#define paddb(vars, vard) mmx_m2m(paddb, vars, vard) - - -/* 4x16 and 8x8 Parallel ADDs using Saturation arithmetic -*/ -#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg) -#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd) -#define paddsw(vars, vard) mmx_m2m(paddsw, vars, vard) - -#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg) -#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd) -#define paddsb(vars, vard) mmx_m2m(paddsb, vars, vard) - - -/* 4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic -*/ -#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg) -#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd) -#define paddusw(vars, vard) mmx_m2m(paddusw, vars, vard) - -#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg) -#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd) -#define paddusb(vars, vard) mmx_m2m(paddusb, vars, vard) - - -/* 2x32, 4x16, and 8x8 Parallel SUBs -*/ -#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg) -#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd) -#define psubd(vars, vard) mmx_m2m(psubd, vars, vard) - -#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg) -#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd) -#define psubw(vars, vard) mmx_m2m(psubw, vars, vard) - -#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg) -#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd) -#define psubb(vars, vard) mmx_m2m(psubb, vars, vard) - - -/* 4x16 and 8x8 Parallel SUBs using Saturation arithmetic -*/ -#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg) -#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd) -#define psubsw(vars, vard) mmx_m2m(psubsw, vars, vard) - -#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg) -#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd) -#define psubsb(vars, vard) mmx_m2m(psubsb, vars, vard) - - -/* 4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic -*/ -#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg) -#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd) -#define psubusw(vars, vard) mmx_m2m(psubusw, vars, vard) - -#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg) -#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd) -#define psubusb(vars, vard) mmx_m2m(psubusb, vars, vard) - - -/* 4x16 Parallel MULs giving Low 4x16 portions of results -*/ -#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg) -#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd) -#define pmullw(vars, vard) mmx_m2m(pmullw, vars, vard) - - -/* 4x16 Parallel MULs giving High 4x16 portions of results -*/ -#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg) -#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd) -#define pmulhw(vars, vard) mmx_m2m(pmulhw, vars, vard) - - -/* 4x16->2x32 Parallel Mul-ADD - (muls like pmullw, then adds adjacent 16-bit fields - in the multiply result to make the final 2x32 result) -*/ -#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg) -#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd) -#define pmaddwd(vars, vard) mmx_m2m(pmaddwd, vars, vard) - - -/* 1x64 bitwise AND -*/ -#ifdef BROKEN_PAND -#define pand_m2r(var, reg) \ - { \ - mmx_m2r(pandn, (mmx_t) -1LL, reg); \ - mmx_m2r(pandn, var, reg); \ - } -#define pand_r2r(regs, regd) \ - { \ - mmx_m2r(pandn, (mmx_t) -1LL, regd); \ - mmx_r2r(pandn, regs, regd); \ - } -#define pand(vars, vard) \ - { \ - movq_m2r(vard, mm0); \ - mmx_m2r(pandn, (mmx_t) -1LL, mm0); \ - mmx_m2r(pandn, vars, mm0); \ - movq_r2m(mm0, vard); \ - } -#else -#define pand_m2r(var, reg) mmx_m2r(pand, var, reg) -#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd) -#define pand(vars, vard) mmx_m2m(pand, vars, vard) -#endif - - -/* 1x64 bitwise AND with Not the destination -*/ -#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg) -#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd) -#define pandn(vars, vard) mmx_m2m(pandn, vars, vard) - - -/* 1x64 bitwise OR -*/ -#define por_m2r(var, reg) mmx_m2r(por, var, reg) -#define por_r2r(regs, regd) mmx_r2r(por, regs, regd) -#define por(vars, vard) mmx_m2m(por, vars, vard) - - -/* 1x64 bitwise eXclusive OR -*/ -#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg) -#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd) -#define pxor(vars, vard) mmx_m2m(pxor, vars, vard) - - -/* 2x32, 4x16, and 8x8 Parallel CoMPare for EQuality - (resulting fields are either 0 or -1) -*/ -#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg) -#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd) -#define pcmpeqd(vars, vard) mmx_m2m(pcmpeqd, vars, vard) - -#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg) -#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd) -#define pcmpeqw(vars, vard) mmx_m2m(pcmpeqw, vars, vard) - -#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg) -#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd) -#define pcmpeqb(vars, vard) mmx_m2m(pcmpeqb, vars, vard) - - -/* 2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than - (resulting fields are either 0 or -1) -*/ -#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg) -#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd) -#define pcmpgtd(vars, vard) mmx_m2m(pcmpgtd, vars, vard) - -#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg) -#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd) -#define pcmpgtw(vars, vard) mmx_m2m(pcmpgtw, vars, vard) - -#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg) -#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd) -#define pcmpgtb(vars, vard) mmx_m2m(pcmpgtb, vars, vard) - - -/* 1x64, 2x32, and 4x16 Parallel Shift Left Logical -*/ -#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg) -#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg) -#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd) -#define psllq(vars, vard) mmx_m2m(psllq, vars, vard) - -#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg) -#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg) -#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd) -#define pslld(vars, vard) mmx_m2m(pslld, vars, vard) - -#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg) -#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg) -#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd) -#define psllw(vars, vard) mmx_m2m(psllw, vars, vard) - - -/* 1x64, 2x32, and 4x16 Parallel Shift Right Logical -*/ -#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg) -#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg) -#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd) -#define psrlq(vars, vard) mmx_m2m(psrlq, vars, vard) - -#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg) -#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg) -#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd) -#define psrld(vars, vard) mmx_m2m(psrld, vars, vard) - -#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg) -#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg) -#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd) -#define psrlw(vars, vard) mmx_m2m(psrlw, vars, vard) - - -/* 2x32 and 4x16 Parallel Shift Right Arithmetic -*/ -#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg) -#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg) -#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd) -#define psrad(vars, vard) mmx_m2m(psrad, vars, vard) - -#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg) -#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg) -#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd) -#define psraw(vars, vard) mmx_m2m(psraw, vars, vard) - - -/* 2x32->4x16 and 4x16->8x8 PACK and Signed Saturate - (packs source and dest fields into dest in that order) -*/ -#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg) -#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd) -#define packssdw(vars, vard) mmx_m2m(packssdw, vars, vard) - -#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg) -#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd) -#define packsswb(vars, vard) mmx_m2m(packsswb, vars, vard) - - -/* 4x16->8x8 PACK and Unsigned Saturate - (packs source and dest fields into dest in that order) -*/ -#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg) -#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd) -#define packuswb(vars, vard) mmx_m2m(packuswb, vars, vard) - - -/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low - (interleaves low half of dest with low half of source - as padding in each result field) -*/ -#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg) -#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd) -#define punpckldq(vars, vard) mmx_m2m(punpckldq, vars, vard) - -#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg) -#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd) -#define punpcklwd(vars, vard) mmx_m2m(punpcklwd, vars, vard) - -#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg) -#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd) -#define punpcklbw(vars, vard) mmx_m2m(punpcklbw, vars, vard) - - -/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High - (interleaves high half of dest with high half of source - as padding in each result field) -*/ -#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg) -#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd) -#define punpckhdq(vars, vard) mmx_m2m(punpckhdq, vars, vard) - -#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg) -#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd) -#define punpckhwd(vars, vard) mmx_m2m(punpckhwd, vars, vard) - -#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg) -#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd) -#define punpckhbw(vars, vard) mmx_m2m(punpckhbw, vars, vard) - - -/* Empty MMx State - (used to clean-up when going from mmx to float use - of the registers that are shared by both; note that - there is no float-to-mmx operation needed, because - only the float tag word info is corruptible) -*/ -#ifdef MMX_TRACE - -#define emms() \ - { \ - fprintf(stderr, "emms()\n"); \ - __asm__ __volatile__ ("emms"); \ - } - -#else - -#define emms() __asm__ __volatile__ ("emms") - -#endif - -#endif diff --git a/gst/deinterlace2/tvtime/plugins.h b/gst/deinterlace2/tvtime/plugins.h deleted file mode 100644 index 8fb01af5..00000000 --- a/gst/deinterlace2/tvtime/plugins.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * GStreamer - * Copyright (C) 2004 Billy Biggs - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - -/* - * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - -#ifndef TVTIME_PLUGINS_H_INCLUDED -#define TVTIME_PLUGINS_H_INCLUDED - -#define GST_TYPE_DEINTERLACE_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ()) -#define GST_TYPE_DEINTERLACE_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ()) -#define GST_TYPE_DEINTERLACE_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ()) -#define GST_TYPE_DEINTERLACE_VFIR (gst_deinterlace_method_vfir_get_type ()) -#define GST_TYPE_DEINTERLACE_LINEAR (gst_deinterlace_method_linear_get_type ()) -#define GST_TYPE_DEINTERLACE_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ()) -#define GST_TYPE_DEINTERLACE_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ()) -#define GST_TYPE_DEINTERLACE_WEAVE (gst_deinterlace_method_weave_get_type ()) -#define GST_TYPE_DEINTERLACE_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ()) -#define GST_TYPE_DEINTERLACE_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ()) - -GType gst_deinterlace_method_tomsmocomp_get_type (void); -GType gst_deinterlace_method_greedy_h_get_type (void); -GType gst_deinterlace_method_greedy_l_get_type (void); -GType gst_deinterlace_method_vfir_get_type (void); - -GType gst_deinterlace_method_linear_get_type (void); -GType gst_deinterlace_method_linear_blend_get_type (void); -GType gst_deinterlace_method_scaler_bob_get_type (void); -GType gst_deinterlace_method_weave_get_type (void); -GType gst_deinterlace_method_weave_tff_get_type (void); -GType gst_deinterlace_method_weave_bff_get_type (void); - -#endif /* TVTIME_PLUGINS_H_INCLUDED */ diff --git a/gst/deinterlace2/tvtime/scalerbob.c b/gst/deinterlace2/tvtime/scalerbob.c deleted file mode 100644 index a37792ab..00000000 --- a/gst/deinterlace2/tvtime/scalerbob.c +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Double lines - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB)) -#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB)) -#define GST_DEINTERLACE_METHOD_SCALER_BOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass)) -#define GST_DEINTERLACE_METHOD_SCALER_BOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBob)) -#define GST_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass)) -#define GST_DEINTERLACE_METHOD_SCALER_BOB_CAST(obj) ((GstDeinterlaceMethodScalerBob*)(obj)) - -GType gst_deinterlace_method_scaler_bob_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodScalerBob; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodScalerBobClass; - - -static void -deinterlace_scanline_scaler_bob (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->t0, parent->row_stride); -} - -G_DEFINE_TYPE (GstDeinterlaceMethodScalerBob, gst_deinterlace_method_scaler_bob, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_scaler_bob_class_init (GstDeinterlaceMethodScalerBobClass - * klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; - - dim_class->fields_required = 1; - dim_class->name = "Double lines"; - dim_class->nick = "scalerbob"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_scaler_bob; -} - -static void -gst_deinterlace_method_scaler_bob_init (GstDeinterlaceMethodScalerBob * self) -{ -} diff --git a/gst/deinterlace2/tvtime/sse.h b/gst/deinterlace2/tvtime/sse.h deleted file mode 100644 index 2e00ee0c..00000000 --- a/gst/deinterlace2/tvtime/sse.h +++ /dev/null @@ -1,992 +0,0 @@ -/* sse.h - - Streaming SIMD Extenstions (a.k.a. Katmai New Instructions) - GCC interface library for IA32. - - To use this library, simply include this header file - and compile with GCC. You MUST have inlining enabled - in order for sse_ok() to work; this can be done by - simply using -O on the GCC command line. - - Compiling with -DSSE_TRACE will cause detailed trace - output to be sent to stderr for each sse operation. - This adds lots of code, and obviously slows execution to - a crawl, but can be very useful for debugging. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT - LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR ANY PARTICULAR PURPOSE. - - 1999 by R. Fisher - Based on libmmx by H. Dietz and R. Fisher - - Notes: - This is still extremely alpha. - Because this library depends on an assembler which understands the - SSE opcodes, you probably won't be able to use this yet. - For now, do not use TRACE versions. These both make use - of the MMX registers, not the SSE registers. This will be resolved - at a later date. - ToDo: - Rewrite TRACE macros - Major Debugging Work -*/ - -#ifndef _SSE_H -#define _SSE_H - - - -/* The type of an value that fits in an SSE register - (note that long long constant values MUST be suffixed - by LL and unsigned long long values by ULL, lest - they be truncated by the compiler) -*/ -typedef union { - float sf[4]; /* Single-precision (32-bit) value */ -} __attribute__ ((aligned (16))) sse_t; /* On a 16 byte (128-bit) boundary */ - - -#if 0 -/* Function to test if multimedia instructions are supported... -*/ -inline extern int -mm_support(void) -{ - /* Returns 1 if MMX instructions are supported, - 3 if Cyrix MMX and Extended MMX instructions are supported - 5 if AMD MMX and 3DNow! instructions are supported - 9 if MMX and SSE instructions are supported - 0 if hardware does not support any of these - */ - register int rval = 0; - - __asm__ __volatile__ ( - /* See if CPUID instruction is supported ... */ - /* ... Get copies of EFLAGS into eax and ecx */ - "pushf\n\t" - "popl %%eax\n\t" - "movl %%eax, %%ecx\n\t" - - /* ... Toggle the ID bit in one copy and store */ - /* to the EFLAGS reg */ - "xorl $0x200000, %%eax\n\t" - "push %%eax\n\t" - "popf\n\t" - - /* ... Get the (hopefully modified) EFLAGS */ - "pushf\n\t" - "popl %%eax\n\t" - - /* ... Compare and test result */ - "xorl %%eax, %%ecx\n\t" - "testl $0x200000, %%ecx\n\t" - "jz NotSupported1\n\t" /* CPUID not supported */ - - - /* Get standard CPUID information, and - go to a specific vendor section */ - "movl $0, %%eax\n\t" - "cpuid\n\t" - - /* Check for Intel */ - "cmpl $0x756e6547, %%ebx\n\t" - "jne TryAMD\n\t" - "cmpl $0x49656e69, %%edx\n\t" - "jne TryAMD\n\t" - "cmpl $0x6c65746e, %%ecx\n" - "jne TryAMD\n\t" - "jmp Intel\n\t" - - /* Check for AMD */ - "\nTryAMD:\n\t" - "cmpl $0x68747541, %%ebx\n\t" - "jne TryCyrix\n\t" - "cmpl $0x69746e65, %%edx\n\t" - "jne TryCyrix\n\t" - "cmpl $0x444d4163, %%ecx\n" - "jne TryCyrix\n\t" - "jmp AMD\n\t" - - /* Check for Cyrix */ - "\nTryCyrix:\n\t" - "cmpl $0x69727943, %%ebx\n\t" - "jne NotSupported2\n\t" - "cmpl $0x736e4978, %%edx\n\t" - "jne NotSupported3\n\t" - "cmpl $0x64616574, %%ecx\n\t" - "jne NotSupported4\n\t" - /* Drop through to Cyrix... */ - - - /* Cyrix Section */ - /* See if extended CPUID level 80000001 is supported */ - /* The value of CPUID/80000001 for the 6x86MX is undefined - according to the Cyrix CPU Detection Guide (Preliminary - Rev. 1.01 table 1), so we'll check the value of eax for - CPUID/0 to see if standard CPUID level 2 is supported. - According to the table, the only CPU which supports level - 2 is also the only one which supports extended CPUID levels. - */ - "cmpl $0x2, %%eax\n\t" - "jne MMXtest\n\t" /* Use standard CPUID instead */ - - /* Extended CPUID supported (in theory), so get extended - features */ - "movl $0x80000001, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%eax\n\t" /* Test for MMX */ - "jz NotSupported5\n\t" /* MMX not supported */ - "testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */ - "jnz EMMXSupported\n\t" - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\n" - "EMMXSupported:\n\t" - "movl $3, %0:\n\n\t" /* EMMX and MMX Supported */ - "jmp Return\n\t" - - - /* AMD Section */ - "AMD:\n\t" - - /* See if extended CPUID is supported */ - "movl $0x80000000, %%eax\n\t" - "cpuid\n\t" - "cmpl $0x80000000, %%eax\n\t" - "jl MMXtest\n\t" /* Use standard CPUID instead */ - - /* Extended CPUID supported, so get extended features */ - "movl $0x80000001, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%edx\n\t" /* Test for MMX */ - "jz NotSupported6\n\t" /* MMX not supported */ - "testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */ - "jnz ThreeDNowSupported\n\t" - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\n" - "ThreeDNowSupported:\n\t" - "movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */ - "jmp Return\n\t" - - - /* Intel Section */ - "Intel:\n\t" - - /* Check for SSE */ - "SSEtest:\n\t" - "movl $1, %%eax\n\t" - "cpuid\n\t" - "testl $0x02000000, %%edx\n\t" /* Test for SSE */ - "jz MMXtest\n\t" /* SSE Not supported */ - "movl $9, %0:\n\n\t" /* SSE Supported */ - "jmp Return\n\t" - - /* Check for MMX */ - "MMXtest:\n\t" - "movl $1, %%eax\n\t" - "cpuid\n\t" - "testl $0x00800000, %%edx\n\t" /* Test for MMX */ - "jz NotSupported7\n\t" /* MMX Not supported */ - "movl $1, %0:\n\n\t" /* MMX Supported */ - "jmp Return\n\t" - - /* Nothing supported */ - "\nNotSupported1:\n\t" - "#movl $101, %0:\n\n\t" - "\nNotSupported2:\n\t" - "#movl $102, %0:\n\n\t" - "\nNotSupported3:\n\t" - "#movl $103, %0:\n\n\t" - "\nNotSupported4:\n\t" - "#movl $104, %0:\n\n\t" - "\nNotSupported5:\n\t" - "#movl $105, %0:\n\n\t" - "\nNotSupported6:\n\t" - "#movl $106, %0:\n\n\t" - "\nNotSupported7:\n\t" - "#movl $107, %0:\n\n\t" - "movl $0, %0:\n\n\t" - - "Return:\n\t" - : "=a" (rval) - : /* no input */ - : "eax", "ebx", "ecx", "edx" - ); - - /* Return */ - return(rval); -} - -/* Function to test if sse instructions are supported... -*/ -inline extern int -sse_ok(void) -{ - /* Returns 1 if SSE instructions are supported, 0 otherwise */ - return ( (mm_support() & 0x8) >> 3 ); -} -#endif - - - -/* Helper functions for the instruction macros that follow... - (note that memory-to-register, m2r, instructions are nearly - as efficient as register-to-register, r2r, instructions; - however, memory-to-memory instructions are really simulated - as a convenience, and are only 1/3 as efficient) -*/ -#ifdef SSE_TRACE - -/* Include the stuff for printing a trace to stderr... -*/ - -#include - -#define sse_i2r(op, imm, reg) \ - { \ - sse_t sse_trace; \ - sse_trace.uq = (imm); \ - fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%08x%08x) => ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (imm)); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%08x%08x\n", \ - sse_trace.d[1], sse_trace.d[0]); \ - } - -#define sse_m2r(op, mem, reg) \ - { \ - sse_t sse_trace; \ - sse_trace = (mem); \ - fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%08x%08x) => ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (mem)); \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #reg "=0x%08x%08x\n", \ - sse_trace.d[1], sse_trace.d[0]); \ - } - -#define sse_r2m(op, reg, mem) \ - { \ - sse_t sse_trace; \ - __asm__ __volatile__ ("movq %%" #reg ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \ - sse_trace.d[1], sse_trace.d[0]); \ - sse_trace = (mem); \ - fprintf(stderr, #mem "=0x%08x%08x) => ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ (#op " %%" #reg ", %0" \ - : "=X" (mem) \ - : /* nothing */ ); \ - sse_trace = (mem); \ - fprintf(stderr, #mem "=0x%08x%08x\n", \ - sse_trace.d[1], sse_trace.d[0]); \ - } - -#define sse_r2r(op, regs, regd) \ - { \ - sse_t sse_trace; \ - __asm__ __volatile__ ("movq %%" #regs ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ ("movq %%" #regd ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #regd "=0x%08x%08x) => ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ (#op " %" #regs ", %" #regd); \ - __asm__ __volatile__ ("movq %%" #regd ", %0" \ - : "=X" (sse_trace) \ - : /* nothing */ ); \ - fprintf(stderr, #regd "=0x%08x%08x\n", \ - sse_trace.d[1], sse_trace.d[0]); \ - } - -#define sse_m2m(op, mems, memd) \ - { \ - sse_t sse_trace; \ - sse_trace = (mems); \ - fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \ - sse_trace.d[1], sse_trace.d[0]); \ - sse_trace = (memd); \ - fprintf(stderr, #memd "=0x%08x%08x) => ", \ - sse_trace.d[1], sse_trace.d[0]); \ - __asm__ __volatile__ ("movq %0, %%mm0\n\t" \ - #op " %1, %%mm0\n\t" \ - "movq %%mm0, %0" \ - : "=X" (memd) \ - : "X" (mems)); \ - sse_trace = (memd); \ - fprintf(stderr, #memd "=0x%08x%08x\n", \ - sse_trace.d[1], sse_trace.d[0]); \ - } - -#else - -/* These macros are a lot simpler without the tracing... -*/ - -#define sse_i2r(op, imm, reg) \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (imm) ) - -#define sse_m2r(op, mem, reg) \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "X" (mem)) - -#define sse_r2m(op, reg, mem) \ - __asm__ __volatile__ (#op " %%" #reg ", %0" \ - : "=X" (mem) \ - : /* nothing */ ) - -#define sse_r2r(op, regs, regd) \ - __asm__ __volatile__ (#op " %" #regs ", %" #regd) - -#define sse_r2ri(op, regs, regd, imm) \ - __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ - : /* nothing */ \ - : "X" (imm) ) - -/* Load data from mems to xmmreg, operate on xmmreg, and store data to memd */ -#define sse_m2m(op, mems, memd, xmmreg) \ - __asm__ __volatile__ ("movups %0, %%xmm0\n\t" \ - #op " %1, %%xmm0\n\t" \ - "movups %%mm0, %0" \ - : "=X" (memd) \ - : "X" (mems)) - -#define sse_m2ri(op, mem, reg, subop) \ - __asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \ - : /* nothing */ \ - : "X" (mem)) - -#define sse_m2mi(op, mems, memd, xmmreg, subop) \ - __asm__ __volatile__ ("movups %0, %%xmm0\n\t" \ - #op " %1, %%xmm0, " #subop "\n\t" \ - "movups %%mm0, %0" \ - : "=X" (memd) \ - : "X" (mems)) -#endif - - - - -/* 1x128 MOVe Aligned four Packed Single-fp -*/ -#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg) -#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var) -#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd) -#define movaps(vars, vard) \ - __asm__ __volatile__ ("movaps %1, %%mm0\n\t" \ - "movaps %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* 1x128 MOVe aligned Non-Temporal four Packed Single-fp -*/ -#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var) - - -/* 1x64 MOVe Non-Temporal Quadword -*/ -#define movntq_r2m(mmreg, var) sse_r2m(movntq, mmreg, var) - - -/* 1x128 MOVe Unaligned four Packed Single-fp -*/ -#define movups_m2r(var, reg) sse_m2r(movups, var, reg) -#define movups_r2m(reg, var) sse_r2m(movups, reg, var) -#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd) -#define movups(vars, vard) \ - __asm__ __volatile__ ("movups %1, %%mm0\n\t" \ - "movups %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* MOVe High to Low Packed Single-fp - high half of 4x32f (x) -> low half of 4x32f (y) -*/ -#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd) - - -/* MOVe Low to High Packed Single-fp - low half of 4x32f (x) -> high half of 4x32f (y) -*/ -#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd) - - -/* MOVe High Packed Single-fp - 2x32f -> high half of 4x32f -*/ -#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg) -#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var) -#define movhps(vars, vard) \ - __asm__ __volatile__ ("movhps %1, %%mm0\n\t" \ - "movhps %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* MOVe Low Packed Single-fp - 2x32f -> low half of 4x32f -*/ -#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg) -#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var) -#define movlps(vars, vard) \ - __asm__ __volatile__ ("movlps %1, %%mm0\n\t" \ - "movlps %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* MOVe Scalar Single-fp - lowest field of 4x32f (x) -> lowest field of 4x32f (y) -*/ -#define movss_m2r(var, reg) sse_m2r(movss, var, reg) -#define movss_r2m(reg, var) sse_r2m(movss, reg, var) -#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd) -#define movss(vars, vard) \ - __asm__ __volatile__ ("movss %1, %%mm0\n\t" \ - "movss %%mm0, %0" \ - : "=X" (vard) \ - : "X" (vars)) - - -/* 4x16 Packed SHUFfle Word -*/ -#define pshufw_m2r(var, reg, index) sse_m2ri(pshufw, var, reg, index) -#define pshufw_r2r(regs, regd, index) sse_r2ri(pshufw, regs, regd, index) - - -/* 1x128 SHUFfle Packed Single-fp -*/ -#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index) -#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index) - - -/* ConVerT Packed signed Int32 to(2) Packed Single-fp -*/ -#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg) -#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg) - - -/* ConVerT Packed Single-fp to(2) Packed signed Int32 -*/ -#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg) -#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg) - - -/* ConVerT with Truncate Packed Single-fp to(2) Packed Int32 -*/ -#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg) -#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg) - - -/* ConVerT Signed Int32 to(2) Single-fp (Scalar) -*/ -#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg) -#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg) - - -/* ConVerT Scalar Single-fp to(2) Signed Int32 -*/ -#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) -#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) - - -/* ConVerT with Truncate Scalar Single-fp to(2) Signed Int32 -*/ -#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg) -#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg) - - -/* Parallel EXTRact Word from 4x16 -*/ -#define pextrw_r2r(mmreg, reg, field) sse_r2ri(pextrw, mmreg, reg, field) - - -/* Parallel INSeRt Word from 4x16 -*/ -#define pinsrw_r2r(reg, mmreg, field) sse_r2ri(pinsrw, reg, mmreg, field) - - - -/* MOVe MaSK from Packed Single-fp -*/ -#ifdef SSE_TRACE - #define movmskps(xmmreg, reg) \ - { \ - fprintf(stderr, "movmskps()\n"); \ - __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) \ - } -#else - #define movmskps(xmmreg, reg) \ - __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) -#endif - - -/* Parallel MOVe MaSK from mmx reg to 32-bit reg -*/ -#ifdef SSE_TRACE - #define pmovmskb(mmreg, reg) \ - { \ - fprintf(stderr, "movmskps()\n"); \ - __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) \ - } -#else - #define pmovmskb(mmreg, reg) \ - __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) -#endif - - -/* MASKed MOVe from 8x8 to memory pointed to by (e)di register -*/ -#define maskmovq(mmregs, fieldreg) sse_r2ri(maskmovq, mmregs, fieldreg) - - - - -/* 4x32f Parallel ADDs -*/ -#define addps_m2r(var, reg) sse_m2r(addps, var, reg) -#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd) -#define addps(vars, vard, xmmreg) sse_m2m(addps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel ADDs -*/ -#define addss_m2r(var, reg) sse_m2r(addss, var, reg) -#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd) -#define addss(vars, vard, xmmreg) sse_m2m(addss, vars, vard, xmmreg) - - -/* 4x32f Parallel SUBs -*/ -#define subps_m2r(var, reg) sse_m2r(subps, var, reg) -#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd) -#define subps(vars, vard, xmmreg) sse_m2m(subps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel SUBs -*/ -#define subss_m2r(var, reg) sse_m2r(subss, var, reg) -#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd) -#define subss(vars, vard, xmmreg) sse_m2m(subss, vars, vard, xmmreg) - - -/* 8x8u -> 4x16u Packed Sum of Absolute Differences -*/ -#define psadbw_m2r(var, reg) sse_m2r(psadbw, var, reg) -#define psadbw_r2r(regs, regd) sse_r2r(psadbw, regs, regd) -#define psadbw(vars, vard, mmreg) sse_m2m(psadbw, vars, vard, mmreg) - - -/* 4x16u Parallel MUL High Unsigned -*/ -#define pmulhuw_m2r(var, reg) sse_m2r(pmulhuw, var, reg) -#define pmulhuw_r2r(regs, regd) sse_r2r(pmulhuw, regs, regd) -#define pmulhuw(vars, vard, mmreg) sse_m2m(pmulhuw, vars, vard, mmreg) - - -/* 4x32f Parallel MULs -*/ -#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg) -#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd) -#define mulps(vars, vard, xmmreg) sse_m2m(mulps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel MULs -*/ -#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg) -#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd) -#define mulss(vars, vard, xmmreg) sse_m2m(mulss, vars, vard, xmmreg) - - -/* 4x32f Parallel DIVs -*/ -#define divps_m2r(var, reg) sse_m2r(divps, var, reg) -#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd) -#define divps(vars, vard, xmmreg) sse_m2m(divps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel DIVs -*/ -#define divss_m2r(var, reg) sse_m2r(divss, var, reg) -#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd) -#define divss(vars, vard, xmmreg) sse_m2m(divss, vars, vard, xmmreg) - - -/* 4x32f Parallel Reciprocals -*/ -#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg) -#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd) -#define rcpps(vars, vard, xmmreg) sse_m2m(rcpps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel Reciprocals -*/ -#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg) -#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd) -#define rcpss(vars, vard, xmmreg) sse_m2m(rcpss, vars, vard, xmmreg) - - -/* 4x32f Parallel Square Root of Reciprocals -*/ -#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg) -#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd) -#define rsqrtps(vars, vard, xmmreg) sse_m2m(rsqrtps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel Square Root of Reciprocals -*/ -#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg) -#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd) -#define rsqrtss(vars, vard, xmmreg) sse_m2m(rsqrtss, vars, vard, xmmreg) - - -/* 4x32f Parallel Square Roots -*/ -#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg) -#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd) -#define sqrtps(vars, vard, xmmreg) sse_m2m(sqrtps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel Square Roots -*/ -#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg) -#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd) -#define sqrtss(vars, vard, xmmreg) sse_m2m(sqrtss, vars, vard, xmmreg) - - -/* 8x8u and 4x16u Parallel AVeraGe -*/ -#define pavgb_m2r(var, reg) sse_m2r(pavgb, var, reg) -#define pavgb_r2r(regs, regd) sse_r2r(pavgb, regs, regd) -#define pavgb(vars, vard, mmreg) sse_m2m(pavgb, vars, vard, mmreg) - -#define pavgw_m2r(var, reg) sse_m2r(pavgw, var, reg) -#define pavgw_r2r(regs, regd) sse_r2r(pavgw, regs, regd) -#define pavgw(vars, vard, mmreg) sse_m2m(pavgw, vars, vard, mmreg) - - -/* 1x128 bitwise AND -*/ -#define andps_m2r(var, reg) sse_m2r(andps, var, reg) -#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd) -#define andps(vars, vard, xmmreg) sse_m2m(andps, vars, vard, xmmreg) - - -/* 1x128 bitwise AND with Not the destination -*/ -#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg) -#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd) -#define andnps(vars, vard, xmmreg) sse_m2m(andnps, vars, vard, xmmreg) - - -/* 1x128 bitwise OR -*/ -#define orps_m2r(var, reg) sse_m2r(orps, var, reg) -#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd) -#define orps(vars, vard, xmmreg) sse_m2m(orps, vars, vard, xmmreg) - - -/* 1x128 bitwise eXclusive OR -*/ -#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg) -#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd) -#define xorps(vars, vard, xmmreg) sse_m2m(xorps, vars, vard, xmmreg) - - -/* 8x8u, 4x16, and 4x32f Parallel Maximum -*/ -#define pmaxub_m2r(var, reg) sse_m2r(pmaxub, var, reg) -#define pmaxub_r2r(regs, regd) sse_r2r(pmaxub, regs, regd) -#define pmaxub(vars, vard, mmreg) sse_m2m(pmaxub, vars, vard, mmreg) - -#define pmaxsw_m2r(var, reg) sse_m2r(pmaxsw, var, reg) -#define pmaxsw_r2r(regs, regd) sse_r2r(pmaxsw, regs, regd) -#define pmaxsw(vars, vard, mmreg) sse_m2m(pmaxsw, vars, vard, mmreg) - -#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg) -#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd) -#define maxps(vars, vard, xmmreg) sse_m2m(maxps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel Maximum -*/ -#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg) -#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd) -#define maxss(vars, vard, xmmreg) sse_m2m(maxss, vars, vard, xmmreg) - - -/* 8x8u, 4x16, and 4x32f Parallel Minimum -*/ -#define pminub_m2r(var, reg) sse_m2r(pminub, var, reg) -#define pminub_r2r(regs, regd) sse_r2r(pminub, regs, regd) -#define pminub(vars, vard, mmreg) sse_m2m(pminub, vars, vard, mmreg) - -#define pminsw_m2r(var, reg) sse_m2r(pminsw, var, reg) -#define pminsw_r2r(regs, regd) sse_r2r(pminsw, regs, regd) -#define pminsw(vars, vard, mmreg) sse_m2m(pminsw, vars, vard, mmreg) - -#define minps_m2r(var, reg) sse_m2r(minps, var, reg) -#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd) -#define minps(vars, vard, xmmreg) sse_m2m(minps, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Parallel Minimum -*/ -#define minss_m2r(var, reg) sse_m2r(minss, var, reg) -#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd) -#define minss(vars, vard, xmmreg) sse_m2m(minss, vars, vard, xmmreg) - - -/* 4x32f Parallel CoMPares - (resulting fields are either 0 or -1) -*/ -#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op) -#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op) -#define cmpps(vars, vard, op, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, op) - -#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0) -#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0) -#define cmpeqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 0) - -#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1) -#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1) -#define cmpltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 1) - -#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2) -#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2) -#define cmpleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 2) - -#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3) -#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3) -#define cmpunordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 3) - -#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4) -#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4) -#define cmpneqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 4) - -#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5) -#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5) -#define cmpnltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 5) - -#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6) -#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6) -#define cmpnleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 6) - -#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7) -#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7) -#define cmpordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 7) - - -/* Lowest Field of 4x32f Parallel CoMPares - (resulting fields are either 0 or -1) -*/ -#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op) -#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op) -#define cmpss(vars, vard, op, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, op) - -#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0) -#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0) -#define cmpeqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 0) - -#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1) -#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1) -#define cmpltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 1) - -#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2) -#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2) -#define cmpless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 2) - -#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3) -#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3) -#define cmpunordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 3) - -#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4) -#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4) -#define cmpneqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 4) - -#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5) -#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5) -#define cmpnltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 5) - -#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6) -#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6) -#define cmpnless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 6) - -#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7) -#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7) -#define cmpordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 7) - - -/* Lowest Field of 4x32f Parallel CoMPares to set EFLAGS - (resulting fields are either 0 or -1) -*/ -#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg) -#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd) -#define comiss(vars, vard, xmmreg) sse_m2m(comiss, vars, vard, xmmreg) - - -/* Lowest Field of 4x32f Unordered Parallel CoMPares to set EFLAGS - (resulting fields are either 0 or -1) -*/ -#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg) -#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd) -#define ucomiss(vars, vard, xmmreg) sse_m2m(ucomiss, vars, vard, xmmreg) - - -/* 2-(4x32f) -> 4x32f UNPaCK Low Packed Single-fp - (interleaves low half of dest with low half of source - as padding in each result field) -*/ -#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg) -#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd) - - -/* 2-(4x32f) -> 4x32f UNPaCK High Packed Single-fp - (interleaves high half of dest with high half of source - as padding in each result field) -*/ -#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg) -#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd) - - - -/* Fp and mmX ReSTORe state -*/ -#ifdef SSE_TRACE - #define fxrstor(mem) \ - { \ - fprintf(stderr, "fxrstor()\n"); \ - __asm__ __volatile__ ("fxrstor %0" \ - : /* nothing */ \ - : "X" (mem)) \ - } -#else - #define fxrstor(mem) \ - __asm__ __volatile__ ("fxrstor %0" \ - : /* nothing */ \ - : "X" (mem)) -#endif - - -/* Fp and mmX SAVE state -*/ -#ifdef SSE_TRACE - #define fxsave(mem) \ - { \ - fprintf(stderr, "fxsave()\n"); \ - __asm__ __volatile__ ("fxsave %0" \ - : /* nothing */ \ - : "X" (mem)) \ - } -#else - #define fxsave(mem) \ - __asm__ __volatile__ ("fxsave %0" \ - : /* nothing */ \ - : "X" (mem)) -#endif - - -/* STore streaMing simd eXtensions Control/Status Register -*/ -#ifdef SSE_TRACE - #define stmxcsr(mem) \ - { \ - fprintf(stderr, "stmxcsr()\n"); \ - __asm__ __volatile__ ("stmxcsr %0" \ - : /* nothing */ \ - : "X" (mem)) \ - } -#else - #define stmxcsr(mem) \ - __asm__ __volatile__ ("stmxcsr %0" \ - : /* nothing */ \ - : "X" (mem)) -#endif - - -/* LoaD streaMing simd eXtensions Control/Status Register -*/ -#ifdef SSE_TRACE - #define ldmxcsr(mem) \ - { \ - fprintf(stderr, "ldmxcsr()\n"); \ - __asm__ __volatile__ ("ldmxcsr %0" \ - : /* nothing */ \ - : "X" (mem)) \ - } -#else - #define ldmxcsr(mem) \ - __asm__ __volatile__ ("ldmxcsr %0" \ - : /* nothing */ \ - : "X" (mem)) -#endif - - -/* Store FENCE - enforce ordering of stores before fence vs. stores - occuring after fence in source code. -*/ -#ifdef SSE_TRACE - #define sfence() \ - { \ - fprintf(stderr, "sfence()\n"); \ - __asm__ __volatile__ ("sfence\n\t") \ - } -#else - #define sfence() \ - __asm__ __volatile__ ("sfence\n\t") -#endif - - -/* PREFETCH data using T0, T1, T2, or NTA hint - T0 = Prefetch into all cache levels - T1 = Prefetch into all cache levels except 0th level - T2 = Prefetch into all cache levels except 0th and 1st levels - NTA = Prefetch data into non-temporal cache structure -*/ -#ifdef SSE_TRACE -#else - #define prefetch(mem, hint) \ - __asm__ __volatile__ ("prefetch" #hint " %0" \ - : /* nothing */ \ - : "X" (mem)) - - #define prefetcht0(mem) prefetch(mem, t0) - #define prefetcht1(mem) prefetch(mem, t1) - #define prefetcht2(mem) prefetch(mem, t2) - #define prefetchnta(mem) prefetch(mem, nta) -#endif - - - -#endif diff --git a/gst/deinterlace2/tvtime/tomsmocomp.c b/gst/deinterlace2/tvtime/tomsmocomp.c deleted file mode 100644 index 64e78c5b..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp.c +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Copyright (C) 2004 Billy Biggs - * Copyright (C) 2008 Sebastian Dröge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include "_stdint.h" -#include - -#include "gst/gst.h" -#include "gstdeinterlace2.h" -#include "plugins.h" - -#define GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP)) -#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP)) -#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass)) -#define GST_DEINTERLACE_METHOD_TOMSMOCOMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoComp)) -#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass)) -#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CAST(obj) ((GstDeinterlaceMethodTomsMoComp*)(obj)) - -GType gst_deinterlace_method_tomsmocomp_get_type (void); - -typedef struct -{ - GstDeinterlaceMethod parent; - - guint search_effort; - gboolean strange_bob; -} GstDeinterlaceMethodTomsMoComp; - -typedef struct -{ - GstDeinterlaceMethodClass parent_class; -} GstDeinterlaceMethodTomsMoCompClass; - -static int -Fieldcopy (void *dest, const void *src, size_t count, - int rows, int dst_pitch, int src_pitch) -{ - unsigned char *pDest = (unsigned char *) dest; - unsigned char *pSrc = (unsigned char *) src; - - int i; - - for (i = 0; i < rows; i++) { - oil_memcpy (pDest, pSrc, count); - pSrc += src_pitch; - pDest += dst_pitch; - } - return 0; -} - -#define USE_FOR_DSCALER - -#define IS_C -#define SIMD_TYPE C -#define FUNCT_NAME tomsmocompDScaler_C -#include "tomsmocomp/TomsMoCompAll.inc" -#undef IS_C -#undef SIMD_TYPE -#undef FUNCT_NAME - -#ifdef BUILD_X86_ASM - -#include "tomsmocomp/tomsmocompmacros.h" -#include "x86-64_macros.inc" - -#define IS_MMX -#define SIMD_TYPE MMX -#define FUNCT_NAME tomsmocompDScaler_MMX -#include "tomsmocomp/TomsMoCompAll.inc" -#undef IS_MMX -#undef SIMD_TYPE -#undef FUNCT_NAME - -#define IS_3DNOW -#define SIMD_TYPE 3DNOW -#define FUNCT_NAME tomsmocompDScaler_3DNOW -#include "tomsmocomp/TomsMoCompAll.inc" -#undef IS_3DNOW -#undef SIMD_TYPE -#undef FUNCT_NAME - -#define IS_MMXEXT -#define SIMD_TYPE MMXEXT -#define FUNCT_NAME tomsmocompDScaler_MMXEXT -#include "tomsmocomp/TomsMoCompAll.inc" -#undef IS_MMXEXT -#undef SIMD_TYPE -#undef FUNCT_NAME - -#endif - -G_DEFINE_TYPE (GstDeinterlaceMethodTomsMoComp, - gst_deinterlace_method_tomsmocomp, GST_TYPE_DEINTERLACE_METHOD); - -enum -{ - ARG_0, - ARG_SEARCH_EFFORT, - ARG_STRANGE_BOB -}; - -static void -gst_deinterlace_method_tomsmocomp_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodTomsMoComp *self = - GST_DEINTERLACE_METHOD_TOMSMOCOMP (object); - - switch (prop_id) { - case ARG_SEARCH_EFFORT: - self->search_effort = g_value_get_uint (value); - break; - case ARG_STRANGE_BOB: - self->strange_bob = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gst_deinterlace_method_tomsmocomp_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDeinterlaceMethodTomsMoComp *self = - GST_DEINTERLACE_METHOD_TOMSMOCOMP (object); - - switch (prop_id) { - case ARG_SEARCH_EFFORT: - g_value_set_uint (value, self->search_effort); - break; - case ARG_STRANGE_BOB: - g_value_set_boolean (value, self->strange_bob); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void - gst_deinterlace_method_tomsmocomp_class_init - (GstDeinterlaceMethodTomsMoCompClass * klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GObjectClass *gobject_class = (GObjectClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - gobject_class->set_property = gst_deinterlace_method_tomsmocomp_set_property; - gobject_class->get_property = gst_deinterlace_method_tomsmocomp_get_property; - - g_object_class_install_property (gobject_class, ARG_SEARCH_EFFORT, - g_param_spec_uint ("search-effort", - "Search Effort", - "Search Effort", 0, 27, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - g_object_class_install_property (gobject_class, ARG_STRANGE_BOB, - g_param_spec_boolean ("strange-bob", - "Strange Bob", - "Use strange bob", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) - ); - - dim_class->fields_required = 4; - dim_class->name = "Motion Adaptive: Motion Search"; - dim_class->nick = "tomsmocomp"; - dim_class->latency = 1; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { - dim_class->deinterlace_frame = tomsmocompDScaler_MMXEXT; - } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) { - dim_class->deinterlace_frame = tomsmocompDScaler_3DNOW; - } else if (cpu_flags & OIL_IMPL_FLAG_MMX) { - dim_class->deinterlace_frame = tomsmocompDScaler_MMX; - } else { - dim_class->deinterlace_frame = tomsmocompDScaler_C; - } -#else - dim_class->deinterlace_frame = tomsmocompDScaler_C; -#endif -} - -static void -gst_deinterlace_method_tomsmocomp_init (GstDeinterlaceMethodTomsMoComp * self) -{ - self->search_effort = 5; - self->strange_bob = FALSE; -} diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc deleted file mode 100644 index b1d9aeca..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc +++ /dev/null @@ -1,15 +0,0 @@ -// -*- c++ -*- - -// Searches just the center pixel, in both the old -// and new fields, but takes averages. This is an even -// pixel address. Any chroma match will be used. (YUY2) -// We best like finding 0 motion so we will bias everything we found previously -// up by a little, and adjust later - -#ifdef IS_SSE2 - "paddusb "_ONES", %%xmm7\n\t" // bias toward no motion -#else - "paddusb "_ONES", %%mm7\n\t" // bias toward no motion -#endif - - MERGE4PIXavg("(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")") // center, in old and new diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc deleted file mode 100644 index e1560353..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc +++ /dev/null @@ -1,174 +0,0 @@ -// -*- c++ -*- - -// Version for non-SSE2 - -#ifndef IS_C - -#ifdef SKIP_SEARCH - "movq %%mm6, %%mm0\n\t" // just use the results of our wierd bob -#else - - - // JA 9/Dec/2002 - // failed experiment - // but leave in placeholder for me to play about -#ifdef DONT_USE_STRANGE_BOB - // Use the best weave if diffs less than 10 as that - // means the image is still or moving cleanly - // if there is motion we will clip which will catch anything - "psubusb "_FOURS", %%mm7\n\t" // sets bits to zero if weave diff < 4 - "pxor %%mm0, %%mm0\n\t" - "pcmpeqb %%mm0, %%mm7\n\t" // all ff where weave better, else 00 - "pcmpeqb %%mm7, %%mm0\n\t" // all ff where bob better, else 00 - "pand %%mm6, %%mm0\n\t" // use bob for these pixel values - "pand %%mm5, %%mm7\n\t" // use weave for these - "por %%mm7, %%mm0\n\t" // combine both -#else - // Use the better of bob or weave - // pminub mm4, TENS // the most we care about - V_PMINUB ("%%mm4", _TENS, "%%mm0") // the most we care about - - "psubusb %%mm4, %%mm7\n\t" // foregive that much from weave est? - "psubusb "_FOURS", %%mm7\n\t" // bias it a bit toward weave - "pxor %%mm0, %%mm0\n\t" - "pcmpeqb %%mm0, %%mm7\n\t" // all ff where weave better, else 00 - "pcmpeqb %%mm7, %%mm0\n\t" // all ff where bob better, else 00 - "pand %%mm6, %%mm0\n\t" // use bob for these pixel values - "pand %%mm5, %%mm7\n\t" // use weave for these - "por %%mm7, %%mm0\n\t" // combine both -#endif - - - // pminub mm0, Max_Vals // but clip to catch the stray error - V_PMINUB ("%%mm0", _Max_Vals, "%%mm1") // but clip to catch the stray error - // pmaxub mm0, Min_Vals - V_PMAXUB ("%%mm0", _Min_Vals) - -#endif - - - MOVX" "_pDest", %%"XAX"\n\t" - -#ifdef USE_VERTICAL_FILTER - "movq %%mm0, %%mm1\n\t" - // pavgb mm0, qword ptr["XBX"] - V_PAVGB ("%%mm0", "(%%"XBX")", "%%mm2", _ShiftMask) - // movntq qword ptr["XAX"+"XDX"], mm0 - V_MOVNTQ ("(%"XAX", %%"XDX")", "%%mm0") - // pavgb mm1, qword ptr["XBX"+"XCX"] - V_PAVGB ("%%mm1", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask) - //FIXME: XDX or XAX!! - "addq "_dst_pitchw", %%"XBX - // movntq qword ptr["XAX"+"XDX"], mm1 - V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm1") -#else - - // movntq qword ptr["XAX"+"XDX"], mm0 - V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm0") -#endif - - LEAX" 8(%%"XDX"), %%"XDX"\n\t" // bump offset pointer - CMPX" "_Last8", %%"XDX"\n\t" // done with line? - "jb 1b\n\t" // y - - MOVX" "_oldbx", %%"XBX"\n\t" - - : /* no outputs */ - - : "m"(pBob), - "m"(src_pitch2), - "m"(ShiftMask), - "m"(pDest), - "m"(dst_pitchw), - "m"(Last8), - "m"(pSrc), - "m"(pSrcP), - "m"(pBobP), - "m"(DiffThres), - "m"(Min_Vals), - "m"(Max_Vals), - "m"(FOURS), - "m"(TENS), - "m"(ONES), - "m"(UVMask), - "m"(Max_Mov), - "m"(YMask), - "m"(oldbx) - - : XAX, XCX, XDX, XSI, XDI, - "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", -#ifdef __MMX__ - "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", -#endif - "memory", "cc" - ); - - // adjust for next line - pSrc += src_pitch2; - pSrcP += src_pitch2; - pDest += dst_pitch2; - pBob += src_pitch2; - pBobP += src_pitch2; - } - - return 0; -#else -#ifdef SKIP_SEARCH - out[0] = best[0]; // just use the results of our wierd bob - out[1] = best[1]; -#else - diff[0] = diff[0] - MIN (diff[0], 10) - 4; - diff[1] = diff[1] - MIN (diff[1] - 10) - 4; - if (diff[0] < 0) - out[0] = weave[0]; - else - out[0] = best[0]; - - if (diff[1] < 0) - out[1] = weave[1]; - else - out[1] = best[1]; - - - out[0] = CLAMP (out[0], MinVals[0], MaxVals[0]); - out[1] = CLAMP (out[1], MinVals[1], MaxVals[1]); -#endif - -#ifdef USE_VERTICAL_FILTER - pDest[x] = (out[0] + pBob[0]) / 2; - pDest[x + dst_pitchw] = (pBob[src_pitch2] + out[0]) / 2; - pDest[x + 1] = (out[1] + pBob[1]) / 2; - pDest[x + 1 + dst_pitchw] = (pBob[src_pitch2 + 1] + out[1]) / 2; -#else - pDest[x] = out[0]; - pDest[x+1] = out[1]; -#endif - pBob += 2; - pBobP += 2; - pSrc += 2; - pSrcP += 2; - } - // adjust for next line - pSrc = src_pitch2 * (y+1) + pWeaveSrc; - pSrcP = src_pitch2 * (y+1) + pWeaveSrcP; - pDest = dst_pitch2 * (y+1) + pWeaveDest + dst_pitch2; - - - if (TopFirst) - { - pBob = pCopySrc + src_pitch2; - pBobP = pCopySrcP + src_pitch2; - } - else - { - pBob = pCopySrc; - pBobP = pCopySrcP; - } - - pBob += src_pitch2 * (y+1); - pBobP += src_pitch2 * (y+1); - } - - return 0; - -#endif diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc deleted file mode 100644 index 6208fe8c..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc +++ /dev/null @@ -1,11 +0,0 @@ -// -*- c++ -*- - -// Searches 2 pixel to the left and right, in both the old -// and new fields, but takes averages. These are even -// pixel addresses. Chroma match will be used. (YUY2) - MERGE4PIXavg("-4(%%"XDI")", "4(%%"XSI", %%"XCX", 2)") // up left, down right - MERGE4PIXavg("4(%%"XDI")", "-4(%%"XSI", %%"XCX", 2)") // up right, down left - MERGE4PIXavg("-4(%%"XDI", %%"XCX")", "4(%%"XSI", %%"XCX")") // left, right - MERGE4PIXavg("4(%%"XDI", %%"XCX")", "-4(%%"XSI", %%"XCX")") // right, left - MERGE4PIXavg("-4(%%"XDI", %%"XCX", 2)", "4(%%"XSI")") // down left, up right - MERGE4PIXavg("4(%%"XDI", %%"XCX", 2)", "-4(%%"XSI")") // down right, up left diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc deleted file mode 100644 index 2841c3f6..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc +++ /dev/null @@ -1,12 +0,0 @@ -// -*- c++ -*- - -// Searches 4 pixel to the left and right, in both the old -// and new fields, but takes averages. These are even -// pixel addresses. Chroma match will be used. (YUY2) - MERGE4PIXavg("-8(%%"XDI")", "8(%%"XSI", %%"XCX", 2)") // up left, down right - MERGE4PIXavg("8(%%"XDI")", "-8(%%"XSI", %%"XCX", 2)") // up right, down left - MERGE4PIXavg("-8(%%"XDI", %%"XCX")", "8(%%"XSI", %%"XCX")") // left, right - MERGE4PIXavg("8(%%"XDI", %%"XCX")", "-8(%%"XSI", %%"XCX")") // right, left - MERGE4PIXavg("-8(%%"XDI", %%"XCX", 2)", "8(%%"XSI")") // down left, up right - MERGE4PIXavg("8(%%"XDI", %%"XCX", 2)", "-8(%%"XSI")") // down right, up left - diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc deleted file mode 100644 index ab5375f4..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc +++ /dev/null @@ -1,10 +0,0 @@ -// -*- c++ -*- - -// Searches 1 pixel to the left and right, in both the old -// and new fields, but takes averages. These are odd -// pixel addresses. Any chroma match will not be used. (YUY2) - MERGE4PIXavg("-2(%%"XDI")", "2(%%"XSI", %%"XCX", 2)") // up left, down right - MERGE4PIXavg("2(%%"XDI")", "-2(%%"XSI", %%"XCX", 2)") // up right, down left - MERGE4PIXavg("-2(%%"XDI", %%"XCX", 2)", "2(%%"XSI")") // down left, up right - MERGE4PIXavg("2(%%"XDI", %%"XCX", 2)", "-2(%%"XSI")") // down right, up left -#include "SearchLoopOddA2.inc" diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc deleted file mode 100644 index fd3f6fb0..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc +++ /dev/null @@ -1,5 +0,0 @@ -// Searches 1 pixel to the left and right, in both the old -// and new fields, but takes averages. These are odd -// pixel addresses. Any chroma match will not be used. (YUY2) - MERGE4PIXavg("-2(%%"XDI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right - MERGE4PIXavg("2(%%"XDI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc deleted file mode 100644 index cbae014e..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc +++ /dev/null @@ -1,11 +0,0 @@ -// -*- c++ -*- - -// Searches 3 pixels to the left and right, in both the old -// and new fields, but takes averages. These are odd -// pixel addresses. Any chroma match will not be used. (YUY2) - MERGE4PIXavg("-6(%%"XDI")", "6(%%"XSI", %%"XCX", 2)") // up left, down right - MERGE4PIXavg("6(%%"XDI")", "-6(%%"XSI", %%"XCX", 2)") // up right, down left - MERGE4PIXavg("-6(%%"XDI", %%"XCX")", "6(%%"XSI", %%"XCX")") // left, right - MERGE4PIXavg("6(%%"XDI", %%"XCX")", "-6(%%"XSI", %%"XCX")") // right, left - MERGE4PIXavg("-6(%%"XDI", %%"XCX", 2)", "6(%%"XSI")") // down left, up right - MERGE4PIXavg("6(%%"XDI", %%"XCX", 2)", "-6(%%"XSI")") // down right, up left diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc deleted file mode 100644 index e59e3c7e..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc +++ /dev/null @@ -1,10 +0,0 @@ -// Searches 1 pixel to the left and right, in both the old -// and new fields, but takes v-half pel averages. These are odd -// pixel addresses. Any chroma match will not be used. (YUY2) - __asm - { - MERGE4PIXavgH("XDI"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2*"XCX"+2) // up left, down right - MERGE4PIXavgH("XDI"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"+2*"XCX"-2) // up right, down left - MERGE4PIXavgH("XDI"+2*"XCX"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2) // down left, up right - MERGE4PIXavgH("XDI"+2*"XCX"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"-2) // down right, up left - } diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc deleted file mode 100644 index cd7d812a..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc +++ /dev/null @@ -1,5 +0,0 @@ -// Searches 1 pixel to the left and right, in both the old -// and new fields, but takes vertical averages. These are odd -// pixel addresses. Any chroma match will not be used. (YUY2) - MERGE4PIXavgH("-2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right - MERGE4PIXavgH("2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc deleted file mode 100644 index 9d6a490f..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc +++ /dev/null @@ -1,254 +0,0 @@ -// -*- c++ -*- - -unsigned char* pDest; -const unsigned char* pSrcP; -const unsigned char* pSrc; -const unsigned char* pBob; -const unsigned char* pBobP; - -// long is int32 on ARCH_368, int64 on ARCH_AMD64. Declaring it this way -// saves a lot of xor's to delete 64bit garbage. - -#if defined(DBL_RESIZE) || defined(USE_FOR_DSCALER) -long src_pitch2 = src_pitch; // even & odd lines are not interleaved in DScaler -#else -long src_pitch2 = 2 * src_pitch; // even & odd lines are interleaved in Avisynth -#endif - - -long dst_pitch2 = 2 * dst_pitch; -long y; - -long Last8; - - pSrc = pWeaveSrc; // points 1 weave line above - pSrcP = pWeaveSrcP; // " - -#ifdef DBL_RESIZE - -#ifdef USE_VERTICAL_FILTER - pDest = pWeaveDest + dst_pitch2; -#else - pDest = pWeaveDest + 3*dst_pitch; -#endif - -#else - -#ifdef USE_VERTICAL_FILTER - pDest = pWeaveDest + dst_pitch; -#else - pDest = pWeaveDest + dst_pitch2; -#endif - -#endif - - if (TopFirst) - { - pBob = pCopySrc + src_pitch2; // remember one weave line just copied previously - pBobP = pCopySrcP + src_pitch2; - } - else - { - pBob = pCopySrc; - pBobP = pCopySrcP; - } - -#ifndef IS_C - -#ifndef _pBob -#define _pBob "%0" -#define _src_pitch2 "%1" -#define _ShiftMask "%2" -#define _pDest "%3" -#define _dst_pitchw "%4" -#define _Last8 "%5" -#define _pSrc "%6" -#define _pSrcP "%7" -#define _pBobP "%8" -#define _DiffThres "%9" -#define _Min_Vals "%10" -#define _Max_Vals "%11" -#define _FOURS "%12" -#define _TENS "%13" -#define _ONES "%14" -#define _UVMask "%15" -#define _Max_Mov "%16" -#define _YMask "%17" -#define _oldbx "%18" -#endif - Last8 = (rowsize-8); - - for (y=1; y < FldHeight-1; y++) - { - long dst_pitchw = dst_pitch; // local stor so asm can ref - int64_t Max_Mov = 0x0404040404040404ull; - int64_t DiffThres = 0x0f0f0f0f0f0f0f0full; - int64_t YMask = 0x00ff00ff00ff00ffull; // keeps only luma - int64_t UVMask = 0xff00ff00ff00ff00ull; // keeps only chroma - int64_t TENS = 0x0a0a0a0a0a0a0a0aull; - int64_t FOURS = 0x0404040404040404ull; - int64_t ONES = 0x0101010101010101ull; - int64_t Min_Vals = 0x0000000000000000ull; - int64_t Max_Vals = 0x0000000000000000ull; - int64_t ShiftMask = 0xfefffefffefffeffull; - - long oldbx; - - // pretend it's indented -->> - __asm__ __volatile__ - ( - // Loop general reg usage - // - // XAX - pBobP, then pDest - // XBX - pBob - // XCX - src_pitch2 - // XDX - current offset - // XDI - prev weave pixels, 1 line up - // XSI - next weave pixels, 1 line up - - // Save "XBX" (-fPIC) - MOVX" %%"XBX", "_oldbx"\n\t" - - // simple bob first 8 bytes - MOVX" "_pBob", %%"XBX"\n\t" - MOVX" "_src_pitch2", %%"XCX"\n\t" - -#ifdef USE_VERTICAL_FILTER - "movq (%%"XBX"), %%mm0\n\t" - "movq (%%"XBX", %%"XCX"), %%mm1\n\t" //, qword ptr["XBX"+"XCX"] - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // halfway between - V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask) // 1/4 way - V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask) // 3/4 way - MOVX" "_pDest", %%"XDI"\n\t" - MOVX" "_dst_pitchw", %%"XAX"\n\t" - V_MOVNTQ ("(%%"XDI")", "%%mm0") - V_MOVNTQ ("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1 - - // simple bob last 8 bytes - MOVX" "_Last8", %%"XDX"\n\t" - LEAX" (%%"XBX", %%"XDX"), %%"XSI"\n\t" // ["XBX"+"XDX"] - "movq (%%"XSI"), %%mm0\n\t" - "movq (%%"XSI", %%"XCX"), %%mm1\n\t" // qword ptr["XSI"+"XCX"] - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // halfway between - V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask) // 1/4 way - V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask) // 3/4 way - ADDX" %%"XDX", %%"XDI"\n\t" // last 8 bytes of dest - V_MOVNTQ ("%%"XDI"", "%%mm0") - V_MOVNTQ ("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1) - -#else - "movq (%%"XBX"), %%mm0\n\t" - // pavgb mm0, qword ptr["XBX"+"XCX"] - V_PAVGB ("%%mm0", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XBX"+"XCX"], mm2, ShiftMask) - MOVX" "_pDest", %%"XDI"\n\t" - V_MOVNTQ ("(%%"XDI")", "%%mm0") - - // simple bob last 8 bytes - MOVX" "_Last8", %%"XDX"\n\t" - LEAX" (%%"XBX", %%"XDX"), %%"XSI"\n\t" //"XSI", ["XBX"+"XDX"] - "movq (%%"XSI"), %%mm0\n\t" - // pavgb mm0, qword ptr["XSI"+"XCX"] - V_PAVGB ("%%mm0", "(%%"XSI", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XSI"+"XCX"], mm2, ShiftMask) - V_MOVNTQ ("(%%"XDI", %%"XDX")", "%%mm0") // qword ptr["XDI"+"XDX"], mm0) -#endif - // now loop and get the middle qwords - MOVX" "_pSrc", %%"XSI"\n\t" - MOVX" "_pSrcP", %%"XDI"\n\t" - MOVX" $8, %%"XDX"\n\t" // curr offset longo all lines - - "1:\n\t" - MOVX" "_pBobP", %%"XAX"\n\t" - ADDX" $8, %%"XDI"\n\t" - ADDX" $8, %%"XSI"\n\t" - ADDX" $8, %%"XBX"\n\t" - ADDX" %%"XDX", %%"XAX"\n\t" - -#ifdef USE_STRANGE_BOB -#include "StrangeBob.inc" -#else -#include "WierdBob.inc" -#endif - - // For non-SSE2: - // through out most of the rest of this loop we will maintain - // mm4 our min bob value - // mm5 best weave pixels so far - // mm6 our max Bob value - // mm7 best weighted pixel ratings so far - - // We will keep a slight bias to using the weave pixels - // from the current location, by rating them by the min distance - // from the Bob value instead of the avg distance from that value. - // our best and only rating so far - "pcmpeqb %%mm7, %%mm7\n\t" // ffff, say we didn't find anything good yet - -#else - Last8 = (rowsize - 4); - - for (y=1; y < FldHeight-1; y++) - { - #ifdef USE_STRANGE_BOB - long DiffThres = 0x0f; - #endif - - #ifndef SKIP_SEARCH - long weave[2], MaxVals[2], MinVals[2]; - #endif - - long diff[2], best[2], avg[2], diff2[2], out[2], x; - -#ifdef USE_VERTICAL_FILTER - pDest[0] = (3 * pBob[0] + pBob[src_pitch2]) / 4; - pDest[1] = (3 * pBob[1] + pBob[src_pitch2 + 1]) / 4; - pDest[2] = (3 * pBob[2] + pBob[src_pitch2 + 2]) / 4; - pDest[3] = (3 * pBob[3] + pBob[src_pitch2 + 3]) / 4; - pDest[dst_pitchw] = (pBob[0] + 3 * pBob[src_pitch2]) / 4; - pDest[dst_pitchw + 1] = (pBob[1] + 3 * pBob[src_pitch2 + 1]) / 4; - pDest[dst_pitchw + 2] = (pBob[2] + 3 * pBob[src_pitch2 + 2]) / 4; - pDest[dst_pitchw + 3] = (pBob[3] + 3 * pBob[src_pitch2 + 3]) / 4; - - // simple bob last byte - pDest[Last8] = (3 * pBob[Last8] + pBob[Last8 + src_pitch2]) / 4; - pDest[Last8 + 1] = (3 * pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 4; - pDest[Last8 + 2] = (3 * pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 4; - pDest[Last8 + 3] = (3 * pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 4; - pDest[Last8 + src_pitch2] = (pBob[Last8] + 3 * pBob[Last8 + src_pitch2]) / 4; - pDest[Last8 + src_pitch2 + 1] = (pBob[Last8 + 1] + 3 * pBob[Last8 + src_pitch2 + 1]) / 4; - pDest[Last8 + src_pitch2 + 2] = (pBob[Last8 + 2] + 3 * pBob[Last8 + src_pitch2 + 2]) / 4; - pDest[Last8 + src_pitch2 + 3] = (pBob[Last8 + 3] + 3 * pBob[Last8 + src_pitch2 + 3]) / 4; -#else - pDest[0] = (pBob[0] + pBob[src_pitch2 + 1]) / 2; - pDest[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2; - pDest[2] = (pBob[2] + pBob[src_pitch2 + 2]) / 2; - pDest[3] = (pBob[3] + pBob[src_pitch2 + 3]) / 2; - - // simple bob last byte - pDest[Last8] = (pBob[Last8] + pBob[Last8 + src_pitch2]) / 2; - pDest[Last8 + 1] = (pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 2; - pDest[Last8 + 2] = (pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 2; - pDest[Last8 + 3] = (pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 2; -#endif - - pBob += 4; - pBobP += 4; - pSrc += 4; - pSrcP += 4; - - for (x=4; x < Last8; x += 2) { - -#ifdef USE_STRANGE_BOB -#include "StrangeBob.inc" -#else -#include "WierdBob.inc" -#endif - - // We will keep a slight bias to using the weave pixels - // from the current location, by rating them by the min distance - // from the Bob value instead of the avg distance from that value. - // our best and only rating so far - diff[0] = diff[1] = 255; - - -#endif diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc deleted file mode 100644 index 3e3d19b5..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc +++ /dev/null @@ -1,6 +0,0 @@ -// -*- c++ -*- - -// Searches the center vertical line above center and below, in both the old -// and new fields, but takes averages. These are even pixel addresses. - MERGE4PIXavg("(%%"XDI", %%"XCX", 2)", "(%%"XSI")") // down, up - MERGE4PIXavg("(%%"XDI")", "(%%"XSI", %%"XCX", 2)") // up, down diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc deleted file mode 100644 index 33155bc1..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc +++ /dev/null @@ -1,6 +0,0 @@ -// -*- c++ -*- - -// Searches the center vertical line above center and below, in both the old -// and new fields, but takes averages. These are even pixel addresses. - MERGE4PIXavgH("(%%"XDI", %%"XCX", 2)", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI")") // down, up - MERGE4PIXavgH("(%%"XDI")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI", %%"XCX", 2)") // up, down diff --git a/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc b/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc deleted file mode 100644 index 45b4c865..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc +++ /dev/null @@ -1,435 +0,0 @@ -// -*- c++ -*- - - // First, get and save our possible Bob values - // Assume our pixels are layed out as follows with x the calc'd bob value - // and the other pixels are from the current field - // - // j a b c k current field - // x calculated line - // m d e f n current field - // - // we calc the bob value luma value as: - // if |j - n| < Thres && |a - m| > Thres - // avg(j,n) - // end if - // if |k - m| < Thres && |c - n| > Thres - // avg(k,m) - // end if - // if |c - d| < Thres && |b - f| > Thres - // avg(c,d) - // end if - // if |a - f| < Thres && |b - d| > Thres - // avg(a,f) - // end if - // if |b - e| < Thres - // avg(b,e) - // end if - // pickup any thing not yet set with avg(b,e) - -#ifndef IS_C - - // j, n - "pxor %%mm5, %%mm5\n\t" - "pxor %%mm6, %%mm6\n\t" - "pxor %%mm7, %%mm7\n\t" - - "movq -2(%%"XBX"), %%mm0\n\t" // value a from top left - "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value m from bottom right - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(a,m) - - "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(a,m) > Thres else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(a,m) < Thres, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(a,m) > Thres, else 00 - - - "movq -4(%%"XBX"), %%mm0\n\t" // value j - "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(j,n) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm0\n\t" - "psubusb %%mm3, %%mm1\n\t" - "por %%mm1, %%mm0\n\t" // abs(j,n) - - "movq %%mm0, %%mm1\n\t" - "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(j,n) > Thres else 0 - "pxor %%mm3, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(j,n) < Thres, else 00 - - "pand %%mm4, %%mm1\n\t" - "pand %%mm1, %%mm2\n\t" - "pand %%mm1, %%mm0\n\t" - - "movq %%mm1, %%mm3\n\t" - "pxor %%mm5, %%mm3\n\t" - "pand %%mm3, %%mm6\n\t" - "pand %%mm3, %%mm7\n\t" - "pand %%mm3, %%mm5\n\t" - - "por %%mm1, %%mm5\n\t" - "por %%mm2, %%mm6\n\t" - "por %%mm0, %%mm7\n\t" - - // k & m - "movq 2(%%"XBX"), %%mm0\n\t" // value c from top left - "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom right - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(c,n) - - "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(c,n) > Thres else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(c,n) < Thres, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(c,n) > Thres, else 00 - - - "movq 4(%%"XBX"), %%mm0\n\t" // value k - "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value m - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(k,m) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm0\n\t" - "psubusb %%mm3, %%mm1\n\t" - "por %%mm1, %%mm0\n\t" // abs(k,m) - - "movq %%mm0, %%mm1\n\t" - "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(k,m) > Thres else 0 - "pxor %%mm3, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(k,m) < Thres, else 00 - - "pand %%mm4, %%mm1\n\t" - - "pand %%mm1, %%mm2\n\t" - "pand %%mm1, %%mm0\n\t" - - "movq %%mm1, %%mm3\n\t" - "pxor %%mm5, %%mm3\n\t" - "pand %%mm3, %%mm6\n\t" - "pand %%mm3, %%mm7\n\t" - "pand %%mm3, %%mm5\n\t" - - "por %%mm1, %%mm5\n\t" - "por %%mm2, %%mm6\n\t" - "por %%mm0, %%mm7\n\t" - - - // c & d - "movq (%%"XBX"), %%mm0\n\t" // value b from top left - "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(b,f) - - "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(b,f) > Thres else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(b,f) < Thres, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(b,f) > Thres, else 00 - - "movq 2(%%"XBX"), %%mm0\n\t" // value c - "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value d - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(c,d) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm0\n\t" - "psubusb %%mm3, %%mm1\n\t" - "por %%mm1, %%mm0\n\t" // abs(c,d) - - "movq %%mm0, %%mm1\n\t" - "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(c,d) > Thres else 0 - "pxor %%mm3, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(c,d) < Thres, else 00 - - "pand %%mm4, %%mm1\n\t" - - "pand %%mm1, %%mm2\n\t" - "pand %%mm1, %%mm0\n\t" - - "movq %%mm1, %%mm3\n\t" - "pxor %%mm5, %%mm3\n\t" - "pand %%mm3, %%mm6\n\t" - "pand %%mm3, %%mm7\n\t" - "pand %%mm3, %%mm5\n\t" - - "por %%mm1, %%mm5\n\t" - "por %%mm2, %%mm6\n\t" - "por %%mm0, %%mm7\n\t" - - // a & f - "movq (%%"XBX"), %%mm0\n\t" // value b from top left - "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value d from bottom right - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(b,d) - - "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(b,d) > Thres else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(b,d) < Thres, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(b,d) > Thres, else 00 - - "movq -2(%%"XBX"), %%mm0\n\t" // value a - "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(a,f) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm0\n\t" - "psubusb %%mm3, %%mm1\n\t" - "por %%mm1, %%mm0\n\t" // abs(a,f) - - "movq %%mm0, %%mm1\n\t" - "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(a,f) > Thres else 0 - "pxor %%mm3, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(a,f) < Thres, else 00 - - "pand %%mm4, %%mm1\n\t" - - "pand %%mm1, %%mm2\n\t" - "pand %%mm1, %%mm0\n\t" - - "movq %%mm1, %%mm3\n\t" - "pxor %%mm5, %%mm3\n\t" - "pand %%mm3, %%mm6\n\t" - "pand %%mm3, %%mm7\n\t" - "pand %%mm3, %%mm5\n\t" - - "por %%mm1, %%mm5\n\t" - "por %%mm2, %%mm6\n\t" - "por %%mm0, %%mm7\n\t" - - "pand "_YMask", %%mm5\n\t" // mask out chroma from here - "pand "_YMask", %%mm6\n\t" // mask out chroma from here - "pand "_YMask", %%mm7\n\t" // mask out chroma from here - - // b,e - "movq (%%"XBX"), %%mm0\n\t" // value b from top - "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom - "movq %%mm0, %%mm2\n\t" - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm0\n\t" - "psubusb %%mm3, %%mm1\n\t" - "por %%mm1, %%mm0\n\t" // abs(b,e) - - "movq %%mm0, %%mm1\n\t" - "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(b,e) > Thres else 0 - "pxor %%mm3, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(b,e) < Thres, else 00 - - "pand %%mm1, %%mm2\n\t" - "pand %%mm1, %%mm0\n\t" - - "movq %%mm1, %%mm3\n\t" - "pxor %%mm5, %%mm3\n\t" - "pand %%mm3, %%mm6\n\t" - "pand %%mm3, %%mm7\n\t" - "pand %%mm3, %%mm5\n\t" - - "por %%mm1, %%mm5\n\t" - "por %%mm2, %%mm6\n\t" - "por %%mm0, %%mm7\n\t" - - // bob in any leftovers - "movq (%%"XBX"), %%mm0\n\t" // value b from top - "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom - - -// We will also calc here the max/min values to later limit comb -// so the max excursion will not exceed the Max_Comb constant - -#ifdef SKIP_SEARCH - "movq %%mm0, %%mm2\n\t" -// pminub %%mm2, %%mm1 - V_PMINUB ("%%mm2", "%%mm1", "%%mm4") - -// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this - V_PMAXUB ("%%mm6", "%%mm2") - "movq %%mm0, %%mm2\n\t" - V_PMAXUB ("%%mm2", "%%mm1") -// pminub %%mm6, %%mm2 // clip our current results so far to be below this - V_PMINUB ("%%mm6", "%%mm2", "%%mm4") - -#else - "movq %%mm0, %%mm2\n\t" - "movq (%%"XAX"), %%mm4\n\t" - "psubusb %%mm4, %%mm2\n\t" - "psubusb %%mm0, %%mm4\n\t" - "por %%mm2, %%mm4\n\t" // abs diff - - "movq %%mm1, %%mm2\n\t" - "movq (%%"XAX", %%"XCX"), %%mm3\n\t" - "psubusb %%mm3, %%mm2\n\t" - "psubusb %%mm1, %%mm3\n\t" - "por %%mm2, %%mm3\n\t" // abs diff -// pmaxub %%mm3, %%mm4 // top or bottom pixel moved most - V_PMAXUB ("%%mm3", "%%mm4") // top or bottom pixel moved most - "psubusb "_DiffThres", %%mm3\n\t" // moved more than allowed? or goes to 0? - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where low motion, else high motion - - "movq %%mm0, %%mm2\n\t" -// pminub %%mm2, %%mm1 - V_PMINUB ("%%mm2", "%%mm1", "%%mm4") - -// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this - V_PMAXUB ("%%mm6", "%%mm2") - - "psubusb %%mm3, %%mm2\n\t" // maybe decrease it to 0000.. if no surround motion - "movq %%mm2, "_Min_Vals"\n\t" - - "movq %%mm0, %%mm2\n\t" - V_PMAXUB ("%%mm2", "%%mm1") -// pminub %%mm6, %%mm2 // clip our current results so far to be below this - V_PMINUB ("%%mm6", "%%mm2", "%%mm4") - "paddusb %%mm3, %%mm2\n\t" // maybe increase it to ffffff if no surround motion - "movq %%mm2, "_Max_Vals"\n\t" -#endif - - "movq %%mm0, %%mm2\n\t" -// pavgb %%mm2, %%mm1 // avg(b,e) - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e) - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(b,e) - "movq %%mm3, %%mm1\n\t" // keep copy of diffs - - "pxor %%mm4, %%mm4\n\t" - "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0 - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00 - "pcmpeqb %%mm0, %%mm0\n\t" - "pandn %%mm0, %%mm5\n\t" - "por %%mm5, %%mm3\n\t" - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00 - - "pand %%mm3, %%mm1\n\t" - "pand %%mm3, %%mm2\n\t" - - "pand %%mm4, %%mm6\n\t" - "pand %%mm4, %%mm7\n\t" - - "por %%mm2, %%mm6\n\t" // our x2 value - "por %%mm1, %%mm7\n\t" // our x2 diffs - "movq %%mm7, %%mm4\n\t" // save as bob uncertainty indicator - -#else - - diff[0] = -1; - diff[1] = -1; - best[0] = 0; - best[1] = 0; - // j, n - if (ABS (pBob[-2] - pBob[src_pitch2 - 4]) < DiffThres && - ABS (pBob[-4] - pBob[src_pitch2 + 4]) > DiffThres) { - best[0] = (pBob[-2] + pBob[src_pitch2 - 4]) / 2; - diff[0] = ABS (pBob[-2] - pBob[src_pitch2 - 4]); - } - if (ABS (pBob[-1] - pBob[src_pitch2 - 3]) < DiffThres && - ABS (pBob[-3] - pBob[src_pitch2 + 5]) > DiffThres) { - best[1] = (pBob[-1] + pBob[src_pitch2 - 3]) / 2; - diff[1] = ABS (pBob[-1] - pBob[src_pitch2 - 3]); - } - - // k & m - if (ABS (pBob[2] - pBob[src_pitch2 + 4]) < DiffThres && - ABS (pBob[4] - pBob[src_pitch2 - 4]) > DiffThres) { - best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2; - diff[0] = ABS (pBob[4] - pBob[src_pitch2 - 4]); - } - - if (ABS (pBob[3] - pBob[src_pitch2 + 5]) < DiffThres && - ABS (pBob[5] - pBob[src_pitch2 - 3]) > DiffThres) { - best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2; - diff[1] = ABS (pBob[5] - pBob[src_pitch2 - 3]); - } - - // c & d - if (ABS (pBob[0] - pBob[src_pitch2 + 2]) < DiffThres && - ABS (pBob[2] - pBob[src_pitch2 - 2]) > DiffThres) { - best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2; - diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]); - } - - if (ABS (pBob[1] - pBob[src_pitch2 + 3]) < DiffThres && - ABS (pBob[3] - pBob[src_pitch2 - 1]) > DiffThres) { - best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2; - diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]); - } - - // a & f - if (ABS (pBob[0] - pBob[src_pitch2 - 2]) < DiffThres && - ABS (pBob[-2] - pBob[src_pitch2 + 2]) > DiffThres) { - best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2; - diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]); - } - - if (ABS (pBob[1] - pBob[src_pitch2 - 1]) < DiffThres && - ABS (pBob[-1] - pBob[src_pitch2 + 3]) > DiffThres) { - best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2; - diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]); - } - - // b,e - if (ABS (pBob[0] - pBob[src_pitch2]) < DiffThres) { - best[0] = (pBob[0] + pBob[src_pitch2]) / 2; - diff[0] = ABS (pBob[0] - pBob[src_pitch2]); - } - - if (ABS (pBob[1] - pBob[src_pitch2 + 1]) < DiffThres) { - best[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2; - diff[1] = ABS (pBob[1] - pBob[src_pitch2 + 1]); - } - - -// We will also calc here the max/min values to later limit comb -// so the max excursion will not exceed the Max_Comb constant - -#ifdef SKIP_SEARCH - best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0])); - best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1])); -#else - mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2])); - mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1])); - - MinVals[0] = 0; - MinVals[1] = 0; - MaxVals[0] = 255; - MaxVals[1] = 255; - if (mov[0] > DiffThres) { - MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]); - MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]); - } - - if (mov[1] > DiffThres) { - MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2+1]), best[1]); - MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2+1]), best[1]); - } - - best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0])); - best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1])); -#endif - avg[0] = (pBob[src_pitch2] + pBob[0]) / 2; - avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2; - diff2[0] = ABS (pBob[src_pitch2 + 1] - pBob[1]); - diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]); - - if (diff[0] == -1 || diff2[0] < diff[0]) { - best[0] = avg[0]; - diff[0] = diff2[0]; - } - - if (diff[1] == -1 || diff2[1] < diff[1]) { - best[1] = avg[1]; - diff[1] = diff2[1]; - } -#endif diff --git a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc b/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc deleted file mode 100644 index 89ed39e4..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc +++ /dev/null @@ -1,241 +0,0 @@ -/* - * GStreamer - * Copyright (c) 2002 Tom Barry All rights reserved. - * - * 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. - */ - -/* - * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - - -#ifndef TopFirst -#define TopFirst IsOdd -#endif - -#ifdef SEFUNC -#undef SEFUNC -#endif - -#if defined(IS_MMXEXT) -#define SEFUNC(x) Search_Effort_MMXEXT_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight) -#elif defined(IS_3DNOW) -#define SEFUNC(x) Search_Effort_3DNOW_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight) -#elif defined(IS_MMX) -#define SEFUNC(x) Search_Effort_MMX_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight) -#else -#define SEFUNC(x) Search_Effort_C_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight) -#endif - -#include "TomsMoCompAll2.inc" - -#define USE_STRANGE_BOB - -#include "TomsMoCompAll2.inc" - -#undef USE_STRANGE_BOB - -#undef SEFUNC -#if defined(IS_MMXEXT) -#define SEFUNC(x) Search_Effort_MMXEXT_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight) -#elif defined(IS_3DNOW) -#define SEFUNC(x) Search_Effort_3DNOW_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight) -#elif defined(IS_MMX) -#define SEFUNC(x) Search_Effort_MMX_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight) -#else -#define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight) -#endif - -void FUNCT_NAME(GstDeinterlaceMethod *d_method, GstDeinterlace2* object, GstBuffer *outbuf) -{ - GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method); - long SearchEffort = self->search_effort; - int UseStrangeBob = self->strange_bob; - int IsOdd; - const unsigned char *pWeaveSrc; - const unsigned char *pWeaveSrcP; - unsigned char *pWeaveDest; - const unsigned char *pCopySrc; - const unsigned char *pCopySrcP; - unsigned char *pCopyDest; - int src_pitch; - int dst_pitch; - int rowsize; - int FldHeight; - - /* double stride do address just every odd/even scanline */ - src_pitch = object->field_stride; - dst_pitch = object->row_stride; - rowsize = object->row_stride; - FldHeight = object->field_height; - - pCopySrc = GST_BUFFER_DATA(object->field_history[object->history_count-1].buf); - pCopySrcP = GST_BUFFER_DATA(object->field_history[object->history_count-3].buf); - pWeaveSrc = GST_BUFFER_DATA(object->field_history[object->history_count-2].buf); - pWeaveSrcP = GST_BUFFER_DATA(object->field_history[object->history_count-4].buf); - - /* use bottom field and interlace top field */ - if (object->field_history[object->history_count-2].flags == PICTURE_INTERLACED_BOTTOM) { - IsOdd = 1; - - // if we have an odd field we copy an even field and weave an odd field - pCopyDest = GST_BUFFER_DATA(outbuf); - pWeaveDest = pCopyDest + dst_pitch; - } - /* do it vice verca */ - else { - - IsOdd = 0; - // if we have an even field we copy an odd field and weave an even field - pCopyDest = GST_BUFFER_DATA(outbuf) + dst_pitch; - pWeaveDest = GST_BUFFER_DATA(outbuf); - } - - - // copy 1st and last weave lines - Fieldcopy(pWeaveDest, pCopySrc, rowsize, - 1, dst_pitch*2, src_pitch); - Fieldcopy(pWeaveDest+(FldHeight-1)*dst_pitch*2, - pCopySrc+(FldHeight-1)*src_pitch, rowsize, - 1, dst_pitch*2, src_pitch); - -#ifdef USE_VERTICAL_FILTER - // Vertical Filter currently not implemented for DScaler !! - // copy 1st and last lines the copy field - Fieldcopy(pCopyDest, pCopySrc, rowsize, - 1, dst_pitch*2, src_pitch); - Fieldcopy(pCopyDest+(FldHeight-1)*dst_pitch*2, - pCopySrc+(FldHeight-1)*src_pitch, rowsize, - 1, dst_pitch*2, src_pitch); -#else - - // copy all of the copy field - Fieldcopy(pCopyDest, pCopySrc, rowsize, - FldHeight, dst_pitch*2, src_pitch); -#endif - // then go fill in the hard part, being variously lazy depending upon - // SearchEffort - - if(!UseStrangeBob) { - if (SearchEffort == 0) - { - SEFUNC(0); - } - else if (SearchEffort <= 1) - { - SEFUNC(1); - } - /* else if (SearchEffort <= 2) - { - SEFUNC(2); - } - */ - else if (SearchEffort <= 3) - { - SEFUNC(3); - } - else if (SearchEffort <= 5) - { - SEFUNC(5); - } - else if (SearchEffort <= 9) - { - SEFUNC(9); - } - else if (SearchEffort <= 11) - { - SEFUNC(11); - } - else if (SearchEffort <= 13) - { - SEFUNC(13); - } - else if (SearchEffort <= 15) - { - SEFUNC(15); - } - else if (SearchEffort <= 19) - { - SEFUNC(19); - } - else if (SearchEffort <= 21) - { - SEFUNC(21); - } - else - { - SEFUNC(Max); - } - } - else - { - if (SearchEffort == 0) - { - SEFUNC(0SB); - } - else if (SearchEffort <= 1) - { - SEFUNC(1SB); - } - /* else if (SearchEffort <= 2) - { - SEFUNC(2SB); - } - */ - else if (SearchEffort <= 3) - { - SEFUNC(3SB); - } - else if (SearchEffort <= 5) - { - SEFUNC(5SB); - } - else if (SearchEffort <= 9) - { - SEFUNC(9SB); - } - else if (SearchEffort <= 11) - { - SEFUNC(11SB); - } - else if (SearchEffort <= 13) - { - SEFUNC(13SB); - } - else if (SearchEffort <= 15) - { - SEFUNC(15SB); - } - else if (SearchEffort <= 19) - { - SEFUNC(19SB); - } - else if (SearchEffort <= 21) - { - SEFUNC(21SB); - } - else - { - SEFUNC(MaxSB); - } - } - -#if defined(BUILD_X86_ASM) && !defined(IS_C) - __asm__ __volatile__("emms"); -#endif -} diff --git a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc b/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc deleted file mode 100644 index f6344eab..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc +++ /dev/null @@ -1,243 +0,0 @@ -// -*- c++ -*- - -#ifdef SEARCH_EFFORT_FUNC -#undef SEARCH_EFFORT_FUNC -#endif - -#ifdef USE_STRANGE_BOB -#define SEARCH_EFFORT_FUNC(n) SEFUNC(n##SB) -#else -#define SEARCH_EFFORT_FUNC(n) SEFUNC(n) -#endif - -static inline int SEARCH_EFFORT_FUNC(0) // we don't try at all ;-) -{ - //see Search_Effort_Max() for comments -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -} - -static inline int SEARCH_EFFORT_FUNC(1) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see Search_Effort_Max() for comments -#include "SearchLoopTop.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -static inline int SEARCH_EFFORT_FUNC(3) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see Search_Effort_Max() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA2.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -static inline int SEARCH_EFFORT_FUNC(5) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see Search_Effort_Max() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA2.inc" -#include "SearchLoopOddAH2.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// 3x3 search -static inline int SEARCH_EFFORT_FUNC(9) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchEffortMax() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoopVA.inc" -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// Search 9 with 2 H-half pels added -static inline int SEARCH_EFFORT_FUNC(11) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchEffortMax() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA.inc" -#include "SearchLoopOddAH2.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoopVA.inc" -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// Search 11 with 2 V-half pels added -static inline int SEARCH_EFFORT_FUNC(13) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchEffortMax() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA.inc" -#include "SearchLoopOddAH2.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoopVAH.inc" -#include "SearchLoopVA.inc" -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// 5x3 -static inline int SEARCH_EFFORT_FUNC(15) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchEffortMax() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoopEdgeA.inc" -#include "SearchLoopVA.inc" -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// 5x3 + 4 half pels -static inline int SEARCH_EFFORT_FUNC(19) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchEffortMax() for comments -#include "SearchLoopTop.inc" -#include "SearchLoopOddA.inc" -#include "SearchLoopOddAH2.inc" - RESET_CHROMA // pretend chroma diffs was 255 each -#include "SearchLoopEdgeA.inc" -#include "SearchLoopVAH.inc" -#include "SearchLoopVA.inc" -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// Handle one 4x1 block of pixels -// Search a 7x3 area, no half pels - -static inline int SEARCH_EFFORT_FUNC(21) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchLoopTop.inc for comments -#include "SearchLoopTop.inc" - - // odd addresses -- the pixels at odd address wouldn't generate - // good luma values but we will mask those off - -#include "SearchLoopOddA6.inc" // 4 odd v half pels, 3 to left & right -#include "SearchLoopOddA.inc" // 6 odd pels, 1 to left & right - - RESET_CHROMA // pretend chroma diffs was 255 each - - // even addresses -- use both luma and chroma from these - // search averages of 2 pixels left and right -#include "SearchLoopEdgeA.inc" - // search vertical line and averages, -1,0,+1 -#include "SearchLoopVA.inc" - // blend our results and loop -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -// Handle one 4x1 block of pixels -// Search a 9x3 area, no half pels -static inline int SEARCH_EFFORT_FUNC(Max) -{ -#ifdef IS_C -#define SKIP_SEARCH -#include "SearchLoopTop.inc" -#include "SearchLoopBottom.inc" -#undef SKIP_SEARCH -#else - //see SearchLoopTop.inc for comments -#include "SearchLoopTop.inc" - - // odd addresses -- the pixels at odd address wouldn't generate - // good luma values but we will mask those off - -#include "SearchLoopOddA6.inc" // 4 odd v half pels, 3 to left & right -#include "SearchLoopOddA.inc" // 6 odd pels, 1 to left & right - - RESET_CHROMA // pretend chroma diffs was 255 each - - // even addresses -- use both luma and chroma from these - // search averages of 4 pixels left and right -#include "SearchLoopEdgeA8.inc" - // search averages of 2 pixels left and right -#include "SearchLoopEdgeA.inc" - // search vertical line and averages, -1,0,+1 -#include "SearchLoopVA.inc" - // blend our results and loop -#include "SearchLoop0A.inc" -#include "SearchLoopBottom.inc" -#endif -} - -#undef SEARCH_EFFORT_FUNC - diff --git a/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc b/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc deleted file mode 100644 index f4bbb830..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc +++ /dev/null @@ -1,286 +0,0 @@ -// -*- c++ -*- - - // First, get and save our possible Bob values - // Assume our pixels are layed out as follows with x the calc'd bob value - // and the other pixels are from the current field - // - // j a b c k current field - // x calculated line - // m d e f n current field - // - // we calc the bob value as: - // x2 = either avg(a,f), avg(c,d), avg(b,e), avg(j,n), or avg(k,m) - - // selected for the smallest of abs(a,f), abs(c,d), or abs(b,e), etc. - -#ifndef IS_C - // a,f - "movq -2(%%"XBX"), %%mm0\n\t" // value a from top left - "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right - "movq %%mm0, %%mm6\n\t" -// pavgb %%mm6, %%mm1 // avg(a,f), also best so far - V_PAVGB ("%%mm6", "%%mm1", "%%mm7", _ShiftMask) // avg(a,f), also best so far - "movq %%mm0, %%mm7\n\t" - "psubusb %%mm1, %%mm7\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm7\n\t" // abs diff, also best so far - - // c,d - "movq 2(%%"XBX"), %%mm0\n\t" // value a from top left - "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right - "movq %%mm0, %%mm2\n\t" -// pavgb %%mm2, %%mm1 // avg(c,d) - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(c,d) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(c,d) - "movq %%mm3, %%mm1\n\t" // keep copy - - "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00 - - "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs - "pand %%mm3, %%mm2\n\t" - - "pand %%mm4, %%mm6\n\t" - "pand %%mm4, %%mm7\n\t" - - "por %%mm2, %%mm6\n\t" // and merge new & old vals keeping best - "por %%mm1, %%mm7\n\t" - "por "_UVMask", %%mm7\n\t" // but we know chroma is worthless so far - "pand "_YMask", %%mm5\n\t" // mask out chroma from here also - - // j,n - "movq -4(%%"XBX"), %%mm0\n\t" // value j from top left - "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom right - "movq %%mm0, %%mm2\n\t" -// pavgb %%mm2, %%mm1 // avg(j,n) - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(j,n) - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(j-n) - "movq %%mm3, %%mm1\n\t" // keep copy - - "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00 - - "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs - "pand %%mm2, %%mm3\n\t" - - "pand %%mm4, %%mm6\n\t" - "pand %%mm4, %%mm7\n\t" - - "por %%mm3, %%mm6\n\t" // and merge new & old vals keeping best - "por %%mm1, %%mm7\n\t" // " - - // k, m - "movq 4(%%"XBX"), %%mm0\n\t" // value k from top right - "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom left - "movq %%mm0, %%mm4\n\t" -// pavgb %%mm4, %%mm1 // avg(k,m) - V_PAVGB ("%%mm4", "%%mm1", "%%mm3", _ShiftMask) // avg(k,m) - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(k,m) - "movq %%mm3, %%mm1\n\t" // keep copy - - "movq %%mm4, %%mm2\n\t" // avg(k,m) - - "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0 - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00 - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00 - - "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs - "pand %%mm2, %%mm3\n\t" - - "pand %%mm4, %%mm6\n\t" - "pand %%mm4, %%mm7\n\t" - - "por %%mm3, %%mm6\n\t" // and merge new & old vals keeping best - "por %%mm1, %%mm7\n\t" // " - - // b,e - "movq (%%"XBX"), %%mm0\n\t" // value b from top - "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom - -// We will also calc here the max/min values to later limit comb -// so the max excursion will not exceed the Max_Comb constant - -#ifdef SKIP_SEARCH - "movq %%mm0, %%mm2\n\t" -// pminub %%mm2, %%mm1 - V_PMINUB ("%%mm2", "%%mm1", "%%mm4") - -// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this - V_PMAXUB ("%%mm6", "%%mm2") - "movq %%mm0, %%mm2\n\t" - V_PMAXUB ("%%mm2", "%%mm1") -// pminub %%mm6, %%mm2 // clip our current results so far to be below this - V_PMINUB ("%%mm6", "%%mm2", "%%mm4") - -#else - "movq %%mm0, %%mm2\n\t" - "movq (%%"XAX"), %%mm4\n\t" - "psubusb %%mm4, %%mm2\n\t" - "psubusb %%mm0, %%mm4\n\t" - "por %%mm2, %%mm4\n\t" // abs diff - - "movq %%mm1, %%mm2\n\t" - "movq (%%"XAX", %%"XCX"), %%mm3\n\t" - "psubusb %%mm3, %%mm2\n\t" - "psubusb %%mm1, %%mm3\n\t" - "por %%mm2, %%mm3\n\t" // abs diff -// pmaxub %%mm3, %%mm4 // top or bottom pixel moved most - V_PMAXUB ("%%mm3", "%%mm4") // top or bottom pixel moved most - "psubusb "_Max_Mov", %%mm3\n\t" // moved more than allowed? or goes to 0? - "pxor %%mm4, %%mm4\n\t" - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where low motion, else high motion - - "movq %%mm0, %%mm2\n\t" -// pminub %%mm2, %%mm1 - V_PMINUB ("%%mm2", "%%mm1", "%%mm4") - -// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this - V_PMAXUB ("%%mm6", "%%mm2") - - "psubusb %%mm3, %%mm2\n\t" // maybe decrease it to 0000.. if no surround motion - "movq %%mm2, "_Min_Vals"\n\t" - - "movq %%mm0, %%mm2\n\t" - V_PMAXUB ("%%mm2", "%%mm1") -// pminub %%mm6, %%mm2 // clip our current results so far to be below this - V_PMINUB ("%%mm6", "%%mm2", "%%mm4") - "paddusb %%mm3, %%mm2\n\t" // maybe increase it to ffffff if no surround motion - "movq %%mm2, "_Max_Vals"\n\t" -#endif - - "movq %%mm0, %%mm2\n\t" -// pavgb %%mm2, %%mm1 // avg(b,e) - V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e) - - "movq %%mm0, %%mm3\n\t" - "psubusb %%mm1, %%mm3\n\t" - "psubusb %%mm0, %%mm1\n\t" - "por %%mm1, %%mm3\n\t" // abs(c,d) - "movq %%mm3, %%mm1\n\t" // keep copy of diffs - - "pxor %%mm4, %%mm4\n\t" - "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0 - "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00 - - "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00 - - "pand %%mm3, %%mm1\n\t" - "pand %%mm3, %%mm2\n\t" - - "pand %%mm4, %%mm6\n\t" - "pand %%mm4, %%mm7\n\t" - - "por %%mm2, %%mm6\n\t" // our x2 value - "por %%mm1, %%mm7\n\t" // our x2 diffs - "movq %%mm7, %%mm4\n\t" // save as bob uncertainty indicator - -#else - - // a,f - best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2; - diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]); - best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2; - diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]); - - // c,d - if (ABS (pBob[2] - pBob[src_pitch2 - 2]) < diff[0]) { - best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2; - diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]); - } - - if (ABS (pBob[3] - pBob[src_pitch2 - 1]) < diff[1]) { - best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2; - diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]); - } - - // j,n - if (ABS (pBob[-4] - pBob[src_pitch2 + 4]) < diff[0]) { - best[0] = (pBob[-4] + pBob[src_pitch2 + 4]) / 2; - diff[0] = ABS (pBob[-4] - pBob[src_pitch2 + 4]); - } - - if (ABS (pBob[-3] - pBob[src_pitch2 + 5]) < diff[1]) { - best[1] = (pBob[-3] + pBob[src_pitch2 + 5]) / 2; - diff[1] = ABS (pBob[-3] - pBob[src_pitch2 + 5]); - } - - // k,m - if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) { - best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2; - diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]); - } - - if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) { - best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2; - diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]); - } - // k,m - if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) { - best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2; - diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]); - } - - if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) { - best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2; - diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]); - } - -// We will also calc here the max/min values to later limit comb -// so the max excursion will not exceed the Max_Comb constant - -#ifdef SKIP_SEARCH - best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0])); - best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1])); -#else - mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2])); - mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1])); - - MinVals[0] = 0; - MinVals[1] = 0; - MaxVals[0] = 255; - MaxVals[1] = 255; - - if (mov[0] > Max_Mov[0]) { - MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]); - MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]); - } - - if (mov[1] > Max_Mov[1]) { - MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2 + 1]), best[1]); - MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2 + 1]), best[1]); - } - - best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0])); - best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1])); -#endif - - avg[0] = (pBob[src_pitch2] + pBob[0]) / 2; - avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2; - diff2[0] = ABS (pBob[src_pitch2] - pBob[0]); - diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]); - - if (diff2[0] < diff[0]) { - best[0] = avg[0]; - diff[0] = diff2[0]; - } - - if (diff2[1] < diff[1]) { - best[1] = avg[1]; - diff[1] = diff2[1]; - } -#endif diff --git a/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h b/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h deleted file mode 100644 index 7e8147ec..00000000 --- a/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include - -// Define a few macros for CPU dependent instructions. -// I suspect I don't really understand how the C macro preprocessor works but -// this seems to get the job done. // TRB 7/01 - -// BEFORE USING THESE YOU MUST SET: - -// #define SIMD_TYPE MMXEXT (or MMX or 3DNOW) - -// some macros for pavgb instruction -// V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it - -#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \ - "movq "mmr2", "mmrw"\n\t" \ - "pand "smask", "mmrw"\n\t" \ - "psrlw $1, "mmrw"\n\t" \ - "pand "smask", "mmr1"\n\t" \ - "psrlw $1, "mmr1"\n\t" \ - "paddusb "mmrw", "mmr1"\n\t" -#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask) "pavgb "mmr2", "mmr1"\n\t" -#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask) "pavgusb "mmr2", "mmr1"\n\t" -#define V_PAVGB(mmr1, mmr2, mmrw, smask) V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE) -#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) -#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask) - -// some macros for pmaxub instruction -#define V_PMAXUB_MMX(mmr1, mmr2) \ - "psubusb "mmr2", "mmr1"\n\t" \ - "paddusb "mmr2", "mmr1"\n\t" -#define V_PMAXUB_MMXEXT(mmr1, mmr2) "pmaxub "mmr2", "mmr1"\n\t" -#define V_PMAXUB_3DNOW(mmr1, mmr2) V_PMAXUB_MMX(mmr1, mmr2) // use MMX version -#define V_PMAXUB(mmr1, mmr2) V_PMAXUB2(mmr1, mmr2, SIMD_TYPE) -#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type) -#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2) - -// some macros for pminub instruction -// V_PMINUB(mmr1, mmr2, mmr work register) mmr2 may NOT = mmrw -#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \ - "pcmpeqb "mmrw", "mmrw"\n\t" \ - "psubusb "mmr2", "mmrw"\n\t" \ - "paddusb "mmrw", "mmr1"\n\t" \ - "psubusb "mmrw", "mmr1"\n\t" -#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw) "pminub "mmr2", "mmr1"\n\t" -#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw) V_PMINUB_MMX(mmr1, mmr2, mmrw) // use MMX version -#define V_PMINUB(mmr1, mmr2, mmrw) V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE) -#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type) -#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw) - -// some macros for movntq instruction -// V_MOVNTQ(mmr1, mmr2) -#define V_MOVNTQ_MMX(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ_3DNOW(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ_MMXEXT(mmr1, mmr2) "movntq "mmr2", "mmr1"\n\t" -#define V_MOVNTQ(mmr1, mmr2) V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE) -#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type) -#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2) - -// end of macros - -#ifdef IS_SSE2 - -#define MERGE4PIXavg(PADDR1, PADDR2) \ - "movdqu "PADDR1", %%xmm0\n\t" /* our 4 pixels */ \ - "movdqu "PADDR2", %%xmm1\n\t" /* our pixel2 value */ \ - "movdqa %%xmm0, %%xmm2\n\t" /* another copy of our pixel1 value */ \ - "movdqa %%xmm1, %%xmm3\n\t" /* another copy of our pixel1 value */ \ - "psubusb %%xmm1, %%xmm2\n\t" \ - "psubusb %%xmm0, %%xmm3\n\t" \ - "por %%xmm3, %%xmm2\n\t" \ - "pavgb %%xmm1, %%xmm0\n\t" /* avg of 2 pixels */ \ - "movdqa %%xmm2, %%xmm3\n\t" /* another copy of our our weights */ \ - "pxor %%xmm1, %%xmm1\n\t" \ - "psubusb %%xmm7, %%xmm3\n\t" /* nonzero where old weights lower, else 0 */ \ - "pcmpeqb %%xmm1, %%xmm3\n\t" /* now ff where new better, else 00 */ \ - "pcmpeqb %%xmm3, %%xmm1\n\t" /* here ff where old better, else 00 */ \ - "pand %%xmm3, %%xmm0\n\t" /* keep only better new pixels */ \ - "pand %%xmm3, %%xmm2\n\t" /* and weights */ \ - "pand %%xmm1, %%xmm5\n\t" /* keep only better old pixels */ \ - "pand %%xmm1, %%xmm7\n\t" \ - "por %%xmm0, %%xmm5\n\t" /* and merge new & old vals */ \ - "por %%xmm2, %%xmm7\n\t" - -#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B) \ - "movdqu "PADDR1A", %%xmm0\n\t" /* our 4 pixels */ \ - "movdqu "PADDR2A", %%xmm1\n\t" /* our pixel2 value */ \ - "movdqu "PADDR1B", %%xmm2\n\t" /* our 4 pixels */ \ - "movdqu "PADDR2B", %%xmm3\n\t" /* our pixel2 value */ \ - "pavgb %%xmm2, %%xmm0\n\t" \ - "pavgb %%xmm3, %%xmm1\n\t" \ - "movdqa %%xmm0, %%xmm2\n\t" /* another copy of our pixel1 value */ \ - "movdqa %%xmm1, %%xmm3\n\t" /* another copy of our pixel1 value */ \ - "psubusb %%xmm1, %%xmm2\n\t" \ - "psubusb %%xmm0, %%xmm3\n\t" \ - "por %%xmm3, %%xmm2\n\t" \ - "pavgb %%xmm1, %%xmm0\n\t" /* avg of 2 pixels */ \ - "movdqa %%xmm2, %%xmm3\n\t" /* another copy of our our weights */ \ - "pxor %%xmm1, %%xmm1\n\t" \ - "psubusb %%xmm7, %%xmm3\n\t" /* nonzero where old weights lower, else 0 */ \ - "pcmpeqb %%xmm1, %%xmm3\n\t" /* now ff where new better, else 00 */ \ - "pcmpeqb %%xmm3, %%xmm1\n\t" /* here ff where old better, else 00 */ \ - "pand %%xmm3, %%xmm0\n\t" /* keep only better new pixels */ \ - "pand %%xmm3, %%xmm2\n\t" /* and weights */ \ - "pand %%xmm1, %%xmm5\n\t" /* keep only better old pixels */ \ - "pand %%xmm1, %%xmm7\n\t" \ - "por %%xmm0, %%xmm5\n\t" /* and merge new & old vals */ \ - "por %%xmm2, %%xmm7\n\t" - -#define RESET_CHROMA "por "_UVMask", %%xmm7\n\t" - -#else // ifdef IS_SSE2 - -#define MERGE4PIXavg(PADDR1, PADDR2) \ - "movq "PADDR1", %%mm0\n\t" /* our 4 pixels */ \ - "movq "PADDR2", %%mm1\n\t" /* our pixel2 value */ \ - "movq %%mm0, %%mm2\n\t" /* another copy of our pixel1 value */ \ - "movq %%mm1, %%mm3\n\t" /* another copy of our pixel1 value */ \ - "psubusb %%mm1, %%mm2\n\t" \ - "psubusb %%mm0, %%mm3\n\t" \ - "por %%mm3, %%mm2\n\t" \ - V_PAVGB ("%%mm0", "%%mm1", "%%mm3", _ShiftMask) /* avg of 2 pixels */ \ - "movq %%mm2, %%mm3\n\t" /* another copy of our our weights */ \ - "pxor %%mm1, %%mm1\n\t" \ - "psubusb %%mm7, %%mm3\n\t" /* nonzero where old weights lower, else 0 */ \ - "pcmpeqb %%mm1, %%mm3\n\t" /* now ff where new better, else 00 */ \ - "pcmpeqb %%mm3, %%mm1\n\t" /* here ff where old better, else 00 */ \ - "pand %%mm3, %%mm0\n\t" /* keep only better new pixels */ \ - "pand %%mm3, %%mm2\n\t" /* and weights */ \ - "pand %%mm1, %%mm5\n\t" /* keep only better old pixels */ \ - "pand %%mm1, %%mm7\n\t" \ - "por %%mm0, %%mm5\n\t" /* and merge new & old vals */ \ - "por %%mm2, %%mm7\n\t" - -#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B) \ - "movq "PADDR1A", %%mm0\n\t" /* our 4 pixels */ \ - "movq "PADDR2A", %%mm1\n\t" /* our pixel2 value */ \ - "movq "PADDR1B", %%mm2\n\t" /* our 4 pixels */ \ - "movq "PADDR2B", %%mm3\n\t" /* our pixel2 value */ \ - V_PAVGB("%%mm0", "%%mm2", "%%mm2", _ShiftMask) \ - V_PAVGB("%%mm1", "%%mm3", "%%mm3", _ShiftMask) \ - "movq %%mm0, %%mm2\n\t" /* another copy of our pixel1 value */ \ - "movq %%mm1, %%mm3\n\t" /* another copy of our pixel1 value */ \ - "psubusb %%mm1, %%mm2\n\t" \ - "psubusb %%mm0, %%mm3\n\t" \ - "por %%mm3, %%mm2\n\t" \ - V_PAVGB("%%mm0", "%%mm1", "%%mm3", _ShiftMask) /* avg of 2 pixels */ \ - "movq %%mm2, %%mm3\n\t" /* another copy of our our weights */ \ - "pxor %%mm1, %%mm1\n\t" \ - "psubusb %%mm7, %%mm3\n\t" /* nonzero where old weights lower, else 0 */ \ - "pcmpeqb %%mm1, %%mm3\n\t" /* now ff where new better, else 00 */ \ - "pcmpeqb %%mm3, %%mm1\n\t" /* here ff where old better, else 00 */ \ - "pand %%mm3, %%mm0\n\t" /* keep only better new pixels */ \ - "pand %%mm3, %%mm2\n\t" /* and weights */ \ - "pand %%mm1, %%mm5\n\t" /* keep only better old pixels */ \ - "pand %%mm1, %%mm7\n\t" \ - "por %%mm0, %%mm5\n\t" /* and merge new & old vals */ \ - "por %%mm2, %%mm7\n\t" - -#define RESET_CHROMA "por "_UVMask", %%mm7\n\t" - -#endif - - diff --git a/gst/deinterlace2/tvtime/vfir.c b/gst/deinterlace2/tvtime/vfir.c deleted file mode 100644 index 56950459..00000000 --- a/gst/deinterlace2/tvtime/vfir.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * - * GStreamer - * Copyright (C) 2004 Billy Biggs - * Copyright (c) 2001, 2002, 2003 Fabrice Bellard. - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - -/* - * This file contains code from ffmpeg, see http://ffmpeg.org/ (LGPL) - * and modifications by Billy Biggs. - * - * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs. - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_VFIR (gst_deinterlace_method_vfir_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_VFIR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR)) -#define GST_IS_DEINTERLACE_METHOD_VFIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR)) -#define GST_DEINTERLACE_METHOD_VFIR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass)) -#define GST_DEINTERLACE_METHOD_VFIR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIR)) -#define GST_DEINTERLACE_METHOD_VFIR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass)) -#define GST_DEINTERLACE_METHOD_VFIR_CAST(obj) ((GstDeinterlaceMethodVFIR*)(obj)) - -GType gst_deinterlace_method_vfir_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodVFIR; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodVFIRClass; - -/* - * The MPEG2 spec uses a slightly harsher filter, they specify - * [-1 8 2 8 -1]. ffmpeg uses a similar filter but with more of - * a tendancy to blur than to use the local information. The - * filter taps here are: [-1 4 2 4 -1]. - */ - -/** - * C implementation. - */ -static inline void -deinterlace_line_c (GstDeinterlaceMethod * self, GstDeinterlace2 * parent, - guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width) -{ - gint sum; - guint8 *lum_m4 = scanlines->tt1; - guint8 *lum_m3 = scanlines->t0; - guint8 *lum_m2 = scanlines->m1; - guint8 *lum_m1 = scanlines->b0; - guint8 *lum = scanlines->bb1; - gint size = width * 2; - - for (; size >= 0; size--) { - sum = -lum_m4[0]; - sum += lum_m3[0] << 2; - sum += lum_m2[0] << 1; - sum += lum_m1[0] << 2; - sum += -lum[0]; - dst[0] = (sum + 4) >> 3; // This needs to be clipped at 0 and 255: cm[(sum + 4) >> 3]; - lum_m4++; - lum_m3++; - lum_m2++; - lum_m1++; - lum++; - dst++; - } -} - -#ifdef BUILD_X86_ASM -#include "mmx.h" -static void -deinterlace_line_mmx (GstDeinterlaceMethod * self, GstDeinterlace2 * parent, - guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width) -{ - mmx_t rounder; - guint8 *lum_m4 = scanlines->tt1; - guint8 *lum_m3 = scanlines->t0; - guint8 *lum_m2 = scanlines->m1; - guint8 *lum_m1 = scanlines->b0; - guint8 *lum = scanlines->bb1; - - rounder.uw[0] = 4; - rounder.uw[1] = 4; - rounder.uw[2] = 4; - rounder.uw[3] = 4; - pxor_r2r (mm7, mm7); - movq_m2r (rounder, mm6); - - for (; width > 1; width -= 2) { - movd_m2r (*lum_m4, mm0); - movd_m2r (*lum_m3, mm1); - movd_m2r (*lum_m2, mm2); - movd_m2r (*lum_m1, mm3); - movd_m2r (*lum, mm4); - punpcklbw_r2r (mm7, mm0); - punpcklbw_r2r (mm7, mm1); - punpcklbw_r2r (mm7, mm2); - punpcklbw_r2r (mm7, mm3); - punpcklbw_r2r (mm7, mm4); - paddw_r2r (mm3, mm1); - psllw_i2r (1, mm2); - paddw_r2r (mm4, mm0); - psllw_i2r (2, mm1); // 2 - paddw_r2r (mm6, mm2); - paddw_r2r (mm2, mm1); - psubusw_r2r (mm0, mm1); - psrlw_i2r (3, mm1); // 3 - packuswb_r2r (mm7, mm1); - movd_r2m (mm1, *dst); - lum_m4 += 4; - lum_m3 += 4; - lum_m2 += 4; - lum_m1 += 4; - lum += 4; - dst += 4; - } - emms (); - - /* Handle odd widths */ - if (width > 0) { - scanlines->tt1 = lum_m4; - scanlines->t0 = lum_m3; - scanlines->m1 = lum_m2; - scanlines->b0 = lum_m1; - scanlines->bb1 = lum; - - deinterlace_line_c (self, parent, dst, scanlines, width); - } -} -#endif - -G_DEFINE_TYPE (GstDeinterlaceMethodVFIR, gst_deinterlace_method_vfir, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_vfir_class_init (GstDeinterlaceMethodVFIRClass * klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; -#ifdef BUILD_X86_ASM - guint cpu_flags = oil_cpu_get_flags (); -#endif - - dim_class->fields_required = 2; - dim_class->name = "Blur Vertical"; - dim_class->nick = "vfir"; - dim_class->latency = 0; - -#ifdef BUILD_X86_ASM - if (cpu_flags & OIL_IMPL_FLAG_MMX) { - dism_class->interpolate_scanline = deinterlace_line_mmx; - } else { - dism_class->interpolate_scanline = deinterlace_line_c; - } -#else - dism_class->interpolate_scanline = deinterlace_line_c; -#endif -} - -static void -gst_deinterlace_method_vfir_init (GstDeinterlaceMethodVFIR * self) -{ -} diff --git a/gst/deinterlace2/tvtime/weave.c b/gst/deinterlace2/tvtime/weave.c deleted file mode 100644 index 09732a3a..00000000 --- a/gst/deinterlace2/tvtime/weave.c +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Weave frames - * Copyright (C) 2002 Billy Biggs . - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_WEAVE (gst_deinterlace_method_weave_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_WEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE)) -#define GST_IS_DEINTERLACE_METHOD_WEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE)) -#define GST_DEINTERLACE_METHOD_WEAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass)) -#define GST_DEINTERLACE_METHOD_WEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeave)) -#define GST_DEINTERLACE_METHOD_WEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass)) -#define GST_DEINTERLACE_METHOD_WEAVE_CAST(obj) ((GstDeinterlaceMethodWeave*)(obj)) - -GType gst_deinterlace_method_weave_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeave; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveClass; - - -static void -deinterlace_scanline_weave (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m1, parent->row_stride); -} - -static void -copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent, - guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m0, parent->row_stride); -} - -G_DEFINE_TYPE (GstDeinterlaceMethodWeave, gst_deinterlace_method_weave, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_weave_class_init (GstDeinterlaceMethodWeaveClass * klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; - - dim_class->fields_required = 2; - dim_class->name = "Weave"; - dim_class->nick = "weave"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_weave; - dism_class->copy_scanline = copy_scanline; -} - -static void -gst_deinterlace_method_weave_init (GstDeinterlaceMethodWeave * self) -{ -} diff --git a/gst/deinterlace2/tvtime/weavebff.c b/gst/deinterlace2/tvtime/weavebff.c deleted file mode 100644 index 4ddf5a51..00000000 --- a/gst/deinterlace2/tvtime/weavebff.c +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Weave frames, bottom-field-first. - * Copyright (C) 2003 Billy Biggs . - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF)) -#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF)) -#define GST_DEINTERLACE_METHOD_WEAVE_BFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass)) -#define GST_DEINTERLACE_METHOD_WEAVE_BFF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFF)) -#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass)) -#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CAST(obj) ((GstDeinterlaceMethodWeaveBFF*)(obj)) - -GType gst_deinterlace_method_weave_bff_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveBFF; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveBFFClass; - - -static void -deinterlace_scanline_weave (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m1, parent->row_stride); -} - -static void -copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent, - guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) -{ - /* FIXME: original code used m2 and m0 but this looks really bad */ - if (scanlines->bottom_field) { - oil_memcpy (out, scanlines->bb2, parent->row_stride); - } else { - oil_memcpy (out, scanlines->bb0, parent->row_stride); - } -} - -G_DEFINE_TYPE (GstDeinterlaceMethodWeaveBFF, gst_deinterlace_method_weave_bff, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_weave_bff_class_init (GstDeinterlaceMethodWeaveBFFClass * - klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; - - dim_class->fields_required = 3; - dim_class->name = "Progressive: Bottom Field First"; - dim_class->nick = "weavebff"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_weave; - dism_class->copy_scanline = copy_scanline; -} - -static void -gst_deinterlace_method_weave_bff_init (GstDeinterlaceMethodWeaveBFF * self) -{ -} diff --git a/gst/deinterlace2/tvtime/weavetff.c b/gst/deinterlace2/tvtime/weavetff.c deleted file mode 100644 index 9411f51b..00000000 --- a/gst/deinterlace2/tvtime/weavetff.c +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Weave frames, top-field-first. - * Copyright (C) 2003 Billy Biggs . - * Copyright (C) 2008 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "_stdint.h" -#include "gstdeinterlace2.h" -#include - -#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ()) -#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF)) -#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF)) -#define GST_DEINTERLACE_METHOD_WEAVE_TFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass)) -#define GST_DEINTERLACE_METHOD_WEAVE_TFF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFF)) -#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass)) -#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CAST(obj) ((GstDeinterlaceMethodWeaveTFF*)(obj)) - -GType gst_deinterlace_method_weave_tff_get_type (void); - -typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveTFF; - -typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveTFFClass; - - -static void -deinterlace_scanline_weave (GstDeinterlaceMethod * self, - GstDeinterlace2 * parent, guint8 * out, - GstDeinterlaceScanlineData * scanlines, gint width) -{ - oil_memcpy (out, scanlines->m1, parent->row_stride); -} - -static void -copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent, - guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) -{ - /* FIXME: original code used m2 and m0 but this looks really bad */ - if (scanlines->bottom_field) { - oil_memcpy (out, scanlines->bb0, parent->row_stride); - } else { - oil_memcpy (out, scanlines->bb2, parent->row_stride); - } -} - -G_DEFINE_TYPE (GstDeinterlaceMethodWeaveTFF, gst_deinterlace_method_weave_tff, - GST_TYPE_DEINTERLACE_SIMPLE_METHOD); - -static void -gst_deinterlace_method_weave_tff_class_init (GstDeinterlaceMethodWeaveTFFClass * - klass) -{ - GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; - GstDeinterlaceSimpleMethodClass *dism_class = - (GstDeinterlaceSimpleMethodClass *) klass; - - dim_class->fields_required = 3; - dim_class->name = "Progressive: Top Field First"; - dim_class->nick = "weavetff"; - dim_class->latency = 0; - - dism_class->interpolate_scanline = deinterlace_scanline_weave; - dism_class->copy_scanline = copy_scanline; -} - -static void -gst_deinterlace_method_weave_tff_init (GstDeinterlaceMethodWeaveTFF * self) -{ -} diff --git a/gst/deinterlace2/tvtime/x86-64_macros.inc b/gst/deinterlace2/tvtime/x86-64_macros.inc deleted file mode 100644 index 2e9df758..00000000 --- a/gst/deinterlace2/tvtime/x86-64_macros.inc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * GStreamer - * Copyright (C) 2004 Dirk Ziegelmeier - * - * 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. - */ - -/* - * - * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578 - */ - -/* - * This file is copied from TVTIME's sources. - * Original author: Achim Schneider - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef XAX - -#if defined (HAVE_CPU_I386) && !defined(HAVE_CPU_X86_64) - -#define XAX "eax" -#define XBX "ebx" -#define XCX "ecx" -#define XDX "edx" -#define XSI "esi" -#define XDI "edi" -#define XSP "esp" -#define MOVX "movl" -#define LEAX "leal" -#define DECX "decl" -#define PUSHX "pushl" -#define POPX "popl" -#define CMPX "cmpl" -#define ADDX "addl" -#define SHLX "shll" -#define SHRX "shrl" -#define SUBX "subl" - -#elif defined (HAVE_CPU_X86_64) - -#define XAX "rax" -#define XBX "rbx" -#define XCX "rcx" -#define XDX "rdx" -#define XSI "rsi" -#define XDI "rdi" -#define XSP "rsp" -#define MOVX "movq" -#define LEAX "leaq" -#define DECX "decq" -#define PUSHX "pushq" -#define POPX "popq" -#define CMPX "cmpq" -#define ADDX "addq" -#define SHLX "shlq" -#define SHRX "shrq" -#define SUBX "subq" - -#else -#error Undefined architecture. Define either ARCH_X86 or ARCH_X86_64. -#endif - -#endif -- cgit v1.2.1 From 60f46ec99ce543a6342b2ec12a2ff26043f98e38 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 13 May 2009 17:54:47 +0200 Subject: y4menc: don't strip timestamps Fixes #582483 --- gst/y4m/gsty4mencode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'gst') diff --git a/gst/y4m/gsty4mencode.c b/gst/y4m/gsty4mencode.c index dc218643..cc9352ab 100644 --- a/gst/y4m/gsty4mencode.c +++ b/gst/y4m/gsty4mencode.c @@ -231,6 +231,7 @@ gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf) { GstY4mEncode *filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); GstBuffer *outbuf; + GstClockTime timestamp; /* check we got some decent info from caps */ if (filter->width < 0) { @@ -240,6 +241,8 @@ gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf) return GST_FLOW_NOT_NEGOTIATED; } + timestamp = GST_BUFFER_TIMESTAMP (buf); + if (G_UNLIKELY (!filter->header)) { outbuf = gst_y4m_encode_get_stream_header (filter); filter->header = TRUE; @@ -252,8 +255,9 @@ gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf) /* decorate */ gst_buffer_make_metadata_writable (outbuf); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (filter->srcpad)); - /* strip to avoid sink dropping on time-base, decorate and send */ - GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + return gst_pad_push (filter->srcpad, outbuf); } -- cgit v1.2.1 From b20a88702d2fb88886575cbeca24ae5684851ca4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 13 May 2009 17:55:46 +0200 Subject: y4menc: change my email change my email to something more current See #580783 --- gst/y4m/gsty4mencode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/y4m/gsty4mencode.c b/gst/y4m/gsty4mencode.c index cc9352ab..3b82f5c1 100644 --- a/gst/y4m/gsty4mencode.c +++ b/gst/y4m/gsty4mencode.c @@ -51,7 +51,7 @@ static const GstElementDetails y4mencode_details = GST_ELEMENT_DETAILS ("YUV4MPEG video encoder", "Codec/Encoder/Video", "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)", - "Wim Taymans "); + "Wim Taymans "); /* Filter signals and args */ -- cgit v1.2.1 From 29b44a5e2f058689ba7ecec00b5355c8cf0dc642 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 May 2009 10:55:38 +0100 Subject: dvdspu: Push update frame, if any, when entering stills. When entering a still frame generates an updated buffer, make sure to push it out, otherwise we may not put a frame onscreen with a rendered button, causing raciness as to whether buttons get drawn or not when jumping back to the menu on some discs. --- gst/dvdspu/gstdvdspu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gst') diff --git a/gst/dvdspu/gstdvdspu.c b/gst/dvdspu/gstdvdspu.c index 82048529..703c405b 100644 --- a/gst/dvdspu/gstdvdspu.c +++ b/gst/dvdspu/gstdvdspu.c @@ -417,6 +417,8 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event) gboolean in_still; if (gst_structure_get_boolean (structure, "still-state", &in_still)) { + GstBuffer *to_push = NULL; + GST_DEBUG_OBJECT (dvdspu, "DVD event of type %s on video pad: in-still = %d", event_type, in_still); @@ -431,10 +433,15 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event) * screen, otherwise the last frame might have been discarded * by QoS */ gst_dvd_spu_redraw_still (dvdspu, TRUE); + to_push = dvdspu->pending_frame; + dvdspu->pending_frame = NULL; + } else { state->flags &= ~(SPU_STATE_STILL_FRAME); } DVD_SPU_UNLOCK (dvdspu); + if (to_push) + gst_pad_push (dvdspu->srcpad, to_push); } gst_event_unref (event); res = TRUE; -- cgit v1.2.1 From f5ba4904f794a107bc5d1e56f824789bca295383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 14 May 2009 21:20:47 +0200 Subject: mxfdemux: Use a RW lock to protect metadata and add all pads at once without a lock held This makes it possible, among other things, to do a query in the pad-added callback. Fixes bug #582656. --- gst/mxf/mxfdemux.c | 161 ++++++++++++++++++++++++++++++----------------------- gst/mxf/mxfdemux.h | 2 +- 2 files changed, 93 insertions(+), 70 deletions(-) (limited to 'gst') diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c index 6d7ca034..c33650b5 100644 --- a/gst/mxf/mxfdemux.c +++ b/gst/mxf/mxfdemux.c @@ -203,7 +203,7 @@ gst_mxf_demux_reset_metadata (GstMXFDemux * demux) { GST_DEBUG_OBJECT (demux, "Resetting metadata"); - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_writer_lock (&demux->metadata_lock); demux->update_metadata = TRUE; demux->metadata_resolved = FALSE; @@ -217,7 +217,7 @@ gst_mxf_demux_reset_metadata (GstMXFDemux * demux) } demux->metadata = mxf_metadata_hash_table_new (); - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_writer_unlock (&demux->metadata_lock); } static void @@ -513,11 +513,14 @@ gst_mxf_demux_resolve_references (GstMXFDemux * demux) GstStructure *structure; GstTagList *taglist; + g_static_rw_lock_writer_lock (&demux->metadata_lock); + GST_DEBUG_OBJECT (demux, "Resolve metadata references"); demux->update_metadata = FALSE; if (!demux->metadata) { GST_ERROR_OBJECT (demux, "No metadata yet"); + g_static_rw_lock_writer_unlock (&demux->metadata_lock); return GST_FLOW_ERROR; } #if GLIB_CHECK_VERSION (2, 16, 0) @@ -565,6 +568,8 @@ gst_mxf_demux_resolve_references (GstMXFDemux * demux) g_list_free (values); #endif + g_static_rw_lock_writer_unlock (&demux->metadata_lock); + return ret; error: @@ -573,6 +578,7 @@ error: #endif demux->metadata_resolved = FALSE; + g_static_rw_lock_writer_unlock (&demux->metadata_lock); return ret; } @@ -913,24 +919,29 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux) gboolean first_run; guint component_index; GstFlowReturn ret; + GList *pads = NULL, *l; + g_static_rw_lock_writer_lock (&demux->metadata_lock); GST_DEBUG_OBJECT (demux, "Updating tracks"); if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) { - return ret; + goto error; } current_package = gst_mxf_demux_choose_package (demux); if (!current_package) { GST_ERROR_OBJECT (demux, "Unable to find current package"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } else if (!current_package->tracks) { GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } else if (!current_package->n_essence_tracks) { GST_ERROR_OBJECT (demux, "Current package has no essence tracks"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } first_run = (demux->src->len == 0); @@ -977,10 +988,12 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux) if (!track->parent.sequence) { GST_WARNING_OBJECT (demux, "Track with no sequence"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } sequence = track->parent.sequence; @@ -1021,20 +1034,24 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux) if (track->parent.type && (track->parent.type & 0xf0) != 0x30) { GST_DEBUG_OBJECT (demux, "No essence track"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN || !source_track) { GST_WARNING_OBJECT (demux, "No source package or track type for track found"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } for (k = 0; k < demux->essence_tracks->len; k++) { @@ -1050,44 +1067,54 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux) if (!etrack) { GST_WARNING_OBJECT (demux, "No essence track for this track found"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 || source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) { GST_WARNING_OBJECT (demux, "Track has an invalid edit rate"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) { GST_WARNING_OBJECT (demux, "Playing material package but found no component for track"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (!source_package->descriptor) { GST_WARNING_OBJECT (demux, "Source package has no descriptors"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (!source_track->parent.descriptor) { GST_WARNING_OBJECT (demux, "No descriptor found for track"); - if (!pad) + if (!pad) { continue; - else - return GST_FLOW_ERROR; + } else { + ret = GST_FLOW_ERROR; + goto error; + } } if (!pad && first_run) { @@ -1178,31 +1205,43 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux) gst_pad_use_fixed_caps (GST_PAD_CAST (pad)); gst_pad_set_active (GST_PAD_CAST (pad), TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (demux), gst_object_ref (pad)); + pads = g_list_prepend (pads, gst_object_ref (pad)); g_ptr_array_add (demux->src, pad); pad->discont = TRUE; } } - if (first_run) - gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); - if (demux->src->len > 0) { for (i = 0; i < demux->src->len; i++) { GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i); if (!pad->material_track || !pad->material_package) { GST_ERROR_OBJECT (demux, "Unable to update existing pad"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } } } else { GST_ERROR_OBJECT (demux, "Couldn't create any streams"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } + g_static_rw_lock_writer_unlock (&demux->metadata_lock); + + for (l = pads; l; l = l->next) + gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data); + g_list_free (pads); + + if (first_run) + gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); + return GST_FLOW_OK; + +error: + g_static_rw_lock_writer_unlock (&demux->metadata_lock); + return ret; } static GstFlowReturn @@ -1276,7 +1315,7 @@ gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key, return GST_FLOW_OK; } - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_writer_lock (&demux->metadata_lock); demux->update_metadata = TRUE; if (MXF_IS_METADATA_PREFACE (metadata)) { @@ -1287,7 +1326,7 @@ gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key, g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (metadata)->instance_uid, metadata); - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_writer_unlock (&demux->metadata_lock); return ret; } @@ -1365,7 +1404,7 @@ gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux, return GST_FLOW_OK; } - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_writer_lock (&demux->metadata_lock); demux->update_metadata = TRUE; gst_mxf_demux_reset_linked_metadata (demux); @@ -1373,7 +1412,7 @@ gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux, g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid, m); - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_writer_unlock (&demux->metadata_lock); return ret; } @@ -2224,17 +2263,14 @@ next_try: /* resolve references etc */ - g_mutex_lock (demux->metadata_lock); if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) { demux->current_partition->parsed_metadata = TRUE; demux->offset = demux->run_in + demux->current_partition->partition.this_partition - demux->current_partition->partition.prev_partition; - g_mutex_unlock (demux->metadata_lock); goto next_try; } - g_mutex_unlock (demux->metadata_lock); out: if (buffer) @@ -2253,7 +2289,6 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key, #endif GstFlowReturn ret = GST_FLOW_OK; - g_mutex_lock (demux->metadata_lock); if (demux->update_metadata && demux->preface && (demux->offset >= @@ -2265,16 +2300,13 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key, demux->current_partition->parsed_metadata = TRUE; if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK || (ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) { - g_mutex_unlock (demux->metadata_lock); goto beach; } } else if (demux->metadata_resolved && demux->requested_package_string) { if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) { - g_mutex_unlock (demux->metadata_lock); goto beach; } } - g_mutex_unlock (demux->metadata_lock); if (!mxf_is_mxf_packet (key)) { GST_WARNING_OBJECT (demux, @@ -3106,15 +3138,12 @@ gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event) guint64 new_offset = -1; GstEvent *e; - g_mutex_lock (demux->metadata_lock); if (!demux->metadata_resolved || demux->update_metadata) { if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) { - g_mutex_unlock (demux->metadata_lock); goto unresolved_metadata; } } - g_mutex_unlock (demux->metadata_lock); /* Do the actual seeking */ for (i = 0; i < demux->src->len; i++) { @@ -3266,15 +3295,12 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event) if (flush || seeksegment.last_stop != demux->segment.last_stop) { guint64 new_offset = -1; - g_mutex_lock (demux->metadata_lock); if (!demux->metadata_resolved || demux->update_metadata) { if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) { - g_mutex_unlock (demux->metadata_lock); goto unresolved_metadata; } } - g_mutex_unlock (demux->metadata_lock); /* Do the actual seeking */ for (i = 0; i < demux->src->len; i++) { @@ -3455,11 +3481,11 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query) pos = mxfpad->last_stop; - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_reader_lock (&demux->metadata_lock); if (format == GST_FORMAT_DEFAULT && pos != GST_CLOCK_TIME_NONE) { if (!mxfpad->material_track || mxfpad->material_track->edit_rate.n == 0 || mxfpad->material_track->edit_rate.d == 0) { - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); goto error; } @@ -3468,7 +3494,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query) mxfpad->material_track->edit_rate.n, mxfpad->material_track->edit_rate.d * GST_SECOND); } - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); GST_DEBUG_OBJECT (pad, "Returning position %" G_GINT64_FORMAT " in format %s", pos, @@ -3487,9 +3513,9 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query) if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) goto error; - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_reader_lock (&demux->metadata_lock); if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) { - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); goto error; } @@ -3500,7 +3526,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query) if (duration != -1 && format == GST_FORMAT_TIME) { if (mxfpad->material_track->edit_rate.n == 0 || mxfpad->material_track->edit_rate.d == 0) { - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); goto error; } @@ -3509,7 +3535,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query) GST_SECOND * mxfpad->material_track->edit_rate.d, mxfpad->material_track->edit_rate.n); } - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); GST_DEBUG_OBJECT (pad, "Returning duration %" G_GINT64_FORMAT " in format %s", duration, @@ -3746,7 +3772,7 @@ gst_mxf_demux_query (GstElement * element, GstQuery * query) if (demux->src->len == 0) goto done; - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_reader_lock (&demux->metadata_lock); for (i = 0; i < demux->src->len; i++) { GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i); gint64 pdur = -1; @@ -3765,7 +3791,7 @@ gst_mxf_demux_query (GstElement * element, GstQuery * query) pad->material_track->edit_rate.n); duration = MAX (duration, pdur); } - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); if (duration == -1) { GST_DEBUG_OBJECT (demux, "No duration known (yet)"); @@ -3862,7 +3888,7 @@ gst_mxf_demux_get_property (GObject * object, guint prop_id, case PROP_STRUCTURE:{ GstStructure *s; - g_mutex_lock (demux->metadata_lock); + g_static_rw_lock_reader_lock (&demux->metadata_lock); if (demux->preface) s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface)); else @@ -3873,7 +3899,7 @@ gst_mxf_demux_get_property (GObject * object, guint prop_id, if (s) gst_structure_free (s); - g_mutex_unlock (demux->metadata_lock); + g_static_rw_lock_reader_unlock (&demux->metadata_lock); break; } default: @@ -3911,10 +3937,7 @@ gst_mxf_demux_finalize (GObject * object) g_hash_table_destroy (demux->metadata); - if (demux->metadata_lock) { - g_mutex_free (demux->metadata_lock); - demux->metadata_lock = NULL; - } + g_static_rw_lock_free (&demux->metadata_lock); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -3990,7 +4013,7 @@ gst_mxf_demux_init (GstMXFDemux * demux, GstMXFDemuxClass * g_class) demux->max_drift = 500 * GST_MSECOND; demux->adapter = gst_adapter_new (); - demux->metadata_lock = g_mutex_new (); + g_static_rw_lock_init (&demux->metadata_lock); demux->src = g_ptr_array_new (); demux->essence_tracks = diff --git a/gst/mxf/mxfdemux.h b/gst/mxf/mxfdemux.h index c8439cf6..e8b90261 100644 --- a/gst/mxf/mxfdemux.h +++ b/gst/mxf/mxfdemux.h @@ -154,7 +154,7 @@ struct _GstMXFDemux GArray *random_index_pack; /* Metadata */ - GMutex *metadata_lock; + GStaticRWLock metadata_lock; gboolean update_metadata; gboolean pull_footer_metadata; -- cgit v1.2.1 From 405f80dec487103dfe52e6ce6aa3fb05db74e495 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 15 May 2009 01:54:44 -0300 Subject: [qtmux] Fixes segfault when adding a blob as first tag. Moves tags data initialization to the function that actually appends the tags to the list. Fixes #582702 Also fixes some style caught by the pre-commit hook. --- gst/qtmux/atoms.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'gst') diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index df6958e0..a5d8fe38 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -1855,13 +1855,11 @@ atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size, break; default: if (se->kind == VIDEO) { - size += - sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker-> - data, buffer, size, offset); + size += sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) + walker->data, buffer, size, offset); } else if (se->kind == AUDIO) { - size += - sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker-> - data, buffer, size, offset); + size += sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) + walker->data, buffer, size, offset); } else { if (!atom_hint_sample_entry_copy_data ( (AtomHintSampleEntry *) walker->data, buffer, size, offset)) { @@ -2547,6 +2545,7 @@ atom_moov_append_tag (AtomMOOV * moov, AtomInfo * tag) { AtomILST *ilst; + atom_moov_init_metatags (moov); ilst = moov->udta->meta->ilst; ilst->entries = g_list_append (ilst->entries, tag); } @@ -2563,7 +2562,6 @@ atom_moov_add_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags, atom_tag_data_alloc_data (tdata, size); g_memmove (tdata->data, data, size); - atom_moov_init_metatags (moov); atom_moov_append_tag (moov, build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data, atom_tag_free)); -- cgit v1.2.1 From 48e32a0890ecb089806768eec4c5ac30cf7333d6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 16 May 2009 00:17:00 +0100 Subject: Moved 'y4menc' from -bad to -good --- gst/y4m/Makefile.am | 10 -- gst/y4m/gsty4mencode.c | 336 ------------------------------------------------- gst/y4m/gsty4mencode.h | 67 ---------- gst/y4m/y4menc.vcproj | 148 ---------------------- 4 files changed, 561 deletions(-) delete mode 100644 gst/y4m/Makefile.am delete mode 100644 gst/y4m/gsty4mencode.c delete mode 100644 gst/y4m/gsty4mencode.h delete mode 100644 gst/y4m/y4menc.vcproj (limited to 'gst') diff --git a/gst/y4m/Makefile.am b/gst/y4m/Makefile.am deleted file mode 100644 index 4415e9e2..00000000 --- a/gst/y4m/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ - -plugin_LTLIBRARIES = libgsty4menc.la - -libgsty4menc_la_SOURCES = gsty4mencode.c -libgsty4menc_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -libgsty4menc_la_LIBADD = $(GST_LIBS) -libgsty4menc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgsty4menc_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gsty4mencode.h diff --git a/gst/y4m/gsty4mencode.c b/gst/y4m/gsty4mencode.c deleted file mode 100644 index 3b82f5c1..00000000 --- a/gst/y4m/gsty4mencode.c +++ /dev/null @@ -1,336 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006> Mark Nauwelaerts - * - * 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. - */ -/** - * SECTION:element-y4menc - * - * - * - * Creates a YU4MPEG2 raw video stream as defined by the mjpegtools project. - * - * Example launch line - * - * (write everything in one line, without the backslash characters) - * - * gst-launch-0.10 videotestsrc num-buffers=250 \ - * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \ - * ! y4menc ! filesink location=test.yuv - * - * - * - * - */ - -/* see mjpegtools/yuv4mpeg.h for yuv4mpeg format */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include "gsty4mencode.h" - -static const GstElementDetails y4mencode_details = -GST_ELEMENT_DETAILS ("YUV4MPEG video encoder", - "Codec/Encoder/Video", - "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)", - "Wim Taymans "); - - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static GstStaticPadTemplate y4mencode_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-yuv4mpeg, " "y4mversion = (int) 2") - ); - -static GstStaticPadTemplate y4mencode_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420 }")) - ); - - -static void gst_y4m_encode_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_y4m_encode_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static void gst_y4m_encode_reset (GstY4mEncode * filter); - -static gboolean gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps); -static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf); -static GstStateChangeReturn gst_y4m_encode_change_state (GstElement * element, - GstStateChange transition); - -GST_BOILERPLATE (GstY4mEncode, gst_y4m_encode, GstElement, GST_TYPE_ELEMENT); - - -static void -gst_y4m_encode_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&y4mencode_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&y4mencode_sink_factory)); - gst_element_class_set_details (element_class, &y4mencode_details); -} - -static void -gst_y4m_encode_class_init (GstY4mEncodeClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_y4m_encode_change_state); - - gobject_class->set_property = gst_y4m_encode_set_property; - gobject_class->get_property = gst_y4m_encode_get_property; -} - -static void -gst_y4m_encode_init (GstY4mEncode * filter, GstY4mEncodeClass * klass) -{ - filter->sinkpad = - gst_pad_new_from_static_template (&y4mencode_sink_factory, "sink"); - gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); - gst_pad_set_chain_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_y4m_encode_chain)); - gst_pad_set_setcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_y4m_encode_setcaps)); - - filter->srcpad = - gst_pad_new_from_static_template (&y4mencode_src_factory, "src"); - gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - gst_pad_use_fixed_caps (filter->srcpad); - - /* init properties */ - gst_y4m_encode_reset (filter); -} - -static void -gst_y4m_encode_reset (GstY4mEncode * filter) -{ - filter->width = filter->height = -1; - filter->fps_num = filter->fps_den = 1; - filter->par_num = filter->par_den = 1; -} - -static gboolean -gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps) -{ - GstY4mEncode *filter; - GstStructure *structure; - gboolean res; - gint w, h; - const GValue *fps, *par; - - filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); - - structure = gst_caps_get_structure (vscaps, 0); - - res = gst_structure_get_int (structure, "width", &w); - res &= gst_structure_get_int (structure, "height", &h); - res &= ((fps = gst_structure_get_value (structure, "framerate")) != NULL); - - if (!res || w <= 0 || h <= 0 || !GST_VALUE_HOLDS_FRACTION (fps)) - return FALSE; - - /* optional par info */ - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - - filter->width = w; - filter->height = h; - filter->fps_num = gst_value_get_fraction_numerator (fps); - filter->fps_den = gst_value_get_fraction_denominator (fps); - if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) { - filter->par_num = gst_value_get_fraction_numerator (par); - filter->par_den = gst_value_get_fraction_denominator (par); - } else { /* indicates unknown */ - filter->par_num = 0; - filter->par_den = 0; - } - - /* the template caps will do for the src pad, should always accept */ - return gst_pad_set_caps (filter->srcpad, - gst_static_pad_template_get_caps (&y4mencode_src_factory)); -} - -static inline GstBuffer * -gst_y4m_encode_get_stream_header (GstY4mEncode * filter) -{ - gpointer header; - GstBuffer *buf; - - header = g_strdup_printf ("YUV4MPEG2 W%d H%d I? F%d:%d A%d:%d\n", - filter->width, filter->height, - filter->fps_num, filter->fps_den, filter->par_num, filter->par_den); - - buf = gst_buffer_new (); - gst_buffer_set_data (buf, header, strlen (header)); - /* so it gets free'd when needed */ - GST_BUFFER_MALLOCDATA (buf) = header; - - return buf; -} - -static inline GstBuffer * -gst_y4m_encode_get_frame_header (GstY4mEncode * filter) -{ - gpointer header; - GstBuffer *buf; - - header = g_strdup_printf ("FRAME\n"); - - buf = gst_buffer_new (); - gst_buffer_set_data (buf, header, strlen (header)); - /* so it gets free'd when needed */ - GST_BUFFER_MALLOCDATA (buf) = header; - - return buf; -} - -static GstFlowReturn -gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf) -{ - GstY4mEncode *filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); - GstBuffer *outbuf; - GstClockTime timestamp; - - /* check we got some decent info from caps */ - if (filter->width < 0) { - GST_ELEMENT_ERROR ("filter", CORE, NEGOTIATION, (NULL), - ("format wasn't negotiated before chain function")); - gst_buffer_unref (buf); - return GST_FLOW_NOT_NEGOTIATED; - } - - timestamp = GST_BUFFER_TIMESTAMP (buf); - - if (G_UNLIKELY (!filter->header)) { - outbuf = gst_y4m_encode_get_stream_header (filter); - filter->header = TRUE; - outbuf = gst_buffer_join (outbuf, gst_y4m_encode_get_frame_header (filter)); - } else { - outbuf = gst_y4m_encode_get_frame_header (filter); - } - /* join with data */ - outbuf = gst_buffer_join (outbuf, buf); - /* decorate */ - gst_buffer_make_metadata_writable (outbuf); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (filter->srcpad)); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - - return gst_pad_push (filter->srcpad, outbuf); -} - -static void -gst_y4m_encode_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstY4mEncode *filter; - - g_return_if_fail (GST_IS_Y4M_ENCODE (object)); - filter = GST_Y4M_ENCODE (object); - - switch (prop_id) { - default: - break; - } -} - -static void -gst_y4m_encode_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstY4mEncode *filter; - - g_return_if_fail (GST_IS_Y4M_ENCODE (object)); - filter = GST_Y4M_ENCODE (object); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_y4m_encode_change_state (GstElement * element, GstStateChange transition) -{ - GstY4mEncode *filter = GST_Y4M_ENCODE (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; - } - - ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, - (element, transition), GST_STATE_CHANGE_SUCCESS); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_y4m_encode_reset (filter); - break; - default: - break; - } - - return GST_STATE_CHANGE_SUCCESS; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "y4menc", GST_RANK_NONE, - GST_TYPE_Y4M_ENCODE); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "y4menc", - "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/y4m/gsty4mencode.h b/gst/y4m/gsty4mencode.h deleted file mode 100644 index 1ca8105a..00000000 --- a/gst/y4m/gsty4mencode.h +++ /dev/null @@ -1,67 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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_Y4MENCODE_H__ -#define __GST_Y4MENCODE_H__ - - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_Y4M_ENCODE \ - (gst_y4m_encode_get_type()) -#define GST_Y4M_ENCODE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncode)) -#define GST_Y4M_ENCODE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass)) -#define GST_Y4M_ENCODE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass)) -#define GST_IS_Y4M_ENCODE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_Y4M_ENCODE)) -#define GST_IS_Y4M_ENCODE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_Y4M_ENCODE)) - -typedef struct _GstY4mEncode GstY4mEncode; -typedef struct _GstY4mEncodeClass GstY4mEncodeClass; - -struct _GstY4mEncode { - GstElement element; - - GstPad *sinkpad,*srcpad; - - /* caps information */ - gint width, height; - gint fps_num, fps_den; - gint par_num, par_den; - - /* state information */ - gboolean header; -}; - -struct _GstY4mEncodeClass { - GstElementClass parent_class; -}; - -GType gst_y4m_encode_get_type(void); - -G_END_DECLS - -#endif /* __GST_Y4MENCODE_H__ */ diff --git a/gst/y4m/y4menc.vcproj b/gst/y4m/y4menc.vcproj deleted file mode 100644 index 7251140e..00000000 --- a/gst/y4m/y4menc.vcproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.1 From 90aa8eff4c553a9be1e644b424116c0280e0abfa Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 15 May 2009 10:45:45 +0100 Subject: fpsdisplaysink: Fix resetting of the sink in NULL Reset the fpsdisplaysink in NULL by removing the textoverlay if we created it. Fixes: #582633 --- gst/debugutils/fpsdisplaysink.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'gst') diff --git a/gst/debugutils/fpsdisplaysink.c b/gst/debugutils/fpsdisplaysink.c index b37ab112..54f5cc54 100644 --- a/gst/debugutils/fpsdisplaysink.c +++ b/gst/debugutils/fpsdisplaysink.c @@ -267,11 +267,11 @@ fps_display_sink_start (GstFPSDisplaySink * self) gst_object_ref (self->text_overlay); g_object_set (self->text_overlay, "font-desc", DEFAULT_FONT, "silent", FALSE, NULL); - } - gst_bin_add (GST_BIN (self), self->text_overlay); + gst_bin_add (GST_BIN (self), self->text_overlay); - if (!gst_element_link (self->text_overlay, self->video_sink)) { - GST_ERROR_OBJECT (self, "Could not link elements"); + if (!gst_element_link (self->text_overlay, self->video_sink)) { + GST_ERROR_OBJECT (self, "Could not link elements"); + } } target_pad = gst_element_get_static_pad (self->text_overlay, "video_sink"); } @@ -280,6 +280,7 @@ no_text_overlay: if (self->text_overlay) { gst_element_unlink (self->text_overlay, self->video_sink); gst_bin_remove (GST_BIN (self), self->text_overlay); + self->text_overlay = NULL; } target_pad = gst_element_get_static_pad (self->video_sink, "sink"); } @@ -300,6 +301,13 @@ fps_display_sink_stop (GstFPSDisplaySink * self) g_source_remove (self->timeout_id); self->timeout_id = 0; } + + if (self->text_overlay) { + gst_element_unlink (self->text_overlay, self->video_sink); + gst_bin_remove (GST_BIN (self), self->text_overlay); + gst_object_unref (self->text_overlay); + self->text_overlay = NULL; + } } static void -- cgit v1.2.1 From 0520a2a53b91fa58ddf605f41b916fe3ef7afb50 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 20 May 2009 17:10:40 +0200 Subject: mxf: Fix frame_layout for non-interlaced formats. Fixes #583337 --- gst/mxf/mxfmetadata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/mxf/mxfmetadata.c b/gst/mxf/mxfmetadata.c index 2237bc60..7d1af0c1 100644 --- a/gst/mxf/mxfmetadata.c +++ b/gst/mxf/mxfmetadata.c @@ -4984,7 +4984,7 @@ gboolean s = gst_caps_get_structure (caps, 0); if (!gst_structure_get_boolean (s, "interlaced", &interlaced) || !interlaced) - self->frame_layout = 1; + self->frame_layout = 0; else self->frame_layout = 3; -- cgit v1.2.1 From fe38f53572ff91b63a3dc5a5a5ed78e13040d16c Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 21 May 2009 13:15:46 -0700 Subject: id3tag: Add new id3 tagging plugin, supports v1, v2.3, and v2.4. By default, does v1 and v2.3, but there are properties to select. Will hopefully replace id3mux, id3v2mux, in the not-too-distant future. --- gst/id3tag/Makefile.am | 19 + gst/id3tag/gstid3tag.c | 229 ++++++++++ gst/id3tag/gstid3tag.h | 63 +++ gst/id3tag/gsttagmux.c | 490 ++++++++++++++++++++ gst/id3tag/gsttagmux.h | 79 ++++ gst/id3tag/id3tag.c | 1194 ++++++++++++++++++++++++++++++++++++++++++++++++ gst/id3tag/id3tag.h | 32 ++ 7 files changed, 2106 insertions(+) create mode 100644 gst/id3tag/Makefile.am create mode 100644 gst/id3tag/gstid3tag.c create mode 100644 gst/id3tag/gstid3tag.h create mode 100644 gst/id3tag/gsttagmux.c create mode 100644 gst/id3tag/gsttagmux.h create mode 100644 gst/id3tag/id3tag.c create mode 100644 gst/id3tag/id3tag.h (limited to 'gst') diff --git a/gst/id3tag/Makefile.am b/gst/id3tag/Makefile.am new file mode 100644 index 00000000..9595be0f --- /dev/null +++ b/gst/id3tag/Makefile.am @@ -0,0 +1,19 @@ +plugin_LTLIBRARIES = libgstid3tag.la + +libgstid3tag_la_SOURCES = \ + gsttagmux.c \ + id3tag.c \ + gstid3tag.c + +libgstid3tag_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_CFLAGS) + +libgstid3tag_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \ + $(GST_LIBS) + +libgstid3tag_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstid3tag_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstid3tag.h id3tag.h gsttagmux.h diff --git a/gst/id3tag/gstid3tag.c b/gst/id3tag/gstid3tag.c new file mode 100644 index 00000000..f67d781f --- /dev/null +++ b/gst/id3tag/gstid3tag.c @@ -0,0 +1,229 @@ +/* GStreamer ID3 v1 and v2 muxer + * + * Copyright (C) 2006 Christophe Fergeau + * Copyright (C) 2006 Tim-Philipp Müller + * Copyright (C) 2009 Pioneers of the Inevitable + * + * 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. + */ + +/** + * SECTION:element-id3tag + * @see_also: #GstID3Demux, #GstTagSetter + * + * This element adds ID3v2 tags to the beginning of a stream, and ID3v1 tags + * to the end. + * + * It defaults to writing ID3 version 2.3.0 tags (since those are the most + * widely supported), but can optionally write version 2.4.0 tags. + * + * Applications can set the tags to write using the #GstTagSetter interface. + * Tags sent by upstream elements will be picked up automatically (and merged + * according to the merge mode set via the tag setter interface). + * + * + * Example pipelines + * |[ + * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! id3tag ! filesink location=foo.mp3 + * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with + * ID3 tags that contain the same metadata as the the Ogg/Vorbis file. + * Make sure the Ogg/Vorbis file actually has comments to preserve. + * |[ + * gst-launch -m filesrc location=foo.mp3 ! id3demux ! fakesink silent=TRUE 2> /dev/null | grep taglist + * ]| Verify that tags have been written. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstid3tag.h" +#include + +#include + +GST_DEBUG_CATEGORY (gst_id3tag_debug); +#define GST_CAT_DEFAULT gst_id3tag_debug + +enum +{ + ARG_0, + ARG_WRITE_V1, + ARG_WRITE_V2, + ARG_V2_MAJOR_VERSION +}; + +#define DEFAULT_WRITE_V1 TRUE +#define DEFAULT_WRITE_V2 TRUE +#define DEFAULT_V2_MAJOR_VERSION 3 + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-id3")); + +GST_BOILERPLATE (GstID3Tag, gst_id3tag, GstTagMux, GST_TYPE_TAG_MUX); + +static GstBuffer *gst_id3tag_render_v2_tag (GstTagMux * mux, + GstTagList * taglist); +static GstBuffer *gst_id3tag_render_v1_tag (GstTagMux * mux, + GstTagList * taglist); + +static void gst_id3tag_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_id3tag_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_id3tag_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details_simple (element_class, + "ID3 v1 and v2 Muxer", "Formatter/Metadata", + "Adds an ID3v2 header and ID3v1 footer to a file", + "Michael Smith , " + "Tim-Philipp Müller "); + + GST_DEBUG_CATEGORY_INIT (gst_id3tag_debug, "id3tag", 0, + "ID3 v1 and v2 tag muxer"); +} + +static void +gst_id3tag_class_init (GstID3TagClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->set_property = gst_id3tag_set_property; + gobject_class->get_property = gst_id3tag_get_property; + + g_object_class_install_property (gobject_class, ARG_WRITE_V1, + g_param_spec_boolean ("write-v1", "Write id3v1 tag", + "Write an id3v1 tag at the end of the file", DEFAULT_WRITE_V1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (gobject_class, ARG_WRITE_V2, + g_param_spec_boolean ("write-v2", "Write id3v2 tag", + "Write an id3v2 tag at the start of the file", DEFAULT_WRITE_V2, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (gobject_class, ARG_V2_MAJOR_VERSION, + g_param_spec_int ("v2-version", "Version (3 or 4) of id3v2 tag", + "Set version (3 for id3v2.3, 4 for id3v2.4) of id3v2 tags", + 3, 4, DEFAULT_V2_MAJOR_VERSION, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + GST_TAG_MUX_CLASS (klass)->render_start_tag = + GST_DEBUG_FUNCPTR (gst_id3tag_render_v2_tag); + + GST_TAG_MUX_CLASS (klass)->render_end_tag = gst_id3tag_render_v1_tag; +} + +static void +gst_id3tag_init (GstID3Tag * id3mux, GstID3TagClass * id3mux_class) +{ + id3mux->write_v1 = DEFAULT_WRITE_V1; + id3mux->write_v2 = DEFAULT_WRITE_V2; + + id3mux->v2_major_version = DEFAULT_V2_MAJOR_VERSION; +} + +static void +gst_id3tag_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstID3Tag *mux = GST_ID3TAG (object); + + switch (prop_id) { + case ARG_WRITE_V1: + mux->write_v1 = g_value_get_boolean (value); + break; + case ARG_WRITE_V2: + mux->write_v2 = g_value_get_boolean (value); + break; + case ARG_V2_MAJOR_VERSION: + mux->v2_major_version = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_id3tag_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstID3Tag *mux = GST_ID3TAG (object); + + switch (prop_id) { + case ARG_WRITE_V1: + g_value_set_boolean (value, mux->write_v1); + break; + case ARG_WRITE_V2: + g_value_set_boolean (value, mux->write_v2); + break; + case ARG_V2_MAJOR_VERSION: + g_value_set_int (value, mux->v2_major_version); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstBuffer * +gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) +{ + GstID3Tag *id3mux = GST_ID3TAG (mux); + + if (id3mux->write_v2) + return gst_id3mux_render_v2_tag (mux, taglist, id3mux->v2_major_version); + else + return NULL; +} + +static GstBuffer * +gst_id3tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist) +{ + GstID3Tag *id3mux = GST_ID3TAG (mux); + + if (id3mux->write_v1) + return gst_id3mux_render_v1_tag (mux, taglist); + else + return NULL; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "id3tag", GST_RANK_NONE, GST_TYPE_ID3TAG)) + return FALSE; + + gst_tag_register_musicbrainz_tags (); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "id3tag", + "ID3 v1 and v2 muxing plugin", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/gst/id3tag/gstid3tag.h b/gst/id3tag/gstid3tag.h new file mode 100644 index 00000000..6b33df25 --- /dev/null +++ b/gst/id3tag/gstid3tag.h @@ -0,0 +1,63 @@ +/* GStreamer ID3 v1 and v2 muxer + * + * Copyright (C) 2006 Christophe Fergeau + * Copyright (C) 2006 Tim-Philipp Müller + * Copyright (C) 2009 Pioneers of the Inevitable + * + * 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_ID3TAG_H +#define GST_ID3TAG_H + +#include "gsttagmux.h" +#include "id3tag.h" + +G_BEGIN_DECLS + +typedef struct _GstID3Tag GstID3Tag; +typedef struct _GstID3TagClass GstID3TagClass; + +struct _GstID3Tag { + GstTagMux tagmux; + + gboolean write_v1; + gboolean write_v2; + + gint v2_major_version; +}; + +struct _GstID3TagClass { + GstTagMuxClass tagmux_class; +}; + +#define GST_TYPE_ID3TAG \ + (gst_id3tag_get_type()) +#define GST_ID3TAG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3TAG,GstID3Tag)) +#define GST_ID3TAG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3TAG,GstID3TagClass)) +#define GST_IS_ID3TAG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3TAG)) +#define GST_IS_ID3TAG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3TAG)) + +GType gst_id3tag_get_type (void); + +G_END_DECLS + +#endif /* GST_ID3TAG_H */ + diff --git a/gst/id3tag/gsttagmux.c b/gst/id3tag/gsttagmux.c new file mode 100644 index 00000000..bfa4e1bc --- /dev/null +++ b/gst/id3tag/gsttagmux.c @@ -0,0 +1,490 @@ +/* GStreamer tag muxer base class + * + * Copyright (C) 2006 Christophe Fergeau + * Copyright (C) 2006 Tim-Philipp Müller + * Copyright (C) 2006 Sebastian Dröge + * Copyright (C) 2009 Pioneers of the Inevitable + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "gsttagmux.h" + +GST_DEBUG_CATEGORY_STATIC (gst_tag_mux_debug); +#define GST_CAT_DEFAULT gst_tag_mux_debug + +/* Subclass provides a src template and pad. We accept anything as input here, + however. */ + +static GstStaticPadTemplate gst_tag_mux_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("ANY")); + +static void +gst_tag_mux_iface_init (GType tag_type) +{ + static const GInterfaceInfo tag_setter_info = { + NULL, + NULL, + NULL + }; + + g_type_add_interface_static (tag_type, GST_TYPE_TAG_SETTER, &tag_setter_info); +} + +GST_BOILERPLATE_FULL (GstTagMux, gst_tag_mux, + GstElement, GST_TYPE_ELEMENT, gst_tag_mux_iface_init); + + +static GstStateChangeReturn +gst_tag_mux_change_state (GstElement * element, GstStateChange transition); +static GstFlowReturn gst_tag_mux_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_tag_mux_sink_event (GstPad * pad, GstEvent * event); + +static void +gst_tag_mux_finalize (GObject * obj) +{ + GstTagMux *mux = GST_TAG_MUX (obj); + + if (mux->newsegment_ev) { + gst_event_unref (mux->newsegment_ev); + mux->newsegment_ev = NULL; + } + + if (mux->event_tags) { + gst_tag_list_free (mux->event_tags); + mux->event_tags = NULL; + } + + if (mux->final_tags) { + gst_tag_list_free (mux->final_tags); + mux->final_tags = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static void +gst_tag_mux_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_tag_mux_sink_template)); + + GST_DEBUG_CATEGORY_INIT (gst_tag_mux_debug, "tagmux", 0, + "tag muxer base class"); +} + +static void +gst_tag_mux_class_init (GstTagMuxClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tag_mux_finalize); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_tag_mux_change_state); +} + +static void +gst_tag_mux_init (GstTagMux * mux, GstTagMuxClass * mux_class) +{ + GstElementClass *element_klass = GST_ELEMENT_CLASS (mux_class); + GstPadTemplate *tmpl; + + /* pad through which data comes in to the element */ + mux->sinkpad = + gst_pad_new_from_static_template (&gst_tag_mux_sink_template, "sink"); + gst_pad_set_chain_function (mux->sinkpad, + GST_DEBUG_FUNCPTR (gst_tag_mux_chain)); + gst_pad_set_event_function (mux->sinkpad, + GST_DEBUG_FUNCPTR (gst_tag_mux_sink_event)); + gst_element_add_pad (GST_ELEMENT (mux), mux->sinkpad); + + /* pad through which data goes out of the element */ + tmpl = gst_element_class_get_pad_template (element_klass, "src"); + if (tmpl) { + mux->srcpad = gst_pad_new_from_template (tmpl, "src"); + gst_pad_use_fixed_caps (mux->srcpad); + gst_pad_set_caps (mux->srcpad, gst_pad_template_get_caps (tmpl)); + gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad); + } + + mux->render_start_tag = TRUE; + mux->render_end_tag = TRUE; +} + +static GstTagList * +gst_tag_mux_get_tags (GstTagMux * mux) +{ + GstTagSetter *tagsetter = GST_TAG_SETTER (mux); + const GstTagList *tagsetter_tags; + GstTagMergeMode merge_mode; + + if (mux->final_tags) + return mux->final_tags; + + tagsetter_tags = gst_tag_setter_get_tag_list (tagsetter); + merge_mode = gst_tag_setter_get_tag_merge_mode (tagsetter); + + GST_LOG_OBJECT (mux, "merging tags, merge mode = %d", merge_mode); + GST_LOG_OBJECT (mux, "event tags: %" GST_PTR_FORMAT, mux->event_tags); + GST_LOG_OBJECT (mux, "set tags: %" GST_PTR_FORMAT, tagsetter_tags); + + mux->final_tags = + gst_tag_list_merge (tagsetter_tags, mux->event_tags, merge_mode); + + GST_LOG_OBJECT (mux, "final tags: %" GST_PTR_FORMAT, mux->final_tags); + + return mux->final_tags; +} + +static GstFlowReturn +gst_tag_mux_render_start_tag (GstTagMux * mux) +{ + GstTagMuxClass *klass; + GstBuffer *buffer; + GstTagList *taglist; + GstEvent *event; + GstFlowReturn ret; + + taglist = gst_tag_mux_get_tags (mux); + + klass = GST_TAG_MUX_CLASS (G_OBJECT_GET_CLASS (mux)); + + if (klass->render_start_tag == NULL) + goto no_vfunc; + + buffer = klass->render_start_tag (mux, taglist); + + /* Null buffer is ok, just means we're not outputting anything */ + if (buffer == NULL) { + GST_INFO_OBJECT (mux, "No start tag generated"); + mux->start_tag_size = 0; + return GST_FLOW_OK; + } + + mux->start_tag_size = GST_BUFFER_SIZE (buffer); + GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes", + mux->start_tag_size); + + /* Send newsegment event from byte position 0, so the tag really gets + * written to the start of the file, independent of the upstream segment */ + gst_pad_push_event (mux->srcpad, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)); + + /* Send an event about the new tags to downstream elements */ + /* gst_event_new_tag takes ownership of the list, so use a copy */ + event = gst_event_new_tag (gst_tag_list_copy (taglist)); + gst_pad_push_event (mux->srcpad, event); + + GST_BUFFER_OFFSET (buffer) = 0; + ret = gst_pad_push (mux->srcpad, buffer); + + mux->current_offset = mux->start_tag_size; + mux->max_offset = MAX (mux->max_offset, mux->current_offset); + + return ret; + +no_vfunc: + { + GST_ERROR_OBJECT (mux, "Subclass does not implement " + "render_start_tag vfunc!"); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_tag_mux_render_end_tag (GstTagMux * mux) +{ + GstTagMuxClass *klass; + GstBuffer *buffer; + GstTagList *taglist; + GstFlowReturn ret; + + taglist = gst_tag_mux_get_tags (mux); + + klass = GST_TAG_MUX_CLASS (G_OBJECT_GET_CLASS (mux)); + + if (klass->render_end_tag == NULL) + goto no_vfunc; + + buffer = klass->render_end_tag (mux, taglist); + + if (buffer == NULL) { + GST_INFO_OBJECT (mux, "No end tag generated"); + mux->end_tag_size = 0; + return GST_FLOW_OK; + } + + mux->end_tag_size = GST_BUFFER_SIZE (buffer); + GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes", + mux->end_tag_size); + + /* Send newsegment event from the end of the file, so it gets written there, + independent of whatever new segment events upstream has sent us */ + gst_pad_push_event (mux->srcpad, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, mux->max_offset, + -1, 0)); + + GST_BUFFER_OFFSET (buffer) = mux->max_offset; + ret = gst_pad_push (mux->srcpad, buffer); + + return ret; + +no_vfunc: + { + GST_ERROR_OBJECT (mux, "Subclass does not implement " + "render_end_tag vfunc!"); + return GST_FLOW_ERROR; + } +} + +static GstEvent * +gst_tag_mux_adjust_event_offsets (GstTagMux * mux, + const GstEvent * newsegment_event) +{ + GstFormat format; + gint64 start, stop, cur; + + gst_event_parse_new_segment ((GstEvent *) newsegment_event, NULL, NULL, + &format, &start, &stop, &cur); + + g_assert (format == GST_FORMAT_BYTES); + + if (start != -1) + start += mux->start_tag_size; + if (stop != -1) + stop += mux->start_tag_size; + if (cur != -1) + cur += mux->start_tag_size; + + GST_DEBUG_OBJECT (mux, "adjusting newsegment event offsets to start=%" + G_GINT64_FORMAT ", stop=%" G_GINT64_FORMAT ", cur=%" G_GINT64_FORMAT + " (delta = +%" G_GSIZE_FORMAT ")", start, stop, cur, mux->start_tag_size); + + return gst_event_new_new_segment (TRUE, 1.0, format, start, stop, cur); +} + +static GstFlowReturn +gst_tag_mux_chain (GstPad * pad, GstBuffer * buffer) +{ + GstTagMux *mux = GST_TAG_MUX (GST_OBJECT_PARENT (pad)); + GstFlowReturn ret; + int length; + + if (mux->render_start_tag) { + + GST_INFO_OBJECT (mux, "Adding tags to stream"); + ret = gst_tag_mux_render_start_tag (mux); + if (ret != GST_FLOW_OK) { + GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret)); + gst_buffer_unref (buffer); + return ret; + } + + /* Now send the cached newsegment event that we got from upstream */ + if (mux->newsegment_ev) { + gint64 start; + GstEvent *newseg; + + GST_DEBUG_OBJECT (mux, "sending cached newsegment event"); + newseg = gst_tag_mux_adjust_event_offsets (mux, mux->newsegment_ev); + gst_event_unref (mux->newsegment_ev); + mux->newsegment_ev = NULL; + + gst_event_parse_new_segment (newseg, NULL, NULL, NULL, &start, NULL, + NULL); + + gst_pad_push_event (mux->srcpad, newseg); + mux->current_offset = start; + mux->max_offset = MAX (mux->max_offset, mux->current_offset); + } else { + /* upstream sent no newsegment event or only one in a non-BYTE format */ + } + + mux->render_start_tag = FALSE; + } + + buffer = gst_buffer_make_metadata_writable (buffer); + + if (GST_BUFFER_OFFSET (buffer) != GST_BUFFER_OFFSET_NONE) { + GST_LOG_OBJECT (mux, "Adjusting buffer offset from %" G_GINT64_FORMAT + " to %" G_GINT64_FORMAT, GST_BUFFER_OFFSET (buffer), + GST_BUFFER_OFFSET (buffer) + mux->start_tag_size); + GST_BUFFER_OFFSET (buffer) += mux->start_tag_size; + } + + length = GST_BUFFER_SIZE (buffer); + + gst_buffer_set_caps (buffer, GST_PAD_CAPS (mux->srcpad)); + ret = gst_pad_push (mux->srcpad, buffer); + + mux->current_offset += length; + mux->max_offset = MAX (mux->max_offset, mux->current_offset); + + return ret; +} + +static gboolean +gst_tag_mux_sink_event (GstPad * pad, GstEvent * event) +{ + GstTagMux *mux; + gboolean result; + + mux = GST_TAG_MUX (gst_pad_get_parent (pad)); + result = FALSE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG:{ + GstTagList *tags; + + gst_event_parse_tag (event, &tags); + + GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags); + + if (mux->event_tags != NULL) { + gst_tag_list_insert (mux->event_tags, tags, GST_TAG_MERGE_REPLACE); + } else { + mux->event_tags = gst_tag_list_copy (tags); + } + + GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT, + mux->event_tags); + + /* just drop the event, we'll push a new tag event in render_start_tag */ + gst_event_unref (event); + result = TRUE; + break; + } + case GST_EVENT_NEWSEGMENT:{ + GstFormat fmt; + gint64 start; + + gst_event_parse_new_segment (event, NULL, NULL, &fmt, &start, NULL, NULL); + + if (fmt != GST_FORMAT_BYTES) { + GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format", + gst_format_get_name (fmt)); + gst_event_unref (event); + break; + } + + if (mux->render_start_tag) { + /* we have not rendered the tag yet, which means that we don't know + * how large it is going to be yet, so we can't adjust the offsets + * here at this point and need to cache the newsegment event for now + * (also, there could be tag events coming after this newsegment event + * and before the first buffer). */ + if (mux->newsegment_ev) { + GST_WARNING_OBJECT (mux, "discarding old cached newsegment event"); + gst_event_unref (mux->newsegment_ev); + } + + GST_LOG_OBJECT (mux, "caching newsegment event for later"); + mux->newsegment_ev = event; + } else { + GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets"); + gst_pad_push_event (mux->srcpad, + gst_tag_mux_adjust_event_offsets (mux, event)); + gst_event_unref (event); + + mux->current_offset = start; + mux->max_offset = MAX (mux->max_offset, mux->current_offset); + } + event = NULL; + result = TRUE; + break; + } + case GST_EVENT_EOS:{ + if (mux->render_end_tag) { + GstFlowReturn ret; + + GST_INFO_OBJECT (mux, "Adding tags to stream"); + ret = gst_tag_mux_render_end_tag (mux); + if (ret != GST_FLOW_OK) { + GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret)); + return ret; + } + + mux->render_end_tag = FALSE; + } + + /* Now forward EOS */ + result = gst_pad_event_default (pad, event); + break; + } + default: + result = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (mux); + + return result; +} + + +static GstStateChangeReturn +gst_tag_mux_change_state (GstElement * element, GstStateChange transition) +{ + GstTagMux *mux; + GstStateChangeReturn result; + + mux = GST_TAG_MUX (element); + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (result != GST_STATE_CHANGE_SUCCESS) { + return result; + } + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY:{ + if (mux->newsegment_ev) { + gst_event_unref (mux->newsegment_ev); + mux->newsegment_ev = NULL; + } + if (mux->event_tags) { + gst_tag_list_free (mux->event_tags); + mux->event_tags = NULL; + } + mux->start_tag_size = 0; + mux->end_tag_size = 0; + mux->render_start_tag = TRUE; + mux->render_end_tag = TRUE; + mux->current_offset = 0; + mux->max_offset = 0; + break; + } + default: + break; + } + + return result; +} diff --git a/gst/id3tag/gsttagmux.h b/gst/id3tag/gsttagmux.h new file mode 100644 index 00000000..c13a7326 --- /dev/null +++ b/gst/id3tag/gsttagmux.h @@ -0,0 +1,79 @@ +/* GStreamer tag muxer base class + * + * Copyright (C) 2006 Christophe Fergeau + * Copyright (C) 2006 Tim-Philipp Müller + * Copyright (C) 2009 Pioneers of the Inevitable + * + * 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_TAG_MUX_H +#define GST_TAG_MUX_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstTagMux GstTagMux; +typedef struct _GstTagMuxClass GstTagMuxClass; + +/* Definition of structure storing data for this element. */ +struct _GstTagMux { + GstElement element; + + GstPad *srcpad; + GstPad *sinkpad; + GstTagList *event_tags; /* tags received from upstream elements */ + GstTagList *final_tags; /* Final set of tags used for muxing */ + gsize start_tag_size; + gsize end_tag_size; + gboolean render_start_tag; + gboolean render_end_tag; + + gint64 current_offset; + gint64 max_offset; + + GstEvent *newsegment_ev; /* cached newsegment event from upstream */ +}; + +/* Standard definition defining a class for this element. */ +struct _GstTagMuxClass { + GstElementClass parent_class; + + /* vfuncs */ + GstBuffer * (*render_start_tag) (GstTagMux * mux, GstTagList * tag_list); + GstBuffer * (*render_end_tag) (GstTagMux * mux, GstTagList * tag_list); +}; + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_TAG_MUX \ + (gst_tag_mux_get_type()) +#define GST_TAG_MUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAG_MUX,GstTagMux)) +#define GST_TAG_MUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAG_MUX,GstTagMuxClass)) +#define GST_IS_TAG_MUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAG_MUX)) +#define GST_IS_TAG_MUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAG_MUX)) + +/* Standard function returning type information. */ +GType gst_tag_mux_get_type (void); + +G_END_DECLS + +#endif + diff --git a/gst/id3tag/id3tag.c b/gst/id3tag/id3tag.c new file mode 100644 index 00000000..0e040f7e --- /dev/null +++ b/gst/id3tag/id3tag.c @@ -0,0 +1,1194 @@ +/* GStreamer ID3v2 tag writer + * + * Copyright (C) 2006 Christophe Fergeau + * Copyright (C) 2006-2009 Tim-Philipp Müller + * Copyright (C) 2009 Pioneers of the Inevitable + * + * 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. + */ + +#include "id3tag.h" +#include + +#include + +GST_DEBUG_CATEGORY_EXTERN (gst_id3tag_debug); +#define GST_CAT_DEFAULT gst_id3tag_debug + +#define ID3V2_APIC_PICTURE_OTHER 0 +#define ID3V2_APIC_PICTURE_FILE_ICON 1 + +/* ======================================================================== */ + +typedef GString GstByteWriter; + +static inline GstByteWriter * +gst_byte_writer_new (guint size) +{ + return (GstByteWriter *) g_string_sized_new (size); +} + +static inline guint +gst_byte_writer_get_length (GstByteWriter * w) +{ + return ((GString *) w)->len; +} + +static inline void +gst_byte_writer_write_bytes (GstByteWriter * w, const guint8 * data, guint len) +{ + g_string_append_len ((GString *) w, (const gchar *) data, len); +} + +static inline void +gst_byte_writer_write_uint8 (GstByteWriter * w, guint8 val) +{ + guint8 data[1]; + + GST_WRITE_UINT8 (data, val); + gst_byte_writer_write_bytes (w, data, 1); +} + +static inline void +gst_byte_writer_write_uint16 (GstByteWriter * w, guint16 val) +{ + guint8 data[2]; + + GST_WRITE_UINT16_BE (data, val); + gst_byte_writer_write_bytes (w, data, 2); +} + +static inline void +gst_byte_writer_write_uint32 (GstByteWriter * w, guint32 val) +{ + guint8 data[4]; + + GST_WRITE_UINT32_BE (data, val); + gst_byte_writer_write_bytes (w, data, 4); +} + +static inline void +gst_byte_writer_write_uint32_syncsafe (GstByteWriter * w, guint32 val) +{ + guint8 data[4]; + + data[0] = (guint8) ((val >> 21) & 0x7f); + data[1] = (guint8) ((val >> 14) & 0x7f); + data[2] = (guint8) ((val >> 7) & 0x7f); + data[3] = (guint8) ((val >> 0) & 0x7f); + gst_byte_writer_write_bytes (w, data, 4); +} + +static void +gst_byte_writer_copy_bytes (GstByteWriter * w, guint8 * dest, guint offset, + gint size) +{ + guint length; + + length = gst_byte_writer_get_length (w); + + if (size == -1) + size = length - offset; + +#if GLIB_CHECK_VERSION(2,16,0) + g_warn_if_fail (length >= (offset + size)); +#endif + + memcpy (dest, w->str + offset, MIN (size, length - offset)); +} + +static inline void +gst_byte_writer_free (GstByteWriter * w) +{ + g_string_free (w, TRUE); +} + +/* ======================================================================== */ + +/* +typedef enum { + GST_ID3V2_FRAME_FLAG_NONE = 0, + GST_ID3V2_FRAME_FLAG_ +} GstID3v2FrameMsgFlags; +*/ + +typedef struct +{ + gchar id[5]; + guint32 len; /* Length encoded in the header; this is the + total length - header size */ + guint16 flags; + GstByteWriter *writer; + gboolean dirty; /* TRUE if frame header needs updating */ +} GstId3v2Frame; + +typedef struct +{ + GArray *frames; + guint major_version; /* The 3 in v2.3.0 */ +} GstId3v2Tag; + +typedef void (*GstId3v2AddTagFunc) (GstId3v2Tag * tag, const GstTagList * list, + const gchar * gst_tag, guint num_tags, const gchar * data); + +#define ID3V2_ENCODING_UTF8 0x03 + +static gboolean id3v2_tag_init (GstId3v2Tag * tag, guint major_version); +static void id3v2_tag_unset (GstId3v2Tag * tag); + +static void id3v2_frame_init (GstId3v2Frame * frame, + const gchar * frame_id, guint16 flags); +static void id3v2_frame_unset (GstId3v2Frame * frame); +static void id3v2_frame_finish (GstId3v2Tag * tag, GstId3v2Frame * frame); +static guint id3v2_frame_get_size (GstId3v2Tag * tag, GstId3v2Frame * frame); + +static void id3v2_tag_add_text_frame (GstId3v2Tag * tag, + const gchar * frame_id, gchar ** strings, int num_strings); + +static gboolean +id3v2_tag_init (GstId3v2Tag * tag, guint major_version) +{ + if (major_version != 3 && major_version != 4) + return FALSE; + + tag->major_version = major_version; + tag->frames = g_array_new (TRUE, TRUE, sizeof (GstId3v2Frame)); + + return TRUE; +} + +static void +id3v2_tag_unset (GstId3v2Tag * tag) +{ + guint i; + + for (i = 0; i < tag->frames->len; ++i) + id3v2_frame_unset (&g_array_index (tag->frames, GstId3v2Frame, i)); + + g_array_free (tag->frames, TRUE); + memset (tag, 0, sizeof (GstId3v2Tag)); +} + +#ifndef GST_ROUND_UP_1024 +#define GST_ROUND_UP_1024(num) (((num)+1023)&~1023) +#endif + +static GstBuffer * +id3v2_tag_to_buffer (GstId3v2Tag * tag) +{ + GstByteWriter *w; + GstBuffer *buf; + guint8 *dest; + guint i, size, offset, size_frames = 0; + + GST_DEBUG ("Creating buffer for ID3v2 tag containing %d frames", + tag->frames->len); + + for (i = 0; i < tag->frames->len; ++i) { + GstId3v2Frame *frame = &g_array_index (tag->frames, GstId3v2Frame, i); + + id3v2_frame_finish (tag, frame); + size_frames += id3v2_frame_get_size (tag, frame); + } + + size = GST_ROUND_UP_1024 (10 + size_frames); + + w = gst_byte_writer_new (10); + gst_byte_writer_write_uint8 (w, 'I'); + gst_byte_writer_write_uint8 (w, 'D'); + gst_byte_writer_write_uint8 (w, '3'); + gst_byte_writer_write_uint8 (w, tag->major_version); + gst_byte_writer_write_uint8 (w, 0); /* micro version */ + gst_byte_writer_write_uint8 (w, 0); /* flags */ + gst_byte_writer_write_uint32_syncsafe (w, size - 10); + + buf = gst_buffer_new_and_alloc (size); + dest = GST_BUFFER_DATA (buf); + gst_byte_writer_copy_bytes (w, dest, 0, 10); + offset = 10; + + for (i = 0; i < tag->frames->len; ++i) { + GstId3v2Frame *frame = &g_array_index (tag->frames, GstId3v2Frame, i); + + gst_byte_writer_copy_bytes (frame->writer, dest + offset, 0, -1); + offset += id3v2_frame_get_size (tag, frame); + } + + /* Zero out any additional space in our buffer as padding. */ + memset (dest + offset, 0, size - offset); + + gst_byte_writer_free (w); + + return buf; +} + +static inline void +id3v2_frame_write_bytes (GstId3v2Frame * frame, const guint8 * data, guint len) +{ + gst_byte_writer_write_bytes (frame->writer, data, len); + frame->dirty = TRUE; +} + +static inline void +id3v2_frame_write_uint8 (GstId3v2Frame * frame, guint8 val) +{ + gst_byte_writer_write_uint8 (frame->writer, val); + frame->dirty = TRUE; +} + +static inline void +id3v2_frame_write_uint16 (GstId3v2Frame * frame, guint16 val) +{ + gst_byte_writer_write_uint16 (frame->writer, val); + frame->dirty = TRUE; +} + +static inline void +id3v2_frame_write_uint32 (GstId3v2Frame * frame, guint32 val) +{ + gst_byte_writer_write_uint32 (frame->writer, val); + frame->dirty = TRUE; +} + +static inline void +id3v2_frame_write_uint32_syncsafe (GstId3v2Frame * frame, guint32 val) +{ + guint8 data[4]; + + data[0] = (guint8) ((val >> 21) & 0x7f); + data[1] = (guint8) ((val >> 14) & 0x7f); + data[2] = (guint8) ((val >> 7) & 0x7f); + data[3] = (guint8) ((val >> 0) & 0x7f); + gst_byte_writer_write_bytes (frame->writer, data, 4); + frame->dirty = TRUE; +} + +static void +id3v2_frame_init (GstId3v2Frame * frame, const gchar * frame_id, guint16 flags) +{ + g_assert (strlen (frame_id) == 4); /* we only handle 2.3.0/2.4.0 */ + memcpy (frame->id, frame_id, 4 + 1); + frame->flags = flags; + frame->len = 0; + frame->writer = gst_byte_writer_new (64); + id3v2_frame_write_bytes (frame, (const guint8 *) frame->id, 4); + id3v2_frame_write_uint32 (frame, 0); /* size, set later */ + id3v2_frame_write_uint16 (frame, frame->flags); +} + +static void +id3v2_frame_finish (GstId3v2Tag * tag, GstId3v2Frame * frame) +{ + if (frame->dirty) { + frame->len = frame->writer->len - 10; + GST_LOG ("[%s] %u bytes", frame->id, frame->len); + if (tag->major_version == 3) { + GST_WRITE_UINT32_BE (frame->writer->str + 4, frame->len); + } else { + /* Version 4 uses a syncsafe int here */ + GST_WRITE_UINT8 (frame->writer->str + 4, (frame->len >> 21) & 0x7f); + GST_WRITE_UINT8 (frame->writer->str + 5, (frame->len >> 14) & 0x7f); + GST_WRITE_UINT8 (frame->writer->str + 6, (frame->len >> 7) & 0x7f); + GST_WRITE_UINT8 (frame->writer->str + 7, (frame->len >> 0) & 0x7f); + } + frame->dirty = FALSE; + } +} + +static guint +id3v2_frame_get_size (GstId3v2Tag * tag, GstId3v2Frame * frame) +{ + id3v2_frame_finish (tag, frame); + return gst_byte_writer_get_length (frame->writer); +} + +static void +id3v2_frame_unset (GstId3v2Frame * frame) +{ + gst_byte_writer_free (frame->writer); + memset (frame, 0, sizeof (GstId3v2Frame)); +} + +static void +id3v2_tag_add_text_frame (GstId3v2Tag * tag, const gchar * frame_id, + gchar ** strings_utf8, int num_strings) +{ + GstId3v2Frame frame; + guint len, i; + + if (num_strings < 1 || strings_utf8 == NULL || strings_utf8[0] == NULL) { + GST_LOG ("Not adding text frame, no strings"); + return; + } + + id3v2_frame_init (&frame, frame_id, 0); + id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8); + + GST_LOG ("Adding text frame %s with %d strings", frame_id, num_strings); + + for (i = 0; i < num_strings; ++i) { + len = strlen (strings_utf8[i]); + g_return_if_fail (g_utf8_validate (strings_utf8[i], len, NULL)); + + /* write NUL terminator as well */ + id3v2_frame_write_bytes (&frame, (const guint8 *) strings_utf8[i], len + 1); + + /* only v2.4.0 supports multiple strings per frame (according to the + * earlier specs tag readers should just ignore everything after the first + * string, but we probably shouldn't write anything there, just in case + * tag readers that only support the old version are not expecting + * more data after the first string) */ + if (tag->major_version < 4) + break; + } + + if (i < num_strings - 1) { + GST_WARNING ("Only wrote one of multiple string values for text frame %s " + "- ID3v2 supports multiple string values only since v2.4.0, but writing" + "v2.%u.0 tag", frame_id, tag->major_version); + } + + g_array_append_val (tag->frames, frame); +} + +/* ====================================================================== */ + +static void +add_text_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * frame_id) +{ + gchar **strings; + guint n, i; + + GST_LOG ("Adding '%s' frame", frame_id); + + strings = g_new0 (gchar *, num_tags + 1); + for (n = 0, i = 0; n < num_tags; ++n) { + if (gst_tag_list_get_string_index (list, tag, n, &strings[i]) && + strings[i] != NULL) { + GST_LOG ("%s: %s[%u] = '%s'", frame_id, tag, i, strings[i]); + ++i; + } + } + + if (strings[0] != NULL) { + id3v2_tag_add_text_frame (id3v2tag, frame_id, strings, i); + } else { + GST_WARNING ("Empty list for tag %s, skipping", tag); + } + + g_strfreev (strings); +} + +static void +add_id3v2frame_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + guint i; + + for (i = 0; i < num_tags; ++i) { + const GValue *val; + GstBuffer *buf; + + val = gst_tag_list_get_value_index (list, tag, i); + buf = (GstBuffer *) gst_value_get_mini_object (val); + + if (buf && GST_BUFFER_CAPS (buf)) { + GstStructure *s; + gint version = 0; + + s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0); + /* We can only add it if this private buffer is for the same ID3 version, + because we don't understand the contents at all. */ + if (s && gst_structure_get_int (s, "version", &version) && + version == id3v2tag->major_version) { + GstId3v2Frame frame; + gchar frame_id[5]; + guint16 flags; + guint8 *data = GST_BUFFER_DATA (buf); + gint size = GST_BUFFER_SIZE (buf); + + if (size < 10) /* header size */ + return; + + /* We only reach here if the frame version matches the muxer. Since the + muxer only does v2.3 or v2.4, the frame must be one of those - and + so the frame header is the same format */ + memcpy (frame_id, data, 4); + frame_id[4] = 0; + flags = GST_READ_UINT16_BE (data + 8); + + id3v2_frame_init (&frame, frame_id, flags); + id3v2_frame_write_bytes (&frame, data + 10, size - 10); + + g_array_append_val (id3v2tag->frames, frame); + GST_DEBUG ("Added unparsed tag with %d bytes", size); + } else { + GST_WARNING ("Discarding unrecognised ID3 tag for different ID3 " + "version"); + } + } + } +} + +static void +add_text_tag_v4 (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * frame_id) +{ + if (id3v2tag->major_version == 4) + add_text_tag (id3v2tag, list, tag, num_tags, frame_id); + else { + GST_WARNING ("Cannot serialise tag '%s' in ID3v2.%d", frame_id, + id3v2tag->major_version); + } +} + +static void +add_count_or_num_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * frame_id) +{ + static const struct + { + const gchar *gst_tag; + const gchar *corr_count; /* corresponding COUNT tag (if number) */ + const gchar *corr_num; /* corresponding NUMBER tag (if count) */ + } corr[] = { + { + GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, NULL}, { + GST_TAG_TRACK_COUNT, NULL, GST_TAG_TRACK_NUMBER}, { + GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, NULL}, { + GST_TAG_ALBUM_VOLUME_COUNT, NULL, GST_TAG_ALBUM_VOLUME_NUMBER} + }; + guint idx; + + for (idx = 0; idx < G_N_ELEMENTS (corr); ++idx) { + if (strcmp (corr[idx].gst_tag, tag) == 0) + break; + } + + g_assert (idx < G_N_ELEMENTS (corr)); + g_assert (frame_id && strlen (frame_id) == 4); + + if (corr[idx].corr_num == NULL) { + guint number; + + /* number tag */ + if (gst_tag_list_get_uint_index (list, tag, 0, &number)) { + gchar *tag_str; + guint count; + + if (gst_tag_list_get_uint_index (list, corr[idx].corr_count, 0, &count)) + tag_str = g_strdup_printf ("%u/%u", number, count); + else + tag_str = g_strdup_printf ("%u", number); + + GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id); + + id3v2_tag_add_text_frame (id3v2tag, frame_id, &tag_str, 1); + g_free (tag_str); + } + } else if (corr[idx].corr_count == NULL) { + guint count; + + /* count tag */ + if (gst_tag_list_get_uint_index (list, corr[idx].corr_num, 0, &count)) { + GST_DEBUG ("%s handled with %s, skipping", tag, corr[idx].corr_num); + } else if (gst_tag_list_get_uint_index (list, tag, 0, &count)) { + gchar *tag_str = g_strdup_printf ("0/%u", count); + GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id); + + id3v2_tag_add_text_frame (id3v2tag, frame_id, &tag_str, 1); + g_free (tag_str); + } + } + + if (num_tags > 1) { + GST_WARNING ("more than one %s, can only handle one", tag); + } +} + +static void +add_comment_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + guint n; + + GST_LOG ("Adding comment frames"); + for (n = 0; n < num_tags; ++n) { + gchar *s = NULL; + + if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) { + gchar *desc = NULL, *val = NULL, *lang = NULL; + int desclen, vallen; + GstId3v2Frame frame; + + id3v2_frame_init (&frame, "COMM", 0); + id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8); + + if (strcmp (tag, GST_TAG_COMMENT) == 0 || + !gst_tag_parse_extended_comment (s, &desc, &lang, &val, TRUE)) { + /* create dummy description fields */ + desc = g_strdup ("Comment"); + val = g_strdup (s); + } + + /* If we don't have a valid language, match what taglib does for + unknown languages */ + if (!lang || strlen (lang) < 3) + lang = g_strdup ("XXX"); + + desclen = strlen (desc); + g_return_if_fail (g_utf8_validate (desc, desclen, NULL)); + vallen = strlen (val); + g_return_if_fail (g_utf8_validate (val, vallen, NULL)); + + GST_LOG ("%s[%u] = '%s' (%s|%s|%s)", tag, n, s, GST_STR_NULL (desc), + GST_STR_NULL (lang), GST_STR_NULL (val)); + + id3v2_frame_write_bytes (&frame, (const guint8 *) lang, 3); + /* write description and value, each including NULL terminator */ + id3v2_frame_write_bytes (&frame, (const guint8 *) desc, desclen + 1); + id3v2_frame_write_bytes (&frame, (const guint8 *) val, vallen + 1); + + g_free (lang); + g_free (desc); + g_free (val); + + g_array_append_val (id3v2tag->frames, frame); + } + g_free (s); + } +} + +static void +add_image_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + guint n; + + for (n = 0; n < num_tags; ++n) { + const GValue *val; + GstBuffer *image; + + GST_DEBUG ("image %u/%u", n + 1, num_tags); + + val = gst_tag_list_get_value_index (list, tag, n); + image = (GstBuffer *) gst_value_get_mini_object (val); + + if (GST_IS_BUFFER (image) && GST_BUFFER_SIZE (image) > 0 && + GST_BUFFER_CAPS (image) != NULL && + !gst_caps_is_empty (GST_BUFFER_CAPS (image))) { + const gchar *mime_type; + GstStructure *s; + + s = gst_caps_get_structure (GST_BUFFER_CAPS (image), 0); + mime_type = gst_structure_get_name (s); + if (mime_type != NULL) { + const gchar *desc; + GstId3v2Frame frame; + + /* APIC frame specifies "-->" if we're providing a URL to the image + rather than directly embedding it */ + if (strcmp (mime_type, "text/uri-list") == 0) + mime_type = "-->"; + + GST_DEBUG ("Attaching picture of %u bytes and mime type %s", + GST_BUFFER_SIZE (image), mime_type); + + id3v2_frame_init (&frame, "APIC", 0); + id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8); + id3v2_frame_write_bytes (&frame, (const guint8 *) mime_type, + strlen (mime_type) + 1); + + /* FIXME set image type properly from caps */ + if (strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0) + id3v2_frame_write_uint8 (&frame, ID3V2_APIC_PICTURE_FILE_ICON); + else + id3v2_frame_write_uint8 (&frame, ID3V2_APIC_PICTURE_OTHER); + + desc = gst_structure_get_string (s, "image-description"); + if (!desc) + desc = ""; + id3v2_frame_write_bytes (&frame, (const guint8 *) desc, + strlen (desc) + 1); + + g_array_append_val (id3v2tag->frames, frame); + } + } else { + GST_WARNING ("NULL image or no caps on image buffer (%p, caps=%" + GST_PTR_FORMAT ")", image, (image) ? GST_BUFFER_CAPS (image) : NULL); + } + } +} + +static void +add_musicbrainz_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * data) +{ + static const struct + { + const gchar gst_tag[28]; + const gchar spec_id[28]; + const gchar realworld_id[28]; + } mb_ids[] = { + { + GST_TAG_MUSICBRAINZ_ARTISTID, "MusicBrainz Artist Id", + "musicbrainz_artistid"}, { + GST_TAG_MUSICBRAINZ_ALBUMID, "MusicBrainz Album Id", "musicbrainz_albumid"}, { + GST_TAG_MUSICBRAINZ_ALBUMARTISTID, "MusicBrainz Album Artist Id", + "musicbrainz_albumartistid"}, { + GST_TAG_MUSICBRAINZ_TRMID, "MusicBrainz TRM Id", "musicbrainz_trmid"}, { + GST_TAG_CDDA_MUSICBRAINZ_DISCID, "MusicBrainz DiscID", + "musicbrainz_discid"}, { + /* the following one is more or less made up, there seems to be little + * evidence that any popular application is actually putting this info + * into TXXX frames; the first one comes from a musicbrainz wiki 'proposed + * tags' page, the second one is analogue to the vorbis/ape/flac tag. */ + GST_TAG_CDDA_CDDB_DISCID, "CDDB DiscID", "discid"} + }; + guint i, idx; + + idx = (guint8) data[0]; + g_assert (idx < G_N_ELEMENTS (mb_ids)); + + for (i = 0; i < num_tags; ++i) { + gchar *id_str; + + if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) { + /* add two frames, one with the ID the musicbrainz.org spec mentions + * and one with the ID that applications use in the real world */ + GstId3v2Frame frame1, frame2; + + GST_DEBUG ("Setting '%s' to '%s'", mb_ids[idx].spec_id, id_str); + + id3v2_frame_init (&frame1, "TXXX", 0); + id3v2_frame_write_uint8 (&frame1, ID3V2_ENCODING_UTF8); + id3v2_frame_write_bytes (&frame1, (const guint8 *) mb_ids[idx].spec_id, + strlen (mb_ids[idx].spec_id) + 1); + id3v2_frame_write_bytes (&frame1, (const guint8 *) id_str, + strlen (id_str) + 1); + g_array_append_val (id3v2tag->frames, frame1); + + id3v2_frame_init (&frame2, "TXXX", 0); + id3v2_frame_write_uint8 (&frame2, ID3V2_ENCODING_UTF8); + id3v2_frame_write_bytes (&frame2, + (const guint8 *) mb_ids[idx].realworld_id, + strlen (mb_ids[idx].realworld_id) + 1); + id3v2_frame_write_bytes (&frame2, (const guint8 *) id_str, + strlen (id_str) + 1); + g_array_append_val (id3v2tag->frames, frame2); + + g_free (id_str); + } + } +} + +static void +add_unique_file_id_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + const gchar *origin = "http://musicbrainz.org"; + gchar *id_str = NULL; + + if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) { + GstId3v2Frame frame; + + GST_LOG ("Adding %s (%s): %s", tag, origin, id_str); + + id3v2_frame_init (&frame, "UFID", 0); + id3v2_frame_write_bytes (&frame, (const guint8 *) origin, + strlen (origin) + 1); + id3v2_frame_write_bytes (&frame, (const guint8 *) id_str, + strlen (id_str) + 1); + g_array_append_val (id3v2tag->frames, frame); + + g_free (id_str); + } +} + +static void +add_date_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + guint n; + guint i = 0; + const gchar *frame_id; + gchar **strings; + + if (id3v2tag->major_version == 3) + frame_id = "TYER"; + else + frame_id = "TDRC"; + + GST_LOG ("Adding date frame"); + + strings = g_new0 (gchar *, num_tags + 1); + for (n = 0; n < num_tags; ++n) { + GDate *date = NULL; + + if (gst_tag_list_get_date_index (list, tag, n, &date) && date != NULL) { + GDateYear year; + gchar *s; + + year = g_date_get_year (date); + if (year > 500 && year < 2100) { + s = g_strdup_printf ("%u", year); + GST_LOG ("%s[%u] = '%s'", tag, n, s); + strings[i] = s; + i++; + } else { + GST_WARNING ("invalid year %u, skipping", year); + } + + g_date_free (date); + } + } + + if (strings[0] != NULL) { + id3v2_tag_add_text_frame (id3v2tag, frame_id, strings, i); + } else { + GST_WARNING ("Empty list for tag %s, skipping", tag); + } + + g_strfreev (strings); +} + +static void +add_encoder_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + guint n; + gchar **strings; + int i = 0; + + /* ENCODER_VERSION is either handled with the ENCODER tag or not at all */ + if (strcmp (tag, GST_TAG_ENCODER_VERSION) == 0) + return; + + strings = g_new0 (gchar *, num_tags + 1); + for (n = 0; n < num_tags; ++n) { + gchar *encoder = NULL; + + if (gst_tag_list_get_string_index (list, tag, n, &encoder) && encoder) { + guint encoder_version; + gchar *s; + + if (gst_tag_list_get_uint_index (list, GST_TAG_ENCODER_VERSION, n, + &encoder_version) && encoder_version > 0) { + s = g_strdup_printf ("%s %u", encoder, encoder_version); + } else { + s = g_strdup (encoder); + } + + GST_LOG ("encoder[%u] = '%s'", n, s); + strings[i] = s; + i++; + g_free (encoder); + } + } + + if (strings[0] != NULL) { + id3v2_tag_add_text_frame (id3v2tag, "TSSE", strings, i); + } else { + GST_WARNING ("Empty list for tag %s, skipping", tag); + } + + g_strfreev (strings); +} + +static void +add_uri_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * frame_id) +{ + gchar *url = NULL; + + g_assert (frame_id != NULL); + + /* URI tags are limited to one of each per taglist */ + if (gst_tag_list_get_string_index (list, tag, 0, &url) && url != NULL) { + guint url_len; + + url_len = strlen (url); + if (url_len > 0 && gst_uri_is_valid (url)) { + GstId3v2Frame frame; + + id3v2_frame_init (&frame, frame_id, 0); + id3v2_frame_write_bytes (&frame, (const guint8 *) url, strlen (url) + 1); + g_array_append_val (id3v2tag->frames, frame); + } else { + GST_WARNING ("Tag %s does not contain a valid URI (%s)", tag, url); + } + + g_free (url); + } +} + +static void +add_relative_volume_tag (GstId3v2Tag * id3v2tag, const GstTagList * list, + const gchar * tag, guint num_tags, const gchar * unused) +{ + const char *gain_tag_name; + const char *peak_tag_name; + gdouble peak_val; + gdouble gain_val; + const char *identification; + guint16 peak_int; + gint16 gain_int; + guint8 peak_bits; + GstId3v2Frame frame; + gchar *frame_id; + + /* figure out tag names and the identification string to use */ + if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 || + strcmp (tag, GST_TAG_TRACK_GAIN) == 0) { + gain_tag_name = GST_TAG_TRACK_GAIN; + peak_tag_name = GST_TAG_TRACK_PEAK; + identification = "track"; + GST_DEBUG ("adding track relative-volume frame"); + } else { + gain_tag_name = GST_TAG_ALBUM_GAIN; + peak_tag_name = GST_TAG_ALBUM_PEAK; + identification = "album"; + + if (id3v2tag->major_version == 3) { + GST_WARNING ("Cannot store replaygain album gain data in ID3v2.3"); + return; + } + GST_DEBUG ("adding album relative-volume frame"); + } + + /* find the value for the paired tag (gain, if this is peak, and + * vice versa). if both tags exist, only write the frame when + * we're processing the peak tag. + */ + if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 || + strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) { + + gst_tag_list_get_double (list, tag, &peak_val); + + if (gst_tag_list_get_tag_size (list, gain_tag_name) > 0) { + gst_tag_list_get_double (list, gain_tag_name, &gain_val); + GST_DEBUG ("setting volume adjustment %g", gain_val); + gain_int = (gint16) (gain_val * 512.0); + } else + gain_int = 0; + + /* copying mutagen: always write as 16 bits for sanity. */ + peak_int = (short) (peak_val * G_MAXSHORT); + peak_bits = 16; + } else { + gst_tag_list_get_double (list, tag, &gain_val); + GST_DEBUG ("setting volume adjustment %g", gain_val); + + gain_int = (gint16) (gain_val * 512.0); + peak_bits = 0; + peak_int = 0; + + if (gst_tag_list_get_tag_size (list, peak_tag_name) != 0) { + GST_DEBUG + ("both gain and peak tags exist, not adding frame this time around"); + return; + } + } + + if (id3v2tag->major_version == 4) { + /* 2.4: Use RVA2 tag */ + frame_id = "RVA2"; + } else { + /* 2.3: Use XRVA tag - this is experimental, but useful in the real world. + This version only officially supports the 'RVAD' tag, but that appears + to not be widely implemented in reality. */ + frame_id = "XRVA"; + } + + id3v2_frame_init (&frame, frame_id, 0); + id3v2_frame_write_bytes (&frame, (const guint8 *) identification, + strlen (identification) + 1); + id3v2_frame_write_uint8 (&frame, 0x01); /* Master volume */ + id3v2_frame_write_uint16 (&frame, gain_int); + id3v2_frame_write_uint8 (&frame, peak_bits); + if (peak_bits) + id3v2_frame_write_uint16 (&frame, peak_int); + + g_array_append_val (id3v2tag->frames, frame); +} + +/* id3demux produces these for frames it cannot parse */ +#define GST_ID3_DEMUX_TAG_ID3V2_FRAME "private-id3v2-frame" + +static const struct +{ + const gchar *gst_tag; + const GstId3v2AddTagFunc func; + const gchar *data; +} add_funcs[] = { + { + /* Simple text tags */ + GST_TAG_ARTIST, add_text_tag, "TPE1"}, { + GST_TAG_TITLE, add_text_tag, "TIT2"}, { + GST_TAG_ALBUM, add_text_tag, "TALB"}, { + GST_TAG_COPYRIGHT, add_text_tag, "TCOP"}, { + GST_TAG_COMPOSER, add_text_tag, "TCOM"}, { + GST_TAG_GENRE, add_text_tag, "TCON"}, { + + /* Private frames */ + GST_ID3_DEMUX_TAG_ID3V2_FRAME, add_id3v2frame_tag, NULL}, { + + /* Track and album numbers */ + GST_TAG_TRACK_NUMBER, add_count_or_num_tag, "TRCK"}, { + GST_TAG_TRACK_COUNT, add_count_or_num_tag, "TRCK"}, { + GST_TAG_ALBUM_VOLUME_NUMBER, add_count_or_num_tag, "TPOS"}, { + GST_TAG_ALBUM_VOLUME_COUNT, add_count_or_num_tag, "TPOS"}, { + + /* Comment tags */ + GST_TAG_COMMENT, add_comment_tag, NULL}, { + GST_TAG_EXTENDED_COMMENT, add_comment_tag, NULL}, { + + /* Images */ + GST_TAG_IMAGE, add_image_tag, NULL}, { + GST_TAG_PREVIEW_IMAGE, add_image_tag, NULL}, { + + /* Misc user-defined text tags for IDs (and UFID frame) */ + GST_TAG_MUSICBRAINZ_ARTISTID, add_musicbrainz_tag, "\000"}, { + GST_TAG_MUSICBRAINZ_ALBUMID, add_musicbrainz_tag, "\001"}, { + GST_TAG_MUSICBRAINZ_ALBUMARTISTID, add_musicbrainz_tag, "\002"}, { + GST_TAG_MUSICBRAINZ_TRMID, add_musicbrainz_tag, "\003"}, { + GST_TAG_CDDA_MUSICBRAINZ_DISCID, add_musicbrainz_tag, "\004"}, { + GST_TAG_CDDA_CDDB_DISCID, add_musicbrainz_tag, "\005"}, { + GST_TAG_MUSICBRAINZ_TRACKID, add_unique_file_id_tag, NULL}, { + + /* Info about encoder */ + GST_TAG_ENCODER, add_encoder_tag, NULL}, { + GST_TAG_ENCODER_VERSION, add_encoder_tag, NULL}, { + + /* URIs */ + GST_TAG_COPYRIGHT_URI, add_uri_tag, "WCOP"}, { + GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}, { + + /* Up to here, all the frame ids and contents have been the same between + versions 2.3 and 2.4. The rest of them differ... */ + /* Date (in ID3v2.3, this is a TYER tag. In v2.4, it's a TDRC tag */ + GST_TAG_DATE, add_date_tag, NULL}, { + + /* Replaygain data (not really supported in 2.3, we use an experimental + tag there) */ + GST_TAG_TRACK_PEAK, add_relative_volume_tag, NULL}, { + GST_TAG_TRACK_GAIN, add_relative_volume_tag, NULL}, { + GST_TAG_ALBUM_PEAK, add_relative_volume_tag, NULL}, { + GST_TAG_ALBUM_GAIN, add_relative_volume_tag, NULL}, { + + /* Sortable version of various tags. These are all v2.4 ONLY */ + GST_TAG_ARTIST_SORTNAME, add_text_tag_v4, "TSOP"}, { + GST_TAG_ALBUM_SORTNAME, add_text_tag_v4, "TSOA"}, { + GST_TAG_TITLE_SORTNAME, add_text_tag_v4, "TSOT"} +}; + +static void +foreach_add_tag (const GstTagList * list, const gchar * tag, gpointer userdata) +{ + GstId3v2Tag *id3v2tag = (GstId3v2Tag *) userdata; + guint num_tags, i; + + num_tags = gst_tag_list_get_tag_size (list, tag); + + GST_LOG ("Processing tag %s (num=%u)", tag, num_tags); + + if (num_tags > 1 && gst_tag_is_fixed (tag)) { + GST_WARNING ("Multiple occurences of fixed tag '%s', ignoring some", tag); + num_tags = 1; + } + + for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) { + if (strcmp (add_funcs[i].gst_tag, tag) == 0) { + add_funcs[i].func (id3v2tag, list, tag, num_tags, add_funcs[i].data); + break; + } + } + + if (i == G_N_ELEMENTS (add_funcs)) { + GST_WARNING ("Unsupported tag '%s' - not written", tag); + } +} + +GstBuffer * +gst_id3mux_render_v2_tag (GstTagMux * mux, GstTagList * taglist, int version) +{ + GstId3v2Tag tag; + GstBuffer *buf; + + if (!id3v2_tag_init (&tag, version)) { + GST_WARNING_OBJECT (mux, "Unsupported version %d", version); + return NULL; + } + + /* Render the tag */ + gst_tag_list_foreach (taglist, foreach_add_tag, &tag); + +#if 0 + /* Do we want to add our own signature to the tag somewhere? */ + { + gchar *tag_producer_str; + + tag_producer_str = g_strdup_printf ("(GStreamer id3v2mux %s, using " + "taglib %u.%u)", VERSION, TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION); + add_one_txxx_tag (id3v2tag, "tag_encoder", tag_producer_str); + g_free (tag_producer_str); + } +#endif + + /* Create buffer with tag */ + buf = id3v2_tag_to_buffer (&tag); + gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad)); + GST_LOG_OBJECT (mux, "tag size = %d bytes", GST_BUFFER_SIZE (buf)); + + id3v2_tag_unset (&tag); + + return buf; +} + +#define ID3_V1_TAG_SIZE 128 + +typedef void (*GstId3v1WriteFunc) (const GstTagList * list, + const gchar * gst_tag, guint8 * dst, int len); + +static void +latin1_convert (const GstTagList * list, const gchar * tag, + guint8 * dst, int maxlen) +{ + gchar *str; + gsize len; + gchar *latin1; + + if (!gst_tag_list_get_string (list, tag, &str)) + return; + + /* Convert to Latin-1 (ISO-8859-1), replacing unrepresentable characters + with '?' */ + latin1 = g_convert_with_fallback (str, -1, "ISO-8859-1", "UTF-8", "?", + NULL, &len, NULL); + + if (latin1) { + len = MIN (len, maxlen); + memcpy (dst, latin1, len); + g_free (latin1); + } + + g_free (str); +} + +static void +date_v1_convert (const GstTagList * list, const gchar * tag, + guint8 * dst, int maxlen) +{ + GDate *date; + + /* Only one date supported */ + if (gst_tag_list_get_date_index (list, tag, 0, &date) && date != NULL) { + GDateYear year = g_date_get_year (date); + /* Check for plausible year */ + if (year > 500 && year < 2100) { + gchar str[5]; + g_snprintf (str, 5, "%.4u", year); + memcpy (dst, str, 4); + } else { + GST_WARNING ("invalid year %u, skipping", year); + } + + g_date_free (date); + } +} + +static void +genre_v1_convert (const GstTagList * list, const gchar * tag, + guint8 * dst, int maxlen) +{ + gchar *str; + int genreidx = -1; + guint i, max; + + /* We only support one genre */ + if (!gst_tag_list_get_string_index (list, tag, 0, &str)) + return; + + max = gst_tag_id3_genre_count (); + + for (i = 0; i < max; i++) { + const gchar *genre = gst_tag_id3_genre_get (i); + if (g_str_equal (str, genre)) { + genreidx = i; + break; + } + } + + if (genreidx >= 0 && genreidx <= 127) + *dst = (guint8) genreidx; + + g_free (str); +} + +static void +track_number_convert (const GstTagList * list, const gchar * tag, + guint8 * dst, int maxlen) +{ + guint tracknum; + + /* We only support one track number */ + if (!gst_tag_list_get_uint_index (list, tag, 0, &tracknum)) + return; + + if (tracknum <= 127) + *dst = (guint8) tracknum; +} + +static const struct +{ + const gchar *gst_tag; + const gint offset; + const gint length; + const GstId3v1WriteFunc func; +} v1_funcs[] = { + { + GST_TAG_TITLE, 3, 30, latin1_convert}, { + GST_TAG_ARTIST, 33, 30, latin1_convert}, { + GST_TAG_ALBUM, 63, 30, latin1_convert}, { + GST_TAG_DATE, 93, 4, date_v1_convert}, { + GST_TAG_COMMENT, 97, 28, latin1_convert}, { + /* Note: one-byte gap here */ + GST_TAG_TRACK_NUMBER, 126, 1, track_number_convert}, { + GST_TAG_GENRE, 127, 1, genre_v1_convert} +}; + +GstBuffer * +gst_id3mux_render_v1_tag (GstTagMux * mux, GstTagList * taglist) +{ + GstBuffer *buf = gst_buffer_new_and_alloc (ID3_V1_TAG_SIZE); + guint8 *data = GST_BUFFER_DATA (buf); + int i; + + memset (data, 0, ID3_V1_TAG_SIZE); + + data[0] = 'T'; + data[1] = 'A'; + data[2] = 'G'; + + for (i = 0; i < G_N_ELEMENTS (v1_funcs); i++) { + v1_funcs[i].func (taglist, v1_funcs[i].gst_tag, data + v1_funcs[i].offset, + v1_funcs[i].length); + } + + gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad)); + return buf; +} diff --git a/gst/id3tag/id3tag.h b/gst/id3tag/id3tag.h new file mode 100644 index 00000000..1fb59376 --- /dev/null +++ b/gst/id3tag/id3tag.h @@ -0,0 +1,32 @@ +/* GStreamer ID3v2 tag writer + * Copyright (C) 2009 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. + */ + +#include "gsttagmux.h" + +G_BEGIN_DECLS + +#define ID3_VERSION_2_3 3 +#define ID3_VERSION_2_4 4 + +GstBuffer * gst_id3mux_render_v2_tag (GstTagMux * mux, GstTagList * taglist, + int version); +GstBuffer * gst_id3mux_render_v1_tag (GstTagMux * mux, GstTagList * taglist); + +G_END_DECLS + -- cgit v1.2.1 From e9eae335f1164c6d57b18d5038c6df2835bfd563 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 18 May 2009 23:21:47 +0200 Subject: sdpdemux: rework RTCP sending and RTP receiving When we are dealing with multiast, create the udp src and sink elements pointing to the multicast addresses. When we are doing unicast, receive data on the local ports and don't send RTCP because we don't know where we have to send it. Fixes #583188 --- gst/sdp/gstsdpdemux.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++----- gst/sdp/gstsdpdemux.h | 1 + 2 files changed, 70 insertions(+), 7 deletions(-) (limited to 'gst') diff --git a/gst/sdp/gstsdpdemux.c b/gst/sdp/gstsdpdemux.c index be34a22a..4deac870 100644 --- a/gst/sdp/gstsdpdemux.c +++ b/gst/sdp/gstsdpdemux.c @@ -51,6 +51,22 @@ #include #endif +#ifdef G_OS_WIN32 +#ifdef _MSC_VER +#include +#endif +/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later. + * * minwg32 headers check WINVER before allowing the use of these */ +#ifndef WINVER +#define WINVER 0x0501 +#endif +#include +#else +#include +#include +#include +#endif + #include #include #include @@ -348,6 +364,39 @@ gst_sdp_demux_stream_free (GstSDPDemux * demux, GstSDPStream * stream) g_free (stream); } +static gboolean +is_multicast_address (const gchar * host_name) +{ + struct addrinfo hints; + struct addrinfo *ai; + struct addrinfo *res; + gboolean ret = FALSE; + int err; + + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_DGRAM; + + g_return_val_if_fail (host_name, FALSE); + + if ((err = getaddrinfo (host_name, NULL, &hints, &res)) < 0) + return FALSE; + + for (ai = res; !ret && ai; ai = ai->ai_next) { + if (ai->ai_family == AF_INET) + ret = + IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)-> + sin_addr.s_addr)); + else + ret = + IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai-> + ai_addr)->sin6_addr); + } + + freeaddrinfo (res); + + return ret; +} + static GstSDPStream * gst_sdp_demux_create_stream (GstSDPDemux * demux, GstSDPMessage * sdp, gint idx) { @@ -395,6 +444,7 @@ gst_sdp_demux_create_stream (GstSDPDemux * demux, GstSDPMessage * sdp, gint idx) stream->destination = conn->address; stream->ttl = conn->ttl; + stream->multicast = is_multicast_address (stream->destination); stream->rtp_port = gst_sdp_media_get_port (media); if ((rtcp = gst_sdp_media_get_attribute_val (media, "rtcp"))) { @@ -885,18 +935,24 @@ start_session_failure: static gboolean gst_sdp_demux_stream_configure_udp (GstSDPDemux * demux, GstSDPStream * stream) { - gchar *uri, *name; + gchar *uri, *name, *destination; GstPad *pad; GST_DEBUG_OBJECT (demux, "creating UDP sources for multicast"); + /* if the destination is not a multicast address, we just want to listen on + * our local ports */ + if (!stream->multicast) + destination = "0.0.0.0"; + else + destination = stream->destination; + /* creating UDP source */ if (stream->rtp_port != -1) { - GST_DEBUG_OBJECT (demux, "receiving RTP from %s:%d", stream->destination, + GST_DEBUG_OBJECT (demux, "receiving RTP from %s:%d", destination, stream->rtp_port); - uri = g_strdup_printf ("udp://%s:%d", stream->destination, - stream->rtp_port); + uri = g_strdup_printf ("udp://%s:%d", destination, stream->rtp_port); stream->udpsrc[0] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL); g_free (uri); if (stream->udpsrc[0] == NULL) @@ -933,10 +989,9 @@ gst_sdp_demux_stream_configure_udp (GstSDPDemux * demux, GstSDPStream * stream) /* creating another UDP source */ if (stream->rtcp_port != -1) { - GST_DEBUG_OBJECT (demux, "receiving RTCP from %s:%d", stream->destination, + GST_DEBUG_OBJECT (demux, "receiving RTCP from %s:%d", destination, stream->rtcp_port); - uri = - g_strdup_printf ("udp://%s:%d", stream->destination, stream->rtcp_port); + uri = g_strdup_printf ("udp://%s:%d", destination, stream->rtcp_port); stream->udpsrc[1] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL); g_free (uri); if (stream->udpsrc[1] == NULL) @@ -988,6 +1043,13 @@ gst_sdp_demux_stream_configure_udp_sink (GstSDPDemux * demux, if (stream->udpsink == NULL) goto no_sink_element; + /* we clear all destinations because we don't really know where to send the + * RTCP to and we want to avoid sending it to our own ports. + * FIXME when we get an RTCP packet from the sender, we could look at its + * source port and address and try to send RTCP there. */ + if (!stream->multicast) + g_signal_emit_by_name (stream->udpsink, "clear"); + /* no sync needed */ g_object_set (G_OBJECT (stream->udpsink), "sync", FALSE, NULL); /* no async state changes needed */ diff --git a/gst/sdp/gstsdpdemux.h b/gst/sdp/gstsdpdemux.h index 0ae60742..32a53293 100644 --- a/gst/sdp/gstsdpdemux.h +++ b/gst/sdp/gstsdpdemux.h @@ -68,6 +68,7 @@ struct _GstSDPStream { gchar *destination; guint ttl; + gboolean multicast; /* our udp sink back to the server */ GstElement *udpsink; -- cgit v1.2.1 From ab80a4fa411e85380ee5da3e7f7abc1553053628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 00:16:19 +0200 Subject: rtpbin: Implement releasing of rtcp src pad See #561752 --- gst/rtpmanager/gstrtpbin.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 7d3b9823..4db28f73 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -2338,8 +2338,13 @@ pad_failed: static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { - g_warning ("gstrtpbin: releasing pad %s:%s is not implemented", - GST_DEBUG_PAD_NAME (pad)); + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (GST_ELEMENT (rtpbin), pad); + + if (session->send_rtcp_src) { + gst_element_release_request_pad (session->session, session->send_rtcp_src); + session->send_rtcp_src = NULL; + } } /* If the requested name is NULL we should create a name with -- cgit v1.2.1 From b831c9b434046ea7e8c6cc757607c67f7f7656dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 00:34:36 +0200 Subject: rtpbin: Implement release of the recv rtcp pad See #561752 --- gst/rtpmanager/gstrtpbin.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 4db28f73..b4e61ac2 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -2176,8 +2176,18 @@ link_failed: static void remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { - g_warning ("gstrtpbin: releasing pad %s:%s is not implemented", - GST_DEBUG_PAD_NAME (pad)); + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); + + if (session->sync_src) { + /* releasing the request pad should also unref the sync pad */ + gst_object_unref (session->sync_src); + session->sync_src = NULL; + } + if (session->recv_rtcp_sink) { + gst_element_release_request_pad (session->session, session->recv_rtcp_sink); + session->recv_rtcp_sink = NULL; + } } /* Create a pad for sending RTP for the session in @name. Must be called with @@ -2339,7 +2349,7 @@ static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { gst_pad_set_active (pad, FALSE); - gst_element_remove_pad (GST_ELEMENT (rtpbin), pad); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); if (session->send_rtcp_src) { gst_element_release_request_pad (session->session, session->send_rtcp_src); -- cgit v1.2.1 From 65d55e6b13c41f3ca6ff5e4e39fbd7ec990e8d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 00:44:51 +0200 Subject: rtpbin: Implement releasing of rtp send pads --- gst/rtpmanager/gstrtpbin.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index b4e61ac2..a1411e10 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -348,6 +348,7 @@ struct _GstRtpBinSession GstPad *sync_src; GstPad *send_rtp_sink; GstPad *send_rtp_src; + GstPad *send_rtp_src_ghost; GstPad *send_rtcp_src; }; @@ -2196,7 +2197,7 @@ remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) static GstPad * create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) { - GstPad *result, *srcghost; + GstPad *result; gchar *gname; guint sessid; GstRtpBinSession *session; @@ -2240,10 +2241,10 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) klass = GST_ELEMENT_GET_CLASS (rtpbin); gname = g_strdup_printf ("send_rtp_src_%d", sessid); templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d"); - srcghost = + session->send_rtp_src_ghost = gst_ghost_pad_new_from_template (gname, session->send_rtp_src, templ); - gst_pad_set_active (srcghost, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost); + gst_pad_set_active (session->send_rtp_src_ghost, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost); g_free (gname); return result; @@ -2281,8 +2282,26 @@ no_srcpad: static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { - g_warning ("gstrtpbin: releasing pad %s:%s is not implemented", - GST_DEBUG_PAD_NAME (pad)); + if (session->send_rtp_src_ghost) { + gst_pad_set_active (session->send_rtp_src_ghost, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), + session->send_rtp_src_ghost); + session->send_rtp_src_ghost = NULL; + } + + if (session->send_rtp_src) { + gst_object_unref (session->send_rtp_src); + session->send_rtp_src = NULL; + } + + if (session->send_rtp_sink) { + gst_element_release_request_pad (GST_ELEMENT_CAST (session->session), + session->send_rtp_sink); + session->send_rtp_sink = NULL; + } + + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); } /* Create a pad for sending RTCP for the session in @name. Must be called with -- cgit v1.2.1 From 4424fd3c93ab2f2b9590a3b0c461c16d01f8a00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 00:51:53 +0200 Subject: rtpbin: Implement relasing of the rtp recv pad --- gst/rtpmanager/gstrtpbin.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index a1411e10..075776ee 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -2081,8 +2081,23 @@ link_failed: static void remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { - g_warning ("gstrtpbin: releasing pad %s:%s is not implemented", - GST_DEBUG_PAD_NAME (pad)); + if (session->demux_newpad_sig) { + g_signal_handler_disconnect (session->demux, session->demux_newpad_sig); + session->demux_newpad_sig = 0; + } + + if (session->recv_rtp_src) { + gst_object_unref (session->recv_rtp_src); + session->recv_rtp_src = NULL; + } + + if (session->recv_rtp_sink) { + gst_element_release_request_pad (session->session, session->recv_rtp_sink); + session->recv_rtp_sink = NULL; + } + + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); } /* Create a pad for receiving RTCP for the session in @name. Must be called with -- cgit v1.2.1 From fb59348dbe0dfd5b6cb0596a031e5c437265e85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 01:03:55 +0200 Subject: rtpbin: Free session if request pads are released Free the session when all the request pads are released. Don't mess with the session list in free_session as it is called from a foreach on that list. Set the state of the upstream element to NULL first. See #561752 --- gst/rtpmanager/gstrtpbin.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 075776ee..11cc2dd9 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -554,8 +554,8 @@ free_session (GstRtpBinSession * sess) GST_DEBUG_OBJECT (bin, "freeing session %p", sess); - gst_element_set_state (sess->session, GST_STATE_NULL); gst_element_set_state (sess->demux, GST_STATE_NULL); + gst_element_set_state (sess->session, GST_STATE_NULL); if (sess->recv_rtp_sink != NULL) { gst_element_release_request_pad (sess->session, sess->recv_rtp_sink); @@ -589,8 +589,6 @@ free_session (GstRtpBinSession * sess) g_mutex_free (sess->lock); g_hash_table_destroy (sess->ptmap); - bin->sessions = g_slist_remove (bin->sessions, sess); - g_free (sess); } @@ -2512,6 +2510,13 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad) } else if (session->send_rtcp_src == target) { remove_rtcp (rtpbin, session, pad); } + + /* no more request pads, free the complete session */ + if (session->recv_rtp_sink == NULL && session->recv_rtcp_sink == NULL && + session->send_rtp_sink == NULL && session->send_rtcp_src == NULL) { + rtpbin->sessions = g_slist_remove (rtpbin->sessions, session); + free_session (session); + } GST_RTP_BIN_UNLOCK (rtpbin); gst_object_unref (target); -- cgit v1.2.1 From b3aeee2bf281225495b09216ec3d796e6330c9e1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 01:12:57 +0200 Subject: rtpbin: use the right lock for the sessions Use the right lock when iterating the sessions. --- gst/rtpmanager/gstrtpbin.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 11cc2dd9..9ab50888 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -1555,6 +1555,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type, if (type < 0 || type > 8) return; + GST_RTP_BIN_LOCK (bin); + GST_OBJECT_LOCK (bin); g_free (bin->sdes[type]); bin->sdes[type] = g_strdup (data); @@ -1563,6 +1565,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type, for (item = bin->sessions; item; item = g_slist_next (item)) g_object_set (item->data, name, bin->sdes[type], NULL); GST_OBJECT_UNLOCK (bin); + + GST_RTP_BIN_UNLOCK (bin); } static gchar * -- cgit v1.2.1 From 451ca5dbc059b369de56cf1a8906f5bd5dc89943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 01:16:11 +0200 Subject: rtpbin: Keep jb signals handler Keep the signal handlers so they can be disconnected at release time See #561752 --- gst/rtpmanager/gstrtpbin.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 9ab50888..977fd787 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -297,6 +297,9 @@ struct _GstRtpBinStream /* the jitterbuffer of the SSRC */ GstElement *buffer; + gulong buffer_handlesync_sig; + gulong buffer_ptreq_sig; + gulong buffer_ntpstop_sig; /* the PT demuxer of the SSRC */ GstElement *demux; @@ -1096,9 +1099,10 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) session->streams = g_slist_prepend (session->streams, stream); /* provide clock_rate to the jitterbuffer when needed */ - g_signal_connect (buffer, "request-pt-map", + stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map", (GCallback) pt_map_requested, session); - g_signal_connect (buffer, "on-npt-stop", (GCallback) on_npt_stop, stream); + stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop", + (GCallback) on_npt_stop, stream); /* configure latency and packet lost */ g_object_set (buffer, "latency", session->bin->latency, NULL); @@ -1950,7 +1954,7 @@ new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad, /* connect to the RTCP sync signal from the jitterbuffer */ GST_DEBUG_OBJECT (rtpbin, "connecting sync signal"); - g_signal_connect (stream->buffer, + stream->buffer_handlesync_sig = g_signal_connect (stream->buffer, "handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream); /* connect to the new-pad signal of the payload demuxer, this will expose the -- cgit v1.2.1 From c5ab83a1cbfb5cae17717a3fe08d9f339181d813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 22 May 2009 01:43:50 +0200 Subject: rtpbin: Implement releasing the streams See #561752 --- gst/rtpmanager/gstrtpbin.c | 74 +++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 21 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 977fd787..7e14a0d9 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -335,6 +335,7 @@ struct _GstRtpBinSession /* the SSRC demuxer */ GstElement *demux; gulong demux_newpad_sig; + gulong demux_padremoved_sig; GMutex *lock; @@ -471,6 +472,45 @@ on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream) stream->session->id, stream->ssrc); } +/* must be called with the SESSION lock */ +static GstRtpBinStream * +find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc) +{ + GSList *walk; + + for (walk = session->streams; walk; walk = g_slist_next (walk)) { + GstRtpBinStream *stream = (GstRtpBinStream *) walk->data; + + if (stream->ssrc == ssrc) + return stream; + } + return NULL; +} + +static void +ssrc_demux_pad_removed (GstElement * element, GstPad * pad, + GstRtpBinSession * session) +{ + guint ssrc; + GstRtpBinStream *stream = NULL; + gchar *name; + gint res; + + name = gst_pad_get_name (pad); + res = sscanf (name, "src_%d", &ssrc); + g_free (name); + + if (res != 1) + return; + + GST_RTP_SESSION_LOCK (session); + if ((stream = find_stream_by_ssrc (session, ssrc))) { + session->streams = g_slist_remove (session->streams, stream); + free_stream (stream); + } + GST_RTP_SESSION_UNLOCK (session); +} + /* create a session with the given id. Must be called with RTP_BIN_LOCK */ static GstRtpBinSession * create_session (GstRtpBin * rtpbin, gint id) @@ -595,22 +635,6 @@ free_session (GstRtpBinSession * sess) g_free (sess); } -#if 0 -static GstRtpBinStream * -find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc) -{ - GSList *walk; - - for (walk = session->streams; walk; walk = g_slist_next (walk)) { - GstRtpBinStream *stream = (GstRtpBinStream *) walk->data; - - if (stream->ssrc == ssrc) - return stream; - } - return NULL; -} -#endif - /* get the payload type caps for the specific payload @pt in @session */ static GstCaps * get_pt_map (GstRtpBinSession * session, guint pt) @@ -1139,14 +1163,18 @@ free_stream (GstRtpBinStream * stream) session = stream->session; - gst_element_set_state (stream->buffer, GST_STATE_NULL); + g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig); + g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig); + g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig); + g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig); + g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig); + gst_element_set_state (stream->demux, GST_STATE_NULL); + gst_element_set_state (stream->buffer, GST_STATE_NULL); gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer); gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux); - session->streams = g_slist_remove (session->streams, stream); - g_free (stream); } @@ -2046,6 +2074,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) /* connect to the new-ssrc-pad signal of the SSRC demuxer */ session->demux_newpad_sig = g_signal_connect (session->demux, "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session); + session->demux_padremoved_sig = g_signal_connect (session->demux, + "pad-removed", (GCallback) ssrc_demux_pad_removed, session); GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad"); result = @@ -2091,12 +2121,14 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) g_signal_handler_disconnect (session->demux, session->demux_newpad_sig); session->demux_newpad_sig = 0; } - + if (session->demux_padremoved_sig) { + g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig); + session->demux_padremoved_sig = 0; + } if (session->recv_rtp_src) { gst_object_unref (session->recv_rtp_src); session->recv_rtp_src = NULL; } - if (session->recv_rtp_sink) { gst_element_release_request_pad (session->session, session->recv_rtp_sink); session->recv_rtp_sink = NULL; -- cgit v1.2.1 From 02bff8754b34a3d5f596f26c8dd7e83ae356130f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 22 May 2009 01:27:09 +0100 Subject: id3tag: register GType of the base class with a less generic name .. so we can easily move the base class into -base later without causing GType name conflicts. --- gst/id3tag/gsttagmux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/id3tag/gsttagmux.c b/gst/id3tag/gsttagmux.c index bfa4e1bc..257f82bb 100644 --- a/gst/id3tag/gsttagmux.c +++ b/gst/id3tag/gsttagmux.c @@ -55,7 +55,12 @@ gst_tag_mux_iface_init (GType tag_type) g_type_add_interface_static (tag_type, GST_TYPE_TAG_SETTER, &tag_setter_info); } -GST_BOILERPLATE_FULL (GstTagMux, gst_tag_mux, +/* make sure to register a less generic type so we can easily move this + * GstTagMux base class into -base without causing GType name conflicts */ +typedef GstTagMux GstID3TagMux; +typedef GstTagMuxClass GstID3TagMuxClass; + +GST_BOILERPLATE_FULL (GstID3TagMux, gst_tag_mux, GstElement, GST_TYPE_ELEMENT, gst_tag_mux_iface_init); -- cgit v1.2.1 From fdaeae57c90ebd1fa001f398be6fec9050129781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 22 May 2009 09:51:29 +0100 Subject: id3tag: change GType to GstId3Tag so it doesn't conflict with the id3tag plugin in -ugly --- gst/id3tag/gstid3tag.c | 14 +++++++------- gst/id3tag/gstid3tag.h | 12 ++++++------ gst/id3tag/gsttagmux.c | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'gst') diff --git a/gst/id3tag/gstid3tag.c b/gst/id3tag/gstid3tag.c index f67d781f..98b05d0d 100644 --- a/gst/id3tag/gstid3tag.c +++ b/gst/id3tag/gstid3tag.c @@ -76,7 +76,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("application/x-id3")); -GST_BOILERPLATE (GstID3Tag, gst_id3tag, GstTagMux, GST_TYPE_TAG_MUX); +GST_BOILERPLATE (GstId3Tag, gst_id3tag, GstTagMux, GST_TYPE_TAG_MUX); static GstBuffer *gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist); @@ -107,7 +107,7 @@ gst_id3tag_base_init (gpointer g_class) } static void -gst_id3tag_class_init (GstID3TagClass * klass) +gst_id3tag_class_init (GstId3TagClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; @@ -137,7 +137,7 @@ gst_id3tag_class_init (GstID3TagClass * klass) } static void -gst_id3tag_init (GstID3Tag * id3mux, GstID3TagClass * id3mux_class) +gst_id3tag_init (GstId3Tag * id3mux, GstId3TagClass * id3mux_class) { id3mux->write_v1 = DEFAULT_WRITE_V1; id3mux->write_v2 = DEFAULT_WRITE_V2; @@ -149,7 +149,7 @@ static void gst_id3tag_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstID3Tag *mux = GST_ID3TAG (object); + GstId3Tag *mux = GST_ID3TAG (object); switch (prop_id) { case ARG_WRITE_V1: @@ -171,7 +171,7 @@ static void gst_id3tag_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstID3Tag *mux = GST_ID3TAG (object); + GstId3Tag *mux = GST_ID3TAG (object); switch (prop_id) { case ARG_WRITE_V1: @@ -192,7 +192,7 @@ gst_id3tag_get_property (GObject * object, guint prop_id, static GstBuffer * gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) { - GstID3Tag *id3mux = GST_ID3TAG (mux); + GstId3Tag *id3mux = GST_ID3TAG (mux); if (id3mux->write_v2) return gst_id3mux_render_v2_tag (mux, taglist, id3mux->v2_major_version); @@ -203,7 +203,7 @@ gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) static GstBuffer * gst_id3tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist) { - GstID3Tag *id3mux = GST_ID3TAG (mux); + GstId3Tag *id3mux = GST_ID3TAG (mux); if (id3mux->write_v1) return gst_id3mux_render_v1_tag (mux, taglist); diff --git a/gst/id3tag/gstid3tag.h b/gst/id3tag/gstid3tag.h index 6b33df25..60643594 100644 --- a/gst/id3tag/gstid3tag.h +++ b/gst/id3tag/gstid3tag.h @@ -28,10 +28,10 @@ G_BEGIN_DECLS -typedef struct _GstID3Tag GstID3Tag; -typedef struct _GstID3TagClass GstID3TagClass; +typedef struct _GstId3Tag GstId3Tag; +typedef struct _GstId3TagClass GstId3TagClass; -struct _GstID3Tag { +struct _GstId3Tag { GstTagMux tagmux; gboolean write_v1; @@ -40,16 +40,16 @@ struct _GstID3Tag { gint v2_major_version; }; -struct _GstID3TagClass { +struct _GstId3TagClass { GstTagMuxClass tagmux_class; }; #define GST_TYPE_ID3TAG \ (gst_id3tag_get_type()) #define GST_ID3TAG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3TAG,GstID3Tag)) + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3TAG,GstId3Tag)) #define GST_ID3TAG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3TAG,GstID3TagClass)) + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3TAG,GstId3TagClass)) #define GST_IS_ID3TAG(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3TAG)) #define GST_IS_ID3TAG_CLASS(klass) \ diff --git a/gst/id3tag/gsttagmux.c b/gst/id3tag/gsttagmux.c index 257f82bb..3b7ff119 100644 --- a/gst/id3tag/gsttagmux.c +++ b/gst/id3tag/gsttagmux.c @@ -57,10 +57,10 @@ gst_tag_mux_iface_init (GType tag_type) /* make sure to register a less generic type so we can easily move this * GstTagMux base class into -base without causing GType name conflicts */ -typedef GstTagMux GstID3TagMux; -typedef GstTagMuxClass GstID3TagMuxClass; +typedef GstTagMux GstId3TagMux; +typedef GstTagMuxClass GstId3TagMuxClass; -GST_BOILERPLATE_FULL (GstID3TagMux, gst_tag_mux, +GST_BOILERPLATE_FULL (GstId3TagMux, gst_tag_mux, GstElement, GST_TYPE_ELEMENT, gst_tag_mux_iface_init); -- cgit v1.2.1 From e5b1c976c4dbbea82d0bc1f0de7c0bf4b6d1705d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 22 May 2009 09:54:57 +0100 Subject: id3tag: canonicalise function names --- gst/id3tag/gstid3tag.c | 38 +++++++++++++++++++------------------- gst/id3tag/gstid3tag.h | 4 ++-- gst/id3tag/id3tag.c | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'gst') diff --git a/gst/id3tag/gstid3tag.c b/gst/id3tag/gstid3tag.c index 98b05d0d..9c8072c0 100644 --- a/gst/id3tag/gstid3tag.c +++ b/gst/id3tag/gstid3tag.c @@ -56,8 +56,8 @@ #include -GST_DEBUG_CATEGORY (gst_id3tag_debug); -#define GST_CAT_DEFAULT gst_id3tag_debug +GST_DEBUG_CATEGORY (gst_id3_tag_debug); +#define GST_CAT_DEFAULT gst_id3_tag_debug enum { @@ -76,20 +76,20 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("application/x-id3")); -GST_BOILERPLATE (GstId3Tag, gst_id3tag, GstTagMux, GST_TYPE_TAG_MUX); +GST_BOILERPLATE (GstId3Tag, gst_id3_tag, GstTagMux, GST_TYPE_TAG_MUX); -static GstBuffer *gst_id3tag_render_v2_tag (GstTagMux * mux, +static GstBuffer *gst_id3_tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist); -static GstBuffer *gst_id3tag_render_v1_tag (GstTagMux * mux, +static GstBuffer *gst_id3_tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist); -static void gst_id3tag_set_property (GObject * object, guint prop_id, +static void gst_id3_tag_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_id3tag_get_property (GObject * object, guint prop_id, +static void gst_id3_tag_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void -gst_id3tag_base_init (gpointer g_class) +gst_id3_tag_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); @@ -102,17 +102,17 @@ gst_id3tag_base_init (gpointer g_class) "Michael Smith , " "Tim-Philipp Müller "); - GST_DEBUG_CATEGORY_INIT (gst_id3tag_debug, "id3tag", 0, + GST_DEBUG_CATEGORY_INIT (gst_id3_tag_debug, "id3tag", 0, "ID3 v1 and v2 tag muxer"); } static void -gst_id3tag_class_init (GstId3TagClass * klass) +gst_id3_tag_class_init (GstId3TagClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_id3tag_set_property; - gobject_class->get_property = gst_id3tag_get_property; + gobject_class->set_property = gst_id3_tag_set_property; + gobject_class->get_property = gst_id3_tag_get_property; g_object_class_install_property (gobject_class, ARG_WRITE_V1, g_param_spec_boolean ("write-v1", "Write id3v1 tag", @@ -131,13 +131,13 @@ gst_id3tag_class_init (GstId3TagClass * klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); GST_TAG_MUX_CLASS (klass)->render_start_tag = - GST_DEBUG_FUNCPTR (gst_id3tag_render_v2_tag); + GST_DEBUG_FUNCPTR (gst_id3_tag_render_v2_tag); - GST_TAG_MUX_CLASS (klass)->render_end_tag = gst_id3tag_render_v1_tag; + GST_TAG_MUX_CLASS (klass)->render_end_tag = gst_id3_tag_render_v1_tag; } static void -gst_id3tag_init (GstId3Tag * id3mux, GstId3TagClass * id3mux_class) +gst_id3_tag_init (GstId3Tag * id3mux, GstId3TagClass * id3mux_class) { id3mux->write_v1 = DEFAULT_WRITE_V1; id3mux->write_v2 = DEFAULT_WRITE_V2; @@ -146,7 +146,7 @@ gst_id3tag_init (GstId3Tag * id3mux, GstId3TagClass * id3mux_class) } static void -gst_id3tag_set_property (GObject * object, guint prop_id, +gst_id3_tag_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstId3Tag *mux = GST_ID3TAG (object); @@ -168,7 +168,7 @@ gst_id3tag_set_property (GObject * object, guint prop_id, } static void -gst_id3tag_get_property (GObject * object, guint prop_id, +gst_id3_tag_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstId3Tag *mux = GST_ID3TAG (object); @@ -190,7 +190,7 @@ gst_id3tag_get_property (GObject * object, guint prop_id, } static GstBuffer * -gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) +gst_id3_tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) { GstId3Tag *id3mux = GST_ID3TAG (mux); @@ -201,7 +201,7 @@ gst_id3tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist) } static GstBuffer * -gst_id3tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist) +gst_id3_tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist) { GstId3Tag *id3mux = GST_ID3TAG (mux); diff --git a/gst/id3tag/gstid3tag.h b/gst/id3tag/gstid3tag.h index 60643594..a9a1ad1c 100644 --- a/gst/id3tag/gstid3tag.h +++ b/gst/id3tag/gstid3tag.h @@ -45,7 +45,7 @@ struct _GstId3TagClass { }; #define GST_TYPE_ID3TAG \ - (gst_id3tag_get_type()) + (gst_id3_tag_get_type()) #define GST_ID3TAG(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3TAG,GstId3Tag)) #define GST_ID3TAG_CLASS(klass) \ @@ -55,7 +55,7 @@ struct _GstId3TagClass { #define GST_IS_ID3TAG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3TAG)) -GType gst_id3tag_get_type (void); +GType gst_id3_tag_get_type (void); G_END_DECLS diff --git a/gst/id3tag/id3tag.c b/gst/id3tag/id3tag.c index 0e040f7e..a39e2a8e 100644 --- a/gst/id3tag/id3tag.c +++ b/gst/id3tag/id3tag.c @@ -25,8 +25,8 @@ #include -GST_DEBUG_CATEGORY_EXTERN (gst_id3tag_debug); -#define GST_CAT_DEFAULT gst_id3tag_debug +GST_DEBUG_CATEGORY_EXTERN (gst_id3_tag_debug); +#define GST_CAT_DEFAULT gst_id3_tag_debug #define ID3V2_APIC_PICTURE_OTHER 0 #define ID3V2_APIC_PICTURE_FILE_ICON 1 -- cgit v1.2.1 From 580b20d6cc155b21e7b0f74f0e4fd28af2c7ce41 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 21 May 2009 16:00:46 +0200 Subject: mpegtsdemux: fix memleaks and refcounts Use correct constants for PID_type so that we clear the right filter. provide_clock must return a ref to a clock. --- gst/mpegdemux/gstmpegtsdemux.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index cad385d0..6438e880 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -382,8 +382,8 @@ gst_mpegts_demux_reset (GstMpegTSDemux * demux) case PID_TYPE_ELEMENTARY: gst_pes_filter_uninit (&stream->filter); break; - case PID_PROGRAM_ASSOCIATION_TABLE: - case PID_CONDITIONAL_ACCESS_TABLE: + case PID_TYPE_PROGRAM_ASSOCIATION: + case PID_TYPE_CONDITIONAL_ACCESS: case PID_TYPE_PROGRAM_MAP: gst_section_filter_uninit (&stream->section_filter); break; @@ -2620,8 +2620,7 @@ gst_mpegts_demux_provide_clock (GstElement * element) "MpegTSClock", NULL); demux->clock_base = GST_CLOCK_TIME_NONE; } - - return demux->clock; + return gst_object_ref (demux->clock); } return NULL; -- cgit v1.2.1 From 58c59d7953e58e262e6eba7fc9906227e68552c6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 11:59:17 +0200 Subject: rtpbin: unref requests pads after releasing --- gst/rtpmanager/gstrtpbin.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 7e14a0d9..e4892d49 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -2131,6 +2131,7 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) } if (session->recv_rtp_sink) { gst_element_release_request_pad (session->session, session->recv_rtp_sink); + gst_object_unref (session->recv_rtp_sink); session->recv_rtp_sink = NULL; } @@ -2240,6 +2241,7 @@ remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) } if (session->recv_rtcp_sink) { gst_element_release_request_pad (session->session, session->recv_rtcp_sink); + gst_object_unref (session->recv_rtcp_sink); session->recv_rtcp_sink = NULL; } } @@ -2350,6 +2352,7 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) if (session->send_rtp_sink) { gst_element_release_request_pad (GST_ELEMENT_CAST (session->session), session->send_rtp_sink); + gst_object_unref (session->send_rtp_sink); session->send_rtp_sink = NULL; } @@ -2425,6 +2428,7 @@ remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) if (session->send_rtcp_src) { gst_element_release_request_pad (session->session, session->send_rtcp_src); + gst_object_unref (session->send_rtcp_src); session->send_rtcp_src = NULL; } } -- cgit v1.2.1 From 142840432ba6c9641f134a1599a76f0c60dd7b5f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 12:20:13 +0200 Subject: rtpbin: set target state on new elements Set the state on newly added elements to the state of the parent. Add some debug info and do some cleanups --- gst/rtpmanager/gstrtpbin.c | 57 ++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index e4892d49..5c0948c6 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -518,6 +518,7 @@ create_session (GstRtpBin * rtpbin, gint id) GstRtpBinSession *sess; GstElement *session, *demux; gint i; + GstState target; if (!(session = gst_element_factory_make ("gstrtpsession", NULL))) goto no_session; @@ -566,11 +567,16 @@ create_session (GstRtpBin * rtpbin, gint id) g_signal_connect (sess->session, "on-sender-timeout", (GCallback) on_sender_timeout, sess); - /* FIXME, change state only to what's needed */ gst_bin_add (GST_BIN_CAST (rtpbin), session); - gst_element_set_state (session, GST_STATE_PLAYING); gst_bin_add (GST_BIN_CAST (rtpbin), demux); - gst_element_set_state (demux, GST_STATE_PLAYING); + + GST_OBJECT_LOCK (rtpbin); + target = GST_STATE_TARGET (rtpbin); + GST_OBJECT_UNLOCK (rtpbin); + + /* change state only to what's needed */ + gst_element_set_state (demux, target); + gst_element_set_state (session, target); return sess; @@ -589,12 +595,8 @@ no_demux: } static void -free_session (GstRtpBinSession * sess) +free_session (GstRtpBinSession * sess, GstRtpBin * bin) { - GstRtpBin *bin; - - bin = sess->bin; - GST_DEBUG_OBJECT (bin, "freeing session %p", sess); gst_element_set_state (sess->demux, GST_STATE_NULL); @@ -848,8 +850,9 @@ get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created) } static void -free_client (GstRtpBinClient * client) +free_client (GstRtpBinClient * client, GstRtpBin * bin) { + GST_DEBUG_OBJECT (bin, "freeing client %p", client); g_slist_free (client->streams); g_free (client->cname); g_free (client); @@ -1105,6 +1108,8 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) { GstElement *buffer, *demux; GstRtpBinStream *stream; + GstRtpBin *rtpbin; + GstState target; if (!(buffer = gst_element_factory_make ("gstrtpjitterbuffer", NULL))) goto no_jitterbuffer; @@ -1112,9 +1117,11 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) if (!(demux = gst_element_factory_make ("gstrtpptdemux", NULL))) goto no_demux; + rtpbin = session->bin; + stream = g_new0 (GstRtpBinStream, 1); stream->ssrc = ssrc; - stream->bin = session->bin; + stream->bin = rtpbin; stream->session = session; stream->buffer = buffer; stream->demux = demux; @@ -1129,17 +1136,23 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) (GCallback) on_npt_stop, stream); /* configure latency and packet lost */ - g_object_set (buffer, "latency", session->bin->latency, NULL); - g_object_set (buffer, "do-lost", session->bin->do_lost, NULL); + g_object_set (buffer, "latency", rtpbin->latency, NULL); + g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL); - gst_bin_add (GST_BIN_CAST (session->bin), buffer); - gst_element_set_state (buffer, GST_STATE_PLAYING); - gst_bin_add (GST_BIN_CAST (session->bin), demux); - gst_element_set_state (demux, GST_STATE_PLAYING); + gst_bin_add (GST_BIN_CAST (rtpbin), demux); + gst_bin_add (GST_BIN_CAST (rtpbin), buffer); /* link stuff */ gst_element_link (buffer, demux); + GST_OBJECT_LOCK (rtpbin); + target = GST_STATE_TARGET (rtpbin); + GST_OBJECT_UNLOCK (rtpbin); + + /* from sink to source */ + gst_element_set_state (demux, target); + gst_element_set_state (buffer, target); + return stream; /* ERRORS */ @@ -1512,11 +1525,11 @@ gst_rtp_bin_dispose (GObject * object) rtpbin = GST_RTP_BIN (object); GST_DEBUG_OBJECT (object, "freeing sessions"); - g_slist_foreach (rtpbin->sessions, (GFunc) free_session, NULL); + g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin); g_slist_free (rtpbin->sessions); rtpbin->sessions = NULL; GST_DEBUG_OBJECT (object, "freeing clients"); - g_slist_foreach (rtpbin->clients, (GFunc) free_client, NULL); + g_slist_foreach (rtpbin->clients, (GFunc) free_client, rtpbin); g_slist_free (rtpbin->clients); rtpbin->clients = NULL; @@ -2494,7 +2507,7 @@ gst_rtp_bin_request_new_pad (GstElement * element, pad_name = g_strdup (name); } - GST_DEBUG ("Trying to request a pad with name %s", pad_name); + GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name); /* figure out the template */ if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) { @@ -2542,6 +2555,9 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad) g_return_if_fail (target); GST_RTP_BIN_LOCK (rtpbin); + GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s", + GST_DEBUG_PAD_NAME (target)); + if (!(session = find_session_by_pad (rtpbin, target))) goto unknown_pad; @@ -2558,8 +2574,9 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad) /* no more request pads, free the complete session */ if (session->recv_rtp_sink == NULL && session->recv_rtcp_sink == NULL && session->send_rtp_sink == NULL && session->send_rtcp_src == NULL) { + GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session); rtpbin->sessions = g_slist_remove (rtpbin->sessions, session); - free_session (session); + free_session (session, rtpbin); } GST_RTP_BIN_UNLOCK (rtpbin); -- cgit v1.2.1 From d48dcb04998835469d15cba23e455c61dfb1a80c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 13:45:15 +0200 Subject: rtpsession: reuse source code for SDES Reuse the RTPSource object property instead of duplicating code. --- gst/rtpmanager/gstrtpsession.c | 60 ++---------------------------------------- 1 file changed, 2 insertions(+), 58 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index 035d82a8..c33fdfc6 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -323,63 +323,6 @@ on_ssrc_active (RTPSession * session, RTPSource * src, GstRtpSession * sess) src->ssrc); } -static GstStructure * -source_get_sdes_structure (RTPSource * src) -{ - GstStructure *result; - GValue val = { 0 }; - gchar *str; - - result = gst_structure_empty_new ("GstRTPSessionSDES"); - - gst_structure_set (result, "ssrc", G_TYPE_UINT, src->ssrc, NULL); - - g_value_init (&val, G_TYPE_STRING); - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "cname", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NAME); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "name", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_EMAIL); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "email", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PHONE); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "phone", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_LOC); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "location", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_TOOL); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "tool", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NOTE); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "note", &val); - } - str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PRIV); - if (str) { - g_value_take_string (&val, str); - gst_structure_set_value (result, "priv", &val); - } - g_value_unset (&val); - - return result; -} - static void on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess) { @@ -388,8 +331,9 @@ on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess) /* convert the new SDES info into a message */ RTP_SESSION_LOCK (session); - s = source_get_sdes_structure (src); + g_object_get (src, "sdes", &s, NULL); RTP_SESSION_UNLOCK (session); + m = gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (sess), s); gst_element_post_message (GST_ELEMENT_CAST (sess), m); -- cgit v1.2.1 From a0b6202baf717f4a5aa74907f6bc8a3ec7e614c5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 13:47:30 +0200 Subject: rtpsource: add RTP and RTCP source address Add the RTP and RTCP sender addresses in the stats structure. --- gst/rtpmanager/rtpsource.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'gst') diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c index a40d974f..6a3dc604 100644 --- a/gst/rtpmanager/rtpsource.c +++ b/gst/rtpmanager/rtpsource.c @@ -188,12 +188,50 @@ rtp_source_finalize (GObject * object) G_OBJECT_CLASS (rtp_source_parent_class)->finalize (object); } +#define MAX_ADDRESS 64 +static void +make_address_string (GstNetAddress * addr, gchar * dest, gulong n) +{ + switch (gst_netaddress_get_net_type (addr)) { + case GST_NET_TYPE_IP4: + { + guint32 address; + guint16 port; + + gst_netaddress_get_ip4_address (addr, &address, &port); + + g_snprintf (dest, n, "%d.%d.%d.%d:%d", (address >> 24) & 0xff, + (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff, port); + break; + } + case GST_NET_TYPE_IP6: + { + guint8 address[16]; + guint16 port; + + gst_netaddress_get_ip6_address (addr, address, &port); + + g_snprintf (dest, n, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%d", + (address[0] << 8) | address[1], (address[2] << 8) | address[3], + (address[4] << 8) | address[5], (address[6] << 8) | address[7], + (address[8] << 8) | address[9], (address[10] << 8) | address[11], + (address[12] << 8) | address[13], (address[14] << 8) | address[15], + port); + break; + } + default: + dest[0] = 0; + break; + } +} + static GstStructure * rtp_source_create_stats (RTPSource * src) { GstStructure *s; gboolean is_sender = src->is_sender; gboolean internal = src->internal; + gchar address_str[MAX_ADDRESS]; /* common data for all types of sources */ s = gst_structure_new ("application/x-rtp-source-stats", @@ -204,6 +242,16 @@ rtp_source_create_stats (RTPSource * src) "is-csrc", G_TYPE_BOOLEAN, src->is_csrc, "is-sender", G_TYPE_BOOLEAN, is_sender, NULL); + /* add address and port */ + if (src->have_rtp_from) { + make_address_string (&src->rtp_from, address_str, sizeof (address_str)); + gst_structure_set (s, "rtp-from", G_TYPE_STRING, address_str, NULL); + } + if (src->have_rtcp_from) { + make_address_string (&src->rtcp_from, address_str, sizeof (address_str)); + gst_structure_set (s, "rtcp-from", G_TYPE_STRING, address_str, NULL); + } + if (internal) { /* our internal source */ if (is_sender) { -- cgit v1.2.1 From 1c85da2d2bfc85722522e3c257271de2f97f734c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 15:36:17 +0200 Subject: rtpbin: don't warn when getting request pads twice Allow getting the request pads multiple times, just return the previously created pads. --- gst/rtpmanager/gstrtpbin.c | 86 ++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 52 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 5c0948c6..bcd363b0 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -347,13 +347,17 @@ struct _GstRtpBinSession /* the pads of the session */ GstPad *recv_rtp_sink; + GstPad *recv_rtp_sink_ghost; GstPad *recv_rtp_src; GstPad *recv_rtcp_sink; + GstPad *recv_rtcp_sink_ghost; GstPad *sync_src; GstPad *send_rtp_sink; + GstPad *send_rtp_sink_ghost; GstPad *send_rtp_src; GstPad *send_rtp_src_ghost; GstPad *send_rtcp_src; + GstPad *send_rtcp_src_ghost; }; /* Manages the RTP streams that come from one client and should therefore be @@ -2034,7 +2038,7 @@ no_stream: static GstPad * create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) { - GstPad *result, *sinkdpad; + GstPad *sinkdpad; guint sessid; GstRtpBinSession *session; GstPadLinkReturn lres; @@ -2056,8 +2060,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) } /* check if pad was requested */ - if (session->recv_rtp_sink != NULL) - goto existed; + if (session->recv_rtp_sink_ghost != NULL) + return session->recv_rtp_sink_ghost; GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad"); /* get recv_rtp pad and store */ @@ -2091,12 +2095,12 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) "pad-removed", (GCallback) ssrc_demux_pad_removed, session); GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad"); - result = + session->recv_rtp_sink_ghost = gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ); - gst_pad_set_active (result, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result); + gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost); - return result; + return session->recv_rtp_sink_ghost; /* ERRORS */ no_name: @@ -2109,12 +2113,6 @@ create_error: /* create_session already warned */ return NULL; } -existed: - { - g_warning ("gstrtpbin: recv_rtp pad already requested for session %d", - sessid); - return NULL; - } pad_failed: { g_warning ("gstrtpbin: failed to get session pad"); @@ -2150,6 +2148,7 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); + session->recv_rtp_sink_ghost = NULL; } /* Create a pad for receiving RTCP for the session in @name. Must be called with @@ -2159,7 +2158,6 @@ static GstPad * create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) { - GstPad *result; guint sessid; GstRtpBinSession *session; GstPad *sinkdpad; @@ -2182,8 +2180,8 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, } /* check if pad was requested */ - if (session->recv_rtcp_sink != NULL) - goto existed; + if (session->recv_rtcp_sink_ghost != NULL) + return session->recv_rtcp_sink_ghost; /* get recv_rtp pad and store */ GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad"); @@ -2205,12 +2203,13 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, if (lres != GST_PAD_LINK_OK) goto link_failed; - result = + session->recv_rtcp_sink_ghost = gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ); - gst_pad_set_active (result, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result); + gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), + session->recv_rtcp_sink_ghost); - return result; + return session->recv_rtcp_sink_ghost; /* ERRORS */ no_name: @@ -2223,12 +2222,6 @@ create_error: /* create_session already warned */ return NULL; } -existed: - { - g_warning ("gstrtpbin: recv_rtcp pad already requested for session %d", - sessid); - return NULL; - } pad_failed: { g_warning ("gstrtpbin: failed to get session pad"); @@ -2244,6 +2237,7 @@ link_failed: static void remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { + session->recv_rtcp_sink_ghost = NULL; gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); @@ -2265,7 +2259,6 @@ remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) static GstPad * create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) { - GstPad *result; gchar *gname; guint sessid; GstRtpBinSession *session; @@ -2285,8 +2278,8 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) } /* check if pad was requested */ - if (session->send_rtp_sink != NULL) - goto existed; + if (session->send_rtp_sink_ghost != NULL) + return session->send_rtp_sink_ghost; /* get send_rtp pad and store */ session->send_rtp_sink = @@ -2294,10 +2287,10 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) if (session->send_rtp_sink == NULL) goto pad_failed; - result = + session->send_rtp_sink_ghost = gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ); - gst_pad_set_active (result, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result); + gst_pad_set_active (session->send_rtp_sink_ghost, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost); /* get srcpad */ session->send_rtp_src = @@ -2315,7 +2308,7 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost); g_free (gname); - return result; + return session->send_rtp_sink_ghost; /* ERRORS */ no_name: @@ -2328,12 +2321,6 @@ create_error: /* create_session already warned */ return NULL; } -existed: - { - g_warning ("gstrtpbin: send_rtp pad already requested for session %d", - sessid); - return NULL; - } pad_failed: { g_warning ("gstrtpbin: failed to get session pad for session %d", sessid); @@ -2369,6 +2356,7 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) session->send_rtp_sink = NULL; } + session->send_rtp_sink_ghost = NULL; gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); } @@ -2379,7 +2367,6 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) static GstPad * create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) { - GstPad *result; guint sessid; GstRtpBinSession *session; @@ -2393,8 +2380,8 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) goto no_session; /* check if pad was requested */ - if (session->send_rtcp_src != NULL) - goto existed; + if (session->send_rtcp_src_ghost != NULL) + return session->send_rtcp_src_ghost; /* get rtcp_src pad and store */ session->send_rtcp_src = @@ -2402,12 +2389,12 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) if (session->send_rtcp_src == NULL) goto pad_failed; - result = + session->send_rtcp_src_ghost = gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ); - gst_pad_set_active (result, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result); + gst_pad_set_active (session->send_rtcp_src_ghost, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost); - return result; + return session->send_rtcp_src_ghost; /* ERRORS */ no_name: @@ -2420,12 +2407,6 @@ no_session: g_warning ("gstrtpbin: session with id %d does not exist", sessid); return NULL; } -existed: - { - g_warning ("gstrtpbin: send_rtcp_src pad already requested for session %d", - sessid); - return NULL; - } pad_failed: { g_warning ("gstrtpbin: failed to get rtcp pad for session %d", sessid); @@ -2436,6 +2417,7 @@ pad_failed: static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) { + session->send_rtcp_src_ghost = NULL; gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); -- cgit v1.2.1 From 9353ceb53049a2fe31a6b986d039dc64208779df Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 15:45:19 +0200 Subject: rtpbin: use our ghostpads instead of its target Since we keep a reference to our ghostpads, we can use them to track sessions. This avoid us having to mess with the target of the ghostpad. --- gst/rtpmanager/gstrtpbin.c | 90 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 44 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index bcd363b0..f7d7e54a 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -398,9 +398,10 @@ find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad) for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) { GstRtpBinSession *sess = (GstRtpBinSession *) walk->data; - if ((sess->recv_rtp_sink == pad) || - (sess->recv_rtcp_sink == pad) || - (sess->send_rtp_sink == pad) || (sess->send_rtcp_src == pad)) + if ((sess->recv_rtp_sink_ghost == pad) || + (sess->recv_rtcp_sink_ghost == pad) || + (sess->send_rtp_sink_ghost == pad) + || (sess->send_rtcp_src_ghost == pad)) return sess; } return NULL; @@ -2126,7 +2127,7 @@ link_failed: } static void -remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) +remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session) { if (session->demux_newpad_sig) { g_signal_handler_disconnect (session->demux, session->demux_newpad_sig); @@ -2145,10 +2146,12 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) gst_object_unref (session->recv_rtp_sink); session->recv_rtp_sink = NULL; } - - gst_pad_set_active (pad, FALSE); - gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); - session->recv_rtp_sink_ghost = NULL; + if (session->recv_rtp_sink_ghost) { + gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), + session->recv_rtp_sink_ghost); + session->recv_rtp_sink_ghost = NULL; + } } /* Create a pad for receiving RTCP for the session in @name. Must be called with @@ -2235,12 +2238,14 @@ link_failed: } static void -remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) +remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session) { - session->recv_rtcp_sink_ghost = NULL; - gst_pad_set_active (pad, FALSE); - gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); - + if (session->recv_rtcp_sink_ghost) { + gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), + session->recv_rtcp_sink_ghost); + session->recv_rtcp_sink_ghost = NULL; + } if (session->sync_src) { /* releasing the request pad should also unref the sync pad */ gst_object_unref (session->sync_src); @@ -2335,7 +2340,7 @@ no_srcpad: } static void -remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) +remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session) { if (session->send_rtp_src_ghost) { gst_pad_set_active (session->send_rtp_src_ghost, FALSE); @@ -2343,22 +2348,22 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) session->send_rtp_src_ghost); session->send_rtp_src_ghost = NULL; } - if (session->send_rtp_src) { gst_object_unref (session->send_rtp_src); session->send_rtp_src = NULL; } - if (session->send_rtp_sink) { gst_element_release_request_pad (GST_ELEMENT_CAST (session->session), session->send_rtp_sink); gst_object_unref (session->send_rtp_sink); session->send_rtp_sink = NULL; } - - session->send_rtp_sink_ghost = NULL; - gst_pad_set_active (pad, FALSE); - gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); + if (session->send_rtp_sink_ghost) { + gst_pad_set_active (session->send_rtp_sink_ghost, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), + session->send_rtp_sink_ghost); + session->send_rtp_sink_ghost = NULL; + } } /* Create a pad for sending RTCP for the session in @name. Must be called with @@ -2415,12 +2420,14 @@ pad_failed: } static void -remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad) +remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session) { - session->send_rtcp_src_ghost = NULL; - gst_pad_set_active (pad, FALSE); - gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), pad); - + if (session->send_rtcp_src_ghost) { + gst_pad_set_active (session->send_rtcp_src_ghost, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin), + session->send_rtcp_src_ghost); + session->send_rtcp_src_ghost = NULL; + } if (session->send_rtcp_src) { gst_element_release_request_pad (session->session, session->send_rtcp_src); gst_object_unref (session->send_rtcp_src); @@ -2526,51 +2533,46 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad) { GstRtpBinSession *session; GstRtpBin *rtpbin; - GstPad *target = NULL; g_return_if_fail (GST_IS_GHOST_PAD (pad)); g_return_if_fail (GST_IS_RTP_BIN (element)); rtpbin = GST_RTP_BIN (element); - target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); - g_return_if_fail (target); - GST_RTP_BIN_LOCK (rtpbin); GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s", - GST_DEBUG_PAD_NAME (target)); + GST_DEBUG_PAD_NAME (pad)); - if (!(session = find_session_by_pad (rtpbin, target))) + if (!(session = find_session_by_pad (rtpbin, pad))) goto unknown_pad; - if (session->recv_rtp_sink == target) { - remove_recv_rtp (rtpbin, session, pad); - } else if (session->recv_rtcp_sink == target) { - remove_recv_rtcp (rtpbin, session, pad); - } else if (session->send_rtp_sink == target) { - remove_send_rtp (rtpbin, session, pad); - } else if (session->send_rtcp_src == target) { - remove_rtcp (rtpbin, session, pad); + if (session->recv_rtp_sink_ghost == pad) { + remove_recv_rtp (rtpbin, session); + } else if (session->recv_rtcp_sink_ghost == pad) { + remove_recv_rtcp (rtpbin, session); + } else if (session->send_rtp_sink_ghost == pad) { + remove_send_rtp (rtpbin, session); + } else if (session->send_rtcp_src_ghost == pad) { + remove_rtcp (rtpbin, session); } /* no more request pads, free the complete session */ - if (session->recv_rtp_sink == NULL && session->recv_rtcp_sink == NULL && - session->send_rtp_sink == NULL && session->send_rtcp_src == NULL) { + if (session->recv_rtp_sink_ghost == NULL + && session->recv_rtcp_sink_ghost == NULL + && session->send_rtp_sink_ghost == NULL + && session->send_rtcp_src_ghost == NULL) { GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session); rtpbin->sessions = g_slist_remove (rtpbin->sessions, session); free_session (session, rtpbin); } GST_RTP_BIN_UNLOCK (rtpbin); - gst_object_unref (target); - return; /* ERROR */ unknown_pad: { GST_RTP_BIN_UNLOCK (rtpbin); - gst_object_unref (target); g_warning ("gstrtpbin: %s:%s is not one of our request pads", GST_DEBUG_PAD_NAME (pad)); return; -- cgit v1.2.1 From 0d014baaa4c61010c98c6899cd2338da1423014b Mon Sep 17 00:00:00 2001 From: Ali Sabil Date: Fri, 22 May 2009 16:35:20 +0200 Subject: ssrcdemux: emit signal when pads are removed Add action signal to clear an SSRC in the ssrc demuxer. Add signal to notify of removed ssrc. See #554839 --- gst/rtpmanager/gstrtpbin-marshal.list | 1 + gst/rtpmanager/gstrtpssrcdemux.c | 74 +++++++++++++++++++++++++++++++++++ gst/rtpmanager/gstrtpssrcdemux.h | 6 ++- 3 files changed, 80 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin-marshal.list b/gst/rtpmanager/gstrtpbin-marshal.list index c4bc0bb2..ed73e43b 100644 --- a/gst/rtpmanager/gstrtpbin-marshal.list +++ b/gst/rtpmanager/gstrtpbin-marshal.list @@ -3,5 +3,6 @@ BOXED:UINT BOXED:UINT,UINT OBJECT:UINT VOID:UINT,OBJECT +VOID:UINT VOID:UINT,UINT VOID:OBJECT,OBJECT diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c index b9a279c2..6a305d8e 100644 --- a/gst/rtpmanager/gstrtpssrcdemux.c +++ b/gst/rtpmanager/gstrtpssrcdemux.c @@ -97,6 +97,8 @@ static GstElementDetails gst_rtp_ssrc_demux_details = { enum { SIGNAL_NEW_SSRC_PAD, + SIGNAL_REMOVED_SSRC_PAD, + SIGNAL_CLEAR_SSRC, LAST_SIGNAL }; @@ -112,6 +114,9 @@ static void gst_rtp_ssrc_demux_finalize (GObject * object); static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement * element, GstStateChange transition); +static void gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, + guint32 ssrc); + /* sinkpad stuff */ static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf); static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event); @@ -245,9 +250,11 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass) { GObjectClass *gobject_klass; GstElementClass *gstelement_klass; + GstRtpSsrcDemuxClass *gstrtpssrcdemux_klass; gobject_klass = (GObjectClass *) klass; gstelement_klass = (GstElementClass *) klass; + gstrtpssrcdemux_klass = (GstRtpSsrcDemuxClass *) klass; gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_dispose); gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_finalize); @@ -267,8 +274,38 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass) NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT, G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD); + /** + * GstRtpSsrcDemux::removed-ssrc-pad: + * @demux: the object which received the signal + * @ssrc: the SSRC of the pad + * @pad: the removed pad. + * + * Emited when a SSRC pad has been removed. + */ + gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD] = + g_signal_new ("removed-ssrc-pad", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, removed_ssrc_pad), + NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT, + G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD); + + /** + * GstRtpSsrcDemux::clear-ssrc: + * @demux: the object which received the signal + * @ssrc: the SSRC of the pad + * + * Action signal to remove the pad for SSRC. + */ + gst_rtp_ssrc_demux_signals[SIGNAL_CLEAR_SSRC] = + g_signal_new ("clear-ssrc", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, clear_ssrc), + NULL, NULL, gst_rtp_bin_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); + gstelement_klass->change_state = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state); + gstrtpssrcdemux_klass->clear_ssrc = + GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_clear_ssrc); GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug, "rtpssrcdemux", 0, "RTP SSRC demuxer"); @@ -342,6 +379,43 @@ gst_rtp_ssrc_demux_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc) +{ + GstRtpSsrcDemuxPad *dpad; + + GST_PAD_LOCK (demux); + dpad = find_demux_pad_for_ssrc (demux, ssrc); + if (dpad != NULL) + goto unknown_pad; + + GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc); + + demux->srcpads = g_slist_remove (demux->srcpads, dpad); + GST_PAD_UNLOCK (demux); + + gst_pad_set_active (dpad->rtp_pad, FALSE); + gst_pad_set_active (dpad->rtcp_pad, FALSE); + + g_signal_emit (G_OBJECT (demux), + gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc, + dpad->rtp_pad); + + gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad); + gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad); + + g_free (dpad); + + return; + + /* ERRORS */ +unknown_pad: + { + g_warning ("unknown SSRC %08x", ssrc); + return; + } +} + static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event) { diff --git a/gst/rtpmanager/gstrtpssrcdemux.h b/gst/rtpmanager/gstrtpssrcdemux.h index d89472af..d5a13caf 100644 --- a/gst/rtpmanager/gstrtpssrcdemux.h +++ b/gst/rtpmanager/gstrtpssrcdemux.h @@ -50,7 +50,11 @@ struct _GstRtpSsrcDemuxClass GstElementClass parent_class; /* signals */ - void (*new_ssrc_pad) (GstElement *element, guint32 ssrc, GstPad *pad); + void (*new_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad); + void (*removed_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad); + + /* actions */ + void (*clear_ssrc) (GstRtpSsrcDemux *demux, guint32 ssrc); }; GType gst_rtp_ssrc_demux_get_type (void); -- cgit v1.2.1 From e8423da78eea949f8223da5c27ea36544a3a6c5b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 22 May 2009 16:41:19 +0200 Subject: rtpbin: add to new signal to remove SSRC pads --- gst/rtpmanager/gstrtpbin.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index f7d7e54a..017ffc02 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -493,27 +493,18 @@ find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc) } static void -ssrc_demux_pad_removed (GstElement * element, GstPad * pad, +ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad, GstRtpBinSession * session) { - guint ssrc; GstRtpBinStream *stream = NULL; - gchar *name; - gint res; - - name = gst_pad_get_name (pad); - res = sscanf (name, "src_%d", &ssrc); - g_free (name); - - if (res != 1) - return; GST_RTP_SESSION_LOCK (session); - if ((stream = find_stream_by_ssrc (session, ssrc))) { + if ((stream = find_stream_by_ssrc (session, ssrc))) session->streams = g_slist_remove (session->streams, stream); - free_stream (stream); - } GST_RTP_SESSION_UNLOCK (session); + + if (stream) + free_stream (stream); } /* create a session with the given id. Must be called with RTP_BIN_LOCK */ @@ -2093,7 +2084,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) session->demux_newpad_sig = g_signal_connect (session->demux, "new-ssrc-pad", (GCallback) new_ssrc_pad_found, session); session->demux_padremoved_sig = g_signal_connect (session->demux, - "pad-removed", (GCallback) ssrc_demux_pad_removed, session); + "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session); GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad"); session->recv_rtp_sink_ghost = -- cgit v1.2.1 From 0444aa33747e0f8c2a59d682668b4b41b7ac23e3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 20 May 2009 16:46:49 +0200 Subject: mpegvideoparse: Detect interlaced content and set it on outgoing caps. I also added the parsing of all the other bits in the sequence extension header in case we need it later. --- gst/mpegvideoparse/mpegpacketiser.c | 7 +++++++ gst/mpegvideoparse/mpegpacketiser.h | 2 ++ gst/mpegvideoparse/mpegvideoparse.c | 1 + 3 files changed, 10 insertions(+) (limited to 'gst') diff --git a/gst/mpegvideoparse/mpegpacketiser.c b/gst/mpegvideoparse/mpegpacketiser.c index 447c50ae..0312680e 100644 --- a/gst/mpegvideoparse/mpegpacketiser.c +++ b/gst/mpegvideoparse/mpegpacketiser.c @@ -498,6 +498,9 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) case MPEG_PACKET_EXT_SEQUENCE: { /* Parse a Sequence Extension */ + guint8 profile_level; + gboolean low_delay; + guint8 chroma_format; guint8 horiz_size_ext, vert_size_ext; guint8 fps_n_ext, fps_d_ext; @@ -505,8 +508,12 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) /* need at least 10 bytes, minus 4 for the start code 000001b5 */ return FALSE; + profile_level = ((data[0] << 4) & 0xf0) | ((data[1]) >> 4); + hdr->progressive = data[1] & 0x08; + chroma_format = (data[1] >> 2) & 0x03; horiz_size_ext = ((data[1] << 1) & 0x02) | ((data[2] >> 7) & 0x01); vert_size_ext = (data[2] >> 5) & 0x03; + low_delay = data[5] >> 7; fps_n_ext = (data[5] >> 5) & 0x03; fps_d_ext = data[5] & 0x1f; diff --git a/gst/mpegvideoparse/mpegpacketiser.h b/gst/mpegvideoparse/mpegpacketiser.h index 426b13aa..549ca621 100644 --- a/gst/mpegvideoparse/mpegpacketiser.h +++ b/gst/mpegvideoparse/mpegpacketiser.h @@ -76,6 +76,8 @@ struct MPEGSeqHdr gint width, height; /* Framerate */ gint fps_n, fps_d; + + gboolean progressive; }; struct MPEGPictureHdr diff --git a/gst/mpegvideoparse/mpegvideoparse.c b/gst/mpegvideoparse/mpegvideoparse.c index 3c930179..2a7f9153 100644 --- a/gst/mpegvideoparse/mpegvideoparse.c +++ b/gst/mpegvideoparse/mpegvideoparse.c @@ -261,6 +261,7 @@ mpegvideoparse_handle_sequence (MpegVideoParse * mpegvideoparse, "height", G_TYPE_INT, new_hdr.height, "framerate", GST_TYPE_FRACTION, new_hdr.fps_n, new_hdr.fps_d, "pixel-aspect-ratio", GST_TYPE_FRACTION, new_hdr.par_w, new_hdr.par_h, + "interlaced", G_TYPE_BOOLEAN, !new_hdr.progressive, "codec_data", GST_TYPE_BUFFER, seq_buf, NULL); GST_DEBUG ("New mpegvideoparse caps: %" GST_PTR_FORMAT, caps); -- cgit v1.2.1 From 1a98c66f4a446a496b1362542da8eda887498103 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 22 May 2009 16:56:52 -0700 Subject: adpcmdec: Add new plugin for ms-adpcm decoding. --- gst/adpcmdec/Makefile.am | 12 ++ gst/adpcmdec/adpcmdec.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 gst/adpcmdec/Makefile.am create mode 100644 gst/adpcmdec/adpcmdec.c (limited to 'gst') diff --git a/gst/adpcmdec/Makefile.am b/gst/adpcmdec/Makefile.am new file mode 100644 index 00000000..5c60ad4f --- /dev/null +++ b/gst/adpcmdec/Makefile.am @@ -0,0 +1,12 @@ +plugin_LTLIBRARIES = libgstadpcmdec.la + +# sources used to compile this plug-in +libgstadpcmdec_la_SOURCES = adpcmdec.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstadpcmdec_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) +libgstadpcmdec_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) +libgstadpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstadpcmdec_la_LIBTOOLFLAGS = --tag=disable-static + diff --git a/gst/adpcmdec/adpcmdec.c b/gst/adpcmdec/adpcmdec.c new file mode 100644 index 00000000..c58dc5d8 --- /dev/null +++ b/gst/adpcmdec/adpcmdec.c @@ -0,0 +1,452 @@ +/* GStreamer + * Copyright (C) 2009 Pioneers of the Inevitable + * + * Authors: Michael Smith + * + * 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. + */ + +/* Based on MS-ADPCM decoder in libsndfile, + Copyright (C) 1999-2002 Erik de Castro Lopo +#include + +#define GST_TYPE_ADPCM_DEC \ + (adpcmdec_get_type ()) + +#define GST_ADPCM_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ADPCM_DEC, ADPCMDec)) + +#define GST_CAT_DEFAULT adpcmdec_debug +GST_DEBUG_CATEGORY_STATIC (adpcmdec_debug); + +static const GstElementDetails adpcmdec_details = +GST_ELEMENT_DETAILS ("MS-ADPCM decoder", + "Codec/Decoder/Audio", + "Decode MS AD-PCM audio", + "Pioneers of the Inevitable output_caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, dec->rate, + "channels", G_TYPE_INT, dec->channels, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + + if (dec->output_caps) { + gst_pad_set_caps (dec->srcpad, dec->output_caps); + } + + dec->is_setup = TRUE; + dec->timestamp = GST_CLOCK_TIME_NONE; + dec->adapter = gst_adapter_new (); + dec->out_samples = 0; + + return gst_pad_push_event (dec->srcpad, gst_event_new_new_segment (FALSE, + 1.0, GST_FORMAT_TIME, 0, -1, 0)); +} + +static void +adpcmdec_teardown (ADPCMDec * dec) +{ + if (dec->output_caps) { + gst_caps_unref (dec->output_caps); + dec->output_caps = NULL; + } + if (dec->adapter) { + g_object_unref (dec->adapter); + dec->adapter = NULL; + } + dec->is_setup = FALSE; +} + +static gboolean +adpcmdec_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad); + GstStructure *structure = gst_caps_get_structure (caps, 0); + + if (!gst_structure_get_int (structure, "block_align", &dec->blocksize)) + return FALSE; + if (!gst_structure_get_int (structure, "rate", &dec->rate)) + return FALSE; + if (!gst_structure_get_int (structure, "channels", &dec->channels)) + return FALSE; + + if (dec->is_setup) + adpcmdec_teardown (dec); + gst_object_unref (dec); + + return TRUE; +} + + +/*===================================================================== + * From libsndfile: + * + * MS ADPCM Block Layout. + * ====================== + * Block is usually 256, 512 or 1024 bytes depending on sample rate. + * For a mono file, the block is laid out as follows: + * byte purpose + * 0 block predictor [0..6] + * 1,2 initial idelta (positive) + * 3,4 sample 1 + * 5,6 sample 0 + * 7..n packed bytecodes + * + * For a stereo file, the block is laid out as follows: + * byte purpose + * 0 block predictor [0..6] for left channel + * 1 block predictor [0..6] for right channel + * 2,3 initial idelta (positive) for left channel + * 4,5 initial idelta (positive) for right channel + * 6,7 sample 1 for left channel + * 8,9 sample 1 for right channel + * 10,11 sample 0 for left channel + * 12,13 sample 0 for right channel + * 14..n packed bytecodes + * + *===================================================================== +*/ +static int AdaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +static int AdaptCoeff1[] = { + 256, 512, 0, 192, 240, 460, 392 +}; + +static int AdaptCoeff2[] = { + 0, -256, 0, 64, 0, -208, -232 +}; + +static gint16 +read_sample (guint8 * data) +{ + guint16 val = data[0] | (data[1] << 8); + return *((gint16 *) & val); +} + +/* Decode a single block of data from 'data', storing 'n_samples' decoded 16 bit + samples in 'samples'. + + All buffer lengths have been verified by the caller + */ +static gboolean +adpcmdec_decode_ms_block (ADPCMDec * dec, int n_samples, guint8 * data, + gint16 * samples) +{ + gint16 pred[2]; + gint16 idelta[2]; + int idx; /* Current byte offset in 'data' */ + int i; /* Current sample index in 'samples' */ + + /* Read the block header, verify for sanity */ + if (dec->channels == 1) { + pred[0] = data[0]; + idelta[0] = read_sample (data + 1); + samples[1] = read_sample (data + 3); + samples[0] = read_sample (data + 5); + idx = 7; + i = 2; + if (pred[0] < 0 || pred[0] > 6) { + GST_WARNING_OBJECT (dec, "Invalid block predictor"); + return FALSE; + } + } + + else { + pred[0] = data[0]; + pred[1] = data[1]; + idelta[0] = read_sample (data + 2); + idelta[1] = read_sample (data + 4); + samples[2] = read_sample (data + 6); + samples[3] = read_sample (data + 8); + samples[0] = read_sample (data + 10); + samples[1] = read_sample (data + 12); + idx = 14; + i = 4; + if (pred[0] < 0 || pred[0] > 6 || pred[1] < 0 || pred[1] > 6) { + GST_WARNING_OBJECT (dec, "Invalid block predictor"); + return FALSE; + } + } + for (; i < n_samples; i++) { + int chan = i % dec->channels; + int bytecode; + int delta; + int current; + int predict; + if (i % 2 == 0) { + bytecode = (data[idx] >> 4) & 0x0F; + } else { + bytecode = data[idx] & 0x0F; + idx++; + } + + delta = idelta[chan]; + idelta[chan] = (AdaptationTable[bytecode] * delta) >> 8; + if (idelta[chan] < 16) + idelta[chan] = 16; + + /* Bytecode is used above as an index into the table. Below, it's used + as a signed 4-bit value; convert appropriately */ + if (bytecode & 0x8) + bytecode -= 0x10; + + predict = ((samples[i - dec->channels] * AdaptCoeff1[pred[chan]]) + + (samples[i - 2 * dec->channels] * AdaptCoeff2[pred[chan]]) + ) >> 8; + + current = (bytecode * delta) + predict; + + /* Clamp to 16 bits, store decoded sample */ + samples[i] = CLAMP (current, G_MININT16, G_MAXINT16); + } + return TRUE; +} + +static GstFlowReturn +adpcmdec_chain (GstPad * pad, GstBuffer * buf) +{ + ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad); + GstFlowReturn ret = GST_FLOW_OK; + guint8 *data; + GstBuffer *outbuf = NULL; + GstBuffer *databuf = NULL; + int outsize; + int samples; + gboolean res; + + if (!dec->is_setup) + adpcmdec_setup (dec); + + if (dec->timestamp == GST_CLOCK_TIME_NONE) + dec->timestamp = GST_BUFFER_TIMESTAMP (buf); + + gst_adapter_push (dec->adapter, buf); + + while (gst_adapter_available (dec->adapter) >= dec->blocksize) { + databuf = gst_adapter_take_buffer (dec->adapter, dec->blocksize); + data = GST_BUFFER_DATA (databuf); + + /* Each block has a 3 byte header per channel, plus 4 bytes per channel to + give two initial sample values per channel. Then the remainder gives + two samples per byte */ + samples = (dec->blocksize - 7 * dec->channels) * 2 + 2 * dec->channels; + outsize = 2 * samples; + outbuf = gst_buffer_new_and_alloc (outsize); + + res = adpcmdec_decode_ms_block (dec, samples, data, + (gint16 *) (GST_BUFFER_DATA (outbuf))); + + /* Done with input data, free it */ + gst_buffer_unref (databuf); + + if (!res) { + gst_buffer_unref (outbuf); + GST_WARNING_OBJECT (dec, "Decode of block failed"); + ret = GST_FLOW_ERROR; + goto done; + } + + gst_buffer_set_caps (outbuf, dec->output_caps); + GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp; + dec->out_samples += samples / dec->channels; + dec->timestamp = + gst_util_uint64_scale_int (dec->out_samples, GST_SECOND, dec->rate); + GST_BUFFER_DURATION (outbuf) = + dec->timestamp - GST_BUFFER_TIMESTAMP (outbuf); + + ret = gst_pad_push (dec->srcpad, outbuf); + if (ret != GST_FLOW_OK) + goto done; + } + +done: + gst_object_unref (dec); + + return ret; +} + +static gboolean +adpcmdec_sink_event (GstPad * pad, GstEvent * event) +{ + ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad); + gboolean res; + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_STOP: + gst_adapter_clear (dec->adapter); + /* Fall through */ + default: + res = gst_pad_push_event (dec->srcpad, event); + break; + } + gst_object_unref (dec); + return res; +} + +static GstStateChangeReturn +adpcmdec_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret; + ADPCMDec *dec = (ADPCMDec *) element; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + adpcmdec_teardown (dec); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + return ret; +} + +static void +adpcmdec_dispose (GObject * obj) +{ + G_OBJECT_CLASS (parent_class)->dispose (obj); +} + +static void +adpcmdec_init (ADPCMDec * dec, ADPCMDecClass * klass) +{ + dec->sinkpad = + gst_pad_new_from_static_template (&adpcmdec_sink_template, "sink"); + gst_pad_set_setcaps_function (dec->sinkpad, + GST_DEBUG_FUNCPTR (adpcmdec_sink_setcaps)); + gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (adpcmdec_chain)); + gst_pad_set_event_function (dec->sinkpad, + GST_DEBUG_FUNCPTR (adpcmdec_sink_event)); + gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); + dec->srcpad = + gst_pad_new_from_static_template (&adpcmdec_src_template, "src"); + gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); +} + +static void +adpcmdec_class_init (ADPCMDecClass * klass) +{ + GObjectClass *gobjectclass = (GObjectClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; + gobjectclass->dispose = adpcmdec_dispose; + gstelement_class->change_state = adpcmdec_change_state; +} static void + +adpcmdec_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&adpcmdec_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&adpcmdec_src_template)); + gst_element_class_set_details (element_class, &adpcmdec_details); +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (adpcmdec_debug, "adpcmdec", 0, "ADPCM Decoders"); + if (!gst_element_register (plugin, "msadpcmdec", GST_RANK_PRIMARY, + GST_TYPE_ADPCM_DEC)) { + return FALSE; + } + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "adpcmdec", + "ADPCM decoder", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN); -- cgit v1.2.1 From 269f3ff1a270e1c3cd9b6204c7171d47eb7dfbf1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 25 May 2009 13:46:29 +0200 Subject: rtpbin: remove ptdemux ghostpads --- gst/rtpmanager/gstrtpbin.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gst') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 017ffc02..19de4f1b 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -306,6 +306,8 @@ struct _GstRtpBinStream gulong demux_newpad_sig; gulong demux_ptreq_sig; gulong demux_pt_change_sig; + /* ghostpads from the ptdemuxer */ + GSList *pads; /* if we have calculated a valid unix_delta for this stream */ gboolean have_sync; @@ -1169,6 +1171,7 @@ static void free_stream (GstRtpBinStream * stream) { GstRtpBinSession *session; + GSList *walk; session = stream->session; @@ -1184,6 +1187,14 @@ free_stream (GstRtpBinStream * stream) gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer); gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux); + for (walk = stream->pads; walk; walk = g_slist_next (walk)) { + GstPad *gpad = GST_PAD_CAST (walk->data); + + gst_pad_set_active (gpad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (session->bin), gpad); + } + g_slist_free (stream->pads); + g_free (stream); } @@ -1880,6 +1891,8 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad, gst_pad_set_active (gpad, TRUE); gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad); + stream->pads = g_slist_prepend (stream->pads, gpad); + GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin); return; -- cgit v1.2.1 From f92f282874addd1091e2d03b25033a12f151eb83 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 15:21:12 +0200 Subject: mpegtsdemux: Add mapping for HDV private streams --- gst/mpegdemux/gstmpegdefs.h | 2 ++ gst/mpegdemux/gstmpegtsdemux.c | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegdefs.h b/gst/mpegdemux/gstmpegdefs.h index 7f38f4de..d63667d8 100644 --- a/gst/mpegdemux/gstmpegdefs.h +++ b/gst/mpegdemux/gstmpegdefs.h @@ -170,6 +170,8 @@ #define ST_PS_AUDIO_AC3 0x81 #define ST_PS_AUDIO_DTS 0x8a #define ST_PS_AUDIO_LPCM 0x8b +#define ST_HDV_PRIVATE_A0 0xa0 +#define ST_HDV_PRIVATE_A1 0xa1 #define ST_PS_DVD_SUBPICTURE 0xff /* Un-official time-code stream */ diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 6438e880..a4d32e36 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -620,6 +620,16 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, caps = gst_caps_new_simple ("private/teletext", NULL); } break; + case ST_HDV_PRIVATE_A0: + template = klass->private_template; + name = g_strdup_printf ("private_%04x", stream->PID); + caps = gst_caps_new_simple ("private/hdv-a0", NULL); + break; + case ST_HDV_PRIVATE_A1: + template = klass->private_template; + name = g_strdup_printf ("private_%04x", stream->PID); + caps = gst_caps_new_simple ("private/hdv-a1", NULL); + break; case ST_PRIVATE_SECTIONS: case ST_MHEG: case ST_DSMCC: -- cgit v1.2.1 From 36cc757bdacbfbeadfce70040fd424b5e7bb2e8b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 15:21:52 +0200 Subject: mpegtsdemux: Ignore NULL packets as early as possible. This avoids: * creating a MpegTSStream structure for nothing * processing packet data for nothing --- gst/mpegdemux/gstmpegtsdemux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index a4d32e36..cd64a295 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -2347,7 +2347,7 @@ static FORCE_INLINE GstFlowReturn gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, const guint8 * data) { - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; guint16 PID; GstMpegTSStream *stream; @@ -2357,6 +2357,10 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, /* get PID */ PID = ((data[0] & 0x1f) << 8) | data[1]; + /* Skip NULL packets */ + if (G_UNLIKELY (PID == 0x1fff)) + goto beach; + /* get the stream. */ stream = gst_mpegts_demux_get_stream_for_PID (demux, PID); @@ -2387,6 +2391,8 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, demux->num_packets = -1; } } + +beach: demux->num_packets++; return ret; -- cgit v1.2.1 From 849ea993587746eff034f5788569e7a991af716b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 16:25:42 +0200 Subject: gstpesfilter: Don't skip private streams PES but push them out. The one thing we *DO* need to do for those streams is to skip all the PTS/DTS/Scrambling/DSM/extension/... handling. --- gst/mpegdemux/gstpesfilter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index 1295a193..a2a6b764 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -189,7 +189,8 @@ gst_pes_filter_parse (GstPESFilter * filter) case ID_PROGRAM_STREAM_DIRECTORY: case ID_DSMCC_STREAM: case ID_ITU_TREC_H222_TYPE_E_STREAM: - goto skip; + /* Push directly out */ + goto push_out; case ID_PADDING_STREAM: GST_DEBUG ("skipping padding stream"); goto skip; @@ -404,6 +405,7 @@ gst_pes_filter_parse (GstPESFilter * filter) goto lost_sync; } +push_out: { GstBuffer *out; guint16 consumed; -- cgit v1.2.1 From 410d8f891035656606382c423e57ae289c17a9be Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 16:27:34 +0200 Subject: gstpesfilter: Don't peek the adapter if we don't have enough data. --- gst/mpegdemux/gstpesfilter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index a2a6b764..4285c940 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -167,6 +167,9 @@ gst_pes_filter_parse (GstPESFilter * filter) avail = MIN (avail, filter->length + 6); } + if (avail < 7) + goto need_more_data; + /* read more data, either the whole packet if there is a length * or whatever we have available if this in an unbounded packet. */ if (!(data = gst_adapter_peek (filter->adapter, avail))) @@ -198,9 +201,6 @@ gst_pes_filter_parse (GstPESFilter * filter) break; } - if (datalen < 1) - goto need_more_data; - filter->pts = filter->dts = -1; /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is -- cgit v1.2.1 From 023af351fba4b22db782b39f4aa8ae75b70cc10f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 19:30:34 +0200 Subject: gstpesfilter: Directly use gst_adapter_take_buffer(). --- gst/mpegdemux/gstpesfilter.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'gst') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index 4285c940..b520c766 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -565,14 +565,8 @@ gst_pes_filter_process (GstPESFilter * filter) ret = GST_FLOW_OK; } else { GstBuffer *out; - guint8 *data; - data = gst_adapter_take (filter->adapter, avail); - - out = gst_buffer_new (); - GST_BUFFER_DATA (out) = data; - GST_BUFFER_SIZE (out) = avail; - GST_BUFFER_MALLOCDATA (out) = data; + out = gst_adapter_take_buffer (filter->adapter, avail); ret = gst_pes_filter_data_push (filter, filter->first, out); filter->first = FALSE; -- cgit v1.2.1