Mercurial > libavformat.hg
comparison rtsp.c @ 774:820863425158 libavformat
RTP/RTSP and MPEG4-AAC audio
- preliminary support for mpeg4-aac rtp payload (no interleaving support)
- use udp transport as default (makes more sense with rtp, doesn't it ?)
- some code factorization, so adding support for new rtp payload will be easier
(I hope ;-)
patch by (Romain DEGEZ: romain degez, smartjog com)
author | michael |
---|---|
date | Thu, 26 May 2005 07:47:51 +0000 |
parents | fc254f396f15 |
children | feca73904e67 |
comparison
equal
deleted
inserted
replaced
773:a5095f5cf38a | 774:820863425158 |
---|---|
64 | 64 |
65 int sdp_port; /* port (from SDP content - not used in RTSP) */ | 65 int sdp_port; /* port (from SDP content - not used in RTSP) */ |
66 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */ | 66 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */ |
67 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ | 67 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ |
68 int sdp_payload_type; /* payload type - only used in SDP */ | 68 int sdp_payload_type; /* payload type - only used in SDP */ |
69 rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from SDP */ | |
69 } RTSPStream; | 70 } RTSPStream; |
70 | 71 |
71 static int rtsp_read_play(AVFormatContext *s); | 72 static int rtsp_read_play(AVFormatContext *s); |
72 | 73 |
73 /* XXX: currently, the only way to change the protocols consists in | 74 /* XXX: currently, the only way to change the protocols consists in |
74 changing this variable */ | 75 changing this variable */ |
75 #if 0 | 76 |
76 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST); | 77 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_UDP); |
77 #else | |
78 /* try it if a proxy is used */ | |
79 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP); | |
80 #endif | |
81 | |
82 /* if non zero, then set a range for RTP ports */ | |
83 int rtsp_rtp_port_min = 0; | |
84 int rtsp_rtp_port_max = 0; | |
85 | 78 |
86 FFRTSPCallback *ff_rtsp_callback = NULL; | 79 FFRTSPCallback *ff_rtsp_callback = NULL; |
87 | 80 |
88 static int rtsp_probe(AVProbeData *p) | 81 static int rtsp_probe(AVProbeData *p) |
89 { | 82 { |
111 { | 104 { |
112 const char *p; | 105 const char *p; |
113 char *q; | 106 char *q; |
114 | 107 |
115 p = *pp; | 108 p = *pp; |
109 if (*p == '/') | |
110 p++; | |
116 skip_spaces(&p); | 111 skip_spaces(&p); |
117 q = buf; | 112 q = buf; |
118 while (!strchr(sep, *p) && *p != '\0') { | 113 while (!strchr(sep, *p) && *p != '\0') { |
119 if ((q - buf) < buf_size - 1) | 114 if ((q - buf) < buf_size - 1) |
120 *q++ = *p; | 115 *q++ = *p; |
143 *pp = p; | 138 *pp = p; |
144 } | 139 } |
145 | 140 |
146 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other | 141 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other |
147 params>] */ | 142 params>] */ |
148 static int sdp_parse_rtpmap(AVCodecContext *codec, const char *p) | 143 static int sdp_parse_rtpmap(AVCodecContext *codec, int payload_type, const char *p) |
149 { | 144 { |
150 char buf[256]; | 145 char buf[256]; |
151 | 146 int i; |
152 /* codec name */ | 147 AVCodec *c; |
148 char *c_name; | |
149 | |
150 /* Loop into AVRtpDynamicPayloadTypes[] and AVRtpPayloadTypes[] and | |
151 see if we can handle this kind of payload */ | |
153 get_word_sep(buf, sizeof(buf), "/", &p); | 152 get_word_sep(buf, sizeof(buf), "/", &p); |
154 if (!strcmp(buf, "MP4V-ES")) { | 153 if (payload_type >= RTP_PT_PRIVATE) { |
155 codec->codec_id = CODEC_ID_MPEG4; | 154 /* We are in dynmaic payload type case ... search into AVRtpDynamicPayloadTypes[] */ |
155 for (i = 0; AVRtpDynamicPayloadTypes[i].codec_id != CODEC_ID_NONE; ++i) | |
156 if (!strcmp(buf, AVRtpDynamicPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpDynamicPayloadTypes[i].codec_type)) { | |
157 codec->codec_id = AVRtpDynamicPayloadTypes[i].codec_id; | |
158 break; | |
159 } | |
160 } else { | |
161 /* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */ | |
162 /* search into AVRtpPayloadTypes[] */ | |
163 for (i = 0; AVRtpPayloadTypes[i].pt >= 0; ++i) | |
164 if (!strcmp(buf, AVRtpPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpPayloadTypes[i].codec_type)){ | |
165 codec->codec_id = AVRtpPayloadTypes[i].codec_id; | |
166 break; | |
167 } | |
168 } | |
169 | |
170 c = avcodec_find_decoder(codec->codec_id); | |
171 if (c && c->name) | |
172 c_name = (char *)c->name; | |
173 else | |
174 c_name = (char *)NULL; | |
175 | |
176 if (c_name) { | |
177 get_word_sep(buf, sizeof(buf), "/", &p); | |
178 i = atoi(buf); | |
179 switch (codec->codec_type) { | |
180 case CODEC_TYPE_AUDIO: | |
181 av_log(codec, AV_LOG_DEBUG, " audio codec set to : %s\n", c_name); | |
182 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; | |
183 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS; | |
184 if (i > 0) { | |
185 codec->sample_rate = i; | |
186 get_word_sep(buf, sizeof(buf), "/", &p); | |
187 i = atoi(buf); | |
188 if (i > 0) | |
189 codec->channels = i; | |
190 } | |
191 av_log(codec, AV_LOG_DEBUG, " audio samplerate set to : %i\n", codec->sample_rate); | |
192 av_log(codec, AV_LOG_DEBUG, " audio channels set to : %i\n", codec->channels); | |
193 break; | |
194 case CODEC_TYPE_VIDEO: | |
195 av_log(codec, AV_LOG_DEBUG, " video codec set to : %s\n", c_name); | |
196 break; | |
197 default: | |
198 break; | |
199 } | |
156 return 0; | 200 return 0; |
157 } else { | 201 } |
158 return -1; | 202 |
159 } | 203 return -1; |
160 } | 204 } |
161 | 205 |
162 /* return the length and optionnaly the data */ | 206 /* return the length and optionnaly the data */ |
163 static int hex_to_data(uint8_t *data, const char *p) | 207 static int hex_to_data(uint8_t *data, const char *p) |
164 { | 208 { |
186 } | 230 } |
187 } | 231 } |
188 return len; | 232 return len; |
189 } | 233 } |
190 | 234 |
191 static void sdp_parse_fmtp(AVCodecContext *codec, const char *p) | 235 static void sdp_parse_fmtp_config(AVCodecContext *codec, char *attr, char *value) |
236 { | |
237 switch (codec->codec_id) { | |
238 case CODEC_ID_MPEG4: | |
239 case CODEC_ID_MPEG4AAC: | |
240 if (!strcmp(attr, "config")) { | |
241 /* decode the hexa encoded parameter */ | |
242 int len = hex_to_data(NULL, value); | |
243 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); | |
244 if (!codec->extradata) | |
245 return; | |
246 codec->extradata_size = len; | |
247 hex_to_data(codec->extradata, value); | |
248 } | |
249 break; | |
250 default: | |
251 break; | |
252 } | |
253 return; | |
254 } | |
255 | |
256 typedef struct attrname_map | |
257 { | |
258 char *str; | |
259 uint16_t type; | |
260 uint32_t offset; | |
261 } attrname_map_t; | |
262 | |
263 /* All known fmtp parmeters and the corresping RTPAttrTypeEnum */ | |
264 #define ATTR_NAME_TYPE_INT 0 | |
265 #define ATTR_NAME_TYPE_STR 1 | |
266 static attrname_map_t attr_names[]= | |
267 { | |
268 {"SizeLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, sizelength)}, | |
269 {"IndexLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexlength)}, | |
270 {"IndexDeltaLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexdeltalength)}, | |
271 {"profile-level-id", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, profile_level_id)}, | |
272 {"StreamType", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, streamtype)}, | |
273 {"mode", ATTR_NAME_TYPE_STR, offsetof(rtp_payload_data_t, mode)}, | |
274 {NULL, -1, -1}, | |
275 }; | |
276 | |
277 /* parse a SDP line and save stream attributes */ | |
278 static void sdp_parse_fmtp(AVStream *st, const char *p) | |
192 { | 279 { |
193 char attr[256]; | 280 char attr[256]; |
194 char value[4096]; | 281 char value[4096]; |
195 int len; | 282 int i; |
283 | |
284 RTSPStream *rtsp_st = st->priv_data; | |
285 AVCodecContext *codec = &st->codec; | |
286 rtp_payload_data_t *rtp_payload_data = &rtsp_st->rtp_payload_data; | |
196 | 287 |
197 /* loop on each attribute */ | 288 /* loop on each attribute */ |
198 for(;;) { | 289 for(;;) { |
199 skip_spaces(&p); | 290 skip_spaces(&p); |
200 if (*p == '\0') | 291 if (*p == '\0') |
203 if (*p == '=') | 294 if (*p == '=') |
204 p++; | 295 p++; |
205 get_word_sep(value, sizeof(value), ";", &p); | 296 get_word_sep(value, sizeof(value), ";", &p); |
206 if (*p == ';') | 297 if (*p == ';') |
207 p++; | 298 p++; |
208 /* handle MPEG4 video */ | 299 /* grab the codec extra_data from the config parameter of the fmtp line */ |
209 switch(codec->codec_id) { | 300 sdp_parse_fmtp_config(codec, attr, value); |
210 case CODEC_ID_MPEG4: | 301 /* Looking for a known attribute */ |
211 if (!strcmp(attr, "config")) { | 302 for (i = 0; attr_names[i].str; ++i) { |
212 /* decode the hexa encoded parameter */ | 303 if (!strcasecmp(attr, attr_names[i].str)) { |
213 len = hex_to_data(NULL, value); | 304 if (attr_names[i].type == ATTR_NAME_TYPE_INT) |
214 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); | 305 *(int *)((char *)rtp_payload_data + attr_names[i].offset) = atoi(value); |
215 if (!codec->extradata) | 306 else if (attr_names[i].type == ATTR_NAME_TYPE_STR) |
216 goto fail; | 307 *(char **)((char *)rtp_payload_data + attr_names[i].offset) = av_strdup(value); |
217 codec->extradata_size = len; | 308 } |
218 hex_to_data(codec->extradata, value); | 309 } |
219 } | |
220 break; | |
221 default: | |
222 /* ignore data for other codecs */ | |
223 break; | |
224 } | |
225 fail: ; | |
226 // printf("'%s' = '%s'\n", attr, value); | |
227 } | 310 } |
228 } | 311 } |
229 | 312 |
230 typedef struct SDPParseState { | 313 typedef struct SDPParseState { |
231 /* SDP only */ | 314 /* SDP only */ |
312 | 395 |
313 /* XXX: handle list of formats */ | 396 /* XXX: handle list of formats */ |
314 get_word(buf1, sizeof(buf1), &p); /* format list */ | 397 get_word(buf1, sizeof(buf1), &p); /* format list */ |
315 rtsp_st->sdp_payload_type = atoi(buf1); | 398 rtsp_st->sdp_payload_type = atoi(buf1); |
316 | 399 |
317 if (rtsp_st->sdp_payload_type == RTP_PT_MPEG2TS) { | 400 if (!strcmp(AVRtpPayloadTypes[rtsp_st->sdp_payload_type].enc_name, "MP2T")) { |
318 /* no corresponding stream */ | 401 /* no corresponding stream */ |
319 } else { | 402 } else { |
320 st = av_new_stream(s, 0); | 403 st = av_new_stream(s, 0); |
321 if (!st) | 404 if (!st) |
322 return; | 405 return; |
323 st->priv_data = rtsp_st; | 406 st->priv_data = rtsp_st; |
324 rtsp_st->stream_index = st->index; | 407 rtsp_st->stream_index = st->index; |
325 st->codec.codec_type = codec_type; | 408 st->codec.codec_type = codec_type; |
326 if (rtsp_st->sdp_payload_type < 96) { | 409 if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { |
327 /* if standard payload type, we can find the codec right now */ | 410 /* if standard payload type, we can find the codec right now */ |
328 rtp_get_codec_info(&st->codec, rtsp_st->sdp_payload_type); | 411 rtp_get_codec_info(&st->codec, rtsp_st->sdp_payload_type); |
329 } | 412 } |
330 } | 413 } |
331 /* put a default control url */ | 414 /* put a default control url */ |
353 payload_type = atoi(buf1); | 436 payload_type = atoi(buf1); |
354 for(i = 0; i < s->nb_streams;i++) { | 437 for(i = 0; i < s->nb_streams;i++) { |
355 st = s->streams[i]; | 438 st = s->streams[i]; |
356 rtsp_st = st->priv_data; | 439 rtsp_st = st->priv_data; |
357 if (rtsp_st->sdp_payload_type == payload_type) { | 440 if (rtsp_st->sdp_payload_type == payload_type) { |
358 sdp_parse_rtpmap(&st->codec, p); | 441 sdp_parse_rtpmap(&st->codec, payload_type, p); |
359 } | 442 } |
360 } | 443 } |
361 } else if (strstart(p, "fmtp:", &p)) { | 444 } else if (strstart(p, "fmtp:", &p)) { |
362 /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ | 445 /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ |
363 get_word(buf1, sizeof(buf1), &p); | 446 get_word(buf1, sizeof(buf1), &p); |
364 payload_type = atoi(buf1); | 447 payload_type = atoi(buf1); |
365 for(i = 0; i < s->nb_streams;i++) { | 448 for(i = 0; i < s->nb_streams;i++) { |
366 st = s->streams[i]; | 449 st = s->streams[i]; |
367 rtsp_st = st->priv_data; | 450 rtsp_st = st->priv_data; |
368 if (rtsp_st->sdp_payload_type == payload_type) { | 451 if (rtsp_st->sdp_payload_type == payload_type) { |
369 sdp_parse_fmtp(&st->codec, p); | 452 sdp_parse_fmtp(st, p); |
370 } | 453 } |
371 } | 454 } |
372 } | 455 } |
373 break; | 456 break; |
374 } | 457 } |
713 AVFormatParameters *ap) | 796 AVFormatParameters *ap) |
714 { | 797 { |
715 RTSPState *rt = s->priv_data; | 798 RTSPState *rt = s->priv_data; |
716 char host[1024], path[1024], tcpname[1024], cmd[2048]; | 799 char host[1024], path[1024], tcpname[1024], cmd[2048]; |
717 URLContext *rtsp_hd; | 800 URLContext *rtsp_hd; |
718 int port, i, ret, err; | 801 int port, i, j, ret, err; |
719 RTSPHeader reply1, *reply = &reply1; | 802 RTSPHeader reply1, *reply = &reply1; |
720 unsigned char *content = NULL; | 803 unsigned char *content = NULL; |
721 RTSPStream *rtsp_st; | 804 RTSPStream *rtsp_st; |
722 int protocol_mask; | 805 int protocol_mask; |
723 AVStream *st; | 806 AVStream *st; |
761 protocol_mask = rtsp_default_protocols; | 844 protocol_mask = rtsp_default_protocols; |
762 | 845 |
763 /* for each stream, make the setup request */ | 846 /* for each stream, make the setup request */ |
764 /* XXX: we assume the same server is used for the control of each | 847 /* XXX: we assume the same server is used for the control of each |
765 RTSP stream */ | 848 RTSP stream */ |
766 for(i=0;i<rt->nb_rtsp_streams;i++) { | 849 |
850 for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) { | |
767 char transport[2048]; | 851 char transport[2048]; |
768 | 852 |
769 rtsp_st = rt->rtsp_streams[i]; | 853 rtsp_st = rt->rtsp_streams[i]; |
770 | 854 |
771 /* compute available transports */ | 855 /* compute available transports */ |
772 transport[0] = '\0'; | 856 transport[0] = '\0'; |
773 | 857 |
774 /* RTP/UDP */ | 858 /* RTP/UDP */ |
775 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) { | 859 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) { |
776 char buf[256]; | 860 char buf[256]; |
777 int j; | |
778 | 861 |
779 /* first try in specified port range */ | 862 /* first try in specified port range */ |
780 if (rtsp_rtp_port_min != 0) { | 863 if (RTSP_RTP_PORT_MIN != 0) { |
781 for(j=rtsp_rtp_port_min;j<=rtsp_rtp_port_max;j++) { | 864 while(j <= RTSP_RTP_PORT_MAX) { |
782 snprintf(buf, sizeof(buf), "rtp://?localport=%d", j); | 865 snprintf(buf, sizeof(buf), "rtp://?localport=%d", j); |
783 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) | 866 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) { |
867 j += 2; /* we will use two port by rtp stream (rtp and rtcp) */ | |
784 goto rtp_opened; | 868 goto rtp_opened; |
869 } | |
785 } | 870 } |
786 } | 871 } |
787 | 872 |
788 /* then try on any port */ | 873 /* then try on any port |
789 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { | 874 ** if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { |
790 err = AVERROR_INVALIDDATA; | 875 ** err = AVERROR_INVALIDDATA; |
791 goto fail; | 876 ** goto fail; |
792 } | 877 ** } |
878 */ | |
793 | 879 |
794 rtp_opened: | 880 rtp_opened: |
795 port = rtp_get_local_port(rtsp_st->rtp_handle); | 881 port = rtp_get_local_port(rtsp_st->rtp_handle); |
796 if (transport[0] != '\0') | 882 if (transport[0] != '\0') |
797 pstrcat(transport, sizeof(transport), ","); | 883 pstrcat(transport, sizeof(transport), ","); |
799 "RTP/AVP/UDP;unicast;client_port=%d-%d", | 885 "RTP/AVP/UDP;unicast;client_port=%d-%d", |
800 port, port + 1); | 886 port, port + 1); |
801 } | 887 } |
802 | 888 |
803 /* RTP/TCP */ | 889 /* RTP/TCP */ |
804 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { | 890 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { |
805 if (transport[0] != '\0') | 891 if (transport[0] != '\0') |
806 pstrcat(transport, sizeof(transport), ","); | 892 pstrcat(transport, sizeof(transport), ","); |
807 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, | 893 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, |
808 "RTP/AVP/TCP"); | 894 "RTP/AVP/TCP"); |
809 } | 895 } |
810 | 896 |
811 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { | 897 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { |
812 if (transport[0] != '\0') | 898 if (transport[0] != '\0') |
813 pstrcat(transport, sizeof(transport), ","); | 899 pstrcat(transport, sizeof(transport), ","); |
814 snprintf(transport + strlen(transport), | 900 snprintf(transport + strlen(transport), |
815 sizeof(transport) - strlen(transport) - 1, | 901 sizeof(transport) - strlen(transport) - 1, |
816 "RTP/AVP/UDP;multicast"); | 902 "RTP/AVP/UDP;multicast"); |
885 st = NULL; | 971 st = NULL; |
886 if (rtsp_st->stream_index >= 0) | 972 if (rtsp_st->stream_index >= 0) |
887 st = s->streams[rtsp_st->stream_index]; | 973 st = s->streams[rtsp_st->stream_index]; |
888 if (!st) | 974 if (!st) |
889 s->ctx_flags |= AVFMTCTX_NOHEADER; | 975 s->ctx_flags |= AVFMTCTX_NOHEADER; |
890 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type); | 976 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data); |
977 | |
891 if (!rtsp_st->rtp_ctx) { | 978 if (!rtsp_st->rtp_ctx) { |
892 err = AVERROR_NOMEM; | 979 err = AVERROR_NOMEM; |
893 goto fail; | 980 goto fail; |
894 } | 981 } |
895 } | 982 } |
1231 st = NULL; | 1318 st = NULL; |
1232 if (rtsp_st->stream_index >= 0) | 1319 if (rtsp_st->stream_index >= 0) |
1233 st = s->streams[rtsp_st->stream_index]; | 1320 st = s->streams[rtsp_st->stream_index]; |
1234 if (!st) | 1321 if (!st) |
1235 s->ctx_flags |= AVFMTCTX_NOHEADER; | 1322 s->ctx_flags |= AVFMTCTX_NOHEADER; |
1236 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type); | 1323 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data); |
1237 if (!rtsp_st->rtp_ctx) { | 1324 if (!rtsp_st->rtp_ctx) { |
1238 err = AVERROR_NOMEM; | 1325 err = AVERROR_NOMEM; |
1239 goto fail; | 1326 goto fail; |
1240 } | 1327 } |
1241 } | 1328 } |