sapdec.c
Go to the documentation of this file.
1 /*
2  * Session Announcement Protocol (RFC 2974) demuxer
3  * Copyright (c) 2010 Martin Storsjo
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 #include "avio_internal.h"
29 #include "url.h"
30 #if HAVE_POLL_H
31 #include <poll.h>
32 #endif
33 
34 struct SAPState {
38  uint16_t hash;
39  char *sdp;
40  int eof;
41 };
42 
43 static int sap_probe(AVProbeData *p)
44 {
45  if (av_strstart(p->filename, "sap:", NULL))
46  return AVPROBE_SCORE_MAX;
47  return 0;
48 }
49 
51 {
52  struct SAPState *sap = s->priv_data;
53  if (sap->sdp_ctx)
55  if (sap->ann_fd)
56  ffurl_close(sap->ann_fd);
57  av_freep(&sap->sdp);
59  return 0;
60 }
61 
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 = ffurl_open(&sap->ann_fd, url, AVIO_FLAG_READ,
88  if (ret)
89  goto fail;
90 
91  while (1) {
92  int addr_type, auth_len;
93  int pos;
94 
95  ret = ffurl_read(sap->ann_fd, recvbuf, sizeof(recvbuf) - 1);
96  if (ret == AVERROR(EAGAIN))
97  continue;
98  if (ret < 0)
99  goto fail;
100  recvbuf[ret] = '\0'; /* Null terminate for easier parsing */
101  if (ret < 8) {
102  av_log(s, AV_LOG_WARNING, "Received too short packet\n");
103  continue;
104  }
105 
106  if ((recvbuf[0] & 0xe0) != 0x20) {
107  av_log(s, AV_LOG_WARNING, "Unsupported SAP version packet "
108  "received\n");
109  continue;
110  }
111 
112  if (recvbuf[0] & 0x04) {
113  av_log(s, AV_LOG_WARNING, "Received stream deletion "
114  "announcement\n");
115  continue;
116  }
117  addr_type = recvbuf[0] & 0x10;
118  auth_len = recvbuf[1];
119  sap->hash = AV_RB16(&recvbuf[2]);
120  pos = 4;
121  if (addr_type)
122  pos += 16; /* IPv6 */
123  else
124  pos += 4; /* IPv4 */
125  pos += auth_len * 4;
126  if (pos + 4 >= ret) {
127  av_log(s, AV_LOG_WARNING, "Received too short packet\n");
128  continue;
129  }
130 #define MIME "application/sdp"
131  if (strcmp(&recvbuf[pos], MIME) == 0) {
132  pos += strlen(MIME) + 1;
133  } else if (strncmp(&recvbuf[pos], "v=0\r\n", 5) == 0) {
134  // Direct SDP without a mime type
135  } else {
136  av_log(s, AV_LOG_WARNING, "Unsupported mime type %s\n",
137  &recvbuf[pos]);
138  continue;
139  }
140 
141  sap->sdp = av_strdup(&recvbuf[pos]);
142  break;
143  }
144 
145  av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sap->sdp);
146  ffio_init_context(&sap->sdp_pb, sap->sdp, strlen(sap->sdp), 0, NULL, NULL,
147  NULL, NULL);
148 
149  infmt = av_find_input_format("sdp");
150  if (!infmt)
151  goto fail;
153  if (!sap->sdp_ctx) {
154  ret = AVERROR(ENOMEM);
155  goto fail;
156  }
157  sap->sdp_ctx->max_delay = s->max_delay;
158  sap->sdp_ctx->pb = &sap->sdp_pb;
160  ret = avformat_open_input(&sap->sdp_ctx, "temp.sdp", infmt, NULL);
161  if (ret < 0)
162  goto fail;
163  if (sap->sdp_ctx->ctx_flags & AVFMTCTX_NOHEADER)
165  for (i = 0; i < sap->sdp_ctx->nb_streams; i++) {
167  if (!st) {
168  ret = AVERROR(ENOMEM);
169  goto fail;
170  }
171  st->id = i;
173  st->time_base = sap->sdp_ctx->streams[i]->time_base;
174  }
175 
176  return 0;
177 
178 fail:
179  sap_read_close(s);
180  return ret;
181 }
182 
184 {
185  struct SAPState *sap = s->priv_data;
186  int fd = ffurl_get_file_handle(sap->ann_fd);
187  int n, ret;
188  struct pollfd p = {fd, POLLIN, 0};
189  uint8_t recvbuf[1500];
190 
191  if (sap->eof)
192  return AVERROR_EOF;
193 
194  while (1) {
195  n = poll(&p, 1, 0);
196  if (n <= 0 || !(p.revents & POLLIN))
197  break;
198  ret = ffurl_read(sap->ann_fd, recvbuf, sizeof(recvbuf));
199  if (ret >= 8) {
200  uint16_t hash = AV_RB16(&recvbuf[2]);
201  /* Should ideally check the source IP address, too */
202  if (recvbuf[0] & 0x04 && hash == sap->hash) {
203  /* Stream deletion */
204  sap->eof = 1;
205  return AVERROR_EOF;
206  }
207  }
208  }
209  ret = av_read_frame(sap->sdp_ctx, pkt);
210  if (ret < 0)
211  return ret;
212  if (s->ctx_flags & AVFMTCTX_NOHEADER) {
213  while (sap->sdp_ctx->nb_streams > s->nb_streams) {
214  int i = s->nb_streams;
216  if (!st) {
217  av_free_packet(pkt);
218  return AVERROR(ENOMEM);
219  }
220  st->id = i;
222  st->time_base = sap->sdp_ctx->streams[i]->time_base;
223  }
224  }
225  return ret;
226 }
227 
229  .name = "sap",
230  .long_name = NULL_IF_CONFIG_SMALL("SAP input"),
231  .priv_data_size = sizeof(struct SAPState),
232  .read_probe = sap_probe,
233  .read_header = sap_read_header,
234  .read_packet = sap_fetch_packet,
235  .read_close = sap_read_close,
236  .flags = AVFMT_NOFILE,
237 };
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition: utils.c:3173
static int sap_read_close(AVFormatContext *s)
Definition: sapdec.c:50
Bytestream IO Context.
Definition: avio.h:68
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:153
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1005
const char * filename
Definition: avformat.h:339
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: utils.c:476
AVInputFormat ff_sap_demuxer
Definition: sapdec.c:228
static int hash(int head, const int add)
Hash function adding character.
Definition: lzwenc.c:74
void ff_network_close(void)
Definition: network.c:148
AVIOContext sdp_pb
Definition: sapdec.c:37
int ctx_flags
Format-specific flags, see AVFMTCTX_xx.
Definition: avformat.h:864
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
Definition: options.c:140
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...) av_printf_format(7
Assemble a URL string from components.
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:151
Format I/O context.
Definition: avformat.h:828
uint8_t
int ff_network_init(void)
Definition: network.c:121
miscellaneous OS support macros and functions.
int id
Format-specific stream ID.
Definition: avformat.h:629
AVStream ** streams
Definition: avformat.h:876
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:97
uint16_t hash
Definition: sapdec.c:38
static int sap_fetch_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sapdec.c:183
#define AV_RB16
Definition: intreadwrite.h:53
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:88
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:146
AVStream * avformat_new_stream(AVFormatContext *s, AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:2736
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:67
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:641
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:875
AVInputFormat * av_find_input_format(const char *short_name)
Find AVInputFormat based on the short name of the input format.
Definition: utils.c:207
char filename[1024]
input or output filename
Definition: avformat.h:878
URLContext * ann_fd
Definition: sapdec.c:35
AVFormatContext * sdp_ctx
Definition: sapdec.c:36
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:340
char * sdp
Definition: sapdec.c:39
Stream structure.
Definition: avformat.h:622
NULL
Definition: eval.c:52
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:166
AVIOContext * pb
I/O context.
Definition: avformat.h:861
Definition: url.h:41
This structure contains the data a format has to probe a file.
Definition: avformat.h:338
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
Definition: utils.c:1206
static int sap_read_header(AVFormatContext *s)
Definition: sapdec.c:62
static int sap_probe(AVProbeData *p)
Definition: sapdec.c:43
int ffurl_close(URLContext *h)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:286
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:32
Main libavformat public API header.
#define MIME
int ffio_init_context(AVIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:70
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:203
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: utils.c:2713
void * priv_data
Format private data.
Definition: avformat.h:848
int eof
Definition: sapdec.c:40
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:455
unbuffered private I/O API
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:669
This structure stores compressed data.
Definition: avcodec.h:898
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:251