126 */ |
133 */ |
127 #ifndef GST_REMOVE_DEPRECATED |
134 #ifndef GST_REMOVE_DEPRECATED |
128 g_object_class_install_property (gobject_class, PROP_QUEUE_DELAY, |
135 g_object_class_install_property (gobject_class, PROP_QUEUE_DELAY, |
129 g_param_spec_uint ("queue-delay", "Queue Delay", |
136 g_param_spec_uint ("queue-delay", "Queue Delay", |
130 "Amount of ms to queue/buffer, deprecated", 0, G_MAXUINT, |
137 "Amount of ms to queue/buffer, deprecated", 0, G_MAXUINT, |
131 DEFAULT_QUEUE_DELAY, G_PARAM_READWRITE)); |
138 DEFAULT_QUEUE_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
132 #endif |
139 #endif |
133 |
140 |
134 gstelement_class->change_state = gst_base_rtp_depayload_change_state; |
141 gstelement_class->change_state = gst_base_rtp_depayload_change_state; |
135 |
142 |
136 klass->set_gst_timestamp = gst_base_rtp_depayload_set_gst_timestamp; |
143 klass->set_gst_timestamp = gst_base_rtp_depayload_set_gst_timestamp; |
|
144 klass->packet_lost = gst_base_rtp_depayload_packet_lost; |
137 |
145 |
138 GST_DEBUG_CATEGORY_INIT (basertpdepayload_debug, "basertpdepayload", 0, |
146 GST_DEBUG_CATEGORY_INIT (basertpdepayload_debug, "basertpdepayload", 0, |
139 "Base class for RTP Depayloaders"); |
147 "Base class for RTP Depayloaders"); |
140 } |
148 } |
141 |
149 |
249 GstBaseRTPDepayloadPrivate *priv; |
259 GstBaseRTPDepayloadPrivate *priv; |
250 GstBaseRTPDepayloadClass *bclass; |
260 GstBaseRTPDepayloadClass *bclass; |
251 GstFlowReturn ret = GST_FLOW_OK; |
261 GstFlowReturn ret = GST_FLOW_OK; |
252 GstBuffer *out_buf; |
262 GstBuffer *out_buf; |
253 GstClockTime timestamp; |
263 GstClockTime timestamp; |
|
264 guint16 seqnum; |
|
265 guint32 rtptime; |
|
266 gboolean reset_seq, discont; |
|
267 gint gap; |
254 |
268 |
255 filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad)); |
269 filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad)); |
256 |
|
257 priv = filter->priv; |
270 priv = filter->priv; |
|
271 |
|
272 /* we must have a setcaps first */ |
|
273 if (G_UNLIKELY (!priv->negotiated)) |
|
274 goto not_negotiated; |
|
275 |
|
276 /* we must validate, it's possible that this element is plugged right after a |
|
277 * network receiver and we don't want to operate on invalid data */ |
|
278 if (G_UNLIKELY (!gst_rtp_buffer_validate (in))) |
|
279 goto invalid_buffer; |
|
280 |
258 priv->discont = GST_BUFFER_IS_DISCONT (in); |
281 priv->discont = GST_BUFFER_IS_DISCONT (in); |
259 |
282 |
|
283 timestamp = GST_BUFFER_TIMESTAMP (in); |
260 /* convert to running_time and save the timestamp, this is the timestamp |
284 /* convert to running_time and save the timestamp, this is the timestamp |
261 * we put on outgoing buffers. */ |
285 * we put on outgoing buffers. */ |
262 timestamp = GST_BUFFER_TIMESTAMP (in); |
|
263 timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, |
286 timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, |
264 timestamp); |
287 timestamp); |
265 priv->timestamp = timestamp; |
288 priv->timestamp = timestamp; |
266 priv->duration = GST_BUFFER_DURATION (in); |
289 priv->duration = GST_BUFFER_DURATION (in); |
267 |
290 |
|
291 seqnum = gst_rtp_buffer_get_seq (in); |
|
292 rtptime = gst_rtp_buffer_get_timestamp (in); |
|
293 reset_seq = TRUE; |
|
294 discont = FALSE; |
|
295 |
|
296 GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %" |
|
297 GST_TIME_FORMAT, priv->discont, seqnum, rtptime, |
|
298 GST_TIME_ARGS (timestamp)); |
|
299 |
|
300 /* Check seqnum. This is a very simple check that makes sure that the seqnums |
|
301 * are striclty increasing, dropping anything that is out of the ordinary. We |
|
302 * can only do this when the next_seqnum is known. */ |
|
303 if (G_LIKELY (priv->next_seqnum != -1)) { |
|
304 gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum); |
|
305 |
|
306 /* if we have no gap, all is fine */ |
|
307 if (G_UNLIKELY (gap != 0)) { |
|
308 GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum, |
|
309 priv->next_seqnum, gap); |
|
310 if (gap < 0) { |
|
311 /* seqnum > next_seqnum, we are missing some packets, this is always a |
|
312 * DISCONT. */ |
|
313 GST_LOG_OBJECT (filter, "%d missing packets", gap); |
|
314 discont = TRUE; |
|
315 } else { |
|
316 /* seqnum < next_seqnum, we have seen this packet before or the sender |
|
317 * could be restarted. If the packet is not too old, we throw it away as |
|
318 * a duplicate, otherwise we mark discont and continue. 100 misordered |
|
319 * packets is a good threshold. See also RFC 4737. */ |
|
320 if (gap < 100) |
|
321 goto dropping; |
|
322 |
|
323 GST_LOG_OBJECT (filter, |
|
324 "%d > 100, packet too old, sender likely restarted", gap); |
|
325 discont = TRUE; |
|
326 } |
|
327 } |
|
328 } |
|
329 priv->next_seqnum = (seqnum + 1) & 0xffff; |
|
330 |
|
331 if (G_UNLIKELY (discont && !priv->discont)) { |
|
332 GST_LOG_OBJECT (filter, "mark DISCONT on input buffer"); |
|
333 /* we detected a seqnum discont but the buffer was not flagged with a discont, |
|
334 * set the discont flag so that the subclass can throw away old data. */ |
|
335 priv->discont = TRUE; |
|
336 GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT); |
|
337 } |
|
338 |
268 bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); |
339 bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); |
|
340 |
|
341 if (G_UNLIKELY (bclass->process == NULL)) |
|
342 goto no_process; |
269 |
343 |
270 /* let's send it out to processing */ |
344 /* let's send it out to processing */ |
271 out_buf = bclass->process (filter, in); |
345 out_buf = bclass->process (filter, in); |
272 if (out_buf) { |
346 if (out_buf) { |
273 guint32 rtptime; |
|
274 |
|
275 rtptime = gst_rtp_buffer_get_timestamp (in); |
|
276 |
|
277 /* we pass rtptime as backward compatibility, in reality, the incomming |
347 /* we pass rtptime as backward compatibility, in reality, the incomming |
278 * buffer timestamp is always applied to the outgoing packet. */ |
348 * buffer timestamp is always applied to the outgoing packet. */ |
279 ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf); |
349 ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf); |
280 } |
350 } |
281 gst_buffer_unref (in); |
351 gst_buffer_unref (in); |
282 |
352 |
283 return ret; |
353 return ret; |
|
354 |
|
355 /* ERRORS */ |
|
356 not_negotiated: |
|
357 { |
|
358 /* this is not fatal but should be filtered earlier */ |
|
359 GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), |
|
360 ("Not RTP format was negotiated")); |
|
361 gst_buffer_unref (in); |
|
362 return GST_FLOW_NOT_NEGOTIATED; |
|
363 } |
|
364 invalid_buffer: |
|
365 { |
|
366 /* this is not fatal but should be filtered earlier */ |
|
367 GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL), |
|
368 ("Received invalid RTP payload, dropping")); |
|
369 gst_buffer_unref (in); |
|
370 return GST_FLOW_OK; |
|
371 } |
|
372 dropping: |
|
373 { |
|
374 GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap); |
|
375 gst_buffer_unref (in); |
|
376 return GST_FLOW_OK; |
|
377 } |
|
378 no_process: |
|
379 { |
|
380 /* this is not fatal but should be filtered earlier */ |
|
381 GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL), |
|
382 ("The subclass does not have a process method")); |
|
383 gst_buffer_unref (in); |
|
384 return GST_FLOW_ERROR; |
|
385 } |
284 } |
386 } |
285 |
387 |
286 static gboolean |
388 static gboolean |
287 gst_base_rtp_depayload_handle_sink_event (GstPad * pad, GstEvent * event) |
389 gst_base_rtp_depayload_handle_sink_event (GstPad * pad, GstEvent * event) |
288 { |
390 { |
314 /* don't pass the event downstream, we generate our own segment including |
417 /* don't pass the event downstream, we generate our own segment including |
315 * the NTP time and other things we receive in caps */ |
418 * the NTP time and other things we receive in caps */ |
316 gst_event_unref (event); |
419 gst_event_unref (event); |
317 break; |
420 break; |
318 } |
421 } |
|
422 case GST_EVENT_CUSTOM_DOWNSTREAM: |
|
423 { |
|
424 GstBaseRTPDepayloadClass *bclass; |
|
425 |
|
426 bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); |
|
427 |
|
428 if (gst_event_has_name (event, "GstRTPPacketLost")) { |
|
429 /* we get this event from the jitterbuffer when it considers a packet as |
|
430 * being lost. We send it to our packet_lost vmethod. The default |
|
431 * implementation will make time progress by pushing out a NEWSEGMENT |
|
432 * update event. Subclasses can override and to one of the following: |
|
433 * - Adjust timestamp/duration to something more accurate before |
|
434 * calling the parent (default) packet_lost method. |
|
435 * - do some more advanced error concealing on the already received |
|
436 * (fragmented) packets. |
|
437 * - ignore the packet lost. |
|
438 */ |
|
439 if (bclass->packet_lost) |
|
440 res = bclass->packet_lost (filter, event); |
|
441 } |
|
442 gst_event_unref (event); |
|
443 break; |
|
444 } |
319 default: |
445 default: |
320 /* pass other events forward */ |
446 /* pass other events forward */ |
321 res = gst_pad_push_event (filter->srcpad, event); |
447 res = gst_pad_push_event (filter->srcpad, event); |
322 break; |
448 break; |
323 } |
449 } |
324 return res; |
450 return res; |
|
451 } |
|
452 |
|
453 static GstEvent * |
|
454 create_segment_event (GstBaseRTPDepayload * filter, gboolean update, |
|
455 GstClockTime position) |
|
456 { |
|
457 GstEvent *event; |
|
458 GstClockTime stop; |
|
459 GstBaseRTPDepayloadPrivate *priv; |
|
460 |
|
461 priv = filter->priv; |
|
462 |
|
463 if (priv->npt_stop != -1) |
|
464 stop = priv->npt_stop - priv->npt_start; |
|
465 else |
|
466 stop = -1; |
|
467 |
|
468 event = gst_event_new_new_segment_full (update, priv->play_speed, |
|
469 priv->play_scale, GST_FORMAT_TIME, position, stop, |
|
470 position + priv->npt_start); |
|
471 |
|
472 return event; |
325 } |
473 } |
326 |
474 |
327 static GstFlowReturn |
475 static GstFlowReturn |
328 gst_base_rtp_depayload_push_full (GstBaseRTPDepayload * filter, |
476 gst_base_rtp_depayload_push_full (GstBaseRTPDepayload * filter, |
329 gboolean do_ts, guint32 rtptime, GstBuffer * out_buf) |
477 gboolean do_ts, guint32 rtptime, GstBuffer * out_buf) |
335 |
483 |
336 priv = filter->priv; |
484 priv = filter->priv; |
337 |
485 |
338 /* set the caps if any */ |
486 /* set the caps if any */ |
339 srccaps = GST_PAD_CAPS (filter->srcpad); |
487 srccaps = GST_PAD_CAPS (filter->srcpad); |
340 if (srccaps) |
488 if (G_LIKELY (srccaps)) |
341 gst_buffer_set_caps (out_buf, srccaps); |
489 gst_buffer_set_caps (out_buf, srccaps); |
342 |
490 |
343 bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); |
491 bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); |
344 |
492 |
345 /* set the timestamp if we must and can */ |
493 /* set the timestamp if we must and can */ |
346 if (bclass->set_gst_timestamp && do_ts) |
494 if (bclass->set_gst_timestamp && do_ts) |
347 bclass->set_gst_timestamp (filter, rtptime, out_buf); |
495 bclass->set_gst_timestamp (filter, rtptime, out_buf); |
348 |
496 |
349 if (priv->discont) { |
497 /* if this is the first buffer send a NEWSEGMENT */ |
|
498 if (G_UNLIKELY (filter->need_newsegment)) { |
|
499 GstEvent *event; |
|
500 |
|
501 event = create_segment_event (filter, FALSE, 0); |
|
502 |
|
503 gst_pad_push_event (filter->srcpad, event); |
|
504 |
|
505 filter->need_newsegment = FALSE; |
|
506 GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer"); |
|
507 } |
|
508 |
|
509 if (G_UNLIKELY (priv->discont)) { |
|
510 GST_LOG_OBJECT (filter, "Marking DISCONT on output buffer"); |
350 GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT); |
511 GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT); |
351 priv->discont = FALSE; |
512 priv->discont = FALSE; |
352 } |
513 } |
353 |
514 |
354 /* push it */ |
515 /* push it */ |
355 GST_LOG_OBJECT (filter, "Pushing buffer size %d, timestamp %" GST_TIME_FORMAT, |
516 GST_LOG_OBJECT (filter, "Pushing buffer size %d, timestamp %" GST_TIME_FORMAT, |
356 GST_BUFFER_SIZE (out_buf), |
517 GST_BUFFER_SIZE (out_buf), |
357 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf))); |
518 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf))); |
|
519 |
358 ret = gst_pad_push (filter->srcpad, out_buf); |
520 ret = gst_pad_push (filter->srcpad, out_buf); |
359 GST_LOG_OBJECT (filter, "Pushed buffer: %s", gst_flow_get_name (ret)); |
|
360 |
521 |
361 return ret; |
522 return ret; |
362 } |
523 } |
363 |
524 |
364 /** |
525 /** |
406 |
567 |
407 GstFlowReturn |
568 GstFlowReturn |
408 gst_base_rtp_depayload_push (GstBaseRTPDepayload * filter, GstBuffer * out_buf) |
569 gst_base_rtp_depayload_push (GstBaseRTPDepayload * filter, GstBuffer * out_buf) |
409 { |
570 { |
410 return gst_base_rtp_depayload_push_full (filter, FALSE, 0, out_buf); |
571 return gst_base_rtp_depayload_push_full (filter, FALSE, 0, out_buf); |
|
572 } |
|
573 |
|
574 /* convert the PacketLost event form a jitterbuffer to a segment update. |
|
575 * subclasses can override this. */ |
|
576 static gboolean |
|
577 gst_base_rtp_depayload_packet_lost (GstBaseRTPDepayload * filter, |
|
578 GstEvent * event) |
|
579 { |
|
580 GstBaseRTPDepayloadPrivate *priv; |
|
581 GstClockTime timestamp, duration, position; |
|
582 GstEvent *sevent; |
|
583 const GstStructure *s; |
|
584 |
|
585 priv = filter->priv; |
|
586 |
|
587 s = gst_event_get_structure (event); |
|
588 |
|
589 /* first start by parsing the timestamp and duration */ |
|
590 timestamp = -1; |
|
591 duration = -1; |
|
592 |
|
593 gst_structure_get_clock_time (s, "timestamp", ×tamp); |
|
594 gst_structure_get_clock_time (s, "duration", &duration); |
|
595 |
|
596 position = timestamp; |
|
597 if (duration != -1) |
|
598 position += duration; |
|
599 |
|
600 /* update the current segment with the elapsed time */ |
|
601 sevent = create_segment_event (filter, TRUE, position); |
|
602 |
|
603 return gst_pad_push_event (filter->srcpad, sevent); |
411 } |
604 } |
412 |
605 |
413 static void |
606 static void |
414 gst_base_rtp_depayload_set_gst_timestamp (GstBaseRTPDepayload * filter, |
607 gst_base_rtp_depayload_set_gst_timestamp (GstBaseRTPDepayload * filter, |
415 guint32 rtptime, GstBuffer * buf) |
608 guint32 rtptime, GstBuffer * buf) |
426 * not otherwise set. */ |
619 * not otherwise set. */ |
427 if (!GST_CLOCK_TIME_IS_VALID (timestamp)) |
620 if (!GST_CLOCK_TIME_IS_VALID (timestamp)) |
428 GST_BUFFER_TIMESTAMP (buf) = priv->timestamp; |
621 GST_BUFFER_TIMESTAMP (buf) = priv->timestamp; |
429 if (!GST_CLOCK_TIME_IS_VALID (duration)) |
622 if (!GST_CLOCK_TIME_IS_VALID (duration)) |
430 GST_BUFFER_DURATION (buf) = priv->duration; |
623 GST_BUFFER_DURATION (buf) = priv->duration; |
431 |
|
432 /* if this is the first buffer send a NEWSEGMENT */ |
|
433 if (filter->need_newsegment) { |
|
434 GstEvent *event; |
|
435 GstClockTime stop, position; |
|
436 |
|
437 if (priv->npt_stop != -1) |
|
438 stop = priv->npt_stop - priv->npt_start; |
|
439 else |
|
440 stop = -1; |
|
441 |
|
442 position = priv->npt_start; |
|
443 |
|
444 event = |
|
445 gst_event_new_new_segment_full (FALSE, priv->play_speed, |
|
446 priv->play_scale, GST_FORMAT_TIME, 0, stop, position); |
|
447 |
|
448 gst_pad_push_event (filter->srcpad, event); |
|
449 |
|
450 filter->need_newsegment = FALSE; |
|
451 GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer"); |
|
452 } |
|
453 } |
624 } |
454 |
625 |
455 static GstStateChangeReturn |
626 static GstStateChangeReturn |
456 gst_base_rtp_depayload_change_state (GstElement * element, |
627 gst_base_rtp_depayload_change_state (GstElement * element, |
457 GstStateChange transition) |
628 GstStateChange transition) |