Last active
August 10, 2022 09:26
-
-
Save RobertoUa/b35d84ff2ddfa6afe5fa446c66053be0 to your computer and use it in GitHub Desktop.
for ffmpeg 5.1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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