|
|
|
@@ -18,6 +18,7 @@ |
|
|
|
*/ |
|
|
|
#include "avformat.h" |
|
|
|
#include "mpegts.h" |
|
|
|
#include "bitstream.h" |
|
|
|
|
|
|
|
#include <unistd.h> |
|
|
|
#include <sys/types.h> |
|
|
|
@@ -42,36 +43,146 @@ |
|
|
|
'url_open_dyn_packet_buf') |
|
|
|
*/ |
|
|
|
|
|
|
|
#define RTP_VERSION 2 |
|
|
|
|
|
|
|
#define RTP_MAX_SDES 256 /* maximum text length for SDES */ |
|
|
|
|
|
|
|
/* RTCP paquets use 0.5 % of the bandwidth */ |
|
|
|
#define RTCP_TX_RATIO_NUM 5 |
|
|
|
#define RTCP_TX_RATIO_DEN 1000 |
|
|
|
|
|
|
|
typedef enum { |
|
|
|
RTCP_SR = 200, |
|
|
|
RTCP_RR = 201, |
|
|
|
RTCP_SDES = 202, |
|
|
|
RTCP_BYE = 203, |
|
|
|
RTCP_APP = 204 |
|
|
|
} rtcp_type_t; |
|
|
|
|
|
|
|
typedef enum { |
|
|
|
RTCP_SDES_END = 0, |
|
|
|
RTCP_SDES_CNAME = 1, |
|
|
|
RTCP_SDES_NAME = 2, |
|
|
|
RTCP_SDES_EMAIL = 3, |
|
|
|
RTCP_SDES_PHONE = 4, |
|
|
|
RTCP_SDES_LOC = 5, |
|
|
|
RTCP_SDES_TOOL = 6, |
|
|
|
RTCP_SDES_NOTE = 7, |
|
|
|
RTCP_SDES_PRIV = 8, |
|
|
|
RTCP_SDES_IMG = 9, |
|
|
|
RTCP_SDES_DOOR = 10, |
|
|
|
RTCP_SDES_SOURCE = 11 |
|
|
|
} rtcp_sdes_type_t; |
|
|
|
/* from http://www.iana.org/assignments/rtp-parameters last updated 05 January 2005 */ |
|
|
|
AVRtpPayloadType_t AVRtpPayloadTypes[]= |
|
|
|
{ |
|
|
|
{0, "PCMU", CODEC_TYPE_AUDIO, CODEC_ID_PCM_MULAW, 8000, 1}, |
|
|
|
{1, "Reserved", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{2, "Reserved", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{3, "GSM", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{4, "G723", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{5, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{6, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 16000, 1}, |
|
|
|
{7, "LPC", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{8, "PCMA", CODEC_TYPE_AUDIO, CODEC_ID_PCM_ALAW, 8000, 1}, |
|
|
|
{9, "G722", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{10, "L16", CODEC_TYPE_AUDIO, CODEC_ID_PCM_S16BE, 44100, 2}, |
|
|
|
{11, "L16", CODEC_TYPE_AUDIO, CODEC_ID_PCM_S16BE, 44100, 1}, |
|
|
|
{12, "QCELP", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{13, "CN", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{14, "MPA", CODEC_TYPE_AUDIO, CODEC_ID_MP2, 90000, -1}, |
|
|
|
{15, "G728", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{16, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 11025, 1}, |
|
|
|
{17, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 22050, 1}, |
|
|
|
{18, "G729", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, |
|
|
|
{19, "reserved", CODEC_TYPE_AUDIO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{20, "unassigned", CODEC_TYPE_AUDIO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{21, "unassigned", CODEC_TYPE_AUDIO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{22, "unassigned", CODEC_TYPE_AUDIO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{23, "unassigned", CODEC_TYPE_AUDIO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{24, "unassigned", CODEC_TYPE_VIDEO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{25, "CelB", CODEC_TYPE_VIDEO, CODEC_ID_NONE, 90000, -1}, |
|
|
|
{26, "JPEG", CODEC_TYPE_VIDEO, CODEC_ID_MJPEG, 90000, -1}, |
|
|
|
{27, "unassigned", CODEC_TYPE_VIDEO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{28, "nv", CODEC_TYPE_VIDEO, CODEC_ID_NONE, 90000, -1}, |
|
|
|
{29, "unassigned", CODEC_TYPE_VIDEO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{30, "unassigned", CODEC_TYPE_VIDEO, CODEC_ID_NONE, -1, -1}, |
|
|
|
{31, "H261", CODEC_TYPE_VIDEO, CODEC_ID_H261, 90000, -1}, |
|
|
|
{32, "MPV", CODEC_TYPE_VIDEO, CODEC_ID_MPEG1VIDEO, 90000, -1}, |
|
|
|
{33, "MP2T", CODEC_TYPE_DATA, CODEC_ID_MPEG2TS, 90000, -1}, |
|
|
|
{34, "H263", CODEC_TYPE_VIDEO, CODEC_ID_H263, 90000, -1}, |
|
|
|
{35, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{36, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{37, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{38, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{39, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{40, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{41, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{42, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{43, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{44, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{45, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{46, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{47, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{48, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{49, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{50, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{51, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{52, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{53, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{54, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{55, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{56, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{57, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{58, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{59, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{60, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{61, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{62, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{63, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{64, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{65, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{66, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{67, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{68, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{69, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{70, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{71, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{72, "reserved for RTCP conflict avoidance", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{73, "reserved for RTCP conflict avoidance", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{74, "reserved for RTCP conflict avoidance", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{75, "reserved for RTCP conflict avoidance", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{76, "reserved for RTCP conflict avoidance", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{77, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{78, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{79, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{80, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{81, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{82, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{83, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{84, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{85, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{86, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{87, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{88, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{89, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{90, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{91, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{92, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{93, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{94, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{95, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{96, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{97, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{98, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{99, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{100, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{101, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{102, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{103, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{104, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{105, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{106, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{107, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{108, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{109, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{110, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{111, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{112, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{113, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{114, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{115, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{116, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{117, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{118, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{119, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{120, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{121, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{122, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{123, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{124, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{125, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{126, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{127, "dynamic", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, |
|
|
|
{-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1} |
|
|
|
}; |
|
|
|
|
|
|
|
AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]= |
|
|
|
{ |
|
|
|
{"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}, |
|
|
|
{"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC}, |
|
|
|
{"", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE} |
|
|
|
}; |
|
|
|
|
|
|
|
struct RTPDemuxContext { |
|
|
|
AVFormatContext *ic; |
|
|
|
@@ -83,7 +194,7 @@ struct RTPDemuxContext { |
|
|
|
uint32_t base_timestamp; |
|
|
|
uint32_t cur_timestamp; |
|
|
|
int max_payload_size; |
|
|
|
MpegTSContext *ts; /* only used for RTP_PT_MPEG2TS payloads */ |
|
|
|
MpegTSContext *ts; /* only used for MP2T payloads */ |
|
|
|
int read_buf_index; |
|
|
|
int read_buf_size; |
|
|
|
|
|
|
|
@@ -99,94 +210,37 @@ struct RTPDemuxContext { |
|
|
|
/* buffer for output */ |
|
|
|
uint8_t buf[RTP_MAX_PACKET_LENGTH]; |
|
|
|
uint8_t *buf_ptr; |
|
|
|
/* special infos for au headers parsing */ |
|
|
|
rtp_payload_data_t *rtp_payload_data; |
|
|
|
}; |
|
|
|
|
|
|
|
int rtp_get_codec_info(AVCodecContext *codec, int payload_type) |
|
|
|
{ |
|
|
|
switch(payload_type) { |
|
|
|
case RTP_PT_ULAW: |
|
|
|
codec->codec_type = CODEC_TYPE_AUDIO; |
|
|
|
codec->codec_id = CODEC_ID_PCM_MULAW; |
|
|
|
codec->channels = 1; |
|
|
|
codec->sample_rate = 8000; |
|
|
|
break; |
|
|
|
case RTP_PT_ALAW: |
|
|
|
codec->codec_type = CODEC_TYPE_AUDIO; |
|
|
|
codec->codec_id = CODEC_ID_PCM_ALAW; |
|
|
|
codec->channels = 1; |
|
|
|
codec->sample_rate = 8000; |
|
|
|
break; |
|
|
|
case RTP_PT_S16BE_STEREO: |
|
|
|
codec->codec_type = CODEC_TYPE_AUDIO; |
|
|
|
codec->codec_id = CODEC_ID_PCM_S16BE; |
|
|
|
codec->channels = 2; |
|
|
|
codec->sample_rate = 44100; |
|
|
|
break; |
|
|
|
case RTP_PT_S16BE_MONO: |
|
|
|
codec->codec_type = CODEC_TYPE_AUDIO; |
|
|
|
codec->codec_id = CODEC_ID_PCM_S16BE; |
|
|
|
codec->channels = 1; |
|
|
|
codec->sample_rate = 44100; |
|
|
|
break; |
|
|
|
case RTP_PT_MPEGAUDIO: |
|
|
|
codec->codec_type = CODEC_TYPE_AUDIO; |
|
|
|
codec->codec_id = CODEC_ID_MP2; |
|
|
|
break; |
|
|
|
case RTP_PT_JPEG: |
|
|
|
codec->codec_type = CODEC_TYPE_VIDEO; |
|
|
|
codec->codec_id = CODEC_ID_MJPEG; |
|
|
|
break; |
|
|
|
case RTP_PT_MPEGVIDEO: |
|
|
|
codec->codec_type = CODEC_TYPE_VIDEO; |
|
|
|
codec->codec_id = CODEC_ID_MPEG1VIDEO; |
|
|
|
break; |
|
|
|
case RTP_PT_MPEG2TS: |
|
|
|
codec->codec_type = CODEC_TYPE_DATA; |
|
|
|
codec->codec_id = CODEC_ID_MPEG2TS; |
|
|
|
break; |
|
|
|
default: |
|
|
|
return -1; |
|
|
|
if (AVRtpPayloadTypes[payload_type].codec_id != CODEC_ID_NONE) { |
|
|
|
codec->codec_type = AVRtpPayloadTypes[payload_type].codec_type; |
|
|
|
codec->codec_id = AVRtpPayloadTypes[payload_type].codec_type; |
|
|
|
if (AVRtpPayloadTypes[payload_type].audio_channels > 0) |
|
|
|
codec->channels = AVRtpPayloadTypes[payload_type].audio_channels; |
|
|
|
if (AVRtpPayloadTypes[payload_type].clock_rate > 0) |
|
|
|
codec->sample_rate = AVRtpPayloadTypes[payload_type].clock_rate; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
/* return < 0 if unknown payload type */ |
|
|
|
int rtp_get_payload_type(AVCodecContext *codec) |
|
|
|
{ |
|
|
|
int payload_type; |
|
|
|
int i, payload_type; |
|
|
|
|
|
|
|
/* compute the payload type */ |
|
|
|
payload_type = -1; |
|
|
|
switch(codec->codec_id) { |
|
|
|
case CODEC_ID_PCM_MULAW: |
|
|
|
payload_type = RTP_PT_ULAW; |
|
|
|
break; |
|
|
|
case CODEC_ID_PCM_ALAW: |
|
|
|
payload_type = RTP_PT_ALAW; |
|
|
|
break; |
|
|
|
case CODEC_ID_PCM_S16BE: |
|
|
|
if (codec->channels == 1) { |
|
|
|
payload_type = RTP_PT_S16BE_MONO; |
|
|
|
} else if (codec->channels == 2) { |
|
|
|
payload_type = RTP_PT_S16BE_STEREO; |
|
|
|
for (payload_type = -1, i = 0; AVRtpPayloadTypes[i].pt >= 0; ++i) |
|
|
|
if (AVRtpPayloadTypes[i].codec_id == codec->codec_id) { |
|
|
|
if (codec->codec_id == CODEC_ID_PCM_S16BE) |
|
|
|
if (codec->channels != AVRtpPayloadTypes[i].audio_channels) |
|
|
|
continue; |
|
|
|
payload_type = AVRtpPayloadTypes[i].pt; |
|
|
|
} |
|
|
|
break; |
|
|
|
case CODEC_ID_MP2: |
|
|
|
case CODEC_ID_MP3: |
|
|
|
payload_type = RTP_PT_MPEGAUDIO; |
|
|
|
break; |
|
|
|
case CODEC_ID_MJPEG: |
|
|
|
payload_type = RTP_PT_JPEG; |
|
|
|
break; |
|
|
|
case CODEC_ID_MPEG1VIDEO: |
|
|
|
payload_type = RTP_PT_MPEGVIDEO; |
|
|
|
break; |
|
|
|
case CODEC_ID_MPEG2TS: |
|
|
|
payload_type = RTP_PT_MPEG2TS; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
return payload_type; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -216,7 +270,7 @@ static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int l |
|
|
|
* MPEG2TS streams to indicate that they should be demuxed inside the |
|
|
|
* rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned) |
|
|
|
*/ |
|
|
|
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type) |
|
|
|
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, rtp_payload_data_t *rtp_payload_data) |
|
|
|
{ |
|
|
|
RTPDemuxContext *s; |
|
|
|
|
|
|
|
@@ -228,7 +282,8 @@ RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_t |
|
|
|
s->first_rtcp_ntp_time = AV_NOPTS_VALUE; |
|
|
|
s->ic = s1; |
|
|
|
s->st = st; |
|
|
|
if (payload_type == RTP_PT_MPEG2TS) { |
|
|
|
s->rtp_payload_data = rtp_payload_data; |
|
|
|
if (!strcmp(AVRtpPayloadTypes[payload_type].enc_name, "MP2T")) { |
|
|
|
s->ts = mpegts_parse_open(s->ic); |
|
|
|
if (s->ts == NULL) { |
|
|
|
av_free(s); |
|
|
|
@@ -250,6 +305,57 @@ RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_t |
|
|
|
return s; |
|
|
|
} |
|
|
|
|
|
|
|
static int rtp_parse_mp4_au(RTPDemuxContext *s, const uint8_t *buf) |
|
|
|
{ |
|
|
|
AVCodecContext codec; |
|
|
|
int au_headers_length, au_header_size, i; |
|
|
|
GetBitContext getbitcontext; |
|
|
|
rtp_payload_data_t *infos; |
|
|
|
|
|
|
|
infos = s->rtp_payload_data; |
|
|
|
|
|
|
|
if (infos == NULL) |
|
|
|
return -1; |
|
|
|
|
|
|
|
codec = s->st->codec; |
|
|
|
|
|
|
|
/* decode the first 2 bytes where are stored the AUHeader sections |
|
|
|
length in bits */ |
|
|
|
au_headers_length = BE_16(buf); |
|
|
|
|
|
|
|
if (au_headers_length > RTP_MAX_PACKET_LENGTH) |
|
|
|
return -1; |
|
|
|
|
|
|
|
infos->au_headers_length_bytes = (au_headers_length + 7) / 8; |
|
|
|
|
|
|
|
/* skip AU headers length section (2 bytes) */ |
|
|
|
buf += 2; |
|
|
|
|
|
|
|
init_get_bits(&getbitcontext, buf, infos->au_headers_length_bytes * 8); |
|
|
|
|
|
|
|
/* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */ |
|
|
|
au_header_size = infos->sizelength + infos->indexlength; |
|
|
|
if (au_header_size <= 0 || (au_headers_length % au_header_size != 0)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
infos->nb_au_headers = au_headers_length / au_header_size; |
|
|
|
infos->au_headers = av_malloc(sizeof(struct AUHeaders) * infos->nb_au_headers); |
|
|
|
|
|
|
|
/* XXX: We handle multiple AU Section as only one (need to fix this for interleaving) |
|
|
|
In my test, the faad decoder doesnt behave correctly when sending each AU one by one |
|
|
|
but does when sending the whole as one big packet... */ |
|
|
|
infos->au_headers[0].size = 0; |
|
|
|
infos->au_headers[0].index = 0; |
|
|
|
for (i = 0; i < infos->nb_au_headers; ++i) { |
|
|
|
infos->au_headers[0].size += get_bits_long(&getbitcontext, infos->sizelength); |
|
|
|
infos->au_headers[0].index = get_bits_long(&getbitcontext, infos->indexlength); |
|
|
|
} |
|
|
|
|
|
|
|
infos->nb_au_headers = 1; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Parse an RTP or RTCP packet directly sent as a buffer. |
|
|
|
* @param s RTP parse context. |
|
|
|
@@ -304,8 +410,8 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, |
|
|
|
av_log(&s->st->codec, AV_LOG_ERROR, "RTP: PT=%02x: bad cseq %04x expected=%04x\n", |
|
|
|
payload_type, seq, ((s->seq + 1) & 0xffff)); |
|
|
|
} |
|
|
|
s->seq = seq; |
|
|
|
#endif |
|
|
|
s->seq = seq; |
|
|
|
len -= 12; |
|
|
|
buf += 12; |
|
|
|
|
|
|
|
@@ -370,6 +476,28 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, |
|
|
|
pkt->pts = addend + delta_timestamp; |
|
|
|
} |
|
|
|
break; |
|
|
|
case CODEC_ID_MPEG4: |
|
|
|
pkt->pts = timestamp; |
|
|
|
break; |
|
|
|
case CODEC_ID_MPEG4AAC: |
|
|
|
if (rtp_parse_mp4_au(s, buf)) |
|
|
|
return -1; |
|
|
|
rtp_payload_data_t *infos = s->rtp_payload_data; |
|
|
|
if (infos == NULL) |
|
|
|
return -1; |
|
|
|
buf += infos->au_headers_length_bytes + 2; |
|
|
|
len -= infos->au_headers_length_bytes + 2; |
|
|
|
|
|
|
|
/* XXX: Fixme we only handle the case where rtp_parse_mp4_au define |
|
|
|
one au_header */ |
|
|
|
av_new_packet(pkt, infos->au_headers[0].size); |
|
|
|
memcpy(pkt->data, buf, infos->au_headers[0].size); |
|
|
|
buf += infos->au_headers[0].size; |
|
|
|
len -= infos->au_headers[0].size; |
|
|
|
s->read_buf_size = len; |
|
|
|
s->buf_ptr = (char *)buf; |
|
|
|
pkt->stream_index = s->st->index; |
|
|
|
return 0; |
|
|
|
default: |
|
|
|
/* no timestamp info yet */ |
|
|
|
break; |
|
|
|
@@ -381,7 +509,7 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, |
|
|
|
|
|
|
|
void rtp_parse_close(RTPDemuxContext *s) |
|
|
|
{ |
|
|
|
if (s->payload_type == RTP_PT_MPEG2TS) { |
|
|
|
if (!strcmp(AVRtpPayloadTypes[s->payload_type].enc_name, "MP2T")) { |
|
|
|
mpegts_parse_close(s->ts); |
|
|
|
} |
|
|
|
av_free(s); |
|
|
|
|