mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-05-18 17:21:08 +02:00
Compare commits
147 commits
Author | SHA1 | Date | |
---|---|---|---|
Laura Hausmann | a5f44b6d54 | ||
Laura Hausmann | cfb277dea7 | ||
Laura Hausmann | d2d55348d6 | ||
3b7ada6677 | |||
22861b746d | |||
6e40dbe805 | |||
5f8a96f505 | |||
9102003adf | |||
ca9fd4a380 | |||
0668f512b6 | |||
e57666bcf4 | |||
Laura Hausmann | 2fee90d89f | ||
Laura Hausmann | e73d44f0fb | ||
9eefedac83 | |||
c4dcf60e63 | |||
e8ff79dfb9 | |||
8e344d7994 | |||
4d15e2c0f1 | |||
d4d762e917 | |||
5cb0be7f09 | |||
1688a23f0a | |||
a2895a03d9 | |||
649d220306 | |||
ca1f3eeaa2 | |||
a4a1343bb8 | |||
14221340d3 | |||
f7254ae5e8 | |||
fe35e3e98b | |||
cdbb1d4dc1 | |||
d743c36996 | |||
59c2454b23 | |||
6c4be06423 | |||
23ec4ce2d7 | |||
882ef5ca1e | |||
eee3c5eb15 | |||
a0a55be887 | |||
ce5a10a0d1 | |||
3bf7523267 | |||
b2049f3c39 | |||
a5ac72c274 | |||
00fd6cfa53 | |||
b4ee055393 | |||
e2a626ac04 | |||
7b7d30f36c | |||
e5b78f2de7 | |||
a65297410e | |||
669059f41b | |||
ff3536996c | |||
15cc5d0226 | |||
504b9ee29d | |||
23d67822b2 | |||
21db986d97 | |||
a01cc448ee | |||
a898a09d87 | |||
916f3f8374 | |||
1c3dc989ef | |||
d25c56fa69 | |||
e65f2d099b | |||
f31e27fbaf | |||
bb4190e248 | |||
542106e4de | |||
9121b34bdc | |||
ff86f5c3fd | |||
f23323a51a | |||
f8992e572f | |||
4975784d46 | |||
07912c5cd1 | |||
95d81573c9 | |||
bc81475b6b | |||
6b8155cf3b | |||
9c71ce6761 | |||
d86287fe3c | |||
ebe697b601 | |||
dc76eb2641 | |||
18b228a01d | |||
4bf6852a28 | |||
4809496d78 | |||
315e8aa497 | |||
dbcb7aa966 | |||
2fd45d4114 | |||
c47cb2370f | |||
a037181c59 | |||
7381b66e13 | |||
a88bc39141 | |||
998de2937a | |||
a2d65b4251 | |||
26d6107307 | |||
e38fcac9c9 | |||
e4799c633a | |||
7db5ef0ea5 | |||
a9e0056d5b | |||
1d5a20ea2b | |||
eca3fa3b04 | |||
2b0596051e | |||
77ba897d2f | |||
6d9a85e061 | |||
b4ecd58544 | |||
aee81e3c8f | |||
45a02da89e | |||
51396cdebb | |||
358806e915 | |||
14b56c4a5b | |||
0df743179d | |||
965523f397 | |||
fe122c1597 | |||
a48dadfbc1 | |||
341b07409d | |||
970da5673d | |||
570204bdeb | |||
8b97be9593 | |||
c3237ae747 | |||
62748fe56d | |||
1e6ae8d94d | |||
281d2226d9 | |||
89dd74e666 | |||
4f96ff087d | |||
16851c4512 | |||
28f75cb86d | |||
2a6b426247 | |||
d171a0a9b0 | |||
0d94bb2c84 | |||
0bd7d6b375 | |||
307c8d969a | |||
93e9377dc6 | |||
5376bd3432 | |||
98f700a090 | |||
0bfbd6b39f | |||
f15596b8d1 | |||
64c0529fde | |||
01825510f7 | |||
93cf3b69f1 | |||
bfaccfd738 | |||
7eb100a306 | |||
a3924dce67 | |||
66b3bcf096 | |||
65e24b3fee | |||
182566fe93 | |||
e8304c9852 | |||
7e68afde6f | |||
d13e665e56 | |||
2855a9ffc1 | |||
86cfd20b28 | |||
cfadbd7779 | |||
c11797815d | |||
6666d789b5 | |||
ede4b5f0f4 | |||
9f75cc2c6e |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
/.settings
|
||||
/.project
|
||||
/.cproject
|
||||
/.vscode
|
||||
|
|
29
README.md
29
README.md
|
@ -91,6 +91,12 @@ For building debug version of nginx add `--with-debug`
|
|||
|
||||
[Read more about debug log](https://github.com/arut/nginx-rtmp-module/wiki/Debug-log)
|
||||
|
||||
### Contributing and Branch Policy
|
||||
|
||||
The "dev" branch is the one where all contributions will be merged before reaching "master".
|
||||
If you plan to propose a patch, please commit into the "dev" branch or its own feature branch.
|
||||
Direct commit to "master" are not permitted.
|
||||
|
||||
### Windows limitations
|
||||
|
||||
Windows support is limited. These features are not supported
|
||||
|
@ -112,10 +118,8 @@ name - interpreted by each application
|
|||
|
||||
### Multi-worker live streaming
|
||||
|
||||
Module supports multi-worker live
|
||||
streaming through automatic stream pushing
|
||||
to nginx workers. This option is toggled with
|
||||
rtmp_auto_push directive.
|
||||
This NGINX-RTMP module does not support multi-worker live
|
||||
streaming. While this feature can be enabled through rtmp_auto_push on|off directive, it is ill advised because it is incompatible with NGINX versions starting 1.7.2 and up, there for it should not be used.
|
||||
|
||||
|
||||
### Example nginx.conf
|
||||
|
@ -153,7 +157,7 @@ rtmp_auto_push directive.
|
|||
application big {
|
||||
live on;
|
||||
|
||||
# On every pusblished stream run this command (ffmpeg)
|
||||
# On every published stream run this command (ffmpeg)
|
||||
# with substitutions: $app/${app}, $name/${name} for application & stream name.
|
||||
#
|
||||
# This ffmpeg call receives stream from this application &
|
||||
|
@ -330,18 +334,3 @@ rtmp_auto_push directive.
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Multi-worker streaming example
|
||||
|
||||
rtmp_auto_push on;
|
||||
|
||||
rtmp {
|
||||
server {
|
||||
listen 1935;
|
||||
|
||||
application mytv {
|
||||
live on;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
10
config
10
config
|
@ -14,11 +14,12 @@ RTMP_CORE_MODULES=" \
|
|||
ngx_rtmp_relay_module \
|
||||
ngx_rtmp_exec_module \
|
||||
ngx_rtmp_auto_push_module \
|
||||
ngx_rtmp_notify_module \
|
||||
ngx_rtmp_auto_push_index_module \
|
||||
ngx_rtmp_log_module \
|
||||
ngx_rtmp_limit_module \
|
||||
ngx_rtmp_hls_module \
|
||||
ngx_rtmp_dash_module \
|
||||
ngx_rtmp_notify_module \
|
||||
"
|
||||
RTMP_HTTP_MODULES=" \
|
||||
ngx_rtmp_stat_module \
|
||||
|
@ -67,7 +68,6 @@ RTMP_CORE_SRCS=" \
|
|||
$ngx_addon_dir/ngx_rtmp_bandwidth.c \
|
||||
$ngx_addon_dir/ngx_rtmp_exec_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_auto_push_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_notify_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_log_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_limit_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_bitop.c \
|
||||
|
@ -75,7 +75,9 @@ RTMP_CORE_SRCS=" \
|
|||
$ngx_addon_dir/hls/ngx_rtmp_hls_module.c \
|
||||
$ngx_addon_dir/dash/ngx_rtmp_dash_module.c \
|
||||
$ngx_addon_dir/hls/ngx_rtmp_mpegts.c \
|
||||
$ngx_addon_dir/hls/ngx_rtmp_mpegts_crc.c \
|
||||
$ngx_addon_dir/dash/ngx_rtmp_mp4.c \
|
||||
$ngx_addon_dir/ngx_rtmp_notify_module.c \
|
||||
"
|
||||
RTMP_HTTP_SRCS=" \
|
||||
$ngx_addon_dir/ngx_rtmp_stat_module.c \
|
||||
|
@ -88,7 +90,7 @@ if [ "$ngx_module_link" = "" ] ; then
|
|||
# Old nginx version
|
||||
ngx_module_link=NONE
|
||||
|
||||
CORE_MODULES="$CORE_MODULES $RTMP_CORE_MODULES"
|
||||
EVENT_MODULES="$EVENT_MODULES $RTMP_CORE_MODULES"
|
||||
HTTP_MODULES="$HTTP_MODULES $RTMP_HTTP_MODULES"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $RTMP_DEPS"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $RTMP_CORE_SRCS $RTMP_HTTP_SRCS"
|
||||
|
@ -99,7 +101,7 @@ if [ $ngx_module_link = DYNAMIC ] ; then
|
|||
ngx_module_srcs="$RTMP_CORE_SRCS $RTMP_HTTP_SRCS"
|
||||
. auto/module
|
||||
elif [ $ngx_module_link = ADDON ] ; then
|
||||
ngx_module_type=CORE
|
||||
ngx_module_type=EVENT
|
||||
ngx_module_name=$RTMP_CORE_MODULES
|
||||
ngx_module_srcs=$RTMP_CORE_SRCS
|
||||
. auto/module
|
||||
|
|
|
@ -20,13 +20,18 @@ static void * ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf);
|
|||
static char * ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static ngx_int_t ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s);
|
||||
static ngx_int_t ngx_rtmp_dash_ensure_directory(ngx_rtmp_session_t *s);
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_BUFSIZE (1024*1024)
|
||||
#define NGX_RTMP_DASH_MAX_MDAT (10*1024*1024)
|
||||
/* Big buffer for 8k (QHD) cameras */
|
||||
#ifndef NGX_RTMP_DASH_BUFSIZE
|
||||
#define NGX_RTMP_DASH_BUFSIZE (16*1024*1024)
|
||||
#endif
|
||||
#define NGX_RTMP_DASH_MAX_MDAT (16*1024*1024)
|
||||
#define NGX_RTMP_DASH_MAX_SAMPLES 1024
|
||||
#define NGX_RTMP_DASH_DIR_ACCESS 0744
|
||||
/* Allow access to www-data (web-server) and others too */
|
||||
#define NGX_RTMP_DASH_DIR_ACCESS 0755
|
||||
|
||||
#define NGX_RTMP_DASH_GMT_LENGTH sizeof("1970-09-28T12:00:00+06:00")
|
||||
|
||||
typedef struct {
|
||||
uint32_t timestamp;
|
||||
|
@ -79,11 +84,29 @@ typedef struct {
|
|||
} ngx_rtmp_dash_cleanup_t;
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF 1
|
||||
#define NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP 2
|
||||
#define NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD 3
|
||||
#define NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO 4
|
||||
|
||||
static ngx_conf_enum_t ngx_rtmp_dash_clock_compensation_type_slots[] = {
|
||||
{ ngx_string("off"), NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF },
|
||||
{ ngx_string("ntp"), NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP },
|
||||
{ ngx_string("http_head"), NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD },
|
||||
{ ngx_string("http_iso"), NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO },
|
||||
{ ngx_null_string, 0 }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t dash;
|
||||
ngx_msec_t fraglen;
|
||||
ngx_msec_t playlen;
|
||||
ngx_flag_t nested;
|
||||
ngx_uint_t clock_compensation; // Try to compensate clock drift
|
||||
// between client and server (on client side)
|
||||
ngx_str_t clock_helper_uri; // Use uri to static file on HTTP server
|
||||
// - same machine as RTMP/DASH)
|
||||
// - or NTP server address
|
||||
ngx_str_t path;
|
||||
ngx_uint_t winfrags;
|
||||
ngx_flag_t cleanup;
|
||||
|
@ -135,6 +158,20 @@ static ngx_command_t ngx_rtmp_dash_commands[] = {
|
|||
offsetof(ngx_rtmp_dash_app_conf_t, nested),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("dash_clock_compensation"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_enum_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_dash_app_conf_t, clock_compensation),
|
||||
&ngx_rtmp_dash_clock_compensation_type_slots },
|
||||
|
||||
{ ngx_string("dash_clock_helper_uri"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_dash_app_conf_t, clock_helper_uri),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
@ -213,6 +250,22 @@ ngx_rtmp_dash_rename_file(u_char *src, u_char *dst)
|
|||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_rtmp_dash_gcd(ngx_uint_t m, ngx_uint_t n)
|
||||
{
|
||||
/* greatest common divisor */
|
||||
|
||||
ngx_uint_t temp;
|
||||
|
||||
while (n) {
|
||||
temp=n;
|
||||
n=m % n;
|
||||
m=temp;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
||||
{
|
||||
|
@ -223,7 +276,11 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
struct tm tm;
|
||||
ngx_str_t noname, *name;
|
||||
ngx_uint_t i, frame_rate_num, frame_rate_denom;
|
||||
ngx_uint_t depth_msec;
|
||||
ngx_uint_t depth_msec, depth_sec;
|
||||
ngx_uint_t update_period, update_period_msec;
|
||||
ngx_uint_t buffer_time, buffer_time_msec;
|
||||
ngx_uint_t presentation_delay, presentation_delay_msec;
|
||||
ngx_uint_t gcd, par_x, par_y;
|
||||
ngx_rtmp_dash_ctx_t *ctx;
|
||||
ngx_rtmp_codec_ctx_t *codec_ctx;
|
||||
ngx_rtmp_dash_frag_t *f;
|
||||
|
@ -232,9 +289,9 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
ngx_rtmp_playlist_t v;
|
||||
|
||||
static u_char buffer[NGX_RTMP_DASH_BUFSIZE];
|
||||
static u_char start_time[sizeof("1970-09-28T12:00:00+06:00")];
|
||||
static u_char end_time[sizeof("1970-09-28T12:00:00+06:00")];
|
||||
static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.00S")];
|
||||
static u_char avaliable_time[NGX_RTMP_DASH_GMT_LENGTH];
|
||||
static u_char publish_time[NGX_RTMP_DASH_GMT_LENGTH];
|
||||
static u_char buffer_depth[sizeof("P00Y00M00DT00H00M00.000S")];
|
||||
static u_char frame_rate[(NGX_INT_T_LEN * 2) + 2];
|
||||
|
||||
dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module);
|
||||
|
@ -265,25 +322,29 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
" type=\"dynamic\"\n" \
|
||||
" xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n" \
|
||||
" availabilityStartTime=\"%s\"\n" \
|
||||
" availabilityEndTime=\"%s\"\n" \
|
||||
" minimumUpdatePeriod=\"PT%uiS\"\n" \
|
||||
" minBufferTime=\"PT%uiS\"\n" \
|
||||
" publishTime=\"%s\"\n" \
|
||||
" minimumUpdatePeriod=\"PT%ui.%03uiS\"\n" \
|
||||
" minBufferTime=\"PT%ui.%03uiS\"\n" \
|
||||
" timeShiftBufferDepth=\"%s\"\n" \
|
||||
" suggestedPresentationDelay=\"PT%uiS\"\n" \
|
||||
" suggestedPresentationDelay=\"PT%ui.%03uiS\"\n" \
|
||||
" profiles=\"urn:hbbtv:dash:profile:isoff-live:2012," \
|
||||
"urn:mpeg:dash:profile:isoff-live:2011\"\n" \
|
||||
" xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n" \
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n" \
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n"
|
||||
|
||||
#define NGX_RTMP_DASH_MANIFEST_PERIOD \
|
||||
" <Period start=\"PT0S\" id=\"dash\">\n"
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_MANIFEST_VIDEO \
|
||||
" <AdaptationSet\n" \
|
||||
" id=\"1\"\n" \
|
||||
" startWithSAP=\"1\"\n" \
|
||||
" segmentAlignment=\"true\"\n" \
|
||||
" maxWidth=\"%ui\"\n" \
|
||||
" maxHeight=\"%ui\"\n" \
|
||||
" maxFrameRate=\"%s\">\n" \
|
||||
" maxFrameRate=\"%s\"\n" \
|
||||
" par=\"%ui:%ui\">\n" \
|
||||
" <Representation\n" \
|
||||
" id=\"%V_H264\"\n" \
|
||||
" mimeType=\"video/mp4\"\n" \
|
||||
|
@ -292,7 +353,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
" height=\"%ui\"\n" \
|
||||
" frameRate=\"%s\"\n" \
|
||||
" sar=\"1:1\"\n" \
|
||||
" startWithSAP=\"1\"\n" \
|
||||
" bandwidth=\"%ui\">\n" \
|
||||
" <SegmentTemplate\n" \
|
||||
" presentationTimeOffset=\"0\"\n" \
|
||||
|
@ -316,6 +376,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
#define NGX_RTMP_DASH_MANIFEST_AUDIO \
|
||||
" <AdaptationSet\n" \
|
||||
" id=\"2\"\n" \
|
||||
" startWithSAP=\"1\"\n" \
|
||||
" segmentAlignment=\"true\">\n" \
|
||||
" <AudioChannelConfiguration\n" \
|
||||
" schemeIdUri=\"urn:mpeg:dash:" \
|
||||
|
@ -326,7 +387,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
" mimeType=\"audio/mp4\"\n" \
|
||||
" codecs=\"mp4a.%s\"\n" \
|
||||
" audioSamplingRate=\"%ui\"\n" \
|
||||
" startWithSAP=\"1\"\n" \
|
||||
" bandwidth=\"%ui\">\n" \
|
||||
" <SegmentTemplate\n" \
|
||||
" presentationTimeOffset=\"0\"\n" \
|
||||
|
@ -343,56 +403,101 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
" </AdaptationSet>\n"
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_PERIOD_FOOTER \
|
||||
" </Period>\n"
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_MANIFEST_CLOCK \
|
||||
" <UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:%s:2014\"\n" \
|
||||
" value=\"%V\" />\n"
|
||||
|
||||
|
||||
#define NGX_RTMP_DASH_MANIFEST_FOOTER \
|
||||
" </Period>\n" \
|
||||
"</MPD>\n"
|
||||
|
||||
ngx_libc_localtime(ctx->start_time.sec, &tm);
|
||||
|
||||
*ngx_sprintf(start_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1,
|
||||
tm.tm_mday, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec,
|
||||
ctx->start_time.gmtoff < 0 ? '-' : '+',
|
||||
ngx_abs(ctx->start_time.gmtoff / 60),
|
||||
ngx_abs(ctx->start_time.gmtoff % 60)) = 0;
|
||||
/**
|
||||
* Availability time must be equal stream start time
|
||||
* Cos segments time counting from it
|
||||
*/
|
||||
ngx_libc_gmtime(ctx->start_time.sec, &tm);
|
||||
*ngx_sprintf(avaliable_time, "%4d-%02d-%02dT%02d:%02d:%02dZ",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1,
|
||||
tm.tm_mday, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec
|
||||
) = 0;
|
||||
|
||||
ngx_libc_localtime(ctx->start_time.sec +
|
||||
(ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp +
|
||||
ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) /
|
||||
1000, &tm);
|
||||
/* Stream publish time */
|
||||
*ngx_sprintf(publish_time, "%s", avaliable_time) = 0;
|
||||
|
||||
*ngx_sprintf(end_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1,
|
||||
tm.tm_mday, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec,
|
||||
ctx->start_time.gmtoff < 0 ? '-' : '+',
|
||||
ngx_abs(ctx->start_time.gmtoff / 60),
|
||||
ngx_abs(ctx->start_time.gmtoff % 60)) = 0;
|
||||
|
||||
|
||||
depth_msec = (ngx_uint_t) (
|
||||
depth_sec = (ngx_uint_t) (
|
||||
ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp +
|
||||
ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration -
|
||||
ngx_rtmp_dash_get_frag(s, 0)->timestamp);
|
||||
|
||||
ngx_libc_gmtime((ngx_uint_t) (depth_msec / 1000), &tm);
|
||||
depth_msec = depth_sec % 1000;
|
||||
depth_sec -= depth_msec;
|
||||
depth_sec /= 1000;
|
||||
|
||||
*ngx_sprintf(buffer_depth, "P%dY%02dM%02dDT%dH%02dM%02d.%02dS",
|
||||
ngx_libc_gmtime(depth_sec, &tm);
|
||||
|
||||
*ngx_sprintf(buffer_depth, "P%dY%02dM%02dDT%dH%02dM%02d.%03dS",
|
||||
tm.tm_year - 70, tm.tm_mon,
|
||||
tm.tm_mday - 1, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec,
|
||||
(ngx_uint_t) ((depth_msec % 1000) / 10)) = 0;
|
||||
depth_msec) = 0;
|
||||
|
||||
last = buffer + sizeof(buffer);
|
||||
|
||||
/**
|
||||
* Calculate playlist minimal update period
|
||||
* This should be more than biggest segment duration
|
||||
* Cos segments rounded by keyframe/GOP.
|
||||
* And that time not always equals to fragment length.
|
||||
*/
|
||||
update_period = dacf->fraglen;
|
||||
|
||||
for (i = 0; i < ctx->nfrags; i++) {
|
||||
f = ngx_rtmp_dash_get_frag(s, i);
|
||||
if (f->duration > update_period) {
|
||||
update_period = f->duration;
|
||||
}
|
||||
}
|
||||
|
||||
// Reasonable delay for streaming
|
||||
presentation_delay = update_period * 2 + 1000;
|
||||
presentation_delay_msec = presentation_delay % 1000;
|
||||
presentation_delay -= presentation_delay_msec;
|
||||
presentation_delay /= 1000;
|
||||
|
||||
// Calculate msec part and seconds
|
||||
update_period_msec = update_period % 1000;
|
||||
update_period -= update_period_msec;
|
||||
update_period /= 1000;
|
||||
|
||||
// Buffer length by default fragment length
|
||||
buffer_time = dacf->fraglen;
|
||||
buffer_time_msec = buffer_time % 1000;
|
||||
buffer_time -= buffer_time_msec;
|
||||
buffer_time /= 1000;
|
||||
|
||||
// Fill DASH header
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER,
|
||||
start_time,
|
||||
end_time,
|
||||
(ngx_uint_t) (dacf->fraglen / 1000),
|
||||
(ngx_uint_t) (dacf->fraglen / 1000),
|
||||
// availabilityStartTime
|
||||
avaliable_time,
|
||||
// publishTime
|
||||
publish_time,
|
||||
// minimumUpdatePeriod
|
||||
update_period, update_period_msec,
|
||||
// minBufferTime
|
||||
buffer_time, buffer_time_msec,
|
||||
// timeShiftBufferDepth
|
||||
buffer_depth,
|
||||
(ngx_uint_t) (dacf->fraglen / 500));
|
||||
// suggestedPresentationDelay
|
||||
presentation_delay, presentation_delay_msec
|
||||
);
|
||||
|
||||
p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_PERIOD);
|
||||
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
|
||||
|
@ -426,10 +531,15 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
*ngx_sprintf(frame_rate, "%ui/%ui", frame_rate_num, frame_rate_denom) = 0;
|
||||
}
|
||||
|
||||
gcd = ngx_rtmp_dash_gcd(codec_ctx->width, codec_ctx->height);
|
||||
par_x = codec_ctx->width / gcd;
|
||||
par_y = codec_ctx->height / gcd;
|
||||
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_VIDEO,
|
||||
codec_ctx->width,
|
||||
codec_ctx->height,
|
||||
frame_rate,
|
||||
par_x, par_y,
|
||||
&ctx->name,
|
||||
codec_ctx->avc_profile,
|
||||
codec_ctx->avc_compat,
|
||||
|
@ -473,6 +583,34 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
|
|||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
}
|
||||
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_PERIOD_FOOTER);
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
|
||||
/* UTCTiming value */
|
||||
switch (dacf->clock_compensation) {
|
||||
case NGX_RTMP_DASH_CLOCK_COMPENSATION_NTP:
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_CLOCK,
|
||||
"ntp",
|
||||
&dacf->clock_helper_uri
|
||||
);
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
break;
|
||||
case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_HEAD:
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_CLOCK,
|
||||
"http-head",
|
||||
&dacf->clock_helper_uri
|
||||
);
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
break;
|
||||
case NGX_RTMP_DASH_CLOCK_COMPENSATION_HTTP_ISO:
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_CLOCK,
|
||||
"http-iso",
|
||||
&dacf->clock_helper_uri
|
||||
);
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_FOOTER);
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
|
||||
|
@ -773,6 +911,10 @@ ngx_rtmp_dash_open_fragments(ngx_rtmp_session_t *s)
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_rtmp_dash_ensure_directory(s) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_rtmp_dash_open_fragment(s, &ctx->video, ctx->id, 'v');
|
||||
|
||||
ngx_rtmp_dash_open_fragment(s, &ctx->audio, ctx->id, 'a');
|
||||
|
@ -1426,7 +1568,7 @@ ngx_rtmp_dash_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
|
|||
"dash: cleanup '%V' allowed, mpd missing '%s'",
|
||||
&name, mpd_path);
|
||||
|
||||
max_age = 0;
|
||||
max_age = playlen / 500;
|
||||
|
||||
} else if (name.len >= 4 && name.data[name.len - 4] == '.' &&
|
||||
name.data[name.len - 3] == 'm' &&
|
||||
|
@ -1482,16 +1624,24 @@ ngx_rtmp_dash_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#if (nginx_version >= 1011005)
|
||||
static ngx_msec_t
|
||||
#else
|
||||
static time_t
|
||||
#endif
|
||||
ngx_rtmp_dash_cleanup(void *data)
|
||||
{
|
||||
ngx_rtmp_dash_cleanup_t *cleanup = data;
|
||||
|
||||
ngx_rtmp_dash_cleanup_dir(&cleanup->path, cleanup->playlen);
|
||||
|
||||
// Next callback in half of playlist length time
|
||||
return cleanup->playlen / 2000;
|
||||
// Next callback in doubled playlist length time to make sure what all
|
||||
// players read all segments
|
||||
#if (nginx_version >= 1011005)
|
||||
return cleanup->playlen * 2;
|
||||
#else
|
||||
return cleanup->playlen / 500;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
|
@ -1515,6 +1665,7 @@ ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf)
|
|||
conf->playlen = NGX_CONF_UNSET_MSEC;
|
||||
conf->cleanup = NGX_CONF_UNSET;
|
||||
conf->nested = NGX_CONF_UNSET;
|
||||
conf->clock_compensation = NGX_CONF_UNSET;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
@ -1532,6 +1683,9 @@ ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_msec_value(conf->playlen, prev->playlen, 30000);
|
||||
ngx_conf_merge_value(conf->cleanup, prev->cleanup, 1);
|
||||
ngx_conf_merge_value(conf->nested, prev->nested, 0);
|
||||
ngx_conf_merge_uint_value(conf->clock_compensation, prev->clock_compensation,
|
||||
NGX_RTMP_DASH_CLOCK_COMPENSATION_OFF);
|
||||
ngx_conf_merge_str_value(conf->clock_helper_uri, prev->clock_helper_uri, "");
|
||||
|
||||
if (conf->fraglen) {
|
||||
conf->winfrags = conf->playlen / conf->fraglen;
|
||||
|
|
|
@ -22,3 +22,8 @@
|
|||
* Notify
|
||||
* [on_playlist](directives.md#on_playlist)
|
||||
* [notify_send_redirect](directives.md#notify_send_redirect)
|
||||
* Client Caching
|
||||
* [hls_allow_client_cache](directives.md#hls_allow_client_cache)
|
||||
* Dash MPD generation
|
||||
* [dash_clock_compensation](directives.md#dash_clock_compensation)
|
||||
* [dash_clock_helper_uri](directives.md#dash_clock_helper_uri)
|
||||
|
|
|
@ -35,6 +35,7 @@ Table of Contents
|
|||
* [exec_play](#exec_play)
|
||||
* [exec_play_done](#exec_play_done)
|
||||
* [exec_publish_done](#exec_publish_done)
|
||||
* [exec_record_started](#exec_record_started)
|
||||
* [exec_record_done](#exec_record_done)
|
||||
* [Live](#live)
|
||||
* [live](#live)
|
||||
|
@ -76,6 +77,7 @@ Table of Contents
|
|||
* [on_done](#on_done)
|
||||
* [on_play_done](#on_play_done)
|
||||
* [on_publish_done](#on_publish_done)
|
||||
* [on_record_started](#on_record_started)
|
||||
* [on_record_done](#on_record_done)
|
||||
* [on_update](#on_update)
|
||||
* [notify_update_timeout](#notify_update_timeout)
|
||||
|
@ -98,6 +100,7 @@ Table of Contents
|
|||
* [hls_fragment_slicing](#hls_fragment_slicing)
|
||||
* [hls_variant](#hls_variant)
|
||||
* [hls_type](#hls_type)
|
||||
* [hls_allow_client_cache](#hls_allow_client_cache)
|
||||
* [hls_keys](#hls_keys)
|
||||
* [hls_key_path](#hls_key_path)
|
||||
* [hls_key_url](#hls_key_url)
|
||||
|
@ -109,6 +112,8 @@ Table of Contents
|
|||
* [dash_playlist_length](#dash_playlist_length)
|
||||
* [dash_nested](#dash_nested)
|
||||
* [dash_cleanup](#dash_cleanup)
|
||||
* [dash_clock_compensation](#dash_clock_compensation)
|
||||
* [dash_clock_helper_uri](#dash_clock_helper_uri)
|
||||
* [Access log](#access-log)
|
||||
* [access_log](#access_log)
|
||||
* [log_format](#log_format)
|
||||
|
@ -476,6 +481,18 @@ Specifies external command with arguments to be executed on
|
|||
publish_done event. Return code is not analyzed. Substitution list
|
||||
is the same as for `exec_publish`.
|
||||
|
||||
#### exec_record_started
|
||||
Syntax: `exec_record_started command arg*`
|
||||
Context: rtmp, server, application, recorder
|
||||
|
||||
Specifies external command with arguments to be executed when
|
||||
recording is started.
|
||||
* `recorder` - recorder name
|
||||
* `path` - recorded file path (`/tmp/rec/mystream-1389499351.flv`)
|
||||
* `filename` - path with directory omitted (`mystream-1389499351.flv`)
|
||||
* `basename` - file name with extension omitted (`mystream-1389499351`)
|
||||
* `dirname` - directory path (`/tmp/rec`)
|
||||
|
||||
#### exec_record_done
|
||||
Syntax: `exec_record_done command arg*`
|
||||
Context: rtmp, server, application, recorder
|
||||
|
@ -1103,6 +1120,16 @@ Context: rtmp, server, application
|
|||
|
||||
Same behavior as `on_done` but only for publish end event.
|
||||
|
||||
#### on_record_started
|
||||
syntax: `on_record_started url`
|
||||
context: rtmp, server, application, recorder
|
||||
|
||||
Set record_started callback. In addition to common HTTP callback
|
||||
variables it receives the following values
|
||||
* recorder - recorder name in config or empty string for inline recorder
|
||||
* path - recording file path
|
||||
|
||||
|
||||
#### on_record_done
|
||||
syntax: `on_record_done url`
|
||||
context: rtmp, server, application, recorder
|
||||
|
@ -1415,6 +1442,19 @@ is enough for the whole event. Default is `live`;
|
|||
hls_type event;
|
||||
```
|
||||
|
||||
#### hls_allow_client_cache
|
||||
Syntax: `hls_allow_client_cache enabled|disabled`
|
||||
Context: rtmp, server, application
|
||||
|
||||
Enables (or disables) client cache with `#EXT-X-ALLOW-CACHE` playlist
|
||||
directive. Setting value to enabled allows supported clients to
|
||||
cache segments in a live DVR manner. Setting value to disabled explicitly
|
||||
tells supported clients to never cache segments.
|
||||
Unset by default (playlist directive will be absent).
|
||||
```sh
|
||||
hls_allow_client_cache enabled;
|
||||
```
|
||||
|
||||
#### hls_keys
|
||||
Syntax: `hls_keys on|off`
|
||||
Context: rtmp, server, application
|
||||
|
@ -1591,6 +1631,45 @@ Init fragments are deleted after stream manifest is deleted.
|
|||
dash_cleanup off;
|
||||
```
|
||||
|
||||
#### dash\_clock_compensation
|
||||
Syntax: `dash_clock_compensation off|ntp|http_head|http_iso`
|
||||
Context: rtmp, server, application
|
||||
Default: off
|
||||
|
||||
Toggles MPEG-DASH clock compentation element output into MPD.
|
||||
In this mode nginx provides `UTCTiming` element for MPEG-DASH manifest.
|
||||
Clock compensation provided by DASH-client if possible.
|
||||
- ntp - use NTP protocol
|
||||
- http_head - client must fetch header `Date` from URI (`dash_clock_helper_uri`)
|
||||
- http_iso - client must fetch date in ISO format from URI (`dash_clock_helper_uri`)
|
||||
|
||||
Standard section: 4.7.2. Service Provider Requirements and Guidelines
|
||||
|
||||
```sh
|
||||
dash\_clock_compensation off;
|
||||
```
|
||||
|
||||
#### dash\_clock_helper_uri
|
||||
Syntax: `dash_clock_helper_uri URI`
|
||||
Context: rtmp, server, application
|
||||
Default: none
|
||||
|
||||
URI helper resource for clock compensation for client.
|
||||
Clock compensation type:
|
||||
- ntp - address of NTP-server
|
||||
- http\_head - full HTTP uri
|
||||
- http\_iso - full HTTP uri
|
||||
|
||||
Standard section: 4.7.2. Service Provider Requirements and Guidelines
|
||||
|
||||
```sh
|
||||
dash\_clock\_helper_uri http://rtmp-server/static/time.txt;
|
||||
|
||||
_or_
|
||||
|
||||
dash\_clock\_helper_uri http://rtmp-server/lua/time-iso;
|
||||
```
|
||||
|
||||
## Access log
|
||||
|
||||
#### access_log
|
||||
|
|
|
@ -36,6 +36,7 @@ rtmp {
|
|||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Re-translate remote stream with HLS support
|
||||
```sh
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
# FAQ
|
||||
|
||||
####RTMP stream is not played normally in IE, stream stops after several seconds.
|
||||
#### RTMP stream is not played normally in IE, stream stops after several seconds.
|
||||
|
||||
Add this directive to fix the problem
|
||||
```sh
|
||||
wait_video on;
|
||||
```
|
||||
|
||||
####I use `pull` directive to get stream from remote location. That works for RTMP clients but does not work for HLS.
|
||||
#### I use `pull` directive to get stream from remote location. That works for RTMP clients but does not work for HLS.
|
||||
|
||||
Currently HLS clients do not trigger any events. You cannot pull or exec when HLS client connects to server. However you can use static directives `exec_static`, `pull ... static` to pull the stream always.
|
||||
|
||||
####Seek does not work with flv files recorded by the module.
|
||||
#### Seek does not work with flv files recorded by the module.
|
||||
|
||||
To make the files seekable add flv metadata with external software like yamdi, flvmeta or ffmpeg.
|
||||
```sh
|
||||
exec_record_done yamdi -i $path -o /var/videos/$basename;
|
||||
```
|
||||
|
||||
####Published stream is missing from stats page after some time and clients fail to connect
|
||||
#### Published stream is missing from stats page after some time and clients fail to connect
|
||||
|
||||
Check if you use multiple workers in nginx (`worker_processes`). In such case you have to enable:
|
||||
```sh
|
||||
|
|
|
@ -9,7 +9,7 @@ $ cd /usr/build
|
|||
|
||||
Download & unpack latest nginx-rtmp (you can also use http)
|
||||
```sh
|
||||
$ git clone git://github.com/arut/nginx-rtmp-module.git
|
||||
$ git clone git://github.com/sergey-dryabzhinsky/nginx-rtmp-module
|
||||
```
|
||||
|
||||
Download & unpack nginx (you can also use svn)
|
||||
|
|
|
@ -30,8 +30,12 @@ static ngx_int_t ngx_rtmp_hls_ensure_directory(ngx_rtmp_session_t *s,
|
|||
ngx_str_t *path);
|
||||
|
||||
|
||||
#define NGX_RTMP_HLS_BUFSIZE (1024*1024)
|
||||
#define NGX_RTMP_HLS_DIR_ACCESS 0744
|
||||
/* Big buffer for 8k (QHD) cameras */
|
||||
#ifndef NGX_RTMP_HLS_BUFSIZE
|
||||
#define NGX_RTMP_HLS_BUFSIZE (16*1024*1024)
|
||||
#endif
|
||||
/* Allow access to www-data (web-server) and others too */
|
||||
#define NGX_RTMP_HLS_DIR_ACCESS 0755
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
@ -39,8 +43,8 @@ typedef struct {
|
|||
uint64_t key_id;
|
||||
ngx_str_t *datetime;
|
||||
double duration;
|
||||
unsigned active:1;
|
||||
unsigned discont:1; /* before */
|
||||
u_char active; /* small int, 0/1 */
|
||||
u_char discont; /* small int, 0/1 */
|
||||
} ngx_rtmp_hls_frag_t;
|
||||
|
||||
|
||||
|
@ -51,7 +55,7 @@ typedef struct {
|
|||
|
||||
|
||||
typedef struct {
|
||||
unsigned opened:1;
|
||||
u_char opened; /* small int, 0/1 */
|
||||
|
||||
ngx_rtmp_mpegts_file_t file;
|
||||
|
||||
|
@ -110,6 +114,7 @@ typedef struct {
|
|||
ngx_msec_t max_audio_delay;
|
||||
size_t audio_buffer_size;
|
||||
ngx_flag_t cleanup;
|
||||
ngx_uint_t allow_client_cache;
|
||||
ngx_array_t *variant;
|
||||
ngx_str_t base_url;
|
||||
ngx_int_t granularity;
|
||||
|
@ -137,6 +142,9 @@ typedef struct {
|
|||
#define NGX_RTMP_HLS_TYPE_LIVE 1
|
||||
#define NGX_RTMP_HLS_TYPE_EVENT 2
|
||||
|
||||
#define NGX_RTMP_HLS_CACHE_DISABLED 1
|
||||
#define NGX_RTMP_HLS_CACHE_ENABLED 2
|
||||
|
||||
|
||||
static ngx_conf_enum_t ngx_rtmp_hls_naming_slots[] = {
|
||||
{ ngx_string("sequential"), NGX_RTMP_HLS_NAMING_SEQUENTIAL },
|
||||
|
@ -167,6 +175,11 @@ static ngx_conf_enum_t ngx_rtmp_hls_type_slots[] = {
|
|||
{ ngx_null_string, 0 }
|
||||
};
|
||||
|
||||
static ngx_conf_enum_t ngx_rtmp_hls_cache[] = {
|
||||
{ ngx_string("enabled"), NGX_RTMP_HLS_CACHE_ENABLED },
|
||||
{ ngx_string("disabled"), NGX_RTMP_HLS_CACHE_DISABLED },
|
||||
{ ngx_null_string, 0 }
|
||||
};
|
||||
|
||||
static ngx_command_t ngx_rtmp_hls_commands[] = {
|
||||
|
||||
|
@ -282,6 +295,13 @@ static ngx_command_t ngx_rtmp_hls_commands[] = {
|
|||
offsetof(ngx_rtmp_hls_app_conf_t, cleanup),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("hls_allow_client_cache"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_enum_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_hls_app_conf_t, allow_client_cache),
|
||||
&ngx_rtmp_hls_cache },
|
||||
|
||||
{ ngx_string("hls_variant"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_hls_variant,
|
||||
|
@ -457,7 +477,7 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s)
|
|||
p = buffer;
|
||||
last = buffer + sizeof(buffer);
|
||||
|
||||
p = ngx_slprintf(p, last, "#EXT-X-STREAM-INF:PROGRAM-ID=1");
|
||||
p = ngx_slprintf(p, last, "#EXT-X-STREAM-INF:PROGRAM-ID=1,CLOSED-CAPTIONS=NONE");
|
||||
|
||||
arg = var->args.elts;
|
||||
for (k = 0; k < var->args.nelts; k++, arg++) {
|
||||
|
@ -509,7 +529,7 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s)
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
||||
ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s, int final)
|
||||
{
|
||||
static u_char buffer[1024];
|
||||
ngx_fd_t fd;
|
||||
|
@ -518,7 +538,9 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
ssize_t n;
|
||||
ngx_rtmp_hls_app_conf_t *hacf;
|
||||
ngx_rtmp_hls_frag_t *f;
|
||||
ngx_uint_t i, max_frag;
|
||||
ngx_int_t i, start_i;
|
||||
ngx_uint_t max_frag;
|
||||
double fragments_length;
|
||||
ngx_str_t name_part, key_name_part;
|
||||
uint64_t prev_key_id;
|
||||
const char *sep, *key_sep;
|
||||
|
@ -543,7 +565,32 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
|
||||
max_frag = hacf->fraglen / 1000;
|
||||
|
||||
for (i = 0; i < ctx->nfrags; i++) {
|
||||
/**
|
||||
* Need to check fragments length sum and playlist max length
|
||||
* Do backward search
|
||||
*/
|
||||
start_i = 0;
|
||||
fragments_length = 0.;
|
||||
for (i = ctx->nfrags-1; i >= 0; i--) {
|
||||
f = ngx_rtmp_hls_get_frag(s, i);
|
||||
if (f->duration) {
|
||||
fragments_length += f->duration;
|
||||
}
|
||||
/**
|
||||
* Think that sum of frag length is more than playlist desired length - half minimal frag length
|
||||
* XXX: sometimes sum of frag lengths are almost playlist length
|
||||
* but key-frames come at random rate...
|
||||
*/
|
||||
if (fragments_length >= hacf->playlen/1000. - max_frag/2) {
|
||||
start_i = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"hls: found starting fragment=%i", start_i);
|
||||
|
||||
for (i = start_i; i < (ngx_int_t)ctx->nfrags; i++) {
|
||||
f = ngx_rtmp_hls_get_frag(s, i);
|
||||
if (f->duration > max_frag) {
|
||||
max_frag = (ngx_uint_t) (f->duration + .5);
|
||||
|
@ -558,12 +605,18 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
"#EXT-X-VERSION:3\n"
|
||||
"#EXT-X-MEDIA-SEQUENCE:%uL\n"
|
||||
"#EXT-X-TARGETDURATION:%ui\n",
|
||||
ctx->frag, max_frag);
|
||||
ctx->frag + start_i, max_frag);
|
||||
|
||||
if (hacf->type == NGX_RTMP_HLS_TYPE_EVENT) {
|
||||
p = ngx_slprintf(p, end, "#EXT-X-PLAYLIST-TYPE:EVENT\n");
|
||||
}
|
||||
|
||||
if (hacf->allow_client_cache == NGX_RTMP_HLS_CACHE_ENABLED) {
|
||||
p = ngx_slprintf(p, end, "#EXT-X-ALLOW-CACHE:YES\n");
|
||||
} else if (hacf->allow_client_cache == NGX_RTMP_HLS_CACHE_DISABLED) {
|
||||
p = ngx_slprintf(p, end, "#EXT-X-ALLOW-CACHE:NO\n");
|
||||
}
|
||||
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
if (n < 0) {
|
||||
goto write_err;
|
||||
|
@ -584,9 +637,9 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
|
||||
prev_key_id = 0;
|
||||
|
||||
for (i = 0; i < ctx->nfrags; i++) {
|
||||
for (i = start_i; i < (ngx_int_t)ctx->nfrags; i++) {
|
||||
f = ngx_rtmp_hls_get_frag(s, i);
|
||||
if (i == 0 && f->datetime && f->datetime->len > 0) {
|
||||
if ((i == start_i || f->discont) && f->datetime && f->datetime->len > 0) {
|
||||
p = ngx_snprintf(buffer, sizeof(buffer), "#EXT-X-PROGRAM-DATE-TIME:");
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
if (n < 0) {
|
||||
|
@ -626,7 +679,7 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"hls: fragment frag=%uL, n=%ui/%ui, duration=%.3f, "
|
||||
"discont=%i",
|
||||
ctx->frag, i + 1, ctx->nfrags, f->duration, f->discont);
|
||||
ctx->frag, i + 1, ctx->nfrags, f->duration, (ngx_int_t)f->discont);
|
||||
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
if (n < 0) {
|
||||
|
@ -634,6 +687,15 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
|
|||
}
|
||||
}
|
||||
|
||||
if (final)
|
||||
{
|
||||
p = ngx_slprintf(p, end, "#EXT-X-ENDLIST\n");
|
||||
n = ngx_write_fd(fd, buffer, p - buffer);
|
||||
if (n < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_close_file(fd);
|
||||
|
||||
if (ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data)
|
||||
|
@ -892,12 +954,13 @@ ngx_rtmp_hls_get_fragment_datetime(ngx_rtmp_session_t *s, uint64_t ts)
|
|||
msec += (ts / 90);
|
||||
ngx_gmtime(msec / 1000, &tm);
|
||||
|
||||
datetime->data = (u_char *) ngx_pcalloc(s->connection->pool, ngx_cached_http_log_iso8601.len * sizeof(u_char));
|
||||
(void) ngx_sprintf(datetime->data, "%4d-%02d-%02dT%02d:%02d:%02d-00:00",
|
||||
datetime->len = sizeof("1970-01-01T00:00:00.000-00:00") - 1;
|
||||
datetime->data = (u_char *) ngx_pcalloc(s->connection->pool, datetime->len * sizeof(u_char));
|
||||
(void) ngx_sprintf(datetime->data, "%4d-%02d-%02dT%02d:%02d:%02d.%03d-00:00",
|
||||
tm.ngx_tm_year, tm.ngx_tm_mon,
|
||||
tm.ngx_tm_mday, tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec);
|
||||
datetime->len = ngx_cached_http_log_iso8601.len;
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec,
|
||||
msec % 1000);
|
||||
return datetime;
|
||||
|
||||
case NGX_RTMP_HLS_DATETIME_SYSTEM:
|
||||
|
@ -913,7 +976,7 @@ ngx_rtmp_hls_get_fragment_datetime(ngx_rtmp_session_t *s, uint64_t ts)
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s)
|
||||
ngx_rtmp_hls_close_final_fragment(ngx_rtmp_session_t *s, int final)
|
||||
{
|
||||
ngx_rtmp_hls_ctx_t *ctx;
|
||||
|
||||
|
@ -931,12 +994,19 @@ ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s)
|
|||
|
||||
ngx_rtmp_hls_next_frag(s);
|
||||
|
||||
ngx_rtmp_hls_write_playlist(s);
|
||||
ngx_rtmp_hls_write_playlist(s, final);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s)
|
||||
{
|
||||
return ngx_rtmp_hls_close_final_fragment(s, 0);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts,
|
||||
ngx_int_t discont)
|
||||
|
@ -1028,7 +1098,7 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts,
|
|||
}
|
||||
|
||||
// This is continuity counter for TS header
|
||||
mpegts_cc = (ctx->nfrags + ctx->frag);
|
||||
mpegts_cc = (ngx_uint_t)(ctx->nfrags + ctx->frag);
|
||||
|
||||
ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"hls: open fragment file='%s', keyfile='%s', "
|
||||
|
@ -1049,7 +1119,7 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts,
|
|||
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
|
||||
|
||||
if (ngx_rtmp_mpegts_open_file(&ctx->file, ctx->stream.data,
|
||||
s->connection->log, &codec_ctx->audio_codec_id, mpegts_cc)
|
||||
s->connection->log, codec_ctx, mpegts_cc)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
|
@ -1397,7 +1467,7 @@ ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"hls: publish: name='%s' type='%s'",
|
||||
v->name, v->type);
|
||||
|
||||
|
@ -1597,7 +1667,7 @@ ngx_rtmp_hls_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v)
|
|||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"hls: close stream");
|
||||
|
||||
ngx_rtmp_hls_close_fragment(s);
|
||||
ngx_rtmp_hls_close_final_fragment(s, 1);
|
||||
|
||||
next:
|
||||
return next_close_stream(s, v);
|
||||
|
@ -2082,6 +2152,7 @@ ngx_rtmp_hls_video(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"hls: error appending AUD NAL");
|
||||
}
|
||||
/* fall through */
|
||||
case 9:
|
||||
aud_sent = 1;
|
||||
break;
|
||||
|
@ -2343,8 +2414,11 @@ ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#if (nginx_version >= 1011005)
|
||||
static ngx_msec_t
|
||||
#else
|
||||
static time_t
|
||||
#endif
|
||||
ngx_rtmp_hls_cleanup(void *data)
|
||||
{
|
||||
ngx_rtmp_hls_cleanup_t *cleanup = data;
|
||||
|
@ -2352,7 +2426,11 @@ ngx_rtmp_hls_cleanup(void *data)
|
|||
ngx_rtmp_hls_cleanup_dir(&cleanup->path, cleanup->playlen);
|
||||
|
||||
// Next callback in half of playlist length time
|
||||
#if (nginx_version >= 1011005)
|
||||
return cleanup->playlen / 2;
|
||||
#else
|
||||
return cleanup->playlen / 2000;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -2440,6 +2518,7 @@ ngx_rtmp_hls_create_app_conf(ngx_conf_t *cf)
|
|||
conf->max_audio_delay = NGX_CONF_UNSET_MSEC;
|
||||
conf->audio_buffer_size = NGX_CONF_UNSET_SIZE;
|
||||
conf->cleanup = NGX_CONF_UNSET;
|
||||
conf->allow_client_cache = NGX_CONF_UNSET_UINT;
|
||||
conf->granularity = NGX_CONF_UNSET;
|
||||
conf->keys = NGX_CONF_UNSET;
|
||||
conf->frags_per_key = NGX_CONF_UNSET_UINT;
|
||||
|
|
|
@ -7,24 +7,30 @@
|
|||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include "ngx_rtmp_mpegts.h"
|
||||
#include "ngx_rtmp_mpegts_crc.h"
|
||||
|
||||
#include "ngx_rtmp_codec_module.h"
|
||||
|
||||
static u_char ngx_rtmp_mpegts_header[] = {
|
||||
|
||||
/* https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet */
|
||||
/* https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet */
|
||||
|
||||
/* TS */
|
||||
/* TS Header */
|
||||
0x47, // Sync byte
|
||||
0x40, 0x00, // TEI(1) + PUS(1) + TP(1) + PID(13)
|
||||
0x10, // SC(2) + AFF(1) + PF(1) + CC(4)
|
||||
0x00,
|
||||
/* PSI */
|
||||
0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00,
|
||||
0x10, // TSC(2) + AFF(1) + PF(1) + CC(4)
|
||||
0x00, // adaption_field_length(8)
|
||||
|
||||
/* PAT */
|
||||
0x00, 0x01, 0xef, 0xff,
|
||||
/* CRC */
|
||||
0x36, 0x90, 0xe2, 0x3d,
|
||||
0x00, // table_id(8)
|
||||
0xb0, 0x0d, // 1011b(4) + section_length(12)
|
||||
0x00, 0x01, // transport_stream_id(16)
|
||||
0xc1, 0x00, 0x00, // 11b(2) + VN(5) + CNI(1), section_no(8), last_section_no(8)
|
||||
/* PAT program loop */
|
||||
0x00, 0x01, 0xef, 0xff, // program_number(16), reserved(3) + program_map_pid(13)
|
||||
/* PAT crc (CRC-32-MPEG2) */
|
||||
0x36, 0x90, 0xe2, 0x3d, // !!! Needs to be recalculated each time any bit in PAT is modified (which we dont do at the moment) !!!
|
||||
|
||||
/* stuffing 167 bytes */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
@ -44,19 +50,26 @@ static u_char ngx_rtmp_mpegts_header[] = {
|
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
/* TS */
|
||||
0x47,
|
||||
0x4f, 0xff,
|
||||
0x10,
|
||||
0x00,
|
||||
/* PSI */
|
||||
0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00,
|
||||
/* TS Header */
|
||||
0x47, // Sync byte
|
||||
0x4f, 0xff, // TEI(1) + PUS(1) + TP(1) + PID(13)
|
||||
0x10, // TSC(2) + AFF(1) + PF(1) + CC(4)
|
||||
0x00, // adaption_field_length(8)
|
||||
|
||||
/* PMT */
|
||||
0xe1, 0x00,
|
||||
0xf0, 0x00,
|
||||
0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, /* audio placeholder */
|
||||
0x00, 0x00, 0x00, 0x00, /* audio crc placeholder */
|
||||
0x02, // table_id(8)
|
||||
0xb0, 0x12, // 1011b(4) + section_length(12) (section length set below. Ignore this value in here)
|
||||
0x00, 0x01, // program_number(16)
|
||||
0xc1, 0x00, 0x00, // 11b(2) + VN(5) + CNI(1), section_no(8), last_section_no(8)
|
||||
0xe1, 0x00, // reserved(3) + PCR_PID(13)
|
||||
0xf0, 0x00, // reserved(4) + program_info_length(12)
|
||||
|
||||
/* PMT component loop, looped through when writing header */
|
||||
/* Max size of 14 bytes */
|
||||
/* Also includes the PMT CRC, calculated dynamically */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
/* stuffing 157 bytes */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
@ -77,18 +90,33 @@ static u_char ngx_rtmp_mpegts_header[] = {
|
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
static u_char ngx_rtmp_mpegts_header_h264[] = {
|
||||
//H.264 Video, PID 0x100
|
||||
0x1b, // stream_type(8)
|
||||
0xe1, 0x00, // reserved(3) + elementary_PID(13)
|
||||
0xf0, 0x00 // reserved(4) + ES_info_length(12)
|
||||
};
|
||||
|
||||
static u_char ngx_rtmp_mpegts_header_mp3[] = {
|
||||
0x03, 0xe1, 0x01, 0xf0, 0x00, /* mp3 */
|
||||
/* CRC */
|
||||
0x4e, 0x59, 0x3d, 0x1e, /* crc for mp3 */
|
||||
//MP3 Audio, PID 0x101
|
||||
0x03, // stream_type(8)
|
||||
0xe1, 0x01, // reserved(3) + elementary_PID(13)
|
||||
0xf0, 0x00 // reserved(4) + ES_info_length(12)
|
||||
};
|
||||
|
||||
static u_char ngx_rtmp_mpegts_header_aac[] = {
|
||||
0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac */
|
||||
/* CRC */
|
||||
0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */
|
||||
//ADTS AAC Audio, PID 0x101
|
||||
0x0f, // stream_type(8)
|
||||
0xe1, 0x01, // reserved(3) + elementary_PID(13)
|
||||
0xf0, 0x00 // reserved(4) + ES_info_length(12)
|
||||
};
|
||||
|
||||
#define NGX_RTMP_MPEGTS_PMT_CRC_START_OFFSET 193
|
||||
#define NGX_RTMP_MPEGTS_PMT_CRC_MIN_LENGTH 12
|
||||
#define NGX_RTMP_MPEGTS_PMT_SECTION_LENGTH_OFFSET 195
|
||||
#define NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET 205
|
||||
#define NGX_RTMP_MPEGTS_PID_SIZE 5
|
||||
|
||||
/* 700 ms PCR delay */
|
||||
#define NGX_RTMP_HLS_DELAY 63000
|
||||
|
||||
|
@ -173,27 +201,53 @@ ngx_rtmp_mpegts_write_file(ngx_rtmp_mpegts_file_t *file, u_char *in,
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file, ngx_uint_t *audio_codec_id, ngx_uint_t mpegts_cc)
|
||||
ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc)
|
||||
{
|
||||
ngx_int_t next_pid_offset = 0; //Used to track the number of PIDs we have and the offset in 5-byte chunks
|
||||
|
||||
if (*audio_codec_id == NGX_RTMP_AUDIO_AAC) {
|
||||
ngx_memcpy(ngx_rtmp_mpegts_header+210, ngx_rtmp_mpegts_header_aac,
|
||||
sizeof(ngx_rtmp_mpegts_header_aac));
|
||||
}
|
||||
//if (*audio_codec_id == NGX_RTMP_AUDIO_MP3) {
|
||||
else {
|
||||
ngx_memcpy(ngx_rtmp_mpegts_header+210, ngx_rtmp_mpegts_header_mp3,
|
||||
sizeof(ngx_rtmp_mpegts_header_mp3));
|
||||
}
|
||||
|
||||
// Truncate counter to 4 bits here
|
||||
//MPEG-TS CC is 4 bits long. Need to truncate it here.
|
||||
mpegts_cc %= 0x0f;
|
||||
// And fill headers
|
||||
// And then put it in the headers
|
||||
ngx_rtmp_mpegts_header[3] = (ngx_rtmp_mpegts_header[3] & 0xf0) + (u_char)mpegts_cc;
|
||||
ngx_rtmp_mpegts_header[191] = (ngx_rtmp_mpegts_header[191] & 0xf0) + (u_char)mpegts_cc;
|
||||
|
||||
return ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header,
|
||||
sizeof(ngx_rtmp_mpegts_header));
|
||||
//ngx_rtmp_mpegts_header
|
||||
|
||||
if (codec_ctx->video_codec_id)
|
||||
{
|
||||
//Put h264 PID in the PMT
|
||||
ngx_memcpy(ngx_rtmp_mpegts_header+NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset, ngx_rtmp_mpegts_header_h264, NGX_RTMP_MPEGTS_PID_SIZE);
|
||||
|
||||
next_pid_offset += NGX_RTMP_MPEGTS_PID_SIZE;
|
||||
}
|
||||
|
||||
if (codec_ctx->audio_codec_id){
|
||||
//Put Audio PID in the PMT
|
||||
if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) {
|
||||
ngx_memcpy(ngx_rtmp_mpegts_header+NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset, ngx_rtmp_mpegts_header_aac, NGX_RTMP_MPEGTS_PID_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ngx_memcpy(ngx_rtmp_mpegts_header+NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset, ngx_rtmp_mpegts_header_mp3, NGX_RTMP_MPEGTS_PID_SIZE);
|
||||
}
|
||||
next_pid_offset += NGX_RTMP_MPEGTS_PID_SIZE;
|
||||
}
|
||||
|
||||
//Set section length of PMT
|
||||
//PMT is 13 bytes long without any programs in it. Add this in
|
||||
ngx_rtmp_mpegts_header[NGX_RTMP_MPEGTS_PMT_SECTION_LENGTH_OFFSET] = 13 + next_pid_offset;
|
||||
|
||||
//Calculate CRC
|
||||
ngx_rtmp_mpegts_crc_t crc = ngx_rtmp_mpegts_crc_init();
|
||||
crc = ngx_rtmp_mpegts_crc_update(crc, ngx_rtmp_mpegts_header+NGX_RTMP_MPEGTS_PMT_CRC_START_OFFSET, NGX_RTMP_MPEGTS_PMT_CRC_MIN_LENGTH+next_pid_offset);
|
||||
crc = ngx_rtmp_mpegts_crc_finalize(crc);
|
||||
|
||||
ngx_rtmp_mpegts_header[NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset] = (crc >> 24) & 0xff;
|
||||
ngx_rtmp_mpegts_header[NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset+1] = (crc >> 16) & 0xff;
|
||||
ngx_rtmp_mpegts_header[NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset+2] = (crc >> 8) & 0xff;
|
||||
ngx_rtmp_mpegts_header[NGX_RTMP_MPEGTS_PMT_LOOP_OFFSET+next_pid_offset+3] = crc & 0xff;
|
||||
|
||||
return ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header, sizeof(ngx_rtmp_mpegts_header));
|
||||
}
|
||||
|
||||
|
||||
|
@ -383,7 +437,7 @@ ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file,
|
|||
|
||||
ngx_int_t
|
||||
ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path,
|
||||
ngx_log_t *log, ngx_uint_t *audio_codec_id, ngx_uint_t mpegts_cc)
|
||||
ngx_log_t *log, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc)
|
||||
{
|
||||
file->log = log;
|
||||
|
||||
|
@ -398,7 +452,7 @@ ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path,
|
|||
|
||||
file->size = 0;
|
||||
|
||||
if (ngx_rtmp_mpegts_write_header(file, audio_codec_id, mpegts_cc) != NGX_OK) {
|
||||
if (ngx_rtmp_mpegts_write_header(file, codec_ctx, mpegts_cc) != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_ERR, log, ngx_errno,
|
||||
"hls: error writing fragment header");
|
||||
ngx_close_file(file->fd);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <ngx_core.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#include <ngx_rtmp_codec_module.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_fd_t fd;
|
||||
|
@ -37,7 +39,7 @@ typedef struct {
|
|||
ngx_int_t ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file,
|
||||
u_char *key, size_t key_len, uint64_t iv);
|
||||
ngx_int_t ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path,
|
||||
ngx_log_t *log, ngx_uint_t *audio_codec_id, ngx_uint_t mpegts_cc);
|
||||
ngx_log_t *log, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc);
|
||||
ngx_int_t ngx_rtmp_mpegts_close_file(ngx_rtmp_mpegts_file_t *file);
|
||||
ngx_int_t ngx_rtmp_mpegts_write_frame(ngx_rtmp_mpegts_file_t *file,
|
||||
ngx_rtmp_mpegts_frame_t *f, ngx_buf_t *b);
|
||||
|
|
80
hls/ngx_rtmp_mpegts_crc.c
Normal file
80
hls/ngx_rtmp_mpegts_crc.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* \file crc.c
|
||||
* Functions and types for CRC checks.
|
||||
*
|
||||
* Generated on Thu May 5 15:32:31 2016,
|
||||
* by pycrc v0.9, https://pycrc.org
|
||||
* using the configuration:
|
||||
* Width = 32
|
||||
* Poly = 0x04c11db7
|
||||
* Xor_In = 0xffffffff
|
||||
* ReflectIn = False
|
||||
* Xor_Out = 0x00000000
|
||||
* ReflectOut = False
|
||||
* Algorithm = table-driven
|
||||
*****************************************************************************/
|
||||
#include "ngx_rtmp_mpegts_crc.h" /* include the header file generated with pycrc */
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Static table used for the table_driven implementation.
|
||||
*****************************************************************************/
|
||||
static const ngx_rtmp_mpegts_crc_t ngx_rtmp_mpegts_crc_table[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the crc value with new data.
|
||||
*
|
||||
* \param crc The current crc value.
|
||||
* \param data Pointer to a buffer of \a data_len bytes.
|
||||
* \param data_len Number of bytes in the \a data buffer.
|
||||
* \return The updated crc value.
|
||||
*****************************************************************************/
|
||||
ngx_rtmp_mpegts_crc_t ngx_rtmp_mpegts_crc_update(ngx_rtmp_mpegts_crc_t crc, const void *data, size_t data_len)
|
||||
{
|
||||
const unsigned char *d = (const unsigned char *)data;
|
||||
unsigned int tbl_idx;
|
||||
|
||||
while (data_len--) {
|
||||
tbl_idx = ((crc >> 24) ^ *d) & 0xff;
|
||||
crc = (ngx_rtmp_mpegts_crc_table[tbl_idx] ^ (crc << 8)) & 0xffffffff;
|
||||
|
||||
d++;
|
||||
}
|
||||
return crc & 0xffffffff;
|
||||
}
|
||||
|
||||
|
83
hls/ngx_rtmp_mpegts_crc.h
Normal file
83
hls/ngx_rtmp_mpegts_crc.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* \file crc.h
|
||||
* Functions and types for CRC checks.
|
||||
*
|
||||
* Generated on Thu May 5 15:32:22 2016,
|
||||
* by pycrc v0.9, https://pycrc.org
|
||||
* using the configuration:
|
||||
* Width = 32
|
||||
* Poly = 0x04c11db7
|
||||
* Xor_In = 0xffffffff
|
||||
* ReflectIn = False
|
||||
* Xor_Out = 0x00000000
|
||||
* ReflectOut = False
|
||||
* Algorithm = table-driven
|
||||
*****************************************************************************/
|
||||
#ifndef _NGX_RTMP_MPEGTS_CRC_H_INCLUDED_
|
||||
#define _NGX_RTMP_MPEGTS_CRC_H_INCLUDED_
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The definition of the used algorithm.
|
||||
*
|
||||
* This is not used anywhere in the generated code, but it may be used by the
|
||||
* application code to call algoritm-specific code, is desired.
|
||||
*****************************************************************************/
|
||||
#define CRC_ALGO_TABLE_DRIVEN 1
|
||||
|
||||
|
||||
/**
|
||||
* The type of the CRC values.
|
||||
*
|
||||
* This type must be big enough to contain at least 32 bits.
|
||||
*****************************************************************************/
|
||||
typedef uint_fast32_t ngx_rtmp_mpegts_crc_t;
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the initial crc value.
|
||||
*
|
||||
* \return The initial crc value.
|
||||
*****************************************************************************/
|
||||
static inline ngx_rtmp_mpegts_crc_t ngx_rtmp_mpegts_crc_init(void)
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the crc value with new data.
|
||||
*
|
||||
* \param crc The current crc value.
|
||||
* \param data Pointer to a buffer of \a data_len bytes.
|
||||
* \param data_len Number of bytes in the \a data buffer.
|
||||
* \return The updated crc value.
|
||||
*****************************************************************************/
|
||||
ngx_rtmp_mpegts_crc_t ngx_rtmp_mpegts_crc_update(ngx_rtmp_mpegts_crc_t crc, const void *data, size_t data_len);
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the final crc value.
|
||||
*
|
||||
* \param crc The current crc value.
|
||||
* \return The final crc value.
|
||||
*****************************************************************************/
|
||||
static inline ngx_rtmp_mpegts_crc_t ngx_rtmp_mpegts_crc_finalize(ngx_rtmp_mpegts_crc_t crc)
|
||||
{
|
||||
return crc ^ 0x00000000;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* closing brace for extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_RTMP_MPEGTS_CRC_H_INCLUDED_ */
|
41
ngx_rtmp.c
41
ngx_rtmp.c
|
@ -87,6 +87,7 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
ngx_uint_t i, m, mi, s;
|
||||
ngx_conf_t pcf;
|
||||
ngx_array_t ports;
|
||||
ngx_module_t **modules;
|
||||
ngx_rtmp_listen_t *listen;
|
||||
ngx_rtmp_module_t *module;
|
||||
ngx_rtmp_conf_ctx_t *ctx;
|
||||
|
@ -101,14 +102,18 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
*(ngx_rtmp_conf_ctx_t **) conf = ctx;
|
||||
|
||||
/* count the number of the rtmp modules and set up their indices */
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1009011
|
||||
modules = cf->cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
ngx_rtmp_max_module = 0;
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_modules[m]->ctx_index = ngx_rtmp_max_module++;
|
||||
modules[m]->ctx_index = ngx_rtmp_max_module++;
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,13 +153,13 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
* of the all rtmp modules
|
||||
*/
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[m]->ctx;
|
||||
mi = ngx_modules[m]->ctx_index;
|
||||
module = modules[m]->ctx;
|
||||
mi = modules[m]->ctx_index;
|
||||
|
||||
if (module->create_main_conf) {
|
||||
ctx->main_conf[mi] = module->create_main_conf(cf);
|
||||
|
@ -181,12 +186,12 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
pcf = *cf;
|
||||
cf->ctx = ctx;
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[m]->ctx;
|
||||
module = modules[m]->ctx;
|
||||
|
||||
if (module->preconfiguration) {
|
||||
if (module->preconfiguration(cf) != NGX_OK) {
|
||||
|
@ -212,13 +217,13 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
cmcf = ctx->main_conf[ngx_rtmp_core_module.ctx_index];
|
||||
cscfp = cmcf->servers.elts;
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[m]->ctx;
|
||||
mi = ngx_modules[m]->ctx_index;
|
||||
module = modules[m]->ctx;
|
||||
mi = modules[m]->ctx_index;
|
||||
|
||||
/* init rtmp{} main_conf's */
|
||||
|
||||
|
@ -283,12 +288,12 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[m]->ctx;
|
||||
module = modules[m]->ctx;
|
||||
|
||||
if (module->postconfiguration) {
|
||||
if (module->postconfiguration(cf) != NGX_OK) {
|
||||
|
|
|
@ -409,9 +409,9 @@ ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
if (!all) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* "all" passes through */
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
default: /* AF_INET */
|
||||
|
||||
|
|
|
@ -328,9 +328,10 @@ ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts,
|
|||
} else {
|
||||
switch (ngx_rtmp_amf_get(ctx, &type8, 1)) {
|
||||
case NGX_DONE:
|
||||
if (elts->type & NGX_RTMP_AMF_OPTIONAL) {
|
||||
if (elts && elts->type & NGX_RTMP_AMF_OPTIONAL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
/* fall through */
|
||||
case NGX_ERROR:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
@ -398,6 +399,7 @@ ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts,
|
|||
if (ngx_rtmp_amf_get(ctx, &max_index, 4) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case NGX_RTMP_AMF_OBJECT:
|
||||
if (ngx_rtmp_amf_read_object(ctx, data,
|
||||
|
@ -592,6 +594,7 @@ ngx_rtmp_amf_write(ngx_rtmp_amf_ctx_t *ctx,
|
|||
if (ngx_rtmp_amf_put(ctx, &max_index, 4) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case NGX_RTMP_AMF_OBJECT:
|
||||
type8 = NGX_RTMP_AMF_END;
|
||||
|
|
|
@ -93,6 +93,34 @@ ngx_module_t ngx_rtmp_auto_push_module = {
|
|||
};
|
||||
|
||||
|
||||
static ngx_rtmp_module_t ngx_rtmp_auto_push_index_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
NULL, /* create app configuration */
|
||||
NULL /* merge app configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_rtmp_auto_push_index_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_rtmp_auto_push_index_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_RTMP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
#define NGX_RTMP_AUTO_PUSH_SOCKNAME "nginx-rtmp"
|
||||
|
||||
|
||||
|
@ -324,7 +352,7 @@ ngx_rtmp_auto_push_reconnect(ngx_event_t *ev)
|
|||
|
||||
apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_rtmp_auto_push_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
@ -461,14 +489,14 @@ ngx_rtmp_auto_push_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module);
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_palloc(s->connection->pool,
|
||||
sizeof(ngx_rtmp_auto_push_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_auto_push_module);
|
||||
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_auto_push_index_module);
|
||||
|
||||
}
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
|
@ -508,7 +536,7 @@ ngx_rtmp_auto_push_delete_stream(ngx_rtmp_session_t *s,
|
|||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module);
|
||||
if (ctx) {
|
||||
if (ctx->push_evt.timer_set) {
|
||||
ngx_del_timer(&ctx->push_evt);
|
||||
|
@ -532,7 +560,7 @@ ngx_rtmp_auto_push_delete_stream(ngx_rtmp_session_t *s,
|
|||
slot, &rctx->app, &rctx->name);
|
||||
|
||||
pctx = ngx_rtmp_get_module_ctx(rctx->publish->session,
|
||||
ngx_rtmp_auto_push_module);
|
||||
ngx_rtmp_auto_push_index_module);
|
||||
if (pctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include "ngx_rtmp.h"
|
||||
|
||||
|
||||
#define NGX_RTMP_MAX_NAME 256
|
||||
#define NGX_RTMP_MAX_URL 256
|
||||
#define NGX_RTMP_MAX_NAME 2048
|
||||
#define NGX_RTMP_MAX_URL 4096
|
||||
#define NGX_RTMP_MAX_ARGS NGX_RTMP_MAX_NAME
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ typedef struct {
|
|||
double trans;
|
||||
u_char app[NGX_RTMP_MAX_NAME];
|
||||
u_char args[NGX_RTMP_MAX_ARGS];
|
||||
u_char flashver[32];
|
||||
u_char flashver[64];
|
||||
u_char swf_url[NGX_RTMP_MAX_URL];
|
||||
u_char tc_url[NGX_RTMP_MAX_URL];
|
||||
double acodecs;
|
||||
|
|
|
@ -306,7 +306,7 @@ ngx_rtmp_codec_parse_aac_header(ngx_rtmp_session_t *s, ngx_chain_t *in)
|
|||
ctx->aac_chan_conf = (ngx_uint_t) ngx_rtmp_bit_read(&br, 4);
|
||||
|
||||
if (ctx->aac_profile == 5 || ctx->aac_profile == 29) {
|
||||
|
||||
|
||||
if (ctx->aac_profile == 29) {
|
||||
ctx->aac_ps = 1;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ ngx_rtmp_codec_parse_aac_header(ngx_rtmp_session_t *s, ngx_chain_t *in)
|
|||
5 bits: object type
|
||||
if (object type == 31)
|
||||
6 bits + 32: object type
|
||||
|
||||
|
||||
var bits: AOT Specific Config
|
||||
*/
|
||||
|
||||
|
@ -415,7 +415,7 @@ ngx_rtmp_codec_parse_avc_header(ngx_rtmp_session_t *s, ngx_chain_t *in)
|
|||
{
|
||||
/* chroma format idc */
|
||||
cf_idc = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br);
|
||||
|
||||
|
||||
if (cf_idc == 3) {
|
||||
|
||||
/* separate color plane */
|
||||
|
@ -454,7 +454,7 @@ ngx_rtmp_codec_parse_avc_header(ngx_rtmp_session_t *s, ngx_chain_t *in)
|
|||
if (sl_next != 0) {
|
||||
|
||||
/* convert to signed: (-1)**k+1 * ceil(k/2) */
|
||||
sl_udelta = ngx_rtmp_bit_read_golomb(&br);
|
||||
sl_udelta = (ngx_uint_t)ngx_rtmp_bit_read_golomb(&br);
|
||||
sl_delta = (sl_udelta + 1) >> 1;
|
||||
if ((sl_udelta & 1) == 0) {
|
||||
sl_delta = -sl_delta;
|
||||
|
@ -595,6 +595,7 @@ ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s)
|
|||
double duration;
|
||||
double frame_rate;
|
||||
double video_data_rate;
|
||||
double video_keyframe_frequency;
|
||||
double video_codec_id;
|
||||
double audio_data_rate;
|
||||
double audio_codec_id;
|
||||
|
@ -640,6 +641,10 @@ ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s)
|
|||
ngx_string("videodatarate"),
|
||||
&v.video_data_rate, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NUMBER,
|
||||
ngx_string("videokeyframe_frequency"),
|
||||
&v.video_keyframe_frequency, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NUMBER,
|
||||
ngx_string("videocodecid"),
|
||||
&v.video_codec_id, 0 },
|
||||
|
@ -689,6 +694,7 @@ ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s)
|
|||
v.duration = ctx->duration;
|
||||
v.frame_rate = ctx->frame_rate;
|
||||
v.video_data_rate = ctx->video_data_rate;
|
||||
v.video_keyframe_frequency = ctx->video_keyframe_frequency;
|
||||
v.video_codec_id = ctx->video_codec_id;
|
||||
v.audio_data_rate = ctx->audio_data_rate;
|
||||
v.audio_codec_id = ctx->audio_codec_id;
|
||||
|
@ -765,6 +771,7 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
double duration;
|
||||
double frame_rate;
|
||||
double video_data_rate;
|
||||
double video_keyframe_frequency;
|
||||
double video_codec_id_n;
|
||||
u_char video_codec_id_s[32];
|
||||
double audio_data_rate;
|
||||
|
@ -822,6 +829,10 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_string("videodatarate"),
|
||||
&v.video_data_rate, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NUMBER,
|
||||
ngx_string("videokeyframe_frequency"),
|
||||
&v.video_keyframe_frequency, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_VARIANT,
|
||||
ngx_string("videocodecid"),
|
||||
in_video_codec_id, sizeof(in_video_codec_id) },
|
||||
|
@ -871,6 +882,7 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
v.duration = -1;
|
||||
v.frame_rate = -1;
|
||||
v.video_data_rate = -1;
|
||||
v.video_keyframe_frequency = -1;
|
||||
v.video_codec_id_n = -1;
|
||||
v.audio_data_rate = -1;
|
||||
v.audio_codec_id_n = -1;
|
||||
|
@ -895,12 +907,13 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
if (v.video_data_rate != -1) ctx->video_data_rate = v.video_data_rate;
|
||||
if (v.video_codec_id_n != -1) ctx->video_codec_id = (ngx_uint_t) v.video_codec_id_n;
|
||||
if (v.audio_data_rate != -1) ctx->audio_data_rate = v.audio_data_rate;
|
||||
if (v.video_keyframe_frequency != -1) ctx->video_keyframe_frequency = v.video_keyframe_frequency;
|
||||
if (v.audio_codec_id_n != -1) ctx->audio_codec_id = (v.audio_codec_id_n == 0
|
||||
? NGX_RTMP_AUDIO_UNCOMPRESSED : (ngx_uint_t) v.audio_codec_id_n);
|
||||
if (v.profile[0] != '\0') ngx_memcpy(ctx->profile, v.profile, sizeof(v.profile));
|
||||
if (v.level[0] != '\0') ngx_memcpy(ctx->level, v.level, sizeof(v.level));
|
||||
|
||||
ngx_log_debug8(NGX_LOG_DEBUG, s->connection->log, 0,
|
||||
ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"codec: data frame: "
|
||||
"width=%ui height=%ui duration=%.3f frame_rate=%.3f "
|
||||
"video=%s (%ui) audio=%s (%ui)",
|
||||
|
@ -910,6 +923,12 @@ ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_rtmp_get_audio_codec_name(ctx->audio_codec_id),
|
||||
ctx->audio_codec_id);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"codec: data frame: "
|
||||
"video_rate=%.3f audio_rate=%.3f ",
|
||||
ctx->video_data_rate, ctx->audio_data_rate
|
||||
);
|
||||
|
||||
switch (cacf->meta) {
|
||||
case NGX_RTMP_CODEC_META_ON:
|
||||
return ngx_rtmp_codec_reconstruct_meta(s);
|
||||
|
@ -976,7 +995,7 @@ ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf)
|
|||
}
|
||||
ngx_str_set(&ch->name, "@setDataFrame");
|
||||
ch->handler = ngx_rtmp_codec_meta_data;
|
||||
|
||||
|
||||
// some encoders send setDataFrame instead of @setDataFrame
|
||||
ch = ngx_array_push(&cmcf->amf);
|
||||
if (ch == NULL) {
|
||||
|
@ -984,7 +1003,7 @@ ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf)
|
|||
}
|
||||
ngx_str_set(&ch->name, "setDataFrame");
|
||||
ch->handler = ngx_rtmp_codec_meta_data;
|
||||
|
||||
|
||||
ch = ngx_array_push(&cmcf->amf);
|
||||
if (ch == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef struct {
|
|||
double duration;
|
||||
double frame_rate;
|
||||
double video_data_rate;
|
||||
double video_keyframe_frequency;
|
||||
ngx_uint_t video_codec_id;
|
||||
double audio_data_rate;
|
||||
ngx_uint_t audio_codec_id;
|
||||
|
|
|
@ -45,7 +45,7 @@ static ngx_command_t ngx_rtmp_core_commands[] = {
|
|||
NULL },
|
||||
|
||||
{ ngx_string("listen"),
|
||||
NGX_RTMP_SRV_CONF|NGX_CONF_TAKE12,
|
||||
NGX_RTMP_SRV_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_core_listen,
|
||||
NGX_RTMP_SRV_CONF_OFFSET,
|
||||
0,
|
||||
|
@ -332,6 +332,7 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
void *mconf;
|
||||
ngx_uint_t m;
|
||||
ngx_conf_t pcf;
|
||||
ngx_module_t **modules;
|
||||
ngx_rtmp_module_t *module;
|
||||
ngx_rtmp_conf_ctx_t *ctx, *rtmp_ctx;
|
||||
ngx_rtmp_core_srv_conf_t *cscf, **cscfp;
|
||||
|
@ -357,12 +358,17 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
#if defined(nginx_version) && nginx_version >= 1009011
|
||||
modules = cf->cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
for (m = 0; modules[m]; m++) {
|
||||
if (modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[m]->ctx;
|
||||
module = modules[m]->ctx;
|
||||
|
||||
if (module->create_srv_conf) {
|
||||
mconf = module->create_srv_conf(cf);
|
||||
|
@ -370,7 +376,7 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
|
||||
ctx->srv_conf[modules[m]->ctx_index] = mconf;
|
||||
}
|
||||
|
||||
if (module->create_app_conf) {
|
||||
|
@ -379,7 +385,7 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ctx->app_conf[ngx_modules[m]->ctx_index] = mconf;
|
||||
ctx->app_conf[modules[m]->ctx_index] = mconf;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,6 +425,7 @@ ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
ngx_int_t i;
|
||||
ngx_str_t *value;
|
||||
ngx_conf_t save;
|
||||
ngx_module_t **modules;
|
||||
ngx_rtmp_module_t *module;
|
||||
ngx_rtmp_conf_ctx_t *ctx, *pctx;
|
||||
ngx_rtmp_core_srv_conf_t *cscf;
|
||||
|
@ -438,17 +445,21 @@ ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; ngx_modules[i]; i++) {
|
||||
if (ngx_modules[i]->type != NGX_RTMP_MODULE) {
|
||||
#if defined(nginx_version) && nginx_version >= 1009011
|
||||
modules = cf->cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
for (i = 0; modules[i]; i++) {
|
||||
if (modules[i]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[i]->ctx;
|
||||
module = modules[i]->ctx;
|
||||
|
||||
if (module->create_app_conf) {
|
||||
ctx->app_conf[ngx_modules[i]->ctx_index] =
|
||||
module->create_app_conf(cf);
|
||||
if (ctx->app_conf[ngx_modules[i]->ctx_index] == NULL) {
|
||||
ctx->app_conf[modules[i]->ctx_index] = module->create_app_conf(cf);
|
||||
if (ctx->app_conf[modules[i]->ctx_index] == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -488,7 +499,7 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
in_port_t port;
|
||||
ngx_str_t *value;
|
||||
ngx_url_t u;
|
||||
ngx_uint_t i, m;
|
||||
ngx_uint_t i;
|
||||
struct sockaddr *sa;
|
||||
ngx_rtmp_listen_t *ls;
|
||||
struct sockaddr_in *sin;
|
||||
|
@ -545,7 +556,11 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
break;
|
||||
}
|
||||
|
||||
#if (nginx_version >= 1011000)
|
||||
if (ngx_memcmp(ls[i].sockaddr + off, (u_char *) &u.sockaddr + off, len) != 0) {
|
||||
#else
|
||||
if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) {
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -565,18 +580,16 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
|
||||
ngx_memzero(ls, sizeof(ngx_rtmp_listen_t));
|
||||
|
||||
#if (nginx_version >= 1011000)
|
||||
ngx_memcpy(ls->sockaddr, (u_char *) &u.sockaddr, u.socklen);
|
||||
#else
|
||||
ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
|
||||
#endif
|
||||
|
||||
ls->socklen = u.socklen;
|
||||
ls->wildcard = u.wildcard;
|
||||
ls->ctx = cf->ctx;
|
||||
|
||||
for (m = 0; ngx_modules[m]; m++) {
|
||||
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 2; i < cf->args->nelts; i++) {
|
||||
|
||||
if (ngx_strcmp(value[i].data, "bind") == 0) {
|
||||
|
@ -586,7 +599,6 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
|
||||
if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
|
||||
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
|
||||
struct sockaddr *sa;
|
||||
u_char buf[NGX_SOCKADDR_STRLEN];
|
||||
|
||||
sa = (struct sockaddr *) ls->sockaddr;
|
||||
|
|
|
@ -154,6 +154,7 @@ ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out,
|
|||
|
||||
name.len = p - name.data;
|
||||
ngx_rtmp_eval_append_var(ctx, &b, e, &name, log);
|
||||
/* fall through */
|
||||
|
||||
case NORMAL:
|
||||
switch (c) {
|
||||
|
@ -164,7 +165,11 @@ ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out,
|
|||
case '\\':
|
||||
state = ESCAPE;
|
||||
continue;
|
||||
/* fall through */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case ESCAPE:
|
||||
ngx_rtmp_eval_append(&b, &c, 1, log);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
static ngx_rtmp_publish_pt next_publish;
|
||||
static ngx_rtmp_play_pt next_play;
|
||||
static ngx_rtmp_close_stream_pt next_close_stream;
|
||||
static ngx_rtmp_record_started_pt next_record_started;
|
||||
static ngx_rtmp_record_done_pt next_record_done;
|
||||
#endif
|
||||
|
||||
|
@ -55,6 +56,7 @@ enum {
|
|||
NGX_RTMP_EXEC_PUBLISH_DONE,
|
||||
NGX_RTMP_EXEC_PLAY,
|
||||
NGX_RTMP_EXEC_PLAY_DONE,
|
||||
NGX_RTMP_EXEC_RECORD_STARTED,
|
||||
NGX_RTMP_EXEC_RECORD_DONE,
|
||||
|
||||
NGX_RTMP_EXEC_MAX,
|
||||
|
@ -208,6 +210,15 @@ static ngx_command_t ngx_rtmp_exec_commands[] = {
|
|||
NGX_RTMP_EXEC_PLAY_DONE * sizeof(ngx_array_t),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("exec_record_started"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
|
||||
NGX_CONF_1MORE,
|
||||
ngx_rtmp_exec_conf,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_exec_app_conf_t, conf) +
|
||||
NGX_RTMP_EXEC_RECORD_STARTED * sizeof(ngx_array_t),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("exec_record_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
|
||||
NGX_CONF_1MORE,
|
||||
|
@ -1307,6 +1318,31 @@ next:
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_exec_record_started(ngx_rtmp_session_t *s, ngx_rtmp_record_started_t *v)
|
||||
{
|
||||
ngx_rtmp_exec_app_conf_t *eacf;
|
||||
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module);
|
||||
if (eacf == NULL || !eacf->active) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_RECORD_STARTED],
|
||||
"record_started");
|
||||
|
||||
ngx_str_null(&v->recorder);
|
||||
ngx_str_null(&v->path);
|
||||
|
||||
next:
|
||||
return next_record_started(s, v);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_exec_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
|
||||
{
|
||||
|
@ -1364,6 +1400,7 @@ ngx_rtmp_exec_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
|
|||
next:
|
||||
return next_record_done(s, v);
|
||||
}
|
||||
|
||||
#endif /* NGX_WIN32 */
|
||||
|
||||
|
||||
|
@ -1603,6 +1640,9 @@ ngx_rtmp_exec_postconfiguration(ngx_conf_t *cf)
|
|||
next_record_done = ngx_rtmp_record_done;
|
||||
ngx_rtmp_record_done = ngx_rtmp_exec_record_done;
|
||||
|
||||
next_record_started = ngx_rtmp_record_started;
|
||||
ngx_rtmp_record_started = ngx_rtmp_exec_record_started;
|
||||
|
||||
#endif /* NGX_WIN32 */
|
||||
|
||||
return NGX_OK;
|
||||
|
|
|
@ -241,7 +241,9 @@ ngx_rtmp_recv(ngx_event_t *rev)
|
|||
"reusing formerly read data: %d", old_size);
|
||||
|
||||
b->pos = b->start;
|
||||
b->last = ngx_movemem(b->pos, old_pos, old_size);
|
||||
|
||||
size = ngx_min((size_t) (b->end - b->start), old_size);
|
||||
b->last = ngx_movemem(b->pos, old_pos, size);
|
||||
|
||||
if (s->in_chunk_size_changing) {
|
||||
ngx_rtmp_finalize_set_chunk_size(s);
|
||||
|
|
|
@ -104,30 +104,37 @@ static ngx_int_t
|
|||
ngx_rtmp_make_digest(ngx_str_t *key, ngx_buf_t *src,
|
||||
u_char *skip, u_char *dst, ngx_log_t *log)
|
||||
{
|
||||
static HMAC_CTX hmac;
|
||||
static unsigned hmac_initialized;
|
||||
static HMAC_CTX *hmac;
|
||||
unsigned int len;
|
||||
|
||||
if (!hmac_initialized) {
|
||||
HMAC_CTX_init(&hmac);
|
||||
hmac_initialized = 1;
|
||||
if (hmac == NULL) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static HMAC_CTX shmac;
|
||||
hmac = &shmac;
|
||||
HMAC_CTX_init(hmac);
|
||||
#else
|
||||
hmac = HMAC_CTX_new();
|
||||
if (hmac == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HMAC_Init_ex(&hmac, key->data, key->len, EVP_sha256(), NULL);
|
||||
HMAC_Init_ex(hmac, key->data, key->len, EVP_sha256(), NULL);
|
||||
|
||||
if (skip && src->pos <= skip && skip <= src->last) {
|
||||
if (skip != src->pos) {
|
||||
HMAC_Update(&hmac, src->pos, skip - src->pos);
|
||||
HMAC_Update(hmac, src->pos, skip - src->pos);
|
||||
}
|
||||
if (src->last != skip + NGX_RTMP_HANDSHAKE_KEYLEN) {
|
||||
HMAC_Update(&hmac, skip + NGX_RTMP_HANDSHAKE_KEYLEN,
|
||||
HMAC_Update(hmac, skip + NGX_RTMP_HANDSHAKE_KEYLEN,
|
||||
src->last - skip - NGX_RTMP_HANDSHAKE_KEYLEN);
|
||||
}
|
||||
} else {
|
||||
HMAC_Update(&hmac, src->pos, src->last - src->pos);
|
||||
HMAC_Update(hmac, src->pos, src->last - src->pos);
|
||||
}
|
||||
|
||||
HMAC_Final(&hmac, dst, &len);
|
||||
HMAC_Final(hmac, dst, &len);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
|
|
@ -76,9 +76,9 @@ ngx_rtmp_init_connection(ngx_connection_t *c)
|
|||
|
||||
break;
|
||||
#endif
|
||||
|
||||
case AF_UNIX:
|
||||
unix_socket = 1;
|
||||
/* fall through */
|
||||
|
||||
default: /* AF_INET */
|
||||
sin = (struct sockaddr_in *) sa;
|
||||
|
@ -110,6 +110,7 @@ ngx_rtmp_init_connection(ngx_connection_t *c)
|
|||
|
||||
case AF_UNIX:
|
||||
unix_socket = 1;
|
||||
/* fall through */
|
||||
|
||||
default: /* AF_INET */
|
||||
addr = port->addrs;
|
||||
|
|
|
@ -40,16 +40,16 @@ static ngx_command_t ngx_rtmp_live_commands[] = {
|
|||
|
||||
{ ngx_string("stream_buckets"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
ngx_conf_set_num_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_live_app_conf_t, nbuckets),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("buffer"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_msec_slot,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_live_app_conf_t, buflen),
|
||||
offsetof(ngx_rtmp_live_app_conf_t, buffer),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("sync"),
|
||||
|
@ -152,7 +152,7 @@ ngx_rtmp_live_create_app_conf(ngx_conf_t *cf)
|
|||
|
||||
lacf->live = NGX_CONF_UNSET;
|
||||
lacf->nbuckets = NGX_CONF_UNSET;
|
||||
lacf->buflen = NGX_CONF_UNSET_MSEC;
|
||||
lacf->buffer = NGX_CONF_UNSET;
|
||||
lacf->sync = NGX_CONF_UNSET_MSEC;
|
||||
lacf->idle_timeout = NGX_CONF_UNSET_MSEC;
|
||||
lacf->interleave = NGX_CONF_UNSET;
|
||||
|
@ -174,7 +174,7 @@ ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
|
||||
ngx_conf_merge_value(conf->live, prev->live, 0);
|
||||
ngx_conf_merge_value(conf->nbuckets, prev->nbuckets, 1024);
|
||||
ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 0);
|
||||
ngx_conf_merge_value(conf->buffer, prev->buffer, 0);
|
||||
ngx_conf_merge_msec_value(conf->sync, prev->sync, 300);
|
||||
ngx_conf_merge_msec_value(conf->idle_timeout, prev->idle_timeout, 0);
|
||||
ngx_conf_merge_value(conf->interleave, prev->interleave, 0);
|
||||
|
@ -553,7 +553,7 @@ ngx_rtmp_live_join(ngx_rtmp_session_t *s, u_char *name, unsigned publisher)
|
|||
|
||||
(*stream)->ctx = ctx;
|
||||
|
||||
if (lacf->buflen) {
|
||||
if (lacf->buffer) {
|
||||
s->out_buffer = 1;
|
||||
}
|
||||
|
||||
|
@ -1138,10 +1138,6 @@ ngx_rtmp_live_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ss->current_time = cs->timestamp;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
ngx_rtmp_free_shared_chain(cscf, data);
|
||||
}
|
||||
|
||||
if (rpkt) {
|
||||
ngx_rtmp_free_shared_chain(cscf, rpkt);
|
||||
}
|
||||
|
@ -1231,7 +1227,7 @@ ngx_rtmp_live_on_fi(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_null_string,
|
||||
"onFi", 0 },
|
||||
"onFI", 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_MIXED_ARRAY,
|
||||
ngx_null_string,
|
||||
|
@ -1258,7 +1254,7 @@ ngx_rtmp_live_on_fi(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
if (res == NGX_OK) {
|
||||
|
||||
ngx_log_error(NGX_LOG_DEBUG, s->connection->log, 0,
|
||||
"live: onFi: date='%s', time='%s'",
|
||||
"live: onFI: date='%s', time='%s'",
|
||||
v.date, v.time);
|
||||
|
||||
out_dt_elts[0].data = v.date;
|
||||
|
@ -1517,7 +1513,7 @@ ngx_rtmp_live_postconfiguration(ngx_conf_t *cf)
|
|||
ch->handler = ngx_rtmp_live_on_cue_point;
|
||||
|
||||
ch = ngx_array_push(&cmcf->amf);
|
||||
ngx_str_set(&ch->name, "onFi");
|
||||
ngx_str_set(&ch->name, "onFI");
|
||||
ch->handler = ngx_rtmp_live_on_fi;
|
||||
|
||||
ch = ngx_array_push(&cmcf->amf);
|
||||
|
|
|
@ -72,7 +72,7 @@ typedef struct {
|
|||
ngx_flag_t publish_notify;
|
||||
ngx_flag_t play_restart;
|
||||
ngx_flag_t idle_streams;
|
||||
ngx_msec_t buflen;
|
||||
ngx_flag_t buffer;
|
||||
ngx_pool_t *pool;
|
||||
ngx_rtmp_live_stream_t *free_streams;
|
||||
} ngx_rtmp_live_app_conf_t;
|
||||
|
|
|
@ -571,6 +571,7 @@ ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, ngx_pool_t *pool)
|
|||
ngx_chain_t *cl;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t *addr_text;
|
||||
size_t bsize;
|
||||
|
||||
addr_text = &s->connection->addr_text;
|
||||
|
||||
|
@ -579,16 +580,34 @@ ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, ngx_pool_t *pool)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("app=") - 1 + s->app.len * 3 +
|
||||
sizeof("&flashver=") - 1 + s->flashver.len * 3 +
|
||||
sizeof("&swfurl=") - 1 + s->swf_url.len * 3 +
|
||||
sizeof("&tcurl=") - 1 + s->tc_url.len * 3 +
|
||||
sizeof("&pageurl=") - 1 + s->page_url.len * 3 +
|
||||
sizeof("&addr=") - 1 + addr_text->len * 3 +
|
||||
sizeof("&clientid=") - 1 + NGX_INT_T_LEN
|
||||
);
|
||||
/**
|
||||
* @2016-04-20 sergey-dryabzhinsky
|
||||
* Not all params may be filled in session
|
||||
* So not override them with empty values
|
||||
*/
|
||||
|
||||
bsize = sizeof("addr=") - 1 + addr_text->len * 3 +
|
||||
sizeof("&clientid=") - 1 + NGX_INT_T_LEN;
|
||||
|
||||
// Indicator of additional vars from session
|
||||
// Event `connect` don't have them, for example
|
||||
if (s->app.len) {
|
||||
bsize += sizeof("&app=") - 1 + s->app.len * 3;
|
||||
}
|
||||
if (s->flashver.len) {
|
||||
bsize += sizeof("&flashver=") - 1 + s->flashver.len * 3;
|
||||
}
|
||||
if (s->swf_url.len) {
|
||||
bsize += sizeof("&swfurl=") - 1 + s->swf_url.len * 3;
|
||||
}
|
||||
if (s->tc_url.len) {
|
||||
bsize += sizeof("&tcurl=") - 1 + s->tc_url.len * 3;
|
||||
}
|
||||
if (s->page_url.len) {
|
||||
bsize += sizeof("&pageurl=") - 1 + s->page_url.len * 3;
|
||||
}
|
||||
|
||||
b = ngx_create_temp_buf(pool, bsize);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -596,31 +615,7 @@ ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, ngx_pool_t *pool)
|
|||
cl->buf = b;
|
||||
cl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "app=", sizeof("app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&flashver=",
|
||||
sizeof("&flashver=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->flashver.data,
|
||||
s->flashver.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&swfurl=",
|
||||
sizeof("&swfurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->swf_url.data,
|
||||
s->swf_url.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&tcurl=",
|
||||
sizeof("&tcurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->tc_url.data,
|
||||
s->tc_url.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&pageurl=",
|
||||
sizeof("&pageurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->page_url.data,
|
||||
s->page_url.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&addr=", sizeof("&addr=") - 1);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "addr=", sizeof("addr=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, addr_text->data,
|
||||
addr_text->len, NGX_ESCAPE_ARGS);
|
||||
|
||||
|
@ -628,6 +623,36 @@ ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, ngx_pool_t *pool)
|
|||
sizeof("&clientid=") - 1);
|
||||
b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->connection->number);
|
||||
|
||||
if (s->app.len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
}
|
||||
if (s->flashver.len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&flashver=",
|
||||
sizeof("&flashver=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->flashver.data,
|
||||
s->flashver.len, NGX_ESCAPE_ARGS);
|
||||
}
|
||||
if (s->swf_url.len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&swfurl=",
|
||||
sizeof("&swfurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->swf_url.data,
|
||||
s->swf_url.len, NGX_ESCAPE_ARGS);
|
||||
}
|
||||
if (s->tc_url.len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&tcurl=",
|
||||
sizeof("&tcurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->tc_url.data,
|
||||
s->tc_url.len, NGX_ESCAPE_ARGS);
|
||||
}
|
||||
if (s->page_url.len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&pageurl=",
|
||||
sizeof("&pageurl=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->page_url.data,
|
||||
s->page_url.len, NGX_ESCAPE_ARGS);
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ static ngx_rtmp_disconnect_pt next_disconnect;
|
|||
static ngx_rtmp_publish_pt next_publish;
|
||||
static ngx_rtmp_play_pt next_play;
|
||||
static ngx_rtmp_close_stream_pt next_close_stream;
|
||||
static ngx_rtmp_record_started_pt next_record_started;
|
||||
static ngx_rtmp_record_done_pt next_record_done;
|
||||
static ngx_rtmp_playlist_pt next_playlist;
|
||||
|
||||
|
@ -56,6 +57,7 @@ enum {
|
|||
NGX_RTMP_NOTIFY_PLAY_DONE,
|
||||
NGX_RTMP_NOTIFY_PUBLISH_DONE,
|
||||
NGX_RTMP_NOTIFY_DONE,
|
||||
NGX_RTMP_NOTIFY_RECORD_STARTED,
|
||||
NGX_RTMP_NOTIFY_RECORD_DONE,
|
||||
NGX_RTMP_NOTIFY_UPDATE,
|
||||
NGX_RTMP_NOTIFY_PLAYLIST,
|
||||
|
@ -154,6 +156,14 @@ static ngx_command_t ngx_rtmp_notify_commands[] = {
|
|||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("on_record_started"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
|
||||
NGX_CONF_TAKE1,
|
||||
ngx_rtmp_notify_on_app_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("on_record_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
|
||||
NGX_CONF_TAKE1,
|
||||
|
@ -347,15 +357,35 @@ ngx_rtmp_notify_create_request(ngx_rtmp_session_t *s, ngx_pool_t *pool,
|
|||
ngx_chain_t *al, *bl, *cl;
|
||||
ngx_url_t *url;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create request: begin");
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
url = nacf->url[url_idx];
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create request: netcall format session");
|
||||
|
||||
al = ngx_rtmp_netcall_http_format_session(s, pool);
|
||||
if (al == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Swap args and fulled session params chain
|
||||
// Because nginx-rtmp session params are higher priority
|
||||
// And must be last in chain to prevent override.
|
||||
// So.
|
||||
// In args first symbol IS NOT '&', but LAST ONE
|
||||
if (args) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create request: swap formated args");
|
||||
|
||||
cl = args;
|
||||
args = al;
|
||||
al = cl;
|
||||
}
|
||||
|
||||
al->next = args;
|
||||
|
||||
bl = NULL;
|
||||
|
@ -366,33 +396,90 @@ ngx_rtmp_notify_create_request(ngx_rtmp_session_t *s, ngx_pool_t *pool,
|
|||
bl = cl;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create request: netcall format request");
|
||||
|
||||
return ngx_rtmp_netcall_http_format_request(nacf->method, &url->host,
|
||||
&url->uri, al, bl, pool,
|
||||
&ngx_rtmp_notify_urlencoded);
|
||||
}
|
||||
|
||||
|
||||
static ngx_chain_t *
|
||||
ngx_rtmp_notify_create_srv_request(ngx_rtmp_session_t *s, ngx_pool_t *pool,
|
||||
ngx_uint_t url_idx, ngx_chain_t *args)
|
||||
{
|
||||
ngx_rtmp_notify_srv_conf_t *nscf;
|
||||
ngx_chain_t *al, *bl, *cl;
|
||||
ngx_url_t *url;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create srv request: begin");
|
||||
|
||||
nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
url = nscf->url[url_idx];
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create srv request: netcall format session");
|
||||
|
||||
al = ngx_rtmp_netcall_http_format_session(s, pool);
|
||||
if (al == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Swap args and fulled session params chain
|
||||
// Because nginx-rtmp session params are higher priority
|
||||
// And must be last in chain to prevent override.
|
||||
// So.
|
||||
// In args first symbol IS NOT '&', but LAST ONE
|
||||
if (args) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create srv request: swap formated args");
|
||||
|
||||
cl = args;
|
||||
args = al;
|
||||
al = cl;
|
||||
}
|
||||
|
||||
al->next = args;
|
||||
|
||||
bl = NULL;
|
||||
|
||||
if (nscf->method == NGX_RTMP_NETCALL_HTTP_POST) {
|
||||
cl = al;
|
||||
al = bl;
|
||||
bl = cl;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: create srv request: netcall format request");
|
||||
|
||||
return ngx_rtmp_netcall_http_format_request(nscf->method, &url->host,
|
||||
&url->uri, al, bl, pool,
|
||||
&ngx_rtmp_notify_urlencoded);
|
||||
}
|
||||
|
||||
|
||||
static ngx_chain_t *
|
||||
ngx_rtmp_notify_connect_create(ngx_rtmp_session_t *s, void *arg,
|
||||
ngx_pool_t *pool)
|
||||
{
|
||||
ngx_rtmp_connect_t *v = arg;
|
||||
|
||||
ngx_rtmp_notify_srv_conf_t *nscf;
|
||||
ngx_url_t *url;
|
||||
ngx_chain_t *al, *bl;
|
||||
ngx_chain_t *al;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t *addr_text;
|
||||
size_t app_len, args_len, flashver_len,
|
||||
swf_url_len, tc_url_len, page_url_len;
|
||||
|
||||
nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
al = ngx_alloc_chain_link(pool);
|
||||
if (al == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"notify: connect: begin");
|
||||
|
||||
/* these values are still missing in session
|
||||
* so we have to construct the request from
|
||||
* connection struct */
|
||||
|
@ -404,18 +491,15 @@ ngx_rtmp_notify_connect_create(ngx_rtmp_session_t *s, void *arg,
|
|||
tc_url_len = ngx_strlen(v->tc_url);
|
||||
page_url_len = ngx_strlen(v->page_url);
|
||||
|
||||
addr_text = &s->connection->addr_text;
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("call=connect") - 1 +
|
||||
sizeof("call=connect") +
|
||||
sizeof("&app=") - 1 + app_len * 3 +
|
||||
sizeof("&flashver=") - 1 + flashver_len * 3 +
|
||||
sizeof("&swfurl=") - 1 + swf_url_len * 3 +
|
||||
sizeof("&tcurl=") - 1 + tc_url_len * 3 +
|
||||
sizeof("&pageurl=") - 1 + page_url_len * 3 +
|
||||
sizeof("&addr=") - 1 + addr_text->len * 3 +
|
||||
sizeof("&epoch=") - 1 + NGX_INT32_LEN +
|
||||
1 + args_len
|
||||
1 + args_len + 1
|
||||
);
|
||||
|
||||
if (b == NULL) {
|
||||
|
@ -425,7 +509,15 @@ ngx_rtmp_notify_connect_create(ngx_rtmp_session_t *s, void *arg,
|
|||
al->buf = b;
|
||||
al->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "app=", sizeof("app=") - 1);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=connect",
|
||||
sizeof("call=connect") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->app, app_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
|
@ -449,33 +541,12 @@ ngx_rtmp_notify_connect_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = (u_char*) ngx_escape_uri(b->last, v->page_url, page_url_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&addr=", sizeof("&addr=") -1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, addr_text->data,
|
||||
addr_text->len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&epoch=", sizeof("&epoch=") -1);
|
||||
b->last = ngx_sprintf(b->last, "%uD", (uint32_t) s->epoch);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=connect",
|
||||
sizeof("&call=connect") - 1);
|
||||
*b->last++ = '&';
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
}
|
||||
|
||||
url = nscf->url[NGX_RTMP_NOTIFY_CONNECT];
|
||||
|
||||
bl = NULL;
|
||||
|
||||
if (nscf->method == NGX_RTMP_NETCALL_HTTP_POST) {
|
||||
bl = al;
|
||||
al = NULL;
|
||||
}
|
||||
|
||||
return ngx_rtmp_netcall_http_format_request(nscf->method, &url->host,
|
||||
&url->uri, al, bl, pool,
|
||||
&ngx_rtmp_notify_urlencoded);
|
||||
return ngx_rtmp_notify_create_srv_request(s, pool, NGX_RTMP_NOTIFY_CONNECT, al);
|
||||
}
|
||||
|
||||
|
||||
|
@ -483,24 +554,20 @@ static ngx_chain_t *
|
|||
ngx_rtmp_notify_disconnect_create(ngx_rtmp_session_t *s, void *arg,
|
||||
ngx_pool_t *pool)
|
||||
{
|
||||
ngx_rtmp_notify_srv_conf_t *nscf;
|
||||
ngx_url_t *url;
|
||||
ngx_chain_t *al, *bl, *pl;
|
||||
ngx_chain_t *pl;
|
||||
ngx_buf_t *b;
|
||||
|
||||
nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
pl = ngx_alloc_chain_link(pool);
|
||||
if (pl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=disconnect") +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("call=disconnect") +
|
||||
sizeof("&bytes_in=") - 1 + NGX_INT32_LEN +
|
||||
sizeof("&bytes_out=") - 1 + NGX_INT32_LEN +
|
||||
1 + s->args.len);
|
||||
1 + s->args.len + 1);
|
||||
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -508,12 +575,13 @@ ngx_rtmp_notify_disconnect_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=disconnect",
|
||||
sizeof("&call=disconnect") - 1);
|
||||
if (s->args.len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, s->args.data, s->args.len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=disconnect",
|
||||
sizeof("call=disconnect") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&bytes_in=", sizeof("&bytes_in=") -1);
|
||||
b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->in_bytes);
|
||||
|
@ -521,30 +589,9 @@ ngx_rtmp_notify_disconnect_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = ngx_cpymem(b->last, (u_char*) "&bytes_out=", sizeof("&bytes_out=") -1);
|
||||
b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->out_bytes);
|
||||
|
||||
if (s->args.len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, s->args.data, s->args.len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
url = nscf->url[NGX_RTMP_NOTIFY_DISCONNECT];
|
||||
|
||||
al = ngx_rtmp_netcall_http_format_session(s, pool);
|
||||
if (al == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
al->next = pl;
|
||||
|
||||
bl = NULL;
|
||||
|
||||
if (nscf->method == NGX_RTMP_NETCALL_HTTP_POST) {
|
||||
bl = al;
|
||||
al = NULL;
|
||||
}
|
||||
|
||||
return ngx_rtmp_netcall_http_format_request(nscf->method, &url->host,
|
||||
&url->uri, al, bl, pool,
|
||||
&ngx_rtmp_notify_urlencoded);
|
||||
return ngx_rtmp_notify_create_srv_request(s, pool, NGX_RTMP_NOTIFY_DISCONNECT, pl);
|
||||
}
|
||||
|
||||
|
||||
|
@ -568,11 +615,10 @@ ngx_rtmp_notify_publish_create(ngx_rtmp_session_t *s, void *arg,
|
|||
args_len = ngx_strlen(v->args);
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=publish") +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("call=publish") +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&type=") + type_len * 3 +
|
||||
1 + args_len);
|
||||
1 + args_len + 1);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -580,12 +626,13 @@ ngx_rtmp_notify_publish_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=publish",
|
||||
sizeof("&call=publish") - 1);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=publish",
|
||||
sizeof("call=publish") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->name, name_len,
|
||||
|
@ -595,10 +642,7 @@ ngx_rtmp_notify_publish_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = (u_char*) ngx_escape_uri(b->last, v->type, type_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PUBLISH, pl);
|
||||
}
|
||||
|
@ -623,11 +667,10 @@ ngx_rtmp_notify_play_create(ngx_rtmp_session_t *s, void *arg,
|
|||
args_len = ngx_strlen(v->args);
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=play") +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("call=play") +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&start=&duration=&reset=") +
|
||||
NGX_INT32_LEN * 3 + 1 + args_len);
|
||||
NGX_INT32_LEN * 3 + 1 + args_len + 1);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -635,12 +678,13 @@ ngx_rtmp_notify_play_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=play",
|
||||
sizeof("&call=play") - 1);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=play",
|
||||
sizeof("call=play") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->name, name_len,
|
||||
|
@ -651,10 +695,7 @@ ngx_rtmp_notify_play_create(ngx_rtmp_session_t *s, void *arg,
|
|||
(uint32_t) v->start, (uint32_t) v->duration,
|
||||
v->reset & 1);
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PLAY, pl);
|
||||
}
|
||||
|
@ -683,12 +724,11 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
args_len = ctx ? ngx_strlen(ctx->args) : 0;
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=") + cbname_len +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("call=") + cbname_len +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&bytes_in=") - 1 + NGX_INT32_LEN +
|
||||
sizeof("&bytes_out=") - 1 + NGX_INT32_LEN +
|
||||
1 + args_len);
|
||||
1 + args_len + 1);
|
||||
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
|
@ -697,12 +737,13 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=", sizeof("&call=") - 1);
|
||||
b->last = ngx_cpymem(b->last, ds->cbname, cbname_len);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=", sizeof("call=") - 1);
|
||||
b->last = ngx_cpymem(b->last, ds->cbname, cbname_len);
|
||||
|
||||
if (name_len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
|
@ -716,10 +757,7 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = ngx_cpymem(b->last, (u_char*) "&bytes_out=", sizeof("&bytes_out=") -1);
|
||||
b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->out_bytes);
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, ds->url_idx, pl);
|
||||
}
|
||||
|
@ -754,12 +792,11 @@ ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg,
|
|||
args_len = ctx ? ngx_strlen(ctx->args) : 0;
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=update") + sfx.len +
|
||||
sizeof("call=update") + sfx.len +
|
||||
sizeof("&time=") + NGX_TIME_T_LEN +
|
||||
sizeof("×tamp=") + NGX_INT32_LEN +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
1 + args_len);
|
||||
1 + args_len + 1);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -767,8 +804,13 @@ ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=update",
|
||||
sizeof("&call=update") - 1);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=update",
|
||||
sizeof("call=update") - 1);
|
||||
b->last = ngx_cpymem(b->last, sfx.data, sfx.len);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char *) "&time=",
|
||||
|
@ -779,25 +821,81 @@ ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg,
|
|||
sizeof("×tamp=") - 1);
|
||||
b->last = ngx_sprintf(b->last, "%D", s->current_time);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
if (name_len) {
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
}
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_UPDATE, pl);
|
||||
}
|
||||
|
||||
|
||||
static ngx_chain_t *
|
||||
ngx_rtmp_notify_record_started_create(ngx_rtmp_session_t *s, void *arg,
|
||||
ngx_pool_t *pool)
|
||||
{
|
||||
ngx_rtmp_record_started_t *v = arg;
|
||||
|
||||
ngx_rtmp_notify_ctx_t *ctx;
|
||||
ngx_chain_t *pl;
|
||||
ngx_buf_t *b;
|
||||
size_t name_len, args_len;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module);
|
||||
|
||||
pl = ngx_alloc_chain_link(pool);
|
||||
if (pl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name_len = ngx_strlen(ctx->name);
|
||||
args_len = ngx_strlen(ctx->args);
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("call=record_started") +
|
||||
sizeof("&recorder=") + v->recorder.len +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&path=") + v->path.len * 3 +
|
||||
1 + args_len + 1);
|
||||
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=record_started",
|
||||
sizeof("call=record_started") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char *) "&recorder=",
|
||||
sizeof("&recorder=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->recorder.data,
|
||||
v->recorder.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&path=", sizeof("&path=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->path.data, v->path.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_STARTED,
|
||||
pl);
|
||||
}
|
||||
|
||||
|
||||
static ngx_chain_t *
|
||||
ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
|
||||
ngx_pool_t *pool)
|
||||
|
@ -820,14 +918,13 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
args_len = ngx_strlen(ctx->args);
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=record_done") +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("call=record_done") +
|
||||
sizeof("&recorder=") + v->recorder.len +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&path=") + v->path.len * 3 +
|
||||
sizeof("&bytes_in=") - 1 + NGX_INT32_LEN +
|
||||
sizeof("&bytes_out=") - 1 + NGX_INT32_LEN +
|
||||
1 + args_len);
|
||||
1 + args_len + 1);
|
||||
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
|
@ -836,12 +933,13 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=record_done",
|
||||
sizeof("&call=record_done") - 1);
|
||||
if (args_len) {
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
*b->last++ = '&';
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=record_done",
|
||||
sizeof("call=record_done") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char *) "&recorder=",
|
||||
sizeof("&recorder=") - 1);
|
||||
|
@ -862,10 +960,7 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = ngx_cpymem(b->last, (u_char*) "&bytes_out=", sizeof("&bytes_out=") -1);
|
||||
b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->out_bytes);
|
||||
|
||||
if (args_len) {
|
||||
*b->last++ = '&';
|
||||
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
|
||||
}
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE,
|
||||
pl);
|
||||
|
@ -892,12 +987,11 @@ ngx_rtmp_notify_playlist_create(ngx_rtmp_session_t *s, void *arg,
|
|||
name_len = ngx_strlen(ctx->name);
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=playlist") +
|
||||
sizeof("call=playlist") +
|
||||
sizeof("&module=") + v->module.len +
|
||||
sizeof("&app=") + s->app.len * 3 +
|
||||
sizeof("&name=") + name_len * 3 +
|
||||
sizeof("&path=") + v->playlist.len * 3 +
|
||||
1);
|
||||
1 + 1);
|
||||
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
|
@ -906,18 +1000,14 @@ ngx_rtmp_notify_playlist_create(ngx_rtmp_session_t *s, void *arg,
|
|||
pl->buf = b;
|
||||
pl->next = NULL;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&call=playlist",
|
||||
sizeof("&call=playlist") - 1);
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "call=playlist",
|
||||
sizeof("call=playlist") - 1);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char *) "&module=",
|
||||
sizeof("&module=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, v->module.data,
|
||||
v->module.len, NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1);
|
||||
b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
@ -926,6 +1016,8 @@ ngx_rtmp_notify_playlist_create(ngx_rtmp_session_t *s, void *arg,
|
|||
b->last = (u_char*) ngx_escape_uri(b->last, v->playlist.data, v->playlist.len,
|
||||
NGX_ESCAPE_ARGS);
|
||||
|
||||
*b->last++ = '&';
|
||||
|
||||
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PLAYLIST,
|
||||
pl);
|
||||
}
|
||||
|
@ -1028,6 +1120,7 @@ ngx_rtmp_notify_parse_http_header(ngx_rtmp_session_t *s,
|
|||
|
||||
n = 0;
|
||||
state = parse_name;
|
||||
/* fall through */
|
||||
|
||||
case parse_name:
|
||||
switch (c) {
|
||||
|
@ -1055,6 +1148,7 @@ ngx_rtmp_notify_parse_http_header(ngx_rtmp_session_t *s,
|
|||
break;
|
||||
}
|
||||
state = parse_value;
|
||||
/* fall through */
|
||||
|
||||
case parse_value:
|
||||
if (c == '\n') {
|
||||
|
@ -1098,7 +1192,7 @@ ngx_rtmp_notify_connect_handle(ngx_rtmp_session_t *s,
|
|||
ngx_rtmp_notify_srv_conf_t *nscf;
|
||||
u_char app[NGX_RTMP_MAX_NAME];
|
||||
|
||||
static ngx_str_t location = ngx_string("location");
|
||||
static ngx_str_t location = ngx_string("x-rtmp-target");
|
||||
|
||||
rc = ngx_rtmp_notify_parse_http_retcode(s, in);
|
||||
|
||||
|
@ -1202,35 +1296,20 @@ next:
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_notify_set_name(u_char *dst, size_t dst_len, u_char *src,
|
||||
size_t src_len)
|
||||
{
|
||||
u_char result[16], *p;
|
||||
ngx_md5_t md5;
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
ngx_md5_update(&md5, src, src_len);
|
||||
ngx_md5_final(result, &md5);
|
||||
|
||||
p = ngx_hex_dump(dst, result, ngx_min((dst_len - 1) / 2, 16));
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_notify_publish_handle(ngx_rtmp_session_t *s,
|
||||
void *arg, ngx_chain_t *in)
|
||||
{
|
||||
ngx_rtmp_publish_t *v = arg;
|
||||
ngx_int_t rc, send;
|
||||
ngx_int_t rc, len_restream, len_user, send;
|
||||
ngx_str_t local_name;
|
||||
ngx_rtmp_relay_target_t target;
|
||||
ngx_url_t *u;
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
u_char name[NGX_RTMP_MAX_NAME];
|
||||
u_char restream[NGX_RTMP_MAX_NAME];
|
||||
u_char user[NGX_RTMP_MAX_NAME];
|
||||
|
||||
static ngx_str_t location = ngx_string("location");
|
||||
static ngx_str_t header_restream = ngx_string("x-rtmp-target");
|
||||
static ngx_str_t header_user = ngx_string("x-rtmp-user");
|
||||
|
||||
rc = ngx_rtmp_notify_parse_http_retcode(s, in);
|
||||
|
||||
|
@ -1270,93 +1349,58 @@ ngx_rtmp_notify_publish_handle(ngx_rtmp_session_t *s,
|
|||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish redirect received");
|
||||
|
||||
rc = ngx_rtmp_notify_parse_http_header(s, in, &location, name,
|
||||
sizeof(name) - 1);
|
||||
if (rc <= 0) {
|
||||
len_user = ngx_rtmp_notify_parse_http_header(s, in, &header_user, user, sizeof(user) - 1);
|
||||
if (len_user <= 0) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (ngx_strncasecmp(name, (u_char *) "rtmp://", 7)) {
|
||||
*ngx_cpymem(v->name, name, rc) = 0;
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish redirect to '%s'", v->name);
|
||||
goto next;
|
||||
}
|
||||
*ngx_cpymem(&v->name, &user, len_user) = 0;
|
||||
|
||||
/* push */
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (nacf->send_redirect) {
|
||||
// Send 302 redirect and go next
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish send 302 redirect");
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: -- for stream '%s' to new location '%*s'", v->name, rc, name);
|
||||
|
||||
local_name.data = ngx_palloc(s->connection->pool, rc+1);
|
||||
local_name.len = rc;
|
||||
*ngx_cpymem(local_name.data, name, rc) = 0;
|
||||
|
||||
/* MAGICK HERE */
|
||||
|
||||
if (!ngx_strncasecmp(s->flashver.data, (u_char *) "FMLE/", 5)) {
|
||||
// Official method, by FMS SDK
|
||||
send = ngx_rtmp_send_redirect_status(s, "onStatus", "Connect here", local_name);
|
||||
send &= ngx_rtmp_send_redirect_status(s, "netStatus", "Connect here", local_name);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish send(o) status = '%ui'", send == NGX_OK);
|
||||
} else {
|
||||
|
||||
// Something by rtmpdump lib
|
||||
send = ngx_rtmp_send_redirect_status(s, "_error", "Connect here", local_name);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish send(e) status = '%ui'", send == NGX_OK);
|
||||
}
|
||||
|
||||
ngx_pfree(s->connection->pool, local_name.data);
|
||||
|
||||
ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PUBLISHING);
|
||||
|
||||
// Something by rtmpdump lib
|
||||
send = ngx_rtmp_send_close_method(s, "close");
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish send(e) close method = '%ui'", send == NGX_OK);
|
||||
|
||||
return send;
|
||||
|
||||
} else if (nacf->relay_redirect) {
|
||||
// Relay local streams, change name
|
||||
|
||||
ngx_rtmp_notify_set_name(v->name, NGX_RTMP_MAX_NAME, name, (size_t) rc);
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: push '%s' to '%*s'", v->name, rc, name);
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "notify: publish redirect to '%s'", v->name);
|
||||
|
||||
local_name.data = v->name;
|
||||
local_name.len = ngx_strlen(v->name);
|
||||
|
||||
ngx_memzero(&target, sizeof(target));
|
||||
|
||||
u = &target.url;
|
||||
u->url = local_name;
|
||||
u->url.data = name + 7;
|
||||
u->url.len = rc - 7;
|
||||
u->default_port = 1935;
|
||||
u->uri_part = 1;
|
||||
u->no_resolve = 1; /* want ip here */
|
||||
|
||||
if (ngx_parse_url(s->connection->pool, u) != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: push failed '%V'", &local_name);
|
||||
return NGX_ERROR;
|
||||
len_restream = ngx_rtmp_notify_parse_http_header(s, in, &header_restream, restream, sizeof(restream) - 1);
|
||||
if (len_restream <= 0) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_rtmp_relay_push(s, &local_name, &target);
|
||||
u_char *start = restream;
|
||||
u_char *next;
|
||||
|
||||
while (start != NULL) {
|
||||
next = (u_char *) ngx_strchr(start, ',');
|
||||
|
||||
ngx_memzero(&target, sizeof(target));
|
||||
u = &target.url;
|
||||
u->url = local_name;
|
||||
|
||||
if (next) {
|
||||
u->url.data = start + 7;
|
||||
u->url.len = next - start - 7;
|
||||
start = next + 1;
|
||||
} else {
|
||||
u->url.data = start + 7;
|
||||
u->url.len = len_restream - (start - restream) - 7;
|
||||
start = NULL;
|
||||
}
|
||||
|
||||
u->default_port = 1935;
|
||||
u->uri_part = 1;
|
||||
u->no_resolve = 0;
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: processing push '%V'", &u->url);
|
||||
|
||||
if (ngx_parse_url(s->connection->pool, u) != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: push failed '%V'", &local_name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_rtmp_relay_push(s, &local_name, &target);
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
|
@ -1425,18 +1469,62 @@ ngx_rtmp_notify_play_handle(ngx_rtmp_session_t *s,
|
|||
goto next;
|
||||
}
|
||||
|
||||
|
||||
if (ngx_strncasecmp(name, (u_char *) "rtmp://", 7)) {
|
||||
*ngx_cpymem(v->name, name, rc) = 0;
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play redirect to '%s'", v->name);
|
||||
"notify: play internal redirect to '%s'", v->name);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* pull */
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
if (nacf->relay_redirect) {
|
||||
ngx_rtmp_notify_set_name(v->name, NGX_RTMP_MAX_NAME, name, (size_t) rc);
|
||||
if (nacf->send_redirect) {
|
||||
// Send 302 redirect and go next
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play send 302 redirect");
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: -- for stream '%s' to new location '%*s'", v->name, rc, name);
|
||||
|
||||
local_name.data = ngx_palloc(s->connection->pool, rc+1);
|
||||
local_name.len = rc;
|
||||
*ngx_cpymem(local_name.data, name, rc) = 0;
|
||||
|
||||
/* MAGICK HERE */
|
||||
|
||||
if (!ngx_strncasecmp(s->flashver.data, (u_char *) "FMLE/", 5)) {
|
||||
// Official method, by FMS SDK
|
||||
send = ngx_rtmp_send_redirect_status(s, "onStatus", "Connect here", local_name);
|
||||
send &= ngx_rtmp_send_redirect_status(s, "netStatus", "Connect here", local_name);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play send(o) status = '%ui'", send == NGX_OK);
|
||||
} else {
|
||||
|
||||
// Something by rtmpdump lib
|
||||
send = ngx_rtmp_send_redirect_status(s, "_error", "Connect here", local_name);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play send(e) status = '%ui'", send == NGX_OK);
|
||||
}
|
||||
|
||||
ngx_pfree(s->connection->pool, local_name.data);
|
||||
|
||||
ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PLAYING);
|
||||
|
||||
// Something by rtmpdump lib
|
||||
send = ngx_rtmp_send_close_method(s, "close");
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play send(e) close method = '%ui'", send == NGX_OK);
|
||||
|
||||
return send;
|
||||
|
||||
} else if (nacf->relay_redirect) {
|
||||
// Relay local streams, change name
|
||||
|
||||
*ngx_cpymem(&v->name, &name, NGX_RTMP_MAX_NAME) = 0;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
|
@ -1483,7 +1571,7 @@ ngx_rtmp_notify_update_handle(ngx_rtmp_session_t *s,
|
|||
|
||||
rc = ngx_rtmp_notify_parse_http_retcode(s, in);
|
||||
|
||||
if ((!nacf->update_strict && rc == NGX_ERROR) ||
|
||||
if ((!nacf->update_strict && (rc == NGX_ERROR || rc == NGX_DECLINED) ) ||
|
||||
(nacf->update_strict && rc != NGX_OK))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
|
@ -1800,6 +1888,39 @@ next:
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_notify_record_started(ngx_rtmp_session_t *s, ngx_rtmp_record_started_t *v)
|
||||
{
|
||||
ngx_rtmp_netcall_init_t ci;
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
if (nacf == NULL || nacf->url[NGX_RTMP_NOTIFY_RECORD_STARTED] == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: record_started recorder=%V path='%V' url='%V'",
|
||||
&v->recorder, &v->path,
|
||||
&nacf->url[NGX_RTMP_NOTIFY_RECORD_STARTED]->url);
|
||||
|
||||
ngx_memzero(&ci, sizeof(ci));
|
||||
|
||||
ci.url = nacf->url[NGX_RTMP_NOTIFY_RECORD_STARTED];
|
||||
ci.create = ngx_rtmp_notify_record_started_create;
|
||||
ci.arg = v;
|
||||
|
||||
ngx_rtmp_netcall_create(s, &ci);
|
||||
|
||||
next:
|
||||
return next_record_started(s, v);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
|
||||
{
|
||||
|
@ -2008,6 +2129,10 @@ ngx_rtmp_notify_on_app_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
n = NGX_RTMP_NOTIFY_PLAY_DONE;
|
||||
break;
|
||||
|
||||
case sizeof("on_record_started") - 1:
|
||||
n = NGX_RTMP_NOTIFY_RECORD_STARTED;
|
||||
break;
|
||||
|
||||
case sizeof("on_record_done") - 1:
|
||||
n = NGX_RTMP_NOTIFY_RECORD_DONE;
|
||||
break;
|
||||
|
@ -2104,6 +2229,9 @@ ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf)
|
|||
next_close_stream = ngx_rtmp_close_stream;
|
||||
ngx_rtmp_close_stream = ngx_rtmp_notify_close_stream;
|
||||
|
||||
next_record_started = ngx_rtmp_record_started;
|
||||
ngx_rtmp_record_started = ngx_rtmp_notify_record_started;
|
||||
|
||||
next_record_done = ngx_rtmp_record_done;
|
||||
ngx_rtmp_record_done = ngx_rtmp_notify_record_done;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "ngx_rtmp_record_module.h"
|
||||
|
||||
|
||||
ngx_rtmp_record_started_pt ngx_rtmp_record_started;
|
||||
ngx_rtmp_record_done_pt ngx_rtmp_record_done;
|
||||
|
||||
|
||||
|
@ -112,7 +113,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
|
|||
|
||||
{ ngx_string("record_interval_size"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|
|
||||
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
|
||||
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_size_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_record_app_conf_t, interval_size),
|
||||
|
@ -856,6 +857,8 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s,
|
|||
v.recorder = rracf->id;
|
||||
ngx_rtmp_record_make_path(s, rctx, &v.path);
|
||||
|
||||
rctx->record_started = 0;
|
||||
|
||||
rc = ngx_rtmp_record_done(s, &v);
|
||||
|
||||
s->app_conf = app_conf;
|
||||
|
@ -905,6 +908,21 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s,
|
|||
rctx->audio = 1;
|
||||
}
|
||||
|
||||
if (rctx->record_started == 0)
|
||||
{
|
||||
rctx->record_started = 1;
|
||||
|
||||
ngx_rtmp_record_started_t v;
|
||||
ngx_rtmp_record_app_conf_t *racf;
|
||||
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module);
|
||||
|
||||
if (racf != NULL && racf->rec.nelts != 0) {
|
||||
v.recorder = racf->id;
|
||||
v.path = racf->path;
|
||||
ngx_rtmp_record_started(s, &v);
|
||||
}
|
||||
}
|
||||
|
||||
timestamp = h->timestamp - rctx->epoch;
|
||||
|
||||
if ((int32_t) timestamp < 0) {
|
||||
|
@ -990,14 +1008,6 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s,
|
|||
ngx_rtmp_record_node_close(s, rctx);
|
||||
}
|
||||
|
||||
/* watch size interval */
|
||||
if ((rracf->interval_size && rctx->file.offset >= (ngx_int_t) rracf->interval_size) ||
|
||||
(rracf->max_frames && rctx->nframes >= rracf->max_frames))
|
||||
{
|
||||
ngx_rtmp_record_node_close(s, rctx);
|
||||
ngx_rtmp_record_node_open(s, rctx);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -1070,9 +1080,9 @@ ngx_rtmp_record_node_avd(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rctx->file.fd == NGX_INVALID_FILE) {
|
||||
/*if (rctx->file.fd == NGX_INVALID_FILE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
}*/
|
||||
|
||||
if (h->type == NGX_RTMP_MSG_AUDIO &&
|
||||
(rracf->flags & NGX_RTMP_RECORD_AUDIO) == 0)
|
||||
|
@ -1093,9 +1103,9 @@ ngx_rtmp_record_node_avd(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
// record interval should work if set, manual mode or not
|
||||
if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) {
|
||||
|
||||
if (brkframe && rracf->interval != NGX_CONF_UNSET_MSEC)
|
||||
{
|
||||
// record interval should work if set, manual mode or not
|
||||
next = rctx->last;
|
||||
next.msec += rracf->interval;
|
||||
next.sec += (next.msec / 1000);
|
||||
|
@ -1104,12 +1114,13 @@ ngx_rtmp_record_node_avd(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
|
|||
if (ngx_cached_time->sec > next.sec ||
|
||||
(ngx_cached_time->sec == next.sec &&
|
||||
ngx_cached_time->msec > next.msec))
|
||||
{
|
||||
ngx_rtmp_record_node_close(s, rctx);
|
||||
ngx_rtmp_record_node_open(s, rctx);
|
||||
}
|
||||
|
||||
} else if (!rctx->failed) {
|
||||
{
|
||||
ngx_rtmp_record_node_close(s, rctx);
|
||||
ngx_rtmp_record_node_open(s, rctx);
|
||||
}
|
||||
}
|
||||
else if (!rctx->failed)
|
||||
{
|
||||
ngx_rtmp_record_node_open(s, rctx);
|
||||
}
|
||||
|
||||
|
@ -1208,6 +1219,12 @@ ngx_rtmp_record_node_avd(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_record_started_init(ngx_rtmp_session_t *s, ngx_rtmp_record_started_t *v)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_record_done_init(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
|
||||
{
|
||||
|
@ -1222,6 +1239,7 @@ ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
ngx_int_t i;
|
||||
ngx_str_t *value;
|
||||
ngx_conf_t save;
|
||||
ngx_module_t **modules;
|
||||
ngx_rtmp_module_t *module;
|
||||
ngx_rtmp_core_app_conf_t *cacf, **pcacf, *rcacf;
|
||||
ngx_rtmp_record_app_conf_t *racf, **pracf, *rracf;
|
||||
|
@ -1248,17 +1266,22 @@ ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; ngx_modules[i]; i++) {
|
||||
if (ngx_modules[i]->type != NGX_RTMP_MODULE) {
|
||||
#if defined(nginx_version) && nginx_version >= 1009011
|
||||
modules = cf->cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
for (i = 0; modules[i]; i++) {
|
||||
if (modules[i]->type != NGX_RTMP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = ngx_modules[i]->ctx;
|
||||
module = modules[i]->ctx;
|
||||
|
||||
if (module->create_app_conf) {
|
||||
ctx->app_conf[ngx_modules[i]->ctx_index] =
|
||||
ctx->app_conf[modules[i]->ctx_index] =
|
||||
module->create_app_conf(cf);
|
||||
if (ctx->app_conf[ngx_modules[i]->ctx_index] == NULL) {
|
||||
if (ctx->app_conf[modules[i]->ctx_index] == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1302,6 +1325,8 @@ ngx_rtmp_record_postconfiguration(ngx_conf_t *cf)
|
|||
ngx_rtmp_core_main_conf_t *cmcf;
|
||||
ngx_rtmp_handler_pt *h;
|
||||
|
||||
ngx_rtmp_record_started = ngx_rtmp_record_started_init;
|
||||
|
||||
ngx_rtmp_record_done = ngx_rtmp_record_done_init;
|
||||
|
||||
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);
|
||||
|
|
|
@ -54,6 +54,7 @@ typedef struct {
|
|||
unsigned video_key_sent:1;
|
||||
unsigned audio:1;
|
||||
unsigned video:1;
|
||||
unsigned record_started:1;
|
||||
} ngx_rtmp_record_rec_ctx_t;
|
||||
|
||||
|
||||
|
@ -84,10 +85,23 @@ typedef struct {
|
|||
} ngx_rtmp_record_done_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t recorder;
|
||||
ngx_str_t path;
|
||||
} ngx_rtmp_record_started_t;
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_rtmp_record_started_pt)(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_record_started_t *v);
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_rtmp_record_done_pt)(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_record_done_t *v);
|
||||
|
||||
|
||||
extern ngx_rtmp_record_started_pt ngx_rtmp_record_started;
|
||||
|
||||
|
||||
extern ngx_rtmp_record_done_pt ngx_rtmp_record_done;
|
||||
|
||||
|
||||
|
|
|
@ -895,7 +895,7 @@ ngx_rtmp_create_fi(ngx_rtmp_session_t *s)
|
|||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_null_string,
|
||||
"onFi", 0 },
|
||||
"onFI", 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NUMBER,
|
||||
ngx_null_string,
|
||||
|
|
|
@ -66,7 +66,8 @@ ngx_rtmp_free_shared_chain(ngx_rtmp_core_srv_conf_t *cscf, ngx_chain_t *in)
|
|||
}
|
||||
|
||||
for (cl = in; ; cl = cl->next) {
|
||||
if (cl->next == NULL) {
|
||||
/* FIXME: Don't create circular chains in the first place */
|
||||
if (cl->next == NULL || cl->next == in) {
|
||||
cl->next = cscf->free;
|
||||
cscf->free = in;
|
||||
return;
|
||||
|
|
|
@ -555,7 +555,17 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
|
|||
NGX_RTMP_STAT_L("</height><frame_rate>");
|
||||
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
|
||||
"%.3f", codec->frame_rate) - buf);
|
||||
NGX_RTMP_STAT_L("</frame_rate>");
|
||||
NGX_RTMP_STAT_L("</frame_rate><data_rate>");
|
||||
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
|
||||
"%.0f", codec->video_data_rate) - buf);
|
||||
NGX_RTMP_STAT_L("</data_rate>");
|
||||
|
||||
if(codec->video_keyframe_frequency) {
|
||||
NGX_RTMP_STAT_L("<keyframe_frequency>");
|
||||
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
|
||||
"%.0f", codec->video_keyframe_frequency) - buf);
|
||||
NGX_RTMP_STAT_L("</keyframe_frequency>");
|
||||
}
|
||||
|
||||
cname = ngx_rtmp_get_video_codec_name(codec->video_codec_id);
|
||||
if (*cname) {
|
||||
|
@ -615,6 +625,12 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
|
|||
"%ui", codec->sample_rate) - buf);
|
||||
NGX_RTMP_STAT_L("</sample_rate>");
|
||||
}
|
||||
if (codec->audio_data_rate) {
|
||||
NGX_RTMP_STAT_L("<data_rate>");
|
||||
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
|
||||
"%0.0f", codec->audio_data_rate) - buf);
|
||||
NGX_RTMP_STAT_L("</data_rate>");
|
||||
}
|
||||
NGX_RTMP_STAT_L("</audio>");
|
||||
|
||||
NGX_RTMP_STAT_L("</meta>\r\n");
|
||||
|
@ -817,7 +833,10 @@ ngx_rtmp_stat_handler(ngx_http_request_t *r)
|
|||
#ifdef NGX_COMPILER
|
||||
NGX_RTMP_STAT_L("<compiler>" NGX_COMPILER "</compiler>\r\n");
|
||||
#endif
|
||||
/* This may prevent reproducible builds. If you need that info - pass `-DNGX_BUILD_DATEITIME=1` to CFLAGS */
|
||||
#ifdef NGX_BUILD_DATEITIME
|
||||
NGX_RTMP_STAT_L("<built>" __DATE__ " " __TIME__ "</built>\r\n");
|
||||
#endif
|
||||
|
||||
NGX_RTMP_STAT_L("<pid>");
|
||||
NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf),
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#define _NGX_RTMP_VERSION_H_INCLUDED_
|
||||
|
||||
|
||||
#define nginx_rtmp_version 1001007
|
||||
#define NGINX_RTMP_VERSION "1.1.7.10"
|
||||
#define nginx_rtmp_version 1002002
|
||||
#define NGINX_RTMP_VERSION "1.2.2-r1"
|
||||
|
||||
|
||||
#endif /* _NGX_RTMP_VERSION_H_INCLUDED_ */
|
||||
|
|
Loading…
Reference in a new issue