• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * gstrtponviftimestamp-parse.c
3  *
4  * Copyright (C) 2014 Axis Communications AB
5  *  Author: Guillaume Desmottes <guillaume.desmottes@collabora.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <gst/rtp/gstrtpbuffer.h>
30 
31 #include "gstrtponvifparse.h"
32 
33 static GstFlowReturn gst_rtp_onvif_parse_chain (GstPad * pad,
34     GstObject * parent, GstBuffer * buf);
35 
36 static GstStaticPadTemplate sink_template_factory =
37 GST_STATIC_PAD_TEMPLATE ("sink",
38     GST_PAD_SINK,
39     GST_PAD_ALWAYS,
40     GST_STATIC_CAPS ("application/x-rtp")
41     );
42 
43 static GstStaticPadTemplate src_template_factory =
44 GST_STATIC_PAD_TEMPLATE ("src",
45     GST_PAD_SRC,
46     GST_PAD_ALWAYS,
47     GST_STATIC_CAPS ("application/x-rtp")
48     );
49 
50 G_DEFINE_TYPE (GstRtpOnvifParse, gst_rtp_onvif_parse, GST_TYPE_ELEMENT);
51 GST_ELEMENT_REGISTER_DEFINE (rtponvifparse, "rtponvifparse",
52     GST_RANK_NONE, GST_TYPE_RTP_ONVIF_PARSE);
53 
54 static void
gst_rtp_onvif_parse_class_init(GstRtpOnvifParseClass * klass)55 gst_rtp_onvif_parse_class_init (GstRtpOnvifParseClass * klass)
56 {
57   GstElementClass *gstelement_class;
58 
59   gstelement_class = GST_ELEMENT_CLASS (klass);
60 
61   /* register pads */
62   gst_element_class_add_static_pad_template (gstelement_class,
63       &sink_template_factory);
64   gst_element_class_add_static_pad_template (gstelement_class,
65       &src_template_factory);
66 
67   gst_element_class_set_static_metadata (gstelement_class,
68       "ONVIF NTP timestamps RTP extension", "Effect/RTP",
69       "Add absolute timestamps and flags of recorded data in a playback "
70       "session", "Guillaume Desmottes <guillaume.desmottes@collabora.com>");
71 }
72 
73 static void
gst_rtp_onvif_parse_init(GstRtpOnvifParse * self)74 gst_rtp_onvif_parse_init (GstRtpOnvifParse * self)
75 {
76   self->sinkpad =
77       gst_pad_new_from_static_template (&sink_template_factory, "sink");
78   gst_pad_set_chain_function (self->sinkpad, gst_rtp_onvif_parse_chain);
79   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
80   GST_PAD_SET_PROXY_CAPS (self->sinkpad);
81 
82   self->srcpad =
83       gst_pad_new_from_static_template (&src_template_factory, "src");
84   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
85 }
86 
87 #define EXTENSION_ID 0xABAC
88 #define EXTENSION_SIZE 3
89 
90 static gboolean
handle_buffer(GstRtpOnvifParse * self,GstBuffer * buf,gboolean * send_eos)91 handle_buffer (GstRtpOnvifParse * self, GstBuffer * buf, gboolean * send_eos)
92 {
93   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
94   guint8 *data;
95   guint16 bits;
96   guint wordlen;
97   guint8 flags;
98   guint64 timestamp_seconds;
99   guint64 timestamp_fraction;
100   guint64 timestamp_nseconds;
101   /*
102      guint8 cseq;
103    */
104 
105   if (!gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp)) {
106     GST_ELEMENT_ERROR (self, STREAM, FAILED,
107         ("Failed to map RTP buffer"), (NULL));
108     return FALSE;
109   }
110 
111   /* Check if the ONVIF RTP extension is present in the packet */
112   if (!gst_rtp_buffer_get_extension_data (&rtp, &bits, (gpointer) & data,
113           &wordlen))
114     goto out;
115 
116   if (bits != EXTENSION_ID || wordlen != EXTENSION_SIZE)
117     goto out;
118 
119   timestamp_seconds = GST_READ_UINT32_BE (data);
120   timestamp_fraction = GST_READ_UINT32_BE (data + 4);
121   timestamp_nseconds =
122       (timestamp_fraction * G_GINT64_CONSTANT (1000000000)) >> 32;
123 
124   if (timestamp_seconds == G_MAXUINT32 && timestamp_fraction == G_MAXUINT32) {
125     GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
126   } else {
127     GST_BUFFER_PTS (buf) =
128         timestamp_seconds * GST_SECOND + timestamp_nseconds * GST_NSECOND;
129   }
130 
131   flags = GST_READ_UINT8 (data + 8);
132   /* cseq = GST_READ_UINT8 (data + 9);  TODO */
133 
134   /* C */
135   if (flags & (1 << 7))
136     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
137   else
138     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
139 
140   /* E */
141   /* if (flags & (1 << 6));  TODO */
142 
143   /* D */
144   if (flags & (1 << 5))
145     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
146   else
147     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
148 
149   /* T */
150   if (flags & (1 << 4))
151     *send_eos = TRUE;
152 
153 out:
154   gst_rtp_buffer_unmap (&rtp);
155   return TRUE;
156 }
157 
158 static GstFlowReturn
gst_rtp_onvif_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)159 gst_rtp_onvif_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
160 {
161   GstRtpOnvifParse *self = GST_RTP_ONVIF_PARSE (parent);
162   GstFlowReturn ret;
163   gboolean send_eos = FALSE;
164 
165   if (!handle_buffer (self, buf, &send_eos)) {
166     gst_buffer_unref (buf);
167     return GST_FLOW_ERROR;
168   }
169 
170   ret = gst_pad_push (self->srcpad, buf);
171 
172   if (ret == GST_FLOW_OK && send_eos) {
173     GstEvent *event;
174 
175     event = gst_event_new_eos ();
176     gst_pad_push_event (self->srcpad, event);
177     ret = GST_FLOW_EOS;
178   }
179 
180   return ret;
181 }
182