From 2a139a28d9bf7be1e36876e9dab0cb35f6d31ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 7 Nov 2011 12:00:12 +0100 Subject: [PATCH 01/11] matroskamux: fix regression causing malformed files This was caused by me in 1b213d. It seems I was too focused on 0.11 when I did this and tested the wrong branch. The problem was reported by Alexey Fisher. --- gst/matroska/ebml-write.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/matroska/ebml-write.c b/gst/matroska/ebml-write.c index 9bc88eafd3..06f3568779 100644 --- a/gst/matroska/ebml-write.c +++ b/gst/matroska/ebml-write.c @@ -411,10 +411,12 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf, if (!buf_data) buf_data = GST_BUFFER_DATA (buf); - if (buf_data_end) + if (buf_data_end) { data_size = buf_data_end - buf_data; - else + GST_BUFFER_SIZE (buf) = data_size; + } else { data_size = GST_BUFFER_SIZE (buf); + } ebml->pos += data_size; From 6a257273212f2c4e5b4edea40554d5635d9e1dc4 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 27 Oct 2011 15:52:47 +0100 Subject: [PATCH 02/11] cairotextoverlay: add a 'silent' property to skip rendering https://bugzilla.gnome.org/show_bug.cgi?id=662856 --- ext/cairo/gsttextoverlay.c | 17 +++++++++++++++++ ext/cairo/gsttextoverlay.h | 1 + 2 files changed, 18 insertions(+) diff --git a/ext/cairo/gsttextoverlay.c b/ext/cairo/gsttextoverlay.c index c210191ee3..3f4fe3a9bd 100644 --- a/ext/cairo/gsttextoverlay.c +++ b/ext/cairo/gsttextoverlay.c @@ -65,12 +65,14 @@ enum ARG_YPAD, ARG_DELTAX, ARG_DELTAY, + ARG_SILENT, ARG_FONT_DESC }; #define DEFAULT_YPAD 25 #define DEFAULT_XPAD 25 #define DEFAULT_FONT "sans" +#define DEFAULT_SILENT FALSE #define GST_CAIRO_TEXT_OVERLAY_DEFAULT_SCALE 20.0 @@ -201,6 +203,11 @@ gst_text_overlay_class_init (GstCairoTextOverlayClass * klass) "See documentation of " "pango_font_description_from_string" " for syntax.", "", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */ + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT, + g_param_spec_boolean ("silent", "silent", + "Whether to render the text string", + DEFAULT_SILENT, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); } static void @@ -267,6 +274,8 @@ gst_text_overlay_init (GstCairoTextOverlay * overlay, overlay->font = g_strdup (DEFAULT_FONT); gst_text_overlay_font_init (overlay); + overlay->silent = DEFAULT_SILENT; + overlay->fps_n = 0; overlay->fps_d = 1; @@ -410,6 +419,9 @@ gst_text_overlay_set_property (GObject * object, guint prop_id, gst_text_overlay_font_init (overlay); break; } + case ARG_SILENT: + overlay->silent = g_value_get_boolean (value); + break; default:{ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -431,6 +443,11 @@ gst_text_overlay_render_text (GstCairoTextOverlay * overlay, gchar *string; double x, y; + if (overlay->silent) { + GST_DEBUG_OBJECT (overlay, "Silent mode, not rendering"); + return; + } + if (textlen < 0) textlen = strlen (text); diff --git a/ext/cairo/gsttextoverlay.h b/ext/cairo/gsttextoverlay.h index 09cfd724ee..dbb21546ff 100644 --- a/ext/cairo/gsttextoverlay.h +++ b/ext/cairo/gsttextoverlay.h @@ -76,6 +76,7 @@ struct _GstCairoTextOverlay { gint slant; gint weight; gdouble scale; + gboolean silent; }; struct _GstCairoTextOverlayClass { From 14a9d1d66e802271b5cfb447442f2d7197e02950 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 7 Oct 2011 19:41:35 +0100 Subject: [PATCH 03/11] flacparse: fix last frame timestamp in fixed block size mode The last block may have a different block size, so we should not use it to scale or we'll end up with a wrong timestamp. See comment and quote from the FLAC format documentation in the code. Fixes looped playback of FLAC files (via about-to-finish). https://bugzilla.gnome.org/show_bug.cgi?id=661215 --- gst/audioparsers/gstflacparse.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index a58c76a4ef..05bfd0e0f1 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -532,6 +532,34 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, if (actual_crc != expected_crc) goto error; + /* + The FLAC format documentation says: + The "blocking strategy" bit determines how to calculate the sample number + of the first sample in the frame. If the bit is 0 (fixed-blocksize), the + frame header encodes the frame number as above, and the frame's starting + sample number will be the frame number times the blocksize. If it is 1 + (variable-blocksize), the frame header encodes the frame's starting + sample number itself. (In the case of a fixed-blocksize stream, only the + last block may be shorter than the stream blocksize; its starting sample + number will be calculated as the frame number times the previous frame's + blocksize, or zero if it is the first frame). + + Therefore, when in fixed block size mode, we only update the block size + the first time, then reuse that block size for subsequent calls. + This will also fix a timestamp problem with the last block's timestamp + being miscalculated by scaling the block number by a "wrong" block size. + */ + if (blocking_strategy == 0) { + if (flacparse->block_size != 0) { + /* after first block */ + if (flacparse->block_size != block_size) { + /* TODO: can we know we're on the last frame, to avoid warning ? */ + GST_WARNING_OBJECT (flacparse, "Block size is not constant"); + block_size = flacparse->block_size; + } + } + } + if (set) { flacparse->block_size = block_size; if (!flacparse->samplerate) @@ -692,7 +720,6 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, flacparse->offset = GST_BUFFER_OFFSET (buffer); flacparse->blocking_strategy = 0; - flacparse->block_size = 0; flacparse->sample_number = 0; GST_DEBUG_OBJECT (flacparse, "Found sync code"); @@ -1334,7 +1361,6 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) flacparse->offset = -1; flacparse->blocking_strategy = 0; - flacparse->block_size = 0; flacparse->sample_number = 0; return GST_FLOW_OK; } From 5a73374f2c30e817440c3a71f0fdac9f1d6b9704 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 22 Aug 2011 10:40:45 +0100 Subject: [PATCH 04/11] flacdec: fix off by one between granpos and last_stop --- ext/flac/gstflacdec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 1e2ef5ee46..a12fd24d0b 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -978,7 +978,9 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, if (flacdec->cur_granulepos != GST_BUFFER_OFFSET_NONE) { /* this should be fine since it should be one flac frame per ogg packet */ - flacdec->segment.last_stop = flacdec->cur_granulepos - samples; + /* note the + 1, as the granpos is the presentation time of the last sample, + whereas the last stop represents the end time of that sample */ + flacdec->segment.last_stop = flacdec->cur_granulepos - samples + 1; GST_LOG_OBJECT (flacdec, "granulepos = %" G_GINT64_FORMAT ", samples = %u", flacdec->cur_granulepos, samples); } From cf3f3f14da6561223bf9f5d6bf1ff230526d40eb Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 3 Oct 2011 17:50:43 +0100 Subject: [PATCH 05/11] flvdemux: detect large pts gaps and resync Should work on multiple gaps, but tested on only one. https://bugzilla.gnome.org/show_bug.cgi?id=631430 --- gst/flv/gstflvdemux.c | 34 ++++++++++++++++++++++++++++++++-- gst/flv/gstflvdemux.h | 4 ++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 8aa352e53b..7d3c992fe1 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -84,6 +84,9 @@ GST_BOILERPLATE (GstFlvDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT); /* 1 byte of tag type + 3 bytes of tag data size */ #define FLV_TAG_TYPE_SIZE 4 +/* two seconds - consider pts are resynced to another base if this different */ +#define RESYNC_THRESHOLD 2000 + static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event); static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, @@ -759,6 +762,23 @@ gst_flv_demux_push_tags (GstFlvDemux * demux) } } +static void +gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, guint32 * last, + GstClockTime * offset) +{ + if (ABS (pts - *last) >= RESYNC_THRESHOLD) { + /* Theoretically, we should use substract the duration of the last buffer, + but this demuxer sends no durations on buffers, not sure if it cannot + know, or just does not care to calculate. */ + gint32 dpts = pts - *last; + *offset -= dpts * GST_MSECOND; + GST_WARNING_OBJECT (demux, + "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %" + GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset)); + } + *last = pts; +} + static GstFlowReturn gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer) { @@ -945,8 +965,12 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer) } } + /* detect (and deem to be resyncs) large pts gaps */ + gst_flv_demux_update_resync (demux, pts, &demux->last_audio_pts, + &demux->audio_time_offset); + /* Fill buffer with data */ - GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND; + GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++; GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset; @@ -1313,8 +1337,12 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer) } } + /* detect (and deem to be resyncs) large pts gaps */ + gst_flv_demux_update_resync (demux, pts, &demux->last_video_pts, + &demux->video_time_offset); + /* Fill buffer with data */ - GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND; + GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (outbuf) = demux->video_offset++; GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset; @@ -1627,6 +1655,8 @@ gst_flv_demux_cleanup (GstFlvDemux * demux) demux->index_max_time = 0; demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE; + demux->last_audio_pts = demux->last_video_pts = 0; + demux->audio_time_offset = demux->video_time_offset = 0; demux->no_more_pads = FALSE; diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index 60083e8675..07559a5201 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -95,6 +95,8 @@ struct _GstFlvDemux gboolean audio_linked; GstBuffer * audio_codec_data; GstClockTime audio_start; + guint32 last_audio_pts; + GstClockTime audio_time_offset; /* Video infos */ guint32 w; @@ -109,6 +111,8 @@ struct _GstFlvDemux gboolean got_par; GstBuffer * video_codec_data; GstClockTime video_start; + guint32 last_video_pts; + GstClockTime video_time_offset; gdouble framerate; gboolean random_access; From 91af805636d22805d17d1db2c1f1bcf30c03846a Mon Sep 17 00:00:00 2001 From: Raul Gutierrez Segales Date: Wed, 2 Nov 2011 17:02:54 +0000 Subject: [PATCH 06/11] gst/flv/: add amfdefs.h to noinst_HEADERS https://bugzilla.gnome.org/show_bug.cgi?id=663334 --- gst/flv/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/flv/Makefile.am b/gst/flv/Makefile.am index 93e1de1cea..e8059cb4d7 100644 --- a/gst/flv/Makefile.am +++ b/gst/flv/Makefile.am @@ -7,7 +7,7 @@ libgstflv_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS} libgstflv_la_SOURCES = gstflvdemux.c gstflvmux.c libgstflv_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = gstflvdemux.h gstflvmux.h +noinst_HEADERS = gstflvdemux.h gstflvmux.h amfdefs.h Android.mk: Makefile.am $(BUILT_SOURCES) androgenizer \ From 4946cc5e7f57b957cff89f7d0bf6e07bfd8768b0 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Tue, 8 Nov 2011 14:31:34 +0100 Subject: [PATCH 07/11] qtdemux: also set segment stop at startup rather than only post seek ... so as to ensure consistent playback with or without seek, especially in presence of some bogus edit list entries. --- gst/isomp4/qtdemux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 4a9463a987..1b7caf3da4 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -8867,8 +8867,13 @@ qtdemux_parse_tree (GstQTDemux * qtdemux) /* set duration in the segment info */ gst_qtdemux_get_duration (qtdemux, &duration); - if (duration) + if (duration) { gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration); + /* also do not exceed duration; stop is set that way post seek anyway, + * and segment activation falls back to duration, + * whereas loop only checks stop, so let's align this here as well */ + qtdemux->segment.stop = duration; + } /* parse all traks */ trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak); From ff31090671a18900e5266d3d4a8a6995f0b4e208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 4 Mar 2009 20:50:19 -0500 Subject: [PATCH 08/11] rtph263ppay: Implement getcaps following RFC 4629, picks the right annexes https://bugzilla.gnome.org/show_bug.cgi?id=577784 --- gst/rtp/gstrtph263ppay.c | 245 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 1 deletion(-) diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c index 54a1991309..69ae80fcff 100644 --- a/gst/rtp/gstrtph263ppay.c +++ b/gst/rtp/gstrtph263ppay.c @@ -22,6 +22,7 @@ #endif #include +#include #include @@ -61,9 +62,21 @@ static GstStaticPadTemplate gst_rtp_h263p_pay_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\" ") + GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\"") ); +/* + * We also set all of those as required: + * + * "annex-f = (boolean) {true, false}," + * "annex-i = (boolean) {true, false}," + * "annex-j = (boolean) {true, false}," + * "annex-l = (boolean) {true, false}," + * "annex-t = (boolean) {true, false}," + * "annex-v = (boolean) {true, false}") + */ + + static GstStaticPadTemplate gst_rtp_h263p_pay_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -87,6 +100,8 @@ static void gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id, static gboolean gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps); +static GstCaps *gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, + GstPad * pad); static GstFlowReturn gst_rtp_h263p_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer); @@ -123,6 +138,7 @@ gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass) gobject_class->get_property = gst_rtp_h263p_pay_get_property; gstbasertppayload_class->set_caps = gst_rtp_h263p_pay_setcaps; + gstbasertppayload_class->get_caps = gst_rtp_h263p_pay_sink_getcaps; gstbasertppayload_class->handle_buffer = gst_rtp_h263p_pay_handle_buffer; g_object_class_install_property (G_OBJECT_CLASS (klass), @@ -191,6 +207,233 @@ gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) return res; } +static GstCaps * +gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) +{ + GstRtpH263PPay *rtph263ppay; + GstCaps *caps = gst_caps_new_empty (); + GstCaps *peercaps = NULL; + GstCaps *intersect = NULL; + guint i; + + rtph263ppay = GST_RTP_H263P_PAY (payload); + + peercaps = gst_pad_peer_get_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload)); + if (!peercaps) + return + gst_caps_copy (gst_pad_get_pad_template_caps + (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); + + intersect = gst_caps_intersect (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); + gst_caps_unref (peercaps); + + if (gst_caps_is_empty (intersect)) + return intersect; + + for (i = 0; i < gst_caps_get_size (intersect); i++) { + GstStructure *s = gst_caps_get_structure (intersect, i); + const gchar *encoding_name = gst_structure_get_string (s, "encoding-name"); + + if (!strcmp (encoding_name, "H263-2000")) { + const gchar *profile_str = gst_structure_get_string (s, "profile"); + const gchar *level_str = gst_structure_get_string (s, "level"); + int profile = 0; + int level = 0; + + if (profile_str && level_str) { + gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE, + v = FALSE; + GstStructure *new_s = gst_structure_new ("video/x-h263", + "variant", G_TYPE_STRING, "itu", + NULL); + + profile = atoi (profile_str); + level = atoi (level_str); + + /* These profiles are defined in the H.263 Annex X */ + switch (profile) { + case 0: + /* The Baseline Profile (Profile 0) */ + break; + case 1: + /* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile + * (Profile 1) + * Baseline + Annexes I, J, L.4 and T + */ + i = j = l = t = TRUE; + break; + case 2: + /* Version 1 Backward-Compatibility Profile (Profile 2) + * Baseline + Annex F + */ + i = j = l = t = f = TRUE; + break; + case 3: + /* Version 2 Interactive and Streaming Wireless Profile + * Baseline + Annexes I, J, T + */ + i = j = t = TRUE; + break; + case 4: + /* Version 3 Interactive and Streaming Wireless Profile (Profile 4) + * Baseline + Annexes I, J, T, V, W.6.3.8, + */ + /* Missing W.6.3.8 */ + i = j = t = v = TRUE; + break; + case 5: + /* Conversational High Compression Profile (Profile 5) + * Baseline + Annexes F, I, J, L.4, T, D, U + */ + /* Missing D, U */ + f = i = j = l = t = TRUE; + break; + case 6: + /* Conversational Internet Profile (Profile 6) + * Baseline + Annexes F, I, J, L.4, T, D, U and + * K with arbitratry slice ordering + */ + /* Missing D, U, K with arbitratry slice ordering */ + f = i = j = l = t = TRUE; + break; + case 7: + /* Conversational Interlace Profile (Profile 7) + * Baseline + Annexes F, I, J, L.4, T, D, U, W.6.3.11 + */ + /* Missing D, U, W.6.3.11 */ + f = i = j = l = t = TRUE; + break; + case 8: + /* High Latency Profile (Profile 8) + * Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and + * K with arbitratry slice ordering + */ + /* Missing D, U, P.5, O.1.1 */ + f = i = j = l = t = TRUE; + break; + } + + + if (f || i || j || t || l || v) { + GValue list = { 0 }; + GValue vstr = { 0 }; + + g_value_init (&list, GST_TYPE_LIST); + g_value_init (&vstr, G_TYPE_STRING); + + g_value_set_static_string (&vstr, "h263"); + gst_value_list_append_value (&list, &vstr); + g_value_set_static_string (&vstr, "h263p"); + gst_value_list_append_value (&list, &vstr); + + if (l || v) { + g_value_set_static_string (&vstr, "h263pp"); + gst_value_list_append_value (&list, &vstr); + } + g_value_unset (&vstr); + + gst_structure_set_value (new_s, "h263version", &list); + g_value_unset (&list); + } else { + gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL); + } + + + if (!f) + gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL); + if (!i) + gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL); + if (!j) + gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL); + if (!t) + gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL); + if (!l) + gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL); + if (!v) + gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL); + + /* FIXME: + * Ignore the profile for now, gst-ffmpeg need to accept + * height/width/framerates first + */ + + gst_caps_merge_structure (caps, new_s); + } else { + GstStructure *new_s = gst_structure_new ("video/x-h263", + "variant", G_TYPE_STRING, "itu", + "h263version", G_TYPE_STRING, "h263", + NULL); + + GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified" + " for H263-2000, defaulting to baseline H263"); + + gst_caps_merge_structure (caps, new_s); + } + } else { + gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE; + /* FIXME: ffmpeg support the Appendix K too, how do we express it ? + * guint k; + */ + const gchar *str; + GstStructure *new_s = gst_structure_new ("video/x-h263", + "variant", G_TYPE_STRING, "itu", + NULL); + + str = gst_structure_get_string (s, "f"); + if (str && !strcmp (str, "1")) + f = TRUE; + + str = gst_structure_get_string (s, "i"); + if (str && !strcmp (str, "1")) + i = TRUE; + + str = gst_structure_get_string (s, "j"); + if (str && !strcmp (str, "1")) + j = TRUE; + + str = gst_structure_get_string (s, "t"); + if (str && !strcmp (str, "1")) + t = TRUE; + + if (f || i || j || t) { + GValue list = { 0 }; + GValue vstr = { 0 }; + + g_value_init (&list, GST_TYPE_LIST); + g_value_init (&vstr, G_TYPE_STRING); + + g_value_set_static_string (&vstr, "h263"); + gst_value_list_append_value (&list, &vstr); + g_value_set_static_string (&vstr, "h263p"); + gst_value_list_append_value (&list, &vstr); + g_value_unset (&vstr); + + gst_structure_set_value (new_s, "h263version", &list); + g_value_unset (&list); + } else { + gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL); + } + + if (!f) + gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL); + if (!i) + gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL); + if (!j) + gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL); + if (!t) + gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL); + + gst_caps_merge_structure (caps, new_s); + } + } + + gst_caps_unref (intersect); + + return caps; +} + + static void gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) From 4b28d9d44e1b332aa7dc9ceddb484ca11f4ab221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Sun, 15 Mar 2009 19:26:48 -0400 Subject: [PATCH 09/11] rtph263ppay: Also implement size/framerate restrictions in getcaps https://bugzilla.gnome.org/show_bug.cgi?id=577784 --- gst/rtp/gstrtph263ppay.c | 164 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 7 deletions(-) diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c index 69ae80fcff..e05293acc9 100644 --- a/gst/rtp/gstrtph263ppay.c +++ b/gst/rtp/gstrtph263ppay.c @@ -23,6 +23,7 @@ #include #include +#include #include @@ -66,8 +67,10 @@ GST_STATIC_PAD_TEMPLATE ("sink", ); /* - * We also set all of those as required: + * We also return these in getcaps() as required by the SDP caps * + * width = (int) [16, 4096] + * height = (int) [16, 4096] * "annex-f = (boolean) {true, false}," * "annex-i = (boolean) {true, false}," * "annex-j = (boolean) {true, false}," @@ -207,6 +210,28 @@ gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) return res; } +static void +caps_append (GstCaps * caps, GstStructure * in_s, guint x, guint y, guint mpi) +{ + GstStructure *s; + + if (!in_s) + return; + + if (mpi < 1 || mpi > 32) + return; + + s = gst_structure_copy (in_s); + + gst_structure_set (s, + "width", GST_TYPE_INT_RANGE, 1, x, + "height", GST_TYPE_INT_RANGE, 1, y, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001 * mpi, NULL); + + gst_caps_merge_structure (caps, s); +} + + static GstCaps * gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) { @@ -353,12 +378,80 @@ gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) if (!v) gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL); - /* FIXME: - * Ignore the profile for now, gst-ffmpeg need to accept - * height/width/framerates first - */ - gst_caps_merge_structure (caps, new_s); + if (level <= 10 || level == 45) { + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 176, + "height", GST_TYPE_INT_RANGE, 1, 144, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL); + gst_caps_merge_structure (caps, new_s); + } else if (level <= 20) { + GstStructure *s_copy = gst_structure_copy (new_s); + + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 352, + "height", GST_TYPE_INT_RANGE, 1, 288, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL); + gst_caps_merge_structure (caps, new_s); + + gst_structure_set (s_copy, + "width", GST_TYPE_INT_RANGE, 1, 176, + "height", GST_TYPE_INT_RANGE, 1, 144, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL); + gst_caps_merge_structure (caps, s_copy); + } else if (level <= 40) { + + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 352, + "height", GST_TYPE_INT_RANGE, 1, 288, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL); + gst_caps_merge_structure (caps, new_s); + } else if (level <= 50) { + GstStructure *s_copy = gst_structure_copy (new_s); + + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 352, + "height", GST_TYPE_INT_RANGE, 1, 288, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); + gst_caps_merge_structure (caps, new_s); + + gst_structure_set (s_copy, + "width", GST_TYPE_INT_RANGE, 1, 352, + "height", GST_TYPE_INT_RANGE, 1, 240, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); + gst_caps_merge_structure (caps, s_copy); + } else if (level <= 60) { + GstStructure *s_copy = gst_structure_copy (new_s); + + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 720, + "height", GST_TYPE_INT_RANGE, 1, 288, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); + gst_caps_merge_structure (caps, new_s); + + gst_structure_set (s_copy, + "width", GST_TYPE_INT_RANGE, 1, 720, + "height", GST_TYPE_INT_RANGE, 1, 240, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); + gst_caps_merge_structure (caps, s_copy); + } else if (level <= 70) { + GstStructure *s_copy = gst_structure_copy (new_s); + + gst_structure_set (new_s, + "width", GST_TYPE_INT_RANGE, 1, 720, + "height", GST_TYPE_INT_RANGE, 1, 576, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); + gst_caps_merge_structure (caps, new_s); + + gst_structure_set (s_copy, + "width", GST_TYPE_INT_RANGE, 1, 720, + "height", GST_TYPE_INT_RANGE, 1, 480, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); + gst_caps_merge_structure (caps, s_copy); + } else { + gst_caps_merge_structure (caps, new_s); + } + } else { GstStructure *new_s = gst_structure_new ("video/x-h263", "variant", G_TYPE_STRING, "itu", @@ -379,6 +472,7 @@ gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) GstStructure *new_s = gst_structure_new ("video/x-h263", "variant", G_TYPE_STRING, "itu", NULL); + gboolean added = FALSE; str = gst_structure_get_string (s, "f"); if (str && !strcmp (str, "1")) @@ -424,7 +518,63 @@ gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) if (!t) gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL); - gst_caps_merge_structure (caps, new_s); + + str = gst_structure_get_string (s, "custom"); + if (str) { + unsigned int xmax, ymax, mpi; + if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) { + if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) { + caps_append (caps, new_s, xmax, ymax, mpi); + added = TRUE; + } else { + GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI" + " %u x %u at %u, ignoring", xmax, ymax, mpi); + } + } else { + GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s," + " ignoring", str); + } + } + + str = gst_structure_get_string (s, "16cif"); + if (str) { + int mpi = atoi (str); + caps_append (caps, new_s, 1408, 1152, mpi); + added = TRUE; + } + + str = gst_structure_get_string (s, "4cif"); + if (str) { + int mpi = atoi (str); + caps_append (caps, new_s, 704, 576, mpi); + added = TRUE; + } + + str = gst_structure_get_string (s, "cif"); + if (str) { + int mpi = atoi (str); + caps_append (caps, new_s, 352, 288, mpi); + added = TRUE; + } + + str = gst_structure_get_string (s, "qcif"); + if (str) { + int mpi = atoi (str); + caps_append (caps, new_s, 176, 144, mpi); + added = TRUE; + } + + str = gst_structure_get_string (s, "sqcif"); + if (str) { + int mpi = atoi (str); + caps_append (caps, new_s, 128, 96, mpi); + added = TRUE; + } + + if (added) + gst_structure_free (new_s); + else + gst_caps_merge_structure (caps, new_s); } } From e15c293f13429f3d4894f332db5026cbf1fd77e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 2 Nov 2011 12:58:12 -0400 Subject: [PATCH 10/11] rtph263ppay: Return the sink pad template as sink caps, not the src's https://bugzilla.gnome.org/show_bug.cgi?id=577784 --- gst/rtp/gstrtph263ppay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c index e05293acc9..0cbe2c0d21 100644 --- a/gst/rtp/gstrtph263ppay.c +++ b/gst/rtp/gstrtph263ppay.c @@ -247,7 +247,7 @@ gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) if (!peercaps) return gst_caps_copy (gst_pad_get_pad_template_caps - (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); + (GST_BASE_RTP_PAYLOAD_SINKPAD (payload))); intersect = gst_caps_intersect (peercaps, gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); From 9c3516116a50750371afa4c26c6a32f5d22d246a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 9 Nov 2011 10:32:06 +0100 Subject: [PATCH 11/11] qtdemux: minimal sanity check on creation datetime --- gst/isomp4/qtdemux.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 1b7caf3da4..ddf4348c4f 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -8830,8 +8830,16 @@ qtdemux_parse_tree (GstQTDemux * qtdemux) /* Moving qt creation time (secs since 1904) to unix time */ if (creation_time != 0) { if (creation_time > QTDEMUX_SECONDS_FROM_1904_TO_1970) { + GTimeVal now; + creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970; - datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time); + /* some data cleansing sanity */ + g_get_current_time (&now); + if (now.tv_sec + 24 * 3600 < creation_time) { + GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time"); + } else { + datetime = gst_date_time_new_from_unix_epoch_local_time (creation_time); + } } else { GST_WARNING_OBJECT (qtdemux, "Can't handle datetimes before 1970 yet, " "please file a bug at http://bugzilla.gnome.org");