Skip to content

Commit d5ecbb0

Browse files
committed
Fixes for crypto, byte ranges, and wrapping jsfetch urls
1 parent d07b9f8 commit d5ecbb0

File tree

6 files changed

+189
-15
lines changed

6 files changed

+189
-15
lines changed

bindings.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,9 @@ int libavjs_with_cli() {
492492
}
493493

494494
#ifndef LIBAVJS_WITH_CLI
495+
static int ffmpeg_get_total_size_bytes() { return 0; }
496+
static int ffmpeg_get_out_time_ms() { return 0; }
497+
static void ffmpeg_interrupt() { }
495498
int ffmpeg_main() { return 0; }
496499
int ffprobe_main() { return 0; }
497500
#endif

configs/configs/h264-aac-mp3/ffmpeg-config.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
--enable-protocol=data --enable-protocol=file
1+
--enable-protocol=data --enable-protocol=file --enable-protocol=jsfetch --enable-protocol=crypto
22
--enable-filter=aresample
33
--enable-filter=asetnsamples
44
--enable-muxer=mp4
55
--enable-muxer=matroska
66
--enable-demuxer=matroska
77
--enable-demuxer=aac
8+
--enable-demuxer=hls
9+
--enable-muxer=hls
810
--enable-parser=aac
911
--enable-decoder=aac
12+
--enable-decoder=h264
1013
--enable-parser=h264
1114
--enable-bsf=h264_metadata
1215
--enable-bsf=extract_extradata

funcs.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@
126126
["libavjs_create_main_thread", "number", []],
127127

128128
["ffmpeg_main", "number", ["number", "number"], {"async": true}],
129-
["ffprobe_main", "number", ["number", "number"], {"async": true}]
129+
["ffprobe_main", "number", ["number", "number"], {"async": true}],
130+
["ffmpeg_interrupt", null, [], {"async": true}],
131+
["ffmpeg_get_out_time_ms", "number", [], {"async": true}],
132+
["ffmpeg_get_total_size_bytes", "number", [], {"async": true}]
130133
],
131134

132135
"fs": [

patches/ffmpeg/07-jsfetch-protocol.diff

Lines changed: 132 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,60 @@ Index: ffmpeg-6.0.1/libavformat/hls.c
1717
===================================================================
1818
--- ffmpeg-6.0.1.orig/libavformat/hls.c
1919
+++ ffmpeg-6.0.1/libavformat/hls.c
20-
@@ -673,6 +673,8 @@ static int open_url(AVFormatContext *s,
20+
--- a/libavformat/hls.c
21+
+++ b/libavformat/hls.c
22+
@@ -311,6 +311,34 @@ static void free_rendition_list(HLSContext *c)
23+
c->n_renditions = 0;
24+
}
25+
26+
+static int jsfetch_wrap_url(const char *url, char **out_url)
27+
+{
28+
+ char *url_fixed = NULL;
29+
+
30+
+ if (av_strstart(url, "http://", NULL) || av_strstart(url, "https://", NULL)) {
31+
+ url_fixed = av_malloc(strlen("jsfetch:") + strlen(url) + 1);
32+
+ if (!url_fixed)
33+
+ return AVERROR(ENOMEM);
34+
+ strcpy(url_fixed, "jsfetch:");
35+
+ strcat(url_fixed, url);
36+
+ } else if (av_strstart(url, "crypto+http://", NULL) || av_strstart(url, "crypto+https://", NULL)) {
37+
+ const char *url_tail = url + strlen("crypto+");
38+
+ url_fixed = av_malloc(strlen("crypto+jsfetch:") + strlen(url_tail) + 1);
39+
+ if (!url_fixed)
40+
+ return AVERROR(ENOMEM);
41+
+ strcpy(url_fixed, "crypto+jsfetch:");
42+
+ strcat(url_fixed, url_tail);
43+
+ } else {
44+
+ // No transformation needed; just duplicate original URL
45+
+ url_fixed = av_strdup(url);
46+
+ if (!url_fixed)
47+
+ return AVERROR(ENOMEM);
48+
+ }
49+
+
50+
+ *out_url = url_fixed;
51+
+ return 0;
52+
+}
53+
+
54+
static struct playlist *new_playlist(HLSContext *c, const char *url,
55+
const char *base)
56+
{
57+
@@ -438,7 +466,14 @@ static struct segment *new_init_section(struct playlist *pls,
58+
return NULL;
59+
}
60+
}
61+
- sec->url = av_strdup(ptr);
62+
+ char *wrapped_url = NULL;
63+
+ int ret = jsfetch_wrap_url(ptr, &wrapped_url);
64+
+ if (ret < 0) {
65+
+ sec->url = av_strdup(ptr);
66+
+ fprintf(stderr, "Failed to wrap URL: %s\n", av_err2str(ret));
67+
+ } else {
68+
+ sec->url = av_strdup(wrapped_url);
69+
+ }
70+
if (!sec->url) {
71+
av_free(sec);
72+
return NULL;
73+
@@ -680,6 +715,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
2174
is_http = 1;
2275
} else if (av_strstart(proto_name, "data", NULL)) {
2376
;
@@ -26,11 +79,70 @@ Index: ffmpeg-6.0.1/libavformat/hls.c
2679
} else
2780
return AVERROR_INVALIDDATA;
2881

29-
Index: ffmpeg-6.0.1/libavformat/jsfetch.c
82+
@@ -981,7 +1018,14 @@ static int parse_playlist(HLSContext *c, const char *url,
83+
av_free(seg);
84+
goto fail;
85+
}
86+
- seg->url = av_strdup(tmp_str);
87+
+ char *wrapped_url = NULL;
88+
+ int ret = jsfetch_wrap_url(tmp_str, &wrapped_url);
89+
+ if (ret < 0) {
90+
+ seg->url = av_strdup(tmp_str);
91+
+ fprintf(stderr, "Failed to wrap URL: %s\n", av_err2str(ret));
92+
+ } else {
93+
+ seg->url = av_strdup(wrapped_url);
94+
+ }
95+
if (!seg->url) {
96+
av_free(seg->key);
97+
av_free(seg);
98+
@@ -1292,8 +1336,17 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
99+
if (seg->size >= 0) {
100+
/* try to restrict the HTTP request to the part we want
101+
* (if this is in fact a HTTP request) */
102+
- av_dict_set_int(&opts, "offset", seg->url_offset, 0);
103+
- av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
104+
+ // av_dict_set_int(&opts, "offset", seg->url_offset, 0);
105+
+ // av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
106+
+
107+
+ char range_header[128] = {0};
108+
+ if (seg->url_offset >= 0 && seg->size > 0) {
109+
+ snprintf(range_header, sizeof(range_header), "bytes=%" PRId64 "-%" PRId64, seg->url_offset, seg->url_offset + seg->size - 1);
110+
+ av_dict_set(&opts, "range_header", range_header, 0);
111+
+ } else if (seg->url_offset >= 0) {
112+
+ snprintf(range_header, sizeof(range_header), "bytes=%" PRId64 "-", seg->url_offset);
113+
+ av_dict_set(&opts, "range_header", range_header, 0);
114+
+ }
115+
}
116+
117+
av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n",
118+
@@ -1348,14 +1401,14 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
119+
* as would be expected. Wrong offset received from the server will not be
120+
* noticed without the call, though.
121+
*/
122+
- if (ret == 0 && !is_http && seg->url_offset) {
123+
- int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET);
124+
- if (seekret < 0) {
125+
- av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url);
126+
- ret = seekret;
127+
- ff_format_io_close(pls->parent, in);
128+
- }
129+
- }
130+
+ // if (ret == 0 && !is_http && seg->url_offset) {
131+
+ // int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET);
132+
+ // if (seekret < 0) {
133+
+ // av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url);
134+
+ // ret = seekret;
135+
+ // ff_format_io_close(pls->parent, in);
136+
+ // }
137+
+ // }
138+
139+
cleanup:
140+
av_dict_free(&opts);
141+
Index: ffmpeg-6.0.1/libavformat/jsfetch.c
30142
===================================================================
31143
--- /dev/null
32144
+++ ffmpeg-6.0.1/libavformat/jsfetch.c
33-
@@ -0,0 +1,188 @@
145+
@@ -0,0 +1,197 @@
34146
+/*
35147
+ * JavaScript fetch metaprotocol for ffmpeg client
36148
+ * Copyright (c) 2023 Yahweasel and contributors
@@ -70,7 +182,6 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
70182
+static const AVOption options[] = {
71183
+ { NULL }
72184
+};
73-
+
74185
+#if CONFIG_JSFETCH_PROTOCOL
75186
+static const AVClass jsfetch_context_class = {
76187
+ .class_name = "jsfetch",
@@ -82,14 +193,20 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
82193
+/**
83194
+ * Open a fetch connection (JavaScript side).
84195
+ */
85-
+EM_JS(int, jsfetch_open_js, (const char *url), {
196+
+EM_JS(int, jsfetch_open_js, (const char *url, char* range_header, bool has_range), {
86197
+ return Asyncify.handleAsync(function() {
87198
+ return Promise.all([]).then(function() {
88199
+ url = UTF8ToString(url);
89-
+ if (url.slice(0, 8) === "jsfetch:")
90-
+ return fetch(url.slice(8));
91-
+ else
92-
+ return fetch(url);
200+
+ var headers = {};
201+
+ if (has_range) {
202+
+ var range = range_header ? UTF8ToString(range_header) : undefined;
203+
+ console.log("range:");
204+
+ console.log(range);
205+
+
206+
+ headers.Range = range;
207+
+ }
208+
+ var fetchUrl = url.startsWith("jsfetch:") ? url.slice(8) : url;
209+
+ return fetch(fetchUrl, { headers });
93210
+ }).then(function(response) {
94211
+ if (!Module.libavjsJSFetch)
95212
+ Module.libavjsJSFetch = {ctr: 1, fetches: {}};
@@ -124,7 +241,11 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
124241
+{
125242
+ JSFetchContext *ctx = h->priv_data;
126243
+ h->is_streamed = 1;
127-
+ ctx->idx = jsfetch_open_js(url);
244+
+
245+
+ AVDictionaryEntry *entry = av_dict_get(*options, "range_header", NULL, 0);
246+
+ const char *range_ptr = entry ? entry->value : NULL;
247+
+ bool has_range = range_ptr != NULL;
248+
+ ctx->idx = jsfetch_open_js(url, range_ptr, has_range);
128249
+ return (ctx->idx > 0) ? 0 : ctx->idx;
129250
+}
130251
+
@@ -216,7 +337,7 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
216337
+ .priv_data_size = sizeof(JSFetchContext),
217338
+ .priv_data_class = &jsfetch_context_class,
218339
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
219-
+ .default_whitelist = "jsfetch,http,https"
340+
+ .default_whitelist = "jsfetch,http,https,crypto"
220341
+};
221342
+#endif
222343
Index: ffmpeg-6.0.1/libavformat/protocols.c

patches/ffmpeg/08-fftools.diff

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,54 @@ Index: ffmpeg-7.1/fftools/ffmpeg.c
3232
}
3333
av_freep(&vstats_filename);
3434
of_enc_stats_close();
35-
@@ -943,7 +950,12 @@ static int64_t getmaxrss(void)
35+
@@ -544,6 +551,19 @@ void update_benchmark(const char *fmt, ...)
36+
current_time = t;
37+
}
38+
}
39+
+static volatile int curr_transcode_pts_ms = 0;
40+
+int ffmpeg_get_out_time_ms(void);
41+
+int ffmpeg_get_out_time_ms()
42+
+{
43+
+ return curr_transcode_pts_ms;
44+
+}
45+
+
46+
+static volatile int curr_total_size_bytes = 0;
47+
+int ffmpeg_get_total_size_bytes(void);
48+
+int ffmpeg_get_total_size_bytes()
49+
+{
50+
+ return curr_total_size_bytes;
51+
+}
52+
53+
static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time, int64_t pts)
54+
{
55+
@@ -645,6 +665,9 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
56+
57+
if (total_size < 0) av_bprintf(&buf_script, "total_size=N/A\n");
58+
else av_bprintf(&buf_script, "total_size=%"PRId64"\n", total_size);
59+
+ if (total_size > 0) {
60+
+ curr_total_size_bytes = total_size;
61+
+ }
62+
if (pts == AV_NOPTS_VALUE) {
63+
av_bprintf(&buf_script, "out_time_us=N/A\n");
64+
av_bprintf(&buf_script, "out_time_ms=N/A\n");
65+
@@ -654,6 +677,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
66+
av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts);
67+
av_bprintf(&buf_script, "out_time=%s%02"PRId64":%02d:%02d.%06d\n",
68+
hours_sign, hours, mins, secs, us);
69+
+ curr_transcode_pts_ms = (pts / 1000);
70+
}
71+
72+
if (nb_frames_dup || nb_frames_drop)
73+
@@ -943,7 +967,17 @@ static int64_t getmaxrss(void)
3674
#endif
3775
}
3876

3977
+#ifdef __EMSCRIPTEN__
78+
+void ffmpeg_interrupt(void);
79+
+void ffmpeg_interrupt() {
80+
+ received_nb_signals++;
81+
+}
82+
+
4083
+int ffmpeg_main(int argc, char **argv);
4184
+int ffmpeg_main(int argc, char **argv)
4285
+#else
@@ -45,7 +88,7 @@ Index: ffmpeg-7.1/fftools/ffmpeg.c
4588
{
4689
Scheduler *sch = NULL;
4790

48-
@@ -1009,8 +1021,12 @@ finish:
91+
@@ -1009,8 +1043,12 @@ finish:
4992
ret = 0;
5093

5194
ffmpeg_cleanup(ret);

post.in.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,3 +2805,4 @@ var ffmpeg = Module.ffmpeg = function() {
28052805
var ffprobe = Module.ffprobe = function() {
28062806
return runMain(ffprobe_main, "ffprobe", arguments);
28072807
};
2808+

0 commit comments

Comments
 (0)