# HG changeset patch
# User Tracey Jaquith <tracey(a)archive.org>
# Date 1623797180 0
# Tue Jun 15 22:46:20 2021 +0000
# Node ID 1879d49fe0cf739f48287b5a38a83d3a1adab939
# Parent 5f765427c17ac8cf753967387562201cf4f78dc4
Add optional "mp4_exact_start" nginx config off/on to show video between keyframes.
archive.org has been using mod_h264_streaming with a similar "exact start" patch from me since 2013.
We just moved to nginx mp4 module and are using this patch.
The technique is to find the video keyframe just before the desired "start" time, and send
that down the wire so video playback can start immediately.
Next calculate how many video samples are between the keyframe and desired "start" time
and update the STTS atom where those samples move the duration from (typically) 1001 to 1.
This way, initial unwanted video frames play at ~1/30,000s -- so visually the
video & audio start playing immediately.
You can see an example before/after here (nginx binary built with mp4 module + patch):
https://pi.archive.org/0/items/CSPAN_20160425_022500_2011_White_House_Corre…https://pi.archive.org/0/items/CSPAN_20160425_022500_2011_White_House_Corre…
Tested on linux and macosx.
(this is me: https://github.com/traceypooh )
diff -r 5f765427c17a -r 1879d49fe0cf src/http/modules/ngx_http_mp4_module.c
--- a/src/http/modules/ngx_http_mp4_module.c Tue Jun 01 17:37:51 2021 +0300
+++ b/src/http/modules/ngx_http_mp4_module.c Tue Jun 15 22:46:20 2021 +0000
@@ -43,6 +43,7 @@
typedef struct {
size_t buffer_size;
size_t max_buffer_size;
+ ngx_flag_t exact_start;
} ngx_http_mp4_conf_t;
@@ -340,6 +341,13 @@
offsetof(ngx_http_mp4_conf_t, max_buffer_size),
NULL },
+ { ngx_string("mp4_exact_start"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_mp4_conf_t, exact_start),
+ NULL },
+
ngx_null_command
};
@@ -2156,6 +2164,83 @@
static ngx_int_t
+ngx_http_mp4_exact_start_video(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak)
+{
+ uint32_t n, speedup_samples, current_count;
+ ngx_uint_t sample_keyframe, start_sample_exact;
+ ngx_mp4_stts_entry_t *entry, *entries_array;
+ ngx_buf_t *data;
+
+ data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
+
+ // Find the keyframe just before the desired start time - so that we can emit an mp4
+ // where the first frame is a keyframe. We'll "speed up" the first frames to 1000x
+ // normal speed (typically), so they won't be noticed. But this way, perceptively,
+ // playback of the _video_ track can start immediately
+ // (and not have to wait until the keyframe _after_ the desired starting time frame).
+ start_sample_exact = trak->start_sample;
+ for (n = 0; n < trak->sync_samples_entries; n++) {
+ // each element of array is the sample number of a keyframe
+ // sync samples starts from 1 -- so subtract 1
+ sample_keyframe = ngx_mp4_get_32value(trak->stss_data_buf.pos + (n * 4)) - 1;
+ if (sample_keyframe <= trak->start_sample) {
+ start_sample_exact = sample_keyframe;
+ }
+ if (sample_keyframe >= trak->start_sample) {
+ break;
+ }
+ }
+
+ if (start_sample_exact < trak->start_sample) {
+ // We're going to prepend an entry with duration=1 for the frames we want to "not see".
+ // MOST of the time (eg: constant video framerate),
+ // we're taking a single element entry array and making it two.
+ speedup_samples = trak->start_sample - start_sample_exact;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "exact trak start_sample move %l to %l (speed up %d samples)\n",
+ trak->start_sample, start_sample_exact, speedup_samples);
+
+ entries_array = ngx_palloc(mp4->request->pool,
+ (1 + trak->time_to_sample_entries) * sizeof(ngx_mp4_stts_entry_t));
+ if (entries_array == NULL) {
+ return NGX_ERROR;
+ }
+ entry = &(entries_array[1]);
+ ngx_memcpy(entry, (ngx_mp4_stts_entry_t *)data->pos,
+ trak->time_to_sample_entries * sizeof(ngx_mp4_stts_entry_t));
+
+ current_count = ngx_mp4_get_32value(entry->count);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "exact split in 2 video STTS entry from count:%d", current_count);
+
+ if (current_count <= speedup_samples) {
+ return NGX_ERROR;
+ }
+
+ ngx_mp4_set_32value(entry->count, current_count - speedup_samples);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "exact split new[1]: count:%d duration:%d",
+ ngx_mp4_get_32value(entry->count),
+ ngx_mp4_get_32value(entry->duration));
+ entry--;
+ ngx_mp4_set_32value(entry->count, speedup_samples);
+ ngx_mp4_set_32value(entry->duration, 1);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "exact split new[0]: count:%d duration:1",
+ ngx_mp4_get_32value(entry->count));
+
+ data->pos = (u_char *) entry;
+ trak->time_to_sample_entries++;
+ trak->start_sample = start_sample_exact;
+ data->last = (u_char *) (entry + trak->time_to_sample_entries);
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak, ngx_uint_t start)
{
@@ -2164,6 +2249,8 @@
ngx_buf_t *data;
ngx_uint_t start_sample, entries, start_sec;
ngx_mp4_stts_entry_t *entry, *end;
+ ngx_http_mp4_conf_t *conf;
+
if (start) {
start_sec = mp4->start;
@@ -2238,6 +2325,10 @@
"start_sample:%ui, new count:%uD",
trak->start_sample, count - rest);
+ conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
+ if (conf->exact_start) {
+ ngx_http_mp4_exact_start_video(mp4, trak);
+ }
} else {
ngx_mp4_set_32value(entry->count, rest);
data->last = (u_char *) (entry + 1);
@@ -3590,6 +3681,7 @@
conf->buffer_size = NGX_CONF_UNSET_SIZE;
conf->max_buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->exact_start = NGX_CONF_UNSET;
return conf;
}
Hi,
I am trying to run the test suite, but it seems that, no matter how I build
Nginx, it systematically fails.
It seems that, most (all?) of the time, tests fail because Nginx returns
403 error codes, e.g.:
./ssi_waited.t ............................. 1/3
# Failed test 'waited non-active'
# at ./ssi_waited.t line 60.
# 'HTTP/1.1 403 Forbidden
# Server: nginx/1.21.0
# Date: Sat, 03 Jul 2021 08:06:00 GMT
# Content-Type: text/html
# Connection: close
#
# <html>
# <head><title>403 Forbidden</title></head>
# <body>
# <center><h1>403 Forbidden</h1></center>
# <hr><center>nginx/1.21.0</center>
# </body>
# </html>
# '
# doesn't match '(?^m:^xFIRSTxWAITEDxSECONDx$)'
The runtime configuration is the default one from nginx-1.20.1.tar.gz
(conf/nginx.conf).
I must be doing something wrong with the build or run time configuration,
but I cannot pinpoint what. Any idea?
Best,
Hugo
--
Hugo Lefeuvre (hle) | www.owl.eu.com
RSA4096_ 360B 03B3 BF27 4F4D 7A3F D5E8 14AA 1EB8 A247 3DFD
ed25519_ 37B2 6D38 0B25 B8A2 6B9F 3A65 A36F 5357 5F2D DC4C
Hi, Alex.
With your patch and this configuration:
image_filter resize 10000000 -; (something wider than input image)
image_filter convert webp;
no conversion occurs but return headers contain content-type: image/webp
I expect that when specifying the conversion filter it will apply anyway.
Most likely there is a shortcut somewhere in the algorithm, where after the
condition code goes directly to the output, but I could not find it.
# HG changeset patch
# User Alexey Radkov <alexey.radkov(a)gmail.com>
# Date 1629395487 -10800
# Thu Aug 19 20:51:27 2021 +0300
# Node ID a1065b2252855730ed8e5368c88fe41a7ff5a698
# Parent 13d0c1d26d47c203b1874ca1ffdb7a9ba7fd2d77
Avoid unnecessary restriction on nohash http variables.
When I use variables with long names albeit being tagged as
NGX_HTTP_VARIABLE_NOHASH, Nginx says "could not build variables_hash,
you should increase variables_hash_bucket_size: 64". It seems that this is
an unnecessary restriction, as soon as the hash gets only built for variables
with names[n].key.data == NULL (note that other pieces in ngx_hash_init()
where the macro NGX_HASH_ELT_SIZE is used, are always guarded with this
condition). This fix puts this same condition into the only unguarded piece:
when testing against the hash_bucket_size.
The issue arises after assignment of key[n].key.data = NULL without symmetric
assignment of key[n].key.len in ngx_http_variables_init_vars(): after this,
the key[n].key comes to an inconsistent state. Perhaps this was made
intentionally, as hash initialization in other places seems to follow the
same pattern (for instance, see how ngx_hash_init() gets called from
ngx_http_upstream_hide_headers_hash()).
Without this fix, I must put in the config "variables_hash_bucket_size 128;"
even if the long-named variables are nohash.
diff -r 13d0c1d26d47 -r a1065b225285 src/core/ngx_hash.c
--- a/src/core/ngx_hash.c Fri Aug 13 03:57:47 2021 -0400
+++ b/src/core/ngx_hash.c Thu Aug 19 20:51:27 2021 +0300
@@ -274,6 +274,9 @@
}
for (n = 0; n < nelts; n++) {
+ if (names[n].key.data == NULL) {
+ continue;
+ }
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
{
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
Hello!
This patch series add kernel TLS / SSL_sendfile() support.
Works on FreeBSD 13.0+ and Linux with kernel 4.13+ (at least 5.2
is recommended, tested with 5.11).
The following questions need additional testing/attention:
- What about EINTR? Looks like it simply results in SSL_ERROR_WANT_WRITE,
so might need extra checking to make sure there will be another write
event.
- What about SSL_sendfile(), early data and write blocking?
Ref. c->ssl->write_blocked, 7431:294162223c7c by pluknet@.
Looks like it is not a problem with SSL_sendfile(), but needs
further checking.
- What about FreeBSD aio sendfile (aka SF_NODISKIO)? Might be
easy enough to support.
Review and testing appreciated.
--
Maxim Dounin
Hello!
On Tue, Sep 18, 2018 at 08:12:20AM -0400, Thomas Ward wrote:
> Downstream in Ubuntu, it has been proposed to demote pcre3 and
> use pcre2 instead as it is newer.
> https://trac.nginx.org/nginx/ticket/720 shows it was marked 4
> years ago that NGINX does not support pcre2. Are there any
> plans to use pcre2 instead of pcre3?
There are no immediate plans.
When we last checked, there were no problems with PCRE, but PCRE2
wasn't available in most distributions we support, making the
switch mostly meaningless.
Also, it looks like PCRE2 is still not supported even by Exim,
which is the parent project of PCRE and PCRE2:
https://bugs.exim.org/show_bug.cgi?id=1878
As such, adding PCRE2 support to nginx looks premature.
--
Maxim Dounin
http://mdounin.ru/