3 * @brief Real-Time Protocol (RTP) Xiph payloads receival
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 ****************************************************************************/
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"
38 typedef struct rtp_xiph_t
46 static void *xiph_init (bool vorbis
)
48 rtp_xiph_t
*self
= malloc (sizeof (*self
));
55 self
->ident
= 0xffffffff; /* impossible value on the wire */
56 self
->vorbis
= vorbis
;
62 * vorbis: Xiph Vorbis audio (RFC 5215)
64 static void *vorbis_init (demux_t
*demux
)
67 return xiph_init (true);
72 * vorbis: Xiph Theora video
74 void *theora_init (demux_t
*demux
)
77 return xiph_init (false);
80 void xiph_destroy (demux_t
*demux
, void *data
)
82 rtp_xiph_t
*self
= data
;
88 self
->block
->i_flags
|= BLOCK_FLAG_CORRUPTED
;
89 codec_decode (demux
, self
->id
, self
->block
);
91 codec_destroy (demux
, self
->id
);
95 /* Convert configuration from RTP to VLC format */
96 static ssize_t
xiph_header (void **pextra
, const uint8_t *buf
, size_t len
)
100 return -1; /* Invalid */
101 unsigned hcount
= 1 + *buf
++;
104 return -1; /* Invalid */
107 uint16_t idlen
= 0, cmtlen
= 0, setuplen
= 0;
112 idlen
= (idlen
<< 7) | (*buf
& 0x7f);
115 while (*buf
++ & 0x80);
120 cmtlen
= (cmtlen
<< 7) | (*buf
& 0x7f);
123 while (*buf
++ & 0x80);
124 if (len
< idlen
+ cmtlen
)
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] = {
139 if (xiph_PackHeaders (&extra_size
, &extra
, sizes
, payloads
, 3))
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)
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;
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
);
175 if (self
->block
) /* Invalid first fragment */
177 block_Release (self
->block
);
184 goto drop
; /* Invalid non-first fragment */
189 if (pkts
> 0 || block
->i_buffer
< 2)
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;
202 { /* Append non-first fragment */
203 size_t len
= self
->block
->i_buffer
;
204 self
->block
= block_Realloc (self
->block
, 0, len
+ fraglen
);
207 block_Release (block
);
210 memcpy (self
->block
->p_buffer
+ len
, block
->p_buffer
+ 2,
212 block_Release (block
);
215 return; /* Non-last fragment */
217 /* Last fragment reached, process it */
220 SetWBE (block
->p_buffer
, block
->i_buffer
- 2);
224 /* RTP payload packets processing */
227 if (block
->i_buffer
< 2)
230 size_t len
= GetWBE (block
->p_buffer
);
231 block
->i_buffer
-= 2;
232 block
->p_buffer
+= 2;
233 if (block
->i_buffer
< len
)
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");
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
);
254 case 1: /* Packed configuration frame (§3.1.1) */
256 if (self
->ident
== ident
)
257 break; /* Ignore config retransmission */
260 ssize_t extc
= xiph_header (&extv
, block
->p_buffer
, len
);
265 es_format_Init (&fmt
, self
->vorbis
? AUDIO_ES
: VIDEO_ES
,
266 self
->vorbis
? VLC_CODEC_VORBIS
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
")",
276 self
->id
= codec_init (demux
, &fmt
);
281 block
->i_buffer
-= len
;
282 block
->p_buffer
+= len
;
287 block_Release (block
);