#include <string.h>
#include <stdlib.h>
#include "avformat.h"
+#include "rtsp.h"
+#include "rtp.h"
+#include "os_support.h"
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
#endif
#include <errno.h>
#include <sys/time.h>
#include "ffserver.h"
#include "random.h"
#include "avstring.h"
+#include "cmdutils.h"
#undef exit
+static const char program_name[] = "FFserver";
+static const int program_birth_year = 2000;
+
/* maximum number of simultaneous HTTP connections */
#define HTTP_MAX_CONNECTIONS 2000
int conns_served;
int64_t bytes_served;
int64_t feed_max_size; /* maximum storage size, zero means unlimited */
- int64_t feed_write_index; /* current write position in feed (it wraps round) */
+ int64_t feed_write_index; /* current write position in feed (it wraps around) */
int64_t feed_size; /* current size of feed */
struct FFStream *next_feed;
} FFStream;
typedef struct FeedData {
long long data_count;
- float avg_frame_size; /* frame size averraged over last frames with exponential mean */
+ float avg_frame_size; /* frame size averaged over last frames with exponential mean */
} FeedData;
static struct sockaddr_in my_http_addr;
/* prepare header */
if (url_open_dyn_buf(&ctx->pb) >= 0) {
av_write_trailer(ctx);
- url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ url_close_dyn_buf(ctx->pb, &c->pb_buffer);
}
}
}
char *p;
time_t ti;
int i, len;
- ByteIOContext pb1, *pb = &pb1;
+ ByteIOContext *pb;
- if (url_open_dyn_buf(pb) < 0) {
+ if (url_open_dyn_buf(&pb) < 0) {
/* XXX: return an error ? */
c->buffer_ptr = c->buffer;
c->buffer_end = c->buffer;
strcpy(eosf - 4, ".asx");
else if (strcmp(eosf - 3, ".rm") == 0)
strcpy(eosf - 3, ".ram");
- else if (stream->fmt == &rtp_muxer) {
+ else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
/* generate a sample RTSP director if
unicast. Generate an SDP redirector if
multicast */
buf_size = FFM_PACKET_SIZE;
/* compute position (absolute time) */
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)) {
int prebuffer = strtol(buf, 0, 10);
stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
buf_size = 0;
/* compute position (relative time) */
if (find_info_tag(buf, sizeof(buf), "date", info))
+ {
stream_pos = parse_date(buf, 1);
+ if (stream_pos == INT64_MIN)
+ return -1;
+ }
else
stream_pos = 0;
}
http_log("%s not found", input_filename);
return -1;
}
+ s->flags |= AVFMT_FLAG_GENPTS;
c->fmt_in = s;
+ av_find_stream_info(c->fmt_in);
/* open each parser */
for(i=0;i<s->nb_streams;i++)
/* XXX: potential leak */
return -1;
}
- c->fmt_ctx.pb.is_streamed = 1;
+ c->fmt_ctx.pb->is_streamed = 1;
av_set_parameters(&c->fmt_ctx, NULL);
if (av_write_header(&c->fmt_ctx) < 0)
return -1;
- len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
+ len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
if (av_write_frame(ctx, &pkt))
c->state = HTTPSTATE_SEND_DATA_TRAILER;
- len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->cur_frame_bytes = len;
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
return -1;
}
av_write_trailer(ctx);
- len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
/* RTP packets are sent inside the RTSP TCP connection */
- ByteIOContext pb1, *pb = &pb1;
+ ByteIOContext *pb;
int interleaved_index, size;
uint8_t header[4];
HTTPContext *rtsp_c;
/* if already sending something, then wait. */
if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
break;
- if (url_open_dyn_buf(pb) < 0)
+ if (url_open_dyn_buf(&pb) < 0)
goto fail1;
interleaved_index = c->packet_stream_index * 2;
/* RTCP packets are sent at odd indexes */
/* We have a header in our hands that contains useful data */
AVFormatContext s;
AVInputFormat *fmt_in;
- ByteIOContext *pb = &s.pb;
int i;
memset(&s, 0, sizeof(s));
- url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
- pb->buf_end = c->buffer_end; /* ?? */
- pb->is_streamed = 1;
+ url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
+ s.pb->is_streamed = 1;
/* use feed output format name to find corresponding input format */
fmt_in = av_find_input_format(feed->fmt->name);
char url[1024];
char protocol[32];
char line[1024];
- ByteIOContext pb1;
int len;
RTSPHeader header1, *header = &header1;
av_strlcpy(c->url, url, sizeof(c->url));
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
- c->pb = &pb1;
- if (url_open_dyn_buf(c->pb) < 0) {
+ if (url_open_dyn_buf(&c->pb) < 0) {
/* XXX: cannot do more */
c->pb = NULL; /* safety */
return -1;
return 0;
}
-/* XXX: move that to rtsp.c, but would need to replace FFStream by
- AVFormatContext */
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
struct in_addr my_ip)
{
- ByteIOContext pb1, *pb = &pb1;
- int i, payload_type, port, private_payload_type, j;
- const char *ipstr, *title, *mediatype;
- AVStream *st;
+ AVFormatContext *avc;
+ AVStream avs[MAX_STREAMS];
+ int i;
- if (url_open_dyn_buf(pb) < 0)
+ avc = av_alloc_format_context();
+ if (avc == NULL) {
return -1;
+ }
+ if (stream->title[0] != 0) {
+ av_strlcpy(avc->title, stream->title, sizeof(avc->title));
+ } else {
+ av_strlcpy(avc->title, "No Title", sizeof(avc->title));
+ }
+ avc->nb_streams = stream->nb_streams;
+ if (stream->is_multicast) {
+ snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
+ inet_ntoa(stream->multicast_ip),
+ stream->multicast_port, stream->multicast_ttl);
+ }
- /* general media info */
-
- url_fprintf(pb, "v=0\n");
- ipstr = inet_ntoa(my_ip);
- url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
- title = stream->title;
- if (title[0] == '\0')
- title = "No Title";
- url_fprintf(pb, "s=%s\n", title);
- if (stream->comment[0] != '\0')
- url_fprintf(pb, "i=%s\n", stream->comment);
- if (stream->is_multicast)
- url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
-
- /* for each stream, we output the necessary info */
- private_payload_type = RTP_PT_PRIVATE;
for(i = 0; i < stream->nb_streams; i++) {
- st = stream->streams[i];
- if (st->codec->codec_id == CODEC_ID_MPEG2TS)
- mediatype = "video";
- else {
- switch(st->codec->codec_type) {
- case CODEC_TYPE_AUDIO:
- mediatype = "audio";
- break;
- case CODEC_TYPE_VIDEO:
- mediatype = "video";
- break;
- default:
- mediatype = "application";
- break;
- }
- }
- /* NOTE: the port indication is not correct in case of
- unicast. It is not an issue because RTSP gives it */
- payload_type = rtp_get_payload_type(st->codec);
- if (payload_type < 0)
- payload_type = private_payload_type++;
- if (stream->is_multicast)
- port = stream->multicast_port + 2 * i;
- else
- port = 0;
-
- url_fprintf(pb, "m=%s %d RTP/AVP %d\n",
- mediatype, port, payload_type);
- if (payload_type >= RTP_PT_PRIVATE) {
- /* for private payload type, we need to give more info */
- switch(st->codec->codec_id) {
- case CODEC_ID_MPEG4:
- {
- uint8_t *data;
- url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n",
- payload_type, 90000);
- /* we must also add the mpeg4 header */
- data = st->codec->extradata;
- if (data) {
- url_fprintf(pb, "a=fmtp:%d config=", payload_type);
- for(j=0;j<st->codec->extradata_size;j++)
- url_fprintf(pb, "%02x", data[j]);
- url_fprintf(pb, "\n");
- }
- }
- break;
- default:
- /* XXX: add other codecs ? */
- goto fail;
- }
- }
- url_fprintf(pb, "a=control:streamid=%d\n", i);
+ avc->streams[i] = &avs[i];
+ avc->streams[i]->codec = stream->streams[i]->codec;
}
- return url_close_dyn_buf(pb, pbuffer);
- fail:
- url_close_dyn_buf(pb, pbuffer);
- av_free(*pbuffer);
- return -1;
+ *pbuffer = av_mallocz(2048);
+ avf_sdp_create(&avc, 1, *pbuffer, 2048);
+ av_free(avc);
+
+ return strlen(*pbuffer);
}
static void rtsp_cmd_options(HTTPContext *c, const char *url)
path++;
for(stream = first_stream; stream != NULL; stream = stream->next) {
- if (!stream->is_feed && stream->fmt == &rtp_muxer &&
+ if (!stream->is_feed &&
+ stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
!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_muxer) {
+ if (!stream->is_feed &&
+ stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
/* accept aggregate filenames only if single stream */
if (!strcmp(path, stream->filename)) {
if (stream->nb_streams != 1) {
ctx = av_alloc_format_context();
if (!ctx)
return -1;
- ctx->oformat = &rtp_muxer;
+ ctx->oformat = guess_format("rtp", NULL, NULL);
st = av_mallocz(sizeof(AVStream));
if (!st)
av_free(ctx);
return -1;
}
- url_close_dyn_buf(&ctx->pb, &dummy_buf);
+ url_close_dyn_buf(ctx->pb, &dummy_buf);
av_free(dummy_buf);
c->rtp_ctx[stream_index] = ctx;
/* try to open the file */
/* open stream */
stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
- if (stream->fmt == &rtp_muxer) {
+ if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
/* specific case : if transport stream output to RTP,
we use a raw transport stream reader */
stream->ap_in->mpeg2ts_raw = 1;
}
/* XXX: need better api */
av_freep(&s->priv_data);
- url_fclose(&s->pb);
+ url_fclose(s->pb);
}
/* get feed size and write index */
fd = open(feed->feed_filename, O_RDONLY);
static int opt_audio_codec(const char *arg)
{
- AVCodec *p;
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
- p = first_avcodec;
- while (p) {
- if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
- break;
- p = p->next;
- }
- if (p == NULL)
+ if (p == NULL || p->type != CODEC_TYPE_AUDIO)
return CODEC_ID_NONE;
return p->id;
static int opt_video_codec(const char *arg)
{
- AVCodec *p;
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
- p = first_avcodec;
- while (p) {
- if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
- break;
- p = p->next;
- }
- if (p == NULL)
+ if (p == NULL || p->type != CODEC_TYPE_VIDEO)
return CODEC_ID_NONE;
return p->id;
if (feed) {
int i;
- feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
+ feed->child_argv = av_mallocz(64 * sizeof(char *));
for (i = 0; i < 62; i++) {
get_arg(arg, sizeof(arg), &p);
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
} else if (!strcasecmp(cmd, "FileMaxSize")) {
if (feed) {
- const char *p1;
+ char *p1;
double fsize;
get_arg(arg, sizeof(arg), &p);
p1 = arg;
- fsize = strtod(p1, (char **)&p1);
+ fsize = strtod(p1, &p1);
switch(toupper(*p1)) {
case 'K':
fsize *= 1024;
}
if (!errors) {
- IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
+ IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
IPAddressACL **naclp = 0;
acl.next = 0;
return 0;
}
-static void show_banner(void)
-{
- printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
-}
-
static void show_help(void)
{
- show_banner();
printf("usage: ffserver [-L] [-h] [-f configfile]\n"
"Hyper fast multi format Audio/Video streaming server\n"
"\n"
);
}
-static void show_license(void)
-{
- show_banner();
- printf(
- "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.1 of the License, or (at your option) any later version.\n"
- "\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 FFmpeg; if not, write to the Free Software\n"
- "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
- );
-}
-
static void handle_child_exit(int sig)
{
pid_t pid;
av_register_all();
+ show_banner(program_name, program_birth_year);
+
config_filename = "/etc/ffserver.conf";
my_program_name = argv[0];