|
|
@@ -83,7 +83,7 @@ typedef struct HTTPContext { |
|
|
UINT8 *buffer_ptr, *buffer_end; |
|
|
UINT8 *buffer_ptr, *buffer_end; |
|
|
int http_error; |
|
|
int http_error; |
|
|
struct HTTPContext *next; |
|
|
struct HTTPContext *next; |
|
|
int got_key_frame[MAX_STREAMS]; /* for each type */ |
|
|
|
|
|
|
|
|
int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ |
|
|
INT64 data_count; |
|
|
INT64 data_count; |
|
|
/* feed input */ |
|
|
/* feed input */ |
|
|
int feed_fd; |
|
|
int feed_fd; |
|
|
@@ -94,6 +94,7 @@ typedef struct HTTPContext { |
|
|
AVFormatContext fmt_ctx; |
|
|
AVFormatContext fmt_ctx; |
|
|
int last_packet_sent; /* true if last data packet was sent */ |
|
|
int last_packet_sent; /* true if last data packet was sent */ |
|
|
int suppress_log; |
|
|
int suppress_log; |
|
|
|
|
|
int bandwidth; |
|
|
char protocol[16]; |
|
|
char protocol[16]; |
|
|
char method[16]; |
|
|
char method[16]; |
|
|
char url[128]; |
|
|
char url[128]; |
|
|
@@ -114,6 +115,7 @@ typedef struct FFStream { |
|
|
struct FFStream *feed; |
|
|
struct FFStream *feed; |
|
|
AVFormat *fmt; |
|
|
AVFormat *fmt; |
|
|
int nb_streams; |
|
|
int nb_streams; |
|
|
|
|
|
int prebuffer; /* Number of millseconds early to start */ |
|
|
AVStream *streams[MAX_STREAMS]; |
|
|
AVStream *streams[MAX_STREAMS]; |
|
|
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */ |
|
|
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */ |
|
|
char feed_filename[1024]; /* file name of the feed storage, or |
|
|
char feed_filename[1024]; /* file name of the feed storage, or |
|
|
@@ -150,6 +152,9 @@ static int http_receive_data(HTTPContext *c); |
|
|
int nb_max_connections; |
|
|
int nb_max_connections; |
|
|
int nb_connections; |
|
|
int nb_connections; |
|
|
|
|
|
|
|
|
|
|
|
int nb_max_bandwidth; |
|
|
|
|
|
int nb_bandwidth; |
|
|
|
|
|
|
|
|
static long gettime_ms(void) |
|
|
static long gettime_ms(void) |
|
|
{ |
|
|
{ |
|
|
struct timeval tv; |
|
|
struct timeval tv; |
|
|
@@ -296,6 +301,7 @@ static int http_server(struct sockaddr_in my_addr) |
|
|
if (c->fmt_in) |
|
|
if (c->fmt_in) |
|
|
av_close_input_file(c->fmt_in); |
|
|
av_close_input_file(c->fmt_in); |
|
|
*cp = c->next; |
|
|
*cp = c->next; |
|
|
|
|
|
nb_bandwidth -= c->bandwidth; |
|
|
free(c); |
|
|
free(c); |
|
|
nb_connections--; |
|
|
nb_connections--; |
|
|
} else { |
|
|
} else { |
|
|
@@ -443,6 +449,7 @@ static int http_parse_request(HTTPContext *c) |
|
|
char *p; |
|
|
char *p; |
|
|
int post; |
|
|
int post; |
|
|
int doing_asx; |
|
|
int doing_asx; |
|
|
|
|
|
int doing_ram; |
|
|
char cmd[32]; |
|
|
char cmd[32]; |
|
|
char info[1024], *filename; |
|
|
char info[1024], *filename; |
|
|
char url[1024], *q; |
|
|
char url[1024], *q; |
|
|
@@ -450,6 +457,7 @@ static int http_parse_request(HTTPContext *c) |
|
|
char msg[1024]; |
|
|
char msg[1024]; |
|
|
const char *mime_type; |
|
|
const char *mime_type; |
|
|
FFStream *stream; |
|
|
FFStream *stream; |
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
p = c->buffer; |
|
|
p = c->buffer; |
|
|
q = cmd; |
|
|
q = cmd; |
|
|
@@ -513,6 +521,15 @@ static int http_parse_request(HTTPContext *c) |
|
|
doing_asx = 0; |
|
|
doing_asx = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (strlen(filename) > 4 && |
|
|
|
|
|
(strcmp(".rpm", filename + strlen(filename) - 4) == 0 || |
|
|
|
|
|
strcmp(".ram", filename + strlen(filename) - 4) == 0)) { |
|
|
|
|
|
doing_ram = 1; |
|
|
|
|
|
strcpy(filename + strlen(filename)-2, "m"); |
|
|
|
|
|
} else { |
|
|
|
|
|
doing_ram = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
stream = first_stream; |
|
|
stream = first_stream; |
|
|
while (stream != NULL) { |
|
|
while (stream != NULL) { |
|
|
if (!strcmp(stream->filename, filename)) |
|
|
if (!strcmp(stream->filename, filename)) |
|
|
@@ -523,7 +540,47 @@ static int http_parse_request(HTTPContext *c) |
|
|
sprintf(msg, "File '%s' not found", url); |
|
|
sprintf(msg, "File '%s' not found", url); |
|
|
goto send_error; |
|
|
goto send_error; |
|
|
} |
|
|
} |
|
|
if (doing_asx) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) { |
|
|
|
|
|
/* See if we meet the bandwidth requirements */ |
|
|
|
|
|
for(i=0;i<stream->nb_streams;i++) { |
|
|
|
|
|
AVStream *st = stream->streams[i]; |
|
|
|
|
|
switch(st->codec.codec_type) { |
|
|
|
|
|
case CODEC_TYPE_AUDIO: |
|
|
|
|
|
c->bandwidth += st->codec.bit_rate; |
|
|
|
|
|
break; |
|
|
|
|
|
case CODEC_TYPE_VIDEO: |
|
|
|
|
|
c->bandwidth += st->codec.bit_rate; |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
abort(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
c->bandwidth /= 1000; |
|
|
|
|
|
nb_bandwidth += c->bandwidth; |
|
|
|
|
|
|
|
|
|
|
|
if (post == 0 && nb_max_bandwidth < nb_bandwidth) { |
|
|
|
|
|
c->http_error = 200; |
|
|
|
|
|
q = c->buffer; |
|
|
|
|
|
q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n"); |
|
|
|
|
|
q += sprintf(q, "Content-type: text/html\r\n"); |
|
|
|
|
|
q += sprintf(q, "\r\n"); |
|
|
|
|
|
q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n"); |
|
|
|
|
|
q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n"); |
|
|
|
|
|
q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n", |
|
|
|
|
|
nb_bandwidth, nb_max_bandwidth); |
|
|
|
|
|
q += sprintf(q, "</body></html>\r\n"); |
|
|
|
|
|
|
|
|
|
|
|
/* prepare output buffer */ |
|
|
|
|
|
c->buffer_ptr = c->buffer; |
|
|
|
|
|
c->buffer_end = q; |
|
|
|
|
|
c->state = HTTPSTATE_SEND_HEADER; |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (doing_asx || doing_ram) { |
|
|
char *hostinfo = 0; |
|
|
char *hostinfo = 0; |
|
|
|
|
|
|
|
|
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { |
|
|
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { |
|
|
@@ -556,14 +613,24 @@ static int http_parse_request(HTTPContext *c) |
|
|
|
|
|
|
|
|
c->http_error = 200; |
|
|
c->http_error = 200; |
|
|
q = c->buffer; |
|
|
q = c->buffer; |
|
|
q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n"); |
|
|
|
|
|
q += sprintf(q, "Content-type: video/x-ms-asf\r\n"); |
|
|
|
|
|
q += sprintf(q, "\r\n"); |
|
|
|
|
|
q += sprintf(q, "<ASX Version=\"3\">\r\n"); |
|
|
|
|
|
q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n"); |
|
|
|
|
|
q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", |
|
|
|
|
|
hostbuf, filename, info); |
|
|
|
|
|
q += sprintf(q, "</ASX>\r\n"); |
|
|
|
|
|
|
|
|
if (doing_asx) { |
|
|
|
|
|
q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n"); |
|
|
|
|
|
q += sprintf(q, "Content-type: video/x-ms-asf\r\n"); |
|
|
|
|
|
q += sprintf(q, "\r\n"); |
|
|
|
|
|
q += sprintf(q, "<ASX Version=\"3\">\r\n"); |
|
|
|
|
|
q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n"); |
|
|
|
|
|
q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", |
|
|
|
|
|
hostbuf, filename, info); |
|
|
|
|
|
q += sprintf(q, "</ASX>\r\n"); |
|
|
|
|
|
} else if (doing_ram) { |
|
|
|
|
|
q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n"); |
|
|
|
|
|
q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n"); |
|
|
|
|
|
q += sprintf(q, "\r\n"); |
|
|
|
|
|
q += sprintf(q, "# Autogenerated by ffserver\r\n"); |
|
|
|
|
|
q += sprintf(q, "http://%s/%s%s\r\n", |
|
|
|
|
|
hostbuf, filename, info); |
|
|
|
|
|
} else |
|
|
|
|
|
abort(); |
|
|
|
|
|
|
|
|
/* prepare output buffer */ |
|
|
/* prepare output buffer */ |
|
|
c->buffer_ptr = c->buffer; |
|
|
c->buffer_ptr = c->buffer; |
|
|
@@ -574,7 +641,7 @@ static int http_parse_request(HTTPContext *c) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
sprintf(msg, "ASX file not handled"); |
|
|
|
|
|
|
|
|
sprintf(msg, "ASX/RAM file not handled"); |
|
|
goto send_error; |
|
|
goto send_error; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -706,8 +773,21 @@ static void compute_stats(HTTPContext *c) |
|
|
q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio<TD>Feed\n"); |
|
|
q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio<TD>Feed\n"); |
|
|
stream = first_stream; |
|
|
stream = first_stream; |
|
|
while (stream != NULL) { |
|
|
while (stream != NULL) { |
|
|
|
|
|
char sfilename[1024]; |
|
|
|
|
|
char *eosf; |
|
|
|
|
|
|
|
|
|
|
|
strlcpy(sfilename, stream->filename, sizeof(sfilename) - 1); |
|
|
|
|
|
eosf = sfilename + strlen(sfilename); |
|
|
|
|
|
if (eosf - sfilename >= 4) { |
|
|
|
|
|
if (strcmp(eosf - 4, ".asf") == 0) { |
|
|
|
|
|
strcpy(eosf - 4, ".asx"); |
|
|
|
|
|
} else if (strcmp(eosf - 3, ".rm") == 0) { |
|
|
|
|
|
strcpy(eosf - 3, ".ram"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", |
|
|
q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", |
|
|
stream->filename, stream->filename); |
|
|
|
|
|
|
|
|
sfilename, stream->filename); |
|
|
switch(stream->stream_type) { |
|
|
switch(stream->stream_type) { |
|
|
case STREAM_TYPE_LIVE: |
|
|
case STREAM_TYPE_LIVE: |
|
|
{ |
|
|
{ |
|
|
@@ -783,6 +863,9 @@ static void compute_stats(HTTPContext *c) |
|
|
q += sprintf(q, "Number of connections: %d / %d<BR>\n", |
|
|
q += sprintf(q, "Number of connections: %d / %d<BR>\n", |
|
|
nb_connections, nb_max_connections); |
|
|
nb_connections, nb_max_connections); |
|
|
|
|
|
|
|
|
|
|
|
q += sprintf(q, "Bandwidth in use: %dk / %dk<BR>\n", |
|
|
|
|
|
nb_bandwidth, nb_max_bandwidth); |
|
|
|
|
|
|
|
|
q += sprintf(q, "<TABLE>\n"); |
|
|
q += sprintf(q, "<TABLE>\n"); |
|
|
q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n"); |
|
|
q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n"); |
|
|
c1 = first_http_ctx; |
|
|
c1 = first_http_ctx; |
|
|
@@ -845,7 +928,7 @@ static int open_input_stream(HTTPContext *c, const char *info) |
|
|
int prebuffer = strtol(buf, 0, 10); |
|
|
int prebuffer = strtol(buf, 0, 10); |
|
|
stream_pos = gettime() - prebuffer * 1000000; |
|
|
stream_pos = gettime() - prebuffer * 1000000; |
|
|
} else { |
|
|
} else { |
|
|
stream_pos = gettime(); |
|
|
|
|
|
|
|
|
stream_pos = gettime() - c->stream->prebuffer * 1000; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
strcpy(input_filename, c->stream->feed_filename); |
|
|
strcpy(input_filename, c->stream->feed_filename); |
|
|
@@ -896,8 +979,8 @@ static int http_prepare_data(HTTPContext *c) |
|
|
|
|
|
|
|
|
st->codec.frame_number = 0; /* XXX: should be done in |
|
|
st->codec.frame_number = 0; /* XXX: should be done in |
|
|
AVStream, not in codec */ |
|
|
AVStream, not in codec */ |
|
|
c->got_key_frame[i] = 0; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
c->got_key_frame = 0; |
|
|
} else { |
|
|
} else { |
|
|
/* open output stream by using codecs in specified file */ |
|
|
/* open output stream by using codecs in specified file */ |
|
|
c->fmt_ctx.format = c->stream->fmt; |
|
|
c->fmt_ctx.format = c->stream->fmt; |
|
|
@@ -909,8 +992,8 @@ static int http_prepare_data(HTTPContext *c) |
|
|
memcpy(st, c->fmt_in->streams[i], sizeof(AVStream)); |
|
|
memcpy(st, c->fmt_in->streams[i], sizeof(AVStream)); |
|
|
st->codec.frame_number = 0; /* XXX: should be done in |
|
|
st->codec.frame_number = 0; /* XXX: should be done in |
|
|
AVStream, not in codec */ |
|
|
AVStream, not in codec */ |
|
|
c->got_key_frame[i] = 0; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
c->got_key_frame = 0; |
|
|
} |
|
|
} |
|
|
init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE, |
|
|
init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE, |
|
|
1, c, NULL, http_write_packet, NULL); |
|
|
1, c, NULL, http_write_packet, NULL); |
|
|
@@ -928,9 +1011,7 @@ static int http_prepare_data(HTTPContext *c) |
|
|
/* overflow : resync. We suppose that wptr is at this |
|
|
/* overflow : resync. We suppose that wptr is at this |
|
|
point a pointer to a valid packet */ |
|
|
point a pointer to a valid packet */ |
|
|
c->rptr = http_fifo.wptr; |
|
|
c->rptr = http_fifo.wptr; |
|
|
for(i=0;i<c->fmt_ctx.nb_streams;i++) { |
|
|
|
|
|
c->got_key_frame[i] = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
c->got_key_frame = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
start_rptr = c->rptr; |
|
|
start_rptr = c->rptr; |
|
|
@@ -956,8 +1037,8 @@ static int http_prepare_data(HTTPContext *c) |
|
|
if (test_header(&hdr, &st->codec)) { |
|
|
if (test_header(&hdr, &st->codec)) { |
|
|
/* only begin sending when got a key frame */ |
|
|
/* only begin sending when got a key frame */ |
|
|
if (st->codec.key_frame) |
|
|
if (st->codec.key_frame) |
|
|
c->got_key_frame[i] = 1; |
|
|
|
|
|
if (c->got_key_frame[i]) { |
|
|
|
|
|
|
|
|
c->got_key_frame |= 1 << i; |
|
|
|
|
|
if (c->got_key_frame & (1 << i)) { |
|
|
ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i, |
|
|
ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i, |
|
|
payload, payload_size); |
|
|
payload, payload_size); |
|
|
} |
|
|
} |
|
|
@@ -1007,7 +1088,19 @@ static int http_prepare_data(HTTPContext *c) |
|
|
for(i=0;i<c->stream->nb_streams;i++) { |
|
|
for(i=0;i<c->stream->nb_streams;i++) { |
|
|
if (c->stream->feed_streams[i] == pkt.stream_index) { |
|
|
if (c->stream->feed_streams[i] == pkt.stream_index) { |
|
|
pkt.stream_index = i; |
|
|
pkt.stream_index = i; |
|
|
goto send_it; |
|
|
|
|
|
|
|
|
if (pkt.flags & PKT_FLAG_KEY) { |
|
|
|
|
|
c->got_key_frame |= 1 << i; |
|
|
|
|
|
} |
|
|
|
|
|
/* See if we have all the key frames, then |
|
|
|
|
|
* we start to send. This logic is not quite |
|
|
|
|
|
* right, but it works for the case of a |
|
|
|
|
|
* single video stream with one or more |
|
|
|
|
|
* audio streams (for which every frame is |
|
|
|
|
|
* typically a key frame). |
|
|
|
|
|
*/ |
|
|
|
|
|
if ((c->got_key_frame + 1) >> c->stream->nb_streams) { |
|
|
|
|
|
goto send_it; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
@@ -1030,7 +1123,7 @@ static int http_prepare_data(HTTPContext *c) |
|
|
|
|
|
|
|
|
codec->frame_number++; |
|
|
codec->frame_number++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
av_free_packet(&pkt); |
|
|
av_free_packet(&pkt); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@@ -1353,12 +1446,16 @@ void add_codec(FFStream *stream, AVCodecContext *av) |
|
|
av->height = 128; |
|
|
av->height = 128; |
|
|
} |
|
|
} |
|
|
/* Bitrate tolerance is less for streaming */ |
|
|
/* Bitrate tolerance is less for streaming */ |
|
|
av->bit_rate_tolerance = av->bit_rate / 4; |
|
|
|
|
|
av->qmin = 3; |
|
|
|
|
|
av->qmax = 31; |
|
|
|
|
|
|
|
|
if (av->bit_rate_tolerance == 0) |
|
|
|
|
|
av->bit_rate_tolerance = av->bit_rate / 4; |
|
|
|
|
|
if (av->qmin == 0) |
|
|
|
|
|
av->qmin = 3; |
|
|
|
|
|
if (av->qmax == 0) |
|
|
|
|
|
av->qmax = 31; |
|
|
|
|
|
if (av->max_qdiff == 0) |
|
|
|
|
|
av->max_qdiff = 3; |
|
|
av->qcompress = 0.5; |
|
|
av->qcompress = 0.5; |
|
|
av->qblur = 0.5; |
|
|
av->qblur = 0.5; |
|
|
av->max_qdiff = 3; |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
@@ -1467,6 +1564,16 @@ int parse_ffconfig(const char *filename) |
|
|
} else { |
|
|
} else { |
|
|
nb_max_connections = val; |
|
|
nb_max_connections = val; |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (!strcasecmp(cmd, "MaxBandwidth")) { |
|
|
|
|
|
get_arg(arg, sizeof(arg), &p); |
|
|
|
|
|
val = atoi(arg); |
|
|
|
|
|
if (val < 10 || val > 100000) { |
|
|
|
|
|
fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", |
|
|
|
|
|
filename, line_num, arg); |
|
|
|
|
|
errors++; |
|
|
|
|
|
} else { |
|
|
|
|
|
nb_max_bandwidth = val; |
|
|
|
|
|
} |
|
|
} else if (!strcasecmp(cmd, "CustomLog")) { |
|
|
} else if (!strcasecmp(cmd, "CustomLog")) { |
|
|
get_arg(logfilename, sizeof(logfilename), &p); |
|
|
get_arg(logfilename, sizeof(logfilename), &p); |
|
|
} else if (!strcasecmp(cmd, "<Feed")) { |
|
|
} else if (!strcasecmp(cmd, "<Feed")) { |
|
|
@@ -1531,7 +1638,12 @@ int parse_ffconfig(const char *filename) |
|
|
errors++; |
|
|
errors++; |
|
|
} else { |
|
|
} else { |
|
|
/* Make sure that we start out clean */ |
|
|
/* Make sure that we start out clean */ |
|
|
unlink(feed->feed_filename); |
|
|
|
|
|
|
|
|
if (unlink(feed->feed_filename) < 0 |
|
|
|
|
|
&& errno != ENOENT) { |
|
|
|
|
|
fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n", |
|
|
|
|
|
filename, line_num, feed->feed_filename, strerror(errno)); |
|
|
|
|
|
errors++; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
feed = NULL; |
|
|
feed = NULL; |
|
|
} else if (!strcasecmp(cmd, "<Stream")) { |
|
|
} else if (!strcasecmp(cmd, "<Stream")) { |
|
|
@@ -1599,6 +1711,11 @@ int parse_ffconfig(const char *filename) |
|
|
audio_id = stream->fmt->audio_codec; |
|
|
audio_id = stream->fmt->audio_codec; |
|
|
video_id = stream->fmt->video_codec; |
|
|
video_id = stream->fmt->video_codec; |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (!strcasecmp(cmd, "Preroll")) { |
|
|
|
|
|
get_arg(arg, sizeof(arg), &p); |
|
|
|
|
|
if (stream) { |
|
|
|
|
|
stream->prebuffer = atoi(arg) * 1000; |
|
|
|
|
|
} |
|
|
} else if (!strcasecmp(cmd, "AudioCodec")) { |
|
|
} else if (!strcasecmp(cmd, "AudioCodec")) { |
|
|
get_arg(arg, sizeof(arg), &p); |
|
|
get_arg(arg, sizeof(arg), &p); |
|
|
audio_id = opt_audio_codec(arg); |
|
|
audio_id = opt_audio_codec(arg); |
|
|
@@ -1664,6 +1781,33 @@ int parse_ffconfig(const char *filename) |
|
|
if (stream) { |
|
|
if (stream) { |
|
|
video_enc.flags |= CODEC_FLAG_HQ; |
|
|
video_enc.flags |= CODEC_FLAG_HQ; |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (!strcasecmp(cmd, "VideoQDiff")) { |
|
|
|
|
|
if (stream) { |
|
|
|
|
|
video_enc.max_qdiff = atoi(arg); |
|
|
|
|
|
if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) { |
|
|
|
|
|
fprintf(stderr, "%s:%d: VideoQDiff out of range\n", |
|
|
|
|
|
filename, line_num); |
|
|
|
|
|
errors++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else if (!strcasecmp(cmd, "VideoQMax")) { |
|
|
|
|
|
if (stream) { |
|
|
|
|
|
video_enc.qmax = atoi(arg); |
|
|
|
|
|
if (video_enc.qmax < 1 || video_enc.qmax > 31) { |
|
|
|
|
|
fprintf(stderr, "%s:%d: VideoQMax out of range\n", |
|
|
|
|
|
filename, line_num); |
|
|
|
|
|
errors++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else if (!strcasecmp(cmd, "VideoQMin")) { |
|
|
|
|
|
if (stream) { |
|
|
|
|
|
video_enc.qmin = atoi(arg); |
|
|
|
|
|
if (video_enc.qmin < 1 || video_enc.qmin > 31) { |
|
|
|
|
|
fprintf(stderr, "%s:%d: VideoQMin out of range\n", |
|
|
|
|
|
filename, line_num); |
|
|
|
|
|
errors++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} else if (!strcasecmp(cmd, "NoVideo")) { |
|
|
} else if (!strcasecmp(cmd, "NoVideo")) { |
|
|
video_id = CODEC_ID_NONE; |
|
|
video_id = CODEC_ID_NONE; |
|
|
} else if (!strcasecmp(cmd, "NoAudio")) { |
|
|
} else if (!strcasecmp(cmd, "NoAudio")) { |
|
|
@@ -1793,6 +1937,7 @@ int main(int argc, char **argv) |
|
|
my_addr.sin_port = htons (8080); |
|
|
my_addr.sin_port = htons (8080); |
|
|
my_addr.sin_addr.s_addr = htonl (INADDR_ANY); |
|
|
my_addr.sin_addr.s_addr = htonl (INADDR_ANY); |
|
|
nb_max_connections = 5; |
|
|
nb_max_connections = 5; |
|
|
|
|
|
nb_max_bandwidth = 1000; |
|
|
first_stream = NULL; |
|
|
first_stream = NULL; |
|
|
logfilename[0] = '\0'; |
|
|
logfilename[0] = '\0'; |
|
|
|
|
|
|
|
|
|