Message ID | 20210623125648.1092-1-jamrial@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | [FFmpeg-devel] avformat: add a concat protocol that takes a line break delimited list of resources | expand |
Context | Check | Description |
---|---|---|
andriy/x86_make | success | Make finished |
andriy/x86_make_fate | success | Make fate finished |
andriy/PPC64_make | success | Make finished |
andriy/PPC64_make_fate | success | Make fate finished |
James Almer (12021-06-23): > Suggested-by: ffmpeg@fb.com > Signed-off-by: James Almer <jamrial@gmail.com> > --- > doc/protocols.texi | 30 +++++++++++ > libavformat/Makefile | 1 + > libavformat/concat.c | 111 ++++++++++++++++++++++++++++++++++++++++ > libavformat/protocols.c | 1 + > 4 files changed, 143 insertions(+) > > diff --git a/doc/protocols.texi b/doc/protocols.texi > index ccdfb6e439..2b8ce1b7d5 100644 > --- a/doc/protocols.texi > +++ b/doc/protocols.texi > @@ -215,6 +215,36 @@ ffplay concat:split1.mpeg\|split2.mpeg\|split3.mpeg > Note that you may need to escape the character "|" which is special for > many shells. > > +@section concatf > + > +Physical concatenation protocol using a line break delimited list of > +resources. > + > +Read and seek from many resources in sequence as if they were > +a unique resource. > + > +A URL accepted by this protocol has the syntax: > +@example > +concatf:@var{URL} > +@end example > + > +where @var{URL} is the url containing a line break delimited list of > +resources to be concatenated, each one possibly specifying a distinct > +protocol. > + > +For example to read a sequence of files @file{split1.mpeg}, > +@file{split2.mpeg}, @file{split3.mpeg} listed in separate lines within > +a file @file{split.txt} with @command{ffplay} use the command: > +@example > +ffplay concatf:split.txt > +@end example > +Where @file{split.txt} contains the lines: > +@example > +split1.mpeg > +split2.mpeg > +split3.mpeg > +@end example > + > @section crypto > > AES-encrypted stream reading protocol. > diff --git a/libavformat/Makefile b/libavformat/Makefile > index c9ef564523..caca95802a 100644 > --- a/libavformat/Makefile > +++ b/libavformat/Makefile > @@ -616,6 +616,7 @@ OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o > OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o > OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o > OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o > +OBJS-$(CONFIG_CONCATF_PROTOCOL) += concat.o > OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o > OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o > OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o > diff --git a/libavformat/concat.c b/libavformat/concat.c > index 278afd997d..d224b51db0 100644 > --- a/libavformat/concat.c > +++ b/libavformat/concat.c > @@ -22,9 +22,12 @@ > */ > > #include "libavutil/avstring.h" > +#include "libavutil/bprint.h" > #include "libavutil/mem.h" > > #include "avformat.h" > +#include "avio_internal.h" > +#include "internal.h" > #include "url.h" > > #define AV_CAT_SEPARATOR "|" > @@ -56,6 +59,7 @@ static av_cold int concat_close(URLContext *h) > return err < 0 ? -1 : 0; > } > > +#if CONFIG_CONCAT_PROTOCOL > static av_cold int concat_open(URLContext *h, const char *uri, int flags) > { > char *node_uri = NULL; > @@ -124,6 +128,7 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) > data->total_size = total_size; > return err; > } > +#endif > > static int concat_read(URLContext *h, unsigned char *buf, int size) > { > @@ -188,6 +193,7 @@ static int64_t concat_seek(URLContext *h, int64_t pos, int whence) > return result; > } > > +#if CONFIG_CONCAT_PROTOCOL > const URLProtocol ff_concat_protocol = { > .name = "concat", > .url_open = concat_open, > @@ -197,3 +203,108 @@ const URLProtocol ff_concat_protocol = { > .priv_data_size = sizeof(struct concat_data), > .default_whitelist = "concat,file,subfile", > }; > +#endif > + > +#if CONFIG_CONCATF_PROTOCOL > +static av_cold int concatf_open(URLContext *h, const char *uri, int flags) > +{ > + AVBPrint bp; > + struct concat_data *data = h->priv_data; > + struct concat_nodes *nodes = NULL; > + AVIOContext *in = NULL; > + URLContext *uc; > + char *node_uri = NULL; > + int64_t size, total_size = 0; > + unsigned int nodes_size = 0; > + size_t i = 0; > + int err = 0; > + > + if (!av_strstart(uri, "concatf:", &uri)) { > + av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri); > + return AVERROR(EINVAL); > + } > + > + /* handle input */ > + if (!*uri) > + return AVERROR(ENOENT); > + > + err = ffio_open_whitelist(&in, uri, AVIO_FLAG_READ, &h->interrupt_callback, > + NULL, h->protocol_whitelist, h->protocol_blacklist); > + if (err < 0) > + return err; > + > + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); > + > + for (i = 0; !avio_feof(in); i++) { > + uint8_t *cursor; > + size_t len = i; > + > + if ((err = ff_read_line_to_bprint_overwrite(in, &bp)) <= 0) { Are we ok that file with a \n in their name will not be supported? > + if (err == 0 && i == 0) > + err = AVERROR_INVALIDDATA; > + else if (err == AVERROR_EOF) > + err = 0; > + break; > + } > + > + cursor = bp.str; > + node_uri = av_get_token((const char **)&cursor, "\t\r\n"); Does this protocol work with file names that contain an apostrophe or an actual backslash? > + if (!node_uri) { > + err = AVERROR(ENOMEM); > + break; > + } > + > + if (++len == SIZE_MAX / sizeof(*nodes)) { > + av_freep(&node_uri); > + err = AVERROR(ENAMETOOLONG); > + break; > + } > + > + /* creating URLContext */ > + err = ffurl_open_whitelist(&uc, node_uri, flags, > + &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h); > + av_freep(&node_uri); > + if (err < 0) > + break; > + > + /* creating size */ > + if ((size = ffurl_size(uc)) < 0) { > + ffurl_close(uc); > + err = AVERROR(ENOSYS); > + break; > + } > + > + nodes = av_fast_realloc(data->nodes, &nodes_size, sizeof(*nodes) * len); > + if (!nodes) { > + ffurl_close(uc); > + err = AVERROR(ENOMEM); > + break; > + } > + data->nodes = nodes; > + > + /* assembling */ > + data->nodes[i].uc = uc; > + data->nodes[i].size = size; > + total_size += size; > + } > + avio_closep(&in); > + av_bprint_finalize(&bp, NULL); > + data->length = i; > + > + if (err < 0) > + concat_close(h); > + > + data->total_size = total_size; > + return err; > +} > + > +const URLProtocol ff_concatf_protocol = { > + .name = "concatf", > + .url_open = concatf_open, > + .url_read = concat_read, > + .url_seek = concat_seek, > + .url_close = concat_close, > + .priv_data_size = sizeof(struct concat_data), > + .default_whitelist = "concatf,concat,file,subfile", > +}; > +#endif > diff --git a/libavformat/protocols.c b/libavformat/protocols.c > index 4b6b1c8e98..7f08f151b6 100644 > --- a/libavformat/protocols.c > +++ b/libavformat/protocols.c > @@ -27,6 +27,7 @@ extern const URLProtocol ff_async_protocol; > extern const URLProtocol ff_bluray_protocol; > extern const URLProtocol ff_cache_protocol; > extern const URLProtocol ff_concat_protocol; > +extern const URLProtocol ff_concatf_protocol; > extern const URLProtocol ff_crypto_protocol; > extern const URLProtocol ff_data_protocol; > extern const URLProtocol ff_ffrtmpcrypt_protocol; Regards,
On 6/24/2021 11:59 AM, Nicolas George wrote: > James Almer (12021-06-23): >> Suggested-by: ffmpeg@fb.com >> Signed-off-by: James Almer <jamrial@gmail.com> >> --- >> doc/protocols.texi | 30 +++++++++++ >> libavformat/Makefile | 1 + >> libavformat/concat.c | 111 ++++++++++++++++++++++++++++++++++++++++ >> libavformat/protocols.c | 1 + >> 4 files changed, 143 insertions(+) >> >> diff --git a/doc/protocols.texi b/doc/protocols.texi >> index ccdfb6e439..2b8ce1b7d5 100644 >> --- a/doc/protocols.texi >> +++ b/doc/protocols.texi >> @@ -215,6 +215,36 @@ ffplay concat:split1.mpeg\|split2.mpeg\|split3.mpeg >> Note that you may need to escape the character "|" which is special for >> many shells. >> >> +@section concatf >> + >> +Physical concatenation protocol using a line break delimited list of >> +resources. >> + >> +Read and seek from many resources in sequence as if they were >> +a unique resource. >> + >> +A URL accepted by this protocol has the syntax: >> +@example >> +concatf:@var{URL} >> +@end example >> + >> +where @var{URL} is the url containing a line break delimited list of >> +resources to be concatenated, each one possibly specifying a distinct >> +protocol. >> + >> +For example to read a sequence of files @file{split1.mpeg}, >> +@file{split2.mpeg}, @file{split3.mpeg} listed in separate lines within >> +a file @file{split.txt} with @command{ffplay} use the command: >> +@example >> +ffplay concatf:split.txt >> +@end example >> +Where @file{split.txt} contains the lines: >> +@example >> +split1.mpeg >> +split2.mpeg >> +split3.mpeg >> +@end example >> + >> @section crypto >> >> AES-encrypted stream reading protocol. >> diff --git a/libavformat/Makefile b/libavformat/Makefile >> index c9ef564523..caca95802a 100644 >> --- a/libavformat/Makefile >> +++ b/libavformat/Makefile >> @@ -616,6 +616,7 @@ OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o >> OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o >> OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o >> OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o >> +OBJS-$(CONFIG_CONCATF_PROTOCOL) += concat.o >> OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o >> OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o >> OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o >> diff --git a/libavformat/concat.c b/libavformat/concat.c >> index 278afd997d..d224b51db0 100644 >> --- a/libavformat/concat.c >> +++ b/libavformat/concat.c >> @@ -22,9 +22,12 @@ >> */ >> >> #include "libavutil/avstring.h" >> +#include "libavutil/bprint.h" >> #include "libavutil/mem.h" >> >> #include "avformat.h" >> +#include "avio_internal.h" >> +#include "internal.h" >> #include "url.h" >> >> #define AV_CAT_SEPARATOR "|" >> @@ -56,6 +59,7 @@ static av_cold int concat_close(URLContext *h) >> return err < 0 ? -1 : 0; >> } >> >> +#if CONFIG_CONCAT_PROTOCOL >> static av_cold int concat_open(URLContext *h, const char *uri, int flags) >> { >> char *node_uri = NULL; >> @@ -124,6 +128,7 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) >> data->total_size = total_size; >> return err; >> } >> +#endif >> >> static int concat_read(URLContext *h, unsigned char *buf, int size) >> { >> @@ -188,6 +193,7 @@ static int64_t concat_seek(URLContext *h, int64_t pos, int whence) >> return result; >> } >> >> +#if CONFIG_CONCAT_PROTOCOL >> const URLProtocol ff_concat_protocol = { >> .name = "concat", >> .url_open = concat_open, >> @@ -197,3 +203,108 @@ const URLProtocol ff_concat_protocol = { >> .priv_data_size = sizeof(struct concat_data), >> .default_whitelist = "concat,file,subfile", >> }; >> +#endif >> + >> +#if CONFIG_CONCATF_PROTOCOL >> +static av_cold int concatf_open(URLContext *h, const char *uri, int flags) >> +{ >> + AVBPrint bp; >> + struct concat_data *data = h->priv_data; >> + struct concat_nodes *nodes = NULL; >> + AVIOContext *in = NULL; >> + URLContext *uc; >> + char *node_uri = NULL; >> + int64_t size, total_size = 0; >> + unsigned int nodes_size = 0; >> + size_t i = 0; >> + int err = 0; >> + >> + if (!av_strstart(uri, "concatf:", &uri)) { >> + av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri); >> + return AVERROR(EINVAL); >> + } >> + >> + /* handle input */ >> + if (!*uri) >> + return AVERROR(ENOENT); >> + >> + err = ffio_open_whitelist(&in, uri, AVIO_FLAG_READ, &h->interrupt_callback, >> + NULL, h->protocol_whitelist, h->protocol_blacklist); >> + if (err < 0) >> + return err; >> + >> + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); >> + >> + for (i = 0; !avio_feof(in); i++) { >> + uint8_t *cursor; >> + size_t len = i; >> + > >> + if ((err = ff_read_line_to_bprint_overwrite(in, &bp)) <= 0) { > > Are we ok that file with a \n in their name will not be supported? Yes, since it's used to delimit files in the list. > >> + if (err == 0 && i == 0) >> + err = AVERROR_INVALIDDATA; >> + else if (err == AVERROR_EOF) >> + err = 0; >> + break; >> + } >> + >> + cursor = bp.str; > >> + node_uri = av_get_token((const char **)&cursor, "\t\r\n"); > > Does this protocol work with file names that contain an apostrophe or an > actual backslash? At least on Windows a backslash is not allowed on file names (Alongside many other such characters), but apostrophes are, and they effectively need to be escaped. Thanks for catching it. I'll add a mention in the doxy about the need to escape certain characters. > >> + if (!node_uri) { >> + err = AVERROR(ENOMEM); >> + break; >> + } >> + >> + if (++len == SIZE_MAX / sizeof(*nodes)) { >> + av_freep(&node_uri); >> + err = AVERROR(ENAMETOOLONG); >> + break; >> + } >> + >> + /* creating URLContext */ >> + err = ffurl_open_whitelist(&uc, node_uri, flags, >> + &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h); >> + av_freep(&node_uri); >> + if (err < 0) >> + break; >> + >> + /* creating size */ >> + if ((size = ffurl_size(uc)) < 0) { >> + ffurl_close(uc); >> + err = AVERROR(ENOSYS); >> + break; >> + } >> + >> + nodes = av_fast_realloc(data->nodes, &nodes_size, sizeof(*nodes) * len); >> + if (!nodes) { >> + ffurl_close(uc); >> + err = AVERROR(ENOMEM); >> + break; >> + } >> + data->nodes = nodes; >> + >> + /* assembling */ >> + data->nodes[i].uc = uc; >> + data->nodes[i].size = size; >> + total_size += size; >> + } >> + avio_closep(&in); >> + av_bprint_finalize(&bp, NULL); >> + data->length = i; >> + >> + if (err < 0) >> + concat_close(h); >> + >> + data->total_size = total_size; >> + return err; >> +} >> + >> +const URLProtocol ff_concatf_protocol = { >> + .name = "concatf", >> + .url_open = concatf_open, >> + .url_read = concat_read, >> + .url_seek = concat_seek, >> + .url_close = concat_close, >> + .priv_data_size = sizeof(struct concat_data), >> + .default_whitelist = "concatf,concat,file,subfile", >> +}; >> +#endif >> diff --git a/libavformat/protocols.c b/libavformat/protocols.c >> index 4b6b1c8e98..7f08f151b6 100644 >> --- a/libavformat/protocols.c >> +++ b/libavformat/protocols.c >> @@ -27,6 +27,7 @@ extern const URLProtocol ff_async_protocol; >> extern const URLProtocol ff_bluray_protocol; >> extern const URLProtocol ff_cache_protocol; >> extern const URLProtocol ff_concat_protocol; >> +extern const URLProtocol ff_concatf_protocol; >> extern const URLProtocol ff_crypto_protocol; >> extern const URLProtocol ff_data_protocol; >> extern const URLProtocol ff_ffrtmpcrypt_protocol; > > Regards, >
James Almer (12021-06-24): > > Are we ok that file with a \n in their name will not be supported? > Yes, since it's used to delimit files in the list. I know, it is the reason I asked. So, I say it negatively: I am not ok that this prevents valid filenames from being used, even if they are very exotic. > At least on Windows a backslash is not allowed on file names (Alongside many > other such characters), but apostrophes are, and they effectively need to be > escaped. Thanks for catching it. > > I'll add a mention in the doxy about the need to escape certain characters. On Unix, backslashes are allowed. So are newlines. They need to be supported. Regards,
On 6/24/2021 12:44 PM, Nicolas George wrote: > James Almer (12021-06-24): >>> Are we ok that file with a \n in their name will not be supported? >> Yes, since it's used to delimit files in the list. > > I know, it is the reason I asked. So, I say it negatively: > > I am not ok that this prevents valid filenames from being used, even if > they are very exotic. Can the \n in filenames be escaped, either with backslash or quotes, like with other special characters? If so, then they should be supported that way already. > >> At least on Windows a backslash is not allowed on file names (Alongside many >> other such characters), but apostrophes are, and they effectively need to be >> escaped. Thanks for catching it. >> >> I'll add a mention in the doxy about the need to escape certain characters. > > On Unix, backslashes are allowed. So are newlines. They need to be > supported. The former is supported, of course. And i assume so should the latter. > > Regards, > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
James Almer (12021-06-24): > Can the \n in filenames be escaped, either with backslash or quotes, like > with other special characters? If so, then they should be supported that way > already. Please test. Reading your code tells me it does not work as is, but it could. You are making a common mistake there: you are parsing the same thing twice differently, once with ff_read_line_to_bprint_overwrite() and once with av_get_token(). Regards,
On 6/24/2021 1:38 PM, Nicolas George wrote: > James Almer (12021-06-24): >> Can the \n in filenames be escaped, either with backslash or quotes, like >> with other special characters? If so, then they should be supported that way >> already. > > Please test. Reading your code tells me it does not work as is, but it > could. You are making a common mistake there: you are parsing the same > thing twice differently, once with ff_read_line_to_bprint_overwrite() > and once with av_get_token(). Can you tell me how to create a file with a \n in its name? I can test on Archlinux. Thanks. > > Regards, > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
James Almer (12021-06-24): > Can you tell me how to create a file with a \n in its name? I can test on > Archlinux. touch 'foo bar' With some shells, you can write: touch $'foo\nbar' Regards,
diff --git a/doc/protocols.texi b/doc/protocols.texi index ccdfb6e439..2b8ce1b7d5 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -215,6 +215,36 @@ ffplay concat:split1.mpeg\|split2.mpeg\|split3.mpeg Note that you may need to escape the character "|" which is special for many shells. +@section concatf + +Physical concatenation protocol using a line break delimited list of +resources. + +Read and seek from many resources in sequence as if they were +a unique resource. + +A URL accepted by this protocol has the syntax: +@example +concatf:@var{URL} +@end example + +where @var{URL} is the url containing a line break delimited list of +resources to be concatenated, each one possibly specifying a distinct +protocol. + +For example to read a sequence of files @file{split1.mpeg}, +@file{split2.mpeg}, @file{split3.mpeg} listed in separate lines within +a file @file{split.txt} with @command{ffplay} use the command: +@example +ffplay concatf:split.txt +@end example +Where @file{split.txt} contains the lines: +@example +split1.mpeg +split2.mpeg +split3.mpeg +@end example + @section crypto AES-encrypted stream reading protocol. diff --git a/libavformat/Makefile b/libavformat/Makefile index c9ef564523..caca95802a 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -616,6 +616,7 @@ OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o +OBJS-$(CONFIG_CONCATF_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o diff --git a/libavformat/concat.c b/libavformat/concat.c index 278afd997d..d224b51db0 100644 --- a/libavformat/concat.c +++ b/libavformat/concat.c @@ -22,9 +22,12 @@ */ #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/mem.h" #include "avformat.h" +#include "avio_internal.h" +#include "internal.h" #include "url.h" #define AV_CAT_SEPARATOR "|" @@ -56,6 +59,7 @@ static av_cold int concat_close(URLContext *h) return err < 0 ? -1 : 0; } +#if CONFIG_CONCAT_PROTOCOL static av_cold int concat_open(URLContext *h, const char *uri, int flags) { char *node_uri = NULL; @@ -124,6 +128,7 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) data->total_size = total_size; return err; } +#endif static int concat_read(URLContext *h, unsigned char *buf, int size) { @@ -188,6 +193,7 @@ static int64_t concat_seek(URLContext *h, int64_t pos, int whence) return result; } +#if CONFIG_CONCAT_PROTOCOL const URLProtocol ff_concat_protocol = { .name = "concat", .url_open = concat_open, @@ -197,3 +203,108 @@ const URLProtocol ff_concat_protocol = { .priv_data_size = sizeof(struct concat_data), .default_whitelist = "concat,file,subfile", }; +#endif + +#if CONFIG_CONCATF_PROTOCOL +static av_cold int concatf_open(URLContext *h, const char *uri, int flags) +{ + AVBPrint bp; + struct concat_data *data = h->priv_data; + struct concat_nodes *nodes = NULL; + AVIOContext *in = NULL; + URLContext *uc; + char *node_uri = NULL; + int64_t size, total_size = 0; + unsigned int nodes_size = 0; + size_t i = 0; + int err = 0; + + if (!av_strstart(uri, "concatf:", &uri)) { + av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri); + return AVERROR(EINVAL); + } + + /* handle input */ + if (!*uri) + return AVERROR(ENOENT); + + err = ffio_open_whitelist(&in, uri, AVIO_FLAG_READ, &h->interrupt_callback, + NULL, h->protocol_whitelist, h->protocol_blacklist); + if (err < 0) + return err; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + for (i = 0; !avio_feof(in); i++) { + uint8_t *cursor; + size_t len = i; + + if ((err = ff_read_line_to_bprint_overwrite(in, &bp)) <= 0) { + if (err == 0 && i == 0) + err = AVERROR_INVALIDDATA; + else if (err == AVERROR_EOF) + err = 0; + break; + } + + cursor = bp.str; + node_uri = av_get_token((const char **)&cursor, "\t\r\n"); + if (!node_uri) { + err = AVERROR(ENOMEM); + break; + } + + if (++len == SIZE_MAX / sizeof(*nodes)) { + av_freep(&node_uri); + err = AVERROR(ENAMETOOLONG); + break; + } + + /* creating URLContext */ + err = ffurl_open_whitelist(&uc, node_uri, flags, + &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h); + av_freep(&node_uri); + if (err < 0) + break; + + /* creating size */ + if ((size = ffurl_size(uc)) < 0) { + ffurl_close(uc); + err = AVERROR(ENOSYS); + break; + } + + nodes = av_fast_realloc(data->nodes, &nodes_size, sizeof(*nodes) * len); + if (!nodes) { + ffurl_close(uc); + err = AVERROR(ENOMEM); + break; + } + data->nodes = nodes; + + /* assembling */ + data->nodes[i].uc = uc; + data->nodes[i].size = size; + total_size += size; + } + avio_closep(&in); + av_bprint_finalize(&bp, NULL); + data->length = i; + + if (err < 0) + concat_close(h); + + data->total_size = total_size; + return err; +} + +const URLProtocol ff_concatf_protocol = { + .name = "concatf", + .url_open = concatf_open, + .url_read = concat_read, + .url_seek = concat_seek, + .url_close = concat_close, + .priv_data_size = sizeof(struct concat_data), + .default_whitelist = "concatf,concat,file,subfile", +}; +#endif diff --git a/libavformat/protocols.c b/libavformat/protocols.c index 4b6b1c8e98..7f08f151b6 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -27,6 +27,7 @@ extern const URLProtocol ff_async_protocol; extern const URLProtocol ff_bluray_protocol; extern const URLProtocol ff_cache_protocol; extern const URLProtocol ff_concat_protocol; +extern const URLProtocol ff_concatf_protocol; extern const URLProtocol ff_crypto_protocol; extern const URLProtocol ff_data_protocol; extern const URLProtocol ff_ffrtmpcrypt_protocol;
Suggested-by: ffmpeg@fb.com Signed-off-by: James Almer <jamrial@gmail.com> --- doc/protocols.texi | 30 +++++++++++ libavformat/Makefile | 1 + libavformat/concat.c | 111 ++++++++++++++++++++++++++++++++++++++++ libavformat/protocols.c | 1 + 4 files changed, 143 insertions(+)