From 2ae18972734cba00a3dc3559c5affbef8ba4f714 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 5 Feb 2014 10:27:54 -0300 Subject: [PATCH] qtmux: add subtitle support to qtmuxmap structures adds basic stubs for subtitle support around the qtmux and qtmuxmap structures. Still no real subtitle implemented, but basic functions in place https://bugzilla.gnome.org/show_bug.cgi?id=581295 --- gst/isomp4/gstqtmux.c | 103 +++++++++++++++++++++++++++++++++++++---------- gst/isomp4/gstqtmux.h | 7 +++- gst/isomp4/gstqtmuxmap.c | 20 ++++----- gst/isomp4/gstqtmuxmap.h | 1 + 4 files changed, 98 insertions(+), 33 deletions(-) diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 3231963..085542b 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -235,7 +235,8 @@ gst_qt_mux_base_init (gpointer g_class) GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstQTMuxClass *klass = (GstQTMuxClass *) g_class; GstQTMuxClassParams *params; - GstPadTemplate *videosinktempl, *audiosinktempl, *srctempl; + GstPadTemplate *videosinktempl, *audiosinktempl, *subtitlesinktempl; + GstPadTemplate *srctempl; gchar *longname, *description; params = @@ -270,6 +271,12 @@ gst_qt_mux_base_init (gpointer g_class) gst_element_class_add_pad_template (element_class, videosinktempl); } + if (params->subtitle_sink_caps) { + subtitlesinktempl = gst_pad_template_new ("subtitle_%u", + GST_PAD_SINK, GST_PAD_REQUEST, params->subtitle_sink_caps); + gst_element_class_add_pad_template (element_class, subtitlesinktempl); + } + klass->format = params->prop->format; } @@ -2478,11 +2485,11 @@ gst_qtmux_caps_is_subset_full (GstQTMux * qtmux, GstCaps * subset, } static gboolean -gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) +gst_qt_mux_audio_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) { + GstPad *pad = qtpad->collect.pad; GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad)); GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux)); - GstQTPad *qtpad = NULL; GstStructure *structure; const gchar *mimetype; gint rate, channels; @@ -2494,10 +2501,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) gint constant_size = 0; const gchar *stream_format; - /* find stream data */ - qtpad = (GstQTPad *) gst_pad_get_element_private (pad); - g_assert (qtpad); - qtpad->prepare_buf_func = NULL; /* does not go well to renegotiate stream mid-way, unless @@ -2794,11 +2797,11 @@ adjust_rate (guint64 rate) } static gboolean -gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) +gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) { + GstPad *pad = qtpad->collect.pad; GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad)); GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux)); - GstQTPad *qtpad = NULL; GstStructure *structure; const gchar *mimetype; gint width, height, depth = -1; @@ -2813,10 +2816,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) gboolean sync = FALSE; int par_num, par_den; - /* find stream data */ - qtpad = (GstQTPad *) gst_pad_get_element_private (pad); - g_assert (qtpad); - qtpad->prepare_buf_func = NULL; /* does not go well to renegotiate stream mid-way, unless @@ -3139,6 +3138,57 @@ refuse_renegotiation: } static gboolean +gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) +{ + GstPad *pad = qtpad->collect.pad; + GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad)); + + qtpad->prepare_buf_func = NULL; + + /* does not go well to renegotiate stream mid-way, unless + * the old caps are a subset of the new one (this means upstream + * added more info to the caps, as both should be 'fixed' caps) */ + if (qtpad->fourcc) { + GstCaps *current_caps; + + current_caps = gst_pad_get_current_caps (pad); + g_assert (caps != NULL); + + if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) { + gst_caps_unref (current_caps); + goto refuse_renegotiation; + } + GST_DEBUG_OBJECT (qtmux, + "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %" + GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps); + gst_caps_unref (current_caps); + } + + GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT, + GST_DEBUG_PAD_NAME (pad), caps); + + /* subtitles default */ + qtpad->is_out_of_order = FALSE; + qtpad->sync = FALSE; + + /* TODO fill me */ + + gst_object_unref (qtmux); + /* not implemented */ + return FALSE; + + /* ERRORS */ +refuse_renegotiation: + { + GST_WARNING_OBJECT (qtmux, + "pad %s refused renegotiation to %" GST_PTR_FORMAT, GST_PAD_NAME (pad), + caps); + gst_object_unref (qtmux); + return FALSE; + } +} + +static gboolean gst_qt_mux_sink_event (GstCollectPads * pads, GstCollectData * data, GstEvent * event, gpointer user_data) { @@ -3161,7 +3211,7 @@ gst_qt_mux_sink_event (GstCollectPads * pads, GstCollectData * data, g_assert (collect_pad); g_assert (collect_pad->set_caps); - ret = collect_pad->set_caps (pad, caps); + ret = collect_pad->set_caps (collect_pad, caps); gst_event_unref (event); event = NULL; break; @@ -3253,7 +3303,7 @@ gst_qt_mux_request_new_pad (GstElement * element, GstQTMux *qtmux = GST_QT_MUX_CAST (element); GstQTPad *collect_pad; GstPad *newpad; - gboolean audio; + GstQTPadSetCapsFunc setcaps_func; gchar *name; gint pad_id; @@ -3264,19 +3314,26 @@ gst_qt_mux_request_new_pad (GstElement * element, goto too_late; if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) { - audio = TRUE; + setcaps_func = gst_qt_mux_audio_sink_set_caps; if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) { name = g_strdup (req_name); } else { name = g_strdup_printf ("audio_%u", qtmux->audio_pads++); } } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) { - audio = FALSE; + setcaps_func = gst_qt_mux_video_sink_set_caps; if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) { name = g_strdup (req_name); } else { name = g_strdup_printf ("video_%u", qtmux->video_pads++); } + } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) { + setcaps_func = gst_qt_mux_subtitle_sink_set_caps; + if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) { + name = g_strdup (req_name); + } else { + name = g_strdup_printf ("subtitle_%u", qtmux->subtitle_pads++); + } } else goto wrong_template; @@ -3296,10 +3353,7 @@ gst_qt_mux_request_new_pad (GstElement * element, qtmux->sinkpads = g_slist_append (qtmux->sinkpads, collect_pad); /* set up pad functions */ - if (audio) - collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_audio_sink_set_caps); - else - collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps); + collect_pad->set_caps = setcaps_func; gst_pad_set_active (newpad, TRUE); gst_element_add_pad (element, newpad); @@ -3506,6 +3560,7 @@ gst_qt_mux_register (GstPlugin * plugin) while (TRUE) { GstQTMuxFormatProp *prop; + GstCaps *subtitle_caps; prop = &gst_qt_mux_format_list[i]; format = prop->format; @@ -3518,6 +3573,12 @@ gst_qt_mux_register (GstPlugin * plugin) params->src_caps = gst_static_caps_get (&prop->src_caps); params->video_sink_caps = gst_static_caps_get (&prop->video_sink_caps); params->audio_sink_caps = gst_static_caps_get (&prop->audio_sink_caps); + subtitle_caps = gst_static_caps_get (&prop->subtitle_sink_caps); + if (!gst_caps_is_equal (subtitle_caps, GST_CAPS_NONE)) { + params->subtitle_sink_caps = subtitle_caps; + } else { + gst_caps_unref (subtitle_caps); + } /* create the type now */ type = g_type_register_static (GST_TYPE_ELEMENT, prop->type_name, &typeinfo, diff --git a/gst/isomp4/gstqtmux.h b/gst/isomp4/gstqtmux.h index e61831d..277283f 100644 --- a/gst/isomp4/gstqtmux.h +++ b/gst/isomp4/gstqtmux.h @@ -78,6 +78,8 @@ typedef struct _GstQTPad GstQTPad; typedef GstBuffer * (*GstQTPadPrepareBufferFunc) (GstQTPad * pad, GstBuffer * buf, GstQTMux * qtmux); +typedef gboolean (*GstQTPadSetCapsFunc) (GstQTPad * pad, GstCaps * caps); + #define QTMUX_NO_OF_TS 10 struct _GstQTPad @@ -126,7 +128,7 @@ struct _GstQTPad /* if nothing is set, it won't be called */ GstQTPadPrepareBufferFunc prepare_buf_func; - gboolean (*set_caps) (GstPad * pad, GstCaps * caps); + GstQTPadSetCapsFunc set_caps; }; typedef enum _GstQTMuxState @@ -192,7 +194,7 @@ struct _GstQTMux gboolean streamable; /* for request pad naming */ - guint video_pads, audio_pads; + guint video_pads, audio_pads, subtitle_pads; }; struct _GstQTMuxClass @@ -209,6 +211,7 @@ typedef struct _GstQTMuxClassParams GstCaps *src_caps; GstCaps *video_sink_caps; GstCaps *audio_sink_caps; + GstCaps *subtitle_sink_caps; } GstQTMuxClassParams; #define GST_QT_MUX_PARAMS_QDATA g_quark_from_static_string("qt-mux-params") diff --git a/gst/isomp4/gstqtmuxmap.c b/gst/isomp4/gstqtmuxmap.c index ff85e09..3cf8136 100644 --- a/gst/isomp4/gstqtmuxmap.c +++ b/gst/isomp4/gstqtmuxmap.c @@ -166,8 +166,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { ADPCM_CAPS " ; " "audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; " "audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; " - AMR_CAPS " ; " ALAC_CAPS) - } + AMR_CAPS " ; " ALAC_CAPS), + GST_STATIC_CAPS_NONE} , /* ISO 14496-14: mp42 as ISO base media extension * (supersedes original ISO 144996-1 mp41) */ @@ -180,8 +180,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { GST_STATIC_CAPS ("video/quicktime, variant = (string) iso"), GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";" "video/x-mp4-part," COMMON_VIDEO_CAPS), - GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS " ; " ALAC_CAPS) - } + GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS " ; " ALAC_CAPS), + GST_STATIC_CAPS_NONE} , /* Microsoft Smooth Streaming fmp4/isml */ /* TODO add WMV/WMA support */ @@ -193,8 +193,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { "GstISMLMux", GST_STATIC_CAPS ("video/quicktime, variant = (string) iso-fragmented"), GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS), - GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS) - } + GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS), + GST_STATIC_CAPS_NONE} , /* 3GPP Technical Specification 26.244 V7.3.0 * (extended in 3GPP2 File Formats for Multimedia Services) */ @@ -206,8 +206,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { "Gst3GPPMux", GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"), GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS), - GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS) - } + GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS), + GST_STATIC_CAPS_NONE} , /* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */ { @@ -219,8 +219,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { GST_STATIC_CAPS ("video/mj2"), GST_STATIC_CAPS ("image/x-j2c, " COMMON_VIDEO_CAPS "; " "image/x-jpc, " COMMON_VIDEO_CAPS), - GST_STATIC_CAPS (PCM_CAPS) - } + GST_STATIC_CAPS (PCM_CAPS), + GST_STATIC_CAPS_NONE} , { GST_QT_MUX_FORMAT_NONE, diff --git a/gst/isomp4/gstqtmuxmap.h b/gst/isomp4/gstqtmuxmap.h index 1c5829c..e578a36 100644 --- a/gst/isomp4/gstqtmuxmap.h +++ b/gst/isomp4/gstqtmuxmap.h @@ -69,6 +69,7 @@ typedef struct _GstQTMuxFormatProp GstStaticCaps src_caps; GstStaticCaps video_sink_caps; GstStaticCaps audio_sink_caps; + GstStaticCaps subtitle_sink_caps; } GstQTMuxFormatProp; extern GstQTMuxFormatProp gst_qt_mux_format_list[]; -- 2.7.4