@@ -17,7 +17,60 @@ Index: ffmpeg-6.0.1/libavformat/hls.c
17
17
===================================================================
18
18
--- ffmpeg-6.0.1.orig/libavformat/hls.c
19
19
+++ 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,
21
74
is_http = 1;
22
75
} else if (av_strstart(proto_name, "data", NULL)) {
23
76
;
@@ -26,11 +79,70 @@ Index: ffmpeg-6.0.1/libavformat/hls.c
26
79
} else
27
80
return AVERROR_INVALIDDATA;
28
81
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
30
142
===================================================================
31
143
--- /dev/null
32
144
+++ ffmpeg-6.0.1/libavformat/jsfetch.c
33
- @@ -0,0 +1,188 @@
145
+ @@ -0,0 +1,197 @@
34
146
+ /*
35
147
+ * JavaScript fetch metaprotocol for ffmpeg client
36
148
+ * Copyright (c) 2023 Yahweasel and contributors
@@ -70,7 +182,6 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
70
182
+ static const AVOption options[] = {
71
183
+ { NULL }
72
184
+ };
73
- +
74
185
+ #if CONFIG_JSFETCH_PROTOCOL
75
186
+ static const AVClass jsfetch_context_class = {
76
187
+ .class_name = "jsfetch",
@@ -82,14 +193,20 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
82
193
+ /**
83
194
+ * Open a fetch connection (JavaScript side).
84
195
+ */
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 ), {
86
197
+ return Asyncify.handleAsync(function() {
87
198
+ return Promise.all([]).then(function() {
88
199
+ 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 });
93
210
+ }).then(function(response) {
94
211
+ if (!Module.libavjsJSFetch)
95
212
+ Module.libavjsJSFetch = {ctr: 1, fetches: {}};
@@ -124,7 +241,11 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
124
241
+ {
125
242
+ JSFetchContext *ctx = h->priv_data;
126
243
+ 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);
128
249
+ return (ctx->idx > 0) ? 0 : ctx->idx;
129
250
+ }
130
251
+
@@ -216,7 +337,7 @@ Index: ffmpeg-6.0.1/libavformat/jsfetch.c
216
337
+ .priv_data_size = sizeof(JSFetchContext),
217
338
+ .priv_data_class = &jsfetch_context_class,
218
339
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
219
- + .default_whitelist = "jsfetch,http,https"
340
+ + .default_whitelist = "jsfetch,http,https,crypto "
220
341
+ };
221
342
+ #endif
222
343
Index: ffmpeg-6.0.1/libavformat/protocols.c
0 commit comments