diff --git a/configs/all/ffmpeg-config.txt b/configs/all/ffmpeg-config.txt index e15149ab..136b3ce1 100644 --- a/configs/all/ffmpeg-config.txt +++ b/configs/all/ffmpeg-config.txt @@ -93,6 +93,8 @@ --enable-decoder=qtrle --enable-encoder=qtrle --enable-protocol=jsfetch +--enable-demuxer=hls +--enable-muxer=hls --enable-libopenh264 --enable-decoder=libopenh264 --enable-encoder=libopenh264 diff --git a/configs/mkconfigs.js b/configs/mkconfigs.js index dacde2af..1df8f19b 100755 --- a/configs/mkconfigs.js +++ b/configs/mkconfigs.js @@ -41,6 +41,7 @@ const configs = [ ["prores", ["format-mp4", "format-webm", "swscale", "codec-prores"]], ["qtrle", ["format-mov", "swscale", "codec-qtrle"]], ["jsfetch", ["protocol-jsfetch"]], + ["hls", ["format-hls"]], // Patent and/or license encumbered encoders ["mediarecorder-openh264", ["format-ogg", "format-webm", "codec-libopus", "format-mp4", "codec-aac", "format-flac", "codec-flac", "swscale", "libvpx", "codec-libvpx_vp8", "decoder-h264", "codec-libopenh264"]], diff --git a/docs/API.md b/docs/API.md index 3fcd3741..f279e744 100644 --- a/docs/API.md +++ b/docs/API.md @@ -33,8 +33,8 @@ Initializes a muxer all at once, opening the file and initializing the format context. You can provide the format as a libav numerical code (`oformat`) or as a name (`format_name`), the filename to write to (which can of course be a device) (`filename`), and/or create it as a writer device automatically -(`device`). You have the option not to open the file (`open=false`), in which -case you will need to provide your own `pb`. +(`device`). You have the option not to open the file (`open=false`, the +default), in which case you will need to provide your own `pb`. For the streams to mux, each stream is in the form `[number, number, number]`, consisting of the codec context, `time_base_num`, and `time_base_den`, diff --git a/docs/IO.md b/docs/IO.md index 20d5b6b2..b6379dd0 100644 --- a/docs/IO.md +++ b/docs/IO.md @@ -10,7 +10,8 @@ JavaScript's `fetch` function to stream data over HTTP or HTTPS. This is not currently enabled by default in any build (other than "all"), but using an experimental build with `jsfetch` enabled, simply use, e.g., the URL `jsfetch:https://example.com/video.mkv` to use fetch. `jsfetch` does not -currently support seeking or writing, only reading in a stream. +currently support seeking or writing, only reading in a stream. If you enable +the HLS demuxer, `jsfetch` supports reading from HLS streams as well. ## Reading diff --git a/mk/ffmpeg.mk b/mk/ffmpeg.mk index 36ef5cfa..a41f888e 100644 --- a/mk/ffmpeg.mk +++ b/mk/ffmpeg.mk @@ -114,8 +114,9 @@ build/ffmpeg-$(FFMPEG_VERSION)/PATCHED: build/ffmpeg-$(FFMPEG_VERSION)/configure cd build/ffmpeg-$(FFMPEG_VERSION) ; ( test -e PATCHED || patch -p1 -i ../../patches/ffmpeg.diff ) touch $@ -build/ffmpeg-$(FFMPEG_VERSION)/libavformat/jsfetch.c: build/ffmpeg-$(FFMPEG_VERSION)/configure - cp patches/jsfetch.c $@ +build/ffmpeg-$(FFMPEG_VERSION)/libavformat/jsfetch.c: patches/jsfetch.c \ + build/ffmpeg-$(FFMPEG_VERSION)/configure + cp $< $@ touch $@ build/ffmpeg-$(FFMPEG_VERSION)/configure: build/ffmpeg-$(FFMPEG_VERSION).tar.xz diff --git a/mk/ffmpeg.mk.m4 b/mk/ffmpeg.mk.m4 index 4a6a28a2..a8f1a692 100644 --- a/mk/ffmpeg.mk.m4 +++ b/mk/ffmpeg.mk.m4 @@ -60,8 +60,9 @@ build/ffmpeg-$(FFMPEG_VERSION)/PATCHED: build/ffmpeg-$(FFMPEG_VERSION)/configure cd build/ffmpeg-$(FFMPEG_VERSION) ; ( test -e PATCHED || patch -p1 -i ../../patches/ffmpeg.diff ) touch $@ -build/ffmpeg-$(FFMPEG_VERSION)/libavformat/jsfetch.c: build/ffmpeg-$(FFMPEG_VERSION)/configure - cp patches/jsfetch.c $@ +build/ffmpeg-$(FFMPEG_VERSION)/libavformat/jsfetch.c: patches/jsfetch.c \ + build/ffmpeg-$(FFMPEG_VERSION)/configure + cp $< $@ touch $@ build/ffmpeg-$(FFMPEG_VERSION)/configure: build/ffmpeg-$(FFMPEG_VERSION).tar.xz diff --git a/patches/ffmpeg.diff b/patches/ffmpeg.diff index 6b62902a..692108aa 100644 --- a/patches/ffmpeg.diff +++ b/patches/ffmpeg.diff @@ -11962,6 +11962,19 @@ index cbdf48d..aeb3767 100644 if (ret == 0 && c->follow) return AVERROR(EAGAIN); if (ret == 0) +diff --git a/libavformat/hls.c b/libavformat/hls.c +index 8a96a37..ede65d6 100644 +--- a/libavformat/hls.c ++++ b/libavformat/hls.c +@@ -673,6 +673,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, + is_http = 1; + } else if (av_strstart(proto_name, "data", NULL)) { + ; ++ } else if (av_strstart(proto_name, "jsfetch", NULL)) { ++ ; + } else + return AVERROR_INVALIDDATA; + diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 3b19e0b..474d82d 100644 --- a/libavformat/oggdec.c diff --git a/patches/jsfetch.c b/patches/jsfetch.c index c4708f23..c5e9491c 100644 --- a/patches/jsfetch.c +++ b/patches/jsfetch.c @@ -99,8 +99,8 @@ static int jsfetch_open(URLContext *h, const char *url, int flags, AVDictionary * Read from a fetch connection (JavaScript side). */ EM_JS(int, jsfetch_read_js, (int idx, unsigned char *toBuf, int size), { + var jsfo = Module.libavjsJSFetch.fetches[idx]; return Asyncify.handleAsync(function() { return Promise.all([]).then(function() { - var jsfo = Module.libavjsJSFetch.fetches[idx]; if (jsfo.buf || jsfo.rej) { // Already have data var fromBuf = jsfo.buf; @@ -109,7 +109,7 @@ EM_JS(int, jsfetch_read_js, (int idx, unsigned char *toBuf, int size), { if (fromBuf) { if (fromBuf.done) { // EOF - return 0; + return -0x20464f45 /* AVERROR_EOF */; } if (fromBuf.value.length > size) { // Return some of the buffer @@ -138,9 +138,10 @@ EM_JS(int, jsfetch_read_js, (int idx, unsigned char *toBuf, int size), { } // The next data isn't available yet. Force them to wait. - return new Promise(function(res) { - setTimeout(function() { res(-6 /* EAGAIN */); }, 100); - }); + return Promise.race([ + jsfo.next, + new Promise(function(res) { setTimeout(res, 100); }) + ]).then(function() { return -6 /* EAGAIN */; }); }); }); }); @@ -182,6 +183,6 @@ const URLProtocol ff_jsfetch_protocol = { .priv_data_size = sizeof(JSFetchContext), .priv_data_class = &jsfetch_context_class, .flags = URL_PROTOCOL_FLAG_NETWORK, - .default_whitelist = "http,https" + .default_whitelist = "jsfetch,http,https" }; #endif