mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-05-09 14:11:07 +02:00
improved frame timing & added meta files
This commit is contained in:
parent
b9ee8dbe09
commit
1e9a7e6efc
8
AUTHORS
Normal file
8
AUTHORS
Normal file
|
@ -0,0 +1,8 @@
|
|||
Project author:
|
||||
|
||||
Roman Arutyunyan
|
||||
Moscow, Russia
|
||||
|
||||
Contacts:
|
||||
arut@qip.ru
|
||||
arutyunyan.roman@gmail.com
|
22
LICENSE
Normal file
22
LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2012, Roman Arutyunyan
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
README
37
README
|
@ -1 +1,36 @@
|
|||
This is an early version of module
|
||||
==nginx-rtmp-module==
|
||||
|
||||
NGINX-based RTMP server
|
||||
|
||||
* Live streaming of video/audio
|
||||
|
||||
* Advanced buffering techniques
|
||||
to keep memory allocations at a minimum
|
||||
level for faster streaming and low
|
||||
memory footprint
|
||||
|
||||
* Works with Flash RTMP clients as well as
|
||||
ffmpeg/rtmpdump/flvstreamer etc
|
||||
(see examples in test/ subdir)
|
||||
|
||||
|
||||
Example nginx.conf:
|
||||
|
||||
|
||||
rtmp {
|
||||
|
||||
server {
|
||||
|
||||
listen 1935;
|
||||
|
||||
wait_key_frame on;
|
||||
|
||||
chunk_size 128;
|
||||
|
||||
max_buf 1000000;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
(c) 2012 Roman Arutyunyan
|
||||
|
||||
|
|
15
TODO
15
TODO
|
@ -1,22 +1,13 @@
|
|||
- implement chain-reuse for output
|
||||
- add support of flv file streaming
|
||||
|
||||
- move shared bufs-related code to a separate .c
|
||||
- compile in release configuration
|
||||
|
||||
- get rid of greedy send_chain
|
||||
- add RTMP authorization
|
||||
|
||||
- remove macros hell from ngx_rtmp_send.c
|
||||
|
||||
- packet dropping
|
||||
|
||||
- l <-> cl
|
||||
|
||||
- closing session on send error
|
||||
causes crash because of double-freeing stack
|
||||
|
||||
- add max message size
|
||||
|
||||
- recognize amf-meta
|
||||
|
||||
- shortcuts for big-endian copy
|
||||
|
||||
- implement loc confs (=fms apps)
|
||||
|
|
|
@ -261,19 +261,28 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_rtmp_broadcast_ctx_t *ctx, *cctx;
|
||||
ngx_rtmp_broadcast_ctx_t *ctx, *cctx, *cnext;
|
||||
ngx_chain_t *out;
|
||||
ngx_rtmp_core_srv_conf_t *cscf;
|
||||
ngx_rtmp_header_t sh;
|
||||
ngx_rtmp_session_t *ss;
|
||||
ngx_rtmp_header_t sh;
|
||||
ngx_uint_t priority;
|
||||
ngx_int_t rc;
|
||||
int keyframe;
|
||||
|
||||
c = s->connection;
|
||||
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module);
|
||||
|
||||
sh = *h;
|
||||
memset(&sh, 0, sizeof(sh));
|
||||
sh.timestamp = h->timestamp + s->epoch;
|
||||
sh.msid = NGX_RTMP_BROADCAST_MSID;
|
||||
sh.type = h->type;
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, c->log, 0,
|
||||
"av packet; peer_epoch=%uD; my_epoch=%uD timestamp=%uD; r=%uD",
|
||||
s->peer_epoch, s->epoch, h->timestamp, sh.timestamp);
|
||||
|
||||
keyframe = 0;
|
||||
if (h->type == NGX_RTMP_MSG_VIDEO) {
|
||||
sh.csid = NGX_RTMP_BROADCAST_CSID_VIDEO;
|
||||
|
@ -282,9 +291,12 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
keyframe = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (h->type == NGX_RTMP_MSG_AUDIO) {
|
||||
sh.csid = NGX_RTMP_BROADCAST_CSID_AUDIO;
|
||||
priority = NGX_RTMP_AUDIO_FRAME;
|
||||
|
||||
} else {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ctx == NULL
|
||||
|
@ -304,9 +316,11 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_rtmp_prepare_message(s, &sh, NULL, out);
|
||||
|
||||
/* broadcast to all subscribers */
|
||||
for (cctx = *ngx_rtmp_broadcast_get_head(s);
|
||||
cctx; cctx = cctx->next)
|
||||
{
|
||||
for (cctx = *ngx_rtmp_broadcast_get_head(s); cctx; cctx = cnext) {
|
||||
/* session can die further in loop
|
||||
* so save next ptr while it's not too late */
|
||||
cnext = cctx->next;
|
||||
|
||||
if (cctx != ctx
|
||||
&& cctx->flags & NGX_RTMP_BROADCAST_SUBSCRIBER
|
||||
&& cctx->stream.len == ctx->stream.len
|
||||
|
@ -317,21 +331,19 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
/* if we have metadata check if the subscriber
|
||||
* has already received one */
|
||||
if (ctx->data_frame
|
||||
if (ctx->data_frame && 0
|
||||
&& !(cctx->flags & NGX_RTMP_BROADCAST_DATA_FRAME))
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"sending data_frame");
|
||||
|
||||
switch (ngx_rtmp_send_message(ss, ctx->data_frame, 0)) {
|
||||
case NGX_OK:
|
||||
cctx->flags |= NGX_RTMP_BROADCAST_DATA_FRAME;
|
||||
break;
|
||||
case NGX_AGAIN:
|
||||
break;
|
||||
default:
|
||||
ngx_log_error(NGX_LOG_INFO, ss->connection->log, 0,
|
||||
"error sending message");
|
||||
rc = ngx_rtmp_send_message(ss, ctx->data_frame, 0);
|
||||
if (rc == NGX_ERROR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
cctx->flags |= NGX_RTMP_BROADCAST_DATA_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,13 +356,13 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ngx_rtmp_send_message(ss, out, priority) == NGX_OK) {
|
||||
if (keyframe) {
|
||||
cctx->flags |= NGX_RTMP_BROADCAST_KEYFRAME;
|
||||
}
|
||||
} else {
|
||||
ngx_log_error(NGX_LOG_INFO, ss->connection->log, 0,
|
||||
"error sending message");
|
||||
if (ngx_rtmp_send_message(ss, out, priority) == NGX_OK
|
||||
&& keyframe
|
||||
&& !(cctx->flags & NGX_RTMP_BROADCAST_KEYFRAME))
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"keyframe sent");
|
||||
cctx->flags |= NGX_RTMP_BROADCAST_KEYFRAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -697,8 +709,8 @@ ngx_rtmp_broadcast_set_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
memset(&sh, 0, sizeof(sh));
|
||||
sh.csid = NGX_RTMP_BROADCAST_CSID_AMF0;
|
||||
sh.msid = h->msid;
|
||||
sh.type = h->type;
|
||||
sh.msid = NGX_RTMP_BROADCAST_MSID;
|
||||
sh.type = NGX_RTMP_MSG_AMF0_META;
|
||||
|
||||
ngx_rtmp_prepare_message(s, h, NULL, ctx->data_frame);
|
||||
|
||||
|
@ -715,7 +727,7 @@ ngx_rtmp_broadcast_ok(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
static double trans;
|
||||
|
||||
static ngx_rtmp_amf0_elt_t in_elts[] = {
|
||||
{ NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) },
|
||||
{ NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) },
|
||||
};
|
||||
|
||||
static ngx_rtmp_amf0_elt_t out_elts[] = {
|
||||
|
@ -733,9 +745,9 @@ ngx_rtmp_broadcast_ok(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
}
|
||||
|
||||
memset(&sh, 0, sizeof(sh));
|
||||
sh.csid = NGX_RTMP_BROADCAST_CSID_AMF0;
|
||||
sh.type = NGX_RTMP_MSG_AMF0_META;
|
||||
sh.msid = h->msid;
|
||||
sh.csid = h->csid;/*NGX_RTMP_BROADCAST_CSID_AMF0;*/
|
||||
sh.type = NGX_RTMP_MSG_AMF0_CMD;
|
||||
sh.msid = 0;//NGX_RTMP_BROADCAST_MSID;
|
||||
|
||||
/* send simple _result */
|
||||
return ngx_rtmp_send_amf0(s, &sh, out_elts,
|
||||
|
|
|
@ -264,8 +264,8 @@ ngx_rtmp_get_timestamp()
|
|||
|
||||
tod = ngx_timeofday();
|
||||
|
||||
return (uint32_t)tod->sec * 1e3
|
||||
+ (uint32_t)tod->msec / 1e3;
|
||||
/* FIXME: divisor */
|
||||
return (uint32_t)(tod->sec * 1000 + tod->msec / 1000) % 0x00ffffff;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,9 +126,9 @@ ngx_rtmp_user_message_handler(ngx_rtmp_session_t *s,
|
|||
p[2] = b->pos[7];
|
||||
p[3] = b->pos[6];
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* use =val as stream id && arg as buflen in msec*/
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, c->log, 0,
|
||||
"msid=%uD buflen: %uD (msec)", val, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ rtmp {
|
|||
|
||||
listen 1935;
|
||||
|
||||
wait_key_frame on;
|
||||
# wait_key_frame on;
|
||||
|
||||
chunk_size 128;
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
<div id="container">Loading the player ...</div>
|
||||
<script type="text/javascript">
|
||||
jwplayer("container").setup({
|
||||
image: "http://10.31.1.78/showme.jpg",
|
||||
modes: [
|
||||
{ type: "flash",
|
||||
src: "/jwplayer/player.swf",
|
||||
config: {
|
||||
file: "video.mp4",
|
||||
streamer: "rtmp://10.31.1.78/helo",
|
||||
provider: "rtmp"
|
||||
bufferlength: 3,
|
||||
file: "livepresentation",
|
||||
streamer: "rtmp://192.168.0.100/helo",
|
||||
provider: "rtmp",
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<a href="index.html">Play</a> | <b>Record</b>
|
||||
<br/>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="jwplayer_old/swfobject.js"></script>
|
||||
<script type="text/javascript">
|
||||
var flashvars =
|
||||
|
|
Loading…
Reference in a new issue