Skip to content

Instantly share code, notes, and snippets.

@RobertoUa
Last active August 10, 2022 09:26
Show Gist options
  • Select an option

  • Save RobertoUa/b35d84ff2ddfa6afe5fa446c66053be0 to your computer and use it in GitHub Desktop.

Select an option

Save RobertoUa/b35d84ff2ddfa6afe5fa446c66053be0 to your computer and use it in GitHub Desktop.
for ffmpeg 5.1
diff --git a/libavformat/tee.c b/libavformat/tee.c
index 6fafc0a99d..e31e00496c 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -20,6 +20,7 @@
*/
+#define _GNU_SOURCE
#include "libavutil/avutil.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
@@ -27,6 +28,9 @@
#include "avformat.h"
#include "avio_internal.h"
#include "tee_common.h"
+#include <pthread.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
typedef enum {
ON_SLAVE_FAILURE_ABORT = 1,
@@ -55,6 +59,7 @@ typedef struct TeeContext {
unsigned nb_alive;
TeeSlave *slaves;
int use_fifo;
+ const char *tee_pipe;
AVDictionary *fifo_options;
} TeeContext;
@@ -68,6 +73,8 @@ static const AVOption options[] = {
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),
AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
+ {"tee_pipe", "tee input pipe", OFFSET(tee_pipe),
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
{NULL}
};
@@ -437,6 +444,7 @@ static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, i
{
TeeContext *tee = avf->priv_data;
TeeSlave *tee_slave = &tee->slaves[slave_idx];
+ char *url = strdup(tee_slave->avf->url);
tee->nb_alive--;
@@ -446,15 +454,69 @@ static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, i
av_log(avf, AV_LOG_ERROR, "All tee outputs failed.\n");
return err_n;
} else if (tee_slave->on_fail == ON_SLAVE_FAILURE_ABORT) {
- av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting.\n", slave_idx);
+ av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting. filename:'%s'\n", slave_idx, url);
return err_n;
} else {
- av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves.\n",
- slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves);
+ av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves. filename:'%s'\n",
+ slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves, url);
return 0;
}
}
+static void *input_listener(void *threadarg)
+{
+ AVFormatContext *avf = threadarg;
+ TeeContext *tee = avf->priv_data;
+
+ int fd;
+ char line[20];
+
+ if (mkfifo(tee->tee_pipe, 0666) == -1) {
+ av_log(avf, AV_LOG_INFO, "Error making tee pipe %s\n", tee->tee_pipe);
+ }
+
+ if ((fd = open(tee->tee_pipe, O_RDWR)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Tee pipe opening error %s\n", tee->tee_pipe);
+ return NULL;
+ }
+
+ av_log(avf, AV_LOG_INFO, "Listen to slave input. Press slave index to close it. Available %u/%u slaves.\n",
+ tee->nb_alive, tee->nb_slaves);
+
+ while (1) {
+ int idx;
+
+ if (read(fd, line, sizeof(line)) > 0) {
+ av_log(avf, AV_LOG_INFO, "Got Line %s\n", line);
+ idx = atoi(line);
+ if (idx == 0 && !(strcmp(line, "0\n") != 0 || strcmp(line, "0") != 0)) idx = -1;
+
+ if (tee->nb_slaves <= idx || idx < 0) {
+ av_log(avf, AV_LOG_WARNING, "Slave muxer #%u not found, available %u/%u slaves.\n",
+ idx, tee->nb_alive, tee->nb_slaves);
+ } else if (tee->slaves[idx].avf == NULL) {
+ av_log(avf, AV_LOG_WARNING, "Slave muxer #%u is already closed, available %u/%u slaves.\n",
+ idx, tee->nb_alive, tee->nb_slaves);
+ } else {
+ TeeSlave *tee_slave = &tee->slaves[idx];
+ char *url = strdup(tee_slave->avf->url);
+
+ log_slave(tee_slave,avf, AV_LOG_INFO);
+
+ tee->nb_alive--;
+
+ close_slave(tee_slave);
+
+ av_log(avf, AV_LOG_INFO, "Slave muxer #%u closed, continuing with %u/%u slaves. Url=%s\n",
+ idx, tee->nb_alive, tee->nb_slaves, url);
+ free(url);
+ }
+ } else break;
+ }
+ close(fd);
+ return NULL;
+}
+
static int tee_write_header(AVFormatContext *avf)
{
TeeContext *tee = avf->priv_data;
@@ -463,6 +525,11 @@ static int tee_write_header(AVFormatContext *avf)
char **slaves = NULL;
int ret;
+ if (tee->tee_pipe != NULL) {
+ pthread_t thread;
+ pthread_create(&thread, NULL, input_listener, avf);
+ }
+
while (*filename) {
char *slave = av_get_token(&filename, slave_delim);
if (!slave) {
@@ -548,6 +615,11 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
unsigned i, s;
int s2;
+ if (tee->nb_alive <= 0){
+ av_log(avf, AV_LOG_INFO, "All tee outputs closed.\n");
+ return AVERROR_EXIT;
+ }
+
for (i = 0; i < tee->nb_slaves; i++) {
if (!(avf2 = tee->slaves[i].avf))
continue;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment