| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * Session Announcement Protocol (RFC 2974) demuxer | 
|  | 3  * Copyright (c) 2010 Martin Storsjo | 
|  | 4  * | 
|  | 5  * This file is part of FFmpeg. | 
|  | 6  * | 
|  | 7  * FFmpeg is free software; you can redistribute it and/or | 
|  | 8  * modify it under the terms of the GNU Lesser General Public | 
|  | 9  * License as published by the Free Software Foundation; either | 
|  | 10  * version 2.1 of the License, or (at your option) any later version. | 
|  | 11  * | 
|  | 12  * FFmpeg is distributed in the hope that it will be useful, | 
|  | 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 15  * Lesser General Public License for more details. | 
|  | 16  * | 
|  | 17  * You should have received a copy of the GNU Lesser General Public | 
|  | 18  * License along with FFmpeg; if not, write to the Free Software | 
|  | 19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
|  | 20  */ | 
|  | 21 | 
|  | 22 #include "avformat.h" | 
|  | 23 #include "libavutil/avstring.h" | 
|  | 24 #include "libavutil/intreadwrite.h" | 
|  | 25 #include "network.h" | 
|  | 26 #include "os_support.h" | 
|  | 27 #include "internal.h" | 
|  | 28 #if HAVE_SYS_SELECT_H | 
|  | 29 #include <sys/select.h> | 
|  | 30 #endif | 
|  | 31 #include <sys/time.h> | 
|  | 32 | 
|  | 33 struct SAPState { | 
|  | 34     URLContext *ann_fd; | 
|  | 35     AVFormatContext *sdp_ctx; | 
|  | 36     ByteIOContext sdp_pb; | 
|  | 37     uint16_t hash; | 
|  | 38     char *sdp; | 
|  | 39     int eof; | 
|  | 40 }; | 
|  | 41 | 
|  | 42 static int sap_probe(AVProbeData *p) | 
|  | 43 { | 
|  | 44     if (av_strstart(p->filename, "sap:", NULL)) | 
|  | 45         return AVPROBE_SCORE_MAX; | 
|  | 46     return 0; | 
|  | 47 } | 
|  | 48 | 
|  | 49 static int sap_read_close(AVFormatContext *s) | 
|  | 50 { | 
|  | 51     struct SAPState *sap = s->priv_data; | 
|  | 52     if (sap->sdp_ctx) | 
|  | 53         av_close_input_stream(sap->sdp_ctx); | 
|  | 54     if (sap->ann_fd) | 
|  | 55         url_close(sap->ann_fd); | 
|  | 56     av_freep(&sap->sdp); | 
|  | 57     ff_network_close(); | 
|  | 58     return 0; | 
|  | 59 } | 
|  | 60 | 
|  | 61 static int sap_read_header(AVFormatContext *s, | 
|  | 62                            AVFormatParameters *ap) | 
|  | 63 { | 
|  | 64     struct SAPState *sap = s->priv_data; | 
|  | 65     char host[1024], path[1024], url[1024]; | 
|  | 66     uint8_t recvbuf[1500]; | 
|  | 67     int port; | 
|  | 68     int ret, i; | 
|  | 69     AVInputFormat* infmt; | 
|  | 70 | 
|  | 71     if (!ff_network_init()) | 
|  | 72         return AVERROR(EIO); | 
|  | 73 | 
|  | 74     av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, | 
|  | 75                  path, sizeof(path), s->filename); | 
|  | 76     if (port < 0) | 
|  | 77         port = 9875; | 
|  | 78 | 
|  | 79     if (!host[0]) { | 
|  | 80         /* Listen for announcements on sap.mcast.net if no host was specified */ | 
|  | 81         av_strlcpy(host, "224.2.127.254", sizeof(host)); | 
|  | 82     } | 
|  | 83 | 
|  | 84     ff_url_join(url, sizeof(url), "udp", NULL, host, port, "?localport=%d", | 
|  | 85                 port); | 
|  | 86     ret = url_open(&sap->ann_fd, url, URL_RDONLY); | 
|  | 87     if (ret) | 
|  | 88         goto fail; | 
|  | 89 | 
|  | 90     while (1) { | 
|  | 91         int addr_type, auth_len; | 
|  | 92         int pos; | 
|  | 93 | 
|  | 94         ret = url_read(sap->ann_fd, recvbuf, sizeof(recvbuf) - 1); | 
|  | 95         if (ret == AVERROR(EAGAIN)) | 
|  | 96             continue; | 
|  | 97         if (ret < 0) | 
|  | 98             goto fail; | 
|  | 99         recvbuf[ret] = '\0'; /* Null terminate for easier parsing */ | 
|  | 100         if (ret < 8) { | 
|  | 101             av_log(s, AV_LOG_WARNING, "Received too short packet\n"); | 
|  | 102             continue; | 
|  | 103         } | 
|  | 104 | 
|  | 105         if ((recvbuf[0] & 0xe0) != 0x20) { | 
|  | 106             av_log(s, AV_LOG_WARNING, "Unsupported SAP version packet " | 
|  | 107                                       "received\n"); | 
|  | 108             continue; | 
|  | 109         } | 
|  | 110 | 
|  | 111         if (recvbuf[0] & 0x04) { | 
|  | 112             av_log(s, AV_LOG_WARNING, "Received stream deletion " | 
|  | 113                                       "announcement\n"); | 
|  | 114             continue; | 
|  | 115         } | 
|  | 116         addr_type = recvbuf[0] & 0x10; | 
|  | 117         auth_len  = recvbuf[1]; | 
|  | 118         sap->hash = AV_RB16(&recvbuf[2]); | 
|  | 119         pos = 4; | 
|  | 120         if (addr_type) | 
|  | 121             pos += 16; /* IPv6 */ | 
|  | 122         else | 
|  | 123             pos += 4; /* IPv4 */ | 
|  | 124         pos += auth_len * 4; | 
|  | 125         if (pos + 4 >= ret) { | 
|  | 126             av_log(s, AV_LOG_WARNING, "Received too short packet\n"); | 
|  | 127             continue; | 
|  | 128         } | 
|  | 129 #define MIME "application/sdp" | 
|  | 130         if (strcmp(&recvbuf[pos], MIME) == 0) { | 
|  | 131             pos += strlen(MIME) + 1; | 
|  | 132         } else if (strncmp(&recvbuf[pos], "v=0\r\n", 5) == 0) { | 
|  | 133             // Direct SDP without a mime type | 
|  | 134         } else { | 
|  | 135             av_log(s, AV_LOG_WARNING, "Unsupported mime type %s\n", | 
|  | 136                                       &recvbuf[pos]); | 
|  | 137             continue; | 
|  | 138         } | 
|  | 139 | 
|  | 140         sap->sdp = av_strdup(&recvbuf[pos]); | 
|  | 141         break; | 
|  | 142     } | 
|  | 143 | 
|  | 144     av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sap->sdp); | 
|  | 145     init_put_byte(&sap->sdp_pb, sap->sdp, strlen(sap->sdp), 0, NULL, NULL, | 
|  | 146                   NULL, NULL); | 
|  | 147 | 
|  | 148     infmt = av_find_input_format("sdp"); | 
|  | 149     if (!infmt) | 
|  | 150         goto fail; | 
|  | 151     sap->sdp_ctx = avformat_alloc_context(); | 
|  | 152     if (!sap->sdp_ctx) { | 
|  | 153         ret = AVERROR(ENOMEM); | 
|  | 154         goto fail; | 
|  | 155     } | 
|  | 156     sap->sdp_ctx->max_delay = s->max_delay; | 
|  | 157     ap->prealloced_context = 1; | 
|  | 158     ret = av_open_input_stream(&sap->sdp_ctx, &sap->sdp_pb, "temp.sdp", | 
|  | 159                                infmt, ap); | 
|  | 160     if (ret < 0) | 
|  | 161         goto fail; | 
|  | 162     if (sap->sdp_ctx->ctx_flags & AVFMTCTX_NOHEADER) | 
|  | 163         s->ctx_flags |= AVFMTCTX_NOHEADER; | 
|  | 164     for (i = 0; i < sap->sdp_ctx->nb_streams; i++) { | 
|  | 165         AVStream *st = av_new_stream(s, i); | 
|  | 166         if (!st) { | 
|  | 167             ret = AVERROR(ENOMEM); | 
|  | 168             goto fail; | 
|  | 169         } | 
|  | 170         avcodec_copy_context(st->codec, sap->sdp_ctx->streams[i]->codec); | 
|  | 171         st->time_base = sap->sdp_ctx->streams[i]->time_base; | 
|  | 172     } | 
|  | 173 | 
|  | 174     return 0; | 
|  | 175 | 
|  | 176 fail: | 
|  | 177     sap_read_close(s); | 
|  | 178     return ret; | 
|  | 179 } | 
|  | 180 | 
|  | 181 static int sap_fetch_packet(AVFormatContext *s, AVPacket *pkt) | 
|  | 182 { | 
|  | 183     struct SAPState *sap = s->priv_data; | 
|  | 184     int fd = url_get_file_handle(sap->ann_fd); | 
|  | 185     int n, ret; | 
|  | 186     fd_set rfds; | 
|  | 187     struct timeval tv; | 
|  | 188     uint8_t recvbuf[1500]; | 
|  | 189 | 
|  | 190     if (sap->eof) | 
|  | 191         return AVERROR_EOF; | 
|  | 192 | 
|  | 193     while (1) { | 
|  | 194         FD_ZERO(&rfds); | 
|  | 195         FD_SET(fd, &rfds); | 
|  | 196         tv.tv_sec = tv.tv_usec = 0; | 
|  | 197         n = select(fd + 1, &rfds, NULL, NULL, &tv); | 
|  | 198         if (n <= 0 || !FD_ISSET(fd, &rfds)) | 
|  | 199             break; | 
|  | 200         ret = url_read(sap->ann_fd, recvbuf, sizeof(recvbuf)); | 
|  | 201         if (ret >= 8) { | 
|  | 202             uint16_t hash = AV_RB16(&recvbuf[2]); | 
|  | 203             /* Should ideally check the source IP address, too */ | 
|  | 204             if (recvbuf[0] & 0x04 && hash == sap->hash) { | 
|  | 205                 /* Stream deletion */ | 
|  | 206                 sap->eof = 1; | 
|  | 207                 return AVERROR_EOF; | 
|  | 208             } | 
|  | 209         } | 
|  | 210     } | 
|  | 211     ret = av_read_frame(sap->sdp_ctx, pkt); | 
|  | 212     if (ret < 0) | 
|  | 213         return ret; | 
|  | 214     if (s->ctx_flags & AVFMTCTX_NOHEADER) { | 
|  | 215         while (sap->sdp_ctx->nb_streams > s->nb_streams) { | 
|  | 216             int i = s->nb_streams; | 
|  | 217             AVStream *st = av_new_stream(s, i); | 
|  | 218             if (!st) { | 
|  | 219                 av_free_packet(pkt); | 
|  | 220                 return AVERROR(ENOMEM); | 
|  | 221             } | 
|  | 222             avcodec_copy_context(st->codec, sap->sdp_ctx->streams[i]->codec); | 
|  | 223             st->time_base = sap->sdp_ctx->streams[i]->time_base; | 
|  | 224         } | 
|  | 225     } | 
|  | 226     return ret; | 
|  | 227 } | 
|  | 228 | 
|  | 229 AVInputFormat sap_demuxer = { | 
|  | 230     "sap", | 
|  | 231     NULL_IF_CONFIG_SMALL("SAP input format"), | 
|  | 232     sizeof(struct SAPState), | 
|  | 233     sap_probe, | 
|  | 234     sap_read_header, | 
|  | 235     sap_fetch_packet, | 
|  | 236     sap_read_close, | 
|  | 237     .flags = AVFMT_NOFILE, | 
|  | 238 }; | 
|  | 239 | 
| OLD | NEW | 
|---|