161 gobject_class->get_property = gst_basertppayload_get_property; |
159 gobject_class->get_property = gst_basertppayload_get_property; |
162 |
160 |
163 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, |
161 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, |
164 g_param_spec_uint ("mtu", "MTU", |
162 g_param_spec_uint ("mtu", "MTU", |
165 "Maximum size of one packet", |
163 "Maximum size of one packet", |
166 28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE)); |
164 28, G_MAXUINT, DEFAULT_MTU, |
|
165 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
167 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, |
166 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, |
168 g_param_spec_uint ("pt", "payload type", |
167 g_param_spec_uint ("pt", "payload type", |
169 "The payload type of the packets", |
168 "The payload type of the packets", 0, 0x80, DEFAULT_PT, |
170 0, 0x80, DEFAULT_PT, G_PARAM_READWRITE)); |
169 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
171 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, |
170 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, |
172 g_param_spec_uint ("ssrc", "SSRC", |
171 g_param_spec_uint ("ssrc", "SSRC", |
173 "The SSRC of the packets (default == random)", |
172 "The SSRC of the packets (default == random)", 0, G_MAXUINT32, |
174 0, G_MAXUINT32, DEFAULT_SSRC, G_PARAM_READWRITE)); |
173 DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
175 g_object_class_install_property (G_OBJECT_CLASS (klass), |
174 g_object_class_install_property (G_OBJECT_CLASS (klass), |
176 PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", |
175 PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", |
177 "Timestamp Offset", |
176 "Timestamp Offset", |
178 "Offset to add to all outgoing timestamps (default = random)", 0, |
177 "Offset to add to all outgoing timestamps (default = random)", 0, |
179 G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE)); |
178 G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, |
|
179 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
180 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, |
180 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, |
181 g_param_spec_int ("seqnum-offset", "Sequence number Offset", |
181 g_param_spec_int ("seqnum-offset", "Sequence number Offset", |
182 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, |
182 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, |
183 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE)); |
183 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
184 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, |
184 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, |
185 g_param_spec_int64 ("max-ptime", "Max packet time", |
185 g_param_spec_int64 ("max-ptime", "Max packet time", |
186 "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", |
186 "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", |
187 -1, G_MAXINT64, DEFAULT_MAX_PTIME, G_PARAM_READWRITE)); |
187 -1, G_MAXINT64, DEFAULT_MAX_PTIME, |
|
188 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
188 /** |
189 /** |
189 * GstBaseRTPAudioPayload:min-ptime: |
190 * GstBaseRTPAudioPayload:min-ptime: |
190 * |
191 * |
191 * Minimum duration of the packet data in ns (can't go above MTU) |
192 * Minimum duration of the packet data in ns (can't go above MTU) |
192 * |
193 * |
193 * Since: 0.10.13 |
194 * Since: 0.10.13 |
194 **/ |
195 **/ |
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, |
196 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, |
196 g_param_spec_int64 ("min-ptime", "Min packet time", |
197 g_param_spec_int64 ("min-ptime", "Min packet time", |
197 "Minimum duration of the packet data in ns (can't go above MTU)", |
198 "Minimum duration of the packet data in ns (can't go above MTU)", |
198 0, G_MAXINT64, DEFAULT_MIN_PTIME, G_PARAM_READWRITE)); |
199 0, G_MAXINT64, DEFAULT_MIN_PTIME, |
|
200 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
199 |
201 |
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, |
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, |
201 g_param_spec_uint ("timestamp", "Timestamp", |
203 g_param_spec_uint ("timestamp", "Timestamp", |
202 "The RTP timestamp of the last processed packet", |
204 "The RTP timestamp of the last processed packet", |
203 0, G_MAXUINT32, 0, G_PARAM_READABLE)); |
205 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
204 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, |
206 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, |
205 g_param_spec_uint ("seqnum", "Sequence number", |
207 g_param_spec_uint ("seqnum", "Sequence number", |
206 "The RTP sequence number of the last processed packet", |
208 "The RTP sequence number of the last processed packet", |
207 0, G_MAXUINT16, 0, G_PARAM_READABLE)); |
209 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
208 |
210 |
209 gstelement_class->change_state = gst_basertppayload_change_state; |
211 gstelement_class->change_state = gst_basertppayload_change_state; |
210 |
212 |
211 GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0, |
213 GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0, |
212 "Base class for RTP Payloaders"); |
214 "Base class for RTP Payloaders"); |
624 return TRUE; |
627 return TRUE; |
625 |
628 |
626 return FALSE; |
629 return FALSE; |
627 } |
630 } |
628 |
631 |
|
632 typedef struct |
|
633 { |
|
634 GstBaseRTPPayload *payload; |
|
635 guint32 ssrc; |
|
636 guint16 seqnum; |
|
637 guint8 pt; |
|
638 GstCaps *caps; |
|
639 GstClockTime timestamp; |
|
640 guint32 rtptime; |
|
641 } HeaderData; |
|
642 |
|
643 static GstBufferListItem |
|
644 find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) |
|
645 { |
|
646 data->timestamp = GST_BUFFER_TIMESTAMP (*buffer); |
|
647 |
|
648 /* stop when we find a timestamp */ |
|
649 if (data->timestamp != -1) |
|
650 return GST_BUFFER_LIST_END; |
|
651 else |
|
652 return GST_BUFFER_LIST_CONTINUE; |
|
653 } |
|
654 |
|
655 static GstBufferListItem |
|
656 set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) |
|
657 { |
|
658 gst_rtp_buffer_set_ssrc (*buffer, data->ssrc); |
|
659 gst_rtp_buffer_set_payload_type (*buffer, data->pt); |
|
660 gst_rtp_buffer_set_seq (*buffer, data->seqnum); |
|
661 gst_rtp_buffer_set_timestamp (*buffer, data->rtptime); |
|
662 gst_buffer_set_caps (*buffer, data->caps); |
|
663 data->seqnum++; |
|
664 |
|
665 return GST_BUFFER_LIST_SKIP_GROUP; |
|
666 } |
|
667 |
|
668 /* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer |
|
669 * before the buffer is pushed. */ |
|
670 static GstFlowReturn |
|
671 gst_basertppayload_prepare_push (GstBaseRTPPayload * payload, |
|
672 gpointer obj, gboolean is_list) |
|
673 { |
|
674 GstBaseRTPPayloadPrivate *priv; |
|
675 HeaderData data; |
|
676 |
|
677 if (payload->clock_rate == 0) |
|
678 goto no_rate; |
|
679 |
|
680 priv = payload->priv; |
|
681 |
|
682 /* update first, so that the property is set to the last |
|
683 * seqnum pushed */ |
|
684 payload->seqnum = priv->next_seqnum; |
|
685 |
|
686 /* fill in the fields we want to set on all headers */ |
|
687 data.payload = payload; |
|
688 data.seqnum = payload->seqnum; |
|
689 data.ssrc = payload->current_ssrc; |
|
690 data.pt = payload->pt; |
|
691 data.caps = GST_PAD_CAPS (payload->srcpad); |
|
692 data.timestamp = -1; |
|
693 |
|
694 /* find the first buffer with a timestamp */ |
|
695 if (is_list) { |
|
696 gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), |
|
697 (GstBufferListFunc) find_timestamp, &data); |
|
698 } else { |
|
699 data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj)); |
|
700 } |
|
701 |
|
702 /* convert to RTP time */ |
|
703 if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) { |
|
704 gint64 rtime; |
|
705 |
|
706 rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, |
|
707 data.timestamp); |
|
708 |
|
709 rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); |
|
710 |
|
711 /* add running_time in clock-rate units to the base timestamp */ |
|
712 data.rtptime = payload->ts_base + rtime; |
|
713 } else { |
|
714 /* no timestamp to convert, take previous timestamp */ |
|
715 data.rtptime = payload->timestamp; |
|
716 } |
|
717 |
|
718 /* set ssrc, payload type, seq number, caps and rtptime */ |
|
719 if (is_list) { |
|
720 gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), |
|
721 (GstBufferListFunc) set_headers, &data); |
|
722 } else { |
|
723 GstBuffer *buf = GST_BUFFER_CAST (obj); |
|
724 set_headers (&buf, 0, 0, &data); |
|
725 } |
|
726 |
|
727 priv->next_seqnum = data.seqnum; |
|
728 payload->timestamp = data.rtptime; |
|
729 |
|
730 GST_LOG_OBJECT (payload, |
|
731 "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %" |
|
732 GST_TIME_FORMAT, (is_list) ? -1 : |
|
733 GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime, |
|
734 GST_TIME_ARGS (data.timestamp)); |
|
735 |
|
736 return GST_FLOW_OK; |
|
737 |
|
738 /* ERRORS */ |
|
739 no_rate: |
|
740 { |
|
741 GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), |
|
742 ("subclass did not specify clock-rate")); |
|
743 return GST_FLOW_ERROR; |
|
744 } |
|
745 } |
|
746 |
|
747 /** |
|
748 * gst_basertppayload_push_list: |
|
749 * @payload: a #GstBaseRTPPayload |
|
750 * @list: a #GstBufferList |
|
751 * |
|
752 * Push @list to the peer element of the payloader. The SSRC, payload type, |
|
753 * seqnum and timestamp of the RTP buffer will be updated first. |
|
754 * |
|
755 * This function takes ownership of @list. |
|
756 * |
|
757 * Returns: a #GstFlowReturn. |
|
758 * |
|
759 * Since: 0.10.24 |
|
760 */ |
|
761 |
|
762 #ifdef __SYMBIAN32__ |
|
763 EXPORT_C |
|
764 #endif |
|
765 |
|
766 GstFlowReturn |
|
767 gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list) |
|
768 { |
|
769 GstFlowReturn res; |
|
770 |
|
771 res = gst_basertppayload_prepare_push (payload, list, TRUE); |
|
772 |
|
773 if (G_LIKELY (res == GST_FLOW_OK)) |
|
774 res = gst_pad_push_list (payload->srcpad, list); |
|
775 else |
|
776 gst_buffer_list_unref (list); |
|
777 |
|
778 return res; |
|
779 } |
|
780 |
629 /** |
781 /** |
630 * gst_basertppayload_push: |
782 * gst_basertppayload_push: |
631 * @payload: a #GstBaseRTPPayload |
783 * @payload: a #GstBaseRTPPayload |
632 * @buffer: a #GstBuffer |
784 * @buffer: a #GstBuffer |
633 * |
785 * |
644 |
796 |
645 GstFlowReturn |
797 GstFlowReturn |
646 gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) |
798 gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) |
647 { |
799 { |
648 GstFlowReturn res; |
800 GstFlowReturn res; |
649 GstClockTime timestamp; |
801 |
650 guint32 rtptime; |
802 res = gst_basertppayload_prepare_push (payload, buffer, FALSE); |
651 GstBaseRTPPayloadPrivate *priv; |
803 |
652 |
804 if (G_LIKELY (res == GST_FLOW_OK)) |
653 if (payload->clock_rate == 0) |
805 res = gst_pad_push (payload->srcpad, buffer); |
654 goto no_rate; |
806 else |
655 |
807 gst_buffer_unref (buffer); |
656 priv = payload->priv; |
|
657 |
|
658 gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc); |
|
659 |
|
660 gst_rtp_buffer_set_payload_type (buffer, payload->pt); |
|
661 |
|
662 /* update first, so that the property is set to the last |
|
663 * seqnum pushed */ |
|
664 payload->seqnum = priv->next_seqnum; |
|
665 gst_rtp_buffer_set_seq (buffer, payload->seqnum); |
|
666 |
|
667 /* can wrap around, which is perfectly fine */ |
|
668 priv->next_seqnum++; |
|
669 |
|
670 /* add our random offset to the timestamp */ |
|
671 rtptime = payload->ts_base; |
|
672 |
|
673 timestamp = GST_BUFFER_TIMESTAMP (buffer); |
|
674 if (GST_CLOCK_TIME_IS_VALID (timestamp)) { |
|
675 gint64 rtime; |
|
676 |
|
677 rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, |
|
678 timestamp); |
|
679 |
|
680 /* take first timestamp as base, we want to calculate the RTP timestamp |
|
681 * starting from the ts_base */ |
|
682 if (priv->rt_base == -1) { |
|
683 priv->rt_base = rtime; |
|
684 GST_LOG_OBJECT (payload, "first timestamp %" GST_TIME_FORMAT, |
|
685 GST_TIME_ARGS (rtime)); |
|
686 } |
|
687 rtime -= priv->rt_base; |
|
688 |
|
689 rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); |
|
690 |
|
691 /* add running_time in clock-rate units to the base timestamp */ |
|
692 rtptime += rtime; |
|
693 } else { |
|
694 /* no timestamp to convert, take previous timestamp */ |
|
695 rtptime = payload->timestamp; |
|
696 } |
|
697 gst_rtp_buffer_set_timestamp (buffer, rtptime); |
|
698 |
|
699 payload->timestamp = rtptime; |
|
700 |
|
701 /* set caps */ |
|
702 gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad)); |
|
703 |
|
704 GST_LOG_OBJECT (payload, |
|
705 "Pushing packet size %d, seq=%d, rtptime=%u, timestamp %" GST_TIME_FORMAT, |
|
706 GST_BUFFER_SIZE (buffer), payload->seqnum, rtptime, |
|
707 GST_TIME_ARGS (timestamp)); |
|
708 |
|
709 res = gst_pad_push (payload->srcpad, buffer); |
|
710 |
808 |
711 return res; |
809 return res; |
712 |
|
713 /* ERRORS */ |
|
714 no_rate: |
|
715 { |
|
716 GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), |
|
717 ("subclass did not specify clock-rate")); |
|
718 gst_buffer_unref (buffer); |
|
719 return GST_FLOW_ERROR; |
|
720 } |
|
721 } |
810 } |
722 |
811 |
723 static void |
812 static void |
724 gst_basertppayload_set_property (GObject * object, guint prop_id, |
813 gst_basertppayload_set_property (GObject * object, guint prop_id, |
725 const GValue * value, GParamSpec * pspec) |
814 const GValue * value, GParamSpec * pspec) |