summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ffserver.conf21
-rw-r--r--ffserver.c76
2 files changed, 97 insertions, 0 deletions
diff --git a/doc/ffserver.conf b/doc/ffserver.conf
index 2fbfecd683..217117005c 100644
--- a/doc/ffserver.conf
+++ b/doc/ffserver.conf
@@ -306,6 +306,27 @@ StartSendOnKey
#</Stream>
+# Transcode an incoming live feed to another live feed,
+# using libx264 and video presets
+
+#<Stream live.h264>
+#Format rtp
+#Feed feed1.ffm
+#VideoCodec libx264
+#VideoFrameRate 24
+#VideoBitRate 100
+#VideoSize 480x272
+#AVPresetVideo default
+#AVPresetVideo baseline
+#AVOptionVideo flags +global_header
+#
+#AudioCodec libfaac
+#AudioBitRate 32
+#AudioChannels 2
+#AudioSampleRate 22050
+#AVOptionAudio flags +global_header
+#</Stream>
+
##################################################################
# SDP/multicast examples
#
diff --git a/ffserver.c b/ffserver.c
index 6d1e710c6a..77340af3df 100644
--- a/ffserver.c
+++ b/ffserver.c
@@ -3949,6 +3949,65 @@ static int ffserver_opt_default(const char *opt, const char *arg,
return ret;
}
+static int ffserver_opt_preset(const char *arg,
+ AVCodecContext *avctx, int type,
+ enum CodecID *audio_id, enum CodecID *video_id)
+{
+ FILE *f=NULL;
+ char filename[1000], tmp[1000], tmp2[1000], line[1000];
+ int i, ret = 0;
+ const char *base[3]= { getenv("FFMPEG_DATADIR"),
+ getenv("HOME"),
+ FFMPEG_DATADIR,
+ };
+
+ for(i=0; i<3 && !f; i++){
+ if(!base[i])
+ continue;
+ snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", arg);
+ f= fopen(filename, "r");
+ if(!f){
+ AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
+ if (codec) {
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", codec->name, arg);
+ f= fopen(filename, "r");
+ }
+ }
+ }
+
+ if(!f){
+ fprintf(stderr, "File for preset '%s' not found\n", arg);
+ return 1;
+ }
+
+ while(!feof(f)){
+ int e= fscanf(f, "%999[^\n]\n", line) - 1;
+ if(line[0] == '#' && !e)
+ continue;
+ e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
+ if(e){
+ fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
+ ret = 1;
+ break;
+ }
+ if(!strcmp(tmp, "acodec")){
+ *audio_id = opt_audio_codec(tmp2);
+ }else if(!strcmp(tmp, "vcodec")){
+ *video_id = opt_video_codec(tmp2);
+ }else if(!strcmp(tmp, "scodec")){
+ /* opt_subtitle_codec(tmp2); */
+ }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
+ fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
+ ret = 1;
+ break;
+ }
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
const char *mime_type)
{
@@ -4403,6 +4462,23 @@ static int parse_ffconfig(const char *filename)
if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
ERROR("AVOption error: %s %s\n", arg, arg2);
}
+ } else if (!strcasecmp(cmd, "AVPresetVideo") ||
+ !strcasecmp(cmd, "AVPresetAudio")) {
+ AVCodecContext *avctx;
+ int type;
+ get_arg(arg, sizeof(arg), &p);
+ if (!strcasecmp(cmd, "AVPresetVideo")) {
+ avctx = &video_enc;
+ video_enc.codec_id = video_id;
+ type = AV_OPT_FLAG_VIDEO_PARAM;
+ } else {
+ avctx = &audio_enc;
+ audio_enc.codec_id = audio_id;
+ type = AV_OPT_FLAG_AUDIO_PARAM;
+ }
+ if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
+ ERROR("AVPreset error: %s\n", arg);
+ }
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)