1 /* GStreamer
2  *
3  * Copyright (C) <2014> Stian Selnes <stian@pexip.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 /**
22  * SECTION:element-rtph261depay
23  * @see_also: rtph261pay
24  *
25  * Extract encoded H.261 video frames from RTP packets according to RFC 4587.
26  * For detailed information see: https://www.rfc-editor.org/rfc/rfc4587.txt
27  *
28  * The depayloader takes an RTP packet and extracts its H.261 stream. It
29  * aggregates the extracted stream until a complete frame is received before
30  * it pushes it downstream.
31  *
32  * <refsect2>
33  * <title>Example pipeline</title>
34  * |[
35  * gst-launch-1.0 udpsrc caps='application/x-rtp, payload=31' ! rtph261depay ! avdec_h261 ! autovideosink
36  * ]| This example pipeline will depayload and decode an RTP H.261 video stream.
37  * Refer to the rtph261pay example to create the RTP stream.
38  * </refsect2>
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #  include "config.h"
43 #endif
44 
45 #include <string.h>
46 
47 #include <gst/rtp/gstrtpbuffer.h>
48 #include <gst/video/video.h>
49 #include "gstrtph261depay.h"
50 #include "gstrtph261pay.h"      /* GstRtpH261PayHeader */
51 #include "gstrtputils.h"
52 
53 GST_DEBUG_CATEGORY_STATIC (rtph261depay_debug);
54 #define GST_CAT_DEFAULT (rtph261depay_debug)
55 
56 static const guint8 NO_LEFTOVER = 0xFF;
57 
58 static GstStaticPadTemplate gst_rtp_h261_depay_src_template =
59 GST_STATIC_PAD_TEMPLATE ("src",
60     GST_PAD_SRC,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS ("video/x-h261")
63     );
64 
65 static GstStaticPadTemplate gst_rtp_h261_depay_sink_template =
66     GST_STATIC_PAD_TEMPLATE ("sink",
67     GST_PAD_SINK,
68     GST_PAD_ALWAYS,
69     GST_STATIC_CAPS ("application/x-rtp, "
70         "media = (string) \"video\", "
71         "payload = (int) " GST_RTP_PAYLOAD_H261_STRING ", "
72         "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"; "
73         "application/x-rtp, "
74         "media = (string) \"video\", "
75         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
76         "clock-rate = (int) 90000, " "encoding-name = (string) \"H261\"")
77     );
78 
79 G_DEFINE_TYPE (GstRtpH261Depay, gst_rtp_h261_depay,
80     GST_TYPE_RTP_BASE_DEPAYLOAD);
81 #define parent_class gst_rtp_h261_depay_parent_class
82 
83 static GstBuffer *
gst_rtp_h261_depay_process(GstRTPBaseDepayload * depayload,GstRTPBuffer * rtp)84 gst_rtp_h261_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
85 {
86   GstRtpH261Depay *depay;
87   GstBuffer *outbuf = NULL;
88   gint payload_len;
89   guint8 *payload;
90   const guint header_len = GST_RTP_H261_PAYLOAD_HEADER_LEN;
91   gboolean marker;
92   GstRtpH261PayHeader *header;
93 
94   depay = GST_RTP_H261_DEPAY (depayload);
95 
96   if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
97     GST_DEBUG_OBJECT (depay, "Discont buffer, flushing adapter");
98     gst_adapter_clear (depay->adapter);
99     depay->leftover = NO_LEFTOVER;
100     depay->start = FALSE;
101   }
102 
103   payload_len = gst_rtp_buffer_get_payload_len (rtp);
104   payload = gst_rtp_buffer_get_payload (rtp);
105 
106   marker = gst_rtp_buffer_get_marker (rtp);
107 
108   if (payload_len < header_len + 1) {
109     /* Must have at least one byte payload */
110     GST_WARNING_OBJECT (depay, "Dropping packet with invalid payload length");
111     return NULL;
112   }
113 
114   header = (GstRtpH261PayHeader *) payload;
115 
116   GST_DEBUG_OBJECT (depay,
117       "payload_len: %d, header_len: %d, sbit: %d, ebit: %d, marker %d",
118       payload_len, header_len, header->sbit, header->ebit, marker);
119 
120   payload += header_len;
121   payload_len -= header_len;
122 
123   if (!depay->start) {
124     /* Check for picture start code */
125     guint32 bits = GST_READ_UINT32_BE (payload) << header->sbit;
126     if (payload_len > 4 && bits >> 12 == 0x10) {
127       GST_DEBUG_OBJECT (depay, "Found picture start code");
128       depay->start = TRUE;
129     } else {
130       GST_DEBUG_OBJECT (depay, "No picture start code yet, skipping payload");
131       goto skip;
132     }
133   }
134 
135   if (header->sbit != 0) {
136     /* Take the leftover from previous packet and merge it at the beginning */
137     payload[0] &= 0xFF >> header->sbit;
138     if (depay->leftover != NO_LEFTOVER) {
139       /* Happens if sbit is set for first packet in frame. Then previous byte
140        * has already been flushed. */
141       payload[0] |= depay->leftover;
142     }
143     depay->leftover = NO_LEFTOVER;
144   }
145 
146   if (header->ebit == 0) {
147     /* H.261 stream ends on byte boundary, take entire packet */
148     gst_adapter_push (depay->adapter,
149         gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, payload_len));
150   } else {
151     /* Take the entire buffer except for the last byte, which will be kept to
152      * merge with next packet */
153     gst_adapter_push (depay->adapter,
154         gst_rtp_buffer_get_payload_subbuffer (rtp, header_len,
155             payload_len - 1));
156     depay->leftover = payload[payload_len - 1] & (0xFF << header->ebit);
157   }
158 
159 skip:
160   if (marker) {
161     if (depay->start) {
162       guint avail;
163 
164       if (depay->leftover != NO_LEFTOVER) {
165         GstBuffer *buf = gst_buffer_new_and_alloc (1);
166         gst_buffer_memset (buf, 0, depay->leftover, 1);
167         gst_adapter_push (depay->adapter, buf);
168         depay->leftover = NO_LEFTOVER;
169       }
170 
171       avail = gst_adapter_available (depay->adapter);
172       outbuf = gst_adapter_take_buffer (depay->adapter, avail);
173       gst_rtp_drop_non_video_meta (depay, outbuf);
174 
175       /* Note that the I flag does not mean intra frame, but that the entire
176        * stream is intra coded. */
177       if (header->i)
178         GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
179       else
180         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
181 
182       GST_DEBUG_OBJECT (depay, "Pushing out a buffer of %u bytes", avail);
183       depay->start = FALSE;
184     } else {
185       depay->start = TRUE;
186     }
187   }
188 
189   return outbuf;
190 }
191 
192 static gboolean
gst_rtp_h261_depay_setcaps(GstRTPBaseDepayload * filter,GstCaps * caps)193 gst_rtp_h261_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
194 {
195   GstCaps *srccaps;
196 
197   srccaps = gst_caps_new_empty_simple ("video/x-h261");
198   gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
199   gst_caps_unref (srccaps);
200 
201   return TRUE;
202 }
203 
204 static GstStateChangeReturn
gst_rtp_h261_depay_change_state(GstElement * element,GstStateChange transition)205 gst_rtp_h261_depay_change_state (GstElement * element,
206     GstStateChange transition)
207 {
208   GstRtpH261Depay *depay;
209   GstStateChangeReturn ret;
210 
211   depay = GST_RTP_H261_DEPAY (element);
212 
213   switch (transition) {
214     case GST_STATE_CHANGE_NULL_TO_READY:
215       break;
216     case GST_STATE_CHANGE_READY_TO_PAUSED:
217       gst_adapter_clear (depay->adapter);
218       depay->start = FALSE;
219       break;
220     default:
221       break;
222   }
223 
224   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
225 
226   switch (transition) {
227     case GST_STATE_CHANGE_READY_TO_NULL:
228       break;
229     default:
230       break;
231   }
232   return ret;
233 }
234 
235 static void
gst_rtp_h261_depay_dispose(GObject * object)236 gst_rtp_h261_depay_dispose (GObject * object)
237 {
238   GstRtpH261Depay *depay;
239 
240   depay = GST_RTP_H261_DEPAY (object);
241 
242   if (depay->adapter) {
243     gst_object_unref (depay->adapter);
244     depay->adapter = NULL;
245   }
246 
247   G_OBJECT_CLASS (parent_class)->dispose (object);
248 }
249 
250 static void
gst_rtp_h261_depay_class_init(GstRtpH261DepayClass * klass)251 gst_rtp_h261_depay_class_init (GstRtpH261DepayClass * klass)
252 {
253   GObjectClass *gobject_class;
254   GstElementClass *gstelement_class;
255   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
256 
257   gobject_class = G_OBJECT_CLASS (klass);
258   gstelement_class = GST_ELEMENT_CLASS (klass);
259   gstrtpbasedepayload_class = GST_RTP_BASE_DEPAYLOAD_CLASS (klass);
260 
261   gst_element_class_add_static_pad_template (gstelement_class,
262       &gst_rtp_h261_depay_src_template);
263   gst_element_class_add_static_pad_template (gstelement_class,
264       &gst_rtp_h261_depay_sink_template);
265 
266   gst_element_class_set_static_metadata (gstelement_class,
267       "RTP H261 depayloader", "Codec/Depayloader/Network/RTP",
268       "Extracts H261 video from RTP packets (RFC 4587)",
269       "Stian Selnes <stian@pexip.com>");
270 
271   gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h261_depay_process;
272   gstrtpbasedepayload_class->set_caps = gst_rtp_h261_depay_setcaps;
273 
274   gobject_class->dispose = gst_rtp_h261_depay_dispose;
275 
276   gstelement_class->change_state = gst_rtp_h261_depay_change_state;
277 
278   GST_DEBUG_CATEGORY_INIT (rtph261depay_debug, "rtph261depay", 0,
279       "H261 Video RTP Depayloader");
280 }
281 
282 static void
gst_rtp_h261_depay_init(GstRtpH261Depay * depay)283 gst_rtp_h261_depay_init (GstRtpH261Depay * depay)
284 {
285   depay->adapter = gst_adapter_new ();
286   depay->leftover = NO_LEFTOVER;
287 }
288 
289 gboolean
gst_rtp_h261_depay_plugin_init(GstPlugin * plugin)290 gst_rtp_h261_depay_plugin_init (GstPlugin * plugin)
291 {
292   return gst_element_register (plugin, "rtph261depay",
293       GST_RANK_SECONDARY, GST_TYPE_RTP_H261_DEPAY);
294 }
295