2008-01-04 21:09:48 +01:00
/*
* RTP output format
2009-01-19 16:46:40 +01:00
* Copyright ( c ) 2002 Fabrice Bellard
2008-01-04 21:09:48 +01:00
*
2011-03-18 18:35:10 +01:00
* This file is part of Libav .
2008-01-04 21:09:48 +01:00
*
2011-03-18 18:35:10 +01:00
* Libav is free software ; you can redistribute it and / or
2008-01-04 21:09:48 +01:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
2011-03-18 18:35:10 +01:00
* Libav is distributed in the hope that it will be useful ,
2008-01-04 21:09:48 +01:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2011-03-18 18:35:10 +01:00
* License along with Libav ; if not , write to the Free Software
2008-01-04 21:09:48 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2008-05-09 13:56:36 +02:00
2008-01-04 21:09:48 +01:00
# include "avformat.h"
# include "mpegts.h"
2010-03-10 23:21:39 +01:00
# include "internal.h"
2010-03-28 10:48:45 +02:00
# include "libavutil/random_seed.h"
2011-05-18 14:00:03 +02:00
# include "libavutil/opt.h"
2008-01-04 21:09:48 +01:00
2009-02-06 11:35:52 +01:00
# include "rtpenc.h"
2008-01-04 21:09:48 +01:00
//#define DEBUG
2011-05-18 14:00:03 +02:00
static const AVOption options [ ] = {
{ " rtpflags " , " RTP muxer flags " , offsetof ( RTPMuxContext , flags ) , FF_OPT_TYPE_FLAGS , { . dbl = 0 } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " rtpflags " } ,
{ " latm " , " Use MP4A-LATM packetization instead of MPEG4-GENERIC for AAC " , 0 , FF_OPT_TYPE_CONST , { . dbl = FF_RTP_FLAG_MP4A_LATM } , INT_MIN , INT_MAX , AV_OPT_FLAG_ENCODING_PARAM , " rtpflags " } ,
{ NULL } ,
} ;
static const AVClass rtp_muxer_class = {
. class_name = " RTP muxer " ,
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2008-01-04 21:09:48 +01:00
# define RTCP_SR_SIZE 28
2009-03-27 22:36:44 +01:00
static int is_supported ( enum CodecID id )
{
switch ( id ) {
2009-04-07 08:41:55 +02:00
case CODEC_ID_H263 :
case CODEC_ID_H263P :
2009-03-27 22:36:44 +01:00
case CODEC_ID_H264 :
case CODEC_ID_MPEG1VIDEO :
case CODEC_ID_MPEG2VIDEO :
case CODEC_ID_MPEG4 :
case CODEC_ID_AAC :
case CODEC_ID_MP2 :
case CODEC_ID_MP3 :
case CODEC_ID_PCM_ALAW :
case CODEC_ID_PCM_MULAW :
case CODEC_ID_PCM_S8 :
case CODEC_ID_PCM_S16BE :
case CODEC_ID_PCM_S16LE :
case CODEC_ID_PCM_U16BE :
case CODEC_ID_PCM_U16LE :
case CODEC_ID_PCM_U8 :
case CODEC_ID_MPEG2TS :
2009-04-08 09:16:14 +02:00
case CODEC_ID_AMR_NB :
case CODEC_ID_AMR_WB :
2010-08-07 13:16:07 +02:00
case CODEC_ID_VORBIS :
case CODEC_ID_THEORA :
2010-08-16 16:21:17 +02:00
case CODEC_ID_VP8 :
2010-09-15 19:35:39 +02:00
case CODEC_ID_ADPCM_G722 :
2009-03-27 22:36:44 +01:00
return 1 ;
default :
return 0 ;
}
}
2008-01-04 21:09:48 +01:00
static int rtp_write_header ( AVFormatContext * s1 )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2009-12-28 14:19:54 +01:00
int max_packet_size , n ;
2008-01-04 21:09:48 +01:00
AVStream * st ;
if ( s1 - > nb_streams ! = 1 )
return - 1 ;
st = s1 - > streams [ 0 ] ;
2009-03-27 22:36:44 +01:00
if ( ! is_supported ( st - > codec - > codec_id ) ) {
av_log ( s1 , AV_LOG_ERROR , " Unsupported codec %x \n " , st - > codec - > codec_id ) ;
return - 1 ;
}
2008-01-04 21:09:48 +01:00
2009-12-28 14:19:54 +01:00
s - > payload_type = ff_rtp_get_payload_type ( st - > codec ) ;
if ( s - > payload_type < 0 )
2010-03-31 01:30:55 +02:00
s - > payload_type = RTP_PT_PRIVATE + ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) ;
2008-01-04 21:09:48 +01:00
2010-05-23 10:53:40 +02:00
s - > base_timestamp = av_get_random_seed ( ) ;
2008-01-04 21:09:48 +01:00
s - > timestamp = s - > base_timestamp ;
s - > cur_timestamp = 0 ;
2010-05-23 10:53:40 +02:00
s - > ssrc = av_get_random_seed ( ) ;
2008-01-04 21:09:48 +01:00
s - > first_packet = 1 ;
2010-03-10 23:21:39 +01:00
s - > first_rtcp_ntp_time = ff_ntp_time ( ) ;
2010-03-15 11:37:12 +01:00
if ( s1 - > start_time_realtime )
/* Round the NTP time to whole milliseconds. */
s - > first_rtcp_ntp_time = ( s1 - > start_time_realtime / 1000 ) * 1000 +
NTP_OFFSET_US ;
2008-01-04 21:09:48 +01:00
2011-03-06 18:04:49 +01:00
max_packet_size = s1 - > pb - > max_packet_size ;
2008-01-04 21:09:48 +01:00
if ( max_packet_size < = 12 )
return AVERROR ( EIO ) ;
2009-02-06 21:41:15 +01:00
s - > buf = av_malloc ( max_packet_size ) ;
if ( s - > buf = = NULL ) {
return AVERROR ( ENOMEM ) ;
}
2008-01-04 21:09:48 +01:00
s - > max_payload_size = max_packet_size - 12 ;
s - > max_frames_per_packet = 0 ;
if ( s1 - > max_delay ) {
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2008-01-04 21:09:48 +01:00
if ( st - > codec - > frame_size = = 0 ) {
av_log ( s1 , AV_LOG_ERROR , " Cannot respect max delay: frame size = 0 \n " ) ;
} else {
s - > max_frames_per_packet = av_rescale_rnd ( s1 - > max_delay , st - > codec - > sample_rate , AV_TIME_BASE * st - > codec - > frame_size , AV_ROUND_DOWN ) ;
}
}
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2008-01-04 21:09:48 +01:00
/* FIXME: We should round down here... */
2008-06-25 13:55:57 +02:00
s - > max_frames_per_packet = av_rescale_q ( s1 - > max_delay , ( AVRational ) { 1 , 1000000 } , st - > codec - > time_base ) ;
2008-01-04 21:09:48 +01:00
}
}
av_set_pts_info ( st , 32 , 1 , 90000 ) ;
switch ( st - > codec - > codec_id ) {
case CODEC_ID_MP2 :
case CODEC_ID_MP3 :
s - > buf_ptr = s - > buf + 4 ;
break ;
case CODEC_ID_MPEG1VIDEO :
case CODEC_ID_MPEG2VIDEO :
break ;
case CODEC_ID_MPEG2TS :
n = s - > max_payload_size / TS_PACKET_SIZE ;
if ( n < 1 )
n = 1 ;
s - > max_payload_size = n * TS_PACKET_SIZE ;
s - > buf_ptr = s - > buf ;
break ;
2010-06-16 14:59:47 +02:00
case CODEC_ID_H264 :
/* check for H.264 MP4 syntax */
2010-06-17 12:30:52 +02:00
if ( st - > codec - > extradata_size > 4 & & st - > codec - > extradata [ 0 ] = = 1 ) {
2010-06-16 14:59:47 +02:00
s - > nal_length_size = ( st - > codec - > extradata [ 4 ] & 0x03 ) + 1 ;
}
break ;
2010-08-07 13:16:07 +02:00
case CODEC_ID_VORBIS :
case CODEC_ID_THEORA :
if ( ! s - > max_frames_per_packet ) s - > max_frames_per_packet = 15 ;
s - > max_frames_per_packet = av_clip ( s - > max_frames_per_packet , 1 , 15 ) ;
s - > max_payload_size - = 6 ; // ident+frag+tdt/vdt+pkt_num+pkt_length
s - > num_frames = 0 ;
goto defaultcase ;
2010-08-16 16:21:17 +02:00
case CODEC_ID_VP8 :
2010-12-05 12:45:57 +01:00
av_log ( s1 , AV_LOG_ERROR , " RTP VP8 payload implementation is "
" incompatible with the latest spec drafts. \n " ) ;
2010-08-16 16:21:17 +02:00
break ;
2010-09-15 19:35:39 +02:00
case CODEC_ID_ADPCM_G722 :
/* Due to a historical error, the clock rate for G722 in RTP is
* 8000 , even if the sample rate is 16000. See RFC 3551. */
av_set_pts_info ( st , 32 , 1 , 8000 ) ;
break ;
2009-04-08 09:16:14 +02:00
case CODEC_ID_AMR_NB :
case CODEC_ID_AMR_WB :
if ( ! s - > max_frames_per_packet )
s - > max_frames_per_packet = 12 ;
if ( st - > codec - > codec_id = = CODEC_ID_AMR_NB )
n = 31 ;
else
n = 61 ;
/* max_header_toc_size + the largest AMR payload must fit */
if ( 1 + s - > max_frames_per_packet + n > s - > max_payload_size ) {
av_log ( s1 , AV_LOG_ERROR , " RTP max payload size too small for AMR \n " ) ;
return - 1 ;
}
if ( st - > codec - > channels ! = 1 ) {
av_log ( s1 , AV_LOG_ERROR , " Only mono is supported \n " ) ;
return - 1 ;
}
2008-01-04 21:09:48 +01:00
case CODEC_ID_AAC :
2009-02-05 15:53:25 +01:00
s - > num_frames = 0 ;
2008-01-04 21:09:48 +01:00
default :
2010-08-07 13:16:07 +02:00
defaultcase :
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2008-01-04 21:09:48 +01:00
av_set_pts_info ( st , 32 , 1 , st - > codec - > sample_rate ) ;
}
s - > buf_ptr = s - > buf ;
break ;
}
return 0 ;
}
/* send an rtcp sender report packet */
static void rtcp_send_sr ( AVFormatContext * s1 , int64_t ntp_time )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
uint32_t rtp_ts ;
2011-01-29 17:46:18 +01:00
av_dlog ( s1 , " RTCP: %02x % " PRIx64 " %x \n " , s - > payload_type , ntp_time , s - > timestamp ) ;
2008-01-04 21:09:48 +01:00
s - > last_rtcp_ntp_time = ntp_time ;
2008-06-25 13:55:57 +02:00
rtp_ts = av_rescale_q ( ntp_time - s - > first_rtcp_ntp_time , ( AVRational ) { 1 , 1000000 } ,
2008-01-04 21:09:48 +01:00
s1 - > streams [ 0 ] - > time_base ) + s - > base_timestamp ;
2011-02-21 19:28:17 +01:00
avio_w8 ( s1 - > pb , ( RTP_VERSION < < 6 ) ) ;
avio_w8 ( s1 - > pb , RTCP_SR ) ;
avio_wb16 ( s1 - > pb , 6 ) ; /* length in words - 1 */
avio_wb32 ( s1 - > pb , s - > ssrc ) ;
avio_wb32 ( s1 - > pb , ntp_time / 1000000 ) ;
avio_wb32 ( s1 - > pb , ( ( ntp_time % 1000000 ) < < 32 ) / 1000000 ) ;
avio_wb32 ( s1 - > pb , rtp_ts ) ;
avio_wb32 ( s1 - > pb , s - > packet_count ) ;
avio_wb32 ( s1 - > pb , s - > octet_count ) ;
2011-03-14 20:39:06 +01:00
avio_flush ( s1 - > pb ) ;
2008-01-04 21:09:48 +01:00
}
/* send an rtp packet. sequence number is incremented, but the caller
must update the timestamp itself */
void ff_rtp_send_data ( AVFormatContext * s1 , const uint8_t * buf1 , int len , int m )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( s1 , " rtp_send_data size=%d \n " , len ) ;
2008-01-04 21:09:48 +01:00
/* build the RTP header */
2011-02-21 19:28:17 +01:00
avio_w8 ( s1 - > pb , ( RTP_VERSION < < 6 ) ) ;
avio_w8 ( s1 - > pb , ( s - > payload_type & 0x7f ) | ( ( m & 0x01 ) < < 7 ) ) ;
avio_wb16 ( s1 - > pb , s - > seq ) ;
avio_wb32 ( s1 - > pb , s - > timestamp ) ;
avio_wb32 ( s1 - > pb , s - > ssrc ) ;
2008-01-04 21:09:48 +01:00
2011-02-21 19:28:17 +01:00
avio_write ( s1 - > pb , buf1 , len ) ;
2011-03-14 20:39:06 +01:00
avio_flush ( s1 - > pb ) ;
2008-01-04 21:09:48 +01:00
s - > seq + + ;
s - > octet_count + = len ;
s - > packet_count + + ;
}
/* send an integer number of samples and compute time stamp and fill
the rtp send buffer before sending . */
static void rtp_send_samples ( AVFormatContext * s1 ,
const uint8_t * buf1 , int size , int sample_size )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
int len , max_packet_size , n ;
max_packet_size = ( s - > max_payload_size / sample_size ) * sample_size ;
/* not needed, but who nows */
if ( ( size % sample_size ) ! = 0 )
av_abort ( ) ;
n = 0 ;
while ( size > 0 ) {
s - > buf_ptr = s - > buf ;
len = FFMIN ( max_packet_size , size ) ;
/* copy data */
memcpy ( s - > buf_ptr , buf1 , len ) ;
s - > buf_ptr + = len ;
buf1 + = len ;
size - = len ;
s - > timestamp = s - > cur_timestamp + n / sample_size ;
ff_rtp_send_data ( s1 , s - > buf , s - > buf_ptr - s - > buf , 0 ) ;
n + = ( s - > buf_ptr - s - > buf ) ;
}
}
static void rtp_send_mpegaudio ( AVFormatContext * s1 ,
const uint8_t * buf1 , int size )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
int len , count , max_packet_size ;
max_packet_size = s - > max_payload_size ;
/* test if we must flush because not enough space */
len = ( s - > buf_ptr - s - > buf ) ;
if ( ( len + size ) > max_packet_size ) {
if ( len > 4 ) {
ff_rtp_send_data ( s1 , s - > buf , s - > buf_ptr - s - > buf , 0 ) ;
s - > buf_ptr = s - > buf + 4 ;
}
}
if ( s - > buf_ptr = = s - > buf + 4 ) {
s - > timestamp = s - > cur_timestamp ;
}
/* add the packet */
if ( size > max_packet_size ) {
/* big packet: fragment */
count = 0 ;
while ( size > 0 ) {
len = max_packet_size - 4 ;
if ( len > size )
len = size ;
/* build fragmented packet */
s - > buf [ 0 ] = 0 ;
s - > buf [ 1 ] = 0 ;
s - > buf [ 2 ] = count > > 8 ;
s - > buf [ 3 ] = count ;
memcpy ( s - > buf + 4 , buf1 , len ) ;
ff_rtp_send_data ( s1 , s - > buf , len + 4 , 0 ) ;
size - = len ;
buf1 + = len ;
count + = len ;
}
} else {
if ( s - > buf_ptr = = s - > buf + 4 ) {
/* no fragmentation possible */
s - > buf [ 0 ] = 0 ;
s - > buf [ 1 ] = 0 ;
s - > buf [ 2 ] = 0 ;
s - > buf [ 3 ] = 0 ;
}
memcpy ( s - > buf_ptr , buf1 , size ) ;
s - > buf_ptr + = size ;
}
}
static void rtp_send_raw ( AVFormatContext * s1 ,
const uint8_t * buf1 , int size )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
int len , max_packet_size ;
max_packet_size = s - > max_payload_size ;
while ( size > 0 ) {
len = max_packet_size ;
if ( len > size )
len = size ;
s - > timestamp = s - > cur_timestamp ;
ff_rtp_send_data ( s1 , buf1 , len , ( len = = size ) ) ;
buf1 + = len ;
size - = len ;
}
}
/* NOTE: size is assumed to be an integer multiple of TS_PACKET_SIZE */
static void rtp_send_mpegts_raw ( AVFormatContext * s1 ,
const uint8_t * buf1 , int size )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
int len , out_len ;
while ( size > = TS_PACKET_SIZE ) {
len = s - > max_payload_size - ( s - > buf_ptr - s - > buf ) ;
if ( len > size )
len = size ;
memcpy ( s - > buf_ptr , buf1 , len ) ;
buf1 + = len ;
size - = len ;
s - > buf_ptr + = len ;
out_len = s - > buf_ptr - s - > buf ;
if ( out_len > = s - > max_payload_size ) {
ff_rtp_send_data ( s1 , s - > buf , out_len , 0 ) ;
s - > buf_ptr = s - > buf ;
}
}
}
static int rtp_write_packet ( AVFormatContext * s1 , AVPacket * pkt )
{
2009-02-06 11:35:52 +01:00
RTPMuxContext * s = s1 - > priv_data ;
2008-01-04 21:09:48 +01:00
AVStream * st = s1 - > streams [ 0 ] ;
int rtcp_bytes ;
int size = pkt - > size ;
2011-01-29 17:46:18 +01:00
av_dlog ( s1 , " %d: write len=%d \n " , pkt - > stream_index , size ) ;
2008-01-04 21:09:48 +01:00
rtcp_bytes = ( ( s - > octet_count - s - > last_octet_count ) * RTCP_TX_RATIO_NUM ) /
RTCP_TX_RATIO_DEN ;
if ( s - > first_packet | | ( ( rtcp_bytes > = RTCP_SR_SIZE ) & &
2010-03-10 23:21:39 +01:00
( ff_ntp_time ( ) - s - > last_rtcp_ntp_time > 5000000 ) ) ) {
rtcp_send_sr ( s1 , ff_ntp_time ( ) ) ;
2008-01-04 21:09:48 +01:00
s - > last_octet_count = s - > octet_count ;
s - > first_packet = 0 ;
}
s - > cur_timestamp = s - > base_timestamp + pkt - > pts ;
switch ( st - > codec - > codec_id ) {
case CODEC_ID_PCM_MULAW :
case CODEC_ID_PCM_ALAW :
case CODEC_ID_PCM_U8 :
case CODEC_ID_PCM_S8 :
2009-12-28 14:41:09 +01:00
rtp_send_samples ( s1 , pkt - > data , size , 1 * st - > codec - > channels ) ;
2008-01-04 21:09:48 +01:00
break ;
case CODEC_ID_PCM_U16BE :
case CODEC_ID_PCM_U16LE :
case CODEC_ID_PCM_S16BE :
case CODEC_ID_PCM_S16LE :
2009-12-28 14:41:09 +01:00
rtp_send_samples ( s1 , pkt - > data , size , 2 * st - > codec - > channels ) ;
2008-01-04 21:09:48 +01:00
break ;
2010-09-15 19:35:39 +02:00
case CODEC_ID_ADPCM_G722 :
/* The actual sample size is half a byte per sample, but since the
* stream clock rate is 8000 Hz while the sample rate is 16000 Hz ,
* the correct parameter for send_samples is 1 byte per stream clock . */
rtp_send_samples ( s1 , pkt - > data , size , 1 * st - > codec - > channels ) ;
break ;
2008-01-04 21:09:48 +01:00
case CODEC_ID_MP2 :
case CODEC_ID_MP3 :
2009-12-28 14:41:09 +01:00
rtp_send_mpegaudio ( s1 , pkt - > data , size ) ;
2008-01-04 21:09:48 +01:00
break ;
case CODEC_ID_MPEG1VIDEO :
case CODEC_ID_MPEG2VIDEO :
2009-12-28 14:41:09 +01:00
ff_rtp_send_mpegvideo ( s1 , pkt - > data , size ) ;
2008-01-04 21:09:48 +01:00
break ;
case CODEC_ID_AAC :
2011-05-18 14:00:03 +02:00
if ( s - > flags & FF_RTP_FLAG_MP4A_LATM )
ff_rtp_send_latm ( s1 , pkt - > data , size ) ;
else
ff_rtp_send_aac ( s1 , pkt - > data , size ) ;
2008-01-04 21:09:48 +01:00
break ;
2009-04-08 09:16:14 +02:00
case CODEC_ID_AMR_NB :
case CODEC_ID_AMR_WB :
2009-12-28 14:41:09 +01:00
ff_rtp_send_amr ( s1 , pkt - > data , size ) ;
2009-04-08 09:16:14 +02:00
break ;
2008-01-04 21:09:48 +01:00
case CODEC_ID_MPEG2TS :
2009-12-28 14:41:09 +01:00
rtp_send_mpegts_raw ( s1 , pkt - > data , size ) ;
2008-01-04 21:09:48 +01:00
break ;
2008-01-21 15:01:57 +01:00
case CODEC_ID_H264 :
2009-12-28 14:41:09 +01:00
ff_rtp_send_h264 ( s1 , pkt - > data , size ) ;
2008-01-21 15:01:57 +01:00
break ;
2009-04-07 08:41:55 +02:00
case CODEC_ID_H263 :
case CODEC_ID_H263P :
2009-12-28 14:41:09 +01:00
ff_rtp_send_h263 ( s1 , pkt - > data , size ) ;
2009-04-07 08:41:55 +02:00
break ;
2010-08-07 13:16:07 +02:00
case CODEC_ID_VORBIS :
case CODEC_ID_THEORA :
ff_rtp_send_xiph ( s1 , pkt - > data , size ) ;
break ;
2010-08-16 16:21:17 +02:00
case CODEC_ID_VP8 :
ff_rtp_send_vp8 ( s1 , pkt - > data , size ) ;
break ;
2008-01-04 21:09:48 +01:00
default :
/* better than nothing : send the codec raw data */
2009-12-28 14:41:09 +01:00
rtp_send_raw ( s1 , pkt - > data , size ) ;
2008-01-04 21:09:48 +01:00
break ;
}
return 0 ;
}
2009-02-06 21:41:15 +01:00
static int rtp_write_trailer ( AVFormatContext * s1 )
{
RTPMuxContext * s = s1 - > priv_data ;
av_freep ( & s - > buf ) ;
return 0 ;
}
2011-01-25 23:03:28 +01:00
AVOutputFormat ff_rtp_muxer = {
2008-01-04 21:09:48 +01:00
" rtp " ,
2008-06-03 18:20:54 +02:00
NULL_IF_CONFIG_SMALL ( " RTP output format " ) ,
2008-01-04 21:09:48 +01:00
NULL ,
NULL ,
2009-02-06 11:35:52 +01:00
sizeof ( RTPMuxContext ) ,
2008-01-04 21:09:48 +01:00
CODEC_ID_PCM_MULAW ,
CODEC_ID_NONE ,
rtp_write_header ,
rtp_write_packet ,
2009-02-06 21:41:15 +01:00
rtp_write_trailer ,
2011-05-18 14:00:03 +02:00
. priv_class = & rtp_muxer_class ,
2008-01-04 21:09:48 +01:00
} ;