| OLD | NEW |
| 1 /* | 1 /* |
| 2 * copyright (c) 2007 Luca Abeni | 2 * copyright (c) 2007 Luca Abeni |
| 3 * | 3 * |
| 4 * This file is part of FFmpeg. | 4 * This file is part of FFmpeg. |
| 5 * | 5 * |
| 6 * FFmpeg is free software; you can redistribute it and/or | 6 * FFmpeg is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Lesser General Public | 7 * modify it under the terms of the GNU Lesser General Public |
| 8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
| 9 * version 2.1 of the License, or (at your option) any later version. | 9 * version 2.1 of the License, or (at your option) any later version. |
| 10 * | 10 * |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 int sdp_version; /**< protocol version (currently 0) */ | 37 int sdp_version; /**< protocol version (currently 0) */ |
| 38 int id; /**< session ID */ | 38 int id; /**< session ID */ |
| 39 int version; /**< session version */ | 39 int version; /**< session version */ |
| 40 int start_time; /**< session start time (NTP time, in seconds), | 40 int start_time; /**< session start time (NTP time, in seconds), |
| 41 or 0 in case of permanent session */ | 41 or 0 in case of permanent session */ |
| 42 int end_time; /**< session end time (NTP time, in seconds), | 42 int end_time; /**< session end time (NTP time, in seconds), |
| 43 or 0 if the session is not bounded */ | 43 or 0 if the session is not bounded */ |
| 44 int ttl; /**< TTL, in case of multicast stream */ | 44 int ttl; /**< TTL, in case of multicast stream */ |
| 45 const char *user; /**< username of the session's creator */ | 45 const char *user; /**< username of the session's creator */ |
| 46 const char *src_addr; /**< IP address of the machine from which the session
was created */ | 46 const char *src_addr; /**< IP address of the machine from which the session
was created */ |
| 47 const char *src_type; /**< address type of src_addr */ |
| 47 const char *dst_addr; /**< destination IP address (can be multicast) */ | 48 const char *dst_addr; /**< destination IP address (can be multicast) */ |
| 49 const char *dst_type; /**< destination IP address type */ |
| 48 const char *name; /**< session name (can be an empty string) */ | 50 const char *name; /**< session name (can be an empty string) */ |
| 49 }; | 51 }; |
| 50 | 52 |
| 51 static void sdp_write_address(char *buff, int size, const char *dest_addr, int t
tl) | 53 static void sdp_write_address(char *buff, int size, const char *dest_addr, |
| 54 const char *dest_type, int ttl) |
| 52 { | 55 { |
| 53 if (dest_addr) { | 56 if (dest_addr) { |
| 57 if (!dest_type) |
| 58 dest_type = "IP4"; |
| 54 if (ttl > 0) { | 59 if (ttl > 0) { |
| 55 av_strlcatf(buff, size, "c=IN IP4 %s/%d\r\n", dest_addr, ttl); | 60 av_strlcatf(buff, size, "c=IN %s %s/%d\r\n", dest_type, dest_addr, t
tl); |
| 56 } else { | 61 } else { |
| 57 av_strlcatf(buff, size, "c=IN IP4 %s\r\n", dest_addr); | 62 av_strlcatf(buff, size, "c=IN %s %s\r\n", dest_type, dest_addr); |
| 58 } | 63 } |
| 59 } | 64 } |
| 60 } | 65 } |
| 61 | 66 |
| 62 static void sdp_write_header(char *buff, int size, struct sdp_session_level *s) | 67 static void sdp_write_header(char *buff, int size, struct sdp_session_level *s) |
| 63 { | 68 { |
| 64 av_strlcatf(buff, size, "v=%d\r\n" | 69 av_strlcatf(buff, size, "v=%d\r\n" |
| 65 "o=- %d %d IN IP4 %s\r\n" | 70 "o=- %d %d IN %s %s\r\n" |
| 66 "s=%s\r\n", | 71 "s=%s\r\n", |
| 67 s->sdp_version, | 72 s->sdp_version, |
| 68 s->id, s->version, s->src_addr, | 73 s->id, s->version, s->src_type, s->src_addr, |
| 69 s->name); | 74 s->name); |
| 70 sdp_write_address(buff, size, s->dst_addr, s->ttl); | 75 sdp_write_address(buff, size, s->dst_addr, s->dst_type, s->ttl); |
| 71 av_strlcatf(buff, size, "t=%d %d\r\n" | 76 av_strlcatf(buff, size, "t=%d %d\r\n" |
| 72 "a=tool:libavformat " AV_STRINGIFY(LIBAVFORMAT_VERSI
ON) "\r\n", | 77 "a=tool:libavformat " AV_STRINGIFY(LIBAVFORMAT_VERSI
ON) "\r\n", |
| 73 s->start_time, s->end_time); | 78 s->start_time, s->end_time); |
| 74 } | 79 } |
| 75 | 80 |
| 76 #if CONFIG_NETWORK | 81 #if CONFIG_NETWORK |
| 77 static void resolve_destination(char *dest_addr, int size) | 82 static void resolve_destination(char *dest_addr, int size, char *type, |
| 83 int type_size) |
| 78 { | 84 { |
| 79 struct addrinfo hints, *ai, *cur; | 85 struct addrinfo hints, *ai; |
| 80 | 86 |
| 87 av_strlcpy(type, "IP4", type_size); |
| 81 if (!dest_addr[0]) | 88 if (!dest_addr[0]) |
| 82 return; | 89 return; |
| 83 | 90 |
| 84 /* Resolve the destination, since it must be written | 91 /* Resolve the destination, since it must be written |
| 85 * as a numeric IP address in the SDP. */ | 92 * as a numeric IP address in the SDP. */ |
| 86 | 93 |
| 87 memset(&hints, 0, sizeof(hints)); | 94 memset(&hints, 0, sizeof(hints)); |
| 88 /* We only support IPv4 addresses in the SDP at the moment. */ | |
| 89 hints.ai_family = AF_INET; | |
| 90 if (getaddrinfo(dest_addr, NULL, &hints, &ai)) | 95 if (getaddrinfo(dest_addr, NULL, &hints, &ai)) |
| 91 return; | 96 return; |
| 92 for (cur = ai; cur; cur = cur->ai_next) { | 97 getnameinfo(ai->ai_addr, ai->ai_addrlen, dest_addr, size, |
| 93 if (cur->ai_family == AF_INET) { | 98 NULL, 0, NI_NUMERICHOST); |
| 94 getnameinfo(cur->ai_addr, cur->ai_addrlen, dest_addr, size, | 99 if (ai->ai_family == AF_INET6) |
| 95 NULL, 0, NI_NUMERICHOST); | 100 av_strlcpy(type, "IP6", type_size); |
| 96 break; | |
| 97 } | |
| 98 } | |
| 99 freeaddrinfo(ai); | 101 freeaddrinfo(ai); |
| 100 } | 102 } |
| 101 #else | 103 #else |
| 102 static void resolve_destination(char *dest_addr, int size) | 104 static void resolve_destination(char *dest_addr, int size, char *type, |
| 105 int type_size) |
| 103 { | 106 { |
| 104 } | 107 } |
| 105 #endif | 108 #endif |
| 106 | 109 |
| 107 static int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url) | 110 static int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url) |
| 108 { | 111 { |
| 109 int port; | 112 int port; |
| 110 const char *p; | 113 const char *p; |
| 111 char proto[32]; | 114 char proto[32]; |
| 112 | 115 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 goto xiph_fail; | 263 goto xiph_fail; |
| 261 | 264 |
| 262 encoded_config = av_malloc(AV_BASE64_SIZE(config_len)); | 265 encoded_config = av_malloc(AV_BASE64_SIZE(config_len)); |
| 263 if (!encoded_config) { | 266 if (!encoded_config) { |
| 264 av_free(config); | 267 av_free(config); |
| 265 goto xiph_fail; | 268 goto xiph_fail; |
| 266 } | 269 } |
| 267 | 270 |
| 268 config[0] = config[1] = config[2] = 0; | 271 config[0] = config[1] = config[2] = 0; |
| 269 config[3] = 1; | 272 config[3] = 1; |
| 270 config[4] = 0xfe; // ident must match the one in rtpenc_xiph.c | 273 config[4] = (RTP_XIPH_IDENT >> 16) & 0xff; |
| 271 config[5] = 0xcd; | 274 config[5] = (RTP_XIPH_IDENT >> 8) & 0xff; |
| 272 config[6] = 0xba; | 275 config[6] = (RTP_XIPH_IDENT ) & 0xff; |
| 273 config[7] = (headers_len >> 8) & 0xff; | 276 config[7] = (headers_len >> 8) & 0xff; |
| 274 config[8] = headers_len & 0xff; | 277 config[8] = headers_len & 0xff; |
| 275 config[9] = 2; | 278 config[9] = 2; |
| 276 config[10] = header_len[0]; | 279 config[10] = header_len[0]; |
| 277 config[11] = 0; // size of comment header; nonexistent | 280 config[11] = 0; // size of comment header; nonexistent |
| 278 memcpy(config + 12, header_start[0], header_len[0]); | 281 memcpy(config + 12, header_start[0], header_len[0]); |
| 279 memcpy(config + 12 + header_len[0], header_start[2], header_len[2]); | 282 memcpy(config + 12 + header_len[0], header_start[2], header_len[2]); |
| 280 | 283 |
| 281 av_base64_encode(encoded_config, AV_BASE64_SIZE(config_len), | 284 av_base64_encode(encoded_config, AV_BASE64_SIZE(config_len), |
| 282 config, config_len); | 285 config, config_len); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 } | 408 } |
| 406 | 409 |
| 407 av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" | 410 av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" |
| 408 "a=fmtp:%d delivery-method=inline; " | 411 "a=fmtp:%d delivery-method=inline; " |
| 409 "width=%d; height=%d; sampling=%s; " | 412 "width=%d; height=%d; sampling=%s; " |
| 410 "configuration=%s\r\n", | 413 "configuration=%s\r\n", |
| 411 payload_type, payload_type, | 414 payload_type, payload_type, |
| 412 c->width, c->height, pix_fmt, config); | 415 c->width, c->height, pix_fmt, config); |
| 413 break; | 416 break; |
| 414 } | 417 } |
| 418 case CODEC_ID_VP8: |
| 419 av_strlcatf(buff, size, "a=rtpmap:%d VP8/90000\r\n", |
| 420 payload_type); |
| 421 break; |
| 415 default: | 422 default: |
| 416 /* Nothing special to do here... */ | 423 /* Nothing special to do here... */ |
| 417 break; | 424 break; |
| 418 } | 425 } |
| 419 | 426 |
| 420 av_free(config); | 427 av_free(config); |
| 421 | 428 |
| 422 return buff; | 429 return buff; |
| 423 } | 430 } |
| 424 | 431 |
| 425 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *des
t_addr, int port, int ttl) | 432 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *des
t_addr, const char *dest_type, int port, int ttl) |
| 426 { | 433 { |
| 427 const char *type; | 434 const char *type; |
| 428 int payload_type; | 435 int payload_type; |
| 429 | 436 |
| 430 payload_type = ff_rtp_get_payload_type(c); | 437 payload_type = ff_rtp_get_payload_type(c); |
| 431 if (payload_type < 0) { | 438 if (payload_type < 0) { |
| 432 payload_type = RTP_PT_PRIVATE + (c->codec_type == AVMEDIA_TYPE_AUDIO); | 439 payload_type = RTP_PT_PRIVATE + (c->codec_type == AVMEDIA_TYPE_AUDIO); |
| 433 } | 440 } |
| 434 | 441 |
| 435 switch (c->codec_type) { | 442 switch (c->codec_type) { |
| 436 case AVMEDIA_TYPE_VIDEO : type = "video" ; break; | 443 case AVMEDIA_TYPE_VIDEO : type = "video" ; break; |
| 437 case AVMEDIA_TYPE_AUDIO : type = "audio" ; break; | 444 case AVMEDIA_TYPE_AUDIO : type = "audio" ; break; |
| 438 case AVMEDIA_TYPE_SUBTITLE: type = "text" ; break; | 445 case AVMEDIA_TYPE_SUBTITLE: type = "text" ; break; |
| 439 default : type = "application"; break; | 446 default : type = "application"; break; |
| 440 } | 447 } |
| 441 | 448 |
| 442 av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type); | 449 av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type); |
| 443 sdp_write_address(buff, size, dest_addr, ttl); | 450 sdp_write_address(buff, size, dest_addr, dest_type, ttl); |
| 444 if (c->bit_rate) { | 451 if (c->bit_rate) { |
| 445 av_strlcatf(buff, size, "b=AS:%d\r\n", c->bit_rate / 1000); | 452 av_strlcatf(buff, size, "b=AS:%d\r\n", c->bit_rate / 1000); |
| 446 } | 453 } |
| 447 | 454 |
| 448 sdp_write_media_attributes(buff, size, c, payload_type); | 455 sdp_write_media_attributes(buff, size, c, payload_type); |
| 449 } | 456 } |
| 450 | 457 |
| 451 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) | 458 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) |
| 452 { | 459 { |
| 453 AVMetadataTag *title = av_metadata_get(ac[0]->metadata, "title", NULL, 0); | 460 AVMetadataTag *title = av_metadata_get(ac[0]->metadata, "title", NULL, 0); |
| 454 struct sdp_session_level s; | 461 struct sdp_session_level s; |
| 455 int i, j, port, ttl; | 462 int i, j, port, ttl; |
| 456 char dst[32]; | 463 char dst[32], dst_type[5]; |
| 457 | 464 |
| 458 memset(buff, 0, size); | 465 memset(buff, 0, size); |
| 459 memset(&s, 0, sizeof(struct sdp_session_level)); | 466 memset(&s, 0, sizeof(struct sdp_session_level)); |
| 460 s.user = "-"; | 467 s.user = "-"; |
| 461 s.src_addr = "127.0.0.1"; /* FIXME: Properly set this */ | 468 s.src_addr = "127.0.0.1"; /* FIXME: Properly set this */ |
| 469 s.src_type = "IP4"; |
| 462 s.name = title ? title->value : "No Name"; | 470 s.name = title ? title->value : "No Name"; |
| 463 | 471 |
| 464 port = 0; | 472 port = 0; |
| 465 ttl = 0; | 473 ttl = 0; |
| 466 if (n_files == 1) { | 474 if (n_files == 1) { |
| 467 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->filename); | 475 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->filename); |
| 468 resolve_destination(dst, sizeof(dst)); | 476 resolve_destination(dst, sizeof(dst), dst_type, sizeof(dst_type)); |
| 469 if (dst[0]) { | 477 if (dst[0]) { |
| 470 s.dst_addr = dst; | 478 s.dst_addr = dst; |
| 479 s.dst_type = dst_type; |
| 471 s.ttl = ttl; | 480 s.ttl = ttl; |
| 481 if (!strcmp(dst_type, "IP6")) { |
| 482 s.src_addr = "::1"; |
| 483 s.src_type = "IP6"; |
| 484 } |
| 472 } | 485 } |
| 473 } | 486 } |
| 474 sdp_write_header(buff, size, &s); | 487 sdp_write_header(buff, size, &s); |
| 475 | 488 |
| 476 dst[0] = 0; | 489 dst[0] = 0; |
| 477 for (i = 0; i < n_files; i++) { | 490 for (i = 0; i < n_files; i++) { |
| 478 if (n_files != 1) { | 491 if (n_files != 1) { |
| 479 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename); | 492 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename); |
| 480 resolve_destination(dst, sizeof(dst)); | 493 resolve_destination(dst, sizeof(dst), dst_type, sizeof(dst_type)); |
| 481 } | 494 } |
| 482 for (j = 0; j < ac[i]->nb_streams; j++) { | 495 for (j = 0; j < ac[i]->nb_streams; j++) { |
| 483 ff_sdp_write_media(buff, size, | 496 ff_sdp_write_media(buff, size, |
| 484 ac[i]->streams[j]->codec, dst[0] ? dst : NULL, | 497 ac[i]->streams[j]->codec, dst[0] ? dst : NULL, |
| 485 (port > 0) ? port + j * 2 : 0, ttl); | 498 dst_type, (port > 0) ? port + j * 2 : 0, ttl); |
| 486 if (port <= 0) { | 499 if (port <= 0) { |
| 487 av_strlcatf(buff, size, | 500 av_strlcatf(buff, size, |
| 488 "a=control:streamid=%d\r\n", i + j); | 501 "a=control:streamid=%d\r\n", i + j); |
| 489 } | 502 } |
| 490 } | 503 } |
| 491 } | 504 } |
| 492 | 505 |
| 493 return 0; | 506 return 0; |
| 494 } | 507 } |
| 495 #else | 508 #else |
| 496 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) | 509 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) |
| 497 { | 510 { |
| 498 return AVERROR(ENOSYS); | 511 return AVERROR(ENOSYS); |
| 499 } | 512 } |
| 500 | 513 |
| 501 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, | 514 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *des
t_addr, const char *dest_type, int port, int ttl) |
| 502 const char *dest_addr, int port, int ttl) | |
| 503 { | 515 { |
| 504 } | 516 } |
| 505 #endif | 517 #endif |
| OLD | NEW |