don't use underscores
[platform/upstream/gstreamer.git] / gst / rtp / gstrtph263ppay.c
1 /* GStreamer
2  * Copyright (C) <2005> Wim Taymans <wim@fluendo.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 
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 #endif
18
19 #include <string.h>
20
21 #include <gst/rtp/gstrtpbuffer.h>
22
23 #include "gstrtph263penc.h"
24
25 /* elementfactory information */
26 static GstElementDetails gst_rtp_h263penc_details = {
27   "RTP packet parser",
28   "Codec/Parser/Network",
29   "Encodes H263+ video in RTP packets (RFC 2429)",
30   "Wim Taymans <wim@fluendo.com>"
31 };
32
33 static GstStaticPadTemplate gst_rtph263penc_sink_template =
34 GST_STATIC_PAD_TEMPLATE ("sink",
35     GST_PAD_SINK,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS ("video/x-h263")
38     );
39
40 static GstStaticPadTemplate gst_rtph263penc_src_template =
41 GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("application/x-rtp, "
45         "media = (string) \"video\", "
46         "payload = (int) [ 96, 255 ], "
47         "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-1998\"")
48     );
49
50 static void gst_rtph263penc_class_init (GstRtpH263PEncClass * klass);
51 static void gst_rtph263penc_base_init (GstRtpH263PEncClass * klass);
52 static void gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc);
53 static void gst_rtph263penc_finalize (GObject * object);
54
55 static gboolean gst_rtph263penc_setcaps (GstBaseRTPPayload * payload,
56     GstCaps * caps);
57 static GstFlowReturn gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload,
58     GstBuffer * buffer);
59
60 static GstBaseRTPPayloadClass *parent_class = NULL;
61
62 static GType
63 gst_rtph263penc_get_type (void)
64 {
65   static GType rtph263penc_type = 0;
66
67   if (!rtph263penc_type) {
68     static const GTypeInfo rtph263penc_info = {
69       sizeof (GstRtpH263PEncClass),
70       (GBaseInitFunc) gst_rtph263penc_base_init,
71       NULL,
72       (GClassInitFunc) gst_rtph263penc_class_init,
73       NULL,
74       NULL,
75       sizeof (GstRtpH263PEnc),
76       0,
77       (GInstanceInitFunc) gst_rtph263penc_init,
78     };
79
80     rtph263penc_type =
81         g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpH263PEnc",
82         &rtph263penc_info, 0);
83   }
84   return rtph263penc_type;
85 }
86
87 static void
88 gst_rtph263penc_base_init (GstRtpH263PEncClass * klass)
89 {
90   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
91
92   gst_element_class_add_pad_template (element_class,
93       gst_static_pad_template_get (&gst_rtph263penc_src_template));
94   gst_element_class_add_pad_template (element_class,
95       gst_static_pad_template_get (&gst_rtph263penc_sink_template));
96
97   gst_element_class_set_details (element_class, &gst_rtp_h263penc_details);
98 }
99
100 static void
101 gst_rtph263penc_class_init (GstRtpH263PEncClass * klass)
102 {
103   GObjectClass *gobject_class;
104   GstElementClass *gstelement_class;
105   GstBaseRTPPayloadClass *gstbasertppayload_class;
106
107   gobject_class = (GObjectClass *) klass;
108   gstelement_class = (GstElementClass *) klass;
109   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
110
111   parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
112
113   gobject_class->finalize = gst_rtph263penc_finalize;
114
115   gstbasertppayload_class->set_caps = gst_rtph263penc_setcaps;
116   gstbasertppayload_class->handle_buffer = gst_rtph263penc_handle_buffer;
117 }
118
119 static void
120 gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc)
121 {
122   rtph263penc->adapter = gst_adapter_new ();
123 }
124
125 static void
126 gst_rtph263penc_finalize (GObject * object)
127 {
128   GstRtpH263PEnc *rtph263penc;
129
130   rtph263penc = GST_RTP_H263P_ENC (object);
131
132   g_object_unref (rtph263penc->adapter);
133   rtph263penc->adapter = NULL;
134
135   G_OBJECT_CLASS (parent_class)->finalize (object);
136 }
137
138 static gboolean
139 gst_rtph263penc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
140 {
141   gst_basertppayload_set_options (payload, "video", TRUE, "H263-1998", 90000);
142   gst_basertppayload_set_outcaps (payload, NULL);
143
144   return TRUE;
145 }
146
147
148 static GstFlowReturn
149 gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
150 {
151   guint avail;
152   GstBuffer *outbuf;
153   GstFlowReturn ret;
154   gboolean fragmented;
155
156   avail = gst_adapter_available (rtph263penc->adapter);
157   if (avail == 0)
158     return GST_FLOW_OK;
159
160   fragmented = FALSE;
161
162   while (avail > 0) {
163     guint towrite;
164     guint8 *payload;
165     guint8 *data;
166     guint payload_len;
167     gint header_len;
168
169     /* FIXME, do better mtu packing, header len etc should be
170      * included in this calculation. */
171     towrite = MIN (avail, GST_BASE_RTP_PAYLOAD_MTU (rtph263penc));
172     /* for fragmented frames we need 2 bytes header, for other
173      * frames we must reuse the first 2 bytes of the data as the
174      * header */
175     header_len = (fragmented ? 2 : 0);
176     payload_len = header_len + towrite;
177
178     outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
179     /* last fragment gets the marker bit set */
180     gst_rtpbuffer_set_marker (outbuf, avail > towrite ? 0 : 1);
181
182     payload = gst_rtpbuffer_get_payload (outbuf);
183
184     data = (guint8 *) gst_adapter_peek (rtph263penc->adapter, towrite);
185     memcpy (&payload[header_len], data, towrite);
186
187     /*  0                   1
188      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
189      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190      * |   RR    |P|V|   PLEN    |PEBIT|
191      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192      */
193     payload[0] = fragmented ? 0x00 : 0x04;
194     payload[1] = 0;
195
196     GST_BUFFER_TIMESTAMP (outbuf) = rtph263penc->first_ts;
197     gst_adapter_flush (rtph263penc->adapter, towrite);
198
199     ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtph263penc), outbuf);
200
201     avail -= towrite;
202     fragmented = TRUE;
203   }
204
205   return ret;
206 }
207
208 static GstFlowReturn
209 gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer)
210 {
211   GstRtpH263PEnc *rtph263penc;
212   GstFlowReturn ret;
213   guint size;
214
215   rtph263penc = GST_RTP_H263P_ENC (payload);
216
217   size = GST_BUFFER_SIZE (buffer);
218   rtph263penc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
219
220   /* we always encode and flush a full picture */
221   gst_adapter_push (rtph263penc->adapter, buffer);
222   ret = gst_rtph263penc_flush (rtph263penc);
223
224   return ret;
225 }
226
227 gboolean
228 gst_rtph263penc_plugin_init (GstPlugin * plugin)
229 {
230   return gst_element_register (plugin, "rtph263penc",
231       GST_RANK_NONE, GST_TYPE_RTP_H263P_ENC);
232 }