typedef struct { int udp_fd; int ttl; int buffer_size; int is_multicast; /*Added by Anderson, Fixed udp multicast*/ int b_localaddr_flag; char local_addr[20]; /*end*/
int local_port; int reuse_socket; struct sockaddr_storage dest_addr; int dest_addr_len; int is_connected;
/* Circular Buffer variables for use in UDP receive code */ int circular_buffer_size; AVFifoBuffer *fifo; int circular_buffer_error; #if HAVE_PTHREADS pthread_t circular_buffer_thread; #endif } UDPContext;
typedef struct URLContext { int flags; int is_streamed; /**< true if streamed (no seek possible), default = false */ int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ void *priv_data; int is_connected; } URLContext;
static int default_interrupt_cb(void); int (*url_interrupt_cb)(void) = default_interrupt_cb;
int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port); int ff_is_multicast_address(struct sockaddr *addr);
/** * 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;
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); left = FFMIN(left, s->fifo->end - s->fifo->wptr);
/* No Space left, error, what do we do now */ if( !left) { //av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n"); fprintf(stderr, "circular_buffer: OVERRUN\n"); s->circular_buffer_error = EIO; return NULL; }
/** Discard data from the FIFO. */ void av_fifo_drain(AVFifoBuffer *f, int size) { f->rptr += size; if (f->rptr >= f->end) f->rptr -= f->end - f->buffer; f->rndx += size; }
int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)) { // Read memory barrier needed for SMP here in theory do { int len = FFMIN(f->end - f->rptr, buf_size);
if(func) { func(dest, f->rptr, len); } else { memcpy(dest, f->rptr, len); dest = (uint8_t*)dest + len; } // memory barrier needed for SMP here in theory av_fifo_drain(f, len); buf_size -= len; } while (buf_size > 0);
return 0; }
int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; int ret; int avail; fd_set rfds; struct timeval tv;
if (s->fifo) { do { avail = av_fifo_size(s->fifo); if (avail) { // >=size) { // Maximum amount available size = FFMIN( avail, size); av_fifo_generic_read(s->fifo, buf, size, NULL); return size; } else { 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) return ret; } } while( 1); }
return 0; }
int udp_leave_multicast_group(int sockfd, struct sockaddr *addr, int b_localaddr, char *pc_local_addr) { if (addr->sa_family == AF_INET) { struct ip_mreq mreq;
/* 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)) 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); }
if (s->is_multicast) { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr, s->b_localaddr_flag, s->local_addr) < 0) goto fail; }
/* 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)); fprintf(stderr, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ //ff_socket_nonblock(udp_fd, 1); fcntl(udp_fd, F_SETFL, fcntl(udp_fd, F_GETFL) | O_NONBLOCK);
s->udp_fd = udp_fd;
#if HAVE_PTHREADS if (!is_output && s->circular_buffer_size) { /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size);