00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "libavutil/parseutils.h"
00024 #include "libavutil/random_seed.h"
00025 #include "libavutil/avstring.h"
00026 #include "libavutil/intreadwrite.h"
00027 #include "internal.h"
00028 #include "network.h"
00029 #include "os_support.h"
00030 #include "rtpenc_chain.h"
00031
00032 struct SAPState {
00033 uint8_t *ann;
00034 int ann_size;
00035 URLContext *ann_fd;
00036 int64_t last_time;
00037 };
00038
00039 static int sap_write_close(AVFormatContext *s)
00040 {
00041 struct SAPState *sap = s->priv_data;
00042 int i;
00043
00044 for (i = 0; i < s->nb_streams; i++) {
00045 AVFormatContext *rtpctx = s->streams[i]->priv_data;
00046 if (!rtpctx)
00047 continue;
00048 av_write_trailer(rtpctx);
00049 avio_close(rtpctx->pb);
00050 avformat_free_context(rtpctx);
00051 s->streams[i]->priv_data = NULL;
00052 }
00053
00054 if (sap->last_time && sap->ann && sap->ann_fd) {
00055 sap->ann[0] |= 4;
00056 url_write(sap->ann_fd, sap->ann, sap->ann_size);
00057 }
00058
00059 av_freep(&sap->ann);
00060 if (sap->ann_fd)
00061 url_close(sap->ann_fd);
00062 ff_network_close();
00063 return 0;
00064 }
00065
00066 static int sap_write_header(AVFormatContext *s)
00067 {
00068 struct SAPState *sap = s->priv_data;
00069 char host[1024], path[1024], url[1024], announce_addr[50] = "";
00070 char *option_list;
00071 int port = 9875, base_port = 5004, i, pos = 0, same_port = 0, ttl = 255;
00072 AVFormatContext **contexts = NULL;
00073 int ret = 0;
00074 struct sockaddr_storage localaddr;
00075 socklen_t addrlen = sizeof(localaddr);
00076 int udp_fd;
00077
00078 if (!ff_network_init())
00079 return AVERROR(EIO);
00080
00081
00082 av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &base_port,
00083 path, sizeof(path), s->filename);
00084 if (base_port < 0)
00085 base_port = 5004;
00086
00087
00088 option_list = strrchr(path, '?');
00089 if (option_list) {
00090 char buf[50];
00091 if (av_find_info_tag(buf, sizeof(buf), "announce_port", option_list)) {
00092 port = strtol(buf, NULL, 10);
00093 }
00094 if (av_find_info_tag(buf, sizeof(buf), "same_port", option_list)) {
00095 same_port = strtol(buf, NULL, 10);
00096 }
00097 if (av_find_info_tag(buf, sizeof(buf), "ttl", option_list)) {
00098 ttl = strtol(buf, NULL, 10);
00099 }
00100 if (av_find_info_tag(buf, sizeof(buf), "announce_addr", option_list)) {
00101 av_strlcpy(announce_addr, buf, sizeof(announce_addr));
00102 }
00103 }
00104
00105 if (!announce_addr[0]) {
00106 struct addrinfo hints, *ai = NULL;
00107 memset(&hints, 0, sizeof(hints));
00108 hints.ai_family = AF_UNSPEC;
00109 if (getaddrinfo(host, NULL, &hints, &ai)) {
00110 av_log(s, AV_LOG_ERROR, "Unable to resolve %s\n", host);
00111 ret = AVERROR(EIO);
00112 goto fail;
00113 }
00114 if (ai->ai_family == AF_INET) {
00115
00116 av_strlcpy(announce_addr, "224.2.127.254", sizeof(announce_addr));
00117 #if HAVE_STRUCT_SOCKADDR_IN6
00118 } else if (ai->ai_family == AF_INET6) {
00119
00120
00121
00122 av_strlcpy(announce_addr, "ff0e::2:7ffe", sizeof(announce_addr));
00123 #endif
00124 } else {
00125 freeaddrinfo(ai);
00126 av_log(s, AV_LOG_ERROR, "Host %s resolved to unsupported "
00127 "address family\n", host);
00128 ret = AVERROR(EIO);
00129 goto fail;
00130 }
00131 freeaddrinfo(ai);
00132 }
00133
00134 contexts = av_mallocz(sizeof(AVFormatContext*) * s->nb_streams);
00135 if (!contexts) {
00136 ret = AVERROR(ENOMEM);
00137 goto fail;
00138 }
00139
00140 s->start_time_realtime = av_gettime();
00141 for (i = 0; i < s->nb_streams; i++) {
00142 URLContext *fd;
00143
00144 ff_url_join(url, sizeof(url), "rtp", NULL, host, base_port,
00145 "?ttl=%d", ttl);
00146 if (!same_port)
00147 base_port += 2;
00148 ret = url_open(&fd, url, URL_WRONLY);
00149 if (ret) {
00150 ret = AVERROR(EIO);
00151 goto fail;
00152 }
00153 s->streams[i]->priv_data = contexts[i] =
00154 ff_rtp_chain_mux_open(s, s->streams[i], fd, 0);
00155 av_strlcpy(contexts[i]->filename, url, sizeof(contexts[i]->filename));
00156 }
00157
00158 ff_url_join(url, sizeof(url), "udp", NULL, announce_addr, port,
00159 "?ttl=%d&connect=1", ttl);
00160 ret = url_open(&sap->ann_fd, url, URL_WRONLY);
00161 if (ret) {
00162 ret = AVERROR(EIO);
00163 goto fail;
00164 }
00165
00166 udp_fd = url_get_file_handle(sap->ann_fd);
00167 if (getsockname(udp_fd, (struct sockaddr*) &localaddr, &addrlen)) {
00168 ret = AVERROR(EIO);
00169 goto fail;
00170 }
00171 if (localaddr.ss_family != AF_INET
00172 #if HAVE_STRUCT_SOCKADDR_IN6
00173 && localaddr.ss_family != AF_INET6
00174 #endif
00175 ) {
00176 av_log(s, AV_LOG_ERROR, "Unsupported protocol family\n");
00177 ret = AVERROR(EIO);
00178 goto fail;
00179 }
00180 sap->ann_size = 8192;
00181 sap->ann = av_mallocz(sap->ann_size);
00182 if (!sap->ann) {
00183 ret = AVERROR(EIO);
00184 goto fail;
00185 }
00186 sap->ann[pos] = (1 << 5);
00187 #if HAVE_STRUCT_SOCKADDR_IN6
00188 if (localaddr.ss_family == AF_INET6)
00189 sap->ann[pos] |= 0x10;
00190 #endif
00191 pos++;
00192 sap->ann[pos++] = 0;
00193 AV_WB16(&sap->ann[pos], av_get_random_seed());
00194 pos += 2;
00195 if (localaddr.ss_family == AF_INET) {
00196 memcpy(&sap->ann[pos], &((struct sockaddr_in*)&localaddr)->sin_addr,
00197 sizeof(struct in_addr));
00198 pos += sizeof(struct in_addr);
00199 #if HAVE_STRUCT_SOCKADDR_IN6
00200 } else {
00201 memcpy(&sap->ann[pos], &((struct sockaddr_in6*)&localaddr)->sin6_addr,
00202 sizeof(struct in6_addr));
00203 pos += sizeof(struct in6_addr);
00204 #endif
00205 }
00206
00207 av_strlcpy(&sap->ann[pos], "application/sdp", sap->ann_size - pos);
00208 pos += strlen(&sap->ann[pos]) + 1;
00209
00210 if (avf_sdp_create(contexts, s->nb_streams, &sap->ann[pos],
00211 sap->ann_size - pos)) {
00212 ret = AVERROR_INVALIDDATA;
00213 goto fail;
00214 }
00215 av_freep(&contexts);
00216 av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", &sap->ann[pos]);
00217 pos += strlen(&sap->ann[pos]);
00218 sap->ann_size = pos;
00219
00220 if (sap->ann_size > url_get_max_packet_size(sap->ann_fd)) {
00221 av_log(s, AV_LOG_ERROR, "Announcement too large to send in one "
00222 "packet\n");
00223 goto fail;
00224 }
00225
00226 return 0;
00227
00228 fail:
00229 av_free(contexts);
00230 sap_write_close(s);
00231 return ret;
00232 }
00233
00234 static int sap_write_packet(AVFormatContext *s, AVPacket *pkt)
00235 {
00236 AVFormatContext *rtpctx;
00237 struct SAPState *sap = s->priv_data;
00238 int64_t now = av_gettime();
00239
00240 if (!sap->last_time || now - sap->last_time > 5000000) {
00241 int ret = url_write(sap->ann_fd, sap->ann, sap->ann_size);
00242
00243 if (ret < 0 && ret != AVERROR(ECONNREFUSED))
00244 return ret;
00245 sap->last_time = now;
00246 }
00247 rtpctx = s->streams[pkt->stream_index]->priv_data;
00248 return ff_write_chained(rtpctx, 0, pkt, s);
00249 }
00250
00251 AVOutputFormat ff_sap_muxer = {
00252 "sap",
00253 NULL_IF_CONFIG_SMALL("SAP output format"),
00254 NULL,
00255 NULL,
00256 sizeof(struct SAPState),
00257 CODEC_ID_AAC,
00258 CODEC_ID_MPEG4,
00259 sap_write_header,
00260 sap_write_packet,
00261 sap_write_close,
00262 .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER,
00263 };
00264