[FFmpeg-devel] [PATCH] libavformat/fifo: Fix initialization of underlying AVFormatContext

2017-07-06 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Pass filename to AVFormatContext of underlying muxer.
This commit fixes bug #6308.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/fifo.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 2cbe5c5..c881f31 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -442,13 +442,14 @@ static void *fifo_consumer_thread(void *data)
 return NULL;
 }
 
-static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat)
+static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat,
+ const char *filename)
 {
 FifoContext *fifo = avf->priv_data;
 AVFormatContext *avf2;
 int ret = 0, i;
 
-ret = avformat_alloc_output_context2(, oformat, NULL, NULL);
+ret = avformat_alloc_output_context2(, oformat, NULL, filename);
 if (ret < 0)
 return ret;
 
@@ -505,7 +506,7 @@ static int fifo_init(AVFormatContext *avf)
 return ret;
 }
 
-ret = fifo_mux_init(avf, oformat);
+ret = fifo_mux_init(avf, oformat, avf->filename);
 if (ret < 0)
 return ret;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] libavformat/tee: Add possibility to pass fifo options by using fifo_ prefix

2016-12-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

---
 doc/muxers.texi   |  9 +
 libavformat/tee.c | 20 
 2 files changed, 29 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index ced223e..139ced0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1603,6 +1603,11 @@ outputs and setup transparent recovery. By default this 
feature is turned off.
 @item fifo_options
 Options to pass to fifo pseudo-muxer instances. See @ref{fifo}.
 
+@item fifo_[opt]
+Option will be passed as [opt] to fifo pseudo-muxer instances. For example
+fifo_queue_size will set queue_size option of fifo pseudo muxer.
+This allows to specify fifo_options without need of extensive escaping.
+
 @end table
 
 The slave outputs are specified in the file name given to the muxer,
@@ -1633,6 +1638,10 @@ This allows to override tee muxer use_fifo option for 
individual slave muxer.
 This allows to override tee muxer fifo_options for individual slave muxer.
 See @ref{fifo}.
 
+@item fifo_[opt]
+This allows to override tee muxer fifo_options by setting [opt] for fifo of
+individual slave muxer, without need of another level of escaping.
+
 It is possible to specify to which streams a given bitstream filter
 applies, by appending a stream specifier to the option separated by
 @code{/}. @var{spec} must be a stream specifier (see @ref{Format
diff --git a/libavformat/tee.c b/libavformat/tee.c
index 99259a7..7001e38 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -156,6 +156,23 @@ static void close_slaves(AVFormatContext *avf)
 av_freep(>slaves);
 }
 
+static int steal_fifo_options(AVDictionary **src_options, AVDictionary 
**dst_options)
+{
+int ret;
+AVDictionaryEntry *entry;
+
+while((entry = av_dict_get(*src_options, "fifo_", NULL, 
AV_DICT_IGNORE_SUFFIX))) {
+ret = av_dict_set(dst_options, entry->key + 5, /* 5 = strlen("fifo_") 
*/
+  entry->value, AV_DICT_DONT_STRDUP_VAL);
+if (ret < 0)
+return ret;
+
+entry->value = NULL;
+ret = av_dict_set(src_options, entry->key, NULL, 0);
+}
+return 0;
+}
+
 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
 {
 int i, ret;
@@ -186,6 +203,9 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 STEAL_OPTION("onfail", on_fail);
 STEAL_OPTION("use_fifo", use_fifo);
 STEAL_OPTION("fifo_options", fifo_options_str);
+ret = steal_fifo_options(, _slave->fifo_options);
+if (ret < 0)
+goto end;
 
 ret = parse_slave_failure_policy_option(on_fail, tee_slave);
 if (ret < 0) {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 0/2] Fifo support for tee

2016-12-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Hello,
I am re-sending the patch(es) adding support for fifo pseudo-muxer in tee muxer.
I will apply the first one in few days (since it already has been reviewed by 
Nicolas,
and it differs only in issues Nicolas pointed out in review and these should be 
fixed now).
The second one adds feature suggested by Nicolas - possibility to pass options 
to fifo 
muxer by prefixing fifo options with fifo_ string. 

I will wait with that second patch for a reaction.

Thanks,
Jan

Jan Sebechlebsky (2):
  libavformat/tee: Add fifo support for tee
  libavformat/tee: Add possibility to pass fifo options by using fifo_
prefix

 doc/muxers.texi   |  29 +++
 libavformat/tee.c | 105 +-
 2 files changed, 133 insertions(+), 1 deletion(-)

-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 1/2] libavformat/tee: Add fifo support for tee

2016-12-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Refactoring based on Nicolas's comments
 - Added TODO regarding boolean option parsing

 doc/muxers.texi   | 20 +
 libavformat/tee.c | 87 ++-
 2 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 075b8d3..ced223e 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1485,6 +1485,7 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@anchor{fifo}
 @section fifo
 
 The fifo pseudo-muxer allows the separation of encoding and muxing by using
@@ -1592,6 +1593,18 @@ with the tee muxer; encoding can be a very expensive 
process. It is not
 useful when using the libavformat API directly because it is then possible
 to feed the same packets to several muxers directly.
 
+@table @option
+
+@item use_fifo @var{bool}
+If set to 1, slave outputs will be processed in separate thread using 
@ref{fifo}
+muxer. This allows to compensate for different speed/latency/reliability of
+outputs and setup transparent recovery. By default this feature is turned off.
+
+@item fifo_options
+Options to pass to fifo pseudo-muxer instances. See @ref{fifo}.
+
+@end table
+
 The slave outputs are specified in the file name given to the muxer,
 separated by '|'. If any of the slave name contains the '|' separator,
 leading or trailing spaces or any special character, it must be
@@ -1613,6 +1626,13 @@ output name suffix.
 Specify a list of bitstream filters to apply to the specified
 output.
 
+@item use_fifo @var{bool}
+This allows to override tee muxer use_fifo option for individual slave muxer.
+
+@item fifo_options
+This allows to override tee muxer fifo_options for individual slave muxer.
+See @ref{fifo}.
+
 It is possible to specify to which streams a given bitstream filter
 applies, by appending a stream specifier to the option separated by
 @code{/}. @var{spec} must be a stream specifier (see @ref{Format
diff --git a/libavformat/tee.c b/libavformat/tee.c
index d59ad4d..99259a7 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -40,6 +40,8 @@ typedef struct {
 AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
+int use_fifo;
+AVDictionary *fifo_options;
 
 /** map from input to output streams indexes,
  * disabled output streams are set to -1 */
@@ -52,15 +54,28 @@ typedef struct TeeContext {
 unsigned nb_slaves;
 unsigned nb_alive;
 TeeSlave *slaves;
+int use_fifo;
+AVDictionary *fifo_options;
+char *fifo_options_str;
 } TeeContext;
 
 static const char *const slave_delim = "|";
 static const char *const slave_bsfs_spec_sep = "/";
 static const char *const slave_select_sep = ",";
 
+#define OFFSET(x) offsetof(TeeContext, x)
+static const AVOption options[] = {
+{"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from 
encoder",
+ OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 
AV_OPT_FLAG_ENCODING_PARAM},
+{"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options_str),
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
+{NULL}
+};
+
 static const AVClass tee_muxer_class = {
 .class_name = "Tee muxer",
 .item_name  = av_default_item_name,
+.option = options,
 .version= LIBAVUTIL_VERSION_INT,
 };
 
@@ -81,6 +96,29 @@ static inline int parse_slave_failure_policy_option(const 
char *opt, TeeSlave *t
 return AVERROR(EINVAL);
 }
 
+static int parse_slave_fifo_options(const char *use_fifo,
+const char *fifo_options, TeeSlave 
*tee_slave)
+{
+int ret = 0;
+
+if (use_fifo) {
+/*TODO - change this to use proper function for parsing boolean
+ *   options when there is one */
+if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
+tee_slave->use_fifo = 1;
+} else if (av_match_name(use_fifo, 
"false,n,no,disable,disabled,off,0")) {
+tee_slave->use_fifo = 0;
+} else {
+return AVERROR(EINVAL);
+}
+}
+
+if (fifo_options)
+ret = av_dict_parse_string(_slave->fifo_options, fifo_options, 
"=", ":", 0);
+
+return ret;
+}
+
 static int close_slave(TeeSlave *tee_slave)
 {
 AVFormatContext *avf;
@@ -125,6 +163,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 AVDictionaryEntry *entry;
 char *filename;
 char *format = NULL, *select = NULL, *on_fail = NULL;
+char *use_fifo = NULL, *fifo_options_str = NULL;
 AVFormatContext *avf2 = NULL;
 AVStream *st, *st2;
 int stream_count;
@@ -145,6 +184,8 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 STEAL_OPTION("f", format);
   

[FFmpeg-devel] [PATCH v2] avformat/tee: Add FATE tests for tee

2016-10-30 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This commit also adds new diff option for fate tests allowing do compare
multiple tuples of files.

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version:
 - fixed out of tree build (previous version refered to SRC_PATH instead of 
TARGET_PATH,
   thanks to Michael for noticing that)

 tests/Makefile|  1 +
 tests/fate-run.sh |  7 
 tests/fate/tee-muxer.mak  | 22 ++
 tests/ref/fate/tee-muxer-h264 |  2 +
 tests/ref/fate/tee-muxer-h264-audio   | 30 +
 tests/ref/fate/tee-muxer-h264-copy| 47 +
 tests/ref/fate/tee-muxer-ignorefail   | 79 +++
 tests/ref/fate/tee-muxer-tstsrc   |  2 +
 tests/ref/fate/tee-muxer-tstsrc-audio | 49 ++
 9 files changed, 239 insertions(+)
 create mode 100644 tests/fate/tee-muxer.mak
 create mode 100644 tests/ref/fate/tee-muxer-h264
 create mode 100644 tests/ref/fate/tee-muxer-h264-audio
 create mode 100644 tests/ref/fate/tee-muxer-h264-copy
 create mode 100644 tests/ref/fate/tee-muxer-ignorefail
 create mode 100644 tests/ref/fate/tee-muxer-tstsrc
 create mode 100644 tests/ref/fate/tee-muxer-tstsrc-audio

diff --git a/tests/Makefile b/tests/Makefile
index 8e810ff..e23260f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -164,6 +164,7 @@ include $(SRC_PATH)/tests/fate/real.mak
 include $(SRC_PATH)/tests/fate/screen.mak
 include $(SRC_PATH)/tests/fate/source.mak
 include $(SRC_PATH)/tests/fate/subtitles.mak
+include $(SRC_PATH)/tests/fate/tee-muxer.mak
 include $(SRC_PATH)/tests/fate/utvideo.mak
 include $(SRC_PATH)/tests/fate/video.mak
 include $(SRC_PATH)/tests/fate/voice.mak
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index c640cc5..9c90ea5 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -73,6 +73,12 @@ oneline(){
 printf '%s\n' "$1" | diff -u -b - "$2"
 }
 
+multidiff(){
+while read -r ref_file out_file; do
+diff -u -b "${base}/ref/fate/${ref_file}" "${outdir}/${out_file}" || 
return $?
+done <"$1"
+}
+
 run(){
 test "${V:-0}" -gt 0 && echo "$target_exec" $target_path/"$@" >&3
 $target_exec $target_path/"$@"
@@ -350,6 +356,7 @@ if test -e "$ref" || test $cmp = "oneline" || test $cmp = 
"grep" ; then
 case $cmp in
 diff)   diff -u -b "$ref" "$outfile">$cmpfile ;;
 rawdiff)diff -u"$ref" "$outfile">$cmpfile ;;
+mdiff)  multidiff  "$ref"   >$cmpfile ;;
 oneoff) oneoff "$ref" "$outfile">$cmpfile ;;
 stddev) stddev "$ref" "$outfile">$cmpfile ;;
 oneline)oneline"$ref" "$outfile">$cmpfile ;;
diff --git a/tests/fate/tee-muxer.mak b/tests/fate/tee-muxer.mak
new file mode 100644
index 000..a76cb18
--- /dev/null
+++ b/tests/fate/tee-muxer.mak
@@ -0,0 +1,22 @@
+fate-tee-muxer-h264: CMD = ffmpeg -i $(TARGET_SAMPLES)/mkv/1242-small.mkv 
-vframes 11\
+   -c:v copy -c:a copy -map v:0 -map a:0 -flags 
+bitexact\
+   -fflags +bitexact -fflags +bitexact -f tee\
+  
"[f=framecrc]$(TARGET_PATH)/tests/data/fate/tee-muxer-h264-copy|[f=framecrc:select=1]$(TARGET_PATH)/tests/data/fate/tee-muxer-h264-audio"
+fate-tee-muxer-h264: CMP = mdiff
+FATE-SAMPLES-TEE-MUXER-$(call ALLYES, TEE_MUXER, MATROSKA_DEMUXER, 
H264_DECODER) += fate-tee-muxer-h264
+
+fate-tee-muxer-ignorefail: CMD = ./ffmpeg  -f lavfi -i "testsrc=s=640x480" -f 
lavfi -i "sine"\
+-t 1 -map 0:v -map 1:a -c:v copy -c:a copy 
-flags +bitexact -fflags +bitexact -f tee\
+
"[f=framecrc]$(TARGET_PATH)/tests/data/fate/tee-muxer-ignorefail|[f=framecrc:onfail=ignore]$(TARGET_PATH)/dev/full"
+FATE-TEE-MUXER-$(CONFIG_TEE_MUXER) += fate-tee-muxer-ignorefail
+
+fate-tee-muxer-tstsrc: CMD = ./ffmpeg  -f lavfi -i "testsrc=s=640x480" -f 
lavfi -i "sine"\
+ -t 1 -map 0:v -map 1:a -c:v copy -c:a copy -flags 
+bitexact -fflags +bitexact -f tee\
+
"[f=framecrc]$(TARGET_PATH)/tests/data/fate/tee-muxer-tstsrc-copy|[f=framecrc:select=1]$(TARGET_PATH)/tests/data/fate/tee-muxer-tstsrc-audio"
+fate-tee-muxer-tstsrc: CMP = mdiff
+FATE-TEE-MUXER-$(CONFIG_TEE_MUXER) += fate-tee-muxer-tstsrc
+
+FATE_SAMPLES_FFMPEG += $(FATE-SAMPLES-TEE-MUXER-yes)
+FATE_FFMPEG += $(FATE-TEE-MUXER-yes)
+
+fate-tee-muxer: $(FATE-TEE-MUXER-yes) $(FATE-SAMPLES-TEE-MUXER-yes)
diff --git a/tests/ref/fate/tee-muxer-h264 b/tests/ref/fate/tee-muxer-h264
new file mode 100644
index 000..2a99a6b
--- /dev/null
+++ b/tests/ref/fate/tee-muxer-h264
@@ -0,0 +1,2 @@
+tee-muxer-h264-copy  tee-muxer-h264-copy
+tee-muxer-h264-audio tee-muxer-h264-audio
\ No newline at end of file
diff --git a/tests/ref/fate/tee-muxer-h264-audio 
b/tests/ref/fate/tee-muxer-h264-audio
new 

[FFmpeg-devel] [PATCH v2] libavformat/tee: Add fifo support for tee

2016-10-17 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Thanks for noticing, I've fixed the patch 
 (also some minor formatting issues I've noticed).

 doc/muxers.texi   | 20 +
 libavformat/tee.c | 87 ++-
 2 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index dbe53f5..7b4e165 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1473,6 +1473,7 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@anchor{fifo}
 @section fifo
 
 The fifo pseudo-muxer allows the separation of encoding and muxing by using
@@ -1580,6 +1581,18 @@ with the tee muxer; encoding can be a very expensive 
process. It is not
 useful when using the libavformat API directly because it is then possible
 to feed the same packets to several muxers directly.
 
+@table @option
+
+@item use_fifo @var{bool}
+If set to 1, slave outputs will be processed in separate thread using 
@ref{fifo}
+muxer. This allows to compensate for different speed/latency/reliability of
+outputs and setup transparent recovery. By default this feature is turned off.
+
+@item fifo_options
+Options to pass to fifo pseudo-muxer instances. See @ref{fifo}.
+
+@end table
+
 The slave outputs are specified in the file name given to the muxer,
 separated by '|'. If any of the slave name contains the '|' separator,
 leading or trailing spaces or any special character, it must be
@@ -1601,6 +1614,13 @@ output name suffix.
 Specify a list of bitstream filters to apply to the specified
 output.
 
+@item use_fifo @var{bool}
+This allows to override tee muxer use_fifo option for individual slave muxer.
+
+@item fifo_options
+This allows to override tee muxer fifo_options for individual slave muxer.
+See @ref{fifo}.
+
 It is possible to specify to which streams a given bitstream filter
 applies, by appending a stream specifier to the option separated by
 @code{/}. @var{spec} must be a stream specifier (see @ref{Format
diff --git a/libavformat/tee.c b/libavformat/tee.c
index d59ad4d..c668e95 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -40,6 +40,8 @@ typedef struct {
 AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
+int use_fifo;
+AVDictionary *fifo_options;
 
 /** map from input to output streams indexes,
  * disabled output streams are set to -1 */
@@ -52,15 +54,28 @@ typedef struct TeeContext {
 unsigned nb_slaves;
 unsigned nb_alive;
 TeeSlave *slaves;
+int use_fifo;
+AVDictionary *fifo_options;
+char *fifo_options_str;
 } TeeContext;
 
 static const char *const slave_delim = "|";
 static const char *const slave_bsfs_spec_sep = "/";
 static const char *const slave_select_sep = ",";
 
+#define OFFSET(x) offsetof(TeeContext, x)
+static const AVOption options[] = {
+{"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from 
encoder",
+ OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 
AV_OPT_FLAG_ENCODING_PARAM},
+{"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options_str),
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
+{NULL}
+};
+
 static const AVClass tee_muxer_class = {
 .class_name = "Tee muxer",
 .item_name  = av_default_item_name,
+.option = options,
 .version= LIBAVUTIL_VERSION_INT,
 };
 
@@ -81,6 +96,27 @@ static inline int parse_slave_failure_policy_option(const 
char *opt, TeeSlave *t
 return AVERROR(EINVAL);
 }
 
+static int parse_slave_fifo_options(const char *use_fifo,
+const char *fifo_options, TeeSlave 
*tee_slave)
+{
+int ret = 0;
+
+if (use_fifo) {
+if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
+tee_slave->use_fifo = 1;
+} else if (av_match_name(use_fifo, 
"false,n,no,disable,disabled,off,0")) {
+tee_slave->use_fifo = 0;
+} else {
+return AVERROR(EINVAL);
+}
+}
+
+if (fifo_options)
+ret = av_dict_parse_string(_slave->fifo_options, fifo_options, 
"=", ":", 0);
+
+return ret;
+}
+
 static int close_slave(TeeSlave *tee_slave)
 {
 AVFormatContext *avf;
@@ -125,6 +161,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 AVDictionaryEntry *entry;
 char *filename;
 char *format = NULL, *select = NULL, *on_fail = NULL;
+char *use_fifo = NULL, *fifo_options_str = NULL;
 AVFormatContext *avf2 = NULL;
 AVStream *st, *st2;
 int stream_count;
@@ -145,6 +182,8 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 STEAL_OPTION("f", format);
 STEAL_OPTION("select", select);
 STEAL_OPTION("onfail", on_fail);
+STEAL_OPTION("use_fifo", use_fifo);
+STEAL_OPTION("fifo_options", 

[FFmpeg-devel] [PATCH] libavformat/tee: Add fifo support for tee

2016-10-06 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
This commit makes use of fifo muxer together with tee muxer
easier, fifo muxer does not have to be explicitly specified
for each slave. For the most simple use case it is sufficient
to turn fifo muxer on for all slaves by switching on use_fifo
option. Same options can be passed to all fifo muxer instances of
slaves by assigning them to fifo_options of tee. 
Both use_fifo option and individual fifo_options can be 
overriden per slave if needed.

 doc/muxers.texi   | 20 +
 libavformat/tee.c | 89 ++-
 2 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 9ec2e31..b88b83c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1473,6 +1473,7 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@anchor{fifo}
 @section fifo
 
 The fifo pseudo-muxer allows the separation of encoding and muxing by using
@@ -1580,6 +1581,18 @@ with the tee muxer; encoding can be a very expensive 
process. It is not
 useful when using the libavformat API directly because it is then possible
 to feed the same packets to several muxers directly.
 
+@table @option
+
+@item use_fifo @var{bool}
+If set to 1, slave outputs will be processed in separate thread using 
@ref{fifo}
+muxer. This allows to compensate for different speed/latency/reliability of
+outputs and setup transparent recovery. By default this feature is turned off.
+
+@item fifo_options
+Options to pass to fifo pseudo-muxer instances. See @ref{fifo}.
+
+@end table
+
 The slave outputs are specified in the file name given to the muxer,
 separated by '|'. If any of the slave name contains the '|' separator,
 leading or trailing spaces or any special character, it must be
@@ -1601,6 +1614,13 @@ output name suffix.
 Specify a list of bitstream filters to apply to the specified
 output.
 
+@item use_fifo @var{bool}
+This allows to override tee muxer use_fifo option for individual slave muxer.
+
+@item fifo_options
+This allows to override tee muxer fifo_options for individual slave muxer.
+See @ref{fifo}.
+
 It is possible to specify to which streams a given bitstream filter
 applies, by appending a stream specifier to the option separated by
 @code{/}. @var{spec} must be a stream specifier (see @ref{Format
diff --git a/libavformat/tee.c b/libavformat/tee.c
index d59ad4d..764135d 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -40,6 +40,8 @@ typedef struct {
 AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
+int use_fifo;
+AVDictionary *fifo_options;
 
 /** map from input to output streams indexes,
  * disabled output streams are set to -1 */
@@ -52,15 +54,28 @@ typedef struct TeeContext {
 unsigned nb_slaves;
 unsigned nb_alive;
 TeeSlave *slaves;
+int use_fifo;
+AVDictionary *fifo_options;
+char *fifo_options_str;
 } TeeContext;
 
 static const char *const slave_delim = "|";
 static const char *const slave_bsfs_spec_sep = "/";
 static const char *const slave_select_sep = ",";
 
+#define OFFSET(x) offsetof(TeeContext, x)
+static const AVOption options[] = {
+{"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from 
encoder",
+ OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 
AV_OPT_FLAG_ENCODING_PARAM},
+{"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options_str),
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
+{NULL}
+};
+
 static const AVClass tee_muxer_class = {
 .class_name = "Tee muxer",
 .item_name  = av_default_item_name,
+.option = options,
 .version= LIBAVUTIL_VERSION_INT,
 };
 
@@ -81,6 +96,27 @@ static inline int parse_slave_failure_policy_option(const 
char *opt, TeeSlave *t
 return AVERROR(EINVAL);
 }
 
+static int parse_slave_fifo_options(const char * use_fifo,
+const char * fifo_options, TeeSlave * 
tee_slave)
+{
+int ret = 0;
+
+if (use_fifo) {
+if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
+tee_slave->use_fifo = 1;
+} else if (av_match_name(use_fifo, 
"false,n,no,disable,disabled,off,0")) {
+tee_slave->use_fifo = 0;
+} else {
+return AVERROR(EINVAL);
+}
+}
+
+if (fifo_options)
+ret = av_dict_parse_string(_slave->fifo_options, fifo_options, 
"=", ":", 0);
+
+return ret;
+}
+
 static int close_slave(TeeSlave *tee_slave)
 {
 AVFormatContext *avf;
@@ -125,6 +161,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 AVDictionaryEntry *entry;
 char *filename;
 char *format = NULL, *select = NULL, *on_fail = NULL;
+char *use_fifo = NULL, *fifo_options_str = NULL;
 AVFormatContext 

[FFmpeg-devel] [PATCH 1/2] avformat/tee: Copy interrupt callback and flags to slave

2016-09-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Copy interrupt callback to slave format context to allow
user to interrupt IO. Copy format flags as well.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 518af4a..d59ad4d 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -161,6 +161,8 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 avf2->opaque   = avf->opaque;
 avf2->io_open  = avf->io_open;
 avf2->io_close = avf->io_close;
+avf2->interrupt_callback = avf->interrupt_callback;
+avf2->flags = avf->flags;
 
 tee_slave->stream_map = av_calloc(avf->nb_streams, 
sizeof(*tee_slave->stream_map));
 if (!tee_slave->stream_map) {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] avformat/tee: Add FATE tests for tee

2016-09-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This commit also adds new diff option for fate tests allowing do compare
multiple tuples of files.

Signed-off-by: Jan Sebechlebsky 
---
 tests/Makefile|  1 +
 tests/fate-run.sh |  7 
 tests/fate/tee-muxer.mak  | 22 ++
 tests/ref/fate/tee-muxer-h264 |  2 +
 tests/ref/fate/tee-muxer-h264-audio   | 30 +
 tests/ref/fate/tee-muxer-h264-copy| 47 +
 tests/ref/fate/tee-muxer-ignorefail   | 79 +++
 tests/ref/fate/tee-muxer-tstsrc   |  2 +
 tests/ref/fate/tee-muxer-tstsrc-audio | 49 ++
 9 files changed, 239 insertions(+)
 create mode 100644 tests/fate/tee-muxer.mak
 create mode 100644 tests/ref/fate/tee-muxer-h264
 create mode 100644 tests/ref/fate/tee-muxer-h264-audio
 create mode 100644 tests/ref/fate/tee-muxer-h264-copy
 create mode 100644 tests/ref/fate/tee-muxer-ignorefail
 create mode 100644 tests/ref/fate/tee-muxer-tstsrc
 create mode 100644 tests/ref/fate/tee-muxer-tstsrc-audio

diff --git a/tests/Makefile b/tests/Makefile
index 8e810ff..e23260f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -164,6 +164,7 @@ include $(SRC_PATH)/tests/fate/real.mak
 include $(SRC_PATH)/tests/fate/screen.mak
 include $(SRC_PATH)/tests/fate/source.mak
 include $(SRC_PATH)/tests/fate/subtitles.mak
+include $(SRC_PATH)/tests/fate/tee-muxer.mak
 include $(SRC_PATH)/tests/fate/utvideo.mak
 include $(SRC_PATH)/tests/fate/video.mak
 include $(SRC_PATH)/tests/fate/voice.mak
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index c640cc5..9c90ea5 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -73,6 +73,12 @@ oneline(){
 printf '%s\n' "$1" | diff -u -b - "$2"
 }
 
+multidiff(){
+while read -r ref_file out_file; do
+diff -u -b "${base}/ref/fate/${ref_file}" "${outdir}/${out_file}" || 
return $?
+done <"$1"
+}
+
 run(){
 test "${V:-0}" -gt 0 && echo "$target_exec" $target_path/"$@" >&3
 $target_exec $target_path/"$@"
@@ -350,6 +356,7 @@ if test -e "$ref" || test $cmp = "oneline" || test $cmp = 
"grep" ; then
 case $cmp in
 diff)   diff -u -b "$ref" "$outfile">$cmpfile ;;
 rawdiff)diff -u"$ref" "$outfile">$cmpfile ;;
+mdiff)  multidiff  "$ref"   >$cmpfile ;;
 oneoff) oneoff "$ref" "$outfile">$cmpfile ;;
 stddev) stddev "$ref" "$outfile">$cmpfile ;;
 oneline)oneline"$ref" "$outfile">$cmpfile ;;
diff --git a/tests/fate/tee-muxer.mak b/tests/fate/tee-muxer.mak
new file mode 100644
index 000..b760ea1
--- /dev/null
+++ b/tests/fate/tee-muxer.mak
@@ -0,0 +1,22 @@
+fate-tee-muxer-h264: CMD = ffmpeg -i $(TARGET_SAMPLES)/mkv/1242-small.mkv 
-vframes 11\
+   -c:v copy -c:a copy -map v:0 -map a:0 -flags 
+bitexact\
+   -fflags +bitexact -fflags +bitexact -f tee\
+  
"[f=framecrc]$(SRC_PATH)/tests/data/fate/tee-muxer-h264-copy|[f=framecrc:select=1]$(SRC_PATH)/tests/data/fate/tee-muxer-h264-audio"
+fate-tee-muxer-h264: CMP = mdiff
+FATE-SAMPLES-TEE-MUXER-$(call ALLYES, TEE_MUXER, MATROSKA_DEMUXER, 
H264_DECODER) += fate-tee-muxer-h264
+
+fate-tee-muxer-ignorefail: CMD = ./ffmpeg  -f lavfi -i "testsrc=s=640x480" -f 
lavfi -i "sine"\
+-t 1 -map 0:v -map 1:a -c:v copy -c:a copy 
-flags +bitexact -fflags +bitexact -f tee\
+
"[f=framecrc]$(SRC_PATH)/tests/data/fate/tee-muxer-ignorefail|[f=framecrc:onfail=ignore]$(SRC_PATH)/dev/full"
+FATE-TEE-MUXER-$(CONFIG_TEE_MUXER) += fate-tee-muxer-ignorefail
+
+fate-tee-muxer-tstsrc: CMD = ./ffmpeg  -f lavfi -i "testsrc=s=640x480" -f 
lavfi -i "sine"\
+ -t 1 -map 0:v -map 1:a -c:v copy -c:a copy -flags 
+bitexact -fflags +bitexact -f tee\
+
"[f=framecrc]$(SRC_PATH)/tests/data/fate/tee-muxer-tstsrc-copy|[f=framecrc:select=1]$(SRC_PATH)/tests/data/fate/tee-muxer-tstsrc-audio"
+fate-tee-muxer-tstsrc: CMP = mdiff
+FATE-TEE-MUXER-$(CONFIG_TEE_MUXER) += fate-tee-muxer-tstsrc
+
+FATE_SAMPLES_FFMPEG += $(FATE-SAMPLES-TEE-MUXER-yes)
+FATE_FFMPEG += $(FATE-TEE-MUXER-yes)
+
+fate-tee-muxer: $(FATE-TEE-MUXER-yes) $(FATE-SAMPLES-TEE-MUXER-yes)
diff --git a/tests/ref/fate/tee-muxer-h264 b/tests/ref/fate/tee-muxer-h264
new file mode 100644
index 000..2a99a6b
--- /dev/null
+++ b/tests/ref/fate/tee-muxer-h264
@@ -0,0 +1,2 @@
+tee-muxer-h264-copy  tee-muxer-h264-copy
+tee-muxer-h264-audio tee-muxer-h264-audio
\ No newline at end of file
diff --git a/tests/ref/fate/tee-muxer-h264-audio 
b/tests/ref/fate/tee-muxer-h264-audio
new file mode 100644
index 000..0b42d11
--- /dev/null
+++ b/tests/ref/fate/tee-muxer-h264-audio
@@ -0,0 +1,30 @@
+#extradata 0:2, 0x00b200a1
+#tb 0: 1/1000
+#media_type 0: 

[FFmpeg-devel] [PATCH v5 5/5] avformat/tee: Use BSF list API

2016-09-01 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - added check for  avcodec_parameters_copy return value
 - fixed stray space
 - rewritten cycle receiving packets from bsf so case when 
av_interleaved_write_frame 
   returns EAGAIN is treated as error.

 libavformat/tee.c | 137 --
 1 file changed, 70 insertions(+), 67 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 5689ca3..c3c30a6 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -37,7 +37,7 @@ typedef enum {
 
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -64,46 +64,6 @@ static const AVClass tee_muxer_class = {
 .version= LIBAVUTIL_VERSION_INT,
 };
 
-/**
- * Parse list of bitstream filters and add them to the list of filters
- * pointed to by bsfs.
- *
- * The list must be specified in the form:
- * BSFS ::= BSF[,BSFS]
- */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
-{
-char *bsf_name, *buf, *dup, *saveptr;
-int ret = 0;
-
-if (!(dup = buf = av_strdup(bsfs_spec)))
-return AVERROR(ENOMEM);
-
-while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
-
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
-   bsf_name);
-ret = AVERROR_UNKNOWN;
-goto end;
-}
-
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
-
-buf = NULL;
-}
-
-end:
-av_free(dup);
-return ret;
-}
-
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
 {
 if (!opt) {
@@ -135,14 +95,8 @@ static int close_slave(TeeSlave *tee_slave)
 ret = av_write_trailer(avf);
 
 if (tee_slave->bsfs) {
-for (i = 0; i < avf->nb_streams; ++i) {
-AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
-while (bsf) {
-bsf_next = bsf->next;
-av_bitstream_filter_close(bsf);
-bsf = bsf_next;
-}
-}
+for (i = 0; i < avf->nb_streams; ++i)
+av_bsf_free(_slave->bsfs[i]);
 }
 av_freep(_slave->stream_map);
 av_freep(_slave->bsfs);
@@ -312,7 +266,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
"output '%s', filters will be ignored\n", i, 
filename);
 continue;
 }
-ret = parse_bsfs(avf, entry->value, _slave->bsfs[i]);
+ret = av_bsf_list_parse_str(entry->value, _slave->bsfs[i]);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR,
"Error parsing bitstream filter sequence '%s' 
associated to "
@@ -325,6 +279,37 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 av_dict_set(, entry->key, NULL, 0);
 }
 
+for (i = 0; i < avf->nb_streams; i++){
+int target_stream = tee_slave->stream_map[i];
+if (target_stream < 0)
+continue;
+
+if (!tee_slave->bsfs[target_stream]) {
+/* Add pass-through bitstream filter */
+ret = av_bsf_get_null_filter(_slave->bsfs[target_stream]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+   "Failed to create pass-through bitstream filter: %s\n",
+   av_err2str(ret));
+goto end;
+}
+}
+
+tee_slave->bsfs[target_stream]->time_base_in = 
avf->streams[i]->time_base;
+ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in,
+  avf->streams[i]->codecpar);
+if (ret < 0)
+goto end;
+
+ret = av_bsf_init(tee_slave->bsfs[target_stream]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+"Failed to initialize bitstream filter(s): %s\n",
+av_err2str(ret));
+goto end;
+}
+}
+
 if (options) {
 entry = NULL;
 while ((entry = av_dict_get(options, "", entry, 
AV_DICT_IGNORE_SUFFIX)))
@@ -349,20 +334,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int 
log_level)
slave->avf->filename, slave->avf->oformat->name);
 for (i = 0; i < slave->avf->nb_streams; i++) {
 AVStream *st = slave->avf->streams[i];
-AVBitStreamFilterContext *bsf = 

[FFmpeg-devel] [PATCH] libavcodec/bsfs: Fix bsf option setting

2016-08-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

AV_OPT_SEARCH_CHILDREN flag must be passed to av_opt_set_dict()
to set options for private context.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/bsf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 2462e62..dfb127e 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -432,7 +432,7 @@ int av_bsf_list_append2(AVBSFList *lst, const char 
*bsf_name, AVDictionary ** op
 return ret;
 
 if (options) {
-ret = av_opt_set_dict(bsf, options);
+ret = av_opt_set_dict2(bsf, options, AV_OPT_SEARCH_CHILDREN);
 if (ret < 0)
 goto end;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v4 5/5] avformat/tee: Use BSF list API

2016-08-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 I believe I have fixed handling input / output timebase and input parameters
 to bitstream filters list.

 libavformat/tee.c | 131 ++
 1 file changed, 64 insertions(+), 67 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 5689ca3..ba852c3 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -37,7 +37,7 @@ typedef enum {
 
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -64,46 +64,6 @@ static const AVClass tee_muxer_class = {
 .version= LIBAVUTIL_VERSION_INT,
 };
 
-/**
- * Parse list of bitstream filters and add them to the list of filters
- * pointed to by bsfs.
- *
- * The list must be specified in the form:
- * BSFS ::= BSF[,BSFS]
- */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
-{
-char *bsf_name, *buf, *dup, *saveptr;
-int ret = 0;
-
-if (!(dup = buf = av_strdup(bsfs_spec)))
-return AVERROR(ENOMEM);
-
-while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
-
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
-   bsf_name);
-ret = AVERROR_UNKNOWN;
-goto end;
-}
-
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
-
-buf = NULL;
-}
-
-end:
-av_free(dup);
-return ret;
-}
-
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
 {
 if (!opt) {
@@ -135,14 +95,8 @@ static int close_slave(TeeSlave *tee_slave)
 ret = av_write_trailer(avf);
 
 if (tee_slave->bsfs) {
-for (i = 0; i < avf->nb_streams; ++i) {
-AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
-while (bsf) {
-bsf_next = bsf->next;
-av_bitstream_filter_close(bsf);
-bsf = bsf_next;
-}
-}
+for (i = 0; i < avf->nb_streams; ++i)
+av_bsf_free(_slave->bsfs[i]);
 }
 av_freep(_slave->stream_map);
 av_freep(_slave->bsfs);
@@ -312,7 +266,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
"output '%s', filters will be ignored\n", i, 
filename);
 continue;
 }
-ret = parse_bsfs(avf, entry->value, _slave->bsfs[i]);
+ret = av_bsf_list_parse_str(entry->value, _slave->bsfs[i]);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR,
"Error parsing bitstream filter sequence '%s' 
associated to "
@@ -325,6 +279,35 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 av_dict_set(, entry->key, NULL, 0);
 }
 
+for (i = 0; i < avf->nb_streams; i++){
+int target_stream = tee_slave->stream_map[i];
+if (target_stream < 0)
+continue;
+
+if (!tee_slave->bsfs[target_stream]) {
+/* Add pass-through bitstream filter */
+ret = av_bsf_get_null_filter(_slave->bsfs[target_stream]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+   "Failed to create pass-through bitstream filter: %s\n",
+   av_err2str(ret));
+goto end;
+}
+}
+
+tee_slave->bsfs[target_stream]->time_base_in = 
avf->streams[i]->time_base;
+ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in,
+  avf->streams[i]->codecpar);
+
+ret = av_bsf_init(tee_slave->bsfs[target_stream]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+"Failed to initialize bitstream filter(s): %s\n",
+av_err2str(ret));
+goto end;
+}
+}
+
 if (options) {
 entry = NULL;
 while ((entry = av_dict_get(options, "", entry, 
AV_DICT_IGNORE_SUFFIX)))
@@ -349,20 +332,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int 
log_level)
slave->avf->filename, slave->avf->oformat->name);
 for (i = 0; i < slave->avf->nb_streams; i++) {
 AVStream *st = slave->avf->streams[i];
-AVBitStreamFilterContext *bsf = slave->bsfs[i];
+AVBSFContext *bsf = slave->bsfs[i];
+const char * bsf_name;
 
 av_log(log_ctx, log_level, "stream:%d codec:%s type:%s",
i, 

[FFmpeg-devel] [PATCH v7 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-18 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version of the patch, just rebased because of
 changes in previous fifo patch.

 libavformat/fifo.c | 62 --
 1 file changed, 56 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 15435fe..7ab5be6 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/thread.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
@@ -76,6 +78,17 @@ typedef struct FifoContext {
 /* Value > 0 signals queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -110,6 +123,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -435,12 +458,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -450,7 +478,8 @@ static int fifo_mux_init(AVFormatContext *avf, 
AVOutputFormat *oformat)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -538,7 +567,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -547,15 +576,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AV_THREAD_MESSAGE_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+goto fail;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -583,6 +618,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join(fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -598,6 +637,17 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+avpriv_atomic_int_set(>termination_requested, 1);
+

[FFmpeg-devel] [PATCH v12 01/11] avformat: Add fifo pseudo-muxer

2016-08-18 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - fixed mistakes in docs (missing "is", 2xmisspelled "unsuccessful")
 - removed braces around return statement in fifo_mux_init()
 - fixed "return 0;" -> "return ret;" in fifo_write_header()

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  95 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 660 +++
 libavformat/version.h|   4 +-
 7 files changed, 761 insertions(+), 2 deletions(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index 7e88e64..fdc0d80 100644
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@ version :
 - crystalizer audio filter
 - acrusher audio filter
 - bitplanenoise video filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9b92426..894e7a9 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..12730a2 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,101 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and can be used to
+send data to several destinations with different reliability/writing 
speed/latency.
+
+API users should be aware that callback functions (interrupt_callback,
+io_open and io_close) used within its AVFormatContext must be thread-safe.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option is set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsuccessful recovery attempts after which
+the output fails permanently. By default this option is set to 0 (unlimited).
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessful
+recovery attempt. Default value is 5 seconds.
+
+@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure 

[FFmpeg-devel] [PATCH v11 01/11] avformat: Add fifo pseudo-muxer

2016-08-18 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Conflicting patch was applied meanwhile, so I am resending this one.
 No changes since the last version.

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  95 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 661 +++
 libavformat/version.h|   4 +-
 7 files changed, 762 insertions(+), 2 deletions(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index 7e88e64..fdc0d80 100644
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@ version :
 - crystalizer audio filter
 - acrusher audio filter
 - bitplanenoise video filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9b92426..894e7a9 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..0f36ddc 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,101 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and can be used to
+send data to several destinations with different reliability/writing 
speed/latency.
+
+API users should be aware that callback functions (interrupt_callback,
+io_open and io_close) used within its AVFormatContext must be thread-safe.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. By default this option is set to 0 (unlimited).
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second indefinitely.
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a aac -f fifo 

[FFmpeg-devel] [PATCH v2] doc/APIchanges: Document addition of list BSF API in lavc

2016-08-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 I've noticed that conflicting patch was applied meanwhile, so I'm resending 
this.
 Please apply :)

 doc/APIchanges | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/doc/APIchanges b/doc/APIchanges
index 74145b2..582563a 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -19,6 +19,13 @@ API changes, most recent first:
   Add trailing_padding to AVCodecContext to match the corresponding
   field in AVCodecParameters.
 
+2016-08-15 - b746ed7 - lavc 57.52.100 - avcodec.h
+  Add a new API for chained BSF filters and passthrough (null) BSF --
+  av_bsf_list_alloc(), av_bsf_list_free(), av_bsf_list_append(),
+  av_bsf_list_append2(), av_bsf_list_finalize(), av_bsf_list_parse_str()
+  and av_bsf_get_null_filter().
+
+
 2016-08-04 - xxx - lavf 57.46.100 - avformat.h
   Add av_get_frame_filename2()
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v10 01/11] avformat: Add fifo pseudo-muxer

2016-08-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Added note in fifo muxer documentation in muxers.texi
   regarding thread-safety requirement for callbacks in AVFormatContext

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  95 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 661 +++
 libavformat/version.h|   2 +-
 7 files changed, 761 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index b903e31..c693d34 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version :
 - True Audio (TTA) muxer
 - crystalizer audio filter
 - acrusher audio filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9b92426..894e7a9 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..0f36ddc 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,101 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and can be used to
+send data to several destinations with different reliability/writing 
speed/latency.
+
+API users should be aware that callback functions (interrupt_callback,
+io_open and io_close) used within its AVFormatContext must be thread-safe.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. By default this option is set to 0 (unlimited).
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second 

[FFmpeg-devel] [PATCH] avformat: Document thread-safety requirement for interrupt callback

2016-08-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Muxing might be running in a separate thread if actual muxer is
run inside of fifo pseudo-muxer. Callback should be therefore
thread-safe.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/avformat.h | 2 +-
 libavformat/avio.h | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 79c2511..8550dca 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1564,7 +1564,7 @@ typedef struct AVFormatContext {
  * muxing: set by the user before avformat_write_header()
  * (mainly useful for AVFMT_NOFILE formats). The callback
  * should also be passed to avio_open2() if it's used to
- * open the file.
+ * open the file. The callback must be thread-safe.
  */
 AVIOInterruptCB interrupt_callback;
 
diff --git a/libavformat/avio.h b/libavformat/avio.h
index b1ce1d1..b5d1396 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -43,6 +43,8 @@
  * opaque as parameter. If the callback returns 1, the
  * blocking operation will be aborted.
  *
+ * If the callback is used in muxing context, it has to be thread-safe.
+ *
  * No members can be added to this struct without a major bump, if
  * new elements have been added after this struct in AVFormatContext
  * or AVIOContext.
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v6 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 No chanes since the last version of patch, rebased because of changes in the
 patch adding fifo.

 libavformat/fifo.c | 62 --
 1 file changed, 56 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 859cbb4..689581f 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/thread.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
@@ -76,6 +78,17 @@ typedef struct FifoContext {
 /* Value > 0 signals queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -110,6 +123,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -435,12 +458,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -451,7 +479,8 @@ static int fifo_mux_init(AVFormatContext *avf, 
AVOutputFormat *oformat)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -539,7 +568,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -548,15 +577,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AV_THREAD_MESSAGE_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+goto fail;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -584,6 +619,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join(fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -599,6 +638,17 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+avpriv_atomic_int_set(>termination_requested, 1);
+ret = 

[FFmpeg-devel] [PATCH v9 01/11] avformat: Add fifo pseudo-muxer

2016-08-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - fixed "s@item" in muxers.texi
 - fixed second -> seconds in FIFO_DEFAULT_RECOVERY_WAIT_TIME_USEC comment
 - removed AVFormat *oformat from FifoContext (it is local variable now)
 - if recovery uses stream time to wait, last_recovery_ts is set to 
AV_NOPTS_VALUE,
   and when recovery is attempted and last_recovery_ts recovery is performed 
immediately
 - fixed stray space in pthread_join in fifo_write_trailer
 - fixed superfluous tests and av_thread_message_flush() in fifo_deinit
 - changed upper bound for queue_size option to INT_MAX

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  92 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 661 +++
 libavformat/version.h|   2 +-
 7 files changed, 758 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index b903e31..c693d34 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version :
 - True Audio (TTA) muxer
 - crystalizer audio filter
 - acrusher audio filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9b92426..894e7a9 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..617c9a3 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,98 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and can be used to
+send data to several destinations with different reliability/writing 
speed/latency.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. By default this option is set to 0 (unlimited).
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 

[FFmpeg-devel] [PATCH v3 4/5] avcodec/bsf: Add custom item name func for BSF list

2016-08-15 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add custom item name function for bsf list, which will
construct string description of filter chain. This is
done using lazy-initialization, so there is no overhead
if item name is never accessed.

Signed-off-by: Jan Sebechlebsky 

Conflicts:
libavcodec/bsf.c
---
 Changes since the last version of the patch:
 - added av_freep(>item_name) from previous commit to bsf_list_close

 libavcodec/bsf.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 664565f..2462e62 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -248,6 +248,7 @@ typedef struct BSFListContext {
 unsigned idx;   // index of currently processed BSF
 unsigned flushed_idx;   // index of BSF being flushed
 
+char * item_name;
 } BSFListContext;
 
 
@@ -345,11 +346,37 @@ static void bsf_list_close(AVBSFContext *bsf)
 for (i = 0; i < lst->nb_bsfs; ++i)
 av_bsf_free(>bsfs[i]);
 av_freep(>bsfs);
+av_freep(>item_name);
+}
+
+static const char *bsf_list_item_name(void *ctx)
+{
+static const char *null_filter_name = "null";
+AVBSFContext *bsf_ctx = ctx;
+BSFListContext *lst = bsf_ctx->priv_data;
+
+if (!lst->nb_bsfs)
+return null_filter_name;
+
+if (!lst->item_name) {
+int i;
+AVBPrint bp;
+av_bprint_init(, 16, 128);
+
+av_bprintf(, "bsf_list(");
+for (i = 0; i < lst->nb_bsfs; i++)
+av_bprintf(, i ? ",%s" : "%s", lst->bsfs[i]->filter->name);
+av_bprintf(, ")");
+
+av_bprint_finalize(, >item_name);
+}
+
+return lst->item_name;
 }
 
 static const AVClass bsf_list_class = {
 .class_name = "bsf_list",
-.item_name  = av_default_item_name,
+.item_name  = bsf_list_item_name,
 .version= LIBAVUTIL_VERSION_INT,
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v5 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-14 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version of the patch, just rebased because
 of changes in previous patch.

 libavformat/fifo.c | 61 --
 1 file changed, 55 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 3748fa9..ef0fda4 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/thread.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
@@ -77,6 +79,17 @@ typedef struct FifoContext {
 /* Value > 0 signals queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -111,6 +124,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -430,12 +453,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -446,7 +474,8 @@ static int fifo_mux_init(AVFormatContext *avf)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -533,7 +562,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -542,15 +571,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AV_THREAD_MESSAGE_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+goto fail;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -578,6 +613,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join( fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -593,6 +632,16 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+avpriv_atomic_int_set(>termination_requested, 1);
+ret = pthread_join( fifo->writer_thread, NULL);
+   

[FFmpeg-devel] [PATCH v8 01/11] avformat: Add fifo pseudo-muxer

2016-08-14 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Fixed documentation (apart from the Marton's suggestions I've
   also changed example, since it used block_on_overflow option
   from the earlier version of patch)
 - Changed max_recovery_attempts default value to 0 (unlimited)
 - Removed unnecessary check for null ptr in free_message
 - Changed log level when loggin recovery attempt to AV_LOG_VERBOSE
 
 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  92 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 662 +++
 libavformat/version.h|   2 +-
 7 files changed, 759 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index b903e31..c693d34 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version :
 - True Audio (TTA) muxer
 - crystalizer audio filter
 - acrusher audio filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index bff8159..a252354 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..b4c3886 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,98 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and can be used to
+send data to several destinations with different reliability/writing 
speed/latency.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. By default this option is set to 0 (unlimited).
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary 

[FFmpeg-devel] [PATCH v5 03/11] avformat/fifo: Add fate test

2016-08-12 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - fixed print_deinit_summary to use int instead of uint8_t

 libavformat/Makefile   |   1 +
 libavformat/tests/fifo_muxer.c | 443 +
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  11 +
 5 files changed, 476 insertions(+)
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2d2b78c..5d827d31 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -591,6 +591,7 @@ TESTPROGS = seek
\
 url \
 #   async   \
 
+TESTPROGS-$(CONFIG_FIFO_MUXER)  += fifo_muxer
 TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
 TESTPROGS-$(CONFIG_MOV_MUXER)+= movenc
 TESTPROGS-$(CONFIG_NETWORK)  += noproxy
diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
new file mode 100644
index 000..9659198
--- /dev/null
+++ b/libavformat/tests/fifo_muxer.c
@@ -0,0 +1,443 @@
+/*
+ * FIFO pseudo-muxer
+ * Copyright (c) 2016 Jan Sebechlebsky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+
+#define MAX_TST_PACKETS 128
+#define SLEEPTIME_50_MS 5
+#define SLEEPTIME_10_MS 1
+
+/* Implementation of mock muxer to simulate real muxer failures */
+
+/* This is structure of data sent in packets to
+ * failing muxer */
+typedef struct FailingMuxerPacketData {
+int ret; /* return value of write_packet call*/
+int recover_after;   /* set ret to zero after this number of recovery 
attempts */
+unsigned sleep_time; /* sleep for this long in write_packet to simulate 
long I/O operation */
+} FailingMuxerPacketData;
+
+
+typedef struct FailingMuxerContext {
+AVClass *class;
+int write_header_ret;
+int write_trailer_ret;
+/* If non-zero, summary of processed packets will be printed in deinit */
+int print_deinit_summary;
+
+int flush_count;
+int pts_written[MAX_TST_PACKETS];
+int pts_written_nr;
+} FailingMuxerContext;
+
+static int failing_write_header(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_header_ret;
+}
+
+static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+int ret = 0;
+if (!pkt) {
+ctx->flush_count++;
+} else {
+FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data;
+
+if (!data->recover_after) {
+data->ret = 0;
+} else {
+data->recover_after--;
+}
+
+ret = data->ret;
+
+if (data->sleep_time) {
+int64_t slept = 0;
+while (slept < data->sleep_time) {
+if (ff_check_interrupt(>interrupt_callback))
+return AVERROR_EXIT;
+av_usleep(SLEEPTIME_10_MS);
+slept += SLEEPTIME_10_MS;
+}
+}
+
+if (!ret) {
+ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
+av_packet_unref(pkt);
+}
+}
+return ret;
+}
+
+static int failing_write_trailer(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_trailer_ret;
+}
+
+static void failing_deinit(AVFormatContext *avf)
+{
+int i;
+FailingMuxerContext *ctx = avf->priv_data;
+
+if (!ctx->print_deinit_summary)
+return;
+
+printf("flush count: %d\n", ctx->flush_count);
+printf("pts seen nr: %d\n", ctx->pts_written_nr);
+printf("pts seen: ");
+for (i = 0; i < ctx->pts_written_nr; ++i ) {
+printf(i ? ",%d" : "%d", ctx->pts_written[i]);
+}
+ 

[FFmpeg-devel] [PATCH v4 03/11] avformat/fifo: Add fate test

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of patch:
 - Fixed make dependencies so the tests are not executed when 
   required components are disabled

 libavformat/Makefile   |   1 +
 libavformat/tests/fifo_muxer.c | 443 +
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  11 +
 5 files changed, 476 insertions(+)
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2d2b78c..5d827d31 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -591,6 +591,7 @@ TESTPROGS = seek
\
 url \
 #   async   \
 
+TESTPROGS-$(CONFIG_FIFO_MUXER)  += fifo_muxer
 TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
 TESTPROGS-$(CONFIG_MOV_MUXER)+= movenc
 TESTPROGS-$(CONFIG_NETWORK)  += noproxy
diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
new file mode 100644
index 000..d6ce85d
--- /dev/null
+++ b/libavformat/tests/fifo_muxer.c
@@ -0,0 +1,443 @@
+/*
+ * FIFO pseudo-muxer
+ * Copyright (c) 2016 Jan Sebechlebsky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+
+#define MAX_TST_PACKETS 128
+#define SLEEPTIME_50_MS 5
+#define SLEEPTIME_10_MS 1
+
+/* Implementation of mock muxer to simulate real muxer failures */
+
+/* This is structure of data sent in packets to
+ * failing muxer */
+typedef struct FailingMuxerPacketData {
+int ret; /* return value of write_packet call*/
+int recover_after;   /* set ret to zero after this number of recovery 
attempts */
+unsigned sleep_time; /* sleep for this long in write_packet to simulate 
long I/O operation */
+} FailingMuxerPacketData;
+
+
+typedef struct FailingMuxerContext {
+AVClass *class;
+int write_header_ret;
+int write_trailer_ret;
+/* If non-zero, summary of processed packets will be printed in deinit */
+uint8_t print_deinit_summary;
+
+int flush_count;
+int pts_written[MAX_TST_PACKETS];
+int pts_written_nr;
+} FailingMuxerContext;
+
+static int failing_write_header(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_header_ret;
+}
+
+static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+int ret = 0;
+if (!pkt) {
+ctx->flush_count++;
+} else {
+FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data;
+
+if (!data->recover_after) {
+data->ret = 0;
+} else {
+data->recover_after--;
+}
+
+ret = data->ret;
+
+if (data->sleep_time) {
+int64_t slept = 0;
+while (slept < data->sleep_time) {
+if (ff_check_interrupt(>interrupt_callback))
+return AVERROR_EXIT;
+av_usleep(SLEEPTIME_10_MS);
+slept += SLEEPTIME_10_MS;
+}
+}
+
+if (!ret) {
+ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
+av_packet_unref(pkt);
+}
+}
+return ret;
+}
+
+static int failing_write_trailer(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_trailer_ret;
+}
+
+static void failing_deinit(AVFormatContext *avf)
+{
+int i;
+FailingMuxerContext *ctx = avf->priv_data;
+
+if (!ctx->print_deinit_summary)
+return;
+
+printf("flush count: %d\n", ctx->flush_count);
+printf("pts seen nr: %d\n", ctx->pts_written_nr);
+printf("pts seen: ");
+for (i = 0; i < ctx->pts_written_nr; ++i ) {
+printf(i ? ",%d" 

[FFmpeg-devel] [PATCH v3 11/11] avformat/fifo: Add test for nonblocking mode

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version of the patch, just rebased 
 because of changes in previous fate test patch.

 libavformat/tests/fifo_muxer.c | 139 +
 tests/ref/fate/fifo-muxer-tst  |   5 ++
 2 files changed, 144 insertions(+)

diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
index d6ce85d..deb2656 100644
--- a/libavformat/tests/fifo_muxer.c
+++ b/libavformat/tests/fifo_muxer.c
@@ -336,6 +336,137 @@ fail:
 return ret;
 }
 
+static int retry_write_frame(AVFormatContext *oc, AVPacket *pkt, int 
max_retries)
+{
+int ret = 0, retry_count = 0;
+do {
+ret = av_write_frame(oc, pkt);
+if (ret == AVERROR(EAGAIN)) {
+av_usleep(SLEEPTIME_10_MS);
+retry_count++;
+}
+} while ( ret == AVERROR(EAGAIN) && retry_count < max_retries);
+return ret;
+}
+
+static int retry_write_trailer(AVFormatContext *oc, int max_retries)
+{
+int ret = 0, retry_count = 0;
+do {
+ret = av_write_trailer(oc);
+if (ret == AVERROR(EAGAIN)) {
+av_usleep(SLEEPTIME_10_MS);
+retry_count++;
+}
+} while (ret == AVERROR(EAGAIN) && retry_count < max_retries);
+return ret;
+}
+
+static int fifo_nonblock_test(AVFormatContext *oc, AVDictionary **opts,
+  const FailingMuxerPacketData *pkt_data)
+{
+int ret = 0, i;
+AVPacket pkt;
+
+av_init_packet();
+
+oc->flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = avformat_write_header(oc, opts);
+if (ret) {
+fprintf(stderr, "Unexpected write_header failure: %s\n",
+av_err2str(ret));
+return ret;
+}
+
+for (i = 0; i < 16; i++ ) {
+ret = prepare_packet(, pkt_data, i);
+if (ret < 0) {
+fprintf(stderr, "Failed to prepare test packet: %s\n",
+av_err2str(ret));
+goto fail;
+}
+ret = retry_write_frame(oc, , 100);
+av_packet_unref();
+if (ret < 0)
+break;
+}
+
+if (ret) {
+fprintf(stderr, "Unexpected write_packet error: %s\n", 
av_err2str(ret));
+goto fail;
+}
+
+ret = retry_write_trailer(oc, 100);
+if (ret == AVERROR(EAGAIN)) {
+fprintf(stderr, "write_trailer() operation timeout\n");
+goto fail;
+} else if (ret < 0)
+fprintf(stderr, "Unexpected write_trailer error: %s\n", 
av_err2str(ret));
+
+return ret;
+fail:
+avformat_write_abort(oc);
+return ret;
+}
+
+static int fifo_nonblock_abort_test(AVFormatContext *oc, AVDictionary **opts,
+const FailingMuxerPacketData *pkt_data)
+{
+int ret = 0, i;
+AVPacket pkt;
+int64_t start_time, end_time, duration;
+
+av_init_packet();
+
+oc->flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = avformat_write_header(oc, opts);
+if (ret) {
+fprintf(stderr, "Unexpected write header failure: %s\n",
+av_err2str(ret));
+goto fail;
+}
+
+av_assert0(pkt_data->sleep_time > 0);
+
+start_time = av_gettime_relative();
+for (i = 0; i < 16; i++ ) {
+ret = prepare_packet(, pkt_data, i);
+if (ret < 0) {
+fprintf(stderr, "Failed to prepare test packet: %s\n",
+av_err2str(ret));
+goto fail;
+}
+ret = retry_write_frame(oc, , 100);
+av_packet_unref();
+if (ret < 0)
+break;
+}
+
+if (ret) {
+fprintf(stderr, "Unexpected write_packet error: %s\n", 
av_err2str(ret));
+goto fail;
+}
+
+avformat_write_abort(oc);
+
+end_time = av_gettime_relative();
+duration = end_time - start_time;
+
+if (duration > (16*pkt_data->sleep_time)/2 ) {
+fprintf(stderr, "Aborting output took too much time: %u us,"
+" expected time if not aborted %u us\n",
+(unsigned) duration, 16*pkt_data->sleep_time);
+ret = AVERROR(ETIMEDOUT);
+}
+
+return ret;
+fail:
+avformat_write_abort(oc);
+return ret;
+}
+
 typedef struct TestCase {
 int (*test_func)(AVFormatContext *, AVDictionary **,const 
FailingMuxerPacketData *pkt_data);
 const char *test_name;
@@ -423,6 +554,14 @@ const TestCase tests[] = {
 {fifo_overflow_drop_test, "overflow with packet dropping", 
"queue_size=3:drop_pkts_on_overflow=1",
  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
 
+/* Simple test of nonblocking mode, the consumer should receive all 
the packets. */
+{fifo_nonblock_test, "nonblocking mode test", "queue_size=3",
+ 1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
+
+/* Test of terminating fifo muxer with av_abort_format() */
+{fifo_nonblock_abort_test, "abort in nonblocking mode", 
"queue_size=16",
+ 0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
+
 

[FFmpeg-devel] [PATCH v4 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version:
 - fixed wrong flag passed to av_thread_message_queue_recv()
 - fixed memleak when queue is full in nonblocking mode

 libavformat/fifo.c | 61 --
 1 file changed, 55 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 8896b9e..cdf9f49 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/thread.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   16
@@ -77,6 +79,17 @@ typedef struct FifoContext {
 /* Value > 0 signals queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -111,6 +124,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -433,12 +456,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -449,7 +477,8 @@ static int fifo_mux_init(AVFormatContext *avf)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -536,7 +565,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -545,15 +574,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AV_THREAD_MESSAGE_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+goto fail;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -581,6 +616,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join( fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -596,6 +635,16 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+avpriv_atomic_int_set(>termination_requested, 1);
+ret = 

[FFmpeg-devel] [PATCH v3 07/11] avformat/mux: Comment and assert AVFMT_FLAG_NONBLOCK

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add comments regarding AVFMG_FLAG_NONBLOCK usage with muxers.
Add assert forbiding use of nonblocking muxer with
av_interleaved_write_frame.

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - added assert to the beginning of av_interleaved_write_frame ensuring
   it is not called with muxer in nonblocking mode.
 - Changed commit description.

 libavformat/avformat.h | 9 -
 libavformat/mux.c  | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 83903b5..79c2511 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1428,7 +1428,7 @@ typedef struct AVFormatContext {
 int flags;
 #define AVFMT_FLAG_GENPTS   0x0001 ///< Generate missing pts even if it 
requires parsing future frames.
 #define AVFMT_FLAG_IGNIDX   0x0002 ///< Ignore index.
-#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets 
from input.
+#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets 
from input / writing packets to output.
 #define AVFMT_FLAG_IGNDTS   0x0008 ///< Ignore DTS on frames that contain 
both DTS & PTS
 #define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other 
values, just return what is stored in the container
 #define AVFMT_FLAG_NOPARSE  0x0020 ///< Do not use AVParsers, you also 
must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing 
-> no frames. Also seeking to frames can not work if parsing to find frame 
boundaries has been disabled
@@ -2391,6 +2391,10 @@ int avformat_write_header(AVFormatContext *s, 
AVDictionary **options);
  * the interleaving should call av_interleaved_write_frame() instead of this
  * function.
  *
+ * In case the muxer is operating in non-blocking mode (AVFMT_FLAG_NONBLOCK
+ * is set), this function can return AVERROR(EAGAIN) meaning the call should
+ * be repeated.
+ *
  * @param s media file handle
  * @param pkt The packet containing the data to be written. Note that unlike
  *av_interleaved_write_frame(), this function does not take
@@ -2433,6 +2437,9 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt);
  * knowledge of future packets, improving e.g. the behaviour of the mp4
  * muxer for VFR content in fragmenting mode.
  *
+ * This call is not supported and must not be called if muxer is operating
+ * in non-blocking mode (AVFMT_FLAG_NONBLOCK is set).
+ *
  * @param s media file handle
  * @param pkt The packet containing the data to be written.
  *
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 0f002a3..b4698b7 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1139,6 +1139,8 @@ int av_interleaved_write_frame(AVFormatContext *s, 
AVPacket *pkt)
 {
 int ret, flush = 0;
 
+av_assert0(!(s->flags & AVFMT_FLAG_NONBLOCK));
+
 ret = prepare_input_packet(s, pkt);
 if (ret < 0)
 goto fail;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 06/11] avformat: add avformat_write_abort() function

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version of the patch, just rebased
 because of the changes in previous patches.

 libavformat/avformat.h | 15 +++
 libavformat/mux.c  | 13 +
 2 files changed, 28 insertions(+)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 2cc3156..83903b5 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2512,6 +2512,8 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
  *
  * If AVFMT_FLAG_NONBLOCK is set, this call may return AVERROR(EAGAIN)
  * meaning the operation is pending and the call should be repeated.
+ * If caller decides to abort operation (after too many calls have returned
+ * AVERROR(EAGAIN)), it can be done by calling @ref avformat_write_abort().
  *
  * @param s media file handle
  * @return 0 if OK, AVERROR(EAGAIN) in case call should be repeated,
@@ -2520,6 +2522,19 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
 int av_write_trailer(AVFormatContext *s);
 
 /**
+ * Abort muxer operation and free private data.
+ * For muxer operating in blocking mode, this is equivalent to calling
+ * av_write_trailer. For muxer operating in non-blocking mode, this will
+ * call deinitialize routine even if there is operation pending
+ * and @ref av_write_trailer() keeps returning AVERROR(EAGAIN).
+ * May only be called after a successful call to avformat_write_header.
+ *
+ * @param s Media file handle
+ * return >= 0 on success, negative AVERROR on error
+ */
+int avformat_write_abort(AVFormatContext *s);
+
+/**
  * Return the output format in the list of registered output formats
  * which best matches the provided parameters, or return NULL if
  * there is no match.
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 45f1401..0f002a3 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1270,6 +1270,19 @@ fail:
 return ret;
 }
 
+int avformat_write_abort(AVFormatContext *s)
+{
+int ret;
+
+ret = av_write_trailer(s);
+if (ret == AVERROR(EAGAIN)) {
+deinit_muxer(s);
+ret = 0;
+}
+
+return ret;
+}
+
 int av_get_output_timestamp(struct AVFormatContext *s, int stream,
 int64_t *dts, int64_t *wall)
 {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 05/11] avformat/mux: Refactor muxer deinit from av_write_trailer

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Move muxer deinitialization and private resources freeing
in a separate static function free_muxer(AVFormatContext*).

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version, just rebased because
 of changes in previous patch.

 libavformat/mux.c | 31 ---
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index 3ae924c..45f1401 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1197,9 +1197,27 @@ fail:
 return ret;
 }
 
+static void deinit_muxer(AVFormatContext *s)
+{
+int i;
+
+if (s->oformat->deinit)
+s->oformat->deinit(s);
+
+for (i = 0; i < s->nb_streams; i++) {
+av_freep(>streams[i]->priv_data);
+av_freep(>streams[i]->index_entries);
+}
+
+if (s->oformat->priv_class)
+av_opt_free(s->priv_data);
+
+av_freep(>priv_data);
+}
+
 int av_write_trailer(AVFormatContext *s)
 {
-int ret, i;
+int ret;
 
 for (;; ) {
 AVPacket pkt;
@@ -1244,20 +1262,11 @@ fail:
 if (ret == AVERROR(EAGAIN))
 return ret;
 
-if (s->oformat->deinit)
-s->oformat->deinit(s);
-
 if (s->pb)
avio_flush(s->pb);
 if (ret == 0)
ret = s->pb ? s->pb->error : 0;
-for (i = 0; i < s->nb_streams; i++) {
-av_freep(>streams[i]->priv_data);
-av_freep(>streams[i]->index_entries);
-}
-if (s->oformat->priv_class)
-av_opt_free(s->priv_data);
-av_freep(>priv_data);
+deinit_muxer(s);
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 04/11] avformat/muxers: Add non-blocking mode support for av_write_trailer

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This makes av_write_trailer not to free the resources if write_trailer
call returns AVERROR(EAGAIN) allowing repeated calls of write_trailer of
non-blocking muxer.

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Added assert to the part of the code dealing with flushing
   interleaved packets which should not be entered if 
   muxer in non-blocking mode is used.
   (also there is assert for the same condition added into
av_interleaved_write_packet in one of the following 
patches).

 libavformat/avformat.h |  6 +-
 libavformat/mux.c  | 10 --
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index d8a6cf3..2cc3156 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2510,8 +2510,12 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
  *
  * May only be called after a successful call to avformat_write_header.
  *
+ * If AVFMT_FLAG_NONBLOCK is set, this call may return AVERROR(EAGAIN)
+ * meaning the operation is pending and the call should be repeated.
+ *
  * @param s media file handle
- * @return 0 if OK, AVERROR_xxx on error
+ * @return 0 if OK, AVERROR(EAGAIN) in case call should be repeated,
+ * other AVERROR on error
  */
 int av_write_trailer(AVFormatContext *s);
 
diff --git a/libavformat/mux.c b/libavformat/mux.c
index e9973ed..3ae924c 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1204,11 +1204,14 @@ int av_write_trailer(AVFormatContext *s)
 for (;; ) {
 AVPacket pkt;
 ret = interleave_packet(s, , NULL, 1);
-if (ret < 0)
-goto fail;
 if (!ret)
 break;
 
+av_assert0(!(s->flags & AVFMT_FLAG_NONBLOCK));
+
+if (ret < 0)
+goto fail;
+
 ret = write_packet(s, );
 if (ret >= 0)
 s->streams[pkt.stream_index]->nb_frames++;
@@ -1238,6 +1241,9 @@ fail:
 }
 }
 
+if (ret == AVERROR(EAGAIN))
+return ret;
+
 if (s->oformat->deinit)
 s->oformat->deinit(s);
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 03/11] avformat/fifo: Add fate test

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Fixed whitespace and missing $(EXESUF) in fifo-muxer.mak
 - Fixed "overflow with packet dropping" test which skipped write_trailer
   call in case of failure.

 libavformat/Makefile   |   1 +
 libavformat/tests/fifo_muxer.c | 443 +
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  11 +
 5 files changed, 476 insertions(+)
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2d2b78c..5d827d31 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -591,6 +591,7 @@ TESTPROGS = seek
\
 url \
 #   async   \
 
+TESTPROGS-$(CONFIG_FIFO_MUXER)   += fifo_muxer
 TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
 TESTPROGS-$(CONFIG_MOV_MUXER)+= movenc
 TESTPROGS-$(CONFIG_NETWORK)  += noproxy
diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
new file mode 100644
index 000..d6ce85d
--- /dev/null
+++ b/libavformat/tests/fifo_muxer.c
@@ -0,0 +1,443 @@
+/*
+ * FIFO pseudo-muxer
+ * Copyright (c) 2016 Jan Sebechlebsky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+
+#define MAX_TST_PACKETS 128
+#define SLEEPTIME_50_MS 5
+#define SLEEPTIME_10_MS 1
+
+/* Implementation of mock muxer to simulate real muxer failures */
+
+/* This is structure of data sent in packets to
+ * failing muxer */
+typedef struct FailingMuxerPacketData {
+int ret; /* return value of write_packet call*/
+int recover_after;   /* set ret to zero after this number of recovery 
attempts */
+unsigned sleep_time; /* sleep for this long in write_packet to simulate 
long I/O operation */
+} FailingMuxerPacketData;
+
+
+typedef struct FailingMuxerContext {
+AVClass *class;
+int write_header_ret;
+int write_trailer_ret;
+/* If non-zero, summary of processed packets will be printed in deinit */
+uint8_t print_deinit_summary;
+
+int flush_count;
+int pts_written[MAX_TST_PACKETS];
+int pts_written_nr;
+} FailingMuxerContext;
+
+static int failing_write_header(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_header_ret;
+}
+
+static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+int ret = 0;
+if (!pkt) {
+ctx->flush_count++;
+} else {
+FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data;
+
+if (!data->recover_after) {
+data->ret = 0;
+} else {
+data->recover_after--;
+}
+
+ret = data->ret;
+
+if (data->sleep_time) {
+int64_t slept = 0;
+while (slept < data->sleep_time) {
+if (ff_check_interrupt(>interrupt_callback))
+return AVERROR_EXIT;
+av_usleep(SLEEPTIME_10_MS);
+slept += SLEEPTIME_10_MS;
+}
+}
+
+if (!ret) {
+ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
+av_packet_unref(pkt);
+}
+}
+return ret;
+}
+
+static int failing_write_trailer(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_trailer_ret;
+}
+
+static void failing_deinit(AVFormatContext *avf)
+{
+int i;
+FailingMuxerContext *ctx = avf->priv_data;
+
+if (!ctx->print_deinit_summary)
+return;
+
+printf("flush count: %d\n", ctx->flush_count);
+printf("pts seen nr: %d\n", ctx->pts_written_nr);
+printf("pts seen: ");
+

[FFmpeg-devel] [PATCH v7 01/11] avformat: Add fifo pseudo-muxer

2016-08-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of the patch:
 - Fixed thread include (old patch included pthread.h directly)

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  93 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 665 +++
 libavformat/version.h|   2 +-
 7 files changed, 763 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index d9b6ecb..db6e415 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version :
 - MediaCodec hwaccel
 - True Audio (TTA) muxer
 - crystalizer audio filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 8e30c68..7599dc1 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..e2f06d3 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,99 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second indefinitely.
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format flv -map 0:v -map 
0:a
+  -block_on_overflow 0 -attempt_recovery 1 -recovery_wait_time 1
+  -max_recovery_attempts 0 rtmp://example.com/live/stream_name
+@end 

[FFmpeg-devel] [PATCH v3 5/5] avformat/tee: Use BSF list API

2016-08-09 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version of patch:
 - removed parse_bsfs() function I accidentaly left out
   (it's replaced by av_bsf_list_parse_str())
 libavformat/tee.c | 120 ++
 1 file changed, 57 insertions(+), 63 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 5689ca3..7218b02 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -37,7 +37,7 @@ typedef enum {
 
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -64,46 +64,6 @@ static const AVClass tee_muxer_class = {
 .version= LIBAVUTIL_VERSION_INT,
 };
 
-/**
- * Parse list of bitstream filters and add them to the list of filters
- * pointed to by bsfs.
- *
- * The list must be specified in the form:
- * BSFS ::= BSF[,BSFS]
- */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
-{
-char *bsf_name, *buf, *dup, *saveptr;
-int ret = 0;
-
-if (!(dup = buf = av_strdup(bsfs_spec)))
-return AVERROR(ENOMEM);
-
-while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
-
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
-   bsf_name);
-ret = AVERROR_UNKNOWN;
-goto end;
-}
-
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
-
-buf = NULL;
-}
-
-end:
-av_free(dup);
-return ret;
-}
-
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
 {
 if (!opt) {
@@ -135,14 +95,8 @@ static int close_slave(TeeSlave *tee_slave)
 ret = av_write_trailer(avf);
 
 if (tee_slave->bsfs) {
-for (i = 0; i < avf->nb_streams; ++i) {
-AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
-while (bsf) {
-bsf_next = bsf->next;
-av_bitstream_filter_close(bsf);
-bsf = bsf_next;
-}
-}
+for (i = 0; i < avf->nb_streams; ++i)
+av_bsf_free(_slave->bsfs[i]);
 }
 av_freep(_slave->stream_map);
 av_freep(_slave->bsfs);
@@ -312,7 +266,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
"output '%s', filters will be ignored\n", i, 
filename);
 continue;
 }
-ret = parse_bsfs(avf, entry->value, _slave->bsfs[i]);
+ret = av_bsf_list_parse_str(entry->value, _slave->bsfs[i]);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR,
"Error parsing bitstream filter sequence '%s' 
associated to "
@@ -325,6 +279,31 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 av_dict_set(, entry->key, NULL, 0);
 }
 
+for (i = 0; i < avf2->nb_streams; i++){
+if (!tee_slave->bsfs[i]) {
+/* Add pass-through bitstream filter */
+ret = av_bsf_get_null_filter(_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+   "Failed to create pass-through bitstream filter: %s\n",
+   av_err2str(ret));
+goto end;
+}
+}
+
+tee_slave->bsfs[i]->time_base_in = avf2->streams[i]->time_base;
+ret = avcodec_parameters_copy(tee_slave->bsfs[i]->par_in,
+  avf2->streams[i]->codecpar);
+
+ret = av_bsf_init(tee_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+"Failed to initialize bitstream filter(s): %s\n",
+av_err2str(ret));
+goto end;
+}
+}
+
 if (options) {
 entry = NULL;
 while ((entry = av_dict_get(options, "", entry, 
AV_DICT_IGNORE_SUFFIX)))
@@ -349,20 +328,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int 
log_level)
slave->avf->filename, slave->avf->oformat->name);
 for (i = 0; i < slave->avf->nb_streams; i++) {
 AVStream *st = slave->avf->streams[i];
-AVBitStreamFilterContext *bsf = slave->bsfs[i];
+AVBSFContext *bsf = slave->bsfs[i];
+const char * bsf_name;
 
 av_log(log_ctx, log_level, "stream:%d codec:%s type:%s",
i, avcodec_get_name(st->codecpar->codec_id),
av_get_media_type_string(st->codecpar->codec_type));
-if (bsf) {
-   

[FFmpeg-devel] [PATCH v3 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-09 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 No changes since the last version of the patch, just rebased
 because of changes in the previous commit.

 libavformat/fifo.c | 61 --
 1 file changed, 55 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index a4bf410..c3f17d5 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
 #include "pthread.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   16
@@ -77,6 +79,17 @@ typedef struct FifoContext {
 /* Value > 0 signals queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -111,6 +124,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -433,12 +456,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -449,7 +477,8 @@ static int fifo_mux_init(AVFormatContext *avf)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -536,7 +565,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -545,15 +574,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+return ret;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -581,6 +616,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join( fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -596,6 +635,16 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+avpriv_atomic_int_set(>termination_requested, 1);
+ret = pthread_join( fifo->writer_thread, NULL);
+if (ret 

[FFmpeg-devel] [PATCH v2 03/11] avformat/fifo: Add fate test

2016-08-09 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version:
 - Removed empty lines at the end of fifo_muxer.c file

 libavformat/Makefile   |   1 +
 libavformat/tests/fifo_muxer.c | 443 +
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  11 +
 5 files changed, 476 insertions(+)
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2d2b78c..5d827d31 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -591,6 +591,7 @@ TESTPROGS = seek
\
 url \
 #   async   \
 
+TESTPROGS-$(CONFIG_FIFO_MUXER)  += fifo_muxer
 TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
 TESTPROGS-$(CONFIG_MOV_MUXER)+= movenc
 TESTPROGS-$(CONFIG_NETWORK)  += noproxy
diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
new file mode 100644
index 000..94510c4
--- /dev/null
+++ b/libavformat/tests/fifo_muxer.c
@@ -0,0 +1,443 @@
+/*
+ * FIFO pseudo-muxer
+ * Copyright (c) 2016 Jan Sebechlebsky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+
+#define MAX_TST_PACKETS 128
+#define SLEEPTIME_50_MS 5
+#define SLEEPTIME_10_MS 1
+
+/* Implementation of mock muxer to simulate real muxer failures */
+
+/* This is structure of data sent in packets to
+ * failing muxer */
+typedef struct FailingMuxerPacketData {
+int ret; /* return value of write_packet call*/
+int recover_after;   /* set ret to zero after this number of recovery 
attempts */
+unsigned sleep_time; /* sleep for this long in write_packet to simulate 
long I/O operation */
+} FailingMuxerPacketData;
+
+
+typedef struct FailingMuxerContext {
+AVClass *class;
+int write_header_ret;
+int write_trailer_ret;
+/* If non-zero, summary of processed packets will be printed in deinit */
+uint8_t print_deinit_summary;
+
+int flush_count;
+int pts_written[MAX_TST_PACKETS];
+int pts_written_nr;
+} FailingMuxerContext;
+
+static int failing_write_header(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_header_ret;
+}
+
+static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+int ret = 0;
+if (!pkt) {
+ctx->flush_count++;
+} else {
+FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data;
+
+if (!data->recover_after) {
+data->ret = 0;
+} else {
+data->recover_after--;
+}
+
+ret = data->ret;
+
+if (data->sleep_time) {
+int64_t slept = 0;
+while (slept < data->sleep_time) {
+if (ff_check_interrupt(>interrupt_callback))
+return AVERROR_EXIT;
+av_usleep(SLEEPTIME_10_MS);
+slept += SLEEPTIME_10_MS;
+}
+}
+
+if (!ret) {
+ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
+av_packet_unref(pkt);
+}
+}
+return ret;
+}
+
+static int failing_write_trailer(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_trailer_ret;
+}
+
+static void failing_deinit(AVFormatContext *avf)
+{
+int i;
+FailingMuxerContext *ctx = avf->priv_data;
+
+if (!ctx->print_deinit_summary)
+return;
+
+printf("flush count: %d\n", ctx->flush_count);
+printf("pts seen nr: %d\n", ctx->pts_written_nr);
+printf("pts seen: ");
+for (i = 0; i < ctx->pts_written_nr; ++i ) {
+printf(i ? ",%d" : "%d", ctx->pts_written[i]);
+}
+

[FFmpeg-devel] [PATCH v6 01/11] avformat: Add fifo pseudo-muxer

2016-08-09 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes since the last version done according Martons review:
 - Documentation fixes as requested
 - Rearanged message processing in while loop inside fifo_cosumer_thread,
   added FIFO_WRITE_HEADER message type, message is initialized to
   FIFO_WRITE_HEADER in fifo_consumer_thread so that this message
   is processed immediately after entering the while loop.
 - Fixed error description when using streamtime is requested, but 
   drop_pkts_on_overflow is turned off.
 - Fixed queue allocation return value check
 - Removed avf check prior to freeing avf in fifo_deinit
   since it is safe to pass NULL to avformat_free_context
 - Removed empty line at the end of the fifo.c file

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  93 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 665 +++
 libavformat/version.h|   2 +-
 7 files changed, 763 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index d9b6ecb..db6e415 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version :
 - MediaCodec hwaccel
 - True Audio (TTA) muxer
 - crystalizer audio filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 8e30c68..7599dc1 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..e2f06d3 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,99 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows the separation of encoding and muxing by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The behavior of the fifo muxer if the queue fills up or if the output fails is
+selectable,
+
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the input, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least 
@var{recovery_wait_time}
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain (usually permanent) errors the recovery is not attempted even when
+@var{attempt_recovery} is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after 

[FFmpeg-devel] [PATCH v2 5/5] avformat/tee: Use BSF list API

2016-08-05 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 No changes from the last version, just rebased after Michael's commit.

 libavformat/tee.c | 80 +++
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 5689ca3..179ad2d 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -37,7 +37,7 @@ typedef enum {
 
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -135,14 +135,8 @@ static int close_slave(TeeSlave *tee_slave)
 ret = av_write_trailer(avf);
 
 if (tee_slave->bsfs) {
-for (i = 0; i < avf->nb_streams; ++i) {
-AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
-while (bsf) {
-bsf_next = bsf->next;
-av_bitstream_filter_close(bsf);
-bsf = bsf_next;
-}
-}
+for (i = 0; i < avf->nb_streams; ++i)
+av_bsf_free(_slave->bsfs[i]);
 }
 av_freep(_slave->stream_map);
 av_freep(_slave->bsfs);
@@ -312,7 +306,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
"output '%s', filters will be ignored\n", i, 
filename);
 continue;
 }
-ret = parse_bsfs(avf, entry->value, _slave->bsfs[i]);
+ret = av_bsf_list_parse_str(entry->value, _slave->bsfs[i]);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR,
"Error parsing bitstream filter sequence '%s' 
associated to "
@@ -325,6 +319,31 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 av_dict_set(, entry->key, NULL, 0);
 }
 
+for (i = 0; i < avf2->nb_streams; i++){
+if (!tee_slave->bsfs[i]) {
+/* Add pass-through bitstream filter */
+ret = av_bsf_get_null_filter(_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+   "Failed to create pass-through bitstream filter: %s\n",
+   av_err2str(ret));
+goto end;
+}
+}
+
+tee_slave->bsfs[i]->time_base_in = avf2->streams[i]->time_base;
+ret = avcodec_parameters_copy(tee_slave->bsfs[i]->par_in,
+  avf2->streams[i]->codecpar);
+
+ret = av_bsf_init(tee_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+"Failed to initialize bitstream filter(s): %s\n",
+av_err2str(ret));
+goto end;
+}
+}
+
 if (options) {
 entry = NULL;
 while ((entry = av_dict_get(options, "", entry, 
AV_DICT_IGNORE_SUFFIX)))
@@ -349,20 +368,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int 
log_level)
slave->avf->filename, slave->avf->oformat->name);
 for (i = 0; i < slave->avf->nb_streams; i++) {
 AVStream *st = slave->avf->streams[i];
-AVBitStreamFilterContext *bsf = slave->bsfs[i];
+AVBSFContext *bsf = slave->bsfs[i];
+const char * bsf_name;
 
 av_log(log_ctx, log_level, "stream:%d codec:%s type:%s",
i, avcodec_get_name(st->codecpar->codec_id),
av_get_media_type_string(st->codecpar->codec_type));
-if (bsf) {
-av_log(log_ctx, log_level, " bsfs:");
-while (bsf) {
-av_log(log_ctx, log_level, "%s%s",
-   bsf->filter->name, bsf->next ? "," : "");
-bsf = bsf->next;
-}
-}
-av_log(log_ctx, log_level, "\n");
+
+bsf_name = bsf->filter->priv_class ?
+   bsf->filter->priv_class->item_name(bsf) : bsf->filter->name;
+av_log(log_ctx, log_level, " bsfs: %s\n", bsf_name);
 }
 }
 
@@ -506,13 +521,32 @@ static int tee_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 av_packet_rescale_ts(, tb, tb2);
 pkt2.stream_index = s2;
 
-if ((ret = av_apply_bitstream_filters(avf2->streams[s2]->codec, ,
-  tee->slaves[i].bsfs[s2])) < 0 ||
-(ret = av_interleaved_write_frame(avf2, )) < 0) {
+ret = av_bsf_send_packet(tee->slaves[i].bsfs[s2], );
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR, "Error while sending packet to bitstream 
filter: %s\n",
+   av_err2str(ret));
 ret = tee_process_slave_failure(avf, i, ret);
 if (!ret_all && ret < 0)
 ret_all = ret;
 }
+
+do {
+ret = av_bsf_receive_packet(tee->slaves[i].bsfs[s2], );
+if (ret < 0)
+

[FFmpeg-devel] [PATCH v2 4/5] avcodec/bsf: Add custom item name func for BSF list

2016-08-05 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add custom item name function for bsf list, which will
construct string description of filter chain. This is
done using lazy-initialization, so there is no overhead
if item name is never accessed.

Signed-off-by: Jan Sebechlebsky 
---
 No changes from last version, just rebased because of the changes in
 previous patch.

 libavcodec/bsf.c | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index dcdc1d3..2462e62 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -248,6 +248,7 @@ typedef struct BSFListContext {
 unsigned idx;   // index of currently processed BSF
 unsigned flushed_idx;   // index of BSF being flushed
 
+char * item_name;
 } BSFListContext;
 
 
@@ -348,9 +349,34 @@ static void bsf_list_close(AVBSFContext *bsf)
 av_freep(>item_name);
 }
 
+static const char *bsf_list_item_name(void *ctx)
+{
+static const char *null_filter_name = "null";
+AVBSFContext *bsf_ctx = ctx;
+BSFListContext *lst = bsf_ctx->priv_data;
+
+if (!lst->nb_bsfs)
+return null_filter_name;
+
+if (!lst->item_name) {
+int i;
+AVBPrint bp;
+av_bprint_init(, 16, 128);
+
+av_bprintf(, "bsf_list(");
+for (i = 0; i < lst->nb_bsfs; i++)
+av_bprintf(, i ? ",%s" : "%s", lst->bsfs[i]->filter->name);
+av_bprintf(, ")");
+
+av_bprint_finalize(, >item_name);
+}
+
+return lst->item_name;
+}
+
 static const AVClass bsf_list_class = {
 .class_name = "bsf_list",
-.item_name  = av_default_item_name,
+.item_name  = bsf_list_item_name,
 .version= LIBAVUTIL_VERSION_INT,
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/5] avcodec/bsf: Add list BSF API

2016-08-05 Thread sebechlebskyjan
From: Jan Sebechlebsky 

---
 Changes from last version:
 - fixed doxygen comments
 - added av_bsf_list_append2() function
 - changed names of array and length fields to follow naming convention
 - idx and flushed_idx is now unsigned
 - merged bsf_list_flush to bsf_list_filter to reduce code duplication
 - aligned structure fields initialization
 - added check for NULL to av_bsf_free()
 - fixed memleak in av_bsf_finalize in case there is only 1 filter

 libavcodec/avcodec.h |  85 
 libavcodec/bsf.c | 279 +++
 2 files changed, 364 insertions(+)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 6c2c4a7..06c2b89 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -5951,6 +5951,91 @@ void av_bsf_free(AVBSFContext **ctx);
  */
 const AVClass *av_bsf_get_class(void);
 
+/**
+ * Structure for chain/list of bitstream filters.
+ * Empty list can be allocated by av_bsf_list_alloc().
+ */
+typedef struct AVBSFList AVBSFList;
+
+/**
+ * Allocate empty list of bitstream filters.
+ * The list must be later freed by av_bsf_list_free()
+ * or finalized by av_bsf_list_finalize().
+ *
+ * @return Pointer to @ref AVBSFList on success, NULL in case of failure
+ */
+AVBSFList *av_bsf_list_alloc(void);
+
+/**
+ * Free list of bitstream filters.
+ *
+ * @param lst Pointer to pointer returned by av_bsf_list_alloc()
+ */
+void av_bsf_list_free(AVBSFList **lst);
+
+/**
+ * Append bitstream filter to the list of bitstream filters.
+ *
+ * @param lst List to append to
+ * @param bsf Filter context to be appended
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf);
+
+/**
+ * Construct new bitstream filter context given it's name and options
+ * and append it to the list of bitstream filters.
+ *
+ * @param lst  List to append to
+ * @param bsf_name Name of the bitstream filter
+ * @param options  Options for the bitstream filter, can be set to NULL
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary 
**options);
+/**
+ * Finalize list of bitstream filters.
+ *
+ * This function will transform @ref AVBSFList to single @ref AVBSFContext,
+ * so the whole chain of bitstream filters can be treated as single filter
+ * freshly allocated by av_bsf_alloc().
+ * If the call is successfull, @ref AVBSFList structure is freed and lst
+ * will be set to NULL. In case of failure, caller is responsible for
+ * freeing the structure by av_bsf_list_free()
+ *
+ * @param  lst Filter list structure to be transformed
+ * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext 
structure
+ * representing the chain of bitstream filters
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf);
+
+/**
+ * Parse string describing list of bitstream filters and create single
+ * @ref AVBSFContext describing the whole chain of bitstream filters.
+ * Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext 
freshly
+ * allocated by av_bsf_alloc().
+ *
+ * @param  str String describing chain of bitstream filters in format
+ * `bsf1[=opt1=val1:opt2=val2][,bsf2]`
+ * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext 
structure
+ * representing the chain of bitstream filters
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf);
+
+/**
+ * Get null/pass-through bitstream filter.
+ *
+ * @param[out] bsf Pointer to be set to new instance of pass-through bitstream 
filter
+ *
+ * @return
+ */
+int av_bsf_get_null_filter(AVBSFContext **bsf);
+
 /* memory */
 
 /**
diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 40fc925..dcdc1d3 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -22,6 +22,8 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
 
 #include "avcodec.h"
 #include "bsf.h"
@@ -236,3 +238,280 @@ int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket 
*pkt)
 
 return 0;
 }
+
+typedef struct BSFListContext {
+const AVClass *class;
+
+AVBSFContext **bsfs;
+int nb_bsfs;
+
+unsigned idx;   // index of currently processed BSF
+unsigned flushed_idx;   // index of BSF being flushed
+
+} BSFListContext;
+
+
+static int bsf_list_init(AVBSFContext *bsf)
+{
+BSFListContext *lst = bsf->priv_data;
+int ret, i;
+const AVCodecParameters *cod_par = bsf->par_in;
+AVRational tb = bsf->time_base_in;
+
+for (i = 0; i < lst->nb_bsfs; ++i) {
+ret = avcodec_parameters_copy(lst->bsfs[i]->par_in, cod_par);
+if (ret < 0)
+goto fail;
+
+ 

[FFmpeg-devel] [PATCH v2 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 Changes from the last version:
 - boolean flags accessed from both threads are ints now
   and are accessed with atomic operations.
 - pthread_tryjoin_np is replaced by flag set before
   fifo_consumer_thread returns

 libavformat/fifo.c | 61 --
 1 file changed, 55 insertions(+), 6 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index bd9d934..9b92eab 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -19,12 +19,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/atomic.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
 #include "pthread.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   16
@@ -77,6 +79,17 @@ typedef struct FifoContext {
 /* Value > 0 signalizes queue overflow */
 volatile uint8_t overflow_flag;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile int termination_requested;
+
+/* Initially 0, set to 1 immediately before thread function
+ * returns */
+volatile int thread_finished_flag;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -110,6 +123,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (avpriv_atomic_int_get(>termination_requested))
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -442,12 +465,17 @@ static void *fifo_consumer_thread(void *data)
 
 fifo->write_trailer_ret = fifo_thread_write_trailer(_thread_ctx);
 
+/* This must be only return path from fifo_consumer_thread function,
+ * so the thread_finised_flag is set. */
+avpriv_atomic_int_set(>thread_finished_flag, 1);
 return NULL;
 }
 
 static int fifo_mux_init(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -458,7 +486,8 @@ static int fifo_mux_init(AVFormatContext *avf)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -543,7 +572,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -552,15 +581,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+return ret;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -588,6 +623,10 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
+if ((avf->flags & AVFMT_FLAG_NONBLOCK) &&
+!avpriv_atomic_int_get(>thread_finished_flag))
+   return AVERROR(EAGAIN);
+
 ret = pthread_join( fifo->writer_thread, NULL);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
@@ -603,6 +642,16 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+

[FFmpeg-devel] [PATCH v2 06/11] avformat: add avformat_write_abort() function

2016-08-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes from last version of patch:
 - removed AVFMT_FLAG_NONBLOCK check and modified comment 
   so it states how function behaves with both blocking / non-blocking muxer

 libavformat/avformat.h | 15 +++
 libavformat/mux.c  | 13 +
 2 files changed, 28 insertions(+)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 578f99f..3f6a6eb 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2512,6 +2512,8 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
  *
  * If AVFMT_FLAG_NONBLOCK is set, this call may return AVERROR(EAGAIN)
  * meaning the operation is pending and the call should be repeated.
+ * If caller decides to abort operation (after too many calls have returned
+ * AVERROR(EAGAIN)), it can be done by calling @ref avformat_write_abort().
  *
  * @param s media file handle
  * @return 0 if OK, AVERROR(EAGAIN) in case call should be repeated,
@@ -2520,6 +2522,19 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
 int av_write_trailer(AVFormatContext *s);
 
 /**
+ * Abort muxer operation and free private data.
+ * For muxer operating in blocking mode, this is equivalent to calling
+ * av_write_trailer. For muxer operating in non-blocking mode, this will
+ * call deinitialize routine even if there is operation pending
+ * and @ref av_write_trailer() keeps returning AVERROR(EAGAIN).
+ * May only be called after a successful call to avformat_write_header.
+ *
+ * @param s Media file handle
+ * return >= 0 on success, negative AVERROR on error
+ */
+int avformat_write_abort(AVFormatContext *s);
+
+/**
  * Return the output format in the list of registered output formats
  * which best matches the provided parameters, or return NULL if
  * there is no match.
diff --git a/libavformat/mux.c b/libavformat/mux.c
index bc9c98f..a3c1d8a 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1267,6 +1267,19 @@ fail:
 return ret;
 }
 
+int avformat_write_abort(AVFormatContext *s)
+{
+int ret;
+
+ret = av_write_trailer(s);
+if (ret == AVERROR(EAGAIN)) {
+deinit_muxer(s);
+ret = 0;
+}
+
+return ret;
+}
+
 int av_get_output_timestamp(struct AVFormatContext *s, int stream,
 int64_t *dts, int64_t *wall)
 {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v5 01/11] avformat: Add fifo pseudo-muxer

2016-08-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes from the last version of patch:
  - boolean AVOptions are now ints, this was the cause of fate test
segfault reported by Michael

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  90 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 674 +++
 libavformat/version.h|   2 +-
 7 files changed, 769 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index 0f9b4cf..3f858f1 100644
--- a/Changelog
+++ b/Changelog
@@ -12,6 +12,7 @@ version :
 - 16-bit support in selectivecolor filter
 - OpenH264 decoder wrapper
 - MediaCodec hwaccel
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9f5b31f..4651f5f 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..e2bc290 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,96 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows to separate encoding from any other muxer by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The behavior of fifo muxer in case of failure can be configured:
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the output, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least recovery_wait_time
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain errors the recovery is not attempted even when @ref{attempt_recovery}
+is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second indefinitely.
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format flv -map 0:v -map 
0:a
+  -block_on_overflow 0 -attempt_recovery 1 -recovery_wait_time 1
+  -max_recovery_attempts 0 rtmp://example.com/live/stream_name
+@end 

[FFmpeg-devel] [PATCH 11/11] avformat/fifo: Add test for nonblocking mode

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tests/fifo_muxer.c | 139 +
 tests/ref/fate/fifo-muxer-tst  |   5 ++
 2 files changed, 144 insertions(+)

diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
index 0b5a95e..0a90f36 100644
--- a/libavformat/tests/fifo_muxer.c
+++ b/libavformat/tests/fifo_muxer.c
@@ -336,6 +336,137 @@ fail:
 return ret;
 }
 
+static int retry_write_frame(AVFormatContext *oc, AVPacket *pkt, int 
max_retries)
+{
+int ret = 0, retry_count = 0;
+do {
+ret = av_write_frame(oc, pkt);
+if (ret == AVERROR(EAGAIN)) {
+av_usleep(SLEEPTIME_10_MS);
+retry_count++;
+}
+} while ( ret == AVERROR(EAGAIN) && retry_count < max_retries);
+return ret;
+}
+
+static int retry_write_trailer(AVFormatContext *oc, int max_retries)
+{
+int ret = 0, retry_count = 0;
+do {
+ret = av_write_trailer(oc);
+if (ret == AVERROR(EAGAIN)) {
+av_usleep(SLEEPTIME_10_MS);
+retry_count++;
+}
+} while (ret == AVERROR(EAGAIN) && retry_count < max_retries);
+return ret;
+}
+
+static int fifo_nonblock_test(AVFormatContext *oc, AVDictionary **opts,
+  const FailingMuxerPacketData *pkt_data)
+{
+int ret = 0, i;
+AVPacket pkt;
+
+av_init_packet();
+
+oc->flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = avformat_write_header(oc, opts);
+if (ret) {
+fprintf(stderr, "Unexpected write_header failure: %s\n",
+av_err2str(ret));
+return ret;
+}
+
+for (i = 0; i < 16; i++ ) {
+ret = prepare_packet(, pkt_data, i);
+if (ret < 0) {
+fprintf(stderr, "Failed to prepare test packet: %s\n",
+av_err2str(ret));
+goto fail;
+}
+ret = retry_write_frame(oc, , 100);
+av_packet_unref();
+if (ret < 0)
+break;
+}
+
+if (ret) {
+fprintf(stderr, "Unexpected write_packet error: %s\n", 
av_err2str(ret));
+goto fail;
+}
+
+ret = retry_write_trailer(oc, 100);
+if (ret == AVERROR(EAGAIN)) {
+fprintf(stderr, "write_trailer() operation timeout\n");
+goto fail;
+} else if (ret < 0)
+fprintf(stderr, "Unexpected write_trailer error: %s\n", 
av_err2str(ret));
+
+return ret;
+fail:
+av_abort_output(oc);
+return ret;
+}
+
+static int fifo_nonblock_abort_test(AVFormatContext *oc, AVDictionary **opts,
+const FailingMuxerPacketData *pkt_data)
+{
+int ret = 0, i;
+AVPacket pkt;
+int64_t start_time, end_time, duration;
+
+av_init_packet();
+
+oc->flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = avformat_write_header(oc, opts);
+if (ret) {
+fprintf(stderr, "Unexpected write header failure: %s\n",
+av_err2str(ret));
+goto fail;
+}
+
+av_assert0(pkt_data->sleep_time > 0);
+
+start_time = av_gettime_relative();
+for (i = 0; i < 16; i++ ) {
+ret = prepare_packet(, pkt_data, i);
+if (ret < 0) {
+fprintf(stderr, "Failed to prepare test packet: %s\n",
+av_err2str(ret));
+goto fail;
+}
+ret = retry_write_frame(oc, , 100);
+av_packet_unref();
+if (ret < 0)
+break;
+}
+
+if (ret) {
+fprintf(stderr, "Unexpected write_packet error: %s\n", 
av_err2str(ret));
+goto fail;
+}
+
+av_abort_output(oc);
+
+end_time = av_gettime_relative();
+duration = end_time - start_time;
+
+if (duration > (16*pkt_data->sleep_time)/2 ) {
+fprintf(stderr, "Aborting output took too much time: %u us,"
+" expected time if not aborted %u us\n",
+(unsigned) duration, 16*pkt_data->sleep_time);
+ret = AVERROR(ETIMEDOUT);
+}
+
+return ret;
+fail:
+av_abort_output(oc);
+return ret;
+}
+
 typedef struct TestCase {
 int (*test_func)(AVFormatContext *, AVDictionary **,const 
FailingMuxerPacketData *pkt_data);
 const char *test_name;
@@ -423,6 +554,14 @@ const TestCase tests[] = {
 {fifo_overflow_drop_test, "overflow with packet dropping", 
"queue_size=3:drop_pkts_on_overflow=1",
  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
 
+/* Simple test of nonblocking mode, the consumer should receive all 
the packets. */
+{fifo_nonblock_test, "nonblocking mode test", "queue_size=3",
+ 1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
+
+/* Test of terminating fifo muxer with av_abort_format() */
+{fifo_nonblock_abort_test, "abort in nonblocking mode", 
"queue_size=16",
+ 0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
+
 {NULL}
 };
 
diff --git a/tests/ref/fate/fifo-muxer-tst b/tests/ref/fate/fifo-muxer-tst
index ca7e294..1c18887 100644
--- 

[FFmpeg-devel] [GSoC] fifo muxer

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Hello,
I am resending fifo muxer related patchset, now 
also with patches adding support for nonblocking 
calls (AVFMT_FLAG_NONBLOCK) and fate tests.

Regards,
Jan

Jan Sebechlebsky (11):
  avformat: Add fifo pseudo-muxer
  MAINTAINERS: Add myself as maintainer of fifo muxer
  avformat/fifo: Add fate test
  avformat/muxers: Add non-blocking mode support for av_write_trailer
  avformat/mux: Refactor muxer deinit from av_write_trailer
  avformat: add av_abort_output() function
  avformat/avformat.h: Add comments regarding AVFMT_FLAG_NONBLOCK.
  avformat/mux: Restore original ts in write_packet on error
  avformat/mux: Restore stream ts in av_write_packet on EAGAIN
  avformat/fifo: Add AVFMT_FLAG_NONBLOCK support
  avformat/fifo: Add test for nonblocking mode

 Changelog  |   1 +
 MAINTAINERS|   1 +
 configure  |   1 +
 doc/muxers.texi|  90 +
 libavformat/Makefile   |   2 +
 libavformat/allformats.c   |   1 +
 libavformat/avformat.h |  29 +-
 libavformat/fifo.c | 722 +
 libavformat/mux.c  |  69 +++-
 libavformat/tests/fifo_muxer.c | 586 +
 libavformat/version.h  |   2 +-
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  16 +
 14 files changed, 1528 insertions(+), 13 deletions(-)
 create mode 100644 libavformat/fifo.c
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 08/11] avformat/mux: Restore original ts in write_packet on error

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Restore original timestamps in write_packet() if the
actual write operation was not successfull. This allows
to pass the same packet to nonblocking muxer repeatedly
without corrupting the timestamps.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/mux.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index 888a9f1..ef4720a 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -657,6 +657,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
 static int write_packet(AVFormatContext *s, AVPacket *pkt)
 {
 int ret, did_split;
+int64_t pts_backup, dts_backup;
+
+pts_backup = pkt->pts;
+dts_backup = pkt->dts;
 
 if (s->output_ts_offset) {
 AVStream *st = s->streams[pkt->stream_index];
@@ -743,6 +747,11 @@ fail:
 if (did_split)
 av_packet_merge_side_data(pkt);
 
+if (ret < 0) {
+pkt->pts = pts_backup;
+pkt->dts = dts_backup;
+}
+
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 05/11] avformat/mux: Refactor muxer deinit from av_write_trailer

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Move muxer deinitialization and private resources freeing
in a separate static function free_muxer(AVFormatContext*).

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/mux.c | 31 ---
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index b58e4c1..bc9c98f 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1197,9 +1197,27 @@ fail:
 return ret;
 }
 
+static void deinit_muxer(AVFormatContext *s)
+{
+int i;
+
+if (s->oformat->deinit)
+s->oformat->deinit(s);
+
+for (i = 0; i < s->nb_streams; i++) {
+av_freep(>streams[i]->priv_data);
+av_freep(>streams[i]->index_entries);
+}
+
+if (s->oformat->priv_class)
+av_opt_free(s->priv_data);
+
+av_freep(>priv_data);
+}
+
 int av_write_trailer(AVFormatContext *s)
 {
-int ret, i;
+int ret;
 
 for (;; ) {
 AVPacket pkt;
@@ -1241,20 +1259,11 @@ fail:
 if (ret == AVERROR(EAGAIN))
 return ret;
 
-if (s->oformat->deinit)
-s->oformat->deinit(s);
-
 if (s->pb)
avio_flush(s->pb);
 if (ret == 0)
ret = s->pb ? s->pb->error : 0;
-for (i = 0; i < s->nb_streams; i++) {
-av_freep(>streams[i]->priv_data);
-av_freep(>streams[i]->index_entries);
-}
-if (s->oformat->priv_class)
-av_opt_free(s->priv_data);
-av_freep(>priv_data);
+deinit_muxer(s);
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 02/11] MAINTAINERS: Add myself as maintainer of fifo muxer

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 932e6fb..9fab34d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -164,6 +164,7 @@ Codecs:
   exif.c, exif.hThilo Borgmann
   ffv1* Michael Niedermayer
   ffwavesynth.c Nicolas George
+  fifo.cJan Sebechlebsky
   flicvideo.c   Mike Melanson
   g722.cMartin Storsjo
   g726.cRoman Shaposhnik
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v4 01/11] avformat: Add fifo pseudo-muxer

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Changes from the last version of patch:
   - I got rid of write header message, and pulled initial write_header
 call out of the while loop as Nicolas originaly suggested.

 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  90 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 674 +++
 libavformat/version.h|   2 +-
 7 files changed, 769 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index 0f9b4cf..3f858f1 100644
--- a/Changelog
+++ b/Changelog
@@ -12,6 +12,7 @@ version :
 - 16-bit support in selectivecolor filter
 - OpenH264 decoder wrapper
 - MediaCodec hwaccel
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 9f5b31f..4651f5f 100755
--- a/configure
+++ b/configure
@@ -2834,6 +2834,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..e2bc290 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,96 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows to separate encoding from any other muxer by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The behavior of fifo muxer in case of failure can be configured:
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the output, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least recovery_wait_time
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain errors the recovery is not attempted even when @ref{attempt_recovery}
+is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second indefinitely.
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format flv -map 0:v -map 
0:a
+  -block_on_overflow 0 -attempt_recovery 1 -recovery_wait_time 1
+  -max_recovery_attempts 0 

[FFmpeg-devel] [PATCH 04/11] avformat/muxers: Add non-blocking mode support for av_write_trailer

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This makes av_write_trailer not to free the resources if write_trailer
call returns AVERROR(EAGAIN) allowing repeated calls of write_trailer of
non-blocking muxer.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/avformat.h | 6 +-
 libavformat/mux.c  | 3 +++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 818184e..9191c69 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2508,8 +2508,12 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
  *
  * May only be called after a successful call to avformat_write_header.
  *
+ * If AVFMT_FLAG_NONBLOCK is set, this call may return AVERROR(EAGAIN)
+ * meaning the operation is pending and the call should be repeated.
+ *
  * @param s media file handle
- * @return 0 if OK, AVERROR_xxx on error
+ * @return 0 if OK, AVERROR(EAGAIN) in case call should be repeated,
+ * other AVERROR on error
  */
 int av_write_trailer(AVFormatContext *s);
 
diff --git a/libavformat/mux.c b/libavformat/mux.c
index e9973ed..b58e4c1 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1238,6 +1238,9 @@ fail:
 }
 }
 
+if (ret == AVERROR(EAGAIN))
+return ret;
+
 if (s->oformat->deinit)
 s->oformat->deinit(s);
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 06/11] avformat: add av_abort_output() function

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/avformat.h | 14 ++
 libavformat/mux.c  | 16 
 2 files changed, 30 insertions(+)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 9191c69..9173908 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2510,6 +2510,8 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
  *
  * If AVFMT_FLAG_NONBLOCK is set, this call may return AVERROR(EAGAIN)
  * meaning the operation is pending and the call should be repeated.
+ * If caller decides to abort operation (after too many calls have returned
+ * AVERROR(EAGAIN)), it can be done by calling @ref av_abort_output().
  *
  * @param s media file handle
  * @return 0 if OK, AVERROR(EAGAIN) in case call should be repeated,
@@ -2518,6 +2520,18 @@ int av_write_uncoded_frame_query(AVFormatContext *s, int 
stream_index);
 int av_write_trailer(AVFormatContext *s);
 
 /**
+ * Abort non-blocking muxer operation and free private data.
+ *
+ * May only be called after a successful call to avformat_write_header,
+ * and used only with muxer operating in non-blocking mode 
(AVFMT_FLAG_NONBLOCK)
+ * must be set.
+ *
+ * @param s media file handle
+ * return >= 0 on success, negative AVERROR on error
+ */
+int av_abort_output(AVFormatContext *s);
+
+/**
  * Return the output format in the list of registered output formats
  * which best matches the provided parameters, or return NULL if
  * there is no match.
diff --git a/libavformat/mux.c b/libavformat/mux.c
index bc9c98f..888a9f1 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1267,6 +1267,22 @@ fail:
 return ret;
 }
 
+int av_abort_output(AVFormatContext *s)
+{
+int ret;
+
+if (!(s->flags & AVFMT_FLAG_NONBLOCK))
+return AVERROR(EINVAL);
+
+ret = av_write_trailer(s);
+if (ret == AVERROR(EAGAIN)) {
+deinit_muxer(s);
+ret = 0;
+}
+
+return ret;
+}
+
 int av_get_output_timestamp(struct AVFormatContext *s, int stream,
 int64_t *dts, int64_t *wall)
 {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 07/11] avformat/avformat.h: Add comments regarding AVFMT_FLAG_NONBLOCK.

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add comments regarding AVFMG_FLAG_NONBLOCK usage with muxers.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/avformat.h | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 9173908..6898c8c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1426,7 +1426,7 @@ typedef struct AVFormatContext {
 int flags;
 #define AVFMT_FLAG_GENPTS   0x0001 ///< Generate missing pts even if it 
requires parsing future frames.
 #define AVFMT_FLAG_IGNIDX   0x0002 ///< Ignore index.
-#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets 
from input.
+#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets 
from input / writing packets to output.
 #define AVFMT_FLAG_IGNDTS   0x0008 ///< Ignore DTS on frames that contain 
both DTS & PTS
 #define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other 
values, just return what is stored in the container
 #define AVFMT_FLAG_NOPARSE  0x0020 ///< Do not use AVParsers, you also 
must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing 
-> no frames. Also seeking to frames can not work if parsing to find frame 
boundaries has been disabled
@@ -2389,6 +2389,10 @@ int avformat_write_header(AVFormatContext *s, 
AVDictionary **options);
  * the interleaving should call av_interleaved_write_frame() instead of this
  * function.
  *
+ * In case the muxer is operating in non-blocking mode (AVFMT_FLAG_NONBLOCK
+ * is set), this function can return AVERROR(EAGAIN) meaning the call should
+ * be repeated.
+ *
  * @param s media file handle
  * @param pkt The packet containing the data to be written. Note that unlike
  *av_interleaved_write_frame(), this function does not take
@@ -2431,6 +2435,9 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt);
  * knowledge of future packets, improving e.g. the behaviour of the mp4
  * muxer for VFR content in fragmenting mode.
  *
+ * This call is not supported and must not be called if muxer is operating
+ * in non-blocking mode (AVFMT_FLAG_NONBLOCK is set).
+ *
  * @param s media file handle
  * @param pkt The packet containing the data to be written.
  *
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 03/11] avformat/fifo: Add fate test

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 This adds two tests checking that the output of muxers is the same
 as when fifo is used and stand-alone test program which covers
 behaviour in failure scenarios.

 libavformat/Makefile   |   1 +
 libavformat/tests/fifo_muxer.c | 447 +
 tests/Makefile |   1 +
 tests/fate/fifo-muxer.mak  |  20 ++
 tests/ref/fate/fifo-muxer-tst  |  11 +
 5 files changed, 480 insertions(+)
 create mode 100644 libavformat/tests/fifo_muxer.c
 create mode 100644 tests/fate/fifo-muxer.mak
 create mode 100644 tests/ref/fate/fifo-muxer-tst

diff --git a/libavformat/Makefile b/libavformat/Makefile
index da94ef8..d2a1a27 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -590,6 +590,7 @@ TESTPROGS = seek
\
 url \
 #   async   \
 
+TESTPROGS-$(CONFIG_FIFO_MUXER)  += fifo_muxer
 TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
 TESTPROGS-$(CONFIG_MOV_MUXER)+= movenc
 TESTPROGS-$(CONFIG_NETWORK)  += noproxy
diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c
new file mode 100644
index 000..0b5a95e
--- /dev/null
+++ b/libavformat/tests/fifo_muxer.c
@@ -0,0 +1,447 @@
+/*
+ * FIFO pseudo-muxer
+ * Copyright (c) 2016 Jan Sebechlebsky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/avassert.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+
+#define MAX_TST_PACKETS 128
+#define SLEEPTIME_50_MS 5
+#define SLEEPTIME_10_MS 1
+
+/* Implementation of mock muxer to simulate real muxer failures */
+
+/* This is structure of data sent in packets to
+ * failing muxer */
+typedef struct FailingMuxerPacketData {
+int ret; /* return value of write_packet call*/
+int recover_after;   /* set ret to zero after this number of recovery 
attempts */
+unsigned sleep_time; /* sleep for this long in write_packet to simulate 
long I/O operation */
+} FailingMuxerPacketData;
+
+
+typedef struct FailingMuxerContext {
+AVClass *class;
+int write_header_ret;
+int write_trailer_ret;
+/* If non-zero, summary of processed packets will be printed in deinit */
+uint8_t print_deinit_summary;
+
+int flush_count;
+int pts_written[MAX_TST_PACKETS];
+int pts_written_nr;
+} FailingMuxerContext;
+
+static int failing_write_header(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_header_ret;
+}
+
+static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+int ret = 0;
+if (!pkt) {
+ctx->flush_count++;
+} else {
+FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data;
+
+if (!data->recover_after) {
+data->ret = 0;
+} else {
+data->recover_after--;
+}
+
+ret = data->ret;
+
+if (data->sleep_time) {
+int64_t slept = 0;
+while (slept < data->sleep_time) {
+if (ff_check_interrupt(>interrupt_callback))
+return AVERROR_EXIT;
+av_usleep(SLEEPTIME_10_MS);
+slept += SLEEPTIME_10_MS;
+}
+}
+
+if (!ret) {
+ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
+av_packet_unref(pkt);
+}
+}
+return ret;
+}
+
+static int failing_write_trailer(AVFormatContext *avf)
+{
+FailingMuxerContext *ctx = avf->priv_data;
+return ctx->write_trailer_ret;
+}
+
+static void failing_deinit(AVFormatContext *avf)
+{
+int i;
+FailingMuxerContext *ctx = avf->priv_data;
+
+if (!ctx->print_deinit_summary)
+return;
+
+printf("flush count: %d\n", ctx->flush_count);
+printf("pts seen nr: %d\n", ctx->pts_written_nr);
+printf("pts seen: ");
+for (i = 0; i < ctx->pts_written_nr; ++i ) {
+  

[FFmpeg-devel] [PATCH 10/11] avformat/fifo: Add AVFMT_FLAG_NONBLOCK support

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add support for nonblocking calls.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/fifo.c | 70 +-
 1 file changed, 59 insertions(+), 11 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index bc8c973..efd91e3 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -25,6 +25,7 @@
 #include "avformat.h"
 #include "internal.h"
 #include "pthread.h"
+#include "url.h"
 
 #define FIFO_DEFAULT_QUEUE_SIZE  60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   16
@@ -77,6 +78,13 @@ typedef struct FifoContext {
  * from failure or queue overflow */
 uint8_t restart_with_keyframe;
 
+/* Whether termination was requested by invoking deinit
+ * before the thread was finished. Used only in non-blocking
+ * mode - when AVFMT_FLAG_NONBLOCK is set. */
+volatile uint8_t termination_requested;
+
+/* Original interrupt callback of the underlying muxer. */
+AVIOInterruptCB orig_interrupt_callback;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -110,6 +118,16 @@ typedef struct FifoMessage {
 AVPacket pkt;
 } FifoMessage;
 
+static int fifo_interrupt_callback_wrapper(void *arg)
+{
+FifoContext *ctx = arg;
+
+if (ctx->termination_requested)
+return 1;
+
+return ff_check_interrupt(>orig_interrupt_callback);
+}
+
 static int fifo_thread_write_header(FifoThreadContext *ctx)
 {
 AVFormatContext *avf = ctx->avf;
@@ -448,6 +466,8 @@ static void *fifo_consumer_thread(void *data)
 static int fifo_mux_init(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
+AVIOInterruptCB interrupt_cb = {.callback = 
fifo_interrupt_callback_wrapper,
+.opaque = fifo};
 AVFormatContext *avf2;
 int ret = 0, i;
 
@@ -458,7 +478,8 @@ static int fifo_mux_init(AVFormatContext *avf)
 
 fifo->avf = avf2;
 
-avf2->interrupt_callback = avf->interrupt_callback;
+fifo->orig_interrupt_callback = avf->interrupt_callback;
+avf2->interrupt_callback = interrupt_cb;
 avf2->max_delay = avf->max_delay;
 ret = av_dict_copy(>metadata, avf->metadata, 0);
 if (ret < 0)
@@ -543,7 +564,7 @@ static int fifo_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 {
 FifoContext *fifo = avf->priv_data;
 FifoMessage msg = {.type = pkt ? FIFO_WRITE_PACKET : FIFO_FLUSH_OUTPUT};
-int ret;
+int ret, queue_flags = 0;
 
 if (pkt) {
 av_init_packet();
@@ -552,15 +573,21 @@ static int fifo_write_packet(AVFormatContext *avf, 
AVPacket *pkt)
 return ret;
 }
 
-ret = av_thread_message_queue_send(fifo->queue, ,
-   fifo->drop_pkts_on_overflow ?
-   AV_THREAD_MESSAGE_NONBLOCK : 0);
+if (fifo->drop_pkts_on_overflow || (avf->flags & AVFMT_FLAG_NONBLOCK))
+queue_flags |= AVFMT_FLAG_NONBLOCK;
+
+ret = av_thread_message_queue_send(fifo->queue, , queue_flags);
+
 if (ret == AVERROR(EAGAIN)) {
-uint8_t overflow_set = 0;
+uint8_t overflow_set;
+
+if (avf->flags & AVFMT_FLAG_NONBLOCK)
+return ret;
 
 /* Queue is full, set fifo->overflow_flag to 1
  * to let consumer thread know the queue should
  * be flushed. */
+overflow_set = 0;
 pthread_mutex_lock(>overflow_flag_lock);
 if (!fifo->overflow_flag)
 fifo->overflow_flag = overflow_set = 1;
@@ -588,11 +615,22 @@ static int fifo_write_trailer(AVFormatContext *avf)
 
 av_thread_message_queue_set_err_recv(fifo->queue, AVERROR_EOF);
 
-ret = pthread_join( fifo->writer_thread, NULL);
-if (ret < 0) {
-av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
-   av_err2str(AVERROR(ret)));
-return AVERROR(ret);
+if (!(avf->flags & AVFMT_FLAG_NONBLOCK)) {
+ret = pthread_join( fifo->writer_thread, NULL);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
+av_err2str(AVERROR(ret)));
+return AVERROR(ret);
+}
+} else {
+ret = pthread_tryjoin_np( fifo->writer_thread, NULL);
+if (ret == EBUSY)
+return AVERROR(EAGAIN);
+if (ret) {
+av_log(avf, AV_LOG_ERROR, "pthread_tryjoin_np error: %s\n",
+   av_err2str(AVERROR(ret)));
+return AVERROR(ret);
+}
 }
 
 ret = fifo->write_trailer_ret;
@@ -603,6 +641,16 @@ static void fifo_deinit(AVFormatContext *avf)
 {
 FifoContext *fifo = avf->priv_data;
 
+if (avf->flags & AVFMT_FLAG_NONBLOCK) {
+int ret;
+fifo->termination_requested = 1;
+ret = pthread_join( fifo->writer_thread, NULL);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR, "pthread join error: %s\n",
+   av_err2str(AVERROR(ret)));
+}
+}
+
 

[FFmpeg-devel] [PATCH 09/11] avformat/mux: Restore stream ts in av_write_packet on EAGAIN

2016-08-02 Thread sebechlebskyjan
From: Jan Sebechlebsky 

compute_muxer_pkt_fields() stores the last seen timestamps in stream
and produces error if the same timestamp is presented again.
This is a problem if muxer works in non-blocking mode and calls
av_write_packet repeatedly with the same packet.
This patch saves stream fields affected by compute_muxer_pkt_fields
and restores them in case AVERROR(EAGAIN) is returned from
write_packet, and muxer has AVFMT_FLAG_NONBLOCK flag set.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/mux.c | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libavformat/mux.c b/libavformat/mux.c
index ef4720a..fdf3fd1 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -880,6 +880,9 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket 
*pkt) {
 int av_write_frame(AVFormatContext *s, AVPacket *pkt)
 {
 int ret;
+#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
+int64_t st_cur_dts_backup, st_priv_pts_val_backup;
+#endif
 
 ret = prepare_input_packet(s, pkt);
 if (ret < 0)
@@ -907,6 +910,9 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
 return ret;
 
 #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
+st_cur_dts_backup = s->streams[pkt->stream_index]->cur_dts;
+st_priv_pts_val_backup = s->streams[pkt->stream_index]->priv_pts->val;
+
 ret = compute_muxer_pkt_fields(s, s->streams[pkt->stream_index], pkt);
 
 if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
@@ -914,7 +920,13 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
 #endif
 
 ret = write_packet(s, pkt);
-if (ret >= 0 && s->pb && s->pb->error < 0)
+if (s->flags & AVFMT_FLAG_NONBLOCK && ret == AVERROR(EAGAIN)) {
+#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
+s->streams[pkt->stream_index]->cur_dts = st_cur_dts_backup;
+s->streams[pkt->stream_index]->priv_pts->val = st_priv_pts_val_backup;
+#endif
+return ret;
+} else if (ret >= 0 && s->pb && s->pb->error < 0)
 ret = s->pb->error;
 
 if (ret >= 0)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/5] doc/bsfs: Fix bsf options divider in documentation

2016-07-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

The actual implementation uses ':' divider, not '/' as
documented.

Signed-off-by: Jan Sebechlebsky 
---
 doc/bitstream_filters.texi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi
index 6c58d02..a85327f 100644
--- a/doc/bitstream_filters.texi
+++ b/doc/bitstream_filters.texi
@@ -18,7 +18,7 @@ comma-separated list of filters, whose parameters follow the 
filter
 name after a '='.
 
 @example
-ffmpeg -i INPUT -c:v copy -bsf:v filter1[=opt1=str1/opt2=str2][,filter2] OUTPUT
+ffmpeg -i INPUT -c:v copy -bsf:v filter1[=opt1=str1:opt2=str2][,filter2] OUTPUT
 @end example
 
 Below is a description of the currently available bitstream filters,
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/5] avcodec/bsf: Add custom item name func for BSF list

2016-07-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add custom item name function for bsf list, which will
construct string description of filter chain. This is
done using lazy-initialization, so there is no overhead
if item name is never accessed.

Signed-off-by: Jan Sebechlebsky 

Conflicts:
libavcodec/bsf.c
---
 This allows to get some text representation of list BSF filter
 for logging purposes.

 libavcodec/bsf.c | 30 +-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 3ae0a2b..c2e13f7 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -23,6 +23,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
 
 #include "avcodec.h"
 #include "bsf.h"
@@ -247,6 +248,7 @@ typedef struct BSFListContext {
 int idx;   // index of currently processed BSF
 int flushed_idx;   // index of BSF being flushed
 
+char * item_name;
 } BSFListContext;
 
 
@@ -370,11 +372,37 @@ static void bsf_list_close(AVBSFContext *bsf)
 for (i = 0; i < lst->ctx_nr; ++i)
 av_bsf_free(>bsf_lst[i]);
 av_freep(>bsf_lst);
+av_freep(>item_name);
+}
+
+static const char *bsf_list_item_name(void *ctx)
+{
+static const char *null_filter_name = "null";
+AVBSFContext *bsf_ctx = ctx;
+BSFListContext *lst = bsf_ctx->priv_data;
+
+if (!lst->ctx_nr)
+return null_filter_name;
+
+if (!lst->item_name) {
+int i;
+AVBPrint bp;
+av_bprint_init(, 16, 128);
+
+av_bprintf(, "bsf_list(");
+for (i = 0; i < lst->ctx_nr; i++)
+av_bprintf(, i ? ",%s" : "%s", lst->bsf_lst[i]->filter->name);
+av_bprintf(, ")");
+
+av_bprint_finalize(, >item_name);
+}
+
+return lst->item_name;
 }
 
 static const AVClass bsf_list_class = {
 .class_name = "bsf_list",
-.item_name = av_default_item_name,
+.item_name = bsf_list_item_name,
 .version = LIBAVUTIL_VERSION_INT,
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/5] avformat/tee: Use BSF list API

2016-07-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 123 +-
 1 file changed, 58 insertions(+), 65 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index b4158e1..1a055cd 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -36,7 +36,7 @@ typedef enum {
 
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+AVBSFContext **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -104,46 +104,6 @@ fail:
 return ret;
 }
 
-/**
- * Parse list of bitstream filters and add them to the list of filters
- * pointed to by bsfs.
- *
- * The list must be specified in the form:
- * BSFS ::= BSF[,BSFS]
- */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
-{
-char *bsf_name, *buf, *dup, *saveptr;
-int ret = 0;
-
-if (!(dup = buf = av_strdup(bsfs_spec)))
-return AVERROR(ENOMEM);
-
-while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
-
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
-   bsf_name);
-ret = AVERROR_UNKNOWN;
-goto end;
-}
-
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
-
-buf = NULL;
-}
-
-end:
-av_free(dup);
-return ret;
-}
-
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
 {
 if (!opt) {
@@ -175,14 +135,8 @@ static int close_slave(TeeSlave *tee_slave)
 ret = av_write_trailer(avf);
 
 if (tee_slave->bsfs) {
-for (i = 0; i < avf->nb_streams; ++i) {
-AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
-while (bsf) {
-bsf_next = bsf->next;
-av_bitstream_filter_close(bsf);
-bsf = bsf_next;
-}
-}
+for (i = 0; i < avf->nb_streams; ++i)
+av_bsf_free(_slave->bsfs[i]);
 }
 av_freep(_slave->stream_map);
 av_freep(_slave->bsfs);
@@ -352,7 +306,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
"output '%s', filters will be ignored\n", i, 
filename);
 continue;
 }
-ret = parse_bsfs(avf, entry->value, _slave->bsfs[i]);
+ret = av_bsf_list_parse_str(entry->value, _slave->bsfs[i]);
 if (ret < 0) {
 av_log(avf, AV_LOG_ERROR,
"Error parsing bitstream filter sequence '%s' 
associated to "
@@ -365,6 +319,31 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 av_dict_set(, entry->key, NULL, 0);
 }
 
+for (i = 0; i < avf2->nb_streams; i++){
+if (!tee_slave->bsfs[i]) {
+/* Add pass-through bitstream filter */
+ret = av_bsf_get_null_filter(_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+   "Failed to create pass-through bitstream filter: %s\n",
+   av_err2str(ret));
+goto end;
+}
+}
+
+tee_slave->bsfs[i]->time_base_in = avf2->streams[i]->time_base;
+ret = avcodec_parameters_copy(tee_slave->bsfs[i]->par_in,
+  avf2->streams[i]->codecpar);
+
+ret = av_bsf_init(tee_slave->bsfs[i]);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR,
+"Failed to initialize bitstream filter(s): %s\n",
+av_err2str(ret));
+goto end;
+}
+}
+
 if (options) {
 entry = NULL;
 while ((entry = av_dict_get(options, "", entry, 
AV_DICT_IGNORE_SUFFIX)))
@@ -389,20 +368,16 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int 
log_level)
slave->avf->filename, slave->avf->oformat->name);
 for (i = 0; i < slave->avf->nb_streams; i++) {
 AVStream *st = slave->avf->streams[i];
-AVBitStreamFilterContext *bsf = slave->bsfs[i];
+AVBSFContext *bsf = slave->bsfs[i];
+const char * bsf_name;
 
 av_log(log_ctx, log_level, "stream:%d codec:%s type:%s",
i, avcodec_get_name(st->codecpar->codec_id),
av_get_media_type_string(st->codecpar->codec_type));
-if (bsf) {
-av_log(log_ctx, log_level, " bsfs:");
-while (bsf) {
-av_log(log_ctx, log_level, "%s%s",
-   bsf->filter->name, bsf->next ? "," : "");
-

[FFmpeg-devel] [PATCH 2/5] avcodec/bsf: Add ff_bsf_get_packet_ref() function

2016-07-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Use of this function can save unnecessary malloc operation
in bitstream filter.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/bsf.c | 16 
 libavcodec/bsf.h | 11 +++
 2 files changed, 27 insertions(+)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 8e36861..40fc925 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -220,3 +220,19 @@ int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt)
 
 return 0;
 }
+
+int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
+{
+AVBSFInternal *in = ctx->internal;
+
+if (in->eof)
+return AVERROR_EOF;
+
+if (!ctx->internal->buffer_pkt->data &&
+!ctx->internal->buffer_pkt->side_data_elems)
+return AVERROR(EAGAIN);
+
+av_packet_move_ref(pkt, ctx->internal->buffer_pkt);
+
+return 0;
+}
diff --git a/libavcodec/bsf.h b/libavcodec/bsf.h
index 3435df5..af035ee 100644
--- a/libavcodec/bsf.h
+++ b/libavcodec/bsf.h
@@ -28,6 +28,17 @@
  */
 int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt);
 
+/**
+ * Called by bitstream filters to get packet for filtering.
+ * The reference to packet is moved to provided packet structure.
+ *
+ * @param ctx pointer to AVBSFContext of filter
+ * @param pkt pointer to packet to move reference to
+ *
+ * @return 0>= on success, negative AVERROR in case of failure
+ */
+int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt);
+
 const AVClass *ff_bsf_child_class_next(const AVClass *prev);
 
 #endif /* AVCODEC_BSF_H */
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/5] avcodec/bsf: Add list BSF API

2016-07-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

---
 libavcodec/avcodec.h |  74 ++
 libavcodec/bsf.c | 284 +++
 2 files changed, 358 insertions(+)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 36f7935..39106ee 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -5949,6 +5949,80 @@ void av_bsf_free(AVBSFContext **ctx);
  */
 const AVClass *av_bsf_get_class(void);
 
+/**
+ * Structure for chain/list of bitstream filters.
+ * Empty list can be allocated by av_bsf_list_alloc().
+ */
+typedef struct AVBSFList AVBSFList;
+
+/**
+ * Allocate empty list of bitstream filters.
+ * The list must be later freed by av_bsf_list_free()
+ * or finalized by av_bsf_list_finalize().
+ *
+ * @return pointer to AVBSFList on success, NULL in case of failure
+ */
+AVBSFList *av_bsf_list_alloc(void);
+
+/**
+ * Free list of bitstream filters.
+ *
+ * @param lst pointer to pointer returned by av_bsf_list_alloc()
+ */
+void av_bsf_list_free(AVBSFList **lst);
+
+/**
+ * Append bitstream filter to the list of bitstream filters.
+ *
+ * @param lst list to append to
+ * @param bsf AVBSFContext to be appended
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf);
+
+/**
+ * Finalize list of bitstream filters.
+ *
+ * This function will transform AVBSFList to single AVBSFContext,
+ * so the whole chain of bitstream filters can be treated as single filter
+ * freshly allocated by av_bsf_alloc().
+ * The AVBSFList structure is destroyed after this call and must not
+ * be accessed.
+ *
+ * @param lst  AVBSFList structure to be transformed
+ * @param bsf[out] pointer to be set to newly created AVBSFContext structure
+ * representing the chain of bitstream filters
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf);
+
+/**
+ * Parse string describing list of bitstream filters and create single
+ * AVBSFContext describing the whole chain of bitstream filters.
+ * Resulting AVBSFContext can be treated as any other AVBSFContext freshly
+ * allocated by av_bsf_alloc().
+ *
+ * @param str  string describing chain of bitstream filters in format
+ * bsf1[=opt1=val1:opt2=val2][,bsf2]
+ * @param bsf[out] pointer to be set to newly created AVBSFContext structure
+ * representing the chain of bitstream filters
+ *
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf);
+
+/**
+ * Get null/pass-through bitstream filter.
+ *
+ * @param bsf[out] pointer to be set to new instance of pass-through
+ * bitstream filter
+ *
+ * @return
+ */
+int av_bsf_get_null_filter(AVBSFContext **bsf);
+
 /* memory */
 
 /**
diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 40fc925..3ae0a2b 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -22,6 +22,7 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
 
 #include "avcodec.h"
 #include "bsf.h"
@@ -236,3 +237,286 @@ int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket 
*pkt)
 
 return 0;
 }
+
+typedef struct BSFListContext {
+const AVClass *class;
+
+AVBSFContext **bsf_lst;
+int ctx_nr;
+
+int idx;   // index of currently processed BSF
+int flushed_idx;   // index of BSF being flushed
+
+} BSFListContext;
+
+
+static int bsf_list_init(AVBSFContext *bsf)
+{
+BSFListContext *lst = bsf->priv_data;
+int ret, i;
+const AVCodecParameters *cod_par = bsf->par_in;
+AVRational tb = bsf->time_base_in;
+
+for (i = 0; i < lst->ctx_nr; ++i) {
+ret = avcodec_parameters_copy(lst->bsf_lst[i]->par_in, cod_par);
+if (ret < 0)
+goto fail;
+
+lst->bsf_lst[i]->time_base_in = tb;
+
+ret = av_bsf_init(lst->bsf_lst[i]);
+if (ret < 0)
+goto fail;
+
+cod_par = lst->bsf_lst[i]->par_out;
+tb = lst->bsf_lst[i]->time_base_out;
+}
+
+bsf->time_base_out = tb;
+ret = avcodec_parameters_copy(bsf->par_out, cod_par);
+
+fail:
+return ret;
+}
+
+static int bsf_list_flush(AVBSFContext *bsf, AVPacket *out)
+{
+BSFListContext *lst = bsf->priv_data;
+int ret;
+
+if (lst->flushed_idx == lst->ctx_nr)
+return AVERROR_EOF;
+
+while (1) {
+if (lst->idx > lst->flushed_idx) {
+ret = av_bsf_receive_packet(lst->bsf_lst[lst->idx-1], out);
+if (ret == AVERROR(EAGAIN)) {
+ret = 0;
+lst->idx--;
+continue;
+} else if (ret == AVERROR_EOF) {
+/* filter idx-1 is done, let's flush filter idx */
+lst->flushed_idx = lst->idx;
+continue;
+} else if (ret < 0) {
+/* 

[FFmpeg-devel] [PATCH v3 2/2] avcodec/bsf: Forbid packet without payload in av_bsf_send_packet

2016-07-26 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/avcodec.h | 3 ++-
 libavcodec/bsf.c | 3 +++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ca8dba8..36f7935 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -5898,7 +5898,8 @@ int av_bsf_init(AVBSFContext *ctx);
  * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or
  * AVERROR_EOF.
  *
- * @param pkt the packet to filter. The bitstream filter will take ownership of
+ * @param pkt the packet to filter. pkt must contain some payload (i.e data or
+ * side data must be present in pkt). The bitstream filter will take ownership 
of
  * the packet and reset the contents of pkt. pkt is not touched if an error 
occurs.
  * This parameter may be NULL, which signals the end of the stream (i.e. no 
more
  * packets will be sent). That will cause the filter to output any packets it
diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 9b9ada7..8e36861 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -21,6 +21,7 @@
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
+#include "libavutil/avassert.h"
 
 #include "avcodec.h"
 #include "bsf.h"
@@ -177,6 +178,8 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
 return 0;
 }
 
+av_assert0(pkt->data || pkt->side_data);
+
 if (ctx->internal->eof) {
 av_log(ctx, AV_LOG_ERROR, "A non-NULL packet sent after an EOF.\n");
 return AVERROR(EINVAL);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 1/2] avcodec/bsf: Set EOF flag only in pkt == NULL

2016-07-26 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Set BSF EOF flag only if pkt == NULL in av_bsf_send_packet().

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/bsf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 88b7f29..9b9ada7 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -172,7 +172,7 @@ int av_bsf_init(AVBSFContext *ctx)
 
 int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
 {
-if (!pkt || !pkt->data) {
+if (!pkt) {
 ctx->internal->eof = 1;
 return 0;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] MAINTAINERS: Add myself as maintainer of fifo muxer

2016-07-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6d4c9f9..0e66170 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -164,6 +164,7 @@ Codecs:
   exif.c, exif.hThilo Borgmann
   ffv1* Michael Niedermayer
   ffwavesynth.c Nicolas George
+  fifo.cJan Sebechlebsky
   flicvideo.c   Mike Melanson
   g722.cMartin Storsjo
   g726.cRoman Shaposhnik
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 1/2] libavformat: Add fifo pseudo-muxer

2016-07-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

The fifo pseudo-muxer allows to separate encoder from the
actual output by using a first-in-first-out queue and
running actual muxer asynchronously in separate thread.

It can be configured to attempt transparent recovery
of output on failure.

Signed-off-by: Jan Sebechlebsky 
---
 Changelog|   1 +
 configure|   1 +
 doc/muxers.texi  |  90 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 666 +++
 libavformat/version.h|   2 +-
 7 files changed, 761 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

diff --git a/Changelog b/Changelog
index 479f164..d7d0056 100644
--- a/Changelog
+++ b/Changelog
@@ -10,6 +10,7 @@ version :
 - curves filter doesn't automatically insert points at x=0 and x=1 anymore
 - 16-bit support in curves filter
 - 16-bit support in selectivecolor filter
+- fifo muxer
 
 
 version 3.1:
diff --git a/configure b/configure
index 1b41303..903205b 100755
--- a/configure
+++ b/configure
@@ -2832,6 +2832,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 5873269..e2bc290 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1436,6 +1436,96 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows to separate encoding from any other muxer by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The behavior of fifo muxer in case of failure can be configured:
+@itemize @bullet
+
+@item
+output can be transparently restarted with configurable delay between retries
+based on real time or time of the processed stream.
+
+@item
+encoding can be blocked during temporary failure, or continue transparently
+dropping packets in case fifo queue fills up.
+
+@end itemize
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item drop_pkts_on_overflow @var{bool}
+If set to 1 (true), in case the fifo queue fills up, packets will be dropped
+rather than blocking the encoder. This allows to continue streaming without
+delaying the output, at the cost of ommiting part of the stream. By default
+this option is set to 0 (false), so in such cases the encoder will be blocked
+until the muxer processes some of the packets and none of them is lost.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least recovery_wait_time
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain errors the recovery is not attempted even when @ref{attempt_recovery}
+is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server, continue processing the stream at real-time
+rate even in case of temporary failure (network outage) and attempt to recover
+streaming every second indefinitely.
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format 

[FFmpeg-devel] [PATCH 0/2][GSoC] Add fifo pseudo-muxer

2016-07-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Hello,
I am sending next version of fifo pseudo-muxer.

I will send patchset adding AVFMT_FLAG_NONBLOCK support requested 
by Nicolas later - it turned out that there are some more things
to solve (av_write_frame does not support repeated calls in current state)
and test.

Regards,
Jan

Jan Sebechlebsky (2):
  libavformat: Add fifo pseudo-muxer
  MAINTAINERS: Add myself as maintainer of fifo muxer

 Changelog|   1 +
 MAINTAINERS  |   1 +
 configure|   1 +
 doc/muxers.texi  |  90 +++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 666 +++
 libavformat/version.h|   2 +-
 8 files changed, 762 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/fifo.c

-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2] avcodec/bsf: Set EOF flag only if pkt == NULL

2016-07-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Set BSF EOF flag only if pkt == NULL in av_bsf_send_packet().

Signed-off-by: Jan Sebechlebsky 
---
 I agree, it seems cleaner that way.

 Thanks,
 please apply this version of patch then and ignore
 the patch changing the comment.

 Regards,
 Jan

 libavcodec/bsf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 88b7f29..9b9ada7 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -172,7 +172,7 @@ int av_bsf_init(AVBSFContext *ctx)
 
 int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
 {
-if (!pkt || !pkt->data) {
+if (!pkt) {
 ctx->internal->eof = 1;
 return 0;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] avcodec/avcodec.h: Change av_bsf_send_packet() comment

2016-07-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Specify av_bsf_packet() behaviour in case that the packet does
not contain any data more precisely in the comment.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/avcodec.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ca8dba8..09ca734 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -5900,9 +5900,9 @@ int av_bsf_init(AVBSFContext *ctx);
  *
  * @param pkt the packet to filter. The bitstream filter will take ownership of
  * the packet and reset the contents of pkt. pkt is not touched if an error 
occurs.
- * This parameter may be NULL, which signals the end of the stream (i.e. no 
more
- * packets will be sent). That will cause the filter to output any packets it
- * may have buffered internally.
+ * If the parameter is NULL, or packet does not contain any data or side data,
+ * it signals the end of the stream (i.e. no more packets will be sent).
+ * That will cause the filter to output any packets it may have buffered 
internally.
  *
  * @return 0 on success, a negative AVERROR on error.
  */
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/2] avcodec/bsf: Check side data when setting BSF EOF flag.

2016-07-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Set BSF EOF flag only if pkt == NULL or both data and
side data are not present in packet.

Signed-off-by: Jan Sebechlebsky 
---
 I believe that side data should be checked too, and 
 EOF flag set only when both data and side data are
 not present.

 I was testing new list BSF API I was working on,
 and with simple pass-though (empty list) BSF filter,
 some tests were failing because packets containing only
 side data were taken as EOF signal for bitsteam filter. 

 Also, I've added comment about this behaviour in next
 patch.

 libavcodec/bsf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 88b7f29..94f0122 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -172,7 +172,7 @@ int av_bsf_init(AVBSFContext *ctx)
 
 int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
 {
-if (!pkt || !pkt->data) {
+if (!pkt || (!pkt->data && !pkt->side_data_elems)) {
 ctx->internal->eof = 1;
 return 0;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] avcodec/mpeg4_unpack_bframes_bsf: Check av_packet_from_data() return value

2016-07-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/mpeg4_unpack_bframes_bsf.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c 
b/libavcodec/mpeg4_unpack_bframes_bsf.c
index aee8ccb..e227f58 100644
--- a/libavcodec/mpeg4_unpack_bframes_bsf.c
+++ b/libavcodec/mpeg4_unpack_bframes_bsf.c
@@ -126,7 +126,11 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, 
AVPacket *out)
 return ret;
 }
 
-av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size);
+ret = av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size);
+if (ret < 0) {
+av_packet_free();
+return ret;
+}
 if (in->size <= MAX_NVOP_SIZE) {
 /* N-VOP */
 av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/2] avcodec/mpeg4_unpack_bframes_bsf: Copy packet props

2016-07-22 Thread sebechlebskyjan
From: Jan Sebechlebsky 

mpeg4_unpack_bframes_bsf bitstream filters constructs
resulting packet using av_packet_from_data() function.
This function however modifies only buffer (data) and leaves
other fields untouched, so the content of other fields
of the output packet is undefined.
It is working with old BSF API, since old API filters
just data and the packet fields are copied in
av_apply_bitstream_filters from input packet.

This change fixes the behaviour for the new BSF API.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/mpeg4_unpack_bframes_bsf.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c 
b/libavcodec/mpeg4_unpack_bframes_bsf.c
index 0615621..aee8ccb 100644
--- a/libavcodec/mpeg4_unpack_bframes_bsf.c
+++ b/libavcodec/mpeg4_unpack_bframes_bsf.c
@@ -120,6 +120,12 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, 
AVPacket *out)
 
 if (nb_vop == 1 && s->b_frame_buf) {
 /* use frame from BSFContext */
+ret = av_packet_copy_props(out, in);
+if (ret < 0) {
+av_packet_free();
+return ret;
+}
+
 av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size);
 if (in->size <= MAX_NVOP_SIZE) {
 /* N-VOP */
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/7] avformat/tee: Rescale ts using av_packet_rescale_ts

2016-07-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This ensures that AV_NOPTS_VALUE value is handled
correctly.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index daddba5..b4158e1 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -543,9 +543,7 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 }
 tb  = avf ->streams[s ]->time_base;
 tb2 = avf2->streams[s2]->time_base;
-pkt2.pts  = av_rescale_q(pkt->pts,  tb, tb2);
-pkt2.dts  = av_rescale_q(pkt->dts,  tb, tb2);
-pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
+av_packet_rescale_ts(, tb, tb2);
 pkt2.stream_index = s2;
 
 if ((ret = av_apply_bitstream_filters(avf2->streams[s2]->codec, ,
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 03/10] avformat/tee: Support flushing by writing NULL pkt

2016-07-11 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This will add support for flushing by writing NULL
packet to the tee muxer, which propagates the action
to slave muxers as expected.

Signed-off-by: Jan Sebechlebsky 
---
 Unfortunately, I've realized that I've forgotten to set AVFMT_ALLOW_FLUSH
 flag to the tee muxer to make it flushable. I've also changed commit 
 message, because crash without AVFMT_ALLOW_FLUSH would not happen
 if write_packet is not called directly with NULL argument.
 This version should be allright.

 libavformat/tee.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index c276a37..e750752 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -520,6 +520,17 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 if (!(avf2 = tee->slaves[i].avf))
 continue;
 
+/* Flush slave if pkt is NULL*/
+if (!pkt) {
+ret = av_interleaved_write_frame(avf2, NULL);
+if (ret < 0) {
+ret = tee_process_slave_failure(avf, i, ret);
+if (!ret_all && ret < 0)
+ret_all = ret;
+}
+continue;
+}
+
 s = pkt->stream_index;
 s2 = tee->slaves[i].stream_map[s];
 if (s2 < 0)
@@ -557,5 +568,5 @@ AVOutputFormat ff_tee_muxer = {
 .write_trailer = tee_write_trailer,
 .write_packet  = tee_write_packet,
 .priv_class= _muxer_class,
-.flags = AVFMT_NOFILE,
+.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
 };
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/7] avformat/utils: Add ff_format_output_open() function

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Add ff_format_output_open utility function to wrap
io_open callback of AVFormatContext structure.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/internal.h | 10 ++
 libavformat/utils.c| 10 ++
 2 files changed, 20 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 1b44bea..0119749 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -572,6 +572,16 @@ int ffio_open2_wrapper(struct AVFormatContext *s, 
AVIOContext **pb, const char *
  */
 #define FFERROR_REDO FFERRTAG('R','E','D','O')
 
+/**
+ * Utility function to open IO stream of output format.
+ *
+ * @param s AVFormatContext
+ * @param url URL or file name to open for writing
+ * @options optional options which will be passed to io_open callback
+ * @return >=0 on success, negative AVERROR in case of failure
+ */
+int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary 
**options);
+
 /*
  * A wrapper around AVFormatContext.io_close that should be used
  * instead of calling the pointer directly.
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 8c16374..d728ca3 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -5168,6 +5168,16 @@ int av_apply_bitstream_filters(AVCodecContext *codec, 
AVPacket *pkt,
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
+int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary 
**options)
+{
+if (!s->oformat)
+return AVERROR(EINVAL);
+
+if (!(s->oformat->flags & AVFMT_NOFILE))
+return s->io_open(s, >pb, url, AVIO_FLAG_WRITE, options);
+return 0;
+}
+
 void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
 {
 if (*pb)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/7] avformat/utils: Add ff_stream_encode_params_copy()

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/internal.h |  9 
 libavformat/utils.c| 56 ++
 2 files changed, 65 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 647ad65..1b44bea 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -491,6 +491,15 @@ int ff_generate_avci_extradata(AVStream *st);
 int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char 
*args);
 
 /**
+ * Copy encoding parameters from source to destination stream
+ *
+ * @param dst pointer to destination AVStream
+ * @param src pointer to source AVStream
+ * @return >=0 on success, AVERROR code on error
+ */
+int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src);
+
+/**
  * Wrap errno on rename() error.
  *
  * @param oldpath source path
diff --git a/libavformat/utils.c b/libavformat/utils.c
index d2a709c..8c16374 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3951,6 +3951,62 @@ int av_read_pause(AVFormatContext *s)
 return AVERROR(ENOSYS);
 }
 
+int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src)
+{
+int ret, i;
+
+dst->id  = src->id;
+dst->time_base   = src->time_base;
+dst->nb_frames   = src->nb_frames;
+dst->disposition = src->disposition;
+dst->sample_aspect_ratio = src->sample_aspect_ratio;
+dst->avg_frame_rate  = src->avg_frame_rate;
+dst->r_frame_rate= src->r_frame_rate;
+
+ret = av_dict_copy(>metadata, src->metadata, 0);
+if (ret < 0)
+return ret;
+
+ret = avcodec_parameters_copy(dst->codecpar, src->codecpar);
+if (ret < 0)
+return ret;
+
+/* Free existing side data*/
+for (i = 0; i < dst->nb_side_data; i++)
+av_free(dst->side_data[i].data);
+av_freep(>side_data);
+dst->nb_side_data = 0;
+
+/* Copy side data if present */
+if (src->nb_side_data) {
+dst->side_data = av_mallocz_array(src->nb_side_data,
+  sizeof(AVPacketSideData));
+if (!dst->side_data)
+return AVERROR(ENOMEM);
+dst->nb_side_data = src->nb_side_data;
+
+for (i = 0; i < src->nb_side_data; i++) {
+uint8_t *data = av_memdup(src->side_data[i].data,
+  src->side_data[i].size);
+if (!data)
+return AVERROR(ENOMEM);
+dst->side_data[i].type = src->side_data[i].type;
+dst->side_data[i].size = src->side_data[i].size;
+dst->side_data[i].data = data;
+}
+}
+
+av_freep(>recommended_encoder_configuration);
+if (src->recommended_encoder_configuration) {
+const char *conf_str = src->recommended_encoder_configuration;
+dst->recommended_encoder_configuration = av_strdup(conf_str);
+if (!dst->recommended_encoder_configuration)
+return AVERROR(ENOMEM);
+}
+
+return 0;
+}
+
 static void free_stream(AVStream **pst)
 {
 AVStream *st = *pst;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 6/7] avformat/tee: Use ff_format_output_open() function

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 996d64d..c60a77f 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -300,12 +300,11 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 goto end;
 }
 
-if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
-if ((ret = avf2->io_open(avf2, >pb, filename, AVIO_FLAG_WRITE, 
NULL)) < 0) {
-av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n",
-   slave, av_err2str(ret));
-goto end;
-}
+ret = ff_format_output_open(avf2, filename, NULL);
+if (ret < 0) {
+av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave,
+   av_err2str(ret));
+goto end;
 }
 
 if ((ret = avformat_write_header(avf2, )) < 0) {
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 7/7] libavformat: Add FIFO pseudo-muxer

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

The fifo pseudo-muxer allows to separate encoder from the
actual output by using a first-in-first-out queue and
running actual muxer asynchronously in separate thread.

It can be configured to attempt transparent recovery
of output on failure.

Signed-off-by: Jan Sebechlebsky 
---
 configure|   1 +
 doc/muxers.texi  |  80 ++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 666 +++
 5 files changed, 749 insertions(+)
 create mode 100644 libavformat/fifo.c

diff --git a/configure b/configure
index 126d0d6..b71c75f 100755
--- a/configure
+++ b/configure
@@ -2826,6 +2826,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index c2ca0ba..7ca14f6 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1408,6 +1408,86 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows to separate encoding from any other muxer by using
+first-in-first-out queue and running the actual muxer in a separate thread. 
This
+is especially useful in combination with the @ref{tee} muxer and output to
+several destinations with different reliability/writing speed/latency.
+
+The fifo muxer can operate in regular or non-blocking mode. This determines the
+behaviour in case the queue fills up. In regular mode the encoding is blocked
+until the muxer processes some of the packets from queue; in non-blocking mode
+the packets are thrown away rather than blocking the encoder (this might be
+useful in real-time streaming scenarios).
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets). Default value is 60.
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item block_on_overflow @var{bool}
+If set to 0 (false), non-blocking mode will be used and in case the queue fills
+up, packets will be dropped. By default this option is set to 1 (true), so in
+case of queue overflow the encoder will be blocked until the muxer processes
+some of the packets.
+
+@item attempt_recovery @var{bool}
+If failure occurs, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option set to 0 (false).
+
+@item max_recovery_attempts
+Sets maximum number of successive unsucessful recovery attempts after which
+the output fails permanently. Unlimited if set to zero. Default value is 16.
+
+@item recovery_wait_time @var{duration}
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt. Default value is 5 seconds.
+
+s@item recovery_wait_streamtime @var{bool}
+If set to 0 (false), the real time is used when waiting for the recovery
+attempt (i.e. the recovery will be attempted after at least
+recovery_wait_time seconds).
+If set to 1 (true), the time of the processed stream is taken into account
+instead (i.e. the recovery will be attempted after at least recovery_wait_time
+seconds of the stream is omitted).
+By default, this option is set to 0 (false).
+
+@item recover_any_error @var{bool}
+If set to 1 (true), recovery will be attempted regardless of type of the error
+causing the failure. By default this option is set to 0 (false) and in case of
+certain errors the recovery is not attempted even when @ref{attempt_recovery}
+is set to 1.
+
+@item restart_with_keyframe @var{bool}
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure. This option is set to 0 (false) by default.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server using non-blocking mode and recover 
automatically
+in case failure happens (for example the network becomes unavailable for a 
moment).
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format flv -map 0:v -map 
0:a
+  -block_on_overflow 0 -attempt_recovery 1 rtmp://example.com/live/stream_name
+@end example
+
+@end itemize
+
 @section tee
 
 The tee muxer can be used to write the same data to several files or any
diff --git a/libavformat/Makefile b/libavformat/Makefile
index c49f9de..42fb9be 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -162,6 +162,7 @@ OBJS-$(CONFIG_FFM_DEMUXER)   += ffmdec.o
 OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o
 OBJS-$(CONFIG_FFMETADATA_DEMUXER)+= ffmetadec.o
 

[FFmpeg-devel] [PATCH 3/7] avformat/tee: Handle AV_NOPTS_VALUE correctly

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Do not rescale pts and dts if they are set to
AV_NOPTS_VALUE.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index c276a37..a56d449 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -533,8 +533,10 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 }
 tb  = avf ->streams[s ]->time_base;
 tb2 = avf2->streams[s2]->time_base;
-pkt2.pts  = av_rescale_q(pkt->pts,  tb, tb2);
-pkt2.dts  = av_rescale_q(pkt->dts,  tb, tb2);
+if (pkt->pts != AV_NOPTS_VALUE)
+pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
+if (pkt->dts != AV_NOPTS_VALUE)
+pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
 pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
 pkt2.stream_index = s2;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/7] avformat/tee: Support flushing by writing NULL pkt

2016-07-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This will fix crash when caller attempts to flush by
calling write_packet with NULL packet pointer and
flushes slaves as expected.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index a56d449..996d64d 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -520,6 +520,17 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 if (!(avf2 = tee->slaves[i].avf))
 continue;
 
+/* Flush slave if pkt is NULL*/
+if (!pkt) {
+ret = av_interleaved_write_frame(avf2, NULL);
+if (ret < 0) {
+ret = tee_process_slave_failure(avf, i, ret);
+if (!ret_all && ret < 0)
+ret_all = ret;
+}
+continue;
+}
+
 s = pkt->stream_index;
 s2 = tee->slaves[i].stream_map[s];
 if (s2 < 0)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/4] avformat/tee: Support flushing by writing NULL pkt

2016-06-30 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This will fix crash when caller attempts to flush by
calling write_packet with NULL packet pointer and
flushes slaves as expected.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 840bee3..5b0fd41 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -520,6 +520,17 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 if (!(avf2 = tee->slaves[i].avf))
 continue;
 
+/* Flush slave if pkt is NULL*/
+if (!pkt) {
+ret = av_interleaved_write_frame(avf2, NULL);
+if (ret < 0) {
+ret = tee_process_slave_failure(avf, i, ret);
+if (!ret_all && ret < 0)
+ret_all = ret;
+}
+continue;
+}
+
 s = pkt->stream_index;
 s2 = tee->slaves[i].stream_map[s];
 if (s2 < 0)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/4] avformat/utils: Add ff_stream_encode_params_copy()

2016-06-30 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 Nicolas - this is the second of the utility functions you asked for in 
 reply to my fifo pseudo-muxer patch. I've tried to search for references
 to AVStream fields in muxers for the fields I wasn't are used, so 
 hopefully this should copy everything which might be used and needed.

 libavformat/internal.h |  9 
 libavformat/utils.c| 56 ++
 2 files changed, 65 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 647ad65..1b44bea 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -491,6 +491,15 @@ int ff_generate_avci_extradata(AVStream *st);
 int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char 
*args);
 
 /**
+ * Copy encoding parameters from source to destination stream
+ *
+ * @param dst pointer to destination AVStream
+ * @param src pointer to source AVStream
+ * @return >=0 on success, AVERROR code on error
+ */
+int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src);
+
+/**
  * Wrap errno on rename() error.
  *
  * @param oldpath source path
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 6f343f2..ff57f57 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3942,6 +3942,62 @@ int av_read_pause(AVFormatContext *s)
 return AVERROR(ENOSYS);
 }
 
+int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src)
+{
+int ret, i;
+
+dst->id  = src->id;
+dst->time_base   = src->time_base;
+dst->nb_frames   = src->nb_frames;
+dst->disposition = src->disposition;
+dst->sample_aspect_ratio = src->sample_aspect_ratio;
+dst->avg_frame_rate  = src->avg_frame_rate;
+dst->r_frame_rate= src->r_frame_rate;
+
+ret = av_dict_copy(>metadata, src->metadata, 0);
+if (ret < 0)
+return ret;
+
+ret = avcodec_parameters_copy(dst->codecpar, src->codecpar);
+if (ret < 0)
+return ret;
+
+/* Free existing side data*/
+for (i = 0; i < dst->nb_side_data; i++)
+av_free(dst->side_data[i].data);
+av_freep(>side_data);
+dst->nb_side_data = 0;
+
+/* Copy side data if present */
+if (src->nb_side_data) {
+dst->side_data = av_mallocz_array(src->nb_side_data,
+  sizeof(AVPacketSideData));
+if (!dst->side_data)
+return AVERROR(ENOMEM);
+dst->nb_side_data = src->nb_side_data;
+
+for (i = 0; i < src->nb_side_data; i++) {
+uint8_t *data = av_memdup(src->side_data[i].data,
+  src->side_data[i].size);
+if (!data)
+return AVERROR(ENOMEM);
+dst->side_data[i].type = src->side_data[i].type;
+dst->side_data[i].size = src->side_data[i].size;
+dst->side_data[i].data = data;
+}
+}
+
+av_freep(>recommended_encoder_configuration);
+if (src->recommended_encoder_configuration) {
+const char *conf_str = src->recommended_encoder_configuration;
+dst->recommended_encoder_configuration = av_strdup(conf_str);
+if (!dst->recommended_encoder_configuration)
+return AVERROR(ENOMEM);
+}
+
+return 0;
+}
+
 static void free_stream(AVStream **pst)
 {
 AVStream *st = *pst;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/4] avformat/tee: Handle AV_NOPTS_VALUE correctly

2016-06-30 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Do not rescale pts and dts if they are set to
AV_NOPTS_VALUE.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index c276a37..840bee3 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -533,8 +533,10 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket 
*pkt)
 }
 tb  = avf ->streams[s ]->time_base;
 tb2 = avf2->streams[s2]->time_base;
-pkt2.pts  = av_rescale_q(pkt->pts,  tb, tb2);
-pkt2.dts  = av_rescale_q(pkt->dts,  tb, tb2);
+if (pkt->pts != AV_NOPTS_VALUE)
+pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
+if (pkt->dts != AV_NOPTS_VALUE)
+pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
 pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
 pkt2.stream_index = s2;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/4] avformat/tee: Use ff_stream_encode_params_copy()

2016-06-30 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Use ff_stream_encode_params_copy() to copy encoding-related
fields (parameters) of stream.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 14 +++---
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 9d0a4cb..c276a37 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -294,17 +294,9 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 ret = AVERROR(ENOMEM);
 goto end;
 }
-st2->id = st->id;
-st2->r_frame_rate= st->r_frame_rate;
-st2->time_base   = st->time_base;
-st2->start_time  = st->start_time;
-st2->duration= st->duration;
-st2->nb_frames   = st->nb_frames;
-st2->disposition = st->disposition;
-st2->sample_aspect_ratio = st->sample_aspect_ratio;
-st2->avg_frame_rate  = st->avg_frame_rate;
-av_dict_copy(>metadata, st->metadata, 0);
-if ((ret = avcodec_parameters_copy(st2->codecpar, st->codecpar)) < 0)
+
+ret = ff_stream_encode_params_copy(st2, st);
+if (ret < 0)
 goto end;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] libavformat: Add FIFO pseudo-muxer

2016-06-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

FIFO pseudo-muxer allows to separate decoder from the
actual output by using first-in-first-out queue and
running actual muxer asynchronously in separate thread.

It can be configured to attempt transparent recovery
of output on failure.

Signed-off-by: Jan Sebechlebsky 
---
 configure|   1 +
 doc/muxers.texi  |  77 ++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 657 +++
 5 files changed, 737 insertions(+)
 create mode 100644 libavformat/fifo.c

diff --git a/configure b/configure
index 007c953..eacda09 100755
--- a/configure
+++ b/configure
@@ -2826,6 +2826,7 @@ dv_muxer_select="dvprofile"
 dxa_demuxer_select="riffdec"
 eac3_demuxer_select="ac3_parser"
 f4v_muxer_select="mov_muxer"
+fifo_muxer_deps="pthreads"
 flac_demuxer_select="flac_parser"
 hds_muxer_select="flv_muxer"
 hls_muxer_select="mpegts_muxer"
diff --git a/doc/muxers.texi b/doc/muxers.texi
index c2ca0ba..e545bc7 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1408,6 +1408,83 @@ Specify whether to remove all fragments when finished. 
Default 0 (do not remove)
 
 @end table
 
+@section fifo
+
+The fifo pseudo-muxer allows to separate encoding from any other muxer
+by using first-in-first-out queue and running the actual muxer in separate
+thread. This is especially useful in combination with tee muxer
+and output to several destinations with different reliability/writing 
speed/latency.
+
+The fifo muxer can operate in regular or fully non-blocking mode. This 
determines
+the behaviour in case the queue fills up. In regular mode the encoding is 
blocked
+until muxer processes some of the packets from queue, in non-blocking mode the 
packets
+are thrown away rather than blocking the encoder (this might be useful in 
real-time
+streaming scenario).
+
+@table @option
+
+@item fifo_format
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item queue_size
+Specify size of the queue (number of packets)
+
+@item format_opts
+Specify format options for the underlying muxer. Muxer options can be specified
+as a list of @var{key}=@var{value} pairs separated by ':'.
+
+@item block_on_overflow 0|1
+If set to 0, fully non-blocking mode will be used and in case the queue
+fills up, packets will be dropped. By default this option is set to 1,
+so in case of queue overflow the encoder will be block until muxer
+processes some of the packets.
+
+@item attempt_recovery 0|1
+If failure happens, attempt to recover the output. This is especially useful
+when used with network output, allows to restart streaming transparently.
+By default this option is turned off.
+
+@item max_recovery_attempts
+Sets maximal number of successive unsucessfull recovery attempts after which
+the output fails permanently. Unlimited if set to zero.
+
+@item recovery_wait_time
+Waiting time before the next recovery attempt after previous unsuccessfull
+recovery attempt.
+
+@item recovery_wait_streamtime 0|1
+If set to 0 (default), the real time is used when waiting for the recovery 
attempt
+(i.e. the recovery will be attempted after at least recovery_wait_time 
seconds).
+If set to 1, the time of the processed stream is taken into account instead
+(i.e. the recovery will be attempted after at least recovery_wait_time seconds
+of the stream is ommited).
+
+@item recover_any_error 0|1
+If set to 1, recovery will be attempted regardless of type of the error causing
+the failure (by default, in case of certain errors the recovery is not 
attempted
+even when attempt_recovery is on).
+
+@item restart_with_keyframe 0|1
+Specify whether to wait for the keyframe after recovering from
+queue overflow or failure.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Stream something to rtmp server using non-blocking mode and recover 
automatically
+in case failure happens (for example the network becomes unavailable for a 
moment).
+@example
+ffmpeg -re -i ... -c:v libx264 -c:a mp2 -f fifo -fifo_format flv -map 0:v -map 
0:a
+  -block_on_overflow 0 -attempt_recovery 1 rtmp://example.com/live/stream_name
+@end example
+
+@end itemize
+
 @section tee
 
 The tee muxer can be used to write the same data to several files or any
diff --git a/libavformat/Makefile b/libavformat/Makefile
index c49f9de..42fb9be 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -162,6 +162,7 @@ OBJS-$(CONFIG_FFM_DEMUXER)   += ffmdec.o
 OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o
 OBJS-$(CONFIG_FFMETADATA_DEMUXER)+= ffmetadec.o
 OBJS-$(CONFIG_FFMETADATA_MUXER)  += ffmetaenc.o
+OBJS-$(CONFIG_FIFO_MUXER)+= fifo.o
 OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o
 OBJS-$(CONFIG_FILMSTRIP_MUXER)   += filmstripenc.o
 OBJS-$(CONFIG_FLAC_DEMUXER)  += flacdec.o rawdec.o \
diff --git 

[FFmpeg-devel] [GSoC][PATCH] Add FIFO muxer

2016-06-28 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Hello,
I'm sending the patch with implementation of discussed FIFO pseudo-muxer which
is part of my GSoC project. The muxer allows to separate decoder from the actual
muxer (or several muxers when combined with tee). Trasparent recovery from 
failure
is also implemented.

I'll appreciate feedback

Best regards,
Jan

Jan Sebechlebsky (1):
  libavformat: Add FIFO pseudo-muxer

 configure|   1 +
 doc/muxers.texi  |  77 ++
 libavformat/Makefile |   1 +
 libavformat/allformats.c |   1 +
 libavformat/fifo.c   | 657 +++
 5 files changed, 737 insertions(+)
 create mode 100644 libavformat/fifo.c

-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3] avformat/tee: Support arbitrary number of slaves

2016-06-25 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 You're right. Should be fixed here.

 libavformat/tee.c | 26 --
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..9d0a4cb 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -27,8 +27,6 @@
 #include "avformat.h"
 #include "avio_internal.h"
 
-#define MAX_SLAVES 16
-
 typedef enum {
 ON_SLAVE_FAILURE_ABORT  = 1,
 ON_SLAVE_FAILURE_IGNORE = 2
@@ -52,7 +50,7 @@ typedef struct TeeContext {
 const AVClass *class;
 unsigned nb_slaves;
 unsigned nb_alive;
-TeeSlave slaves[MAX_SLAVES];
+TeeSlave *slaves;
 } TeeContext;
 
 static const char *const slave_delim = "|";
@@ -203,6 +201,7 @@ static void close_slaves(AVFormatContext *avf)
 for (i = 0; i < tee->nb_slaves; i++) {
 close_slave(>slaves[i]);
 }
+av_freep(>slaves);
 }
 
 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
@@ -443,24 +442,28 @@ static int tee_write_header(AVFormatContext *avf)
 TeeContext *tee = avf->priv_data;
 unsigned nb_slaves = 0, i;
 const char *filename = avf->filename;
-char *slaves[MAX_SLAVES];
+char **slaves = NULL;
 int ret;
 
 while (*filename) {
-if (nb_slaves == MAX_SLAVES) {
-av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
-   MAX_SLAVES);
-ret = AVERROR_PATCHWELCOME;
+char *slave = av_get_token(, slave_delim);
+if (!slave) {
+ret = AVERROR(ENOMEM);
 goto fail;
 }
-if (!(slaves[nb_slaves++] = av_get_token(, slave_delim))) {
-ret = AVERROR(ENOMEM);
+ret = av_dynarray_add_nofree(, _slaves, slave);
+if (ret < 0) {
+av_free(slave);
 goto fail;
 }
 if (strspn(filename, slave_delim))
 filename++;
 }
 
+if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 tee->nb_slaves = tee->nb_alive = nb_slaves;
 
 for (i = 0; i < nb_slaves; i++) {
@@ -483,12 +486,14 @@ static int tee_write_header(AVFormatContext *avf)
 av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
"to any slave.\n", i);
 }
+av_free(slaves);
 return 0;
 
 fail:
 for (i = 0; i < nb_slaves; i++)
 av_freep([i]);
 close_slaves(avf);
+av_free(slaves);
 return ret;
 }
 
@@ -505,6 +510,7 @@ static int tee_write_trailer(AVFormatContext *avf)
 ret_all = ret;
 }
 }
+av_freep(>slaves);
 return ret_all;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/3] avformat/segment: Use deinit function to deinitialize muxer

2016-06-20 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This commit moves all deinitialization of SegmentContext to
seg_free_context function and registers this function as
.deinit function of segment muxer. This also fixes memory leaks
caused by context not being deinitialized when write_header
call of segment muxer fails.

Signed-off-by: Jan Sebechlebsky 
---
 Thanks for noticing, I've removed unused declarations, this patch
 should be fine.

 libavformat/segment.c | 50 +++---
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index df37a56..c9d0074 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -627,9 +627,28 @@ static int select_reference_stream(AVFormatContext *s)
 return 0;
 }
 
-static void seg_free_context(SegmentContext *seg)
+static void seg_free_context(AVFormatContext *s)
 {
-ff_format_io_close(seg->avf, >list_pb);
+SegmentContext *seg = s->priv_data;
+SegmentListEntry *cur, *next;
+
+if (seg->list)
+ff_format_io_close(s, >list_pb);
+
+av_dict_free(>format_options);
+av_opt_free(seg);
+av_freep(>times);
+av_freep(>frames);
+av_freep(>cur_entry.filename);
+
+cur = seg->segment_list_entries;
+while (cur) {
+next = cur->next;
+av_freep(>filename);
+av_free(cur);
+cur = next;
+}
+
 avformat_free_context(seg->avf);
 seg->avf = NULL;
 }
@@ -801,8 +820,6 @@ static int seg_init(AVFormatContext *s)
 
 fail:
 av_dict_free();
-if (ret < 0)
-seg_free_context(seg);
 
 return ret;
 }
@@ -917,9 +934,6 @@ fail:
 seg->segment_frame_count++;
 }
 
-if (ret < 0)
-seg_free_context(seg);
-
 return ret;
 }
 
@@ -927,7 +941,6 @@ static int seg_write_trailer(struct AVFormatContext *s)
 {
 SegmentContext *seg = s->priv_data;
 AVFormatContext *oc = seg->avf;
-SegmentListEntry *cur, *next;
 int ret = 0;
 
 if (!oc)
@@ -944,25 +957,6 @@ static int seg_write_trailer(struct AVFormatContext *s)
 ret = segment_end(s, 1, 1);
 }
 fail:
-if (seg->list)
-ff_format_io_close(s, >list_pb);
-
-av_dict_free(>format_options);
-av_opt_free(seg);
-av_freep(>times);
-av_freep(>frames);
-av_freep(>cur_entry.filename);
-
-cur = seg->segment_list_entries;
-while (cur) {
-next = cur->next;
-av_freep(>filename);
-av_free(cur);
-cur = next;
-}
-
-avformat_free_context(oc);
-seg->avf = NULL;
 return ret;
 }
 
@@ -1045,6 +1039,7 @@ AVOutputFormat ff_segment_muxer = {
 .write_packet   = seg_write_packet,
 .write_trailer  = seg_write_trailer,
 .check_bitstream = seg_check_bitstream,
+.deinit = seg_free_context,
 .priv_class = _class,
 };
 
@@ -1064,5 +1059,6 @@ AVOutputFormat ff_stream_segment_muxer = {
 .write_packet   = seg_write_packet,
 .write_trailer  = seg_write_trailer,
 .check_bitstream = seg_check_bitstream,
+.deinit = seg_free_context,
 .priv_class = _class,
 };
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/3] avformat/segment: Check write_header return value immediately

2016-06-20 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Check write_header return value immediately after call,
so in the successive statements we can assume the write_header
was successful.

Signed-off-by: Jan Sebechlebsky 
---
 This is needed for the next patch in patchset.

 libavformat/segment.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index df6f4b5..7e4e840 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -754,6 +754,11 @@ static int seg_init(AVFormatContext *s)
 
 av_dict_copy(, seg->format_options, 0);
 ret = avformat_write_header(oc, );
+if (ret < 0) {
+ff_format_io_close(oc, >pb);
+goto fail;
+}
+
 if (av_dict_count(options)) {
 av_log(s, AV_LOG_ERROR,
"Some of the provided format options in '%s' are not 
recognized\n", seg->format_options_str);
@@ -761,10 +766,6 @@ static int seg_init(AVFormatContext *s)
 goto fail;
 }
 
-if (ret < 0) {
-ff_format_io_close(oc, >pb);
-goto fail;
-}
 seg->segment_frame_count = 0;
 
 av_assert0(s->nb_streams == oc->nb_streams);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] Fix memory leaks in segment muxer

2016-06-20 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Hello,
I've observed several memory leaks in segment muxer in case the
failure happens in seg_init (write_header call). 
I'm sending patchset to fix those.

Regards,
Jan

Jan Sebechlebsky (3):
  avformat/segment: Check write_header return value immediately
  avformat/segment: Ensure write_trailer is called
  avformat/segment: Use deinit function to deinitialize muxer

 libavformat/segment.c | 68 ---
 1 file changed, 37 insertions(+), 31 deletions(-)

-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/3] avformat/segment: Use deinit function to deinitialize muxer

2016-06-20 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This commit moves all deinitialization of SegmentContext to
seg_free_context function and registers this function as
.deinit function of segment muxer. This also fixes memory leaks
caused by context not being deinitialized when write_header
call of segment muxer fails.

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/segment.c | 49 +++--
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index df37a56..872233b 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -627,9 +627,28 @@ static int select_reference_stream(AVFormatContext *s)
 return 0;
 }
 
-static void seg_free_context(SegmentContext *seg)
+static void seg_free_context(AVFormatContext *s)
 {
-ff_format_io_close(seg->avf, >list_pb);
+SegmentContext *seg = s->priv_data;
+SegmentListEntry *cur, *next;
+
+if (seg->list)
+ff_format_io_close(s, >list_pb);
+
+av_dict_free(>format_options);
+av_opt_free(seg);
+av_freep(>times);
+av_freep(>frames);
+av_freep(>cur_entry.filename);
+
+cur = seg->segment_list_entries;
+while (cur) {
+next = cur->next;
+av_freep(>filename);
+av_free(cur);
+cur = next;
+}
+
 avformat_free_context(seg->avf);
 seg->avf = NULL;
 }
@@ -801,8 +820,6 @@ static int seg_init(AVFormatContext *s)
 
 fail:
 av_dict_free();
-if (ret < 0)
-seg_free_context(seg);
 
 return ret;
 }
@@ -917,9 +934,6 @@ fail:
 seg->segment_frame_count++;
 }
 
-if (ret < 0)
-seg_free_context(seg);
-
 return ret;
 }
 
@@ -944,25 +958,6 @@ static int seg_write_trailer(struct AVFormatContext *s)
 ret = segment_end(s, 1, 1);
 }
 fail:
-if (seg->list)
-ff_format_io_close(s, >list_pb);
-
-av_dict_free(>format_options);
-av_opt_free(seg);
-av_freep(>times);
-av_freep(>frames);
-av_freep(>cur_entry.filename);
-
-cur = seg->segment_list_entries;
-while (cur) {
-next = cur->next;
-av_freep(>filename);
-av_free(cur);
-cur = next;
-}
-
-avformat_free_context(oc);
-seg->avf = NULL;
 return ret;
 }
 
@@ -1045,6 +1040,7 @@ AVOutputFormat ff_segment_muxer = {
 .write_packet   = seg_write_packet,
 .write_trailer  = seg_write_trailer,
 .check_bitstream = seg_check_bitstream,
+.deinit = seg_free_context,
 .priv_class = _class,
 };
 
@@ -1064,5 +1060,6 @@ AVOutputFormat ff_stream_segment_muxer = {
 .write_packet   = seg_write_packet,
 .write_trailer  = seg_write_trailer,
 .check_bitstream = seg_check_bitstream,
+.deinit = seg_free_context,
 .priv_class = _class,
 };
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/3] avformat/segment: Ensure write_trailer is called

2016-06-20 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Ensure that write_trailer is always called after successful
write_header operation so underlying muxer is deinitialized.

Signed-off-by: Jan Sebechlebsky 
---
 This is a little tricky - we have to ensure that 
 write_trailer is called if the write_header succeeded, however
 if the io_open fails the AVIOContext is invalid and cause
 underlying muxer to crash (the muxer may assume that AVIOContext 
 is initialized). So temporarily AVIOContext is initialized to null
 context just to allow write_trailer to finalize underlying muxer
 successfully.

 libavformat/segment.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index 7e4e840..df37a56 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -763,6 +763,8 @@ static int seg_init(AVFormatContext *s)
 av_log(s, AV_LOG_ERROR,
"Some of the provided format options in '%s' are not 
recognized\n", seg->format_options_str);
 ret = AVERROR(EINVAL);
+av_write_trailer(oc);
+ff_format_io_close(oc, >pb);
 goto fail;
 }
 
@@ -785,8 +787,14 @@ static int seg_init(AVFormatContext *s)
 } else {
 close_null_ctxp(>pb);
 }
-if ((ret = oc->io_open(oc, >pb, oc->filename, AVIO_FLAG_WRITE, 
NULL)) < 0)
+if ((ret = oc->io_open(oc, >pb, oc->filename, AVIO_FLAG_WRITE, 
NULL)) < 0) {
+// Some muxers rely on valid AVIOContext so we need to create one
+// before performing write trailer
+open_null_ctx(>pb);
+av_write_trailer(oc);
+close_null_ctxp(>pb);
 goto fail;
+}
 if (!seg->individual_header_trailer)
 oc->pb->seekable = 0;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3] avformat/tee: Support arbitrary number of slaves

2016-06-16 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 I've missed that - sorry, should be fixed in this patch.

 libavformat/tee.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..421623d 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -27,8 +27,6 @@
 #include "avformat.h"
 #include "avio_internal.h"
 
-#define MAX_SLAVES 16
-
 typedef enum {
 ON_SLAVE_FAILURE_ABORT  = 1,
 ON_SLAVE_FAILURE_IGNORE = 2
@@ -52,7 +50,7 @@ typedef struct TeeContext {
 const AVClass *class;
 unsigned nb_slaves;
 unsigned nb_alive;
-TeeSlave slaves[MAX_SLAVES];
+TeeSlave *slaves;
 } TeeContext;
 
 static const char *const slave_delim = "|";
@@ -203,6 +201,7 @@ static void close_slaves(AVFormatContext *avf)
 for (i = 0; i < tee->nb_slaves; i++) {
 close_slave(>slaves[i]);
 }
+av_freep(>slaves);
 }
 
 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
@@ -443,24 +442,26 @@ static int tee_write_header(AVFormatContext *avf)
 TeeContext *tee = avf->priv_data;
 unsigned nb_slaves = 0, i;
 const char *filename = avf->filename;
-char *slaves[MAX_SLAVES];
+char **slaves = NULL;
 int ret;
 
 while (*filename) {
-if (nb_slaves == MAX_SLAVES) {
-av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
-   MAX_SLAVES);
-ret = AVERROR_PATCHWELCOME;
-goto fail;
-}
-if (!(slaves[nb_slaves++] = av_get_token(, slave_delim))) {
+char *slave = av_get_token(, slave_delim);
+if (!slave) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
+ret = av_dynarray_add_nofree(, _slaves, slave);
+if (ret < 0)
+goto fail;
 if (strspn(filename, slave_delim))
 filename++;
 }
 
+if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 tee->nb_slaves = tee->nb_alive = nb_slaves;
 
 for (i = 0; i < nb_slaves; i++) {
@@ -483,12 +484,14 @@ static int tee_write_header(AVFormatContext *avf)
 av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
"to any slave.\n", i);
 }
+av_free(slaves);
 return 0;
 
 fail:
 for (i = 0; i < nb_slaves; i++)
 av_freep([i]);
 close_slaves(avf);
+av_free(slaves);
 return ret;
 }
 
@@ -505,6 +508,7 @@ static int tee_write_trailer(AVFormatContext *avf)
 ret_all = ret;
 }
 }
+av_freep(>slaves);
 return ret_all;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2] avformat/tee: Support arbitrary number of slaves

2016-06-12 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 24 +++-
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..bf7438c 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -27,8 +27,6 @@
 #include "avformat.h"
 #include "avio_internal.h"
 
-#define MAX_SLAVES 16
-
 typedef enum {
 ON_SLAVE_FAILURE_ABORT  = 1,
 ON_SLAVE_FAILURE_IGNORE = 2
@@ -52,7 +50,7 @@ typedef struct TeeContext {
 const AVClass *class;
 unsigned nb_slaves;
 unsigned nb_alive;
-TeeSlave slaves[MAX_SLAVES];
+TeeSlave *slaves;
 } TeeContext;
 
 static const char *const slave_delim = "|";
@@ -203,6 +201,7 @@ static void close_slaves(AVFormatContext *avf)
 for (i = 0; i < tee->nb_slaves; i++) {
 close_slave(>slaves[i]);
 }
+av_freep(>slaves);
 }
 
 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
@@ -443,17 +442,17 @@ static int tee_write_header(AVFormatContext *avf)
 TeeContext *tee = avf->priv_data;
 unsigned nb_slaves = 0, i;
 const char *filename = avf->filename;
-char *slaves[MAX_SLAVES];
+char **slaves = NULL;
 int ret;
 
 while (*filename) {
-if (nb_slaves == MAX_SLAVES) {
-av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
-   MAX_SLAVES);
-ret = AVERROR_PATCHWELCOME;
+char *slave = av_get_token(, slave_delim);
+if (!slave) {
+ret = AVERROR(ENOMEM);
 goto fail;
 }
-if (!(slaves[nb_slaves++] = av_get_token(, slave_delim))) {
+dynarray_add(, _slaves, slave);
+if (!slaves) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
@@ -461,6 +460,10 @@ static int tee_write_header(AVFormatContext *avf)
 filename++;
 }
 
+if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 tee->nb_slaves = tee->nb_alive = nb_slaves;
 
 for (i = 0; i < nb_slaves; i++) {
@@ -483,12 +486,14 @@ static int tee_write_header(AVFormatContext *avf)
 av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
"to any slave.\n", i);
 }
+av_free(slaves);
 return 0;
 
 fail:
 for (i = 0; i < nb_slaves; i++)
 av_freep([i]);
 close_slaves(avf);
+av_free(slaves);
 return ret;
 }
 
@@ -505,6 +510,7 @@ static int tee_write_trailer(AVFormatContext *avf)
 ret_all = ret;
 }
 }
+av_freep(>slaves);
 return ret_all;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/tee: Support arbitrary number of slaves

2016-06-10 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..427e999 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -27,8 +27,6 @@
 #include "avformat.h"
 #include "avio_internal.h"
 
-#define MAX_SLAVES 16
-
 typedef enum {
 ON_SLAVE_FAILURE_ABORT  = 1,
 ON_SLAVE_FAILURE_IGNORE = 2
@@ -52,7 +50,7 @@ typedef struct TeeContext {
 const AVClass *class;
 unsigned nb_slaves;
 unsigned nb_alive;
-TeeSlave slaves[MAX_SLAVES];
+TeeSlave *slaves;
 } TeeContext;
 
 static const char *const slave_delim = "|";
@@ -203,6 +201,8 @@ static void close_slaves(AVFormatContext *avf)
 for (i = 0; i < tee->nb_slaves; i++) {
 close_slave(>slaves[i]);
 }
+
+av_freep(>slaves);
 }
 
 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
@@ -443,17 +443,17 @@ static int tee_write_header(AVFormatContext *avf)
 TeeContext *tee = avf->priv_data;
 unsigned nb_slaves = 0, i;
 const char *filename = avf->filename;
-char *slaves[MAX_SLAVES];
+char **slaves = NULL;
 int ret;
 
 while (*filename) {
-if (nb_slaves == MAX_SLAVES) {
-av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
-   MAX_SLAVES);
-ret = AVERROR_PATCHWELCOME;
+char *slave = av_get_token(, slave_delim);
+if (!slave) {
+ret = AVERROR(ENOMEM);
 goto fail;
 }
-if (!(slaves[nb_slaves++] = av_get_token(, slave_delim))) {
+dynarray_add(, _slaves, slave);
+if (!slaves) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
@@ -461,6 +461,10 @@ static int tee_write_header(AVFormatContext *avf)
 filename++;
 }
 
+if (!(tee->slaves = calloc(nb_slaves, sizeof(*tee->slaves {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 tee->nb_slaves = tee->nb_alive = nb_slaves;
 
 for (i = 0; i < nb_slaves; i++) {
@@ -483,12 +487,13 @@ static int tee_write_header(AVFormatContext *avf)
 av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
"to any slave.\n", i);
 }
+av_free(slaves);
 return 0;
-
 fail:
 for (i = 0; i < nb_slaves; i++)
 av_freep([i]);
 close_slaves(avf);
+av_free(slaves);
 return ret;
 }
 
@@ -505,6 +510,8 @@ static int tee_write_trailer(AVFormatContext *avf)
 ret_all = ret;
 }
 }
+
+av_freep(>slaves);
 return ret_all;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avutil/threadmessage.h: Fix swapped comments

2016-06-10 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Fix swapped descriptions of av_thread_message_queue_set_err_send
and av_thread_message_queue_set_err_recv.

Signed-off-by: Jan Sebechlebsky 
---
 libavutil/threadmessage.h | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libavutil/threadmessage.h b/libavutil/threadmessage.h
index e256cae..8480a0a 100644
--- a/libavutil/threadmessage.h
+++ b/libavutil/threadmessage.h
@@ -69,10 +69,10 @@ int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
 /**
  * Set the sending error code.
  *
- * If the error code is set to non-zero, av_thread_message_queue_recv() will
- * return it immediately when there are no longer available messages.
- * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used
- * to cause the receiving thread to stop or suspend its operation.
+ * If the error code is set to non-zero, av_thread_message_queue_send() will
+ * return it immediately. Conventional values, such as AVERROR_EOF or
+ * AVERROR(EAGAIN), can be used to cause the sending thread to stop or
+ * suspend its operation.
  */
 void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
   int err);
@@ -80,10 +80,10 @@ void 
av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
 /**
  * Set the receiving error code.
  *
- * If the error code is set to non-zero, av_thread_message_queue_send() will
- * return it immediately. Conventional values, such as AVERROR_EOF or
- * AVERROR(EAGAIN), can be used to cause the sending thread to stop or
- * suspend its operation.
+ * If the error code is set to non-zero, av_thread_message_queue_recv() will
+ * return it immediately when there are no longer available messages.
+ * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used
+ * to cause the receiving thread to stop or suspend its operation.
  */
 void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
   int err);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2] avformat/tee: Move to new BSF API

2016-06-04 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 I've rewritten the patch rapidly. Instead of using recursion it
 accumulates bitstream filtered packets in fifo buffer and
 dynamic array is used instead of linked list to store chain of
 bitstream filters.

 libavformat/tee.c | 301 +-
 1 file changed, 255 insertions(+), 46 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..0e394ea 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -23,6 +23,7 @@
 #include "libavutil/avutil.h"
 #include "libavutil/avstring.h"
 #include "libavutil/opt.h"
+#include "libavutil/fifo.h"
 #include "internal.h"
 #include "avformat.h"
 #include "avio_internal.h"
@@ -37,8 +38,15 @@ typedef enum {
 #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
 
 typedef struct {
+AVBSFContext **bsfs_ctxs;
+unsigned bsfs_ctxs_nr;
+} TeeBSFList;
+
+typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+TeeBSFList *bsfs; // bitstream filters per stream
+
+AVFifoBuffer *fifo; // fifo buffer used for bsf processing
 
 SlaveFailurePolicy on_fail;
 
@@ -106,6 +114,46 @@ fail:
 return ret;
 }
 
+static int initialize_bsf(AVFormatContext *avf, const char * bsf_name,
+  AVCodecParameters *par_in, AVRational tb_in,
+  AVBSFContext ** bsf_ctx)
+{
+int ret = 0;
+const AVBitStreamFilter *filter = av_bsf_get_by_name(bsf_name);
+AVBSFContext *bsf_ctx_tmp;
+
+if (!filter) {
+av_log(avf, AV_LOG_ERROR, "Unknown bitstream filter '%s'\n",
+   bsf_name);
+ret = AVERROR(EINVAL);
+return ret;
+}
+
+if ((ret = av_bsf_alloc(filter, _ctx_tmp)) < 0) {
+av_log(avf, AV_LOG_ERROR, "Cannot initialize bitstream filter '%s'",
+   bsf_name);
+return ret;
+}
+
+ret = avcodec_parameters_copy(bsf_ctx_tmp->par_in, par_in);
+if (ret < 0) {
+goto fail;
+}
+
+bsf_ctx_tmp->time_base_in = tb_in;
+
+if ((ret = av_bsf_init(bsf_ctx_tmp)) < 0) {
+goto fail;
+}
+
+*bsf_ctx = bsf_ctx_tmp;
+
+return ret;
+fail:
+av_bsf_free(_ctx_tmp);
+return ret;
+}
+
 /**
  * Parse list of bitstream filters and add them to the list of filters
  * pointed to by bsfs.
@@ -113,37 +161,49 @@ fail:
  * The list must be specified in the form:
  * BSFS ::= BSF[,BSFS]
  */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
+static int parse_bsfs(AVFormatContext *avf, const char *bsfs_spec,
+  TeeBSFList * bsf_list, int stream_nr)
 {
 char *bsf_name, *buf, *dup, *saveptr;
-int ret = 0;
+int ret = 0, i;
+AVBSFContext *bsf_ctx;
+AVStream *stream = avf->streams[stream_nr];
+AVCodecParameters *last_codecpar = stream->codecpar;
+AVRational last_tb = stream->time_base;
 
-if (!(dup = buf = av_strdup(bsfs_spec)))
-return AVERROR(ENOMEM);
+if (!(dup = buf = av_strdup(bsfs_spec))) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 
 while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
-
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
-   bsf_name);
-ret = AVERROR_UNKNOWN;
-goto end;
+ret = initialize_bsf(avf, bsf_name, last_codecpar, last_tb, _ctx);
+if (ret < 0) {
+goto fail;
 }
 
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
+last_tb = bsf_ctx->time_base_out;
+last_codecpar = bsf_ctx->par_out;
+
+ret = av_dynarray_add_nofree(_list->bsfs_ctxs, 
_list->bsfs_ctxs_nr, bsf_ctx);
+if (ret < 0) {
+goto fail;
+}
 
 buf = NULL;
+bsf_ctx = NULL;
 }
 
-end:
 av_free(dup);
 return ret;
+fail:
+for (i = 0; i < bsf_list->bsfs_ctxs_nr; ++i) {
+av_bsf_free(_list->bsfs_ctxs[i]);
+}
+bsf_list->bsfs_ctxs_nr = 0;
+av_free(dup);
+av_bsf_free(_ctx);
+return ret;
 }
 
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
@@ -163,6 +223,154 @@ static inline int parse_slave_failure_policy_option(const 
char *opt, TeeSlave *t
 return AVERROR(EINVAL);
 }
 
+/*
+ * Applies single bitstream filter to single packet, all resulting filtered 
packets
+ * are pushed to fifo buffer
+ */
+static int tee_apply_bsf(AVFifoBuffer *fifo, AVBSFContext *bsf_ctx, AVPacket 
*pkt)
+{
+int ret = 0;
+ret = av_bsf_send_packet(bsf_ctx, pkt);
+   

[FFmpeg-devel] [PATCH] libavutil/fifo: Fix fifo grow step

2016-06-03 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Fifo was reallocating always to twice of the requested size.
This fixes it to reallocate to requested size, or twice of the
original size - whichever is greater.

Signed-off-by: Jan Sebechlebsky 
---
 I believe the intended behaviour was as described in commit message
 and FFMAX(size,2*size) is a mistake.

 libavutil/fifo.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavutil/fifo.c b/libavutil/fifo.c
index 986729a..1060aed 100644
--- a/libavutil/fifo.c
+++ b/libavutil/fifo.c
@@ -113,7 +113,7 @@ int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
 size += av_fifo_size(f);
 
 if (old_size < size)
-return av_fifo_realloc2(f, FFMAX(size, 2*size));
+return av_fifo_realloc2(f, FFMAX(size, 2*old_size));
 return 0;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/tee: Move to new BSF API

2016-05-10 Thread sebechlebskyjan
From: Jan Sebechlebsky 

Signed-off-by: Jan Sebechlebsky 
---
 libavformat/tee.c | 171 --
 1 file changed, 139 insertions(+), 32 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 806beaa..ff0918b 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -36,9 +36,14 @@ typedef enum {
 
 #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
 
+typedef struct TeeBSFList {
+AVBSFContext *bsf_ctx;
+struct TeeBSFList *next;
+} TeeBSFList;
+
 typedef struct {
 AVFormatContext *avf;
-AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+TeeBSFList **bsfs; ///< bitstream filters per stream
 
 SlaveFailurePolicy on_fail;
 
@@ -113,30 +118,61 @@ fail:
  * The list must be specified in the form:
  * BSFS ::= BSF[,BSFS]
  */
-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
-  AVBitStreamFilterContext **bsfs)
+static int parse_bsfs(AVFormatContext *avf, const char *bsfs_spec,
+  TeeBSFList **bsfs, int stream_nr)
 {
 char *bsf_name, *buf, *dup, *saveptr;
 int ret = 0;
+const AVBitStreamFilter *filter;
+AVBSFContext *bsf_ctx;
+TeeBSFList *bsf_lst;
+AVStream *stream = avf->streams[stream_nr];
+AVRational last_tb = stream->time_base;
 
 if (!(dup = buf = av_strdup(bsfs_spec)))
 return AVERROR(ENOMEM);
 
 while (bsf_name = av_strtok(buf, ",", )) {
-AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
+filter = av_bsf_get_by_name(bsf_name);
+
+if (!filter) {
+av_log(avf, AV_LOG_ERROR, "Unknown bitstream filter '%s'\n",
+   bsf_name);
+ret = AVERROR(EINVAL);
+goto end;
+}
 
-if (!bsf) {
-av_log(log_ctx, AV_LOG_ERROR,
-   "Cannot initialize bitstream filter with name '%s', "
-   "unknown filter or internal error happened\n",
+if ((ret = av_bsf_alloc(filter, _ctx)) < 0) {
+av_log(avf, AV_LOG_ERROR, "Cannot initialize bitstream filter 
'%s'",
bsf_name);
-ret = AVERROR_UNKNOWN;
 goto end;
 }
 
-/* append bsf context to the list of bsf contexts */
-*bsfs = bsf;
-bsfs = >next;
+ret = avcodec_parameters_copy(bsf_ctx->par_in, stream->codecpar);
+if (ret < 0) {
+goto fail;
+}
+
+bsf_ctx->time_base_in = last_tb;
+
+if ((ret = av_bsf_init(bsf_ctx)) < 0) {
+goto fail;
+}
+
+last_tb = bsf_ctx->time_base_out;
+
+/* allocate new bsf list node and append to the list of bsf contexts */
+bsf_lst = av_mallocz(sizeof(TeeBSFList));
+
+if (!bsf_lst) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
+bsf_lst->bsf_ctx = bsf_ctx;
+
+*bsfs = bsf_lst;
+bsfs = _lst->next;
 
 buf = NULL;
 }
@@ -144,6 +180,10 @@ static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
 end:
 av_free(dup);
 return ret;
+fail:
+av_free(dup);
+av_bsf_free(_ctx);
+return ret;
 }
 
 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave 
*tee_slave)
@@ -163,6 +203,75 @@ static inline int parse_slave_failure_policy_option(const 
char *opt, TeeSlave *t
 return AVERROR(EINVAL);
 }
 
+/**
+ * Apply bitstream filters and write frame(s)
+ */
+static int tee_process_packet(AVFormatContext *avf, TeeBSFList *bsf, AVPacket 
*pkt,
+  AVRational pkt_tb, int stream_nr)
+{
+int ret_all = 0,ret;
+if (!bsf) {
+if (pkt) {
+AVRational out_tb = avf->streams[stream_nr]->time_base;
+pkt->pts = av_rescale_q(pkt->pts, pkt_tb, out_tb);
+pkt->dts = av_rescale_q(pkt->dts, pkt_tb, out_tb);
+pkt->duration = av_rescale_q(pkt->duration, pkt_tb, out_tb);
+pkt->stream_index = stream_nr;
+
+ret_all = av_interleaved_write_frame(avf, pkt);
+}
+goto end;
+}
+
+if ((ret_all = av_bsf_send_packet(bsf->bsf_ctx, pkt)) < 0) {
+return ret_all;
+}
+
+do {
+if (!(ret = av_bsf_receive_packet(bsf->bsf_ctx, pkt))) {
+ret = tee_process_packet(avf, bsf->next, pkt,
+ bsf->bsf_ctx->time_base_out, stream_nr);
+}
+} while(!ret);
+
+if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
+ret_all = ret;
+}
+
+end:
+return ret_all;
+}
+
+static void free_bsfs(TeeBSFList *bsf_list) {
+TeeBSFList *next, *current = bsf_list;
+
+while (current) {
+av_bsf_free(>bsf_ctx);
+next = current->next;
+av_free(current);
+current = next;
+}
+}
+
+static int flush_bsfs(TeeSlave *tee_slave)
+{
+AVFormatContext *avf = tee_slave->avf;
+int i;
+

[FFmpeg-devel] [PATCH v2 1/2] avformat/tee: Fix TeeSlave.bsfs pointer array size

2016-05-03 Thread sebechlebskyjan
From: Jan Sebechlebsky 

TeeSlave.bsfs is array of pointers to AVBitStreamFilterContext,
so element size should be really size of a pointer, not size
of TeeSlave structure.

Signed-off-by: Jan Sebechlebsky 
---
 I've rewritten sizeof as suggested :)

 libavformat/tee.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index 499ef33..6d2ce53 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -324,7 +324,7 @@ static int open_slave(AVFormatContext *avf, char *slave, 
TeeSlave *tee_slave)
 }
 tee_slave->header_written = 1;
 
-tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(TeeSlave));
+tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(*tee_slave->bsfs));
 if (!tee_slave->bsfs) {
 ret = AVERROR(ENOMEM);
 goto end;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2] avcodec/mjpeg2jpeg_bsf: Check ff_bsf_get_packet success

2016-05-01 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This fixes ticket #5487 - mjpeg2jpeg bitstream filter causes
segmentation fault with header-less mjpeg.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/mjpeg2jpeg_bsf.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavcodec/mjpeg2jpeg_bsf.c b/libavcodec/mjpeg2jpeg_bsf.c
index 2d4cee2..6f02bc0 100644
--- a/libavcodec/mjpeg2jpeg_bsf.c
+++ b/libavcodec/mjpeg2jpeg_bsf.c
@@ -86,6 +86,8 @@ static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out)
 uint8_t *output;
 
 ret = ff_bsf_get_packet(ctx, );
+if (ret < 0)
+return ret;
 
 if (in->size < 12) {
 av_log(ctx, AV_LOG_ERROR, "input is truncated\n");
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avcodec/mjpeg2jpeg_bsf: Check ff_bsf_get_packet success

2016-05-01 Thread sebechlebskyjan
From: Jan Sebechlebsky 

This fixes ticket #5487 - mjpeg2jpeg bitstream filter causes
segmentation fault with header-less mjpeg.

Signed-off-by: Jan Sebechlebsky 
---
 libavcodec/mjpeg2jpeg_bsf.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libavcodec/mjpeg2jpeg_bsf.c b/libavcodec/mjpeg2jpeg_bsf.c
index 2d4cee2..c4b5050 100644
--- a/libavcodec/mjpeg2jpeg_bsf.c
+++ b/libavcodec/mjpeg2jpeg_bsf.c
@@ -85,7 +85,9 @@ static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out)
 int input_skip, output_size;
 uint8_t *output;
 
-ret = ff_bsf_get_packet(ctx, );
+if ((ret = ff_bsf_get_packet(ctx, )) < 0) {
+return ret;
+}
 
 if (in->size < 12) {
 av_log(ctx, AV_LOG_ERROR, "input is truncated\n");
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


  1   2   >