static int open_input(struct variant *var) { AVDictionary *opts = NULL; int ret; struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; av_dict_set(&opts, "seekable", "0", 0); if (seg->key_type == KEY_NONE) { ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ, &var->parent->interrupt_callback, &opts); goto cleanup; } else if (seg->key_type == KEY_AES_128) { char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, var->key_url)) { URLContext *uc; if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, &var->parent->interrupt_callback, &opts) == 0) { if (ffurl_read_complete(uc, var->key, sizeof(var->key)) != sizeof(var->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", seg->key); } ffurl_close(uc); } else { av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", seg->key); } av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); } ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); ff_data_to_hex(key, var->key, sizeof(var->key), 0); iv[32] = key[32] = '\0'; if (strstr(seg->url, "://")) snprintf(url, sizeof(url), "crypto+%s", seg->url); else snprintf(url, sizeof(url), "crypto:%s", seg->url); if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ, &var->parent->interrupt_callback)) < 0) goto cleanup; av_opt_set(var->input->priv_data, "key", key, 0); av_opt_set(var->input->priv_data, "iv", iv, 0); /* Need to repopulate options */ av_dict_free(&opts); av_dict_set(&opts, "seekable", "0", 0); if ((ret = ffurl_connect(var->input, &opts)) < 0) { ffurl_close(var->input); var->input = NULL; goto cleanup; } ret = 0; } else ret = AVERROR(ENOSYS); cleanup: av_dict_free(&opts); return ret; }
static int gopher_open(URLContext *h, const char *uri, int flags) { GopherContext *s = h->priv_data; char hostname[1024], auth[1024], path[1024], buf[1024]; int port, err; h->is_streamed = 1; /* needed in any case to build the host string */ av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (port < 0) port = 70; ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); s->hd = NULL; err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, NULL); if (err < 0) goto fail; if ((err = gopher_connect(h, path)) < 0) goto fail; return 0; fail: gopher_close(h); return err; }
static int cache_open(URLContext *h, const char *arg, int flags) { int access; const char *buffername; Context *c; c = av_mallocz(sizeof(Context)); if (!c) { return AVERROR(ENOMEM); } h->priv_data = c; av_strstart(arg, "cache:", &arg); c->fd = av_tempfile("ffcache", &buffername, 0, h); if (c->fd < 0){ av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n"); return c->fd; } unlink(buffername); av_free(buffername); return ffurl_open(&c->inner, arg, flags); }
static int mtc_open(URLContext * h, const char *uri, int flags) { char path[1024]; char buf[1024]; const char *p; int error; MTCContext *c = h->priv_data; av_url_split(NULL, 0, NULL, 0, c->hostname, sizeof(c->hostname), &c->server_control_port, path, sizeof(path), uri); p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "authorization", p)) { av_strlcpy(c->credencials, buf, sizeof(c->credencials)); } } if (!s->conn_control) { ff_url_join(buf, sizeof(buf), "tcp", NULL, c->hostname, c->server_control_port,NULL); error = ffurl_open(&c->conn_control, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, NULL); if (erro < 0) { av_log(h, AV_LOG_ERROR, "Cannot open control connection\n"); return error; } } //授权 return 0; }
static int rtmpe_open(URLContext *h, const char *uri, int flags) { RTMPEContext *rt = h->priv_data; char host[256], url[1024]; int ret, port; av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri); if (rt->tunneling) { if (port < 0) port = 80; ff_url_join(url, sizeof(url), "ffrtmphttp", NULL, host, port, NULL); } else { if (port < 0) port = 1935; ff_url_join(url, sizeof(url), "tcp", NULL, host, port, NULL); } /* open the tcp or ffrtmphttp connection */ if ((ret = ffurl_open(&rt->stream, url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, NULL)) < 0) { rtmpe_close(h); return ret; } return 0; }
static int srtp_open(URLContext *h, const char *uri, int flags) { SRTPProtoContext *s = h->priv_data; char hostname[256], buf[1024], path[1024]; int rtp_port, ret; if (s->out_suite && s->out_params) if ((ret = ff_srtp_set_crypto(&s->srtp_out, s->out_suite, s->out_params)) < 0) goto fail; if (s->in_suite && s->in_params) if ((ret = ff_srtp_set_crypto(&s->srtp_in, s->in_suite, s->in_params)) < 0) goto fail; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, path, sizeof(path), uri); ff_url_join(buf, sizeof(buf), "rtp", NULL, hostname, rtp_port, "%s", path); if ((ret = ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL)) < 0) goto fail; h->max_packet_size = FFMIN(s->rtp_hd->max_packet_size, sizeof(s->encryptbuf)) - 14; h->is_streamed = 1; return 0; fail: srtp_close(h); return ret; }
static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; int ret; static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; char hostname[1024], proto[10]; char lower_url[100]; const char *lower_proto = "tcp"; int port, new_location; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); if (!strcmp(proto, "https")) lower_proto = "tls"; ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port, NULL); av_dict_set(options, "listen", "1", 0); if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options)) < 0) goto fail; if ((ret = http_read_header(h, &new_location)) < 0) goto fail; if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) goto fail; return 0; fail: handle_http_errors(h, ret); av_dict_free(&s->chained_options); return ret; }
static int md5_close(URLContext *h) { struct MD5Context *c = h->priv_data; const char *filename = h->filename; uint8_t md5[16], buf[64]; URLContext *out; int i, err = 0; av_md5_final(c->md5, md5); for (i = 0; i < sizeof(md5); i++) snprintf(buf + i*2, 3, "%02x", md5[i]); buf[i*2] = '\n'; av_strstart(filename, "md5:", &filename); if (*filename) { err = ffurl_open(&out, filename, AVIO_FLAG_WRITE, &h->interrupt_callback, NULL); if (err) return err; err = ffurl_write(out, buf, i*2+1); ffurl_close(out); } else { if (fwrite(buf, 1, i*2+1, stdout) < i*2+1) err = AVERROR(errno); } av_freep(&c->md5); return err; }
static int cache_open(URLContext *h, const char *arg, int flags) { int ret; Context *c= (Context*)h->priv_data; c->local_buffer_path = getLocalCachePath(h); if(!c->local_buffer_path){ c->fd = -1; return -1; } av_strstart(arg, "ucache:", &arg); av_log(h, AV_LOG_INFO, "cache_open:local_buffer_path:%s\n",c->local_buffer_path); c->fd = open(c->local_buffer_path, O_RDWR | O_CREAT | O_TRUNC, 0666); if (c->fd < 0){ av_log(h, AV_LOG_ERROR, "ucache_protocol.cache_open:Failed to create tempfile\n"); //return c->fd; } ret = ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL); if(ret && c->fd >= 0){ //删除文件 close(c->fd); c->fd = -1; unlink(c->local_buffer_path); } return ret; }
static int md5_close(URLContext *h) { const char *filename = h->filename; uint8_t md5[16], buf[64]; URLContext *out; int i, err = 0; av_md5_final(h->priv_data, md5); for (i = 0; i < sizeof(md5); i++) snprintf(buf + i*2, 3, "%02x", md5[i]); buf[i*2] = '\n'; av_strstart(filename, "md5:", &filename); if (*filename) { err = ffurl_open(&out, filename, AVIO_WRONLY); if (err) return err; err = ffurl_write(out, buf, i*2+1); ffurl_close(out); } else { if (fwrite(buf, 1, i*2+1, stdout) < i*2+1) err = AVERROR(errno); } return err; }
/* * open fec connect */ int fec_connect(AVFormatContext *s,RTSPStream* rtsp_fec){ int err = 0; av_log(NULL,AV_LOG_ERROR,"%s:s->filename = %s",__FUNCTION__,s->filename); if (!ff_network_init()){ av_log(NULL,AV_LOG_ERROR,"%s:ff_network_init fail",__FUNCTION__); return AVERROR(EIO); } int flags = AVIO_FLAG_READ; av_log(NULL,AV_LOG_ERROR,"%s:url = %s",__FUNCTION__,rtsp_fec->control_url); if (ffurl_open(&rtsp_fec->rtp_handle, rtsp_fec->control_url, flags, &s->interrupt_callback, NULL) < 0) { err = AVERROR_INVALIDDATA; av_log(NULL,AV_LOG_ERROR,"%s: ffurl_open fail",__FUNCTION__); goto fail; } if ((err = ff_rtsp_open_transport_ctx(s, rtsp_fec))) goto fail; av_log(NULL,AV_LOG_ERROR,"%s: OK********",__FUNCTION__); return 0; fail: ff_network_close(); return -1; }
static int http_open_cnx_internal(URLContext *h, AVDictionary **options) { const char *path, *proxy_path, *lower_proto = "tcp", *local_path; char hostname[1024], hoststr[1024], proto[10]; char auth[1024], proxyauth[1024] = ""; char path1[MAX_URL_SIZE]; char buf[1024], urlbuf[MAX_URL_SIZE]; int port, use_proxy, err, location_changed = 0; HTTPContext *s = h->priv_data; av_url_split(proto, sizeof(proto), auth, sizeof(auth), hostname, sizeof(hostname), &port, path1, sizeof(path1), s->location); ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); proxy_path = getenv("http_proxy"); use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) && proxy_path && av_strstart(proxy_path, "http://", NULL); if (!strcmp(proto, "https")) { lower_proto = "tls"; use_proxy = 0; if (port < 0) port = 443; } if (port < 0) port = 80; if (path1[0] == '\0') path = "/"; else path = path1; local_path = path; if (use_proxy) { /* Reassemble the request URL without auth string - we don't * want to leak the auth to the proxy. */ ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s", path1); path = urlbuf; av_url_split(NULL, 0, proxyauth, sizeof(proxyauth), hostname, sizeof(hostname), &port, NULL, 0, proxy_path); } ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL); if (!s->hd) { err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options); if (err < 0) return err; } err = http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed); if (err < 0) return err; return location_changed; }
int url_exist(const char *filename) { URLContext *h; if (ffurl_open(&h, filename, AVIO_FLAG_READ) < 0) return 0; ffurl_close(h); return 1; }
static int open_input(struct variant *var) { struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; if (seg->key_type == KEY_NONE) { return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ); } else if (seg->key_type == KEY_AES_128) { char iv[33], key[33], url[MAX_URL_SIZE]; int ret; if (strcmp(seg->key, var->key_url)) { URLContext *uc; if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ) == 0) { if (ffurl_read_complete(uc, var->key, sizeof(var->key)) != sizeof(var->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", seg->key); } ffurl_close(uc); } else { av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", seg->key); } av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); } ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); ff_data_to_hex(key, var->key, sizeof(var->key), 0); iv[32] = key[32] = '\0'; if (strstr(seg->url, "://")) snprintf(url, sizeof(url), "crypto+%s", seg->url); else snprintf(url, sizeof(url), "crypto:%s", seg->url); if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ)) < 0) return ret; av_set_string3(var->input->priv_data, "key", key, 0, NULL); av_set_string3(var->input->priv_data, "iv", iv, 0, NULL); if ((ret = ffurl_connect(var->input)) < 0) { ffurl_close(var->input); var->input = NULL; return ret; } return 0; } return AVERROR(ENOSYS); }
static int applehttp_read(URLContext *h, uint8_t *buf, int size) { AppleHTTPContext *s = h->priv_data; const char *url; int ret; start: if (s->seg_hd) { ret = ffurl_read(s->seg_hd, buf, size); if (ret > 0) return ret; } if (s->seg_hd) { ffurl_close(s->seg_hd); s->seg_hd = NULL; s->cur_seq_no++; } retry: if (!s->finished) { int64_t now = av_gettime(); if (now - s->last_load_time >= s->target_duration*1000000) if ((ret = parse_playlist(h, s->playlisturl)) < 0) return ret; } if (s->cur_seq_no < s->start_seq_no) { av_log(h, AV_LOG_WARNING, "skipping %d segments ahead, expired from playlist\n", s->start_seq_no - s->cur_seq_no); s->cur_seq_no = s->start_seq_no; } if (s->cur_seq_no - s->start_seq_no >= s->n_segments) { if (s->finished) return AVERROR_EOF; while (av_gettime() - s->last_load_time < s->target_duration*1000000) { if (ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; usleep(100*1000); } goto retry; } url = s->segments[s->cur_seq_no - s->start_seq_no]->url, av_log(h, AV_LOG_DEBUG, "opening %s\n", url); ret = ffurl_open(&s->seg_hd, url, AVIO_FLAG_READ, &h->interrupt_callback, NULL); if (ret < 0) { if (ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; av_log(h, AV_LOG_WARNING, "Unable to open %s\n", url); s->cur_seq_no++; goto retry; } goto start; }
static int open_url(HLSContext *c, URLContext **uc, const char *url) { AVDictionary *tmp = NULL; int ret; av_dict_copy(&tmp, c->avio_opts, 0); ret = ffurl_open(uc, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); av_dict_free(&tmp); return ret; }
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options) { int port; const char *p; char buf[200], opts[50] = ""; struct addrinfo hints = { 0 }, *ai = NULL; const char *proxy_path; int use_proxy; if (c->listen) snprintf(opts, sizeof(opts), "?listen=1"); av_url_split(NULL, 0, NULL, 0, c->host, sizeof(c->host), &port, NULL, 0, uri); p = strchr(uri, '?'); if (!p) { p = opts; } else { if (av_find_info_tag(opts, sizeof(opts), "listen", p)) c->listen = 1; } ff_url_join(buf, sizeof(buf), "tcp", NULL, c->host, port, "%s", p); hints.ai_flags = AI_NUMERICHOST; if (!getaddrinfo(c->host, NULL, &hints, &ai)) { c->numerichost = 1; freeaddrinfo(ai); } proxy_path = getenv("http_proxy"); use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), c->host) && proxy_path && av_strstart(proxy_path, "http://", NULL); if (use_proxy) { char proxy_host[200], proxy_auth[200], dest[200]; int proxy_port; av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth), proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0, proxy_path); ff_url_join(dest, sizeof(dest), NULL, NULL, c->host, port, NULL); ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host, proxy_port, "/%s", dest); } return ffurl_open(&c->tcp, buf, AVIO_FLAG_READ_WRITE, &parent->interrupt_callback, options, parent->protocols, parent); }
static int cache_open(URLContext *h, const char *arg, int flags) { const char *buffername; Context *c= (Context *)h->priv_data; av_strstart(arg, "cache:", &arg); c->fd = av_tempfile("ffcache", (char **)&buffername, 0, h); if (c->fd < 0){ av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n"); return c->fd; } unlink(buffername); av_freep(&buffername); return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL); }
bool StreamingRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) { avcodeclock->lock(); av_register_all(); avcodeclock->unlock(); RingBuffer::AVFormatInitNetwork(); rwlock.lockForWrite(); safefilename = lfilename; filename = lfilename; // TODO check whether local area file QUrl url = filename; if (url.path().endsWith(QLatin1String("m3u8"), Qt::CaseInsensitive)) { url.setScheme("hls+http"); } int res = ffurl_open(&m_context, url.toString().toLatin1(), AVIO_FLAG_READ, NULL, NULL); if (res >=0 && m_context && !m_context->is_streamed && ffurl_seek(m_context, 0, SEEK_SET) >= 0) { m_streamed = false; m_allowSeeks = true; } LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying %1 (allow seeks: %2") .arg(filename).arg(m_allowSeeks)); rwlock.unlock(); if (res < 0 || !m_context) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open stream (error %1)") .arg(res)); return false; } return true; }
static int crypto_open(URLContext *h, const char *uri, int flags) { const char *nested_url; int ret = 0; CryptoContext *c = h->priv_data; if (!av_strstart(uri, "crypto+", &nested_url) && !av_strstart(uri, "crypto:", &nested_url)) { av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri); ret = AVERROR(EINVAL); goto err; } if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) { av_log(h, AV_LOG_ERROR, "Key or IV not set\n"); ret = AVERROR(EINVAL); goto err; } if (flags & AVIO_FLAG_WRITE) { av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n"); ret = AVERROR(ENOSYS); goto err; } if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ, &h->interrupt_callback, NULL, h->protocols, h)) < 0) { av_log(h, AV_LOG_ERROR, "Unable to open input\n"); goto err; } c->aes = av_aes_alloc(); if (!c->aes) { ret = AVERROR(ENOMEM); goto err; } av_aes_init(c->aes, c->key, 128, 1); h->is_streamed = 1; err: return ret; }
static int gopher_open(URLContext *h, const char *uri, int flags) { GopherContext *s; char hostname[1024], auth[1024], path[1024], buf[1024]; int port, err; h->is_streamed = 1; s = av_malloc(sizeof(GopherContext)); if (!s) { return AVERROR(ENOMEM); } h->priv_data = s; /* needed in any case to build the host string */ av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (port < 0) port = 70; ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); s->hd = NULL; err = ffurl_open(&s->hd, buf, AVIO_RDWR); if (err < 0) goto fail; if ((err = gopher_connect(h, path)) < 0) goto fail; return 0; fail: gopher_close(h); return err; }
static int rtsp_listen(AVFormatContext *s) { RTSPState *rt = s->priv_data; char host[128], path[512], auth[128]; char uri[500]; int port; char tcpname[500]; unsigned char rbuf[4096]; unsigned char method[10]; int rbuflen = 0; int ret; enum RTSPMethod methodcode; /* extract hostname and port */ av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port, path, sizeof(path), s->filename); /* ff_url_join. No authorization by now (NULL) */ ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, host, port, "%s", path); if (port < 0) port = RTSP_DEFAULT_PORT; /* Create TCP connection */ ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, "?listen&listen_timeout=%d", rt->initial_timeout * 1000); if (ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, NULL)) { av_log(s, AV_LOG_ERROR, "Unable to open RTSP for listening\n"); return ret; } rt->state = RTSP_STATE_IDLE; rt->rtsp_hd_out = rt->rtsp_hd; for (;;) { /* Wait for incoming RTSP messages */ ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen); if (ret < 0) return ret; ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method, sizeof(method), &methodcode); if (ret) { av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n"); return ret; } if (methodcode == ANNOUNCE) { ret = rtsp_read_announce(s); rt->state = RTSP_STATE_PAUSED; } else if (methodcode == OPTIONS) { ret = rtsp_read_options(s); } else if (methodcode == RECORD) { ret = rtsp_read_record(s); if (!ret) return 0; // We are ready for streaming } else if (methodcode == SETUP) ret = rtsp_read_setup(s, host, uri); if (ret) { ffurl_close(rt->rtsp_hd); return AVERROR_INVALIDDATA; } } return 0; }
static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl) { RTSPState *rt = s->priv_data; RTSPMessageHeader request = { 0 }; int ret = 0; char url[1024]; RTSPStream *rtsp_st; char responseheaders[1024]; int localport = -1; int transportidx = 0; int streamid = 0; ret = rtsp_read_request(s, &request, "SETUP"); if (ret) return ret; rt->seq++; if (!request.nb_transports) { av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n"); return AVERROR_INVALIDDATA; } for (transportidx = 0; transportidx < request.nb_transports; transportidx++) { if (!request.transports[transportidx].mode_record || (request.transports[transportidx].lower_transport != RTSP_LOWER_TRANSPORT_UDP && request.transports[transportidx].lower_transport != RTSP_LOWER_TRANSPORT_TCP)) { av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport" " protocol not supported (yet)\n"); return AVERROR_INVALIDDATA; } } if (request.nb_transports > 1) av_log(s, AV_LOG_WARNING, "More than one transport not supported, " "using first of all\n"); for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) { if (!strcmp(rt->rtsp_streams[streamid]->control_url, controlurl)) break; } if (streamid == rt->nb_rtsp_streams) { av_log(s, AV_LOG_ERROR, "Unable to find requested track\n"); return AVERROR_STREAM_NOT_FOUND; } rtsp_st = rt->rtsp_streams[streamid]; localport = rt->rtp_port_min; if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) { rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP; if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) { rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq); return ret; } rtsp_st->interleaved_min = request.transports[0].interleaved_min; rtsp_st->interleaved_max = request.transports[0].interleaved_max; snprintf(responseheaders, sizeof(responseheaders), "Transport: " "RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d" "\r\n", request.transports[0].interleaved_min, request.transports[0].interleaved_max); } else { do { ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL); av_dlog(s, "Opening: %s", url); ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, NULL); if (ret) localport += 2; } while (ret || localport > rt->rtp_port_max); if (localport > rt->rtp_port_max) { rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq); return ret; } av_dlog(s, "Listening on: %d", ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle)); if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) { rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq); return ret; } localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle); snprintf(responseheaders, sizeof(responseheaders), "Transport: " "RTP/AVP/UDP;unicast;mode=receive;source=%s;" "client_port=%d-%d;server_port=%d-%d\r\n", host, request.transports[0].client_port_min, request.transports[0].client_port_max, localport, localport + 1); } /* Establish sessionid if not previously set */ /* Put this in a function? */ /* RFC 2326: session id must be at least 8 digits */ while (strlen(rt->session_id) < 8) av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed()); av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n", rt->session_id); /* Send Reply */ rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq); rt->state = RTSP_STATE_PAUSED; return 0; }
static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s = h->priv_data; int rtp_port, rtcp_port, ttl, connect, local_rtp_port, local_rtcp_port, max_packet_size; char hostname[256]; char buf[1024]; char path[1024]; const char *p; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, path, sizeof(path), uri); /* extract parameters */ ttl = -1; rtcp_port = rtp_port+1; local_rtp_port = -1; local_rtcp_port = -1; max_packet_size = -1; connect = 0; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) { rtcp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { local_rtp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) { local_rtp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) { local_rtcp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { connect = strtol(buf, NULL, 10); } } build_udp_url(buf, sizeof(buf), hostname, rtp_port, local_rtp_port, ttl, max_packet_size, connect); if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) goto fail; if (local_rtp_port>=0 && local_rtcp_port<0) local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1; build_udp_url(buf, sizeof(buf), hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, connect); if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) goto fail; /* just to ease handle access. XXX: need to suppress direct handle access */ s->rtp_fd = ffurl_get_file_handle(s->rtp_hd); s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd); h->max_packet_size = s->rtp_hd->max_packet_size; h->is_streamed = 1; return 0; fail: if (s->rtp_hd) ffurl_close(s->rtp_hd); if (s->rtcp_hd) ffurl_close(s->rtcp_hd); return AVERROR(EIO); }
static int mms_open(URLContext *h, const char *uri, int flags) { MMSTContext *mmst; MMSContext *mms; int port, err; char tcpname[256]; h->is_streamed = 1; mmst = h->priv_data = av_mallocz(sizeof(MMSTContext)); if (!h->priv_data) return AVERROR(ENOMEM); mms = &mmst->mms; // only for MMS over TCP, so set proto = NULL av_url_split(NULL, 0, NULL, 0, mmst->host, sizeof(mmst->host), &port, mmst->path, sizeof(mmst->path), uri); if(port < 0) port = 1755; // defaut mms protocol port // establish tcp connection. ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, mmst->host, port, NULL); err = ffurl_open(&mms->mms_hd, tcpname, AVIO_RDWR); if (err) goto fail; mmst->packet_id = 3; // default, initial value. mmst->header_packet_id = 2; // default, initial value. err = mms_safe_send_recv(mmst, send_startup_packet, SC_PKT_CLIENT_ACCEPTED); if (err) goto fail; err = mms_safe_send_recv(mmst, send_time_test_data, SC_PKT_TIMING_TEST_REPLY); if (err) goto fail; err = mms_safe_send_recv(mmst, send_protocol_select, SC_PKT_PROTOCOL_ACCEPTED); if (err) goto fail; err = mms_safe_send_recv(mmst, send_media_file_request, SC_PKT_MEDIA_FILE_DETAILS); if (err) goto fail; err = mms_safe_send_recv(mmst, send_media_header_request, SC_PKT_HEADER_REQUEST_ACCEPTED); if (err) goto fail; err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_HEADER); if (err) goto fail; if((mmst->incoming_flags != 0X08) && (mmst->incoming_flags != 0X0C)) { av_log(NULL, AV_LOG_ERROR, "The server does not support MMST (try MMSH or RTSP)\n"); err = AVERROR(EINVAL); goto fail; } err = ff_mms_asf_header_parser(mms); if (err) { av_dlog(NULL, "asf header parsed failed!\n"); goto fail; } mms->header_parsed = 1; if (!mms->asf_packet_len || !mms->stream_num) goto fail; clear_stream_buffers(mms); err = mms_safe_send_recv(mmst, send_stream_selection_request, SC_PKT_STREAM_ID_ACCEPTED); if (err) goto fail; // send media packet request err = mms_safe_send_recv(mmst, send_media_packet_request, SC_PKT_MEDIA_PKT_FOLLOWS); if (err) { goto fail; } av_dlog(NULL, "Leaving open (success)\n"); return 0; fail: mms_close(h); av_dlog(NULL, "Leaving open (failure: %d)\n", err); return err; }
int url_open(URLContext **puc, const char *filename, int flags) { return ffurl_open(puc, filename, flags); }
static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s = h->priv_data; int rtp_port, rtcp_port, ttl, connect, local_rtp_port, local_rtcp_port, max_packet_size; char hostname[256], include_sources[1024] = "", exclude_sources[1024] = ""; char buf[1024]; char path[1024]; const char *p; int i, max_retry_count = 3; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, path, sizeof(path), uri); /* extract parameters */ ttl = -1; rtcp_port = rtp_port+1; local_rtp_port = -1; local_rtcp_port = -1; max_packet_size = -1; connect = 0; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) { rtcp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { local_rtp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) { local_rtp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) { local_rtcp_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { connect = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) { s->write_to_source = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { av_strlcpy(include_sources, buf, sizeof(include_sources)); rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs); } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { av_strlcpy(exclude_sources, buf, sizeof(exclude_sources)); rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs); } } for (i = 0;i < max_retry_count;i++) { build_udp_url(buf, sizeof(buf), hostname, rtp_port, local_rtp_port, ttl, max_packet_size, connect, include_sources, exclude_sources); if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) goto fail; local_rtp_port = ff_udp_get_local_port(s->rtp_hd); if(local_rtp_port == 65535) { local_rtp_port = -1; continue; } if (local_rtcp_port<0) { local_rtcp_port = local_rtp_port + 1; build_udp_url(buf, sizeof(buf), hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, connect, include_sources, exclude_sources); if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) { local_rtp_port = local_rtcp_port = -1; continue; } break; } build_udp_url(buf, sizeof(buf), hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, connect, include_sources, exclude_sources); if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) goto fail; break; } /* just to ease handle access. XXX: need to suppress direct handle access */ s->rtp_fd = ffurl_get_file_handle(s->rtp_hd); s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd); h->max_packet_size = s->rtp_hd->max_packet_size; h->is_streamed = 1; return 0; fail: if (s->rtp_hd) ffurl_close(s->rtp_hd); if (s->rtcp_hd) ffurl_close(s->rtcp_hd); return AVERROR(EIO); }
static int sap_write_header(AVFormatContext *s) { struct SAPState *sap = s->priv_data; char host[1024], path[1024], url[1024], announce_addr[50] = ""; char *option_list; int port = 9875, base_port = 5004, i, pos = 0, same_port = 0, ttl = 255; AVFormatContext **contexts = NULL; int ret = 0; struct sockaddr_storage localaddr; socklen_t addrlen = sizeof(localaddr); int udp_fd; if (!ff_network_init()) return AVERROR(EIO); /* extract hostname and port */ av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &base_port, path, sizeof(path), s->filename); if (base_port < 0) base_port = 5004; /* search for options */ option_list = strrchr(path, '?'); if (option_list) { char buf[50]; if (av_find_info_tag(buf, sizeof(buf), "announce_port", option_list)) { port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "same_port", option_list)) { same_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "ttl", option_list)) { ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "announce_addr", option_list)) { av_strlcpy(announce_addr, buf, sizeof(announce_addr)); } } if (!announce_addr[0]) { struct addrinfo hints = { 0 }, *ai = NULL; hints.ai_family = AF_UNSPEC; if (getaddrinfo(host, NULL, &hints, &ai)) { av_log(s, AV_LOG_ERROR, "Unable to resolve %s\n", host); ret = AVERROR(EIO); goto fail; } if (ai->ai_family == AF_INET) { /* Also known as sap.mcast.net */ av_strlcpy(announce_addr, "224.2.127.254", sizeof(announce_addr)); #if HAVE_STRUCT_SOCKADDR_IN6 } else if (ai->ai_family == AF_INET6) { /* With IPv6, you can use the same destination in many different * multicast subnets, to choose how far you want it routed. * This one is intended to be routed globally. */ av_strlcpy(announce_addr, "ff0e::2:7ffe", sizeof(announce_addr)); #endif } else { freeaddrinfo(ai); av_log(s, AV_LOG_ERROR, "Host %s resolved to unsupported " "address family\n", host); ret = AVERROR(EIO); goto fail; } freeaddrinfo(ai); } contexts = av_mallocz(sizeof(AVFormatContext*) * s->nb_streams); if (!contexts) { ret = AVERROR(ENOMEM); goto fail; } s->start_time_realtime = av_gettime(); for (i = 0; i < s->nb_streams; i++) { URLContext *fd; ff_url_join(url, sizeof(url), "rtp", NULL, host, base_port, "?ttl=%d", ttl); if (!same_port) base_port += 2; ret = ffurl_open(&fd, url, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); if (ret) { ret = AVERROR(EIO); goto fail; } s->streams[i]->priv_data = contexts[i] = ff_rtp_chain_mux_open(s, s->streams[i], fd, 0); av_strlcpy(contexts[i]->filename, url, sizeof(contexts[i]->filename)); } ff_url_join(url, sizeof(url), "udp", NULL, announce_addr, port, "?ttl=%d&connect=1", ttl); ret = ffurl_open(&sap->ann_fd, url, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); if (ret) { ret = AVERROR(EIO); goto fail; } udp_fd = ffurl_get_file_handle(sap->ann_fd); if (getsockname(udp_fd, (struct sockaddr*) &localaddr, &addrlen)) { ret = AVERROR(EIO); goto fail; } if (localaddr.ss_family != AF_INET #if HAVE_STRUCT_SOCKADDR_IN6 && localaddr.ss_family != AF_INET6 #endif ) { av_log(s, AV_LOG_ERROR, "Unsupported protocol family\n"); ret = AVERROR(EIO); goto fail; } sap->ann_size = 8192; sap->ann = av_mallocz(sap->ann_size); if (!sap->ann) { ret = AVERROR(EIO); goto fail; } sap->ann[pos] = (1 << 5); #if HAVE_STRUCT_SOCKADDR_IN6 if (localaddr.ss_family == AF_INET6) sap->ann[pos] |= 0x10; #endif pos++; sap->ann[pos++] = 0; /* Authentication length */ AV_WB16(&sap->ann[pos], av_get_random_seed()); pos += 2; if (localaddr.ss_family == AF_INET) { memcpy(&sap->ann[pos], &((struct sockaddr_in*)&localaddr)->sin_addr, sizeof(struct in_addr)); pos += sizeof(struct in_addr); #if HAVE_STRUCT_SOCKADDR_IN6 } else { memcpy(&sap->ann[pos], &((struct sockaddr_in6*)&localaddr)->sin6_addr, sizeof(struct in6_addr)); pos += sizeof(struct in6_addr); #endif } av_strlcpy(&sap->ann[pos], "application/sdp", sap->ann_size - pos); pos += strlen(&sap->ann[pos]) + 1; if (av_sdp_create(contexts, s->nb_streams, &sap->ann[pos], sap->ann_size - pos)) { ret = AVERROR_INVALIDDATA; goto fail; } av_freep(&contexts); av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", &sap->ann[pos]); pos += strlen(&sap->ann[pos]); sap->ann_size = pos; if (sap->ann_size > sap->ann_fd->max_packet_size) { av_log(s, AV_LOG_ERROR, "Announcement too large to send in one " "packet\n"); goto fail; } return 0; fail: av_free(contexts); sap_write_close(s); return ret; }
static int m3u_format_parser(struct list_mgt *mgt,ByteIOContext *s) { unsigned char line[1024]; int ret; unsigned char *p; int getnum=0; struct list_item tmpitem; char prefix[1024]=""; char prefixex[1024]=""; int prefix_len=0,prefixex_len=0; double start_time=mgt->full_time; char *oprefix=mgt->location!=NULL?mgt->location:mgt->filename; if(NULL!=mgt->prefix) { av_free(mgt->prefix); mgt->prefix = NULL; } if(oprefix) { mgt->prefix = strdup(oprefix); char *tail,*tailex,*extoptions; extoptions=strchr(oprefix,'?');/*ext options is start with ? ,we don't need in nested*/ if(is_NET_URL(oprefix)) { tail=strchr(oprefix+10,'/');/*skip Http:// and shttp:,and to first '/'*/ if(!extoptions)// no ? tailex=strrchr(oprefix+10,'/');/*skip Http:// and shttp:,start to last '/'*/ else tailex=memrchr(oprefix+10,'/',extoptions-oprefix-10);/*skip Http:// and shttp:,start to last '/',between http-->? */ } else { tail=strchr(oprefix,'/'); /*first '/'*/ if(!extoptions)//no ? tailex=strrchr(oprefix,'/'); /*to last '/' */ else tailex=memrchr(oprefix+10,'/',extoptions-oprefix-10);/*skip Http:// and shttp:,start to last '/',between http-->? */ } if(tail!=NULL) { prefix_len=tail-oprefix+1;/*left '/'..*/ memcpy(prefix,oprefix,prefix_len); prefix[prefix_len]='\0'; } if(tailex!=NULL) { prefixex_len=tailex-oprefix+1;/*left '/'..*/ memcpy(prefixex,oprefix,prefixex_len); prefixex[prefixex_len]='\0'; } } memset(&tmpitem,0,sizeof(tmpitem)); tmpitem.seq=-1; av_log(NULL, AV_LOG_INFO, "m3u_format_parser get prefix=%s\n",prefix); av_log(NULL, AV_LOG_INFO, "m3u_format_parser get prefixex=%s\n",prefixex); #if 0 if(mgt->n_variants>0) { free_variant_list(mgt); } #endif while(m3u_format_get_line(s,line,1024)>=0) { if (url_interrupt_cb()) { return -1; } tmpitem.ktype = KEY_NONE; ret = m3u_parser_line(mgt,line,&tmpitem); if(ret>0) { struct list_item*item; int need_prefix=0; int size_file=tmpitem.file?(strlen(tmpitem.file)+32):4; tmpitem.start_time=start_time; if(tmpitem.file && (is_NET_URL(prefix)) && /*net protocal*/ !(is_NET_URL(tmpitem.file)))/*if item is not net protocal*/ { /*if m3u is http,item is not http,add prefix*/ need_prefix=1; size_file+=prefixex_len; } item=av_malloc(sizeof(struct list_item)+size_file); if(!item) return AVERROR(ENOMEM); memcpy(item,&tmpitem,sizeof(tmpitem)); item->file=NULL; if(tmpitem.file) { item->file=&item[1]; if(need_prefix) { if(tmpitem.file[0]=='/') { /*has '/',not need the dir */ strcpy(item->file,prefix); strcpy(item->file+prefix_len,tmpitem.file+1);/*don't copy two '/',we have left before*/ } else { /*no '/', some I save the full path frefix*/ if(!strncmp(prefixex,"shttps://",9)) { strcpy(item->file,"http"); strcpy(item->file+4,prefixex+6); strcpy(item->file+4+prefixex_len -6,tmpitem.file); } else { strcpy(item->file,prefixex); strcpy(item->file+prefixex_len,tmpitem.file); } } } else { strcpy(item->file,tmpitem.file); } } if(mgt->flags&KEY_FLAG&&NULL!= mgt->key_tmp&&mgt->key_tmp->is_have_key_file>0) { item->key_ctx = av_mallocz(sizeof(struct AES128KeyContext)); if(!item->key_ctx) { ret = AVERROR(ENOMEM); break; } memcpy(item->key_ctx->key,mgt->key_tmp->key,sizeof(item->key_ctx->key)); if(mgt->has_iv>0) { memcpy(item->key_ctx->iv,mgt->key_tmp->iv,sizeof(item->key_ctx->iv)); } else { //from applehttp.c av_log(NULL,AV_LOG_INFO,"Current item seq number:%d\n",item->seq); AV_WB32(item->key_ctx->iv + 12, item->seq); } item->ktype = mgt->key_tmp->key_type; } if(mgt->next_seq>=0 && item->seq<0) { item->seq=mgt->next_seq; mgt->next_seq++; } if(!(tmpitem.flags&INVALID_ITEM_FLAG)) { ret =list_test_and_add_item(mgt,item); if(ret==0) { getnum++; start_time+=item->duration; } else { av_free(item); mgt->next_seq--; } } if((item->flags &ENDLIST_FLAG) && (item->flags < (1<<12))) { mgt->have_list_end=1; break; } memset(&tmpitem,0,sizeof(tmpitem)); tmpitem.seq=-1; } else if(ret <0) { if(ret ==-(TRICK_LOGIC_BASE+0)&&(mgt->flags&KEY_FLAG)&&NULL!= mgt->key_tmp&&0==mgt->key_tmp->is_have_key_file) { //get key from server URLContext *uc; if (ffurl_open(&uc, mgt->key_tmp->key_from, AVIO_FLAG_READ) == 0) { if (ffurl_read_complete(uc, mgt->key_tmp->key, sizeof(mgt->key_tmp->key)) != sizeof(mgt->key_tmp->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", mgt->key_tmp->key_from); } av_log(NULL,AV_LOG_INFO,"Just get aes key file from server\n"); mgt->key_tmp->is_have_key_file = 1; ffurl_close(uc); } else { av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", mgt->key_tmp->key_from); } memset(&tmpitem,0,sizeof(tmpitem)); continue; } if(ret ==-(TRICK_LOGIC_BASE+1)||ret ==-(TRICK_LOGIC_BASE+2)) { memset(&tmpitem,0,sizeof(tmpitem)); continue; } break; } else { if(tmpitem.flags&ALLOW_CACHE_FLAG) mgt->flags|=ALLOW_CACHE_FLAG; if(tmpitem.flags&INVALID_ITEM_FLAG) { av_log(NULL,AV_LOG_INFO,"just a trick,drop this item,seq number:%d\n",tmpitem.seq); continue; } } } if(mgt->key_tmp) { av_free(mgt->key_tmp); mgt->key_tmp = NULL; } mgt->file_size=AVERROR_STREAM_SIZE_NOTVALID; mgt->full_time=start_time; mgt->last_load_time = av_gettime(); av_log(NULL, AV_LOG_INFO, "m3u_format_parser end num =%d,fulltime=%.4lf\n",getnum,start_time); return getnum; }
static int sap_read_header(AVFormatContext *s) { struct SAPState *sap = s->priv_data; char host[1024], path[1024], url[1024]; uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; int port; int ret, i; AVInputFormat* infmt; if (!ff_network_init()) return AVERROR(EIO); av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), s->filename); if (port < 0) port = 9875; if (!host[0]) { /* Listen for announcements on sap.mcast.net if no host was specified */ av_strlcpy(host, "224.2.127.254", sizeof(host)); } ff_url_join(url, sizeof(url), "udp", NULL, host, port, "?localport=%d", port); ret = ffurl_open(&sap->ann_fd, url, AVIO_FLAG_READ, &s->interrupt_callback, NULL); if (ret) goto fail; while (1) { int addr_type, auth_len; int pos; ret = ffurl_read(sap->ann_fd, recvbuf, sizeof(recvbuf) - 1); if (ret == AVERROR(EAGAIN)) continue; if (ret < 0) goto fail; recvbuf[ret] = '\0'; /* Null terminate for easier parsing */ if (ret < 8) { av_log(s, AV_LOG_WARNING, "Received too short packet\n"); continue; } if ((recvbuf[0] & 0xe0) != 0x20) { av_log(s, AV_LOG_WARNING, "Unsupported SAP version packet " "received\n"); continue; } if (recvbuf[0] & 0x04) { av_log(s, AV_LOG_WARNING, "Received stream deletion " "announcement\n"); continue; } addr_type = recvbuf[0] & 0x10; auth_len = recvbuf[1]; sap->hash = AV_RB16(&recvbuf[2]); pos = 4; if (addr_type) pos += 16; /* IPv6 */ else pos += 4; /* IPv4 */ pos += auth_len * 4; if (pos + 4 >= ret) { av_log(s, AV_LOG_WARNING, "Received too short packet\n"); continue; } #define MIME "application/sdp" if (strcmp(&recvbuf[pos], MIME) == 0) { pos += strlen(MIME) + 1; } else if (strncmp(&recvbuf[pos], "v=0\r\n", 5) == 0) { // Direct SDP without a mime type } else { av_log(s, AV_LOG_WARNING, "Unsupported mime type %s\n", &recvbuf[pos]); continue; } sap->sdp = av_strdup(&recvbuf[pos]); break; } av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sap->sdp); ffio_init_context(&sap->sdp_pb, sap->sdp, strlen(sap->sdp), 0, NULL, NULL, NULL, NULL); infmt = av_find_input_format("sdp"); if (!infmt) goto fail; sap->sdp_ctx = avformat_alloc_context(); if (!sap->sdp_ctx) { ret = AVERROR(ENOMEM); goto fail; } sap->sdp_ctx->max_delay = s->max_delay; sap->sdp_ctx->pb = &sap->sdp_pb; sap->sdp_ctx->interrupt_callback = s->interrupt_callback; ret = avformat_open_input(&sap->sdp_ctx, "temp.sdp", infmt, NULL); if (ret < 0) goto fail; if (sap->sdp_ctx->ctx_flags & AVFMTCTX_NOHEADER) s->ctx_flags |= AVFMTCTX_NOHEADER; for (i = 0; i < sap->sdp_ctx->nb_streams; i++) { AVStream *st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avcodec_copy_context(st->codec, sap->sdp_ctx->streams[i]->codec); st->time_base = sap->sdp_ctx->streams[i]->time_base; } return 0; fail: sap_read_close(s); return ret; }