├── test ├── dump.sh ├── play.sh ├── www │ ├── bg.jpg │ ├── jwplayer_old │ │ ├── player.swf │ │ └── swfobject.js │ ├── jwplayer │ │ └── jwplayer.flash.swf │ ├── index.html │ └── record.html ├── ffstream.sh ├── rtmp-publisher │ ├── RtmpPlayer.swf │ ├── RtmpPublisher.swf │ ├── RtmpPlayerLight.swf │ ├── README.md │ ├── publisher.html │ ├── player.html │ ├── RtmpPlayer.mxml │ ├── RtmpPublisher.mxml │ ├── RtmpPlayerLight.mxml │ └── swfobject.js ├── README.md └── nginx.conf ├── doc └── README.md ├── AUTHORS ├── ngx_rtmp_version.h ├── ngx_rtmp_proxy_protocol.h ├── ngx_rtmp_streams.h ├── ngx_rtmp_bandwidth.c ├── ngx_rtmp_bandwidth.h ├── ngx_rtmp_eval.h ├── hls ├── ngx_rtmp_mpegts.h └── ngx_rtmp_mpegts.c ├── LICENSE ├── ngx_rtmp_bitop.h ├── dash └── ngx_rtmp_mp4.h ├── ngx_rtmp_bitop.c ├── ngx_rtmp_amf.h ├── ngx_rtmp_netcall_module.h ├── ngx_rtmp_relay_module.h ├── ngx_rtmp_play_module.h ├── ngx_rtmp_codec_module.h ├── ngx_rtmp_live_module.h ├── ngx_rtmp_shared.c ├── ngx_rtmp_record_module.h ├── ngx_rtmp_proxy_protocol.c ├── ngx_rtmp_cmd_module.h ├── config ├── ngx_rtmp_limit_module.c ├── ngx_rtmp_eval.c ├── ngx_rtmp_init.c ├── README.md ├── stat.xsl ├── ngx_rtmp_receive.c ├── ngx_rtmp_access_module.c ├── ngx_rtmp_send.c └── ngx_rtmp_amf.c /test/dump.sh: -------------------------------------------------------------------------------- 1 | rtmpdump -v -r "rtmp://localhost/myapp/mystream" 2 | -------------------------------------------------------------------------------- /test/play.sh: -------------------------------------------------------------------------------- 1 | ffplay -loglevel verbose "rtmp://localhost/myapp/mystream" 2 | -------------------------------------------------------------------------------- /test/www/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/www/bg.jpg -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | Documentation is available here: 2 | https://github.com/arut/nginx-rtmp-module/wiki 3 | -------------------------------------------------------------------------------- /test/ffstream.sh: -------------------------------------------------------------------------------- 1 | ffmpeg -loglevel verbose -re -i ~/movie.avi -f flv rtmp://localhost/myapp/mystream 2 | -------------------------------------------------------------------------------- /test/www/jwplayer_old/player.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/www/jwplayer_old/player.swf -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPlayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/rtmp-publisher/RtmpPlayer.swf -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPublisher.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/rtmp-publisher/RtmpPublisher.swf -------------------------------------------------------------------------------- /test/www/jwplayer/jwplayer.flash.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/www/jwplayer/jwplayer.flash.swf -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPlayerLight.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adwpc/nginx-rtmp-module/HEAD/test/rtmp-publisher/RtmpPlayerLight.swf -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Project author: 2 | 3 | Roman Arutyunyan 4 | Moscow, Russia 5 | 6 | Contacts: 7 | arut@qip.ru 8 | arutyunyan.roman@gmail.com 9 | -------------------------------------------------------------------------------- /ngx_rtmp_version.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_VERSION_H_INCLUDED_ 8 | #define _NGX_RTMP_VERSION_H_INCLUDED_ 9 | 10 | 11 | #define nginx_rtmp_version 1001004 12 | #define NGINX_RTMP_VERSION "1.1.4" 13 | 14 | 15 | #endif /* _NGX_RTMP_VERSION_H_INCLUDED_ */ 16 | -------------------------------------------------------------------------------- /test/rtmp-publisher/README.md: -------------------------------------------------------------------------------- 1 | # RTMP Publisher 2 | 3 | Simple RTMP publisher. 4 | 5 | Edit the following flashvars in publisher.html & player.html to suite your needs. 6 | 7 | streamer: RTMP endpoint 8 | file: live stream name 9 | 10 | ## Compile 11 | 12 | Install flex sdk http://www.adobe.com/devnet/flex/flex-sdk-download.html 13 | 14 | mxmlc RtmpPublisher.mxml 15 | mxmlc RtmpPlayer.mxml 16 | -------------------------------------------------------------------------------- /ngx_rtmp_proxy_protocol.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ 8 | #define _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | void ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *c); 17 | 18 | 19 | #endif /* _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ */ 20 | -------------------------------------------------------------------------------- /ngx_rtmp_streams.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_STREAMS_H_INCLUDED_ 8 | #define _NGX_RTMP_STREAMS_H_INCLUDED_ 9 | 10 | 11 | #define NGX_RTMP_MSID 1 12 | 13 | #define NGX_RTMP_CSID_AMF_INI 3 14 | #define NGX_RTMP_CSID_AMF 5 15 | #define NGX_RTMP_CSID_AUDIO 6 16 | #define NGX_RTMP_CSID_VIDEO 7 17 | 18 | 19 | #endif /* _NGX_RTMP_STREAMS_H_INCLUDED_ */ 20 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # RTMP tests 2 | 3 | nginx.conf is sample config for testing nginx-rtmp. 4 | Please update paths in it before using. 5 | 6 | RTMP port: 1935, HTTP port: 8080 7 | 8 | * http://localhost:8080/ - play myapp/mystream with JWPlayer 9 | * http://localhost:8080/record.html - capture myapp/mystream from webcam with old JWPlayer 10 | * http://localhost:8080/rtmp-publisher/player.html - play myapp/mystream with the test flash applet 11 | * http://localhost:8080/rtmp-publisher/publisher.html - capture myapp/mystream with the test flash applet 12 | -------------------------------------------------------------------------------- /test/www/index.html: -------------------------------------------------------------------------------- 1 | Play | Record 2 |
3 | 4 | 5 |
Loading the player ...
6 | 20 | -------------------------------------------------------------------------------- /test/rtmp-publisher/publisher.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RTMP Publisher 5 | 6 | 13 | 14 | 15 |
16 |

Flash not installed

17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /ngx_rtmp_bandwidth.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp_bandwidth.h" 10 | 11 | 12 | void 13 | ngx_rtmp_update_bandwidth(ngx_rtmp_bandwidth_t *bw, uint32_t bytes) 14 | { 15 | if (ngx_cached_time->sec > bw->intl_end) { 16 | bw->bandwidth = ngx_cached_time->sec > 17 | bw->intl_end + NGX_RTMP_BANDWIDTH_INTERVAL 18 | ? 0 19 | : bw->intl_bytes / NGX_RTMP_BANDWIDTH_INTERVAL; 20 | bw->intl_bytes = 0; 21 | bw->intl_end = ngx_cached_time->sec + NGX_RTMP_BANDWIDTH_INTERVAL; 22 | } 23 | 24 | bw->bytes += bytes; 25 | bw->intl_bytes += bytes; 26 | } 27 | -------------------------------------------------------------------------------- /test/rtmp-publisher/player.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RTMP Player 5 | 6 | 16 | 17 | 18 |
19 |

Flash not installed

20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /ngx_rtmp_bandwidth.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_BANDWIDTH_H_INCLUDED_ 8 | #define _NGX_RTMP_BANDWIDTH_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* Bandwidth update interval in seconds */ 16 | #define NGX_RTMP_BANDWIDTH_INTERVAL 10 17 | 18 | 19 | typedef struct { 20 | uint64_t bytes; 21 | uint64_t bandwidth; /* bytes/sec */ 22 | 23 | time_t intl_end; 24 | uint64_t intl_bytes; 25 | } ngx_rtmp_bandwidth_t; 26 | 27 | 28 | void ngx_rtmp_update_bandwidth(ngx_rtmp_bandwidth_t *bw, uint32_t bytes); 29 | 30 | 31 | #endif /* _NGX_RTMP_BANDWIDTH_H_INCLUDED_ */ 32 | -------------------------------------------------------------------------------- /ngx_rtmp_eval.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_EVAL_H_INCLUDED_ 8 | #define _NGX_RTMP_EVAL_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | typedef struct ngx_rtmp_eval_s ngx_rtmp_eval_t; 17 | 18 | 19 | typedef void (* ngx_rtmp_eval_pt)(void *ctx, ngx_rtmp_eval_t *e, 20 | ngx_str_t *ret); 21 | 22 | 23 | struct ngx_rtmp_eval_s { 24 | ngx_str_t name; 25 | ngx_rtmp_eval_pt handler; 26 | ngx_uint_t offset; 27 | }; 28 | 29 | 30 | #define ngx_rtmp_null_eval { ngx_null_string, NULL, 0 } 31 | 32 | 33 | /* standard session eval variables */ 34 | extern ngx_rtmp_eval_t ngx_rtmp_eval_session[]; 35 | 36 | 37 | ngx_int_t ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, 38 | ngx_str_t *out, ngx_log_t *log); 39 | 40 | 41 | ngx_int_t ngx_rtmp_eval_streams(ngx_str_t *in); 42 | 43 | 44 | #endif /* _NGX_RTMP_EVAL_H_INCLUDED_ */ 45 | -------------------------------------------------------------------------------- /hls/ngx_rtmp_mpegts.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_MPEGTS_H_INCLUDED_ 8 | #define _NGX_RTMP_MPEGTS_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | typedef struct { 17 | ngx_fd_t fd; 18 | ngx_log_t *log; 19 | unsigned encrypt:1; 20 | unsigned size:4; 21 | u_char buf[16]; 22 | u_char iv[16]; 23 | AES_KEY key; 24 | unsigned video_codec_id; 25 | } ngx_rtmp_mpegts_file_t; 26 | 27 | 28 | typedef struct { 29 | uint64_t pts; 30 | uint64_t dts; 31 | ngx_uint_t pid; 32 | ngx_uint_t sid; 33 | ngx_uint_t cc; 34 | unsigned key:1; 35 | } ngx_rtmp_mpegts_frame_t; 36 | 37 | 38 | ngx_int_t ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file, 39 | u_char *key, size_t key_len, uint64_t iv); 40 | ngx_int_t ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, 41 | ngx_log_t *log); 42 | ngx_int_t ngx_rtmp_mpegts_close_file(ngx_rtmp_mpegts_file_t *file); 43 | ngx_int_t ngx_rtmp_mpegts_write_frame(ngx_rtmp_mpegts_file_t *file, 44 | ngx_rtmp_mpegts_frame_t *f, ngx_buf_t *b); 45 | 46 | 47 | #endif /* _NGX_RTMP_MPEGTS_H_INCLUDED_ */ 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014, Roman Arutyunyan 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /ngx_rtmp_bitop.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_BITOP_H_INCLUDED_ 8 | #define _NGX_RTMP_BITOP_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | 14 | 15 | typedef struct { 16 | u_char *pos; 17 | u_char *last; 18 | ngx_uint_t offs; 19 | ngx_uint_t err; 20 | } ngx_rtmp_bit_reader_t; 21 | 22 | void ngx_rtmp_hex_dump(ngx_log_t *log,const char * tag,u_char * start, u_char * end); 23 | 24 | void ngx_rtmp_bit_init_reader(ngx_rtmp_bit_reader_t *br, u_char *pos, 25 | u_char *last); 26 | uint64_t ngx_rtmp_bit_read(ngx_rtmp_bit_reader_t *br, ngx_uint_t n); 27 | uint64_t ngx_rtmp_bit_read_golomb(ngx_rtmp_bit_reader_t *br); 28 | 29 | 30 | #define ngx_rtmp_bit_read_err(br) ((br)->err) 31 | 32 | #define ngx_rtmp_bit_read_eof(br) ((br)->pos == (br)->last) 33 | 34 | #define ngx_rtmp_bit_read_8(br) \ 35 | ((uint8_t) ngx_rtmp_bit_read(br, 8)) 36 | 37 | #define ngx_rtmp_bit_read_16(br) \ 38 | ((uint16_t) ngx_rtmp_bit_read(br, 16)) 39 | 40 | #define ngx_rtmp_bit_read_32(br) \ 41 | ((uint32_t) ngx_rtmp_bit_read(br, 32)) 42 | 43 | #define ngx_rtmp_bit_read_64(br) \ 44 | ((uint64_t) ngx_rtmp_read(br, 64)) 45 | 46 | 47 | #endif /* _NGX_RTMP_BITOP_H_INCLUDED_ */ 48 | -------------------------------------------------------------------------------- /test/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log logs/error.log debug; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | 9 | rtmp { 10 | server { 11 | listen 1935; 12 | 13 | application myapp { 14 | live on; 15 | 16 | #record keyframes; 17 | #record_path /tmp; 18 | #record_max_size 128K; 19 | #record_interval 30s; 20 | #record_suffix .this.is.flv; 21 | 22 | #on_publish http://localhost:8080/publish; 23 | #on_play http://localhost:8080/play; 24 | #on_record_done http://localhost:8080/record_done; 25 | } 26 | } 27 | } 28 | 29 | http { 30 | server { 31 | listen 8080; 32 | 33 | location /stat { 34 | rtmp_stat all; 35 | rtmp_stat_stylesheet stat.xsl; 36 | } 37 | 38 | location /stat.xsl { 39 | root /path/to/nginx-rtmp-module/; 40 | } 41 | 42 | location /control { 43 | rtmp_control all; 44 | } 45 | 46 | #location /publish { 47 | # return 201; 48 | #} 49 | 50 | #location /play { 51 | # return 202; 52 | #} 53 | 54 | #location /record_done { 55 | # return 203; 56 | #} 57 | 58 | location /rtmp-publisher { 59 | root /path/to/nginx-rtmp-module/test; 60 | } 61 | 62 | location / { 63 | root /path/to/nginx-rtmp-module/test/www; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /dash/ngx_rtmp_mp4.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _NGX_RTMP_MP4_H_INCLUDED_ 4 | #define _NGX_RTMP_MP4_H_INCLUDED_ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define NGX_RTMP_MP4_SAMPLE_SIZE 0x01 13 | #define NGX_RTMP_MP4_SAMPLE_DURATION 0x02 14 | #define NGX_RTMP_MP4_SAMPLE_DELAY 0x04 15 | #define NGX_RTMP_MP4_SAMPLE_KEY 0x08 16 | 17 | 18 | typedef struct { 19 | uint32_t size; 20 | uint32_t duration; 21 | uint32_t delay; 22 | uint32_t timestamp; 23 | unsigned key:1; 24 | } ngx_rtmp_mp4_sample_t; 25 | 26 | 27 | typedef enum { 28 | NGX_RTMP_MP4_FILETYPE_INIT, 29 | NGX_RTMP_MP4_FILETYPE_SEG 30 | } ngx_rtmp_mp4_file_type_t; 31 | 32 | 33 | typedef enum { 34 | NGX_RTMP_MP4_VIDEO_TRACK, 35 | NGX_RTMP_MP4_AUDIO_TRACK 36 | } ngx_rtmp_mp4_track_type_t; 37 | 38 | 39 | ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b); 40 | ngx_int_t ngx_rtmp_mp4_write_styp(ngx_buf_t *b); 41 | ngx_int_t ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, 42 | ngx_rtmp_mp4_track_type_t ttype); 43 | ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, uint32_t earliest_pres_time, 44 | uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, 45 | ngx_uint_t sample_mask, uint32_t index); 46 | ngx_int_t ngx_rtmp_mp4_write_sidx(ngx_buf_t *b, 47 | ngx_uint_t reference_size, uint32_t earliest_pres_time, 48 | uint32_t latest_pres_time); 49 | ngx_uint_t ngx_rtmp_mp4_write_mdat(ngx_buf_t *b, ngx_uint_t size); 50 | 51 | 52 | #endif /* _NGX_RTMP_MP4_H_INCLUDED_ */ 53 | -------------------------------------------------------------------------------- /test/www/record.html: -------------------------------------------------------------------------------- 1 | Play | Record 2 |
3 | 4 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ngx_rtmp_bitop.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp_bitop.h" 10 | 11 | 12 | //ngx_log_debug increase buffer, e.g.: 13 | //sed -i 's/#define NGX_MAX_ERROR_STR 2048/#define NGX_MAX_ERROR_STR 1024*1024/' ./src/core/ngx_log.h 14 | void 15 | ngx_rtmp_hex_dump(ngx_log_t *log, const char * tag, u_char * start, u_char * end) 16 | { 17 | u_char buf[1024*1024], *p, *pp; 18 | u_char hex[] = "0123456789abcdef"; 19 | 20 | for (pp = buf, p = start; 21 | p < end && pp < buf + sizeof(buf) - 1; 22 | ++p) 23 | { 24 | *pp++ = hex[*p >> 4]; 25 | *pp++ = hex[*p & 0x0f]; 26 | *pp++ = ' '; 27 | } 28 | 29 | *pp = 0; 30 | 31 | ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, "[hex][%s][%s] ", tag, buf); 32 | } 33 | 34 | 35 | 36 | void 37 | ngx_rtmp_bit_init_reader(ngx_rtmp_bit_reader_t *br, u_char *pos, u_char *last) 38 | { 39 | ngx_memzero(br, sizeof(ngx_rtmp_bit_reader_t)); 40 | 41 | br->pos = pos; 42 | br->last = last; 43 | } 44 | 45 | 46 | uint64_t 47 | ngx_rtmp_bit_read(ngx_rtmp_bit_reader_t *br, ngx_uint_t n) 48 | { 49 | uint64_t v; 50 | ngx_uint_t d; 51 | 52 | v = 0; 53 | 54 | while (n) { 55 | 56 | if (br->pos >= br->last) { 57 | br->err = 1; 58 | return 0; 59 | } 60 | 61 | d = (br->offs + n > 8 ? (ngx_uint_t) (8 - br->offs) : n); 62 | 63 | v <<= d; 64 | v += (*br->pos >> (8 - br->offs - d)) & ((u_char) 0xff >> (8 - d)); 65 | 66 | br->offs += d; 67 | n -= d; 68 | 69 | if (br->offs == 8) { 70 | br->pos++; 71 | br->offs = 0; 72 | } 73 | } 74 | 75 | return v; 76 | } 77 | 78 | 79 | uint64_t 80 | ngx_rtmp_bit_read_golomb(ngx_rtmp_bit_reader_t *br) 81 | { 82 | ngx_uint_t n; 83 | 84 | for (n = 0; ngx_rtmp_bit_read(br, 1) == 0 && !br->err; n++); 85 | 86 | return ((uint64_t) 1 << n) + ngx_rtmp_bit_read(br, n) - 1; 87 | } 88 | -------------------------------------------------------------------------------- /ngx_rtmp_amf.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_AMF_H_INCLUDED_ 8 | #define _NGX_RTMP_AMF_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* basic types */ 16 | #define NGX_RTMP_AMF_NUMBER 0x00 17 | #define NGX_RTMP_AMF_BOOLEAN 0x01 18 | #define NGX_RTMP_AMF_STRING 0x02 19 | #define NGX_RTMP_AMF_OBJECT 0x03 20 | #define NGX_RTMP_AMF_NULL 0x05 21 | #define NGX_RTMP_AMF_ARRAY_NULL 0x06 22 | #define NGX_RTMP_AMF_MIXED_ARRAY 0x08 23 | #define NGX_RTMP_AMF_END 0x09 24 | #define NGX_RTMP_AMF_ARRAY 0x0a 25 | 26 | /* extended types */ 27 | #define NGX_RTMP_AMF_INT8 0x0100 28 | #define NGX_RTMP_AMF_INT16 0x0101 29 | #define NGX_RTMP_AMF_INT32 0x0102 30 | #define NGX_RTMP_AMF_VARIANT_ 0x0103 31 | 32 | /* r/w flags */ 33 | #define NGX_RTMP_AMF_OPTIONAL 0x1000 34 | #define NGX_RTMP_AMF_TYPELESS 0x2000 35 | #define NGX_RTMP_AMF_CONTEXT 0x4000 36 | 37 | #define NGX_RTMP_AMF_VARIANT (NGX_RTMP_AMF_VARIANT_\ 38 | |NGX_RTMP_AMF_TYPELESS) 39 | 40 | 41 | typedef struct { 42 | ngx_int_t type; 43 | ngx_str_t name; 44 | void *data; 45 | size_t len; 46 | } ngx_rtmp_amf_elt_t; 47 | 48 | 49 | typedef ngx_chain_t * (*ngx_rtmp_amf_alloc_pt)(void *arg); 50 | 51 | 52 | typedef struct { 53 | ngx_chain_t *link, *first; 54 | size_t offset; 55 | ngx_rtmp_amf_alloc_pt alloc; 56 | void *arg; 57 | ngx_log_t *log; 58 | } ngx_rtmp_amf_ctx_t; 59 | 60 | 61 | /* reading AMF */ 62 | ngx_int_t ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, 63 | ngx_rtmp_amf_elt_t *elts, size_t nelts); 64 | 65 | /* writing AMF */ 66 | ngx_int_t ngx_rtmp_amf_write(ngx_rtmp_amf_ctx_t *ctx, 67 | ngx_rtmp_amf_elt_t *elts, size_t nelts); 68 | 69 | 70 | #endif /* _NGX_RTMP_AMF_H_INCLUDED_ */ 71 | 72 | -------------------------------------------------------------------------------- /ngx_rtmp_netcall_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_NETCALL_H_INCLUDED_ 8 | #define _NGX_RTMP_NETCALL_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | typedef ngx_chain_t * (*ngx_rtmp_netcall_create_pt)(ngx_rtmp_session_t *s, 17 | void *arg, ngx_pool_t *pool); 18 | typedef ngx_int_t (*ngx_rtmp_netcall_filter_pt)(ngx_chain_t *in); 19 | typedef ngx_int_t (*ngx_rtmp_netcall_sink_pt)(ngx_rtmp_session_t *s, 20 | ngx_chain_t *in); 21 | typedef ngx_int_t (*ngx_rtmp_netcall_handle_pt)(ngx_rtmp_session_t *s, 22 | void *arg, ngx_chain_t *in); 23 | 24 | #define NGX_RTMP_NETCALL_HTTP_GET 0 25 | #define NGX_RTMP_NETCALL_HTTP_POST 1 26 | 27 | 28 | /* If handle is NULL then netcall is created detached 29 | * which means it's completely independent of RTMP 30 | * session and its result is never visible to anyone. 31 | * 32 | * WARNING: It's not recommended to create non-detached 33 | * netcalls from disconect handlers. Netcall disconnect 34 | * handler which detaches active netcalls is executed 35 | * BEFORE your handler. It leads to a crash 36 | * after netcall connection is closed */ 37 | typedef struct { 38 | ngx_url_t *url; 39 | ngx_rtmp_netcall_create_pt create; 40 | ngx_rtmp_netcall_filter_pt filter; 41 | ngx_rtmp_netcall_sink_pt sink; 42 | ngx_rtmp_netcall_handle_pt handle; 43 | void *arg; 44 | size_t argsize; 45 | } ngx_rtmp_netcall_init_t; 46 | 47 | 48 | ngx_int_t ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, 49 | ngx_rtmp_netcall_init_t *ci); 50 | 51 | 52 | /* HTTP handling */ 53 | ngx_chain_t * ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, 54 | ngx_pool_t *pool); 55 | ngx_chain_t * ngx_rtmp_netcall_http_format_request(ngx_int_t method, 56 | ngx_str_t *host, ngx_str_t *uri, ngx_chain_t *args, ngx_chain_t *body, 57 | ngx_pool_t *pool, ngx_str_t *content_type); 58 | ngx_chain_t * ngx_rtmp_netcall_http_skip_header(ngx_chain_t *in); 59 | 60 | 61 | /* Memcache handling */ 62 | ngx_chain_t * ngx_rtmp_netcall_memcache_set(ngx_rtmp_session_t *s, 63 | ngx_pool_t *pool, ngx_str_t *key, ngx_str_t *value, 64 | ngx_uint_t flags, ngx_uint_t sec); 65 | 66 | 67 | #endif /* _NGX_RTMP_NETCALL_H_INCLUDED_ */ 68 | -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPlayer.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /ngx_rtmp_relay_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_RELAY_H_INCLUDED_ 8 | #define _NGX_RTMP_RELAY_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | typedef struct { 17 | ngx_url_t url; 18 | ngx_str_t app; 19 | ngx_str_t name; 20 | ngx_str_t tc_url; 21 | ngx_str_t page_url; 22 | ngx_str_t swf_url; 23 | ngx_str_t flash_ver; 24 | ngx_str_t play_path; 25 | ngx_int_t live; 26 | ngx_int_t start; 27 | ngx_int_t stop; 28 | 29 | void *tag; /* usually module reference */ 30 | void *data; /* module-specific data */ 31 | ngx_uint_t counter; /* mutable connection counter */ 32 | } ngx_rtmp_relay_target_t; 33 | 34 | 35 | typedef struct ngx_rtmp_relay_ctx_s ngx_rtmp_relay_ctx_t; 36 | 37 | struct ngx_rtmp_relay_ctx_s { 38 | ngx_str_t name; 39 | ngx_str_t url; 40 | ngx_log_t log; 41 | ngx_rtmp_session_t *session; 42 | ngx_rtmp_relay_ctx_t *publish; 43 | ngx_rtmp_relay_ctx_t *play; 44 | ngx_rtmp_relay_ctx_t *next; 45 | 46 | ngx_str_t app; 47 | ngx_str_t tc_url; 48 | ngx_str_t page_url; 49 | ngx_str_t swf_url; 50 | ngx_str_t flash_ver; 51 | ngx_str_t play_path; 52 | ngx_int_t live; 53 | ngx_int_t start; 54 | ngx_int_t stop; 55 | 56 | ngx_event_t push_evt; 57 | ngx_event_t *static_evt; 58 | void *tag; 59 | void *data; 60 | }; 61 | 62 | 63 | extern ngx_module_t ngx_rtmp_relay_module; 64 | 65 | 66 | ngx_int_t ngx_rtmp_relay_pull(ngx_rtmp_session_t *s, ngx_str_t *name, 67 | ngx_rtmp_relay_target_t *target); 68 | ngx_int_t ngx_rtmp_relay_push(ngx_rtmp_session_t *s, ngx_str_t *name, 69 | ngx_rtmp_relay_target_t *target); 70 | 71 | 72 | #endif /* _NGX_RTMP_RELAY_H_INCLUDED_ */ 73 | -------------------------------------------------------------------------------- /ngx_rtmp_play_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_PLAY_H_INCLUDED_ 8 | #define _NGX_RTMP_PLAY_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | #include "ngx_rtmp_cmd_module.h" 15 | 16 | 17 | typedef ngx_int_t (*ngx_rtmp_play_init_pt) (ngx_rtmp_session_t *s, 18 | ngx_file_t *f, ngx_int_t aindex, ngx_int_t vindex); 19 | typedef ngx_int_t (*ngx_rtmp_play_done_pt) (ngx_rtmp_session_t *s, 20 | ngx_file_t *f); 21 | typedef ngx_int_t (*ngx_rtmp_play_start_pt) (ngx_rtmp_session_t *s, 22 | ngx_file_t *f); 23 | typedef ngx_int_t (*ngx_rtmp_play_seek_pt) (ngx_rtmp_session_t *s, 24 | ngx_file_t *f, ngx_uint_t offs); 25 | typedef ngx_int_t (*ngx_rtmp_play_stop_pt) (ngx_rtmp_session_t *s, 26 | ngx_file_t *f); 27 | typedef ngx_int_t (*ngx_rtmp_play_send_pt) (ngx_rtmp_session_t *s, 28 | ngx_file_t *f, ngx_uint_t *ts); 29 | 30 | 31 | typedef struct { 32 | ngx_str_t name; 33 | ngx_str_t pfx; 34 | ngx_str_t sfx; 35 | 36 | ngx_rtmp_play_init_pt init; 37 | ngx_rtmp_play_done_pt done; 38 | ngx_rtmp_play_start_pt start; 39 | ngx_rtmp_play_seek_pt seek; 40 | ngx_rtmp_play_stop_pt stop; 41 | ngx_rtmp_play_send_pt send; 42 | } ngx_rtmp_play_fmt_t; 43 | 44 | 45 | typedef struct ngx_rtmp_play_ctx_s ngx_rtmp_play_ctx_t; 46 | 47 | 48 | struct ngx_rtmp_play_ctx_s { 49 | ngx_rtmp_session_t *session; 50 | ngx_file_t file; 51 | ngx_rtmp_play_fmt_t *fmt; 52 | ngx_event_t send_evt; 53 | unsigned playing:1; 54 | unsigned opened:1; 55 | unsigned joined:1; 56 | ngx_uint_t ncrs; 57 | ngx_uint_t nheader; 58 | ngx_uint_t nbody; 59 | size_t pfx_size; 60 | ngx_str_t sfx; 61 | ngx_uint_t file_id; 62 | ngx_int_t aindex, vindex; 63 | ngx_uint_t nentry; 64 | ngx_uint_t post_seek; 65 | u_char name[NGX_RTMP_MAX_NAME]; 66 | ngx_rtmp_play_ctx_t *next; 67 | }; 68 | 69 | 70 | typedef struct { 71 | ngx_str_t *root; 72 | ngx_url_t *url; 73 | } ngx_rtmp_play_entry_t; 74 | 75 | 76 | typedef struct { 77 | ngx_str_t temp_path; 78 | ngx_str_t local_path; 79 | ngx_array_t entries; /* ngx_rtmp_play_entry_t * */ 80 | ngx_uint_t nbuckets; 81 | ngx_rtmp_play_ctx_t **ctx; 82 | } ngx_rtmp_play_app_conf_t; 83 | 84 | 85 | typedef struct { 86 | ngx_array_t fmts; /* ngx_rtmp_play_fmt_t * */ 87 | } ngx_rtmp_play_main_conf_t; 88 | 89 | 90 | extern ngx_module_t ngx_rtmp_play_module; 91 | 92 | 93 | #endif /* _NGX_RTMP_PLAY_H_INCLUDED_ */ 94 | -------------------------------------------------------------------------------- /ngx_rtmp_codec_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_CODEC_H_INCLUDED_ 8 | #define _NGX_RTMP_CODEC_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | /* Audio codecs */ 17 | enum { 18 | /* Uncompressed codec id is actually 0, 19 | * but we use another value for consistency */ 20 | NGX_RTMP_AUDIO_UNCOMPRESSED = 16, 21 | NGX_RTMP_AUDIO_ADPCM = 1, 22 | NGX_RTMP_AUDIO_MP3 = 2, 23 | NGX_RTMP_AUDIO_LINEAR_LE = 3, 24 | NGX_RTMP_AUDIO_NELLY16 = 4, 25 | NGX_RTMP_AUDIO_NELLY8 = 5, 26 | NGX_RTMP_AUDIO_NELLY = 6, 27 | NGX_RTMP_AUDIO_G711A = 7, 28 | NGX_RTMP_AUDIO_G711U = 8, 29 | NGX_RTMP_AUDIO_AAC = 10, 30 | NGX_RTMP_AUDIO_SPEEX = 11, 31 | NGX_RTMP_AUDIO_MP3_8 = 14, 32 | NGX_RTMP_AUDIO_DEVSPEC = 15, 33 | }; 34 | 35 | 36 | /* Video codecs */ 37 | enum { 38 | NGX_RTMP_VIDEO_JPEG = 1, 39 | NGX_RTMP_VIDEO_SORENSON_H263 = 2, 40 | NGX_RTMP_VIDEO_SCREEN = 3, 41 | NGX_RTMP_VIDEO_ON2_VP6 = 4, 42 | NGX_RTMP_VIDEO_ON2_VP6_ALPHA = 5, 43 | NGX_RTMP_VIDEO_SCREEN2 = 6, 44 | NGX_RTMP_VIDEO_H264 = 7, 45 | NGX_RTMP_VIDEO_H265 = 12 46 | }; 47 | 48 | 49 | u_char * ngx_rtmp_get_audio_codec_name(ngx_uint_t id); 50 | u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id); 51 | 52 | 53 | typedef struct { 54 | ngx_uint_t width; 55 | ngx_uint_t height; 56 | ngx_uint_t duration; 57 | ngx_uint_t frame_rate; 58 | ngx_uint_t video_data_rate; 59 | ngx_uint_t video_codec_id; 60 | ngx_uint_t audio_data_rate; 61 | ngx_uint_t audio_codec_id; 62 | ngx_uint_t aac_profile; 63 | ngx_uint_t aac_chan_conf; 64 | ngx_uint_t aac_sbr; 65 | ngx_uint_t aac_ps; 66 | ngx_uint_t avc_profile; 67 | ngx_uint_t avc_compat; 68 | ngx_uint_t avc_level; 69 | ngx_uint_t avc_nal_bytes; 70 | ngx_uint_t avc_ref_frames; 71 | ngx_uint_t sample_rate; /* 5512, 11025, 22050, 44100 */ 72 | ngx_uint_t sample_size; /* 1=8bit, 2=16bit */ 73 | ngx_uint_t audio_channels; /* 1, 2 */ 74 | u_char profile[32]; 75 | u_char level[32]; 76 | 77 | ngx_chain_t *avc_header; 78 | ngx_chain_t *aac_header; 79 | 80 | ngx_chain_t *meta; 81 | ngx_uint_t meta_version; 82 | } ngx_rtmp_codec_ctx_t; 83 | 84 | 85 | extern ngx_module_t ngx_rtmp_codec_module; 86 | 87 | 88 | #endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ 89 | -------------------------------------------------------------------------------- /ngx_rtmp_live_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_LIVE_H_INCLUDED_ 8 | #define _NGX_RTMP_LIVE_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | #include "ngx_rtmp_cmd_module.h" 15 | #include "ngx_rtmp_bandwidth.h" 16 | #include "ngx_rtmp_streams.h" 17 | 18 | 19 | typedef struct ngx_rtmp_live_ctx_s ngx_rtmp_live_ctx_t; 20 | typedef struct ngx_rtmp_live_stream_s ngx_rtmp_live_stream_t; 21 | 22 | 23 | typedef struct { 24 | unsigned active:1; 25 | uint32_t timestamp; 26 | uint32_t csid; 27 | uint32_t dropped; 28 | } ngx_rtmp_live_chunk_stream_t; 29 | 30 | 31 | struct ngx_rtmp_live_ctx_s { 32 | ngx_rtmp_session_t *session; 33 | ngx_rtmp_live_stream_t *stream; 34 | ngx_rtmp_live_ctx_t *next; 35 | ngx_uint_t ndropped; 36 | ngx_rtmp_live_chunk_stream_t cs[2]; 37 | ngx_uint_t meta_version; 38 | ngx_event_t idle_evt; 39 | unsigned active:1; 40 | unsigned publishing:1; 41 | unsigned silent:1; 42 | unsigned paused:1; 43 | }; 44 | 45 | 46 | struct ngx_rtmp_live_stream_s { 47 | u_char name[NGX_RTMP_MAX_NAME]; 48 | ngx_rtmp_live_stream_t *next; 49 | ngx_rtmp_live_ctx_t *ctx; 50 | ngx_rtmp_bandwidth_t bw_in; 51 | ngx_rtmp_bandwidth_t bw_in_audio; 52 | ngx_rtmp_bandwidth_t bw_in_video; 53 | ngx_rtmp_bandwidth_t bw_out; 54 | ngx_msec_t epoch; 55 | unsigned active:1; 56 | unsigned publishing:1; 57 | }; 58 | 59 | 60 | typedef struct { 61 | ngx_int_t nbuckets; 62 | ngx_rtmp_live_stream_t **streams; 63 | ngx_flag_t live; 64 | ngx_flag_t meta; 65 | ngx_msec_t sync; 66 | ngx_msec_t idle_timeout; 67 | ngx_flag_t atc; 68 | ngx_flag_t interleave; 69 | ngx_flag_t wait_key; 70 | ngx_flag_t wait_video; 71 | ngx_flag_t publish_notify; 72 | ngx_flag_t play_restart; 73 | ngx_flag_t idle_streams; 74 | ngx_msec_t buflen; 75 | ngx_pool_t *pool; 76 | ngx_rtmp_live_stream_t *free_streams; 77 | } ngx_rtmp_live_app_conf_t; 78 | 79 | 80 | extern ngx_module_t ngx_rtmp_live_module; 81 | 82 | 83 | #endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ 84 | -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPublisher.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /ngx_rtmp_shared.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp.h" 10 | 11 | 12 | ngx_chain_t * 13 | ngx_rtmp_alloc_shared_buf(ngx_rtmp_core_srv_conf_t *cscf) 14 | { 15 | u_char *p; 16 | ngx_chain_t *out; 17 | ngx_buf_t *b; 18 | size_t size; 19 | 20 | if (cscf->free) { 21 | out = cscf->free; 22 | cscf->free = out->next; 23 | 24 | } else { 25 | 26 | size = cscf->chunk_size + NGX_RTMP_MAX_CHUNK_HEADER; 27 | 28 | p = ngx_pcalloc(cscf->pool, NGX_RTMP_REFCOUNT_BYTES 29 | + sizeof(ngx_chain_t) 30 | + sizeof(ngx_buf_t) 31 | + size); 32 | if (p == NULL) { 33 | return NULL; 34 | } 35 | 36 | p += NGX_RTMP_REFCOUNT_BYTES; 37 | out = (ngx_chain_t *)p; 38 | 39 | p += sizeof(ngx_chain_t); 40 | out->buf = (ngx_buf_t *)p; 41 | 42 | p += sizeof(ngx_buf_t); 43 | out->buf->start = p; 44 | out->buf->end = p + size; 45 | } 46 | 47 | out->next = NULL; 48 | b = out->buf; 49 | b->pos = b->last = b->start + NGX_RTMP_MAX_CHUNK_HEADER; 50 | b->memory = 1; 51 | 52 | /* buffer has refcount =1 when created! */ 53 | ngx_rtmp_ref_set(out, 1); 54 | 55 | return out; 56 | } 57 | 58 | 59 | void 60 | ngx_rtmp_free_shared_chain(ngx_rtmp_core_srv_conf_t *cscf, ngx_chain_t *in) 61 | { 62 | ngx_chain_t *cl; 63 | 64 | if (ngx_rtmp_ref_put(in)) { 65 | return; 66 | } 67 | 68 | for (cl = in; ; cl = cl->next) { 69 | if (cl->next == NULL) { 70 | cl->next = cscf->free; 71 | cscf->free = in; 72 | return; 73 | } 74 | } 75 | } 76 | 77 | 78 | ngx_chain_t * 79 | ngx_rtmp_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, 80 | ngx_chain_t *head, ngx_chain_t *in) 81 | { 82 | ngx_chain_t *l, **ll; 83 | u_char *p; 84 | size_t size; 85 | 86 | ll = &head; 87 | p = in->buf->pos; 88 | l = head; 89 | 90 | if (l) { 91 | for(; l->next; l = l->next); 92 | ll = &l->next; 93 | } 94 | 95 | for ( ;; ) { 96 | 97 | if (l == NULL || l->buf->last == l->buf->end) { 98 | l = ngx_rtmp_alloc_shared_buf(cscf); 99 | if (l == NULL || l->buf == NULL) { 100 | break; 101 | } 102 | 103 | *ll = l; 104 | ll = &l->next; 105 | } 106 | 107 | while (l->buf->end - l->buf->last >= in->buf->last - p) { 108 | l->buf->last = ngx_cpymem(l->buf->last, p, 109 | in->buf->last - p); 110 | in = in->next; 111 | if (in == NULL) { 112 | goto done; 113 | } 114 | p = in->buf->pos; 115 | } 116 | 117 | size = l->buf->end - l->buf->last; 118 | l->buf->last = ngx_cpymem(l->buf->last, p, size); 119 | p += size; 120 | } 121 | 122 | done: 123 | *ll = NULL; 124 | 125 | return head; 126 | } 127 | -------------------------------------------------------------------------------- /test/rtmp-publisher/RtmpPlayerLight.mxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ngx_rtmp_record_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_RECORD_H_INCLUDED_ 8 | #define _NGX_RTMP_RECORD_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include "ngx_rtmp.h" 14 | 15 | 16 | #define NGX_RTMP_RECORD_OFF 0x01 17 | #define NGX_RTMP_RECORD_AUDIO 0x02 18 | #define NGX_RTMP_RECORD_VIDEO 0x04 19 | #define NGX_RTMP_RECORD_KEYFRAMES 0x08 20 | #define NGX_RTMP_RECORD_MANUAL 0x10 21 | 22 | 23 | typedef struct { 24 | ngx_str_t id; 25 | ngx_uint_t flags; 26 | ngx_str_t path; 27 | size_t max_size; 28 | size_t max_frames; 29 | ngx_msec_t interval; 30 | ngx_str_t suffix; 31 | ngx_flag_t unique; 32 | ngx_flag_t append; 33 | ngx_flag_t lock_file; 34 | ngx_flag_t notify; 35 | ngx_url_t *url; 36 | 37 | void **rec_conf; 38 | ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */ 39 | } ngx_rtmp_record_app_conf_t; 40 | 41 | 42 | typedef struct { 43 | ngx_rtmp_record_app_conf_t *conf; 44 | ngx_file_t file; 45 | ngx_uint_t nframes; 46 | uint32_t epoch, time_shift; 47 | ngx_time_t last; 48 | time_t timestamp; 49 | unsigned failed:1; 50 | unsigned initialized:1; 51 | unsigned aac_header_sent:1; 52 | unsigned avc_header_sent:1; 53 | unsigned video_key_sent:1; 54 | unsigned audio:1; 55 | unsigned video:1; 56 | } ngx_rtmp_record_rec_ctx_t; 57 | 58 | 59 | typedef struct { 60 | ngx_array_t rec; /* ngx_rtmp_record_rec_ctx_t */ 61 | u_char name[NGX_RTMP_MAX_NAME]; 62 | u_char args[NGX_RTMP_MAX_ARGS]; 63 | } ngx_rtmp_record_ctx_t; 64 | 65 | 66 | ngx_uint_t ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, 67 | ngx_str_t *id); 68 | 69 | 70 | /* Manual recording control, 71 | * 'n' is record node index in config array. 72 | * Note: these functions allocate path in static buffer */ 73 | 74 | ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, 75 | ngx_str_t *path); 76 | ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, 77 | ngx_str_t *path); 78 | 79 | 80 | typedef struct { 81 | ngx_str_t recorder; 82 | ngx_str_t path; 83 | } ngx_rtmp_record_done_t; 84 | 85 | 86 | typedef ngx_int_t (*ngx_rtmp_record_done_pt)(ngx_rtmp_session_t *s, 87 | ngx_rtmp_record_done_t *v); 88 | 89 | 90 | extern ngx_rtmp_record_done_pt ngx_rtmp_record_done; 91 | 92 | 93 | extern ngx_module_t ngx_rtmp_record_module; 94 | 95 | 96 | #endif /* _NGX_RTMP_RECORD_H_INCLUDED_ */ 97 | -------------------------------------------------------------------------------- /ngx_rtmp_proxy_protocol.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ngx_rtmp_proxy_protocol.h" 11 | 12 | 13 | static void ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev); 14 | 15 | 16 | void 17 | ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *s) 18 | { 19 | ngx_event_t *rev; 20 | ngx_connection_t *c; 21 | 22 | c = s->connection; 23 | rev = c->read; 24 | rev->handler = ngx_rtmp_proxy_protocol_recv; 25 | 26 | ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, 27 | "proxy_protocol: start"); 28 | 29 | if (rev->ready) { 30 | /* the deferred accept(), rtsig, aio, iocp */ 31 | 32 | if (ngx_use_accept_mutex) { 33 | ngx_post_event(rev, &ngx_posted_events); 34 | return; 35 | } 36 | 37 | rev->handler(rev); 38 | return; 39 | } 40 | 41 | ngx_add_timer(rev, s->timeout); 42 | 43 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { 44 | ngx_rtmp_finalize_session(s); 45 | return; 46 | } 47 | } 48 | 49 | 50 | static void 51 | ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev) 52 | { 53 | u_char buf[107], *p, *pp, *text; 54 | size_t len; 55 | ssize_t n; 56 | ngx_err_t err; 57 | ngx_int_t i; 58 | ngx_addr_t addr; 59 | ngx_connection_t *c; 60 | ngx_rtmp_session_t *s; 61 | 62 | c = rev->data; 63 | s = c->data; 64 | 65 | if (c->destroyed) { 66 | return; 67 | } 68 | 69 | if (rev->timedout) { 70 | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, 71 | "proxy_protocol: recv: client timed out"); 72 | c->timedout = 1; 73 | ngx_rtmp_finalize_session(s); 74 | return; 75 | } 76 | 77 | if (rev->timer_set) { 78 | ngx_del_timer(rev); 79 | } 80 | 81 | n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); 82 | 83 | err = ngx_socket_errno; 84 | 85 | ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "recv(): %d", n); 86 | 87 | if (n == -1) { 88 | 89 | if (err == NGX_EAGAIN) { 90 | ngx_add_timer(rev, s->timeout); 91 | 92 | if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 93 | ngx_rtmp_finalize_session(s); 94 | } 95 | 96 | return; 97 | } 98 | 99 | ngx_rtmp_finalize_session(s); 100 | 101 | return; 102 | } 103 | 104 | p = buf; 105 | 106 | if (n <= 8 && ngx_strncmp(p, "PROXY ", 6) != 0) { 107 | goto bad_header; 108 | } 109 | 110 | n -= 6; 111 | p += 6; 112 | 113 | ngx_memzero(&addr, sizeof(ngx_addr_t)); 114 | 115 | if (n >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { 116 | n -= 7; 117 | p += 7; 118 | goto skip; 119 | } 120 | 121 | if (n < 5 || ngx_strncmp(p, "TCP", 3) != 0 122 | || (p[3] != '4' && p[3] != '6') || p[4] != ' ') 123 | { 124 | goto bad_header; 125 | } 126 | 127 | n -= 5; 128 | p += 5; 129 | 130 | pp = ngx_strlchr(p, p + n, ' '); 131 | 132 | if (pp == NULL) { 133 | goto bad_header; 134 | } 135 | 136 | if (ngx_parse_addr(s->connection->pool, &addr, p, pp - p) != NGX_OK) { 137 | goto bad_header; 138 | } 139 | 140 | n -= pp - p; 141 | p = pp; 142 | 143 | skip: 144 | 145 | for (i = 0; i + 1 < n; i++) { 146 | if (p[i] == CR && p[i + 1] == LF) { 147 | break; 148 | } 149 | } 150 | 151 | if (i + 1 >= n) { 152 | goto bad_header; 153 | } 154 | 155 | n = p - buf + i + 2; 156 | 157 | if (c->recv(c, buf, n) != n) { 158 | goto failed; 159 | } 160 | 161 | if (addr.socklen) { 162 | text = ngx_palloc(s->connection->pool, NGX_SOCKADDR_STRLEN); 163 | 164 | if (text == NULL) { 165 | goto failed; 166 | } 167 | 168 | len = ngx_sock_ntop(addr.sockaddr, 169 | #if (nginx_version >= 1005003) 170 | addr.socklen, 171 | #endif 172 | text, NGX_SOCKADDR_STRLEN, 0); 173 | if (len == 0) { 174 | goto failed; 175 | } 176 | 177 | c->sockaddr = addr.sockaddr; 178 | c->socklen = addr.socklen; 179 | c->addr_text.data = text; 180 | c->addr_text.len = len; 181 | 182 | ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, 183 | "proxy_protocol: remote_addr:'%V'", &c->addr_text); 184 | } 185 | 186 | ngx_rtmp_handshake(s); 187 | 188 | return; 189 | 190 | bad_header: 191 | 192 | ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy_protocol: bad header"); 193 | 194 | failed: 195 | 196 | ngx_rtmp_finalize_session(s); 197 | } 198 | -------------------------------------------------------------------------------- /ngx_rtmp_cmd_module.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #ifndef _NGX_RTMP_CMD_H_INCLUDED_ 8 | #define _NGX_RTMP_CMD_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include "ngx_rtmp.h" 15 | 16 | 17 | #define NGX_RTMP_MAX_NAME 256 18 | #define NGX_RTMP_MAX_URL 256 19 | #define NGX_RTMP_MAX_ARGS NGX_RTMP_MAX_NAME 20 | 21 | 22 | /* Basic RTMP call support */ 23 | 24 | typedef struct { 25 | double trans; 26 | u_char app[NGX_RTMP_MAX_NAME]; 27 | u_char args[NGX_RTMP_MAX_ARGS]; 28 | u_char flashver[32]; 29 | u_char swf_url[NGX_RTMP_MAX_URL]; 30 | u_char tc_url[NGX_RTMP_MAX_URL]; 31 | double acodecs; 32 | double vcodecs; 33 | u_char page_url[NGX_RTMP_MAX_URL]; 34 | double object_encoding; 35 | } ngx_rtmp_connect_t; 36 | 37 | 38 | typedef struct { 39 | double trans; 40 | double stream; 41 | } ngx_rtmp_create_stream_t; 42 | 43 | 44 | typedef struct { 45 | double stream; 46 | } ngx_rtmp_delete_stream_t; 47 | 48 | 49 | typedef struct { 50 | double stream; 51 | } ngx_rtmp_close_stream_t; 52 | 53 | 54 | typedef struct { 55 | u_char name[NGX_RTMP_MAX_NAME]; 56 | u_char args[NGX_RTMP_MAX_ARGS]; 57 | u_char type[16]; 58 | int silent; 59 | } ngx_rtmp_publish_t; 60 | 61 | 62 | typedef struct { 63 | u_char name[NGX_RTMP_MAX_NAME]; 64 | u_char args[NGX_RTMP_MAX_ARGS]; 65 | double start; 66 | double duration; 67 | int reset; 68 | int silent; 69 | } ngx_rtmp_play_t; 70 | 71 | 72 | typedef struct { 73 | double offset; 74 | } ngx_rtmp_seek_t; 75 | 76 | 77 | typedef struct { 78 | uint8_t pause; 79 | double position; 80 | } ngx_rtmp_pause_t; 81 | 82 | 83 | typedef struct { 84 | uint32_t msid; 85 | } ngx_rtmp_msid_t; 86 | 87 | 88 | typedef ngx_rtmp_msid_t ngx_rtmp_stream_begin_t; 89 | typedef ngx_rtmp_msid_t ngx_rtmp_stream_eof_t; 90 | typedef ngx_rtmp_msid_t ngx_rtmp_stream_dry_t; 91 | typedef ngx_rtmp_msid_t ngx_rtmp_recorded_t; 92 | 93 | 94 | typedef struct { 95 | uint32_t msid; 96 | uint32_t buflen; 97 | } ngx_rtmp_set_buflen_t; 98 | 99 | 100 | void ngx_rtmp_cmd_fill_args(u_char name[NGX_RTMP_MAX_NAME], 101 | u_char args[NGX_RTMP_MAX_ARGS]); 102 | 103 | 104 | typedef ngx_int_t (*ngx_rtmp_connect_pt)(ngx_rtmp_session_t *s, 105 | ngx_rtmp_connect_t *v); 106 | typedef ngx_int_t (*ngx_rtmp_disconnect_pt)(ngx_rtmp_session_t *s); 107 | typedef ngx_int_t (*ngx_rtmp_create_stream_pt)(ngx_rtmp_session_t *s, 108 | ngx_rtmp_create_stream_t *v); 109 | typedef ngx_int_t (*ngx_rtmp_close_stream_pt)(ngx_rtmp_session_t *s, 110 | ngx_rtmp_close_stream_t *v); 111 | typedef ngx_int_t (*ngx_rtmp_delete_stream_pt)(ngx_rtmp_session_t *s, 112 | ngx_rtmp_delete_stream_t *v); 113 | typedef ngx_int_t (*ngx_rtmp_publish_pt)(ngx_rtmp_session_t *s, 114 | ngx_rtmp_publish_t *v); 115 | typedef ngx_int_t (*ngx_rtmp_play_pt)(ngx_rtmp_session_t *s, 116 | ngx_rtmp_play_t *v); 117 | typedef ngx_int_t (*ngx_rtmp_seek_pt)(ngx_rtmp_session_t *s, 118 | ngx_rtmp_seek_t *v); 119 | typedef ngx_int_t (*ngx_rtmp_pause_pt)(ngx_rtmp_session_t *s, 120 | ngx_rtmp_pause_t *v); 121 | 122 | typedef ngx_int_t (*ngx_rtmp_stream_begin_pt)(ngx_rtmp_session_t *s, 123 | ngx_rtmp_stream_begin_t *v); 124 | typedef ngx_int_t (*ngx_rtmp_stream_eof_pt)(ngx_rtmp_session_t *s, 125 | ngx_rtmp_stream_eof_t *v); 126 | typedef ngx_int_t (*ngx_rtmp_stream_dry_pt)(ngx_rtmp_session_t *s, 127 | ngx_rtmp_stream_dry_t *v); 128 | typedef ngx_int_t (*ngx_rtmp_recorded_pt)(ngx_rtmp_session_t *s, 129 | ngx_rtmp_recorded_t *v); 130 | typedef ngx_int_t (*ngx_rtmp_set_buflen_pt)(ngx_rtmp_session_t *s, 131 | ngx_rtmp_set_buflen_t *v); 132 | 133 | 134 | extern ngx_rtmp_connect_pt ngx_rtmp_connect; 135 | extern ngx_rtmp_disconnect_pt ngx_rtmp_disconnect; 136 | extern ngx_rtmp_create_stream_pt ngx_rtmp_create_stream; 137 | extern ngx_rtmp_close_stream_pt ngx_rtmp_close_stream; 138 | extern ngx_rtmp_delete_stream_pt ngx_rtmp_delete_stream; 139 | extern ngx_rtmp_publish_pt ngx_rtmp_publish; 140 | extern ngx_rtmp_play_pt ngx_rtmp_play; 141 | extern ngx_rtmp_seek_pt ngx_rtmp_seek; 142 | extern ngx_rtmp_pause_pt ngx_rtmp_pause; 143 | 144 | extern ngx_rtmp_stream_begin_pt ngx_rtmp_stream_begin; 145 | extern ngx_rtmp_stream_eof_pt ngx_rtmp_stream_eof; 146 | extern ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry; 147 | extern ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen; 148 | extern ngx_rtmp_recorded_pt ngx_rtmp_recorded; 149 | 150 | 151 | #endif /*_NGX_RTMP_CMD_H_INCLUDED_ */ 152 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name="ngx_rtmp_module" 2 | 3 | RTMP_CORE_MODULES=" \ 4 | ngx_rtmp_module \ 5 | ngx_rtmp_core_module \ 6 | ngx_rtmp_cmd_module \ 7 | ngx_rtmp_codec_module \ 8 | ngx_rtmp_access_module \ 9 | ngx_rtmp_record_module \ 10 | ngx_rtmp_live_module \ 11 | ngx_rtmp_play_module \ 12 | ngx_rtmp_flv_module \ 13 | ngx_rtmp_mp4_module \ 14 | ngx_rtmp_netcall_module \ 15 | ngx_rtmp_relay_module \ 16 | ngx_rtmp_exec_module \ 17 | ngx_rtmp_auto_push_module \ 18 | ngx_rtmp_auto_push_index_module \ 19 | ngx_rtmp_notify_module \ 20 | ngx_rtmp_log_module \ 21 | ngx_rtmp_limit_module \ 22 | ngx_rtmp_hls_module \ 23 | ngx_rtmp_dash_module \ 24 | " 25 | 26 | 27 | RTMP_HTTP_MODULES=" \ 28 | ngx_rtmp_stat_module \ 29 | ngx_rtmp_control_module \ 30 | " 31 | 32 | 33 | RTMP_DEPS=" \ 34 | $ngx_addon_dir/ngx_rtmp_amf.h \ 35 | $ngx_addon_dir/ngx_rtmp_bandwidth.h \ 36 | $ngx_addon_dir/ngx_rtmp_cmd_module.h \ 37 | $ngx_addon_dir/ngx_rtmp_codec_module.h \ 38 | $ngx_addon_dir/ngx_rtmp_eval.h \ 39 | $ngx_addon_dir/ngx_rtmp.h \ 40 | $ngx_addon_dir/ngx_rtmp_version.h \ 41 | $ngx_addon_dir/ngx_rtmp_live_module.h \ 42 | $ngx_addon_dir/ngx_rtmp_netcall_module.h \ 43 | $ngx_addon_dir/ngx_rtmp_play_module.h \ 44 | $ngx_addon_dir/ngx_rtmp_record_module.h \ 45 | $ngx_addon_dir/ngx_rtmp_relay_module.h \ 46 | $ngx_addon_dir/ngx_rtmp_streams.h \ 47 | $ngx_addon_dir/ngx_rtmp_bitop.h \ 48 | $ngx_addon_dir/ngx_rtmp_proxy_protocol.h \ 49 | $ngx_addon_dir/hls/ngx_rtmp_mpegts.h \ 50 | $ngx_addon_dir/dash/ngx_rtmp_mp4.h \ 51 | " 52 | 53 | 54 | RTMP_CORE_SRCS=" \ 55 | $ngx_addon_dir/ngx_rtmp.c \ 56 | $ngx_addon_dir/ngx_rtmp_init.c \ 57 | $ngx_addon_dir/ngx_rtmp_handshake.c \ 58 | $ngx_addon_dir/ngx_rtmp_handler.c \ 59 | $ngx_addon_dir/ngx_rtmp_amf.c \ 60 | $ngx_addon_dir/ngx_rtmp_send.c \ 61 | $ngx_addon_dir/ngx_rtmp_shared.c \ 62 | $ngx_addon_dir/ngx_rtmp_eval.c \ 63 | $ngx_addon_dir/ngx_rtmp_receive.c \ 64 | $ngx_addon_dir/ngx_rtmp_core_module.c \ 65 | $ngx_addon_dir/ngx_rtmp_cmd_module.c \ 66 | $ngx_addon_dir/ngx_rtmp_codec_module.c \ 67 | $ngx_addon_dir/ngx_rtmp_access_module.c \ 68 | $ngx_addon_dir/ngx_rtmp_record_module.c \ 69 | $ngx_addon_dir/ngx_rtmp_live_module.c \ 70 | $ngx_addon_dir/ngx_rtmp_play_module.c \ 71 | $ngx_addon_dir/ngx_rtmp_flv_module.c \ 72 | $ngx_addon_dir/ngx_rtmp_mp4_module.c \ 73 | $ngx_addon_dir/ngx_rtmp_netcall_module.c \ 74 | $ngx_addon_dir/ngx_rtmp_relay_module.c \ 75 | $ngx_addon_dir/ngx_rtmp_bandwidth.c \ 76 | $ngx_addon_dir/ngx_rtmp_exec_module.c \ 77 | $ngx_addon_dir/ngx_rtmp_auto_push_module.c \ 78 | $ngx_addon_dir/ngx_rtmp_notify_module.c \ 79 | $ngx_addon_dir/ngx_rtmp_log_module.c \ 80 | $ngx_addon_dir/ngx_rtmp_limit_module.c \ 81 | $ngx_addon_dir/ngx_rtmp_bitop.c \ 82 | $ngx_addon_dir/ngx_rtmp_proxy_protocol.c \ 83 | $ngx_addon_dir/hls/ngx_rtmp_hls_module.c \ 84 | $ngx_addon_dir/dash/ngx_rtmp_dash_module.c \ 85 | $ngx_addon_dir/hls/ngx_rtmp_mpegts.c \ 86 | $ngx_addon_dir/dash/ngx_rtmp_mp4.c \ 87 | " 88 | 89 | 90 | RTMP_HTTP_SRCS=" \ 91 | $ngx_addon_dir/ngx_rtmp_stat_module.c \ 92 | $ngx_addon_dir/ngx_rtmp_control_module.c \ 93 | " 94 | 95 | if [ -f auto/module ] ; then 96 | ngx_module_incs=$ngx_addon_dir 97 | ngx_module_deps=$RTMP_DEPS 98 | 99 | if [ $ngx_module_link = DYNAMIC ] ; then 100 | ngx_module_name="$RTMP_CORE_MODULES $RTMP_HTTP_MODULES" 101 | ngx_module_srcs="$RTMP_CORE_SRCS $RTMP_HTTP_SRCS" 102 | 103 | . auto/module 104 | 105 | else 106 | ngx_module_type=CORE 107 | ngx_module_name=$RTMP_CORE_MODULES 108 | ngx_module_srcs=$RTMP_CORE_SRCS 109 | 110 | . auto/module 111 | 112 | 113 | ngx_module_type=HTTP 114 | ngx_module_name=$RTMP_HTTP_MODULES 115 | ngx_module_incs= 116 | ngx_module_deps= 117 | ngx_module_srcs=$RTMP_HTTP_SRCS 118 | 119 | . auto/module 120 | fi 121 | 122 | else 123 | CORE_MODULES="$CORE_MODULES $RTMP_CORE_MODULES" 124 | HTTP_MODULES="$HTTP_MODULES $RTMP_HTTP_MODULES" 125 | 126 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $RTMP_DEPS" 127 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $RTMP_CORE_SRCS $RTMP_HTTP_SRCS" 128 | 129 | CFLAGS="$CFLAGS -I$ngx_addon_dir" 130 | fi 131 | 132 | USE_OPENSSL=YES 133 | 134 | -------------------------------------------------------------------------------- /ngx_rtmp_limit_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp.h" 10 | 11 | 12 | typedef struct { 13 | ngx_int_t max_conn; 14 | ngx_shm_zone_t *shm_zone; 15 | } ngx_rtmp_limit_main_conf_t; 16 | 17 | 18 | static ngx_str_t shm_name = ngx_string("rtmp_limit"); 19 | 20 | 21 | static ngx_int_t ngx_rtmp_limit_postconfiguration(ngx_conf_t *cf); 22 | static void *ngx_rtmp_limit_create_main_conf(ngx_conf_t *cf); 23 | 24 | 25 | static ngx_command_t ngx_rtmp_limit_commands[] = { 26 | 27 | { ngx_string("max_connections"), 28 | NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, 29 | ngx_conf_set_num_slot, 30 | NGX_RTMP_MAIN_CONF_OFFSET, 31 | offsetof(ngx_rtmp_limit_main_conf_t, max_conn), 32 | NULL }, 33 | 34 | ngx_null_command 35 | }; 36 | 37 | 38 | static ngx_rtmp_module_t ngx_rtmp_limit_module_ctx = { 39 | NULL, /* preconfiguration */ 40 | ngx_rtmp_limit_postconfiguration, /* postconfiguration */ 41 | ngx_rtmp_limit_create_main_conf, /* create main configuration */ 42 | NULL, /* init main configuration */ 43 | NULL, /* create server configuration */ 44 | NULL, /* merge server configuration */ 45 | NULL, /* create app configuration */ 46 | NULL /* merge app configuration */ 47 | }; 48 | 49 | 50 | ngx_module_t ngx_rtmp_limit_module = { 51 | NGX_MODULE_V1, 52 | &ngx_rtmp_limit_module_ctx, /* module context */ 53 | ngx_rtmp_limit_commands, /* module directives */ 54 | NGX_RTMP_MODULE, /* module type */ 55 | NULL, /* init master */ 56 | NULL, /* init module */ 57 | NULL, /* init process */ 58 | NULL, /* init thread */ 59 | NULL, /* exit thread */ 60 | NULL, /* exit process */ 61 | NULL, /* exit master */ 62 | NGX_MODULE_V1_PADDING 63 | }; 64 | 65 | 66 | static void * 67 | ngx_rtmp_limit_create_main_conf(ngx_conf_t *cf) 68 | { 69 | ngx_rtmp_limit_main_conf_t *lmcf; 70 | 71 | lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_limit_main_conf_t)); 72 | if (lmcf == NULL) { 73 | return NULL; 74 | } 75 | 76 | lmcf->max_conn = NGX_CONF_UNSET; 77 | 78 | return lmcf; 79 | } 80 | 81 | 82 | static ngx_int_t 83 | ngx_rtmp_limit_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, 84 | ngx_chain_t *in) 85 | { 86 | ngx_rtmp_limit_main_conf_t *lmcf; 87 | ngx_slab_pool_t *shpool; 88 | ngx_shm_zone_t *shm_zone; 89 | uint32_t *nconn, n; 90 | ngx_int_t rc; 91 | 92 | lmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_limit_module); 93 | if (lmcf->max_conn == NGX_CONF_UNSET) { 94 | return NGX_OK; 95 | } 96 | 97 | shm_zone = lmcf->shm_zone; 98 | shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; 99 | nconn = shm_zone->data; 100 | 101 | ngx_shmtx_lock(&shpool->mutex); 102 | n = ++*nconn; 103 | ngx_shmtx_unlock(&shpool->mutex); 104 | 105 | rc = n > (ngx_uint_t) lmcf->max_conn ? NGX_ERROR : NGX_OK; 106 | 107 | ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, 108 | "limit: inc conection counter: %uD", n); 109 | 110 | if (rc != NGX_OK) { 111 | ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, 112 | "limit: too many connections: %uD > %i", 113 | n, lmcf->max_conn); 114 | } 115 | 116 | return rc; 117 | } 118 | 119 | 120 | static ngx_int_t 121 | ngx_rtmp_limit_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, 122 | ngx_chain_t *in) 123 | { 124 | ngx_rtmp_limit_main_conf_t *lmcf; 125 | ngx_slab_pool_t *shpool; 126 | ngx_shm_zone_t *shm_zone; 127 | uint32_t *nconn, n; 128 | 129 | lmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_limit_module); 130 | if (lmcf->max_conn == NGX_CONF_UNSET) { 131 | return NGX_OK; 132 | } 133 | 134 | shm_zone = lmcf->shm_zone; 135 | shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; 136 | nconn = shm_zone->data; 137 | 138 | ngx_shmtx_lock(&shpool->mutex); 139 | n = --*nconn; 140 | ngx_shmtx_unlock(&shpool->mutex); 141 | 142 | (void) n; 143 | ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, 144 | "limit: dec conection counter: %uD", n); 145 | 146 | return NGX_OK; 147 | } 148 | 149 | 150 | static ngx_int_t 151 | ngx_rtmp_limit_shm_init(ngx_shm_zone_t *shm_zone, void *data) 152 | { 153 | ngx_slab_pool_t *shpool; 154 | uint32_t *nconn; 155 | 156 | if (data) { 157 | shm_zone->data = data; 158 | return NGX_OK; 159 | } 160 | 161 | shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; 162 | 163 | nconn = ngx_slab_alloc(shpool, 4); 164 | if (nconn == NULL) { 165 | return NGX_ERROR; 166 | } 167 | 168 | *nconn = 0; 169 | 170 | shm_zone->data = nconn; 171 | 172 | return NGX_OK; 173 | } 174 | 175 | 176 | static ngx_int_t 177 | ngx_rtmp_limit_postconfiguration(ngx_conf_t *cf) 178 | { 179 | ngx_rtmp_core_main_conf_t *cmcf; 180 | ngx_rtmp_limit_main_conf_t *lmcf; 181 | ngx_rtmp_handler_pt *h; 182 | 183 | cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); 184 | 185 | h = ngx_array_push(&cmcf->events[NGX_RTMP_CONNECT]); 186 | *h = ngx_rtmp_limit_connect; 187 | 188 | h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); 189 | *h = ngx_rtmp_limit_disconnect; 190 | 191 | lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_limit_module); 192 | if (lmcf->max_conn == NGX_CONF_UNSET) { 193 | return NGX_OK; 194 | } 195 | 196 | lmcf->shm_zone = ngx_shared_memory_add(cf, &shm_name, ngx_pagesize * 2, 197 | &ngx_rtmp_limit_module); 198 | if (lmcf->shm_zone == NULL) { 199 | return NGX_ERROR; 200 | } 201 | 202 | lmcf->shm_zone->init = ngx_rtmp_limit_shm_init; 203 | 204 | return NGX_OK; 205 | } 206 | -------------------------------------------------------------------------------- /ngx_rtmp_eval.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp_eval.h" 10 | 11 | 12 | #define NGX_RTMP_EVAL_BUFLEN 16 13 | 14 | 15 | static void 16 | ngx_rtmp_eval_session_str(void *ctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) 17 | { 18 | *ret = *(ngx_str_t *) ((u_char *) ctx + e->offset); 19 | } 20 | 21 | 22 | static void 23 | ngx_rtmp_eval_connection_str(void *ctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) 24 | { 25 | ngx_rtmp_session_t *s = ctx; 26 | 27 | *ret = *(ngx_str_t *) ((u_char *) s->connection + e->offset); 28 | } 29 | 30 | 31 | ngx_rtmp_eval_t ngx_rtmp_eval_session[] = { 32 | 33 | { ngx_string("app"), 34 | ngx_rtmp_eval_session_str, 35 | offsetof(ngx_rtmp_session_t, app) }, 36 | 37 | { ngx_string("flashver"), 38 | ngx_rtmp_eval_session_str, 39 | offsetof(ngx_rtmp_session_t, flashver) }, 40 | 41 | { ngx_string("swfurl"), 42 | ngx_rtmp_eval_session_str, 43 | offsetof(ngx_rtmp_session_t, swf_url) }, 44 | 45 | { ngx_string("tcurl"), 46 | ngx_rtmp_eval_session_str, 47 | offsetof(ngx_rtmp_session_t, tc_url) }, 48 | 49 | { ngx_string("pageurl"), 50 | ngx_rtmp_eval_session_str, 51 | offsetof(ngx_rtmp_session_t, page_url) }, 52 | 53 | { ngx_string("addr"), 54 | ngx_rtmp_eval_connection_str, 55 | offsetof(ngx_connection_t, addr_text) }, 56 | 57 | ngx_rtmp_null_eval 58 | }; 59 | 60 | 61 | static void 62 | ngx_rtmp_eval_append(ngx_buf_t *b, void *data, size_t len, ngx_log_t *log) 63 | { 64 | size_t buf_len; 65 | 66 | if (b->last + len > b->end) { 67 | buf_len = 2 * (b->last - b->pos) + len; 68 | 69 | b->start = ngx_alloc(buf_len, log); 70 | if (b->start == NULL) { 71 | return; 72 | } 73 | 74 | b->last = ngx_cpymem(b->start, b->pos, b->last - b->pos); 75 | b->pos = b->start; 76 | b->end = b->start + buf_len; 77 | } 78 | 79 | b->last = ngx_cpymem(b->last, data, len); 80 | } 81 | 82 | 83 | static void 84 | ngx_rtmp_eval_append_var(void *ctx, ngx_buf_t *b, ngx_rtmp_eval_t **e, 85 | ngx_str_t *name, ngx_log_t *log) 86 | { 87 | ngx_uint_t k; 88 | ngx_str_t v; 89 | ngx_rtmp_eval_t *ee; 90 | 91 | for (; *e; ++e) { 92 | for (k = 0, ee = *e; ee->handler; ++k, ++ee) { 93 | if (ee->name.len == name->len && 94 | ngx_memcmp(ee->name.data, name->data, name->len) == 0) 95 | { 96 | ee->handler(ctx, ee, &v); 97 | ngx_rtmp_eval_append(b, v.data, v.len, log); 98 | } 99 | } 100 | } 101 | } 102 | 103 | 104 | ngx_int_t 105 | ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out, 106 | ngx_log_t *log) 107 | { 108 | u_char c, *p; 109 | ngx_str_t name; 110 | ngx_buf_t b; 111 | ngx_uint_t n; 112 | 113 | enum { 114 | NORMAL, 115 | ESCAPE, 116 | NAME, 117 | SNAME 118 | } state = NORMAL; 119 | 120 | b.pos = b.last = b.start = ngx_alloc(NGX_RTMP_EVAL_BUFLEN, log); 121 | if (b.pos == NULL) { 122 | return NGX_ERROR; 123 | } 124 | 125 | b.end = b.pos + NGX_RTMP_EVAL_BUFLEN; 126 | name.data = NULL; 127 | 128 | for (n = 0; n < in->len; ++n) { 129 | p = &in->data[n]; 130 | c = *p; 131 | 132 | switch (state) { 133 | case SNAME: 134 | if (c != '}') { 135 | continue; 136 | } 137 | 138 | name.len = p - name.data; 139 | ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); 140 | 141 | state = NORMAL; 142 | 143 | continue; 144 | 145 | case NAME: 146 | if (c == '{' && name.data == p) { 147 | ++name.data; 148 | state = SNAME; 149 | continue; 150 | } 151 | if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 152 | continue; 153 | } 154 | 155 | name.len = p - name.data; 156 | ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); 157 | /* fall through */ 158 | 159 | case NORMAL: 160 | switch (c) { 161 | case '$': 162 | name.data = p + 1; 163 | state = NAME; 164 | continue; 165 | case '\\': 166 | state = ESCAPE; 167 | continue; 168 | } 169 | 170 | case ESCAPE: 171 | ngx_rtmp_eval_append(&b, &c, 1, log); 172 | state = NORMAL; 173 | break; 174 | 175 | } 176 | } 177 | 178 | if (state == NAME) { 179 | p = &in->data[n]; 180 | name.len = p - name.data; 181 | ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); 182 | } 183 | 184 | c = 0; 185 | ngx_rtmp_eval_append(&b, &c, 1, log); 186 | 187 | out->data = b.pos; 188 | out->len = b.last - b.pos - 1; 189 | 190 | return NGX_OK; 191 | } 192 | 193 | 194 | ngx_int_t 195 | ngx_rtmp_eval_streams(ngx_str_t *in) 196 | { 197 | #if !(NGX_WIN32) 198 | ngx_int_t mode, create, v, close_src; 199 | ngx_fd_t dst, src; 200 | u_char *path; 201 | 202 | path = in->data; 203 | 204 | while (*path >= '0' && *path <= '9') { 205 | path++; 206 | } 207 | 208 | switch ((char) *path) { 209 | 210 | case '>': 211 | 212 | v = (path == in->data ? 1 : ngx_atoi(in->data, path - in->data)); 213 | if (v == NGX_ERROR) { 214 | return NGX_ERROR; 215 | } 216 | 217 | dst = (ngx_fd_t) v; 218 | mode = NGX_FILE_WRONLY; 219 | create = NGX_FILE_TRUNCATE; 220 | path++; 221 | 222 | if (*path == (u_char) '>') { 223 | mode = NGX_FILE_APPEND; 224 | create = NGX_FILE_CREATE_OR_OPEN; 225 | path++; 226 | } 227 | 228 | break; 229 | 230 | case '<': 231 | 232 | v = (path == in->data ? 0 : ngx_atoi(in->data, path - in->data)); 233 | if (v == NGX_ERROR) { 234 | return NGX_ERROR; 235 | } 236 | 237 | dst = (ngx_fd_t) v; 238 | mode = NGX_FILE_RDONLY; 239 | create = NGX_FILE_OPEN; 240 | path++; 241 | 242 | break; 243 | 244 | default: 245 | 246 | return NGX_DONE; 247 | } 248 | 249 | if (*path == (u_char) '&') { 250 | 251 | path++; 252 | v = ngx_atoi(path, in->data + in->len - path); 253 | if (v == NGX_ERROR) { 254 | return NGX_ERROR; 255 | } 256 | src = (ngx_fd_t) v; 257 | close_src = 0; 258 | 259 | } else { 260 | 261 | src = ngx_open_file(path, mode, create, NGX_FILE_DEFAULT_ACCESS); 262 | if (src == NGX_INVALID_FILE) { 263 | return NGX_ERROR; 264 | } 265 | close_src = 1; 266 | 267 | } 268 | 269 | if (src == dst) { 270 | return NGX_OK; 271 | } 272 | 273 | dup2(src, dst); 274 | 275 | if (close_src) { 276 | ngx_close_file(src); 277 | } 278 | return NGX_OK; 279 | 280 | #else 281 | return NGX_DONE; 282 | #endif 283 | } 284 | -------------------------------------------------------------------------------- /ngx_rtmp_init.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Roman Arutyunyan 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include "ngx_rtmp.h" 10 | #include "ngx_rtmp_proxy_protocol.h" 11 | 12 | 13 | static void ngx_rtmp_close_connection(ngx_connection_t *c); 14 | static u_char * ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len); 15 | 16 | 17 | void 18 | ngx_rtmp_init_connection(ngx_connection_t *c) 19 | { 20 | ngx_uint_t i; 21 | ngx_rtmp_port_t *port; 22 | struct sockaddr *sa; 23 | struct sockaddr_in *sin; 24 | ngx_rtmp_in_addr_t *addr; 25 | ngx_rtmp_session_t *s; 26 | ngx_rtmp_addr_conf_t *addr_conf; 27 | ngx_int_t unix_socket; 28 | #if (NGX_HAVE_INET6) 29 | struct sockaddr_in6 *sin6; 30 | ngx_rtmp_in6_addr_t *addr6; 31 | #endif 32 | 33 | ++ngx_rtmp_naccepted; 34 | 35 | /* find the server configuration for the address:port */ 36 | 37 | /* AF_INET only */ 38 | 39 | port = c->listening->servers; 40 | unix_socket = 0; 41 | 42 | if (port->naddrs > 1) { 43 | 44 | /* 45 | * There are several addresses on this port and one of them 46 | * is the "*:port" wildcard so getsockname() is needed to determine 47 | * the server address. 48 | * 49 | * AcceptEx() already gave this address. 50 | */ 51 | 52 | if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { 53 | ngx_rtmp_close_connection(c); 54 | return; 55 | } 56 | 57 | sa = c->local_sockaddr; 58 | 59 | switch (sa->sa_family) { 60 | 61 | #if (NGX_HAVE_INET6) 62 | case AF_INET6: 63 | sin6 = (struct sockaddr_in6 *) sa; 64 | 65 | addr6 = port->addrs; 66 | 67 | /* the last address is "*" */ 68 | 69 | for (i = 0; i < port->naddrs - 1; i++) { 70 | if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { 71 | break; 72 | } 73 | } 74 | 75 | addr_conf = &addr6[i].conf; 76 | 77 | break; 78 | #endif 79 | 80 | case AF_UNIX: 81 | unix_socket = 1; 82 | /* fall through */ 83 | 84 | default: /* AF_INET */ 85 | sin = (struct sockaddr_in *) sa; 86 | 87 | addr = port->addrs; 88 | 89 | /* the last address is "*" */ 90 | 91 | for (i = 0; i < port->naddrs - 1; i++) { 92 | if (addr[i].addr == sin->sin_addr.s_addr) { 93 | break; 94 | } 95 | } 96 | 97 | addr_conf = &addr[i].conf; 98 | 99 | break; 100 | } 101 | 102 | } else { 103 | switch (c->local_sockaddr->sa_family) { 104 | 105 | #if (NGX_HAVE_INET6) 106 | case AF_INET6: 107 | addr6 = port->addrs; 108 | addr_conf = &addr6[0].conf; 109 | break; 110 | #endif 111 | 112 | case AF_UNIX: 113 | unix_socket = 1; 114 | /* fall through */ 115 | 116 | default: /* AF_INET */ 117 | addr = port->addrs; 118 | addr_conf = &addr[0].conf; 119 | break; 120 | } 121 | } 122 | 123 | ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client connected '%V'", 124 | c->number, &c->addr_text); 125 | 126 | s = ngx_rtmp_init_session(c, addr_conf); 127 | if (s == NULL) { 128 | return; 129 | } 130 | 131 | /* only auto-pushed connections are 132 | * done through unix socket */ 133 | 134 | s->auto_pushed = unix_socket; 135 | 136 | if (addr_conf->proxy_protocol) { 137 | ngx_rtmp_proxy_protocol(s); 138 | 139 | } else { 140 | ngx_rtmp_handshake(s); 141 | } 142 | } 143 | 144 | 145 | ngx_rtmp_session_t * 146 | ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) 147 | { 148 | ngx_rtmp_session_t *s; 149 | ngx_rtmp_core_srv_conf_t *cscf; 150 | ngx_rtmp_error_log_ctx_t *ctx; 151 | 152 | s = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_session_t) + 153 | sizeof(ngx_chain_t *) * ((ngx_rtmp_core_srv_conf_t *) 154 | addr_conf->ctx-> srv_conf[ngx_rtmp_core_module 155 | .ctx_index])->out_queue); 156 | if (s == NULL) { 157 | ngx_rtmp_close_connection(c); 158 | return NULL; 159 | } 160 | 161 | s->main_conf = addr_conf->ctx->main_conf; 162 | s->srv_conf = addr_conf->ctx->srv_conf; 163 | 164 | s->addr_text = &addr_conf->addr_text; 165 | 166 | c->data = s; 167 | s->connection = c; 168 | 169 | ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_error_log_ctx_t)); 170 | if (ctx == NULL) { 171 | ngx_rtmp_close_connection(c); 172 | return NULL; 173 | } 174 | 175 | ctx->client = &c->addr_text; 176 | ctx->session = s; 177 | 178 | c->log->connection = c->number; 179 | c->log->handler = ngx_rtmp_log_error; 180 | c->log->data = ctx; 181 | c->log->action = NULL; 182 | 183 | c->log_error = NGX_ERROR_INFO; 184 | 185 | s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_rtmp_max_module); 186 | if (s->ctx == NULL) { 187 | ngx_rtmp_close_connection(c); 188 | return NULL; 189 | } 190 | 191 | cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); 192 | 193 | s->out_queue = cscf->out_queue; 194 | s->out_cork = cscf->out_cork; 195 | s->in_streams = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_stream_t) 196 | * cscf->max_streams); 197 | if (s->in_streams == NULL) { 198 | ngx_rtmp_close_connection(c); 199 | return NULL; 200 | } 201 | 202 | #if (nginx_version >= 1007005) 203 | ngx_queue_init(&s->posted_dry_events); 204 | #endif 205 | 206 | s->epoch = ngx_current_msec; 207 | s->timeout = cscf->timeout; 208 | s->buflen = cscf->buflen; 209 | ngx_rtmp_set_chunk_size(s, NGX_RTMP_DEFAULT_CHUNK_SIZE); 210 | 211 | 212 | if (ngx_rtmp_fire_event(s, NGX_RTMP_CONNECT, NULL, NULL) != NGX_OK) { 213 | ngx_rtmp_finalize_session(s); 214 | return NULL; 215 | } 216 | 217 | return s; 218 | } 219 | 220 | 221 | static u_char * 222 | ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len) 223 | { 224 | u_char *p; 225 | ngx_rtmp_session_t *s; 226 | ngx_rtmp_error_log_ctx_t *ctx; 227 | 228 | if (log->action) { 229 | p = ngx_snprintf(buf, len, " while %s", log->action); 230 | len -= p - buf; 231 | buf = p; 232 | } 233 | 234 | ctx = log->data; 235 | 236 | p = ngx_snprintf(buf, len, ", client: %V", ctx->client); 237 | len -= p - buf; 238 | buf = p; 239 | 240 | s = ctx->session; 241 | 242 | if (s == NULL) { 243 | return p; 244 | } 245 | 246 | p = ngx_snprintf(buf, len, ", server: %V", s->addr_text); 247 | len -= p - buf; 248 | buf = p; 249 | 250 | return p; 251 | } 252 | 253 | 254 | static void 255 | ngx_rtmp_close_connection(ngx_connection_t *c) 256 | { 257 | ngx_pool_t *pool; 258 | 259 | ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close connection"); 260 | 261 | #if (NGX_STAT_STUB) 262 | (void) ngx_atomic_fetch_add(ngx_stat_active, -1); 263 | #endif 264 | 265 | pool = c->pool; 266 | ngx_close_connection(c); 267 | ngx_destroy_pool(pool); 268 | } 269 | 270 | 271 | static void 272 | ngx_rtmp_close_session_handler(ngx_event_t *e) 273 | { 274 | ngx_rtmp_session_t *s; 275 | ngx_connection_t *c; 276 | ngx_rtmp_core_srv_conf_t *cscf; 277 | 278 | s = e->data; 279 | c = s->connection; 280 | 281 | cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); 282 | 283 | ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close session"); 284 | 285 | ngx_rtmp_fire_event(s, NGX_RTMP_DISCONNECT, NULL, NULL); 286 | 287 | if (s->ping_evt.timer_set) { 288 | ngx_del_timer(&s->ping_evt); 289 | } 290 | 291 | if (s->in_old_pool) { 292 | ngx_destroy_pool(s->in_old_pool); 293 | } 294 | 295 | if (s->in_pool) { 296 | ngx_destroy_pool(s->in_pool); 297 | } 298 | 299 | ngx_rtmp_free_handshake_buffers(s); 300 | 301 | while (s->out_pos != s->out_last) { 302 | ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos++]); 303 | s->out_pos %= s->out_queue; 304 | } 305 | 306 | ngx_rtmp_close_connection(c); 307 | } 308 | 309 | 310 | void 311 | ngx_rtmp_finalize_session(ngx_rtmp_session_t *s) 312 | { 313 | ngx_event_t *e; 314 | ngx_connection_t *c; 315 | 316 | c = s->connection; 317 | if (c->destroyed) { 318 | return; 319 | } 320 | 321 | ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "finalize session"); 322 | 323 | c->destroyed = 1; 324 | e = &s->close; 325 | e->data = s; 326 | e->handler = ngx_rtmp_close_session_handler; 327 | e->log = c->log; 328 | 329 | ngx_post_event(e, &ngx_posted_events); 330 | } 331 | 332 | -------------------------------------------------------------------------------- /test/www/jwplayer_old/swfobject.js: -------------------------------------------------------------------------------- 1 | /* SWFObject v2.1 2 | Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis 3 | This software is released under the MIT License 4 | */ 5 | var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("