rtpvrawpay: Add missing break
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpsv3vdepay.c
1 /* GStreamer
2  * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <string.h>
25
26 #include <gst/rtp/gstrtpbuffer.h>
27 #include "gstrtpsv3vdepay.h"
28
29 GST_DEBUG_CATEGORY (rtpsv3vdepay_debug);
30 #define GST_CAT_DEFAULT rtpsv3vdepay_debug
31
32 static GstStaticPadTemplate gst_rtp_sv3v_depay_src_template =
33 GST_STATIC_PAD_TEMPLATE ("src",
34     GST_PAD_SRC,
35     GST_PAD_ALWAYS,
36     GST_STATIC_CAPS ("video/x-svq, " "svqversion = (int) 3")
37     );
38
39 static GstStaticPadTemplate gst_rtp_sv3v_depay_sink_template =
40 GST_STATIC_PAD_TEMPLATE ("sink",
41     GST_PAD_SINK,
42     GST_PAD_ALWAYS,
43     GST_STATIC_CAPS ("application/x-rtp, "
44         "media = (string) \"video\", "
45         "clock-rate = (int) 90000, "
46         "encoding-name = (string) { \"X-SV3V-ES\", \"X-SORENSON-VIDEO\" , \"X-SORENSONVIDEO\" , \"X-SorensonVideo\" }")
47     );
48
49 #define gst_rtp_sv3v_depay_parent_class parent_class
50 G_DEFINE_TYPE (GstRtpSV3VDepay, gst_rtp_sv3v_depay,
51     GST_TYPE_RTP_BASE_DEPAYLOAD);
52
53 static void gst_rtp_sv3v_depay_finalize (GObject * object);
54
55 static GstStateChangeReturn gst_rtp_sv3v_depay_change_state (GstElement *
56     element, GstStateChange transition);
57
58 static GstBuffer *gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload,
59     GstBuffer * buf);
60 gboolean gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter,
61     GstCaps * caps);
62
63 static void
64 gst_rtp_sv3v_depay_class_init (GstRtpSV3VDepayClass * klass)
65 {
66   GObjectClass *gobject_class;
67   GstElementClass *gstelement_class;
68   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
69
70   gobject_class = (GObjectClass *) klass;
71   gstelement_class = (GstElementClass *) klass;
72   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
73
74   gstrtpbasedepayload_class->process = gst_rtp_sv3v_depay_process;
75   gstrtpbasedepayload_class->set_caps = gst_rtp_sv3v_depay_setcaps;
76
77   gobject_class->finalize = gst_rtp_sv3v_depay_finalize;
78
79   gstelement_class->change_state = gst_rtp_sv3v_depay_change_state;
80
81   gst_element_class_add_pad_template (gstelement_class,
82       gst_static_pad_template_get (&gst_rtp_sv3v_depay_src_template));
83   gst_element_class_add_pad_template (gstelement_class,
84       gst_static_pad_template_get (&gst_rtp_sv3v_depay_sink_template));
85
86   gst_element_class_set_static_metadata (gstelement_class,
87       "RTP SVQ3 depayloader", "Codec/Depayloader/Network/RTP",
88       "Extracts SVQ3 video from RTP packets (no RFC)",
89       "Wim Taymans <wim.taymans@gmail.com>");
90 }
91
92 static void
93 gst_rtp_sv3v_depay_init (GstRtpSV3VDepay * rtpsv3vdepay)
94 {
95   rtpsv3vdepay->adapter = gst_adapter_new ();
96 }
97
98 static void
99 gst_rtp_sv3v_depay_finalize (GObject * object)
100 {
101   GstRtpSV3VDepay *rtpsv3vdepay;
102
103   rtpsv3vdepay = GST_RTP_SV3V_DEPAY (object);
104
105   g_object_unref (rtpsv3vdepay->adapter);
106   rtpsv3vdepay->adapter = NULL;
107
108   G_OBJECT_CLASS (parent_class)->finalize (object);
109 }
110
111 /* only on the sink */
112 gboolean
113 gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
114 {
115   GstStructure *structure = gst_caps_get_structure (caps, 0);
116   gint clock_rate;
117
118   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
119     clock_rate = 90000;         /* default */
120   filter->clock_rate = clock_rate;
121
122   /* will set caps later */
123
124   return TRUE;
125 }
126
127 static GstBuffer *
128 gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
129 {
130   GstRtpSV3VDepay *rtpsv3vdepay;
131   static struct
132   {
133     guint width, height;
134   } resolutions[7] = {
135     {
136     160, 128}, {
137     128, 96}, {
138     176, 144}, {
139     352, 288}, {
140     704, 576}, {
141     240, 180}, {
142     320, 240}
143   };
144   gint payload_len;
145   guint8 *payload;
146   gboolean M;
147   gboolean C, S, E;
148   GstBuffer *outbuf = NULL;
149   guint16 seq;
150   GstRTPBuffer rtp = { NULL };
151
152   rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload);
153
154   gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
155
156   /* flush on sequence number gaps */
157   seq = gst_rtp_buffer_get_seq (&rtp);
158
159   GST_DEBUG ("timestamp %" GST_TIME_FORMAT ", sequence number:%d",
160       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), seq);
161
162   if (seq != rtpsv3vdepay->nextseq) {
163     GST_DEBUG ("Sequence discontinuity, clearing adapter");
164     gst_adapter_clear (rtpsv3vdepay->adapter);
165   }
166   rtpsv3vdepay->nextseq = seq + 1;
167
168   payload_len = gst_rtp_buffer_get_payload_len (&rtp);
169   if (payload_len < 3)
170     goto bad_packet;
171
172   payload = gst_rtp_buffer_get_payload (&rtp);
173
174   M = gst_rtp_buffer_get_marker (&rtp);
175
176   /* This is all a guess:
177    *                      1 1 1 1 1 1
178    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
179    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180    * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
181    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182    *
183    * C: config, packet contains config info
184    * S: start, packet contains start of frame
185    * E: end, packet contains end of frame
186    */
187   /* this seems to indicate a packet with a config string sent before each
188    * keyframe */
189   C = (payload[0] & 0x40) == 0x40;
190
191   /* redundant with the RTP marker bit */
192   S = (payload[0] & 0x20) == 0x20;
193   E = (payload[0] & 0x10) == 0x10;
194
195   GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E);
196
197   GST_MEMDUMP ("incoming buffer", payload, payload_len);
198
199   if (G_UNLIKELY (C)) {
200     GstCaps *caps;
201     GstBuffer *codec_data;
202     GstMapInfo cmap;
203     guint8 res;
204
205     GST_DEBUG ("Configuration packet");
206
207     /* if we already have caps, we don't need to do anything. FIXME, check if
208      * something changed. */
209     if (G_UNLIKELY (gst_pad_has_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD
210                 (depayload)))) {
211       GST_DEBUG ("Already configured, skipping config parsing");
212       goto beach;
213     }
214
215     res = payload[2] >> 5;
216
217     /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */
218     if (G_LIKELY (res < 7)) {
219       rtpsv3vdepay->width = resolutions[res].width;
220       rtpsv3vdepay->height = resolutions[res].height;
221     } else {
222       /* extended width/height, they're contained in the following 24bit */
223       rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1);
224       rtpsv3vdepay->height =
225           (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5);
226     }
227
228     /* CodecData needs to be 'SEQH' + len (32bit) + data according to
229      * ffmpeg's libavcodec/svq3.c:svq3_decode_init */
230     codec_data = gst_buffer_new_and_alloc (payload_len + 6);
231     gst_buffer_map (codec_data, &cmap, GST_MAP_WRITE);
232     memcpy (cmap.data, "SEQH", 4);
233     GST_WRITE_UINT32_LE (cmap.data + 4, payload_len - 2);
234     memcpy (cmap.data + 8, payload + 2, payload_len - 2);
235     GST_MEMDUMP ("codec_data", cmap.data, gst_buffer_get_size (codec_data));
236     gst_buffer_unmap (codec_data, &cmap);
237
238     caps = gst_caps_new_simple ("video/x-svq",
239         "svqversion", G_TYPE_INT, 3,
240         "width", G_TYPE_INT, rtpsv3vdepay->width,
241         "height", G_TYPE_INT, rtpsv3vdepay->height,
242         "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
243     gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps);
244     gst_caps_unref (caps);
245
246     GST_DEBUG ("Depayloader now configured");
247
248     rtpsv3vdepay->configured = TRUE;
249
250     goto beach;
251   }
252
253   if (G_LIKELY (rtpsv3vdepay->configured)) {
254     GstBuffer *tmpbuf;
255
256     GST_DEBUG ("Storing incoming payload");
257     /* store data in adapter, stip off 2 bytes header */
258     tmpbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 2, -1);
259     gst_adapter_push (rtpsv3vdepay->adapter, tmpbuf);
260
261     if (G_UNLIKELY (M)) {
262       /* frame is completed: push contents of adapter */
263       guint avail;
264
265       avail = gst_adapter_available (rtpsv3vdepay->adapter);
266       GST_DEBUG ("Returning completed output buffer [%d bytes]", avail);
267       outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);
268     }
269   }
270
271 beach:
272   gst_rtp_buffer_unmap (&rtp);
273   return outbuf;
274
275   /* ERRORS */
276 bad_packet:
277   {
278     GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE,
279         (NULL), ("Packet was too short"));
280     gst_rtp_buffer_unmap (&rtp);
281     return NULL;
282   }
283 }
284
285 static GstStateChangeReturn
286 gst_rtp_sv3v_depay_change_state (GstElement * element,
287     GstStateChange transition)
288 {
289   GstRtpSV3VDepay *rtpsv3vdepay;
290   GstStateChangeReturn ret;
291
292   rtpsv3vdepay = GST_RTP_SV3V_DEPAY (element);
293
294   switch (transition) {
295     case GST_STATE_CHANGE_NULL_TO_READY:
296       break;
297     case GST_STATE_CHANGE_READY_TO_PAUSED:
298       gst_adapter_clear (rtpsv3vdepay->adapter);
299       break;
300     default:
301       break;
302   }
303
304   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
305
306   switch (transition) {
307     case GST_STATE_CHANGE_READY_TO_NULL:
308       break;
309     default:
310       break;
311   }
312   return ret;
313 }
314
315 gboolean
316 gst_rtp_sv3v_depay_plugin_init (GstPlugin * plugin)
317 {
318   GST_DEBUG_CATEGORY_INIT (rtpsv3vdepay_debug, "rtpsv3vdepay", 0,
319       "RTP SV3V depayloader");
320
321   return gst_element_register (plugin, "rtpsv3vdepay",
322       GST_RANK_SECONDARY, GST_TYPE_RTP_SV3V_DEPAY);
323 }