* Multiple format streaming server
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define HAVE_AV_CONFIG_H
#include "avformat.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
+#endif
#include <errno.h>
#include <sys/time.h>
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
-#ifdef CONFIG_HAVE_DLFCN
+#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
+#include "version.h"
#include "ffserver.h"
+#include "random.h"
/* maximum number of simultaneous HTTP connections */
#define HTTP_MAX_CONNECTIONS 2000
typedef struct {
int64_t count1, count2;
- long time1, time2;
+ int64_t time1, time2;
} DataRateData;
/* context associated with one connection */
int fd; /* socket file descriptor */
struct sockaddr_in from_addr; /* origin */
struct pollfd *poll_entry; /* used when polling */
- long timeout;
+ int64_t timeout;
uint8_t *buffer_ptr, *buffer_end;
int http_error;
int post;
int feed_fd;
/* input format handling */
AVFormatContext *fmt_in;
- long start_time; /* In milliseconds - this wraps fairly often */
+ int64_t start_time; /* In milliseconds - this wraps fairly often */
int64_t first_pts; /* initial pts value */
int64_t cur_pts; /* current pts value from the stream in us */
int64_t cur_frame_duration; /* duration of the current frame in us */
IPAddressACL *acl;
int nb_streams;
int prebuffer; /* Number of millseconds early to start */
- long max_time; /* Number of milliseconds to run */
+ int64_t max_time; /* Number of milliseconds to run */
int send_on_key;
AVStream *streams[MAX_STREAMS];
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
struct sockaddr_in my_http_addr;
struct sockaddr_in my_rtsp_addr;
-char logfilename[1024];
-HTTPContext *first_http_ctx;
-FFStream *first_feed; /* contains only feeds */
-FFStream *first_stream; /* contains all streams, including feeds */
+static char logfilename[1024];
+static HTTPContext *first_http_ctx;
+static FFStream *first_feed; /* contains only feeds */
+static FFStream *first_stream; /* contains all streams, including feeds */
static void new_connection(int server_fd, int is_rtsp);
static void close_connection(HTTPContext *c);
static int no_launch;
static int need_to_start_children;
-int nb_max_connections;
-int nb_connections;
+static int nb_max_connections;
+static int nb_connections;
-int max_bandwidth;
-int current_bandwidth;
+static int max_bandwidth;
+static int current_bandwidth;
-static long cur_time; // Making this global saves on passing it around everywhere
+static int64_t cur_time; // Making this global saves on passing it around everywhere
-static long gettime_ms(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv,NULL);
- return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
-}
+static AVRandomState random_state;
static FILE *logfile = NULL;
return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
}
-static int get_longterm_datarate(DataRateData *drd, int64_t count)
-{
- /* You get the first 3 seconds flat out */
- if (cur_time - drd->time1 < 3000)
- return 0;
- return compute_datarate(drd, count);
-}
-
static void start_children(FFStream *feed)
{
char bindmsg[32];
snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
perror (bindmsg);
- close(server_fd);
+ closesocket(server_fd);
return -1;
}
if (listen (server_fd, 5) < 0) {
perror ("listen");
- close(server_fd);
+ closesocket(server_fd);
return -1;
}
fcntl(server_fd, F_SETFL, O_NONBLOCK);
for(stream = first_stream; stream != NULL; stream = stream->next) {
if (stream->is_multicast) {
/* open the RTP connection */
- snprintf(session_id, sizeof(session_id),
- "%08x%08x", (int)random(), (int)random());
+ snprintf(session_id, sizeof(session_id), "%08x%08x",
+ av_random(&random_state), av_random(&random_state));
/* choose a port if none given */
if (stream->multicast_port == 0) {
return -1;
} while (ret <= 0);
- cur_time = gettime_ms();
+ cur_time = av_gettime() / 1000;
if (need_to_start_children) {
need_to_start_children = 0;
av_free(c->buffer);
av_free(c);
}
- close(fd);
+ closesocket(fd);
}
static void close_connection(HTTPContext *c)
/* remove connection associated resources */
if (c->fd >= 0)
- close(c->fd);
+ closesocket(c->fd);
if (c->fmt_in) {
/* close each frame parser */
for(i=0;i<c->fmt_in->nb_streams;i++) {
if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
current_bandwidth -= c->stream->bandwidth;
+
+ /* signal that there is no feed if we are the feeder socket */
+ if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
+ c->stream->feed_opened = 0;
+ close(c->feed_fd);
+ }
+
av_freep(&c->pb_buffer);
av_freep(&c->packet_buffer);
av_free(c->buffer);
return 0;
/* read the data */
read_loop:
- len = read(c->fd, c->buffer_ptr, 1);
+ len = recv(c->fd, c->buffer_ptr, 1, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR)
return -1;
/* no need to write if no events */
if (!(c->poll_entry->revents & POLLOUT))
return 0;
- len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
+ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR) {
/* error : close connection */
}
if (http_send_data(c) < 0)
return -1;
+ /* close connection if trailer sent */
+ if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
+ return -1;
break;
case HTTPSTATE_RECEIVE_DATA:
/* no need to read if no events */
/* no need to write if no events */
if (!(c->poll_entry->revents & POLLOUT))
return 0;
- len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
+ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR) {
/* error : close connection */
/* no need to write if no events */
if (!(c->poll_entry->revents & POLLOUT))
return 0;
- len = write(c->fd, c->packet_buffer_ptr,
- c->packet_buffer_end - c->packet_buffer_ptr);
+ len = send(c->fd, c->packet_buffer_ptr,
+ c->packet_buffer_end - c->packet_buffer_ptr, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR) {
/* error : close connection */
char *p;
enum RedirType redir_type;
char cmd[32];
- char info[1024], *filename;
+ char info[1024], filename[1024];
char url[1024], *q;
char protocol[32];
char msg[1024];
pstrcpy(c->protocol, sizeof(c->protocol), protocol);
if (ffserver_debug)
- http_log("New connection: %s %s\n", cmd, url);
+ http_log("New connection: %s %s\n", cmd, url);
/* find the filename and the optional info string in the request */
- p = url;
- if (*p == '/')
- p++;
- filename = p;
- p = strchr(p, '?');
+ p = strchr(url, '?');
if (p) {
pstrcpy(info, sizeof(info), p);
*p = '\0';
info[0] = '\0';
}
+ pstrcpy(filename, sizeof(filename)-1, url + ((*url == '/') ? 1 : 0));
+
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
if (strncasecmp(p, "User-Agent:", 11) == 0) {
useragent = p + 11;
strcpy(filename + strlen(filename)-2, "m");
} else if (match_ext(filename, "rtsp")) {
redir_type = REDIR_RTSP;
- compute_real_filename(filename, sizeof(url) - 1);
+ compute_real_filename(filename, sizeof(filename) - 1);
} else if (match_ext(filename, "sdp")) {
redir_type = REDIR_SDP;
- compute_real_filename(filename, sizeof(url) - 1);
+ compute_real_filename(filename, sizeof(filename) - 1);
}
+ // "redirect" / request to index.html
+ if (!strlen(filename))
+ pstrcpy(filename, sizeof(filename) - 1, "index.html");
+
stream = first_stream;
while (stream != NULL) {
if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
}
}
+ /* If already streaming this feed, dont let start an another feeder */
+ if (stream->feed_opened) {
+ snprintf(msg, sizeof(msg), "This feed is already being received.");
+ goto send_error;
+ }
+
if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
current_bandwidth += stream->bandwidth;
}
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "The server is too busy to serve your request at this time.<p>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
+ q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
+ q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
current_bandwidth, max_bandwidth);
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
if (!strcmp(c->stream->fmt->name,"asf_stream")) {
/* Need to allocate a client id */
- c->wmp_client_id = random() & 0x7fffffff;
+ c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
}
strcpy(eosf - 4, ".asx");
} else if (strcmp(eosf - 3, ".rm") == 0) {
strcpy(eosf - 3, ".ram");
- } else if (stream->fmt == &rtp_mux) {
+ } else if (stream->fmt == &rtp_muxer) {
/* generate a sample RTSP director if
unicast. Generate an SDP redirector if
multicast */
switch(st->codec->codec_type) {
case CODEC_TYPE_AUDIO:
type = "audio";
+ snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
break;
case CODEC_TYPE_VIDEO:
type = "video";
avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
avg /= enc->frame_size;
- url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n",
+ url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
buf, enc->frame_number, fdata->data_count, avg / 1000.0);
}
url_fprintf(pb, "</TABLE>\n");
#if 0
{ time_t when = stream_pos / 1000000;
- http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
+ http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
}
#endif
static int64_t get_server_clock(HTTPContext *c)
{
/* compute current pts value from system time */
- return (int64_t)(cur_time - c->start_time) * 1000LL;
+ return (cur_time - c->start_time) * 1000;
}
/* return the estimated time at which the current packet must be sent
c->fmt_ctx.nb_streams = c->stream->nb_streams;
for(i=0;i<c->fmt_ctx.nb_streams;i++) {
AVStream *st;
- AVStream *src;
+ AVStream *src;
st = av_mallocz(sizeof(AVStream));
st->codec= avcodec_alloc_context();
c->fmt_ctx.streams[i] = st;
else
src = c->stream->feed->streams[c->stream->feed_streams[i]];
- *st = *src;
- st->priv_data = 0;
+ *st = *src;
+ st->priv_data = 0;
st->codec->frame_number = 0; /* XXX: should be done in
AVStream, not in codec */
/* I'm pretty sure that this is not correct...
c->fmt_ctx.pb.is_streamed = 1;
av_set_parameters(&c->fmt_ctx, NULL);
- av_write_header(&c->fmt_ctx);
+ if (av_write_header(&c->fmt_ctx) < 0)
+ return -1;
len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
/* XXX: potential leak */
return -1;
}
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts,
+ c->fmt_in->streams[pkt.stream_index]->time_base,
+ ctx->streams[pkt.stream_index]->time_base);
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts,
+ c->fmt_in->streams[pkt.stream_index]->time_base,
+ ctx->streams[pkt.stream_index]->time_base);
if (av_write_frame(ctx, &pkt)) {
c->state = HTTPSTATE_SEND_DATA_TRAILER;
}
c->buffer_ptr += len;
/* send everything we can NOW */
- len = write(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
- rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr);
+ len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
+ rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
if (len > 0) {
rtsp_c->packet_buffer_ptr += len;
}
}
} else {
/* TCP data output */
- len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
+ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR) {
/* error : close connection */
if (c->buffer_end > c->buffer_ptr) {
int len;
- len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
+ len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR) {
/* error : close connection */
if header */
if (c->data_count > FFM_PACKET_SIZE) {
- // printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
+ // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
/* XXX: use llseek or url_seek */
lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
s.priv_data = av_mallocz(fmt_in->priv_data_size);
if (!s.priv_data)
goto fail;
- } else
- s.priv_data = NULL;
+ } else
+ s.priv_data = NULL;
if (fmt_in->read_header(&s, 0) < 0) {
av_freep(&s.priv_data);
path++;
for(stream = first_stream; stream != NULL; stream = stream->next) {
- if (!stream->is_feed && stream->fmt == &rtp_mux &&
+ if (!stream->is_feed && stream->fmt == &rtp_muxer &&
!strcmp(path, stream->filename)) {
goto found;
}
/* now check each stream */
for(stream = first_stream; stream != NULL; stream = stream->next) {
- if (!stream->is_feed && stream->fmt == &rtp_mux) {
+ if (!stream->is_feed && stream->fmt == &rtp_muxer) {
/* accept aggregate filenames only if single stream */
if (!strcmp(path, stream->filename)) {
if (stream->nb_streams != 1) {
/* generate session id if needed */
if (h->session_id[0] == '\0') {
- snprintf(h->session_id, sizeof(h->session_id),
- "%08x%08x", (int)random(), (int)random());
+ snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
+ av_random(&random_state), av_random(&random_state));
}
/* find rtp session, and create it if none found */
ctx = av_alloc_format_context();
if (!ctx)
return -1;
- ctx->oformat = &rtp_mux;
+ ctx->oformat = &rtp_muxer;
st = av_mallocz(sizeof(AVStream));
if (!st)
if (p[0] == 0x00 && p[1] == 0x00 &&
p[2] == 0x01 && p[3] == 0xb6) {
size = p - pkt.data;
- // av_hex_dump(pkt.data, size);
+ // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
st->codec->extradata = av_malloc(size);
st->codec->extradata_size = size;
memcpy(st->codec->extradata, pkt.data, size);
/* try to open the file */
/* open stream */
stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
- if (stream->fmt == &rtp_mux) {
+ if (stream->fmt == &rtp_muxer) {
/* specific case : if transport stream output to RTP,
we use a raw transport stream reader */
stream->ap_in->mpeg2ts_raw = 1;
s->streams[i] = st;
}
av_set_parameters(s, NULL);
- av_write_header(s);
+ if (av_write_header(s) < 0) {
+ fprintf(stderr, "Container doesn't supports the required parameters\n");
+ exit(1);
+ }
/* XXX: need better api */
av_freep(&s->priv_data);
url_fclose(&s->pb);
/* simplistic plugin support */
-#ifdef CONFIG_HAVE_DLOPEN
-void load_module(const char *filename)
+#ifdef HAVE_DLOPEN
+static void load_module(const char *filename)
{
void *dll;
void (*init_func)(void);
feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
- snprintf(feed->child_argv[i], 30+strlen(feed->filename),
- "http://%s:%d/%s",
- (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
- inet_ntoa(my_http_addr.sin_addr),
- ntohs(my_http_addr.sin_port), feed->filename);
-
- if (ffserver_debug)
- {
- int j;
- fprintf(stdout, "Launch commandline: ");
- for (j = 0; j <= i; j++)
- fprintf(stdout, "%s ", feed->child_argv[j]);
- fprintf(stdout, "\n");
- }
+ snprintf(feed->child_argv[i], 30+strlen(feed->filename),
+ "http://%s:%d/%s",
+ (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
+ inet_ntoa(my_http_addr.sin_addr),
+ ntohs(my_http_addr.sin_port), feed->filename);
+
+ if (ffserver_debug)
+ {
+ int j;
+ fprintf(stdout, "Launch commandline: ");
+ for (j = 0; j <= i; j++)
+ fprintf(stdout, "%s ", feed->child_argv[j]);
+ fprintf(stdout, "\n");
+ }
}
} else if (!strcasecmp(cmd, "ReadOnlyFile")) {
if (feed) {
if (stream) {
audio_enc.sample_rate = atoi(arg);
}
- } else if (!strcasecmp(cmd, "AudioQuality")) {
- get_arg(arg, sizeof(arg), &p);
+ } else if (!strcasecmp(cmd, "AudioQuality")) {
+ get_arg(arg, sizeof(arg), &p);
if (stream) {
// audio_enc.quality = atof(arg) * 1000;
}
video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
video_enc.flags |= CODEC_FLAG_4MV;
}
+ } else if (!strcasecmp(cmd, "VideoTag")) {
+ get_arg(arg, sizeof(arg), &p);
+ if ((strlen(arg) == 4) && stream) {
+ video_enc.codec_tag = ff_get_fourcc(arg);
+ }
+ } else if (!strcasecmp(cmd, "BitExact")) {
+ if (stream) {
+ video_enc.flags |= CODEC_FLAG_BITEXACT;
+ }
+ } else if (!strcasecmp(cmd, "DctFastint")) {
+ if (stream) {
+ video_enc.dct_algo = FF_DCT_FASTINT;
+ }
+ } else if (!strcasecmp(cmd, "IdctSimple")) {
+ if (stream) {
+ video_enc.idct_algo = FF_IDCT_SIMPLE;
+ }
+ } else if (!strcasecmp(cmd, "Qscale")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ video_enc.flags |= CODEC_FLAG_QSCALE;
+ video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
+ }
} else if (!strcasecmp(cmd, "VideoQDiff")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
redirect = NULL;
} else if (!strcasecmp(cmd, "LoadModule")) {
get_arg(arg, sizeof(arg), &p);
-#ifdef CONFIG_HAVE_DLOPEN
+#ifdef HAVE_DLOPEN
load_module(arg);
#else
fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
static void show_banner(void)
{
- printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
+ printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
}
static void show_help(void)
{
show_banner();
printf(
- "This library is free software; you can redistribute it and/or\n"
+ "FFmpeg is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU Lesser General Public\n"
"License as published by the Free Software Foundation; either\n"
- "version 2 of the License, or (at your option) any later version.\n"
+ "version 2.1 of the License, or (at your option) any later version.\n"
"\n"
- "This library is distributed in the hope that it will be useful,\n"
+ "FFmpeg is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
"Lesser General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU Lesser General Public\n"
- "License along with this library; if not, write to the Free Software\n"
- "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
+ "License along with FFmpeg; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
);
}
putenv("http_proxy"); /* Kill the http_proxy */
- srandom(gettime_ms() + (getpid() << 16));
+ av_init_random(av_gettime() + (getpid() << 16), &random_state);
/* address on which the server will handle HTTP connections */
my_http_addr.sin_family = AF_INET;