static int hls_read(URLContext *h, uint8_t *buf, int size) { HLSContext *s = h->priv_data; const char *url; int ret; int64_t reload_interval; 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++; } reload_interval = s->n_segments > 0 ? s->segments[s->n_segments - 1]->duration : s->target_duration; retry: if (!s->finished) { int64_t now = av_gettime_relative(); if (now - s->last_load_time >= reload_interval) { if ((ret = parse_playlist(h, s->playlisturl)) < 0) return ret; /* If we need to reload the playlist again below (if * there's still no more segments), switch to a reload * interval of half the target duration. */ reload_interval = s->target_duration / 2; } } 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_relative() - s->last_load_time < reload_interval) { if (ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; av_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_whitelist(&s->seg_hd, url, AVIO_FLAG_READ, &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h); 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; }
/* 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; int timeout = 100; 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; if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { timeout = strtol(buf, NULL, 10); } } 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(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; restart: ret = AVERROR(EIO); 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; ff_socket_nonblock(fd, 1); } else { redo: ff_socket_nonblock(fd, 1); ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); } if (ret < 0) { struct pollfd p = {fd, POLLOUT, 0}; ret = ff_neterrno(); if (ret == AVERROR(EINTR)) { if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail1; } goto redo; } if (ret != AVERROR(EINPROGRESS) && ret != AVERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ while(timeout--) { if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail1; } ret = poll(&p, 1, 100); if (ret > 0) break; } if (ret <= 0) { ret = AVERROR(ETIMEDOUT); goto fail; } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) { av_log(h, AV_LOG_ERROR, "TCP connection to %s:%d failed: %s\n", hostname, port, strerror(ret)); ret = AVERROR(ret); goto fail; } } s = av_malloc(sizeof(TCPContext)); if (!s) { freeaddrinfo(ai); return AVERROR(ENOMEM); } 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; } fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
static int read_data(void *opaque, uint8_t *buf, int buf_size) { struct variant *v = opaque; AppleHTTPContext *c = v->parent->priv_data; int ret, i; restart: if (!v->input) { reload: /* If this is a live stream and target_duration has elapsed since * the last playlist reload, reload the variant playlists now. */ if (!v->finished && av_gettime() - v->last_load_time >= v->target_duration*1000000 && (ret = parse_playlist(c, v->url, v, NULL)) < 0) return ret; if (v->cur_seq_no < v->start_seq_no) { av_log(NULL, AV_LOG_WARNING, "skipping %d segments ahead, expired from playlists\n", v->start_seq_no - v->cur_seq_no); v->cur_seq_no = v->start_seq_no; } if (v->cur_seq_no >= v->start_seq_no + v->n_segments) { if (v->finished) return AVERROR_EOF; while (av_gettime() - v->last_load_time < v->target_duration*1000000) { if (ff_check_interrupt(c->interrupt_callback)) return AVERROR_EXIT; usleep(100*1000); } /* Enough time has elapsed since the last reload */ goto reload; } ret = open_input(v); if (ret < 0) return ret; } ret = ffurl_read(v->input, buf, buf_size); if (ret > 0) return ret; if (ret < 0 && ret != AVERROR_EOF) return ret; ffurl_close(v->input); v->input = NULL; v->cur_seq_no++; c->end_of_segment = 1; c->cur_seq_no = v->cur_seq_no; if (v->ctx && v->ctx->nb_streams) { v->needed = 0; for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; i++) { if (v->parent->streams[i]->discard < AVDISCARD_ALL) v->needed = 1; } } if (!v->needed) { av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n", v->index); return AVERROR_EOF; } goto restart; }
static int read_data(void *opaque, uint8_t *buf, int buf_size) { #ifdef USED_LP_BUF URLContext *url=opaque; struct variant *v = url->priv_data; HLSContext *c = v->parent->priv_data; #else struct variant *v = opaque; HLSContext *c = v->parent->priv_data; #endif int ret, i; restart: if (!v->input) { /* If this is a live stream and the reload interval has elapsed since * the last playlist reload, reload the variant playlists now. */ int64_t reload_interval = v->n_segments > 0 ? v->segments[v->n_segments - 1]->duration : v->target_duration; reload_interval *= 1000000; reload: if (!v->finished && av_gettime() - v->last_load_time >= reload_interval) { if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) return ret; /* If we need to reload the playlist again below (if * there's still no more segments), switch to a reload * interval of half the target duration. */ reload_interval = v->target_duration * 500000; } if (v->cur_seq_no < v->start_seq_no) { av_log(NULL, AV_LOG_WARNING, "skipping %d segments ahead, expired from playlists\n", v->start_seq_no - v->cur_seq_no); v->cur_seq_no = v->start_seq_no; } if (v->cur_seq_no >= v->start_seq_no + v->n_segments) { if (v->finished) return AVERROR_EOF; while (av_gettime() - v->last_load_time < reload_interval) { #ifdef AVIO_OPEN2 if (ff_check_interrupt(c->interrupt_callback)) return AVERROR_EXIT; #else if (url_interrupt_cb()) return AVERROR_EXIT; #endif usleep(100*1000); } /* Enough time has elapsed since the last reload */ goto reload; } ret = open_input(v); if (ret < 0) return ret; } ret = ffurl_read(v->input, buf, buf_size); if (ret > 0) return ret; if (ret < 0 && ret != AVERROR_EOF) return ret; ffurl_close(v->input); v->input = NULL; v->cur_seq_no++; c->end_of_segment = 1; c->cur_seq_no = v->cur_seq_no; if (v->ctx && v->ctx->nb_streams) { v->needed = 0; for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; i++) { if (v->parent->streams[i]->discard < AVDISCARD_ALL) v->needed = 1; } } if (!v->needed) { av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n", v->index); return AVERROR_EOF; } goto restart; }
static void *circular_buffer_task( void *_URLContext) { URLContext *h = _URLContext; UDPContext *s = h->priv_data; fd_set rfds; struct timeval tv; for(;;) { int left; int ret; int len; if (ff_check_interrupt(&h->interrupt_callback)) { s->circular_buffer_error = EINTR; goto end; } FD_ZERO(&rfds); FD_SET(s->udp_fd, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); if (ret < 0) { if (ff_neterrno() == AVERROR(EINTR)) continue; s->circular_buffer_error = EIO; goto end; } if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) continue; /* How much do we have left to the end of the buffer */ /* Whats the minimum we can read so that we dont comletely fill the buffer */ left = av_fifo_space(s->fifo); /* No Space left, error, what do we do now */ if(left < UDP_MAX_PKT_SIZE + 4) { av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n"); s->circular_buffer_error = EIO; goto end; } left = FFMIN(left, s->fifo->end - s->fifo->wptr); len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0); if (len < 0) { if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) { s->circular_buffer_error = EIO; goto end; } continue; } AV_WL32(s->tmp, len); pthread_mutex_lock(&s->mutex); av_fifo_generic_write(s->fifo, s->tmp, len+4, NULL); pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->mutex); } end: pthread_mutex_lock(&s->mutex); pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->mutex); return NULL; }