#include <stdio.h>
#include "libavformat/avformat.h"
/* FIXME: those are internal headers, ffserver _really_ shouldn't use them */
-#include "libavformat/ffm.h"
-#include "libavformat/network.h"
-#include "libavformat/os_support.h"
-#include "libavformat/rtpdec.h"
#include "libavformat/rtpproto.h"
#include "libavformat/rtsp.h"
-#include "libavformat/rtspcodes.h"
#include "libavformat/avio_internal.h"
#include "libavformat/internal.h"
-#include "libavformat/url.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/random_seed.h"
+#include "libavutil/rational.h"
#include "libavutil/parseutils.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
int switch_pending;
- AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
+ AVFormatContext *pfmt_ctx; /* instance of FFServerStream for one user */
int last_packet_sent; /* true if last data packet was sent */
int suppress_log;
DataRateData datarate;
/* utils */
static size_t htmlencode (const char *src, char **dest);
static inline void cp_html_entity (char *buffer, const char *entity);
-static inline int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs,
- int stream);
+static inline int check_codec_match(AVStream *ccf, AVStream *ccs, int stream);
static const char *my_program_name;
ffurl_close(c->rtp_handles[i]);
}
- ctx = &c->fmt_ctx;
+ ctx = c->pfmt_ctx;
- if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
- /* prepare header */
- if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
- av_write_trailer(ctx);
- av_freep(&c->pb_buffer);
- avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
+ if (ctx) {
+ if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
+ /* prepare header */
+ if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
+ av_write_trailer(ctx);
+ av_freep(&c->pb_buffer);
+ avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
+ }
+ }
+ for(i=0; i<ctx->nb_streams; i++)
+ av_freep(&ctx->streams[i]);
+ av_freep(&ctx->streams);
+ av_freep(&ctx->priv_data);
}
- }
-
- for(i=0; i<ctx->nb_streams; i++)
- av_freep(&ctx->streams[i]);
- av_freep(&ctx->streams);
- av_freep(&ctx->priv_data);
if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
current_bandwidth -= c->stream->bandwidth;
return 0;
}
-static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
+static int find_stream_in_feed(FFServerStream *feed, AVCodecParameters *codec,
int bit_rate)
{
int i;
int best = -1;
for (i = 0; i < feed->nb_streams; i++) {
- AVCodecContext *feed_codec = feed->streams[i]->codec;
+ AVCodecParameters *feed_codec = feed->streams[i]->codecpar;
if (feed_codec->codec_id != codec->codec_id ||
feed_codec->sample_rate != codec->sample_rate ||
return 0;
for (i = 0; i < req->nb_streams; i++) {
- AVCodecContext *codec = req->streams[i]->codec;
+ AVCodecParameters *codec = req->streams[i]->codecpar;
switch(rates[i]) {
case 0:
const char *p;
char *q;
+#define SPACE_CHARS " \t\r\n"
+
p = *pp;
p += strspn(p, SPACE_CHARS);
q = buf;
memcpy(q, sdp_data, sdp_data_size);
q += sdp_data_size;
*q = '\0';
- av_free(sdp_data);
+ av_freep(&sdp_data);
}
}
break;
for (i = 0; i < stream_no; i++) {
st = stream->streams[i];
- codec = avcodec_find_encoder(st->codec->codec_id);
+ codec = avcodec_find_encoder(st->codecpar->codec_id);
parameters[0] = 0;
- switch(st->codec->codec_type) {
+ switch(st->codecpar->codec_type) {
case AVMEDIA_TYPE_AUDIO:
type = "audio";
snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
- st->codec->channels, st->codec->sample_rate);
+ st->codecpar->channels, st->codecpar->sample_rate);
break;
case AVMEDIA_TYPE_VIDEO:
type = "video";
snprintf(parameters, sizeof(parameters),
- "%dx%d, q=%d-%d, fps=%d", st->codec->width,
- st->codec->height, st->codec->qmin, st->codec->qmax,
- st->codec->time_base.den / st->codec->time_base.num);
+ "%dx%d, q=%d-%d, fps=%d", st->codecpar->width,
+ st->codecpar->height, st->codec->qmin, st->codec->qmax,
+ st->time_base.den / st->time_base.num);
break;
default:
abort();
avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%"PRId64
"<td>%s<td>%s\n",
- i, type, (int64_t)st->codec->bit_rate/1000,
+ i, type, (int64_t)st->codecpar->bit_rate/1000,
codec ? codec->name : "", parameters);
}
for(i=0;i<stream->nb_streams;i++) {
AVStream *st = stream->streams[i];
- AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
+ AVCodec *codec = avcodec_find_encoder(st->codecpar->codec_id);
- switch(st->codec->codec_type) {
+ switch(st->codecpar->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- audio_bit_rate += st->codec->bit_rate;
+ audio_bit_rate += st->codecpar->bit_rate;
if (codec) {
if (*audio_codec_name)
audio_codec_name_extra = "...";
}
break;
case AVMEDIA_TYPE_VIDEO:
- video_bit_rate += st->codec->bit_rate;
+ video_bit_rate += st->codecpar->bit_rate;
if (codec) {
if (*video_codec_name)
video_codec_name_extra = "...";
}
break;
case AVMEDIA_TYPE_DATA:
- video_bit_rate += st->codec->bit_rate;
+ video_bit_rate += st->codecpar->bit_rate;
break;
default:
abort();
if (c1->stream) {
for (j = 0; j < c1->stream->nb_streams; j++) {
if (!c1->stream->feed)
- bitrate += c1->stream->streams[j]->codec->bit_rate;
+ bitrate += c1->stream->streams[j]->codecpar->bit_rate;
else if (c1->feed_streams[j] >= 0)
- bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
+ bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codecpar->bit_rate;
}
}
c->pts_stream_index = 0;
for(i=0;i<c->stream->nb_streams;i++) {
if (c->pts_stream_index == 0 &&
- c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ c->stream->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
c->pts_stream_index = i;
}
}
ctx = avformat_alloc_context();
if (!ctx)
return AVERROR(ENOMEM);
- c->fmt_ctx = *ctx;
- av_freep(&ctx);
- av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
- c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
+ c->pfmt_ctx = ctx;
+ av_dict_copy(&(c->pfmt_ctx->metadata), c->stream->metadata, 0);
+ c->pfmt_ctx->streams = av_mallocz_array(c->stream->nb_streams,
sizeof(AVStream *));
- if (!c->fmt_ctx.streams)
+ if (!c->pfmt_ctx->streams)
return AVERROR(ENOMEM);
for(i=0;i<c->stream->nb_streams;i++) {
AVStream *src;
- c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
+ c->pfmt_ctx->streams[i] = av_mallocz(sizeof(AVStream));
/* if file or feed, then just take streams from FFServerStream
* struct */
else
src = c->stream->feed->streams[c->stream->feed_streams[i]];
- *(c->fmt_ctx.streams[i]) = *src;
- c->fmt_ctx.streams[i]->priv_data = 0;
+ *(c->pfmt_ctx->streams[i]) = *src;
+ c->pfmt_ctx->streams[i]->priv_data = 0;
/* XXX: should be done in AVStream, not in codec */
- c->fmt_ctx.streams[i]->codec->frame_number = 0;
+ c->pfmt_ctx->streams[i]->codec->frame_number = 0;
}
/* set output format parameters */
- c->fmt_ctx.oformat = c->stream->fmt;
- c->fmt_ctx.nb_streams = c->stream->nb_streams;
+ c->pfmt_ctx->oformat = c->stream->fmt;
+ c->pfmt_ctx->nb_streams = c->stream->nb_streams;
c->got_key_frame = 0;
/* prepare header and save header data in a stream */
- if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
+ if (avio_open_dyn_buf(&c->pfmt_ctx->pb) < 0) {
/* XXX: potential leak */
return -1;
}
- c->fmt_ctx.pb->seekable = 0;
+ c->pfmt_ctx->pb->seekable = 0;
/*
* HACK to avoid MPEG-PS muxer to spit many underflow errors
* Default value from FFmpeg
* Try to set it using configuration option
*/
- c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
+ c->pfmt_ctx->max_delay = (int)(0.7*AV_TIME_BASE);
- if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
+ if ((ret = avformat_write_header(c->pfmt_ctx, NULL)) < 0) {
http_log("Error writing output header for stream '%s': %s\n",
c->stream->filename, av_err2str(ret));
return ret;
}
- av_dict_free(&c->fmt_ctx.metadata);
+ av_dict_free(&c->pfmt_ctx->metadata);
- len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
+ len = avio_close_dyn_buf(c->pfmt_ctx->pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
/* only one stream per RTP connection */
pkt.stream_index = 0;
} else {
- ctx = &c->fmt_ctx;
+ ctx = c->pfmt_ctx;
/* Fudge here */
codec = ctx->streams[pkt.stream_index]->codec;
}
/* last packet test ? */
if (c->last_packet_sent || c->is_packetized)
return -1;
- ctx = &c->fmt_ctx;
+ ctx = c->pfmt_ctx;
/* prepare header */
if (avio_open_dyn_buf(&ctx->pb) < 0) {
/* XXX: potential leak */
return -1;
}
- c->fmt_ctx.pb->seekable = 0;
+ c->pfmt_ctx->pb->seekable = 0;
av_write_trailer(ctx);
len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
avcodec_parameters_from_context(stream->streams[i]->codecpar, stream->streams[i]->codec);
avc->streams[i]->codecpar = stream->streams[i]->codecpar;
}
- *pbuffer = av_mallocz(2048);
+#define PBUFFER_SIZE 2048
+ *pbuffer = av_mallocz(PBUFFER_SIZE);
if (!*pbuffer)
goto sdp_done;
- av_sdp_create(&avc, 1, *pbuffer, 2048);
+ av_sdp_create(&avc, 1, *pbuffer, PBUFFER_SIZE);
sdp_done:
av_freep(&avc->streams);
}
static inline
-int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs, int stream)
+int check_codec_match(AVStream *ccf, AVStream *ccs, int stream)
{
int matches = 1;
-#define CHECK_CODEC(x) (ccf->x != ccs->x)
+/* FIXME: Missed check on AVCodecContext.flags */
+#define CHECK_CODEC(x) (ccf->codecpar->x != ccs->codecpar->x)
if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
http_log("Codecs do not match for stream %d\n", stream);
matches = 0;
- } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
+ } else if (CHECK_CODEC(bit_rate)) {
http_log("Codec bitrates do not match for stream %d\n", stream);
matches = 0;
- } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (CHECK_CODEC(time_base.den) ||
- CHECK_CODEC(time_base.num) ||
- CHECK_CODEC(width) ||
- CHECK_CODEC(height)) {
+ } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (av_cmp_q(ccf->time_base, ccs->time_base) ||
+ CHECK_CODEC(width) || CHECK_CODEC(height)) {
http_log("Codec width, height or framerate do not match for stream %d\n", stream);
matches = 0;
}
- } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
+ } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (CHECK_CODEC(sample_rate) ||
CHECK_CODEC(channels) ||
CHECK_CODEC(frame_size)) {
break;
}
- matches = check_codec_match (sf->codec, ss->codec, i);
+ matches = check_codec_match (sf, ss, i);
if (!matches)
break;
}
int cfg_parsed;
int ret = EXIT_FAILURE;
+ init_dynload();
config.filename = av_strdup("/etc/ffserver.conf");