#include <stdio.h>
#include <pcap.h>
#include "remote-ext.h"
#include "cfg.h"
#define RTP2H264_VERSION "1.2"
#define MAXDATASIZE (1500)
FILE * g_outFd = NULL;
char * g_outputFile = NULL;
int g_naluNum = 0;
int g_destPort = -1;
int g_srcPort = -1;
char *g_inputFile = NULL;
int g_payloadType= -1;
int g_rawRtpData = -1;
int g_writeLen = 0;
int g_rtpNum = 0;
/* 4 bytes IP address */
typedef struct ip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
struct ether_hdr {
char ether_dst[6];
char ether_src[6];
u_int16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */
};
/* IPv4 header */
typedef struct ip_header{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;
/* UDP header*/
typedef struct udp_header{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum
}udp_header;
typedef struct
{
unsigned char version; //!< Version, 2 bits, MUST be 0x2
unsigned char padding; //!< Padding bit, Padding MUST NOT be used
unsigned char extension; //!< Extension, MUST be zero
unsigned char cc; //!< CSRC count, normally 0 in the absence of RTP mixers
unsigned char marker; //!< Marker bit
unsigned char pt; //!< 7 bits, Payload Type, dynamically established
unsigned int seq_no; //!< RTP sequence number, incremented by one for each sent packet
unsigned int timestamp; //!< timestamp, 27 MHz for H.264
unsigned int ssrc; //!< Synchronization Source, chosen randomly
unsigned char * payload; //!< the payload including payload headers
unsigned int paylen; //!< length of payload in bytes
} RTPpacket_t;
typedef struct
{
/* 0 1 2 3
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
//intel 的cpu 是intel为小端字节序(低端存到底地址) 而网络流为大端字节序(高端存到低地址)
/*intel 的cpu : 高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端
在内存中存储 :
低->4001(内存地址)version:2
4002(内存地址)padding:1
4003(内存地址)extension:1
高->4004(内存地址)csrc_len:4
网络传输解析 : 高端->version:2->padding:1->extension:1->csrc_len:4->低端 (为正确的文档描述格式)
存入接收内存 :
低->4001(内存地址)version:2
4002(内存地址)padding:1
4003(内存地址)extension:1
高->4004(内存地址)csrc_len:4
本地内存解析 :高端->csrc_len:4 -> extension:1-> padding:1 -> version:2 ->低端 ,
即:
unsigned char csrc_len:4; // expect 0
unsigned char extension:1; // expect 1
unsigned char padding:1; // expect 0
unsigned char version:2; // expect 2
*/
/* byte 0 */
unsigned char csrc_len:4; /* expect 0 */
unsigned char extension:1; /* expect 1, see RTP_OP below */
unsigned char padding:1; /* expect 0 */
unsigned char version:2; /* expect 2 */
/* byte 1 */
unsigned char payloadtype:7; /* RTP_PAYLOAD_RTSP */
unsigned char marker:1; /* expect 1 */
/* bytes 2,3 */
unsigned int seq_no;
/* bytes 4-7 */
unsigned int timestamp;
/* bytes 8-11 */
unsigned int ssrc; /* stream number is used here. */
} RTP_FIXED_HEADER;
typedef struct
{
unsigned char forbidden_bit; //! Should always be FALSE
unsigned char nal_reference_idc; //! NALU_PRIORITY_xxxx
unsigned char nal_unit_type; //! NALU_TYPE_xxxx
unsigned int startcodeprefix_len; //! 前缀字节数
unsigned int len; //! 包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度
unsigned int max_size; //! 做多一个nal 的长度
unsigned char * buf; //! 包含nal 头的nal 数据
unsigned int lost_packets; //! 预留
} NALU_t;
/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
*/
typedef struct
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
} NALU_HEADER; // 1 BYTE
/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
*/
typedef struct
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
} FU_INDICATOR; // 1 BYTE
/*
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
*/
typedef struct
{
//byte 0
unsigned char TYPE:5;
unsigned char R:1;
unsigned char E:1;
unsigned char S:1;
} FU_HEADER; // 1 BYTES
NALU_t *AllocNALU(int buffersize)
{
NALU_t *n;
if ((n = (NALU_t*)calloc (1, sizeof(NALU_t))) == NULL)
{
printf("AllocNALU Error: Allocate Meory To NALU_t Failed ");
exit(0);
}
return n;
}
void FreeNALU(NALU_t *n)
{
if (n)
{
free (n);
}
}
/*
*bufIn:rtppackage
*len: the lengthe of rtppackage
*/
void rtp_unpackage(char *bufIn,int len)
{
unsigned char recvbuf[MAXDATASIZE]={0};
RTPpacket_t *p = NULL;
RTP_FIXED_HEADER * rtp_hdr = NULL;
NALU_HEADER * nalu_hdr = NULL;
NALU_t * n = NULL;
FU_INDICATOR *fu_ind = NULL;
FU_HEADER *fu_hdr= NULL;
int fwrite_number = 0; //存入文件的数据长度
unsigned int seqno;
int version;
if( len <= 12 ) /* rtp header len > 12 */
{
return ;
}
memcpy(recvbuf,bufIn, len); //复制rtp包
//printf("包长度+ rtp头: = %d\n",len);
//////////////////////////////////////////////////////////////////////////
//begin rtp_payload and rtp_header
p = (RTPpacket_t*)&recvbuf[0];
if ((p = (RTPpacket_t*)malloc (sizeof (RTPpacket_t)))== NULL)
{
printf ("RTPpacket_t MMEMORY ERROR\n");
}
if ((p->payload = (unsigned char *)malloc (MAXDATASIZE))== NULL)
{
printf ("RTPpacket_t payload MMEMORY ERROR\n");
}
rtp_hdr =(RTP_FIXED_HEADER*)&recvbuf[0];
//printf("版本号 : %d\n",rtp_hdr->version);
seqno = ntohl(recvbuf[0]);
p->version = rtp_hdr->version;
/* Check RTP version */
version = (seqno & 0xC0000000) >> 30;
if(version != 2)
{
goto breakoff;
}
p->padding = rtp_hdr->padding;
p->extension = rtp_hdr->extension;
p->cc = rtp_hdr->csrc_len;
//printf("标志位 : %d\n",rtp_hdr->marker);
p->marker = rtp_hdr->marker;
//printf("负载类型 :%d\n",rtp_hdr->payloadtype);
p->pt = rtp_hdr->payloadtype;
if( g_payloadType != p->pt)
{
goto breakoff;
}
g_rtpNum++;
//printf("包号 : %d \n",rtp_hdr->seq_no);
p->seq_no = rtp_hdr->seq_no;
//printf("时间戳 : %d\n",rtp_hdr->timestamp);
p->timestamp = rtp_hdr->timestamp;
//printf("帧号 : %d\n",rtp_hdr->ssrc);
p->ssrc = rtp_hdr->ssrc;
if(g_rawRtpData > 0) /* RTP raw data write */
{
memcpy(p->payload,&recvbuf[12],len-12);
p->paylen = len-12;
if( p->paylen > MAXDATASIZE)
printf("write len %d too large\n",p->paylen);
if( p->paylen > 0)
{
fwrite_number = fwrite(p->payload,1,p->paylen,g_outFd); //写RTP数据
}
g_writeLen += p->paylen;
goto breakoff;
}
//end rtp_payload and rtp_header
//////////////////////////////////////////////////////////////////////////
//begin nal_hdr
if (!(n = AllocNALU(800000))) //为结构体nalu_t及其成员buf分配空间。返回值为指向nalu_t存储空间的指针
{
printf("NALU_t MMEMORY ERROR\n");
}
nalu_hdr =(NALU_HEADER*)&recvbuf[12]; //网络传输过来的字节序 ,当存入内存还是和文档描述的相反,只要匹配网络字节序和文档描述即可传输正确。
//printf("forbidden_zero_bit: %d\n",nalu_hdr->F); //网络传输中的方式为:F->NRI->TYPE.. 内存中存储方式为 TYPE->NRI->F (和nal头匹配)。
n->forbidden_bit= nalu_hdr->F << 7; //内存中的字节序。
//printf("nal_reference_idc: %d\n",nalu_hdr->NRI);
n->nal_reference_idc = nalu_hdr->NRI << 5;
//printf("nal 负载类型: %d\n",nalu_hdr->TYPE);
n->nal_unit_type = nalu_hdr->TYPE;
//end nal_hdr
//////////////////////////////////////////////////////////////////////////
//开始解包
if ( nalu_hdr->TYPE == 0)
{
printf("这个包有错误,0无定义\n");
}
else if ( nalu_hdr->TYPE >0 && nalu_hdr->TYPE < 24) //单包
{
// printf("当前包为单包\n");
putc(0x00, g_outFd);
putc(0x00, g_outFd);
putc(0x00, g_outFd);
putc(0x01, g_outFd); //写进起始字节0x00000001
g_writeLen +=4;
memcpy(p->payload,&recvbuf[13],len-13);
p->paylen = len-13;
fwrite(nalu_hdr,1,1,g_outFd); //写NAL_HEADER
g_writeLen += 1;
if(p->paylen > 0)
fwrite_number = fwrite(p->payload,1,p->paylen,g_outFd); //写NAL数据
g_writeLen += p->paylen;
//printf("包长度 + nal= %d\n",total_bytes);
g_naluNum++;
}
else if ( nalu_hdr->TYPE == 24) //STAP-A 单一时间的组合包
{
printf("当前包为STAP-A\n");
}
else if ( nalu_hdr->TYPE == 25) //STAP-B 单一时间的组合包
{
printf("当前包为STAP-B\n");
}
else if (nalu_hdr->TYPE == 26) //MTAP16 多个时间的组合包
{
printf("当前包为MTAP16\n");
}
else if ( nalu_hdr->TYPE == 27) //MTAP24 多个时间的组合包
{
printf("当前包为MTAP24\n");
}
else if ( nalu_hdr->TYPE == 28) //FU-A分片包,解码顺序和传输顺序相同
{
g_naluNum++;
if ((fu_ind = (FU_INDICATOR *)malloc(sizeof(FU_INDICATOR))) == NULL)
{
printf("FU_INDICATOR MEMORY ERROR\n");
}
if ((fu_hdr = (FU_HEADER *)malloc(sizeof(FU_HEADER))) == NULL)
{
printf("FU_HEADER MEMORY ERROR\n");
}
fu_ind=(FU_INDICATOR*)&recvbuf[12]; //分片包用的是FU_INDICATOR而不是NALU_HEADER
//printf("FU_INDICATOR->F :%d\n",fu_ind->F);
n->forbidden_bit = fu_ind->F << 7;
//printf("FU_INDICATOR->NRI :%d\n",fu_ind->NRI);
n->nal_reference_idc = fu_ind->NRI << 5;
//printf("FU_INDICATOR->TYPE :%d\n",fu_ind->TYPE);
n->nal_unit_type = fu_ind->TYPE;
fu_hdr=(FU_HEADER*)&recvbuf[13]; //FU_HEADER赋值
//printf("FU_HEADER->S :%d\n",fu_hdr->S);
//printf("FU_HEADER->E :%d\n",fu_hdr->E);
//printf("FU_HEADER->R :%d\n",fu_hdr->R);
//printf("FU_HEADER->TYPE :%d\n",fu_hdr->TYPE);
n->nal_unit_type = fu_hdr->TYPE; //应用的是FU_HEADER的TYPE
if (rtp_hdr->marker == 1) //分片包最后一个包
{
//printf("当前包为FU-A分片包最后一个包\n");
memcpy(p->payload,&recvbuf[14],len - 14);
p->paylen = len - 14;
if(p->paylen > 0)
fwrite_number = fwrite(p->payload,1,p->paylen,g_outFd); //写NAL数据
g_writeLen += p->paylen;
//printf("包长度 + FU = %d\n",total_bytes);
}else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包
{
if (fu_hdr->S == 1) //分片的第一个包
{
unsigned char F;
unsigned char NRI;
unsigned char TYPE;
unsigned char nh;
//printf("当前包为FU-A分片包第一个包\n");
putc(0x00, g_outFd);
putc(0x00, g_outFd);
putc(0x00, g_outFd);
putc(0x01, g_outFd); //写起始字节码0x00000001
g_writeLen += 4;
F = fu_ind->F << 7;
NRI = fu_ind->NRI << 5;
TYPE = fu_hdr->TYPE; //应用的是FU_HEADER的TYPE
//nh = n->forbidden_bit|n->nal_reference_idc|n->nal_unit_type; //二进制文件也是按 大字节序存储
nh = F | NRI | TYPE;
putc(nh,g_outFd); //写NAL HEADER
g_writeLen +=1;
memcpy(p->payload,&recvbuf[14],len - 14);
p->paylen = len - 14;
if(p->paylen > 0)
fwrite_number = fwrite(p->payload,1,p->paylen,g_outFd); //写NAL数据
g_writeLen += p->paylen;
//printf("包长度 + FU_First = %d\n",total_bytes);
} else //如果不是第一个包
{
//printf("当前包为FU-A分片包\n");
memcpy(p->payload,&recvbuf[14],len - 14);
p->paylen= len - 14;
if(p->paylen > 0)
fwrite_number = fwrite(p->payload,1,p->paylen,g_outFd); //写NAL数据
g_writeLen += p->paylen;
// printf("包长度 + FU = %d\n",total_bytes);
}
}
}else if ( nalu_hdr->TYPE == 29) //FU-B分片包,解码顺序和传输顺序相同
{
if (rtp_hdr->marker == 1) //分片包最后一个包
{
printf("当前包为FU-B分片包最后一个包\n");
}else if (rtp_hdr->marker == 0) //分片包 但不是最后一个包
{
printf("当前包为FU-B分片包\n");
}
} else
{
printf("Unknown NALU Type %d\n",nalu_hdr->TYPE);
}
breakoff:
if(NULL != p)
{
if( NULL != p->payload)
{
free (p->payload);
p->payload = NULL;
}
free (p);
p = NULL;
}
if(NULL!= n)
{
FreeNALU(n);
n=NULL;
}
//结束解包
//////////////////////////////////////////////////////////////////////////
return ;
}
/* Callback function invoked by libpcap for every incoming packet */
/*
pkt_tlen = ip_tlen + eth_hlen(14)
ip_tlen = ip_hlen + udp_tlen
udp_tlen = udp_hlen + udp data len
*/
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
ip_header *ih;
udp_header *uh;
u_int ip_hlen; /* ip header len */
u_int ip_tlen; /* ip total len */
u_int udp_tlen; /* udp total len */
u_int udp_dlen; /* udp data len */
u_int pkt_tlen; /* packet total len */
u_int cap_tlen; /* 实际报文长度,可能与pkt_tlen不一致,tcpdump时默认抓取长度pkt_tlen=96? */
u_int cap_udplen; /* 实际udp长度 */
u_short sport,dport;
struct ether_hdr *ethhdr = NULL;
/*
* unused parameter
*/
(VOID)(param);
if(NULL == pkt_data || NULL == header)
{
return;
}
ethhdr = (struct ether_hdr *)pkt_data;
pkt_tlen = header->len;
cap_tlen = header->caplen;
if (ntohs(ethhdr->ether_type) != 0x0800
|| pkt_tlen <= 0 || pkt_tlen > MAXDATASIZE)/* IPv4 */
{
//printf("Ignoring non IPv4 packet!\n");
return;
}
/* retireve the position of the ip header */
ih = (ip_header *) (pkt_data +
14); //length of ethernet header
if(17 != ih->proto) /* not udp */
{
return ;
}
ip_hlen = (ih->ver_ihl & 0xf) * 4;
ip_tlen = ntohs( ih->tlen );
/* retireve the position of the udp header */
uh = (udp_header *) ((u_char*)ih + ip_hlen);
udp_tlen = (u_long)(ntohs(uh->len));
udp_dlen = udp_tlen-8;
cap_udplen = cap_tlen -14 -ip_hlen -8;
if( pkt_tlen != ip_tlen+14 ||
ip_tlen != ip_hlen+udp_tlen
|| udp_tlen > MAXDATASIZE
|| udp_tlen <= 0
|| cap_udplen <= 0)
{
return ;
}
/* convert from network byte order to host byte order */
sport = ntohs( uh->sport );
dport = ntohs( uh->dport );
if(g_destPort >0 && dport != g_destPort )
{
return ;
}
if(g_srcPort > 0 && sport != g_srcPort)
{
return ;
}
/* print ip addresses and udp ports */
/*
printf("%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d len:%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
sport,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4,
dport, udp_len-8);
*/
rtp_unpackage((u_char*)uh+8, cap_udplen);
return;
}
void print_usage ()
{
fprintf (stdout, "\n\
usage:\n rtp2h264 [-i input_file] [-p payload_type] [-d dest_port] [-s src_port] [-o output_file]\n\
-i input_file specify path of input RTP-H264-ES file(default: h264.pcap)\n\
-o output_file specify path of output H264-Annexb file(default: out.h264)\n\
-d dest_port specify the udp destination port(default: 9080)\n\
-s src_port specify the udp soure port(default: 9078)\n\
-p payload_type specify the rtp payload type(default: 102)\n\
-r write raw rtp data\n\
-h display this usage\n\
-v display version \n");
}
int parse_cmdline(int argc, char **argv)
{
int arg_num=1;
int parseFlag = 1 ;
while (arg_num < argc)
{
if (strncmp ("-d", argv[arg_num], 2) == 0)
{
arg_num++;
if (arg_num < argc)
g_destPort = atoi (argv[arg_num]);
else
g_destPort = 9080;
}
else if (strncmp ("-s", argv[arg_num], 2) == 0)
{
arg_num++;
if (arg_num < argc)
g_srcPort = atoi (argv[arg_num]);
else
g_srcPort = 9078;
}
else if (strncmp ("-p", argv[arg_num], 2) == 0)
{
arg_num++;
if (arg_num < argc)
g_payloadType = atoi (argv[arg_num]);
else
g_payloadType = 102;
}
else if (strncmp ("-r", argv[arg_num], 2) == 0)
{
g_rawRtpData = 1;
}
else if (strncmp ("-i", argv[arg_num], 2) == 0)
{
arg_num++;
g_inputFile = argv[arg_num];
}
else if (strncmp ("-o", argv[arg_num], 2) == 0)
{
arg_num++;
g_outputFile = argv[arg_num];
}
else if (strncmp ("-h", argv[arg_num], 2) == 0)
{
arg_num++;
parseFlag = 0 ;
}
else if (strncmp ("-v", argv[arg_num], 2) == 0)
{
arg_num++;
parseFlag = 0 ;
printf ("\n rtp2h264 version: " RTP2H264_VERSION "\n");
}
else
{
parseFlag = 1 ;
}
arg_num++;
}
return parseFlag;
}
int main(int argc, char **argv)
{
pcap_t *fp;
int parseFlag = -1;
char errbuf[PCAP_ERRBUF_SIZE]={0};
char source[PCAP_BUF_SIZE]={0};
Cfg *cfg = NULL;
parseFlag = parse_cmdline(argc, argv);
if(parseFlag <= 0 )
{
print_usage();
return 0;
}
cfg=cfg_new("config.ini");
if(NULL == cfg )
{
fprintf(stderr,"\nUnable to open the config file 'config.ini'\n");
return -1;
}
g_inputFile = cfg_get_string(cfg,"rtp","input_file","h264.pcap");
g_outputFile = cfg_get_string(cfg,"rtp","output_file","out.h264");
g_payloadType = cfg_get_int(cfg,"rtp","payload_type",102);
g_srcPort = cfg_get_int(cfg,"rtp","src_port",9078);
g_destPort = cfg_get_int(cfg,"rtp","dest_port",9080);
g_rawRtpData = cfg_get_int(cfg,"rtp","write_raw_rtp_data",0);
/* Create the source string according to the new WinPcap syntax */
if ( pcap_createsrcstr( source, // variable that will keep the source string
PCAP_SRC_FILE, // we want to open a file
NULL, // remote host
NULL, // port on the remote host
g_inputFile, // name of the file we want to open
errbuf // error buffer
) != 0)
{
fprintf(stderr,"\nError creating a source string\n");
return -1;
}
/* Open the capture file */
if ( (fp= pcap_open(source, // name of the device
65536, // portion of the packet to capture
// 65536 guarantees that the whole packet will be captured on all the link layers
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout
NULL, // authentication on the remote machine
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the input file %s\n", g_inputFile);
print_usage();
return -1;
}
//print_usage();
if(g_rawRtpData <= 0 )
{
fprintf(stderr,"\nrtp2h264 -i %s -p %d -d %d -s %d -o %s\n",
g_inputFile,g_payloadType,g_destPort, g_srcPort, g_outputFile );
}else
{
fprintf(stderr,"\nrtp2h264 -i %s -p %d -d %d -s %d -o %s -r(write raw rtp data) \n",
g_inputFile,g_payloadType,g_destPort, g_srcPort, g_outputFile );
}
g_outFd = fopen(g_outputFile, "wb");
if (NULL == g_outFd)
{
printf("Error: Open output file %s error\n", g_outputFile);
return -1;
}
// read and dispatch packets until EOF is reached
pcap_loop(fp, 0, packet_handler, NULL);
if(g_rawRtpData <= 0 )
{
fprintf(stderr,"from RTP-H264-ES to H264-Annexb, rtp-package:%d, nalu:%d, total-len:%d\n",g_rtpNum,g_naluNum,g_writeLen);
}else
{
fprintf(stderr,"write rtp raw data total-len:%d\n",g_writeLen);
}
fprintf (stdout, "\n\usage(see 'config.ini'):\n\
-i input_file specify path of input RTP-H264-ES file('%s')\n\
-o output_file specify path of output H264-Annexb file('%s')\n\
-d dest_port specify the udp destination port('%d')\n\
-s src_port specify the udp soure port('%d')\n\
-p payload_type specify the rtp payload type('%d')\n\
-r write raw rtp data('%d')\n",
g_inputFile,g_outputFile,g_destPort,g_srcPort,g_payloadType,g_rawRtpData);
goto_exit:
cfg_destroy(cfg);
return 0;
}