Merge branch 'master' into 0.11

Conflicts:
	gst/audioparsers/gstamrparse.c
	gst/isomp4/qtdemux.c
This commit is contained in:
Wim Taymans 2011-09-06 16:06:25 +02:00
commit 33f18b8ea4
10 changed files with 160 additions and 21 deletions

View file

@ -1370,7 +1370,7 @@ gst_soup_http_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
return FALSE; return FALSE;
} }
if (segment->rate != 1.0 || segment->format != GST_FORMAT_BYTES) { if (segment->rate < 0.0 || segment->format != GST_FORMAT_BYTES) {
GST_WARNING_OBJECT (src, "Invalid seek segment"); GST_WARNING_OBJECT (src, "Invalid seek segment");
return FALSE; return FALSE;
} }

View file

@ -296,12 +296,28 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse,
* to contain a valid header as well (and there is enough data to * to contain a valid header as well (and there is enough data to
* perform this check) * perform this check)
*/ */
if (fsize && if (fsize) {
(!GST_BASE_PARSE_LOST_SYNC (parse) || GST_BASE_PARSE_DRAINING (parse) gboolean found = FALSE;
|| (dsize > fsize && (data[fsize] & 0x83) == 0))) {
/* in sync, no further check */
if (!GST_BASE_PARSE_LOST_SYNC (parse)) {
found = TRUE;
} else if (dsize > fsize) {
/* enough data, check for next sync */
if ((data[fsize] & 0x83) == 0)
found = TRUE;
} else if (GST_BASE_PARSE_DRAINING (parse)) {
/* not enough, but draining, so ok */
found = TRUE;
} else {
/* indicate we need not skip, but need more data */
*skipsize = 0;
*framesize = fsize + 1;
}
if (found) {
*framesize = fsize; *framesize = fsize;
ret = TRUE; return TRUE;
goto done; }
} }
} }
GST_LOG ("sync lost"); GST_LOG ("sync lost");

View file

@ -318,7 +318,7 @@ struct _QtDemuxStream
guint32 stts_samples; guint32 stts_samples;
guint32 n_sample_times; guint32 n_sample_times;
guint32 stts_sample_index; guint32 stts_sample_index;
guint32 stts_time; guint64 stts_time;
guint32 stts_duration; guint32 stts_duration;
/* stss */ /* stss */
gboolean stss_present; gboolean stss_present;
@ -1311,7 +1311,10 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
GST_TIME_ARGS (desired_offset)); GST_TIME_ARGS (desired_offset));
if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) { /* may not have enough fragmented info to do this adjustment,
* and we can't scan (and probably should not) at this time with
* possibly flushing upstream */
if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
gint64 min_offset; gint64 min_offset;
gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL); gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
@ -1864,6 +1867,8 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE; qtdemux->requested_seek_time = GST_CLOCK_TIME_NONE;
qtdemux->seek_offset = 0; qtdemux->seek_offset = 0;
qtdemux->upstream_seekable = FALSE;
qtdemux->upstream_size = 0;
break; break;
} }
default: default:
@ -2103,6 +2108,14 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
stream->track_id, d_sample_duration, d_sample_size, d_sample_flags, stream->track_id, d_sample_duration, d_sample_size, d_sample_flags,
*base_offset); *base_offset);
/* presence of stss or not can't really tell us much,
* and flags and so on tend to be marginally reliable in these files */
if (stream->subtype == FOURCC_soun) {
GST_DEBUG_OBJECT (qtdemux,
"sound track in fragmented file; marking all keyframes");
stream->all_keyframe = TRUE;
}
if (!gst_byte_reader_skip (trun, 1) || if (!gst_byte_reader_skip (trun, 1) ||
!gst_byte_reader_get_uint24_be (trun, &flags)) !gst_byte_reader_get_uint24_be (trun, &flags))
goto fail; goto fail;
@ -3971,6 +3984,47 @@ qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
return res; return res;
} }
/* check for seekable upstream, above and beyond a mere query */
static void
gst_qtdemux_check_seekability (GstQTDemux * demux)
{
GstQuery *query;
gboolean seekable = FALSE;
gint64 start = -1, stop = -1;
if (demux->upstream_size)
return;
query = gst_query_new_seeking (GST_FORMAT_BYTES);
if (!gst_pad_peer_query (demux->sinkpad, query)) {
GST_DEBUG_OBJECT (demux, "seeking query failed");
goto done;
}
gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
/* try harder to query upstream size if we didn't get it the first time */
if (seekable && stop == -1) {
GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
gst_pad_query_peer_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
}
/* if upstream doesn't know the size, it's likely that it's not seekable in
* practice even if it technically may be seekable */
if (seekable && (start != 0 || stop <= start)) {
GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
seekable = FALSE;
}
done:
gst_query_unref (query);
GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
G_GUINT64_FORMAT ")", seekable, start, stop);
demux->upstream_seekable = seekable;
demux->upstream_size = seekable ? stop : -1;
}
/* FIXME, unverified after edit list updates */ /* FIXME, unverified after edit list updates */
static GstFlowReturn static GstFlowReturn
gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf) gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
@ -4002,6 +4056,8 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
guint32 fourcc; guint32 fourcc;
guint64 size; guint64 size;
gst_qtdemux_check_seekability (demux);
data = gst_adapter_map (demux->adapter, demux->neededbytes); data = gst_adapter_map (demux->adapter, demux->neededbytes);
/* get fourcc/length, set neededbytes */ /* get fourcc/length, set neededbytes */
@ -4040,7 +4096,15 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
target = old + size; target = old + size;
/* try to jump over the atom with a seek */ /* try to jump over the atom with a seek */
/* only bother if it seems worth doing so,
* and avoids possible upstream/server problems */
if (demux->upstream_seekable &&
demux->upstream_size > 4 * (1 << 20)) {
res = qtdemux_seek_offset (demux, target); res = qtdemux_seek_offset (demux, target);
} else {
GST_DEBUG_OBJECT (demux, "skipping seek");
res = FALSE;
}
if (res) { if (res) {
GST_DEBUG_OBJECT (demux, "seek success"); GST_DEBUG_OBJECT (demux, "seek success");
@ -4058,7 +4122,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
} else { } else {
/* seek failed, need to buffer */ /* seek failed, need to buffer */
demux->offset = old; demux->offset = old;
GST_DEBUG_OBJECT (demux, "seek failed"); GST_DEBUG_OBJECT (demux, "seek failed/skipped");
/* there may be multiple mdat (or alike) buffers */ /* there may be multiple mdat (or alike) buffers */
/* sanity check */ /* sanity check */
if (demux->mdatbuffer) if (demux->mdatbuffer)
@ -4153,6 +4217,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
* put preceding buffered data ahead of current moov data. * put preceding buffered data ahead of current moov data.
* This should also handle evil mdat, moov, mdat cases and alike */ * This should also handle evil mdat, moov, mdat cases and alike */
gst_adapter_clear (demux->adapter); gst_adapter_clear (demux->adapter);
gst_adapter_push (demux->adapter, demux->mdatbuffer);
demux->mdatbuffer = NULL; demux->mdatbuffer = NULL;
demux->offset = demux->mdatoffset; demux->offset = demux->mdatoffset;
demux->neededbytes = next_entry_size (demux); demux->neededbytes = next_entry_size (demux);
@ -5640,8 +5705,8 @@ done2:
for (i = stream->stts_index; i < n_sample_times; i++) { for (i = stream->stts_index; i < n_sample_times; i++) {
guint32 stts_samples; guint32 stts_samples;
guint32 stts_duration; gint32 stts_duration;
guint32 stts_time; gint64 stts_time;
if (stream->stts_sample_index >= stream->stts_samples if (stream->stts_sample_index >= stream->stts_samples
|| !stream->stts_sample_index) { || !stream->stts_sample_index) {
@ -5671,7 +5736,9 @@ done2:
cur->timestamp = stts_time; cur->timestamp = stts_time;
cur->duration = stts_duration; cur->duration = stts_duration;
stts_time += stts_duration; /* avoid 32-bit wrap-around,
* but still mind possible 'negative' duration */
stts_time += (gint64) stts_duration;
cur++; cur++;
if (G_UNLIKELY (cur > last)) { if (G_UNLIKELY (cur > last)) {

View file

@ -108,6 +108,9 @@ struct _GstQTDemux {
gint64 requested_seek_time; gint64 requested_seek_time;
guint64 seek_offset; guint64 seek_offset;
gboolean upstream_seekable;
gboolean upstream_size;
}; };
struct _GstQTDemuxClass { struct _GstQTDemuxClass {

View file

@ -157,9 +157,32 @@ static gboolean
gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
{ {
gboolean res; gboolean res;
GstCaps *peercaps;
gchar *encoding_name = NULL;
gst_basertppayload_set_options (payload, "video", TRUE, "H263-1998", 90000); g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
peercaps =
gst_pad_peer_get_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), NULL);
if (peercaps) {
GstCaps *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)) {
GstStructure *s = gst_caps_get_structure (intersect, 0);
encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
}
gst_caps_unref (intersect);
}
if (!encoding_name)
encoding_name = g_strdup ("H263-1998");
gst_basertppayload_set_options (payload, "video", TRUE,
(gchar *) encoding_name, 90000);
res = gst_basertppayload_set_outcaps (payload, NULL); res = gst_basertppayload_set_outcaps (payload, NULL);
g_free (encoding_name);
return res; return res;
} }

View file

@ -567,6 +567,7 @@ rtp_session_init (RTPSession * sess)
DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD; DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
sess->rtcp_pli_requests = g_array_new (FALSE, FALSE, sizeof (guint32)); sess->rtcp_pli_requests = g_array_new (FALSE, FALSE, sizeof (guint32));
sess->last_keyframe_request = GST_CLOCK_TIME_NONE;
GST_DEBUG ("%p: session using SSRC: %08x", sess, sess->source->ssrc); GST_DEBUG ("%p: session using SSRC: %08x", sess, sess->source->ssrc);
} }

View file

@ -173,6 +173,7 @@ gst_rtsp_src_buffer_mode_get_type (void)
#define DEFAULT_USER_PW NULL #define DEFAULT_USER_PW NULL
#define DEFAULT_BUFFER_MODE BUFFER_MODE_AUTO #define DEFAULT_BUFFER_MODE BUFFER_MODE_AUTO
#define DEFAULT_PORT_RANGE NULL #define DEFAULT_PORT_RANGE NULL
#define DEFAULT_SHORT_HEADER FALSE
enum enum
{ {
@ -194,6 +195,7 @@ enum
PROP_BUFFER_MODE, PROP_BUFFER_MODE,
PROP_PORT_RANGE, PROP_PORT_RANGE,
PROP_UDP_BUFFER_SIZE, PROP_UDP_BUFFER_SIZE,
PROP_SHORT_HEADER,
PROP_LAST PROP_LAST
}; };
@ -444,6 +446,18 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE, 0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPSrc::short-header:
*
* Only send the basic RTSP headers for broken encoders.
*
* Since: 0.10.31
*/
g_object_class_install_property (gobject_class, PROP_SHORT_HEADER,
g_param_spec_boolean ("short-header", "Short Header",
"Only send the basic RTSP headers for broken encoders",
DEFAULT_SHORT_HEADER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->send_event = gst_rtspsrc_send_event; gstelement_class->send_event = gst_rtspsrc_send_event;
gstelement_class->change_state = gst_rtspsrc_change_state; gstelement_class->change_state = gst_rtspsrc_change_state;
@ -492,6 +506,7 @@ gst_rtspsrc_init (GstRTSPSrc * src)
src->client_port_range.min = 0; src->client_port_range.min = 0;
src->client_port_range.max = 0; src->client_port_range.max = 0;
src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE;
src->short_header = DEFAULT_SHORT_HEADER;
/* get a list of all extensions */ /* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get (); src->extensions = gst_rtsp_ext_list_get ();
@ -685,6 +700,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
case PROP_UDP_BUFFER_SIZE: case PROP_UDP_BUFFER_SIZE:
rtspsrc->udp_buffer_size = g_value_get_int (value); rtspsrc->udp_buffer_size = g_value_get_int (value);
break; break;
case PROP_SHORT_HEADER:
rtspsrc->short_header = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -777,6 +795,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_UDP_BUFFER_SIZE: case PROP_UDP_BUFFER_SIZE:
g_value_set_int (value, rtspsrc->udp_buffer_size); g_value_set_int (value, rtspsrc->udp_buffer_size);
break; break;
case PROP_SHORT_HEADER:
g_value_set_boolean (value, rtspsrc->short_header);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -4399,6 +4420,7 @@ gst_rtspsrc_try_send (GstRTSPSrc * src, GstRTSPConnection * conn,
gint try = 0; gint try = 0;
again: again:
if (!src->short_header)
gst_rtsp_ext_list_before_send (src->extensions, request); gst_rtsp_ext_list_before_send (src->extensions, request);
GST_DEBUG_OBJECT (src, "sending message"); GST_DEBUG_OBJECT (src, "sending message");

View file

@ -214,6 +214,7 @@ struct _GstRTSPSrc {
gint buffer_mode; gint buffer_mode;
GstRTSPRange client_port_range; GstRTSPRange client_port_range;
gint udp_buffer_size; gint udp_buffer_size;
gboolean short_header;
/* state */ /* state */
GstRTSPState state; GstRTSPState state;

View file

@ -174,7 +174,8 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
* of destinations. * of destinations.
*/ */
gst_multiudpsink_signals[SIGNAL_ADD] = gst_multiudpsink_signals[SIGNAL_ADD] =
g_signal_new ("add", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("add", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstMultiUDPSinkClass, add), G_STRUCT_OFFSET (GstMultiUDPSinkClass, add),
NULL, NULL, gst_udp_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, NULL, NULL, gst_udp_marshal_VOID__STRING_INT, G_TYPE_NONE, 2,
G_TYPE_STRING, G_TYPE_INT); G_TYPE_STRING, G_TYPE_INT);
@ -188,7 +189,8 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
* clients. * clients.
*/ */
gst_multiudpsink_signals[SIGNAL_REMOVE] = gst_multiudpsink_signals[SIGNAL_REMOVE] =
g_signal_new ("remove", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("remove", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstMultiUDPSinkClass, remove), G_STRUCT_OFFSET (GstMultiUDPSinkClass, remove),
NULL, NULL, gst_udp_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, NULL, NULL, gst_udp_marshal_VOID__STRING_INT, G_TYPE_NONE, 2,
G_TYPE_STRING, G_TYPE_INT); G_TYPE_STRING, G_TYPE_INT);
@ -199,7 +201,8 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
* Clear the list of clients. * Clear the list of clients.
*/ */
gst_multiudpsink_signals[SIGNAL_CLEAR] = gst_multiudpsink_signals[SIGNAL_CLEAR] =
g_signal_new ("clear", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("clear", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstMultiUDPSinkClass, clear), G_STRUCT_OFFSET (GstMultiUDPSinkClass, clear),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
/** /**
@ -214,7 +217,8 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
* connect_time (in epoch seconds), disconnect_time (in epoch seconds) * connect_time (in epoch seconds), disconnect_time (in epoch seconds)
*/ */
gst_multiudpsink_signals[SIGNAL_GET_STATS] = gst_multiudpsink_signals[SIGNAL_GET_STATS] =
g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstMultiUDPSinkClass, get_stats), G_STRUCT_OFFSET (GstMultiUDPSinkClass, get_stats),
NULL, NULL, gst_udp_marshal_BOXED__STRING_INT, G_TYPE_VALUE_ARRAY, 2, NULL, NULL, gst_udp_marshal_BOXED__STRING_INT, G_TYPE_VALUE_ARRAY, 2,
G_TYPE_STRING, G_TYPE_INT); G_TYPE_STRING, G_TYPE_INT);

View file

@ -339,7 +339,9 @@ gst_parser_test_drain_garbage (guint8 * data, guint size, guint8 * garbage,
{ {
GstParserTest ptest; GstParserTest ptest;
gst_parser_test_init (&ptest, data, size, 1); /* provide enough initial frames since it may take some parsers some
* time to be convinced of proper sync */
gst_parser_test_init (&ptest, data, size, 10);
ptest.series[1].data = garbage; ptest.series[1].data = garbage;
ptest.series[1].size = gsize; ptest.series[1].size = gsize;
ptest.series[1].num = 1; ptest.series[1].num = 1;