diff --git a/modules/demux/rtp.c b/modules/demux/rtp.c index 8f917efce2ee6cdc4ad55d073cf54f6cf4499c29..fb512ad83c9a7bb849bbde84b6bffb1e818b5ca6 100644 --- a/modules/demux/rtp.c +++ b/modules/demux/rtp.c @@ -601,6 +601,130 @@ static void *ts_init (demux_t *demux) * Hmm, none implemented yet. */ +/* PT=dynamic + * vorbis: Xiph Vorbis audio (draft-ietf-avt-rtp-vorbis-09, RFC FIXME) + */ +typedef struct rtp_vorbis_t +{ + es_out_id_t *id; + block_t *block; +} rtp_vorbis_t; + +static void *vorbis_init (demux_t *demux) +{ + es_format_t fmt; + rtp_vorbis_t *self = malloc (sizeof (*self)); + + if (self == NULL) + return NULL; + + es_format_Init (&fmt, AUDIO_ES, VLC_FOURCC ('v', 'o', 'r', 'b')); + self->id = codec_init (demux, &fmt); + self->block = NULL; + return self; +} + +static void vorbis_destroy (demux_t *demux, void *data) +{ + rtp_vorbis_t *self = data; + + if (!data) + return; + if (self->block) + { + self->block->i_flags |= BLOCK_FLAG_CORRUPTED; + codec_decode (demux, NULL, self->block); + } + codec_destroy (demux, self->id); + free (self); +} + +static void vorbis_decode (demux_t *demux, void *data, block_t *block) +{ + rtp_vorbis_t *self = data; + + if (!data || block->i_buffer < 4) + goto drop; + + /* 32-bits Vorbis RTP header */ + uint32_t ident = GetDWBE (block->p_buffer); + block->i_buffer -= 4; + block->p_buffer += 4; + + unsigned fragtype = (ident >> 6) & 3; + unsigned datatype = (ident >> 4) & 3; + unsigned pkts = (ident) & 15; + ident >>= 8; + + /* Vorbis RTP defragmentation */ + if ((fragtype != 0) && (pkts > 0)) + goto drop; + + if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY)) + { /* Screwed! discontinuity within a fragmented packet */ + msg_Warn (demux, "discontinuity in fragmented Vorbis packet"); + self->block->i_flags |= BLOCK_FLAG_CORRUPTED; + codec_decode (demux, NULL, self->block); + self->block = NULL; + } + + if (fragtype <= 1) + { + if (self->block) /* Buggy sender! */ + { + block_Release (self->block); + self->block = NULL; + } + if (fragtype == 1) + { + self->block = block; + return; + } + } + else + { + if (!self->block) /* Buggy sender! */ + goto drop; + + size_t len = self->block->i_buffer; + self->block = block_Realloc (self->block, 0, len + block->i_buffer); + if (self->block) + memcpy (self->block->p_buffer + len, block->p_buffer, + block->i_buffer); + block_Release (block); + if (fragtype == 2 || !self->block) + return; + + /* End of fragment reached */ + block = self->block; + self->block = NULL; + } + + switch (datatype) + { + case 0: + msg_Dbg (demux, "Payload: raw"); + break; + case 1: + msg_Dbg (demux, "Payload: configuration"); + break; + case 2: + msg_Dbg (demux, "Payload: comment"); + break; + default: + block_Release (block); + return; + } + msg_Dbg (demux, "Packets number %u", pkts); + msg_Dbg (demux, "Configuration %"PRIu32, ident); + + codec_decode (demux, NULL, block); + return; + +drop: + block_Release (block); +} + /** * Processing callback */ @@ -692,6 +816,14 @@ static int Demux (demux_t *demux) pt.frequency = 90000; break; + case 96: + msg_Dbg (demux, "detected Vorbis"); + pt.init = vorbis_init; + pt.destroy = vorbis_destroy; + pt.decode = vorbis_decode; + pt.frequency = 4281000; + break; + default: goto drop; }