* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define _XOPEN_SOURCE 600
+
#include "config.h"
-#ifndef HAVE_CLOSESOCKET
+#if !HAVE_CLOSESOCKET
#define closesocket close
#endif
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
-#include "libavutil/random.h"
-#include "libavutil/avstring.h"
+/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
#include "libavformat/avformat.h"
#include "libavformat/network.h"
#include "libavformat/os_support.h"
#include "libavformat/rtp.h"
#include "libavformat/rtsp.h"
+#include "libavutil/avstring.h"
+#include "libavutil/random.h"
+#include "libavutil/intreadwrite.h"
#include "libavcodec/opt.h"
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#ifdef HAVE_POLL_H
+#if HAVE_POLL_H
#include <poll.h>
#endif
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#include <signal.h>
-#ifdef HAVE_DLFCN_H
+#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif
static const OptionDef options[];
-/* maximum number of simultaneous HTTP connections */
-#define HTTP_MAX_CONNECTIONS 2000
-
enum HTTPState {
HTTPSTATE_WAIT_REQUEST,
HTTPSTATE_SEND_HEADER,
int seq; /* RTSP sequence number */
/* RTP state specific */
- enum RTSPProtocol rtp_protocol;
+ enum RTSPLowerTransport rtp_protocol;
char session_id[32]; /* session id */
AVFormatContext *rtp_ctx[MAX_STREAMS];
/* RTP handling */
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
FFStream *stream, const char *session_id,
- enum RTSPProtocol rtp_protocol);
+ enum RTSPLowerTransport rtp_protocol);
static int rtp_new_av_stream(HTTPContext *c,
int stream_index, struct sockaddr_in *dest_addr,
HTTPContext *rtsp_c);
static int no_launch;
static int need_to_start_children;
-static int nb_max_connections = 5;
-static int nb_connections;
+/* maximum number of simultaneous HTTP connections */
+static unsigned int nb_max_http_connections = 2000;
+static unsigned int nb_max_connections = 5;
+static unsigned int nb_connections;
static uint64_t max_bandwidth = 1000;
static uint64_t current_bandwidth;
if (level > av_log_level)
return;
if (print_prefix && avc)
- http_log("[%s @ %p]", avc->item_name(ptr), avc);
+ http_log("[%s @ %p]", avc->item_name(ptr), ptr);
print_prefix = strstr(fmt, "\n") != NULL;
http_vlog(fmt, vargs);
}
char *slash;
int i;
+ av_strlcpy(pathname, my_program_name, sizeof(pathname));
+
+ slash = strrchr(pathname, '/');
+ if (!slash)
+ slash = pathname;
+ else
+ slash++;
+ strcpy(slash, "ffmpeg");
+
+ http_log("Launch commandline: ");
+ http_log("%s ", pathname);
+ for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
+ http_log("%s ", feed->child_argv[i]);
+ http_log("\n");
+
for (i = 3; i < 256; i++)
close(i);
}
}
- av_strlcpy(pathname, my_program_name, sizeof(pathname));
-
- slash = strrchr(pathname, '/');
- if (!slash)
- slash = pathname;
- else
- slash++;
- strcpy(slash, "ffmpeg");
-
/* This is needed to make relative pathnames work */
chdir(my_program_dir);
dest_addr.sin_port = htons(stream->multicast_port);
rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
- RTSP_PROTOCOL_RTP_UDP_MULTICAST);
+ RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
if (!rtp_c)
continue;
{
int server_fd = 0, rtsp_server_fd = 0;
int ret, delay, delay1;
- struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
+ struct pollfd *poll_table, *poll_entry;
HTTPContext *c, *c_next;
+ if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
+ http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
+ return -1;
+ }
+
if (my_http_addr.sin_port) {
server_fd = socket_open_listen(&my_http_addr);
if (server_fd < 0)
return -1;
}
- http_log("ffserver started.\n");
+ http_log("FFserver started.\n");
start_children(first_feed);
- first_http_ctx = NULL;
- nb_connections = 0;
-
start_multicast();
for(;;) {
ctx = &c->fmt_ctx;
- if (!c->last_packet_sent) {
+ if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
if (ctx->oformat) {
/* prepare header */
if (url_open_dyn_buf(&ctx->pb) >= 0) {
if (stream->stream_type == STREAM_TYPE_REDIRECT) {
c->http_error = 301;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
- 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>Moved</title></head><body>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
-
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 301 Moved\r\n"
+ "Location: %s\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Moved</title></head><body>\r\n"
+ "You should be <a href=\"%s\">redirected</a>.\r\n"
+ "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
/* If this is WMP, get the rate information */
if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
if (modify_current_stream(c, ratebuf)) {
- for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
+ for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
if (c->switch_feed_streams[i] >= 0)
do_switch_stream(c, i);
}
/* If already streaming this feed, do not let start another feeder. */
if (stream->feed_opened) {
snprintf(msg, sizeof(msg), "This feed is already being received.");
+ http_log("feed %s already being received\n", stream->feed_filename);
goto send_error;
}
if (c->post == 0 && max_bandwidth < current_bandwidth) {
c->http_error = 200;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
- 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, "<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 %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
- current_bandwidth, max_bandwidth);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
-
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 Server too busy\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Too busy</title></head><body>\r\n"
+ "<p>The server is too busy to serve your request at this time.</p>\r\n"
+ "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
+ "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
+ "</body></html>\r\n", current_bandwidth, max_bandwidth);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
q = c->buffer;
switch(redir_type) {
case REDIR_ASX:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
- //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
- hostbuf, filename, info);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASX Follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "<ASX Version=\"3\">\r\n"
+ //"<!-- Autogenerated by ffserver -->\r\n"
+ "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
+ "</ASX>\r\n", hostbuf, filename, info);
break;
case REDIR_RAM:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
- hostbuf, filename, info);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RAM Follows\r\n"
+ "Content-type: audio/x-pn-realaudio\r\n"
+ "\r\n"
+ "# Autogenerated by ffserver\r\n"
+ "http://%s/%s%s\r\n", hostbuf, filename, info);
break;
case REDIR_ASF:
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
- hostbuf, filename, info);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASF Redirect follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "[Reference]\r\n"
+ "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
break;
case REDIR_RTSP:
{
p = strrchr(hostname, ':');
if (p)
*p = '\0';
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
- /* XXX: incorrect mime type ? */
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
- hostname, ntohs(my_rtsp_addr.sin_port),
- filename);
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RTSP Redirect follows\r\n"
+ /* XXX: incorrect mime type ? */
+ "Content-type: application/x-rtsp\r\n"
+ "\r\n"
+ "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
}
break;
case REDIR_SDP:
int sdp_data_size, len;
struct sockaddr_in my_addr;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 OK\r\n"
+ "Content-type: application/sdp\r\n"
+ "\r\n");
len = sizeof(my_addr);
getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
if (c->post) {
/* if post, it means a feed is being sent */
if (!stream->is_feed) {
- /* However it might be a status report from WMP! Lets log the data
- * as it might come in handy one day
- */
+ /* However it might be a status report from WMP! Let us log the
+ * data as it might come in handy one day. */
char *logline = 0;
int client_id = 0;
send_error:
c->http_error = 404;
q = c->buffer;
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
-
+ q += snprintf(q, c->buffer_size,
+ "HTTP/1.0 404 Not Found\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<HTML>\n"
+ "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
+ "<BODY>%s</BODY>\n"
+ "</HTML>\n", msg);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
url_fprintf(pb, "Pragma: no-cache\r\n");
url_fprintf(pb, "\r\n");
- url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
+ url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
if (c->stream->feed_filename[0])
url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
url_fprintf(pb, "</HEAD>\n<BODY>");
stream->conns_served);
fmt_bytecount(pb, stream->bytes_served);
switch(stream->stream_type) {
- case STREAM_TYPE_LIVE:
- {
+ case STREAM_TYPE_LIVE: {
int audio_bit_rate = 0;
int video_bit_rate = 0;
const char *audio_codec_name = "";
url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
nb_connections, nb_max_connections);
- url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
+ url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<BR>\n",
current_bandwidth, max_bandwidth);
url_fprintf(pb, "<TABLE>\n");
strcpy(input_filename, c->stream->feed->feed_filename);
buf_size = FFM_PACKET_SIZE;
/* compute position (absolute time) */
- if (find_info_tag(buf, sizeof(buf), "date", info))
- {
+ if (find_info_tag(buf, sizeof(buf), "date", info)) {
stream_pos = parse_date(buf, 0);
if (stream_pos == INT64_MIN)
return -1;
- }
- else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
+ } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
int prebuffer = strtol(buf, 0, 10);
stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
} else
strcpy(input_filename, c->stream->feed_filename);
buf_size = 0;
/* compute position (relative time) */
- if (find_info_tag(buf, sizeof(buf), "date", info))
- {
+ if (find_info_tag(buf, sizeof(buf), "date", info)) {
stream_pos = parse_date(buf, 1);
if (stream_pos == INT64_MIN)
return -1;
- }
- else
+ } else
stream_pos = 0;
}
if (input_filename[0] == '\0')
}
} else {
AVCodecContext *codec;
- AVStream *ist = c->fmt_in->streams[source_index];
- AVStream *ost = ctx->streams[pkt.stream_index];
+ AVStream *ist, *ost;
send_it:
+ ist = c->fmt_in->streams[source_index];
/* specific handling for RTP: we use several
output stream (one for each RTP
connection). XXX: need more abstract handling */
} else {
ctx = &c->fmt_ctx;
/* Fudge here */
- codec = ost->codec;
+ codec = ctx->streams[pkt.stream_index]->codec;
}
if (c->is_packetized) {
int max_packet_size;
- if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
+ if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
else
max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
/* XXX: potential leak */
return -1;
}
- c->fmt_ctx.pb->is_streamed = 1;
+ ost = ctx->streams[pkt.stream_index];
+
+ ctx->pb->is_streamed = 1;
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
if (c->stream)
c->stream->bytes_served += len;
- if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
+ if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
/* RTP packets are sent inside the RTSP TCP connection */
ByteIOContext *pb;
int interleaved_index, size;
goto fail;
}
- for (i = 0; i < s->nb_streams; i++)
- memcpy(feed->streams[i]->codec,
- s->streams[i]->codec, sizeof(AVCodecContext));
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *fst = feed->streams[i];
+ AVStream *st = s->streams[i];
+ memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
+ if (fst->codec->extradata_size) {
+ fst->codec->extradata = av_malloc(fst->codec->extradata_size);
+ if (!fst->codec->extradata)
+ goto fail;
+ memcpy(fst->codec->extradata, st->codec->extradata,
+ fst->codec->extradata_size);
+ }
+ }
av_close_input_stream(s);
av_free(pb);
return NULL;
}
-static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
+static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPLowerTransport lower_transport)
{
RTSPTransportField *th;
int i;
for(i=0;i<h->nb_transports;i++) {
th = &h->transports[i];
- if (th->protocol == protocol)
+ if (th->lower_transport == lower_transport)
return th;
}
return NULL;
rtp_c = find_rtp_session(h->session_id);
if (!rtp_c) {
/* always prefer UDP */
- th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
+ th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
if (!th) {
- th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
+ th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
if (!th) {
rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
return;
}
rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
- th->protocol);
+ th->lower_transport);
if (!rtp_c) {
rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
return;
/* check transport */
th = find_transport(h, rtp_c->rtp_protocol);
- if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
+ if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
th->client_port_min <= 0)) {
rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
return;
url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
switch(rtp_c->rtp_protocol) {
- case RTSP_PROTOCOL_RTP_UDP:
+ case RTSP_LOWER_TRANSPORT_UDP:
port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
"client_port=%d-%d;server_port=%d-%d",
th->client_port_min, th->client_port_min + 1,
port, port + 1);
break;
- case RTSP_PROTOCOL_RTP_TCP:
+ case RTSP_LOWER_TRANSPORT_TCP:
url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
stream_index * 2, stream_index * 2 + 1);
break;
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
FFStream *stream, const char *session_id,
- enum RTSPProtocol rtp_protocol)
+ enum RTSPLowerTransport rtp_protocol)
{
HTTPContext *c = NULL;
const char *proto_str;
/* protocol is shown in statistics */
switch(c->rtp_protocol) {
- case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
+ case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
proto_str = "MCAST";
break;
- case RTSP_PROTOCOL_RTP_UDP:
+ case RTSP_LOWER_TRANSPORT_UDP:
proto_str = "UDP";
break;
- case RTSP_PROTOCOL_RTP_TCP:
+ case RTSP_LOWER_TRANSPORT_TCP:
proto_str = "TCP";
break;
default:
ipaddr = inet_ntoa(dest_addr->sin_addr);
switch(c->rtp_protocol) {
- case RTSP_PROTOCOL_RTP_UDP:
- case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
+ case RTSP_LOWER_TRANSPORT_UDP:
+ case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
/* RTP/UDP case */
/* XXX: also pass as parameter to function ? */
c->rtp_handles[stream_index] = h;
max_packet_size = url_get_max_packet_size(h);
break;
- case RTSP_PROTOCOL_RTP_TCP:
+ case RTSP_LOWER_TRANSPORT_TCP:
/* RTP/TCP case */
c->rtsp_c = rtsp_c;
max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
if (sf->index != ss->index ||
sf->id != ss->id) {
- printf("Index & Id do not match for stream %d (%s)\n",
+ http_log("Index & Id do not match for stream %d (%s)\n",
i, feed->feed_filename);
matches = 0;
} else {
#define CHECK_CODEC(x) (ccf->x != ccs->x)
if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
- printf("Codecs do not match for stream %d\n", i);
+ http_log("Codecs do not match for stream %d\n", i);
matches = 0;
} else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
- printf("Codec bitrates do not match for stream %d\n", i);
+ http_log("Codec bitrates do not match for stream %d\n", i);
matches = 0;
} else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
if (CHECK_CODEC(time_base.den) ||
CHECK_CODEC(time_base.num) ||
CHECK_CODEC(width) ||
CHECK_CODEC(height)) {
- printf("Codec width, height and framerate do not match for stream %d\n", i);
+ http_log("Codec width, height and framerate do not match for stream %d\n", i);
matches = 0;
}
} else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
if (CHECK_CODEC(sample_rate) ||
CHECK_CODEC(channels) ||
CHECK_CODEC(frame_size)) {
- printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
+ http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
matches = 0;
}
} else {
- printf("Unknown codec type\n");
+ http_log("Unknown codec type\n");
matches = 0;
}
}
break;
}
} else
- printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
+ http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
feed->feed_filename, s->nb_streams, feed->nb_streams);
av_close_input_file(s);
} else
- printf("Deleting feed file '%s' as it appears to be corrupt\n",
+ http_log("Deleting feed file '%s' as it appears to be corrupt\n",
feed->feed_filename);
if (!matches) {
if (feed->readonly) {
- printf("Unable to delete feed file '%s' as it is marked readonly\n",
+ http_log("Unable to delete feed file '%s' as it is marked readonly\n",
feed->feed_filename);
exit(1);
}
}
}
if (!url_exist(feed->feed_filename)) {
- AVFormatContext s1, *s = &s1;
+ AVFormatContext s1 = {0}, *s = &s1;
if (feed->readonly) {
- printf("Unable to create feed file '%s' as it is marked readonly\n",
+ http_log("Unable to create feed file '%s' as it is marked readonly\n",
feed->feed_filename);
exit(1);
}
memcpy(st->codec, av, sizeof(AVCodecContext));
}
-static int opt_audio_codec(const char *arg)
+static enum CodecID opt_audio_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
return p->id;
}
-static int opt_video_codec(const char *arg)
+static enum CodecID opt_video_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
/* simplistic plugin support */
-#ifdef HAVE_DLOPEN
+#if HAVE_DLOPEN
static void load_module(const char *filename)
{
void *dll;
}
#endif
-static int opt_default(const char *opt, const char *arg,
+static int ffserver_opt_default(const char *opt, const char *arg,
AVCodecContext *avctx, int type)
{
- const AVOption *o = NULL;
- const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
- if(o2)
- o = av_set_string(avctx, opt, arg);
- if(!o)
- return -1;
- return 0;
+ int ret = 0;
+ const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
+ if(o)
+ ret = av_set_string3(avctx, opt, arg, 1, NULL);
+ return ret;
}
static int parse_ffconfig(const char *filename)
FFStream **last_stream, *stream, *redirect;
FFStream **last_feed, *feed;
AVCodecContext audio_enc, video_enc;
- int audio_id, video_id;
+ enum CodecID audio_id, video_id;
f = fopen(filename, "r");
if (!f) {
filename, line_num, arg);
errors++;
}
+ } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
+ get_arg(arg, sizeof(arg), &p);
+ val = atoi(arg);
+ if (val < 1 || val > 65536) {
+ fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
+ filename, line_num, arg);
+ errors++;
+ }
+ nb_max_http_connections = val;
} else if (!strcasecmp(cmd, "MaxClients")) {
get_arg(arg, sizeof(arg), &p);
val = atoi(arg);
- if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
+ if (val < 1 || val > nb_max_http_connections) {
fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
filename, line_num, arg);
errors++;
(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) {
} else if (!strcasecmp(cmd, "Format")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
- if (!strcmp(arg, "status")) {
- stream->stream_type = STREAM_TYPE_STATUS;
- stream->fmt = NULL;
- } else {
- stream->stream_type = STREAM_TYPE_LIVE;
- /* jpeg cannot be used here, so use single frame jpeg */
- if (!strcmp(arg, "jpeg"))
- strcpy(arg, "mjpeg");
- stream->fmt = guess_stream_format(arg, NULL, NULL);
- if (!stream->fmt) {
- fprintf(stderr, "%s:%d: Unknown Format: %s\n",
- filename, line_num, arg);
- errors++;
+ if (!strcmp(arg, "status")) {
+ stream->stream_type = STREAM_TYPE_STATUS;
+ stream->fmt = NULL;
+ } else {
+ stream->stream_type = STREAM_TYPE_LIVE;
+ /* jpeg cannot be used here, so use single frame jpeg */
+ if (!strcmp(arg, "jpeg"))
+ strcpy(arg, "mjpeg");
+ stream->fmt = guess_stream_format(arg, NULL, NULL);
+ if (!stream->fmt) {
+ fprintf(stderr, "%s:%d: Unknown Format: %s\n",
+ filename, line_num, arg);
+ errors++;
+ }
+ }
+ if (stream->fmt) {
+ audio_id = stream->fmt->audio_codec;
+ video_id = stream->fmt->video_codec;
}
- }
- if (stream->fmt) {
- audio_id = stream->fmt->audio_codec;
- video_id = stream->fmt->video_codec;
- }
}
} else if (!strcasecmp(cmd, "InputFormat")) {
get_arg(arg, sizeof(arg), &p);
- stream->ifmt = av_find_input_format(arg);
- if (!stream->ifmt) {
- fprintf(stderr, "%s:%d: Unknown input format: %s\n",
- filename, line_num, arg);
+ if (stream) {
+ stream->ifmt = av_find_input_format(arg);
+ if (!stream->ifmt) {
+ fprintf(stderr, "%s:%d: Unknown input format: %s\n",
+ filename, line_num, arg);
+ }
}
} else if (!strcasecmp(cmd, "FaviconURL")) {
if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
avctx = &audio_enc;
type = AV_OPT_FLAG_AUDIO_PARAM;
}
- if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
+ if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
errors++;
}
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)
- video_enc.codec_tag = ff_get_fourcc(arg);
+ video_enc.codec_tag = AV_RL32(arg);
} else if (!strcasecmp(cmd, "BitExact")) {
if (stream)
video_enc.flags |= CODEC_FLAG_BITEXACT;
}
} else if (!strcasecmp(cmd, "LoadModule")) {
get_arg(arg, sizeof(arg), &p);
-#ifdef HAVE_DLOPEN
+#if HAVE_DLOPEN
load_module(arg);
#else
fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
unsetenv("http_proxy"); /* Kill the http_proxy */
- av_init_random(av_gettime() + (getpid() << 16), &random_state);
+ av_random_init(&random_state, av_gettime() + (getpid() << 16));
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;
exit(1);
}
+ /* open log file if needed */
+ if (logfilename[0] != '\0') {
+ if (!strcmp(logfilename, "-"))
+ logfile = stdout;
+ else
+ logfile = fopen(logfilename, "a");
+ av_log_set_callback(http_av_log);
+ }
+
build_file_streams();
build_feed_streams();
} else {
/* child */
setsid();
- chdir("/");
close(0);
open("/dev/null", O_RDWR);
if (strcmp(logfilename, "-") != 0) {
/* signal init */
signal(SIGPIPE, SIG_IGN);
- /* open log file if needed */
- if (logfilename[0] != '\0') {
- if (!strcmp(logfilename, "-"))
- logfile = stderr;
- else
- logfile = fopen(logfilename, "a");
- av_log_set_callback(http_av_log);
- }
+ if (ffserver_daemon)
+ chdir("/");
if (http_server() < 0) {
http_log("Could not start server\n");