static void rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) { char path[4096]; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } if(strcmp(ctx->session_id, h->session_id) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } // if(ctx->state != SERVER_STATE_READY && ctx->state != SERVER_STATE_PAUSE) { rtsp_reply_error(ctx, RTSP_STATUS_STATE); return; } // 2014-05-20: support only shared-encoder model if(ff_server_register_client(ctx) < 0) { ga_error("cannot register encoder client.\n"); rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL); return; } // ctx->state = SERVER_STATE_PLAYING; rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id); rtsp_printf(ctx, "\r\n"); return; }
static RTSPContext *find_rtp_session_with_url(const char *url, const char *session_id) { RTSPContext *rtp_c; char path1[1024]; const char *path; char buf[1024]; int s, len; rtp_c = find_rtp_session(session_id); if (!rtp_c) return NULL; /* find which URL is asked */ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); len = strlen(path1); if (path1[len-1] == '/') { path1[len-1] = '\0'; } path = path1; if (*path == '/') path++; if(!strcmp(path, rtp_c->stream->name)) return rtp_c; return NULL; }
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 void rtsp_cmd_describe(RTSPContext *ctx, const char *url) { struct sockaddr_in myaddr; #ifdef WIN32 int addrlen; #else socklen_t addrlen; #endif char path[4096]; char content[4096]; int content_length; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); if(strcmp(path, rtspconf->object) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SERVICE); return; } // addrlen = sizeof(myaddr); getsockname(ctx->fd, (struct sockaddr*) &myaddr, &addrlen); content_length = prepare_sdp_description(ctx, content, sizeof(content)); if(content_length < 0) { rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL); return; } // state does not change rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Content-Base: %s/\r\n", url); rtsp_printf(ctx, "Content-Type: application/sdp\r\n"); rtsp_printf(ctx, "Content-Length: %d\r\n", content_length); rtsp_printf(ctx, "\r\n"); rtsp_write(ctx, content, content_length); return; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * url syntax: udp://host:port[?option=val...] * option: 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size * 'reuse=1' : enable reusing the socket * * @param h media file context * @param uri of the remote server * @return zero if no error. */ int ff_udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256], buf[10]; int port; const char *p; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); if (s->dest_addr_len < 0) { return AVERROR(EIO); } s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr); p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { int was_connected = s->is_connected; s->is_connected = strtol(buf, NULL, 10); if (s->is_connected && !was_connected) { if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { s->is_connected = 0; av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); return AVERROR(EIO); } } } } return 0; }
int ff_rtp_set_remote_url(URLContext *h, const char *uri) { RTPContext *s = h->priv_data; char hostname[256]; int port, rtcp_port; const char *p; char buf[1024]; char path[1024]; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); rtcp_port = port + 1; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) { rtcp_port = strtol(buf, NULL, 10); } } ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path); ff_udp_set_remote_url(s->rtp_hd, buf); ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path); ff_udp_set_remote_url(s->rtcp_hd, buf); return 0; }
static void rtsp_cmd_pause(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) { char path[4096]; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } if(strcmp(ctx->session_id, h->session_id) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } // if(ctx->state != SERVER_STATE_PLAYING) { rtsp_reply_error(ctx, RTSP_STATUS_STATE); return; } // ctx->state = SERVER_STATE_PAUSE; rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id); rtsp_printf(ctx, "\r\n"); return; }
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; }
void ring_url_split(const char *url, char *hostname, size_t hostname_size, int *port, char *path, size_t path_size) { av_url_split(NULL, 0, NULL, 0, hostname, hostname_size, port, path, path_size, url); }
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 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 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 resetup_tcp(AVFormatContext *s) { RTSPState *rt = s->priv_data; char host[1024]; int port; av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, s->filename); ff_rtsp_undo_setup(s); return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP, rt->real_challenge); }
static void rtsp_cmd_describe(RTSPContext *c, const char *url) { iStream *stream; char path1[1024]; const char *path; uint8_t *content; int content_length = 0; socklen_t len; struct sockaddr_in my_addr; /* find which URL is asked */ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); int l = strlen(path1); if (path1[l-1] == '/') { path1[l-1] = '\0'; } path = path1; if (*path == '/') path++; for(stream = first_stream; stream != NULL; stream = stream->next) { if (!strcmp(path, stream->name)) { goto found; } } /* no stream found */ rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */ return; found: /* prepare the media description in SDP format */ content = av_mallocz(1024); /* get the host IP */ len = sizeof(my_addr); getsockname(c->fd, (struct sockaddr *)&my_addr, &len); rtsp_reply_header(c, RTSP_STATUS_OK); avio_printf(c->pb, "Content-Base: %s/\r\n", url); avio_printf(c->pb, "Content-Type: application/sdp\r\n"); int added_length = 0; // 여기에 sdp정보 추가 해야 함. content_length = generate_sdp_context(stream, &content); avio_printf(c->pb, "Content-Length: %d\r\n", content_length + added_length); avio_printf(c->pb, "\r\n"); // content added avio_write(c->pb, content, content_length + added_length); av_free(content); }
static void rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) { char path[4096]; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } if(strcmp(ctx->session_id, h->session_id) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } // if(ctx->state != SERVER_STATE_READY && ctx->state != SERVER_STATE_PAUSE) { rtsp_reply_error(ctx, RTSP_STATUS_STATE); return; } // create threads #ifndef SHARE_ENCODER if(pthread_create(&ctx->vthread, NULL, vencoder_thread, ctx) != 0) { ga_error("cannot create video thread\n"); rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL); return; } #ifdef ENABLE_AUDIO if(pthread_create(&ctx->athread, NULL, aencoder_thread, ctx) != 0) { ga_error("cannot create audio thread\n"); rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL); return; } #endif /* ENABLE_AUDIO */ #else if(encoder_register_client(ctx) < 0) { ga_error("cannot register encoder client.\n"); rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL); return; } #endif /* SHARE_ENCODER */ // ctx->state = SERVER_STATE_PLAYING; rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id); rtsp_printf(ctx, "\r\n"); return; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * url syntax: udp://host:port[?option=val...] * option: 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size * 'reuse=1' : enable reusing the socket * * @param h media file context * @param uri of the remote server * @return zero if no error. */ int udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256]; int port; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); if (s->dest_addr_len < 0) { return AVERROR(EIO); } s->is_multicast = is_multicast_address(&s->dest_addr); return 0; }
int ff_rtp_set_remote_url(URLContext *h, const char *uri) { RTPContext *s = h->priv_data; char hostname[256]; int port; char buf[1024]; char path[1024]; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path); ff_udp_set_remote_url(s->rtp_hd, buf); ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path); ff_udp_set_remote_url(s->rtcp_hd, buf); return 0; }
static void rtsp_cmd_teardown(RTSPContext *ctx, const char *url, RTSPMessageHeader *h, int bruteforce) { char path[4096]; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } if(strcmp(ctx->session_id, h->session_id) != 0) { rtsp_reply_error(ctx, RTSP_STATUS_SESSION); return; } // ctx->state = SERVER_STATE_TEARDOWN; if(bruteforce != 0) return; // XXX: well, gently response rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id); rtsp_printf(ctx, "\r\n"); return; }
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 icecast_open(URLContext *h, const char *uri, int flags) { IcecastContext *s = h->priv_data; // Dict to set options that we pass to the HTTP protocol AVDictionary *opt_dict = NULL; // URI part variables char h_url[1024], host[1024], auth[1024], path[1024]; char *headers = NULL, *user = NULL; int port, ret; AVBPrint bp; if (flags & AVIO_FLAG_READ) return AVERROR(ENOSYS); av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); // Build header strings cat_header(&bp, "Ice-Name", s->name); cat_header(&bp, "Ice-Description", s->description); cat_header(&bp, "Ice-URL", s->url); cat_header(&bp, "Ice-Genre", s->genre); cat_header(&bp, "Ice-Public", s->public ? "1" : "0"); if (!av_bprint_is_complete(&bp)) { ret = AVERROR(ENOMEM); goto cleanup; } av_bprint_finalize(&bp, &headers); // Set options av_dict_set(&opt_dict, "method", s->legacy_icecast ? "SOURCE" : "PUT", 0); av_dict_set(&opt_dict, "auth_type", "basic", 0); av_dict_set(&opt_dict, "headers", headers, 0); av_dict_set(&opt_dict, "chunked_post", "0", 0); av_dict_set(&opt_dict, "send_expect_100", s->legacy_icecast ? "0" : "1", 0); if (NOT_EMPTY(s->content_type)) av_dict_set(&opt_dict, "content_type", s->content_type, 0); else av_dict_set(&opt_dict, "content_type", "audio/mpeg", 0); if (NOT_EMPTY(s->user_agent)) av_dict_set(&opt_dict, "user_agent", s->user_agent, 0); // Parse URI av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port, path, sizeof(path), uri); // Check for auth data in URI if (auth[0]) { char *sep = strchr(auth, ':'); if (sep) { *sep = 0; sep++; if (s->pass) { av_free(s->pass); av_log(h, AV_LOG_WARNING, "Overwriting -password <pass> with URI password!\n"); } if (!(s->pass = av_strdup(sep))) { ret = AVERROR(ENOMEM); goto cleanup; } } if (!(user = av_strdup(auth))) { ret = AVERROR(ENOMEM); goto cleanup; } } // Build new authstring snprintf(auth, sizeof(auth), "%s:%s", user ? user : DEFAULT_ICE_USER, s->pass ? s->pass : ""); // Check for mountpoint (path) if (!path[0] || strcmp(path, "/") == 0) { av_log(h, AV_LOG_ERROR, "No mountpoint (path) specified!\n"); ret = AVERROR(EIO); goto cleanup; } // Build new URI for passing to http protocol ff_url_join(h_url, sizeof(h_url), "http", auth, host, port, "%s", path); // Finally open http proto handler ret = ffurl_open_whitelist(&s->hd, h_url, AVIO_FLAG_READ_WRITE, NULL, &opt_dict, h->protocol_whitelist, h->protocol_blacklist, h); cleanup: av_freep(&user); av_freep(&headers); av_dict_free(&opt_dict); return ret; }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; int len; int reuse_specified = 0; h->is_streamed = 1; h->max_packet_size = 1472; is_output = !(flags & AVIO_FLAG_READ); s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; s->circular_buffer_size = 7*188*4096; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr=NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; reuse_specified = 1; } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buf_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10)*188; } } /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitely disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (!(h->flags & AVIO_FLAG_READ)) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { /* input */ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { av_log(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { av_log(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); goto fail; } } s->udp_fd = udp_fd; #if 0 && HAVE_PTHREADS if (!is_output && s->circular_buffer_size) { /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) { av_log(h, AV_LOG_ERROR, "pthread_create failed\n"); goto fail; } } #endif return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_free(s->fifo); av_free(s); return AVERROR(EIO); }
static inline int parse_command_line(AVFormatContext *s, const char *line, int linelen, char *uri, int urisize, char *method, int methodsize, enum RTSPMethod *methodcode) { RTSPState *rt = s->priv_data; const char *linept, *searchlinept; linept = strchr(line, ' '); if (linept - line > methodsize - 1) { av_log(s, AV_LOG_ERROR, "Method string too long\n"); return AVERROR(EIO); } memcpy(method, line, linept - line); method[linept - line] = '\0'; linept++; if (!strcmp(method, "ANNOUNCE")) *methodcode = ANNOUNCE; else if (!strcmp(method, "OPTIONS")) *methodcode = OPTIONS; else if (!strcmp(method, "RECORD")) *methodcode = RECORD; else if (!strcmp(method, "SETUP")) *methodcode = SETUP; else if (!strcmp(method, "PAUSE")) *methodcode = PAUSE; else if (!strcmp(method, "TEARDOWN")) *methodcode = TEARDOWN; else *methodcode = UNKNOWN; /* Check method with the state */ if (rt->state == RTSP_STATE_IDLE) { if ((*methodcode != ANNOUNCE) && (*methodcode != OPTIONS)) { av_log(s, AV_LOG_ERROR, "Unexpected command in Idle State %s\n", line); return AVERROR_PROTOCOL_NOT_FOUND; } } else if (rt->state == RTSP_STATE_PAUSED) { if ((*methodcode != OPTIONS) && (*methodcode != RECORD) && (*methodcode != SETUP)) { av_log(s, AV_LOG_ERROR, "Unexpected command in Paused State %s\n", line); return AVERROR_PROTOCOL_NOT_FOUND; } } else if (rt->state == RTSP_STATE_STREAMING) { if ((*methodcode != PAUSE) && (*methodcode != OPTIONS) && (*methodcode != TEARDOWN)) { av_log(s, AV_LOG_ERROR, "Unexpected command in Streaming State" " %s\n", line); return AVERROR_PROTOCOL_NOT_FOUND; } } else { av_log(s, AV_LOG_ERROR, "Unexpected State [%d]\n", rt->state); return AVERROR_BUG; } searchlinept = strchr(linept, ' '); if (searchlinept == NULL) { av_log(s, AV_LOG_ERROR, "Error parsing message URI\n"); return AVERROR_INVALIDDATA; } if (searchlinept - linept > urisize - 1) { av_log(s, AV_LOG_ERROR, "uri string length exceeded buffer size\n"); return AVERROR(EIO); } memcpy(uri, linept, searchlinept - linept); uri[searchlinept - linept] = '\0'; if (strcmp(rt->control_uri, uri)) { char host[128], path[512], auth[128]; int port; char ctl_host[128], ctl_path[512], ctl_auth[128]; int ctl_port; av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port, path, sizeof(path), uri); av_url_split(NULL, 0, ctl_auth, sizeof(ctl_auth), ctl_host, sizeof(ctl_host), &ctl_port, ctl_path, sizeof(ctl_path), rt->control_uri); if (strcmp(host, ctl_host)) av_log(s, AV_LOG_INFO, "Host %s differs from expected %s\n", host, ctl_host); if (strcmp(path, ctl_path) && *methodcode != SETUP) av_log(s, AV_LOG_WARNING, "WARNING: Path %s differs from expected" " %s\n", path, ctl_path); if (*methodcode == ANNOUNCE) { av_log(s, AV_LOG_INFO, "Updating control URI to %s\n", uri); av_strlcpy(rt->control_uri, uri, sizeof(rt->control_uri)); } } linept = searchlinept + 1; if (!av_strstart(linept, "RTSP/1.0", NULL)) { av_log(s, AV_LOG_ERROR, "Error parsing protocol or version\n"); return AVERROR_PROTOCOL_NOT_FOUND; } return 0; }
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; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints = { 0 }, *ai, *cur_ai; int port, fd = -1; TCPContext *s = h->priv_data; int listen_socket = 0; const char *p; char buf[256]; int ret; int timeout = 100, listen_timeout = -1; char hostname[1024],proto[1024],path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto, "tcp")) return AVERROR(EINVAL); if (port <= 0 || port >= 65536) { av_log(h, AV_LOG_ERROR, "Port missing in uri\n"); return AVERROR(EINVAL); } p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { timeout = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { listen_timeout = strtol(buf, NULL, 10); } } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); if (listen_socket) hints.ai_flags |= AI_PASSIVE; if (!hostname[0]) ret = getaddrinfo(NULL, portstr, &hints, &ai); else ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; restart: fd = ff_socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) { ret = ff_neterrno(); goto fail; } if (listen_socket) { if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, listen_timeout, h)) < 0) { ret = fd; goto fail1; } } else { if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, timeout * 100, h, !!cur_ai->ai_next)) < 0) { if (ret == AVERROR_EXIT) goto fail1; else goto fail; } } h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); ret = 0; goto restart; } fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints, *ai, *cur_ai; int port, fd = -1; TCPContext *s = NULL; int listen_socket = 0; const char *p; char buf[256]; int ret; socklen_t optlen; char hostname[1024],proto[1024],path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(NULL, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; restart: fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) goto fail; if (listen_socket) { int fd1; ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); listen(fd, 1); fd1 = accept(fd, NULL, NULL); closesocket(fd); fd = fd1; } else { redo: ff_socket_nonblock(fd, 1); //av_log (NULL, AV_LOG_INFO, "connecting....\n"); ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); //av_log (NULL, AV_LOG_INFO, "connecting done.\n"); } if (ret < 0) { int timeout = 10; //1s timeout struct pollfd p = {fd, POLLOUT, 0}; if (ff_neterrno() == AVERROR(EINTR)) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } goto redo; } if (ff_neterrno() != AVERROR(EINPROGRESS) && ff_neterrno() != AVERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } ret = poll(&p, 1, 100); if (ret > 0) break; if(!--timeout){ av_log(NULL, AV_LOG_ERROR, "TCP open %s:%d timeout\n", hostname, port); goto fail; } } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "TCP connection to %s:%d failed: %s\n", hostname, port, strerror(ret)); goto fail; } } s = av_malloc(sizeof(TCPContext)); if (!s) { ret = AVERROR(ENOMEM); goto fail1; } h->priv_data = s; h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); goto restart; } ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
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; }
static int mmsh_open(URLContext *h, const char *uri, int flags) { int i, port, err; char httpname[256], path[256], host[128], location[1024]; char *stream_selection = NULL; char headers[1024]; MMSHContext *mmsh; MMSContext *mms; mmsh = h->priv_data = av_mallocz(sizeof(MMSHContext)); if (!h->priv_data) return AVERROR(ENOMEM); mmsh->request_seq = h->is_streamed = 1; mms = &mmsh->mms; av_strlcpy(location, uri, sizeof(location)); av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), location); if (port<0) port = 80; // default mmsh protocol port ff_url_join(httpname, sizeof(httpname), "http", NULL, host, port, path); if (url_alloc(&mms->mms_hd, httpname, URL_RDONLY) < 0) { return AVERROR(EIO); } snprintf(headers, sizeof(headers), "Accept: */*\r\n" USERAGENT "Host: %s:%d\r\n" "Pragma: no-cache,rate=1.000000,stream-time=0," "stream-offset=0:0,request-context=%u,max-duration=0\r\n" CLIENTGUID "Connection: Close\r\n\r\n", host, port, mmsh->request_seq++); ff_http_set_headers(mms->mms_hd, headers); err = url_connect(mms->mms_hd); if (err) { goto fail; } err = get_http_header_data(mmsh); if (err) { av_log(NULL, AV_LOG_ERROR, "Get http header data failed!\n"); goto fail; } // close the socket and then reopen it for sending the second play request. url_close(mms->mms_hd); memset(headers, 0, sizeof(headers)); if (url_alloc(&mms->mms_hd, httpname, URL_RDONLY) < 0) { return AVERROR(EIO); } stream_selection = av_mallocz(mms->stream_num * 19 + 1); if (!stream_selection) return AVERROR(ENOMEM); for (i = 0; i < mms->stream_num; i++) { char tmp[20]; err = snprintf(tmp, sizeof(tmp), "ffff:%d:0 ", mms->streams[i].id); if (err < 0) goto fail; av_strlcat(stream_selection, tmp, mms->stream_num * 19 + 1); } // send play request err = snprintf(headers, sizeof(headers), "Accept: */*\r\n" USERAGENT "Host: %s:%d\r\n" "Pragma: no-cache,rate=1.000000,request-context=%u\r\n" "Pragma: xPlayStrm=1\r\n" CLIENTGUID "Pragma: stream-switch-count=%d\r\n" "Pragma: stream-switch-entry=%s\r\n" "Connection: Close\r\n\r\n", host, port, mmsh->request_seq++, mms->stream_num, stream_selection); av_freep(&stream_selection); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "Build play request failed!\n"); goto fail; } av_dlog(NULL, "out_buffer is %s", headers); ff_http_set_headers(mms->mms_hd, headers); err = url_connect(mms->mms_hd); if (err) { goto fail; } err = get_http_header_data(mmsh); if (err) { av_log(NULL, AV_LOG_ERROR, "Get http header data failed!\n"); goto fail; } av_dlog(NULL, "Connection successfully open\n"); return 0; fail: av_freep(&stream_selection); mmsh_close(h); av_dlog(NULL, "Connection failed with error %d\n", err); return err; }
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); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1, dscp = -1; UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; socklen_t len; int i, num_include_sources = 0, num_exclude_sources = 0; char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; is_output = !(flags & AVIO_FLAG_READ); if (s->buffer_size < 0) s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; if (s->sources) { if (parse_source_list(s->sources, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (s->block) { if (parse_source_list(s->block, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (s->pkt_size > 0) h->max_packet_size = s->pkt_size; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; } if (av_find_info_tag(buf, sizeof(buf), "overrun_nonfatal", p)) { char *endptr = NULL; s->overrun_nonfatal = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->overrun_nonfatal = 1; if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'overrun_nonfatal' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "udplite_coverage", p)) { s->udplite_coverage = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { s->pkt_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) { dscp = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10); if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'circular_buffer_size' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { if (parse_source_list(buf, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { if (parse_source_list(buf, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) s->timeout = strtol(buf, NULL, 10); if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p)) s->is_broadcast = strtol(buf, NULL, 10); } /* handling needed to support options picking from both AVOption and URL */ s->circular_buffer_size *= 188; if (flags & AVIO_FLAG_WRITE) { h->max_packet_size = s->pkt_size; } else { h->max_packet_size = UDP_MAX_PKT_SIZE; } h->rw_timeout = s->timeout; /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if ((s->is_multicast || s->local_port <= 0) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; if (localaddr[0]) udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); else udp_fd = udp_socket_create(s, &my_addr, &len, s->localaddr); if (udp_fd < 0) goto fail; s->local_addr_storage=my_addr; //store for future multicast join /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ if (s->reuse_socket > 0 || (s->is_multicast && s->reuse_socket < 0)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } if (s->is_broadcast) { #ifdef SO_BROADCAST if (setsockopt (udp_fd, SOL_SOCKET, SO_BROADCAST, &(s->is_broadcast), sizeof(s->is_broadcast)) != 0) #endif goto fail; } /* Set the checksum coverage for UDP-Lite (RFC 3828) for sending and receiving. * The receiver coverage has to be less than or equal to the sender coverage. * Otherwise, the receiver will drop all packets. */ if (s->udplite_coverage) { if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_SEND_CSCOV not available"); if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_RECV_CSCOV not available"); } if (dscp >= 0) { dscp <<= 2; if (setsockopt (udp_fd, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) != 0) goto fail; } /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address * using sendto() fail, so only do it if we're opened in read-only mode. */ if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { log_net_error(h, AV_LOG_ERROR, "bind failed"); goto fail; } len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & AVIO_FLAG_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (h->flags & AVIO_FLAG_READ) { /* input */ if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; } if (num_include_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) goto fail; } if (num_exclude_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0) goto fail; } } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); goto fail; } } else { /* set udp recv buffer size to the requested value (default 64K) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } len = sizeof(tmp); if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); } else { av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp); if(tmp < s->buffer_size) av_log(h, AV_LOG_WARNING, "attempted to set receive buffer to size %d but it only ended up set as %d", s->buffer_size, tmp); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; #if HAVE_PTHREAD_CANCEL if (!is_output && s->circular_buffer_size) { int ret; /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); ret = pthread_mutex_init(&s->mutex, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", strerror(ret)); goto fail; } ret = pthread_cond_init(&s->cond, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", strerror(ret)); goto cond_fail; } ret = pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret)); goto thread_fail; } s->thread_started = 1; } #endif return 0; #if HAVE_PTHREAD_CANCEL thread_fail: pthread_cond_destroy(&s->cond); cond_fail: pthread_mutex_destroy(&s->mutex); #endif fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_freep(&s->fifo); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); return AVERROR(EIO); }