#endif
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
#include "libavformat/avformat.h"
+// FIXME those are internal headers, avserver _really_ shouldn't use them
#include "libavformat/ffm.h"
#include "libavformat/network.h"
#include "libavformat/os_support.h"
#include "libavformat/rtpdec.h"
#include "libavformat/rtsp.h"
-// XXX for ffio_open_dyn_packet_buffer, to be removed
#include "libavformat/avio_internal.h"
+#include "libavformat/internal.h"
+#include "libavformat/url.h"
+
#include "libavutil/avstring.h"
#include "libavutil/lfg.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/random_seed.h"
#include "libavutil/parseutils.h"
#include "libavutil/opt.h"
+#include "libavutil/time.h"
+
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#endif
#include <errno.h>
-#include <sys/time.h>
#include <time.h>
#include <sys/wait.h>
#include <signal.h>
HTTPContext *rtsp_c);
static const char *my_program_name;
-static const char *my_program_dir;
static const char *config_filename = "/etc/avserver.conf";
static int avserver_debug;
-static int avserver_daemon;
static int no_launch;
static int need_to_start_children;
static FILE *logfile = NULL;
-void exit_program(int ret)
+static int64_t ffm_read_write_index(int fd)
+{
+ uint8_t buf[8];
+
+ lseek(fd, 8, SEEK_SET);
+ if (read(fd, buf, 8) != 8)
+ return AVERROR(EIO);
+ return AV_RB64(buf);
+}
+
+static int ffm_write_write_index(int fd, int64_t pos)
+{
+ uint8_t buf[8];
+ int i;
+
+ for(i=0;i<8;i++)
+ buf[i] = (pos >> (56 - i * 8)) & 0xff;
+ lseek(fd, 8, SEEK_SET);
+ if (write(fd, buf, 8) != 8)
+ return AVERROR(EIO);
+ return 8;
+}
+
+static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
+ int64_t file_size)
{
- exit(ret);
+ FFMContext *ffm = s->priv_data;
+ ffm->write_index = pos;
+ ffm->file_size = file_size;
}
/* FIXME: make avserver work with IPv6 */
if (!ff_inet_aton(hostname, sin_addr)) {
#if HAVE_GETADDRINFO
struct addrinfo *ai, *cur;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
+ struct addrinfo hints = { 0 };
hints.ai_family = AF_INET;
if (getaddrinfo(hostname, NULL, &hints, &ai))
return -1;
slash++;
strcpy(slash, "avconv");
- http_log("Launch commandline: ");
+ http_log("Launch command line: ");
http_log("%s ", pathname);
for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
http_log("%s ", feed->child_argv[i]);
close(i);
if (!avserver_debug) {
- i = open("/dev/null", O_RDWR);
- if (i != -1) {
- dup2(i, 0);
- dup2(i, 1);
- dup2(i, 2);
- close(i);
- }
+ if (!freopen("/dev/null", "r", stdin))
+ http_log("failed to redirect STDIN to /dev/null\n;");
+ if (!freopen("/dev/null", "w", stdout))
+ http_log("failed to redirect STDOUT to /dev/null\n;");
+ if (!freopen("/dev/null", "w", stderr))
+ http_log("failed to redirect STDERR to /dev/null\n;");
}
- /* This is needed to make relative pathnames work */
- chdir(my_program_dir);
-
signal(SIGPIPE, SIG_DFL);
execvp(pathname, feed->child_argv);
static void new_connection(int server_fd, int is_rtsp)
{
struct sockaddr_in from_addr;
- int fd, len;
+ socklen_t len;
+ int fd;
HTTPContext *c = NULL;
len = sizeof(from_addr);
if (st->codec->codec)
avcodec_close(st->codec);
}
- av_close_input_file(c->fmt_in);
+ avformat_close_input(&c->fmt_in);
}
/* free RTP output streams if any */
}
h = c->rtp_handles[i];
if (h)
- url_close(h);
+ ffurl_close(h);
}
ctx = &c->fmt_ctx;
if (av_strncasecmp(p, "Pragma:", 7) == 0) {
const char *q = p + 7;
- while (*q && *q != '\n' && isspace(*q))
+ while (*q && *q != '\n' && av_isspace(*q))
q++;
if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
if (stream_no < ratelen && stream_no >= 0)
rates[stream_no] = rate_no;
- while (*q && *q != '\n' && !isspace(*q))
+ while (*q && *q != '\n' && !av_isspace(*q))
q++;
}
p = *pp;
skip_spaces(&p);
q = buf;
- while (!isspace(*p) && *p != '\0') {
+ while (!av_isspace(*p) && *p != '\0') {
if ((q - buf) < buf_size - 1)
*q++ = *p;
p++;
int quote;
p = *pp;
- while (isspace(*p)) p++;
+ while (av_isspace(*p)) p++;
q = buf;
quote = 0;
if (*p == '\"' || *p == '\'')
if (*p == quote)
break;
} else {
- if (isspace(*p))
+ if (av_isspace(*p))
break;
}
if (*p == '\0')
break;
line_num++;
p = line;
- while (isspace(*p))
+ while (av_isspace(*p))
p++;
if (*p == '\0' || *p == '#')
continue;
/* parse http request and prepare header */
static int http_parse_request(HTTPContext *c)
{
- char *p;
+ const char *p;
+ char *p1;
enum RedirType redir_type;
char cmd[32];
char info[1024], filename[1024];
FFStream *stream;
int i;
char ratebuf[32];
- char *useragent = 0;
+ const char *useragent = 0;
p = c->buffer;
- get_word(cmd, sizeof(cmd), (const char **)&p);
+ get_word(cmd, sizeof(cmd), &p);
av_strlcpy(c->method, cmd, sizeof(c->method));
if (!strcmp(cmd, "GET"))
else
return -1;
- get_word(url, sizeof(url), (const char **)&p);
+ get_word(url, sizeof(url), &p);
av_strlcpy(c->url, url, sizeof(c->url));
get_word(protocol, sizeof(protocol), (const char **)&p);
http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
/* find the filename and the optional info string in the request */
- p = strchr(url, '?');
- if (p) {
- av_strlcpy(info, p, sizeof(info));
- *p = '\0';
+ p1 = strchr(url, '?');
+ if (p1) {
+ av_strlcpy(info, p1, sizeof(info));
+ *p1 = '\0';
} else
info[0] = '\0';
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
useragent = p + 11;
- if (*useragent && *useragent != '\n' && isspace(*useragent))
+ if (*useragent && *useragent != '\n' && av_isspace(*useragent))
useragent++;
break;
}
}
if (redir_type != REDIR_NONE) {
- char *hostinfo = 0;
+ const char *hostinfo = 0;
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
if (av_strncasecmp(p, "Host:", 5) == 0) {
char *eoh;
char hostbuf[260];
- while (isspace(*hostinfo))
+ while (av_isspace(*hostinfo))
hostinfo++;
eoh = strchr(hostinfo, '\n');
case REDIR_SDP:
{
uint8_t *sdp_data;
- int sdp_data_size, len;
+ int sdp_data_size;
+ socklen_t len;
struct sockaddr_in my_addr;
q += snprintf(q, c->buffer_size,
if (!stream->is_feed) {
/* 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;
+ const char *logline = 0;
int client_id = 0;
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
static void fmt_bytecount(AVIOContext *pb, int64_t count)
{
- static const char *suffix = " kMGTP";
+ static const char suffix[] = " kMGTP";
const char *s;
for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
c->buffer_end = c->pb_buffer + len;
}
-/* check if the parser needs to be opened for stream i */
-static void open_parser(AVFormatContext *s, int i)
-{
- AVStream *st = s->streams[i];
- AVCodec *codec;
-
- if (!st->codec->codec) {
- codec = avcodec_find_decoder(st->codec->codec_id);
- if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
- st->codec->parse_only = 1;
- if (avcodec_open2(st->codec, codec, NULL) < 0)
- st->codec->parse_only = 0;
- }
- }
-}
-
static int open_input_stream(HTTPContext *c, const char *info)
{
char buf[128];
c->fmt_in = s;
if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
http_log("Could not find stream info '%s'\n", input_filename);
- av_close_input_file(s);
+ avformat_close_input(&s);
return -1;
}
- /* open each parser */
- for(i=0;i<s->nb_streams;i++)
- open_parser(s, i);
-
/* choose stream as clock source (we favorize video stream if
present) for packet sending */
c->pts_stream_index = 0;
* Default value from Libav
* Try to set it use configuration option
*/
- c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
return 0;
} else {
if (c->stream->loop) {
- av_close_input_file(c->fmt_in);
- c->fmt_in = NULL;
+ avformat_close_input(&c->fmt_in);
if (open_input_stream(c, "") < 0)
goto no_loop;
goto redo;
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]);
+ max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
} else {
ret = avio_open_dyn_buf(&ctx->pb);
} else {
/* send RTP packet directly in UDP */
c->buffer_ptr += 4;
- url_write(c->rtp_handles[c->packet_stream_index],
- c->buffer_ptr, len);
+ ffurl_write(c->rtp_handles[c->packet_stream_index],
+ c->buffer_ptr, len);
c->buffer_ptr += len;
/* here we continue as we can send several packets per 10 ms slot */
}
if (c->stream->truncate) {
/* truncate feed file */
ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
- ftruncate(c->feed_fd, FFM_PACKET_SIZE);
http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
+ if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
+ http_log("Error truncating feed file: %s\n", strerror(errno));
+ return -1;
+ }
} else {
if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
http_log("Error reading write index from feed file: %s\n", strerror(errno));
/* a packet has been received : write it in the store, except
if header */
if (c->data_count > FFM_PACKET_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);
if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
/* Now we have the actual streams */
if (s->nb_streams != feed->nb_streams) {
- av_close_input_stream(s);
+ avformat_close_input(&s);
av_free(pb);
http_log("Feed '%s' stream number does not match registered feed\n",
c->stream->feed_filename);
avcodec_copy_context(fst->codec, st->codec);
}
- av_close_input_stream(s);
+ avformat_close_input(&s);
av_free(pb);
}
c->buffer_ptr = c->buffer;
char protocol[32];
char line[1024];
int len;
- RTSPMessageHeader header1, *header = &header1;
+ RTSPMessageHeader header1 = { 0 }, *header = &header1;
c->buffer_ptr[0] = '\0';
p = c->buffer;
}
/* parse each header line */
- memset(header, 0, sizeof(*header));
/* skip to next line */
while (*p != '\n' && *p != '\0')
p++;
char path1[1024];
const char *path;
uint8_t *content;
- int content_length, len;
+ int content_length;
+ socklen_t len;
struct sockaddr_in my_addr;
/* find which url is asked */
"rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
}
- if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
+ if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
goto fail;
c->rtp_handles[stream_index] = h;
- max_packet_size = url_get_max_packet_size(h);
+ max_packet_size = h->max_packet_size;
break;
case RTSP_LOWER_TRANSPORT_TCP:
/* RTP/TCP case */
if (avformat_write_header(ctx, NULL) < 0) {
fail:
if (h)
- url_close(h);
+ ffurl_close(h);
av_free(ctx);
return -1;
}
}
fst->priv_data = av_mallocz(sizeof(FeedData));
fst->index = stream->nb_streams;
- av_set_pts_info(fst, 33, 1, 90000);
+ avpriv_set_pts_info(fst, 33, 1, 90000);
fst->sample_aspect_ratio = codec->sample_aspect_ratio;
stream->streams[stream->nb_streams++] = fst;
return fst;
AVStream *st;
const uint8_t *p;
+ infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
+
mpeg4_count = 0;
for(i=0;i<infile->nb_streams;i++) {
st = infile->streams[i];
- if (st->codec->codec_id == CODEC_ID_MPEG4 &&
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
st->codec->extradata_size == 0) {
mpeg4_count++;
}
printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
while (mpeg4_count > 0) {
- if (av_read_packet(infile, &pkt) < 0)
+ if (av_read_frame(infile, &pkt) < 0)
break;
st = infile->streams[pkt.stream_index];
- if (st->codec->codec_id == CODEC_ID_MPEG4 &&
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
st->codec->extradata_size == 0) {
av_freep(&st->codec->extradata);
/* fill extradata with the header */
if (avformat_find_stream_info(infile, NULL) < 0) {
http_log("Could not find codec parameters from '%s'\n",
stream->feed_filename);
- av_close_input_file(infile);
+ avformat_close_input(&infile);
goto fail;
}
extract_mpeg4_header(infile);
for(i=0;i<infile->nb_streams;i++)
add_av_stream1(stream, infile->streams[i]->codec, 1);
- av_close_input_file(infile);
+ avformat_close_input(&infile);
}
}
}
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);
+ avformat_close_input(&s);
} else
http_log("Deleting feed file '%s' as it appears to be corrupt\n",
feed->feed_filename);
memcpy(st->codec, av, sizeof(AVCodecContext));
}
-static enum CodecID opt_audio_codec(const char *arg)
+static enum AVCodecID opt_audio_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
- return CODEC_ID_NONE;
+ return AV_CODEC_ID_NONE;
return p->id;
}
-static enum CodecID opt_video_codec(const char *arg)
+static enum AVCodecID opt_video_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
- return CODEC_ID_NONE;
+ return AV_CODEC_ID_NONE;
return p->id;
}
static int avserver_opt_preset(const char *arg,
AVCodecContext *avctx, int type,
- enum CodecID *audio_id, enum CodecID *video_id)
+ enum AVCodecID *audio_id, enum AVCodecID *video_id)
{
FILE *f=NULL;
char filename[1000], tmp[1000], tmp2[1000], line[1000];
FFStream **last_stream, *stream, *redirect;
FFStream **last_feed, *feed, *s;
AVCodecContext audio_enc, video_enc;
- enum CodecID audio_id, video_id;
+ enum AVCodecID audio_id, video_id;
f = fopen(filename, "r");
if (!f) {
stream = NULL;
feed = NULL;
redirect = NULL;
- audio_id = CODEC_ID_NONE;
- video_id = CODEC_ID_NONE;
+ audio_id = AV_CODEC_ID_NONE;
+ video_id = AV_CODEC_ID_NONE;
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
for(;;) {
break;
line_num++;
p = line;
- while (isspace(*p))
+ while (av_isspace(*p))
p++;
if (*p == '\0' || *p == '#')
continue;
if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
}
- } else if (!av_strcasecmp(cmd, "NoDaemon")) {
- avserver_daemon = 0;
} else if (!av_strcasecmp(cmd, "RTSPPort")) {
get_arg(arg, sizeof(arg), &p);
val = atoi(arg);
get_arg(arg, sizeof(arg), &p);
p1 = arg;
fsize = strtod(p1, &p1);
- switch(toupper(*p1)) {
+ switch(av_toupper(*p1)) {
case 'K':
fsize *= 1024;
break;
stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
avcodec_get_context_defaults3(&video_enc, NULL);
avcodec_get_context_defaults3(&audio_enc, NULL);
- audio_id = CODEC_ID_NONE;
- video_id = CODEC_ID_NONE;
+ audio_id = AV_CODEC_ID_NONE;
+ video_id = AV_CODEC_ID_NONE;
if (stream->fmt) {
audio_id = stream->fmt->audio_codec;
video_id = stream->fmt->video_codec;
} else if (!av_strcasecmp(cmd, "AudioCodec")) {
get_arg(arg, sizeof(arg), &p);
audio_id = opt_audio_codec(arg);
- if (audio_id == CODEC_ID_NONE) {
+ if (audio_id == AV_CODEC_ID_NONE) {
ERROR("Unknown AudioCodec: %s\n", arg);
}
} else if (!av_strcasecmp(cmd, "VideoCodec")) {
get_arg(arg, sizeof(arg), &p);
video_id = opt_video_codec(arg);
- if (video_id == CODEC_ID_NONE) {
+ if (video_id == AV_CODEC_ID_NONE) {
ERROR("Unknown VideoCodec: %s\n", arg);
}
} else if (!av_strcasecmp(cmd, "MaxTime")) {
ERROR("VideoQMin out of range\n");
}
}
- } else if (!av_strcasecmp(cmd, "LumaElim")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- video_enc.luma_elim_threshold = atoi(arg);
- } else if (!av_strcasecmp(cmd, "ChromaElim")) {
- get_arg(arg, sizeof(arg), &p);
- if (stream)
- video_enc.chroma_elim_threshold = atoi(arg);
} else if (!av_strcasecmp(cmd, "LumiMask")) {
get_arg(arg, sizeof(arg), &p);
if (stream)
if (stream)
video_enc.dark_masking = atof(arg);
} else if (!av_strcasecmp(cmd, "NoVideo")) {
- video_id = CODEC_ID_NONE;
+ video_id = AV_CODEC_ID_NONE;
} else if (!av_strcasecmp(cmd, "NoAudio")) {
- audio_id = CODEC_ID_NONE;
+ audio_id = AV_CODEC_ID_NONE;
} else if (!av_strcasecmp(cmd, "ACL")) {
parse_acl_row(stream, feed, NULL, p, filename, line_num);
} else if (!av_strcasecmp(cmd, "DynamicACL")) {
ERROR("No corresponding <Stream> for </Stream>\n");
} else {
if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
- if (audio_id != CODEC_ID_NONE) {
+ if (audio_id != AV_CODEC_ID_NONE) {
audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
audio_enc.codec_id = audio_id;
add_codec(stream, &audio_enc);
}
- if (video_id != CODEC_ID_NONE) {
+ if (video_id != AV_CODEC_ID_NONE) {
video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
video_enc.codec_id = video_id;
add_codec(stream, &video_enc);
static void opt_debug(void)
{
avserver_debug = 1;
- avserver_daemon = 0;
logfilename[0] = '-';
}
-static void show_help(void)
+void show_help_default(const char *opt, const char *arg)
{
printf("usage: avserver [options]\n"
"Hyper fast multi format Audio/Video streaming server\n");
printf("\n");
- show_help_options(options, "Main options:\n", 0, 0);
+ show_help_options(options, "Main options:", 0, 0, 0);
}
static const OptionDef options[] = {
int main(int argc, char **argv)
{
- struct sigaction sigact;
+ struct sigaction sigact = { { 0 } };
parse_loglevel(argc, argv, options);
av_register_all();
+ avformat_network_init();
show_banner();
my_program_name = argv[0];
- my_program_dir = getcwd(0, 0);
- avserver_daemon = 1;
parse_options(NULL, argc, argv, options, NULL);
av_lfg_init(&random_state, av_get_random_seed());
- memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;
sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
sigaction(SIGCHLD, &sigact, 0);
compute_bandwidth();
- /* put the process in background and detach it from its TTY */
- if (avserver_daemon) {
- int pid;
-
- pid = fork();
- if (pid < 0) {
- perror("fork");
- exit(1);
- } else if (pid > 0) {
- /* parent : exit */
- exit(0);
- } else {
- /* child */
- setsid();
- close(0);
- open("/dev/null", O_RDWR);
- if (strcmp(logfilename, "-") != 0) {
- close(1);
- dup(0);
- }
- close(2);
- dup(0);
- }
- }
-
/* signal init */
signal(SIGPIPE, SIG_IGN);
- if (avserver_daemon)
- chdir("/");
-
if (http_server() < 0) {
http_log("Could not start server\n");
exit(1);