lib: media_player: fix aout callbacks having no effects
[vlc.git] / modules / access / rtp / xiph.c
blob8cdfcd4a57afa00d6ac496b61e3e3c909d7fa827
1 /**
2 * @file rtpxiph.c
3 * @brief Real-Time Protocol (RTP) Xiph payloads receival
4 */
5 /*****************************************************************************
6 * Copyright © 2008 Rémi Denis-Courmont
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 #include <stdarg.h>
27 #include <assert.h>
29 #include <vlc_common.h>
30 #include <vlc_demux.h>
31 #include <vlc_network.h>
32 #include <vlc_plugin.h>
34 #include "../../demux/xiph.h"
36 #include "rtp.h"
38 typedef struct rtp_xiph_t
40 es_out_id_t *id;
41 block_t *block;
42 uint32_t ident;
43 bool vorbis;
44 } rtp_xiph_t;
46 static void *xiph_init (bool vorbis)
48 rtp_xiph_t *self = malloc (sizeof (*self));
50 if (self == NULL)
51 return NULL;
53 self->id = NULL;
54 self->block = NULL;
55 self->ident = 0xffffffff; /* impossible value on the wire */
56 self->vorbis = vorbis;
57 return self;
60 #if 0
61 /* PT=dynamic
62 * vorbis: Xiph Vorbis audio (RFC 5215)
64 static void *vorbis_init (demux_t *demux)
66 (void)demux;
67 return xiph_init (true);
69 #endif
71 /* PT=dynamic
72 * vorbis: Xiph Theora video
74 void *theora_init (demux_t *demux)
76 (void)demux;
77 return xiph_init (false);
80 void xiph_destroy (demux_t *demux, void *data)
82 rtp_xiph_t *self = data;
84 if (!data)
85 return;
86 if (self->block)
88 self->block->i_flags |= BLOCK_FLAG_CORRUPTED;
89 codec_decode (demux, self->id, self->block);
91 codec_destroy (demux, self->id);
92 free (self);
95 /* Convert configuration from RTP to VLC format */
96 static ssize_t xiph_header (void **pextra, const uint8_t *buf, size_t len)
98 /* Headers number */
99 if (len == 0)
100 return -1; /* Invalid */
101 unsigned hcount = 1 + *buf++;
102 len--;
103 if (hcount != 3)
104 return -1; /* Invalid */
106 /* Header lengths */
107 uint16_t idlen = 0, cmtlen = 0, setuplen = 0;
110 if (len == 0)
111 return -1;
112 idlen = (idlen << 7) | (*buf & 0x7f);
113 len--;
115 while (*buf++ & 0x80);
118 if (len == 0)
119 return -1;
120 cmtlen = (cmtlen << 7) | (*buf & 0x7f);
121 len--;
123 while (*buf++ & 0x80);
124 if (len < idlen + cmtlen)
125 return -1;
126 setuplen = len - (idlen + cmtlen);
128 /* Create the VLC extra format header */
129 unsigned sizes[3] = {
130 idlen, cmtlen, setuplen
132 const void *payloads[3] = {
133 buf + 0,
134 buf + idlen,
135 buf + idlen + cmtlen
137 void *extra;
138 int extra_size;
139 if (xiph_PackHeaders (&extra_size, &extra, sizes, payloads, 3))
140 return -1;;
141 *pextra = extra;
142 return extra_size;
146 void xiph_decode (demux_t *demux, void *data, block_t *block)
148 rtp_xiph_t *self = data;
150 if (!data || block->i_buffer < 4)
151 goto drop;
153 /* 32-bits RTP header (§2.2) */
154 uint32_t ident = GetDWBE (block->p_buffer);
155 block->i_buffer -= 4;
156 block->p_buffer += 4;
158 unsigned fragtype = (ident >> 6) & 3;
159 unsigned datatype = (ident >> 4) & 3;
160 unsigned pkts = (ident) & 15;
161 ident >>= 8;
163 /* RTP defragmentation */
164 if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY))
165 { /* Screwed! discontinuity within a fragmented packet */
166 msg_Warn (demux, self->vorbis ?
167 "discontinuity in fragmented Vorbis packet" :
168 "discontinuity in fragmented Theora packet");
169 block_Release (self->block);
170 self->block = NULL;
173 if (fragtype <= 1)
175 if (self->block) /* Invalid first fragment */
177 block_Release (self->block);
178 self->block = NULL;
181 else
183 if (!self->block)
184 goto drop; /* Invalid non-first fragment */
187 if (fragtype > 0)
188 { /* Fragment */
189 if (pkts > 0 || block->i_buffer < 2)
190 goto drop;
192 size_t fraglen = GetWBE (block->p_buffer);
193 if (block->i_buffer < (fraglen + 2))
194 goto drop; /* Invalid payload length */
195 block->i_buffer = fraglen;
196 if (fragtype == 1)/* Keep first fragment */
198 block->i_buffer += 2;
199 self->block = block;
201 else
202 { /* Append non-first fragment */
203 size_t len = self->block->i_buffer;
204 self->block = block_Realloc (self->block, 0, len + fraglen);
205 if (!self->block)
207 block_Release (block);
208 return;
210 memcpy (self->block->p_buffer + len, block->p_buffer + 2,
211 fraglen);
212 block_Release (block);
214 if (fragtype < 3)
215 return; /* Non-last fragment */
217 /* Last fragment reached, process it */
218 block = self->block;
219 self->block = NULL;
220 SetWBE (block->p_buffer, block->i_buffer - 2);
221 pkts = 1;
224 /* RTP payload packets processing */
225 while (pkts > 0)
227 if (block->i_buffer < 2)
228 goto drop;
230 size_t len = GetWBE (block->p_buffer);
231 block->i_buffer -= 2;
232 block->p_buffer += 2;
233 if (block->i_buffer < len)
234 goto drop;
236 switch (datatype)
238 case 0: /* Raw payload */
240 if (self->ident != ident)
242 msg_Warn (demux, self->vorbis ?
243 "ignoring raw Vorbis payload without configuration" :
244 "ignoring raw Theora payload without configuration");
245 break;
247 block_t *raw = block_Alloc (len);
248 memcpy (raw->p_buffer, block->p_buffer, len);
249 raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */
250 codec_decode (demux, self->id, raw);
251 break;
254 case 1: /* Packed configuration frame (§3.1.1) */
256 if (self->ident == ident)
257 break; /* Ignore config retransmission */
259 void *extv;
260 ssize_t extc = xiph_header (&extv, block->p_buffer, len);
261 if (extc < 0)
262 break;
264 es_format_t fmt;
265 es_format_Init (&fmt, self->vorbis ? AUDIO_ES : VIDEO_ES,
266 self->vorbis ? VLC_CODEC_VORBIS
267 : VLC_CODEC_THEORA);
268 fmt.p_extra = extv;
269 fmt.i_extra = extc;
270 codec_destroy (demux, self->id);
271 msg_Dbg (demux, self->vorbis ?
272 "Vorbis packed configuration received (%06"PRIx32")" :
273 "Theora packed configuration received (%06"PRIx32")",
274 ident);
275 self->ident = ident;
276 self->id = codec_init (demux, &fmt);
277 break;
281 block->i_buffer -= len;
282 block->p_buffer += len;
283 pkts--;
286 drop:
287 block_Release (block);