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