mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-05-09 06:01:08 +02:00
added AMF shortcuts & project-wide stream numbers; updated mp4 streamer
This commit is contained in:
parent
f22e72ab21
commit
a92d23d530
25
ngx_rtmp.h
25
ngx_rtmp.h
|
@ -375,6 +375,27 @@ void * ngx_rtmp_rmemcpy(void *dst, const void* src, size_t n);
|
|||
(((u_char*)ngx_rtmp_rmemcpy(dst, src, n)) + (n))
|
||||
|
||||
|
||||
static inline uint16_t
|
||||
ngx_rtmp_r16(uint16_t n)
|
||||
{
|
||||
return (n << 8) | (n >> 8);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
ngx_rtmp_r32(uint32_t n)
|
||||
{
|
||||
return (n << 24) | ((n << 8) & 0xff0000) | ((n >> 8) & 0xff00) | (n >> 24);
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t
|
||||
ngx_rtmp_r64(uint64_t n)
|
||||
{
|
||||
return (uint64_t) ngx_rtmp_r32(n) << 32 | ngx_rtmp_r32(n >> 32);
|
||||
}
|
||||
|
||||
|
||||
/* Receiving messages */
|
||||
ngx_int_t ngx_rtmp_protocol_message_handler(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_header_t *h, ngx_chain_t *in);
|
||||
|
@ -469,6 +490,10 @@ ngx_int_t ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
ngx_int_t ngx_rtmp_receive_amf(ngx_rtmp_session_t *s, ngx_chain_t *in,
|
||||
ngx_rtmp_amf_elt_t *elts, size_t nelts);
|
||||
|
||||
/* AMF status sender */
|
||||
ngx_int_t ngx_rtmp_send_status(ngx_rtmp_session_t *s, char *code,
|
||||
char* level, char *desc);
|
||||
|
||||
|
||||
/* Frame types */
|
||||
#define NGX_RTMP_VIDEO_KEY_FRAME 1
|
||||
|
|
|
@ -3,15 +3,12 @@
|
|||
*/
|
||||
|
||||
#include "ngx_rtmp_cmd_module.h"
|
||||
#include "ngx_rtmp_streams.h"
|
||||
|
||||
|
||||
#define NGX_RTMP_FMS_VERSION "FMS/3,0,1,123"
|
||||
#define NGX_RTMP_CAPABILITIES 31
|
||||
|
||||
#define NGX_RTMP_CMD_CSID_AMF_INI 3
|
||||
#define NGX_RTMP_CMD_CSID_AMF 5
|
||||
#define NGX_RTMP_CMD_MSID 1
|
||||
|
||||
|
||||
ngx_rtmp_connect_pt ngx_rtmp_connect;
|
||||
ngx_rtmp_create_stream_pt ngx_rtmp_create_stream;
|
||||
|
|
|
@ -10,19 +10,13 @@
|
|||
#include "ngx_rtmp.h"
|
||||
#include "ngx_rtmp_cmd_module.h"
|
||||
#include "ngx_rtmp_bandwidth.h"
|
||||
#include "ngx_rtmp_streams.h"
|
||||
|
||||
|
||||
/* session flags */
|
||||
#define NGX_RTMP_LIVE_PUBLISHING 0x01
|
||||
|
||||
|
||||
/* Chunk stream ids for output */
|
||||
#define NGX_RTMP_LIVE_CSID_META 5
|
||||
#define NGX_RTMP_LIVE_CSID_AUDIO 6
|
||||
#define NGX_RTMP_LIVE_CSID_VIDEO 7
|
||||
#define NGX_RTMP_LIVE_MSID 1
|
||||
|
||||
|
||||
typedef struct ngx_rtmp_live_ctx_s ngx_rtmp_live_ctx_t;
|
||||
typedef struct ngx_rtmp_live_stream_s ngx_rtmp_live_stream_t;
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
|
||||
#include "ngx_rtmp_cmd_module.h"
|
||||
#include "ngx_rtmp_live_module.h"
|
||||
#include "ngx_rtmp_codec_module.h"
|
||||
#include "ngx_rtmp_streams.h"
|
||||
|
||||
|
||||
static ngx_rtmp_play_pt next_play;
|
||||
|
@ -118,6 +118,8 @@ typedef struct {
|
|||
ngx_int_t key;
|
||||
uint32_t delay;
|
||||
|
||||
unsigned valid:1;
|
||||
|
||||
ngx_uint_t pos;
|
||||
|
||||
ngx_uint_t key_pos;
|
||||
|
@ -186,56 +188,8 @@ typedef struct {
|
|||
} ngx_rtmp_mp4_ctx_t;
|
||||
|
||||
|
||||
/* system stuff for mmapping; 4K pages assumed */
|
||||
/* TODO: more portable code */
|
||||
#define NGX_RTMP_PAGE_SHIFT 12
|
||||
#define NGX_RTMP_PAGE_SIZE (1 << NGX_RTMP_PAGE_SHIFT)
|
||||
#define NGX_RTMP_PAGE_MASK (NGX_RTMP_PAGE_SIZE - 1)
|
||||
|
||||
|
||||
#define ngx_rtmp_mp4_make_tag(a, b, c, d) ((uint32_t) d << 24 | \
|
||||
(uint32_t) c << 16 | \
|
||||
(uint32_t) b << 8 | \
|
||||
(uint32_t) a)
|
||||
|
||||
|
||||
/*
|
||||
#define ngx_rtmp_r32(n) (((n) & 0x000000ffull) << 24 | \
|
||||
((n) & 0x0000ff00ull) << 8 | \
|
||||
((n) & 0x00ff0000ull) >> 8 | \
|
||||
((n) & 0xff000000ull) >> 24)
|
||||
*/
|
||||
|
||||
static inline uint16_t
|
||||
ngx_rtmp_r16(uint16_t n)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
/*TODO: optimize */
|
||||
ngx_rtmp_rmemcpy(&ret, &n, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
ngx_rtmp_r32(uint32_t n)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
/*TODO: optimize */
|
||||
ngx_rtmp_rmemcpy(&ret, &n, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t
|
||||
ngx_rtmp_r64(uint64_t n)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
ngx_rtmp_rmemcpy(&ret, &n, 8);
|
||||
return ret;
|
||||
}
|
||||
#define ngx_rtmp_mp4_make_tag(a, b, c, d) \
|
||||
((uint32_t)d << 24 | (uint32_t)c << 16 | (uint32_t)b << 8 | (uint32_t)a)
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
|
@ -252,8 +206,6 @@ ngx_rtmp_mp4_from_rtmp_timestamp(ngx_rtmp_mp4_track_t *t, uint32_t ts)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define NGX_RTMP_MP4_DEFAULT_BUFLEN 1000
|
||||
|
||||
|
||||
|
@ -526,14 +478,14 @@ ngx_rtmp_mp4_parse_hdlr(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
|||
|
||||
if (type == ngx_rtmp_mp4_make_tag('v','i','d','e')) {
|
||||
ctx->track->type = NGX_RTMP_MSG_VIDEO;
|
||||
ctx->track->csid = NGX_RTMP_LIVE_CSID_VIDEO;
|
||||
ctx->track->csid = NGX_RTMP_CSID_VIDEO;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: video track");
|
||||
|
||||
} else if (type == ngx_rtmp_mp4_make_tag('s','o','u','n')) {
|
||||
ctx->track->type = NGX_RTMP_MSG_AUDIO;
|
||||
ctx->track->csid = NGX_RTMP_LIVE_CSID_AUDIO;
|
||||
ctx->track->csid = NGX_RTMP_CSID_AUDIO;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: audio track");
|
||||
|
@ -1082,7 +1034,6 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s)
|
|||
offset = 0;
|
||||
size = 0;
|
||||
|
||||
/* find moov box */
|
||||
for ( ;; ) {
|
||||
n = ngx_read_file(&ctx->file, (u_char *) &hdr, sizeof(hdr), offset);
|
||||
|
||||
|
@ -1093,8 +1044,6 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s)
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*TODO: implement 64-bit boxes */
|
||||
|
||||
size = ngx_rtmp_r32(hdr[0]);
|
||||
|
||||
if (hdr[1] == ngx_rtmp_mp4_make_tag('m','o','o','v')) {
|
||||
|
@ -1116,8 +1065,7 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s)
|
|||
size -= 8;
|
||||
offset += 8;
|
||||
|
||||
/* mmap moov box */
|
||||
page_offset = (offset & NGX_RTMP_PAGE_MASK);
|
||||
page_offset = offset & (ngx_pagesize - 1);
|
||||
ctx->mmaped_size = page_offset + size;
|
||||
|
||||
ctx->mmaped = mmap(NULL, ctx->mmaped_size, PROT_READ, MAP_SHARED,
|
||||
|
@ -1131,7 +1079,6 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s)
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* locate all required data within mapped area */
|
||||
return ngx_rtmp_mp4_parse(s, (u_char *) ctx->mmaped + page_offset,
|
||||
(u_char *) ctx->mmaped + page_offset + size);
|
||||
}
|
||||
|
@ -1214,7 +1161,6 @@ ngx_rtmp_mp4_seek_time(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t,
|
|||
ngx_rtmp_mp4_cursor_t *cr;
|
||||
ngx_rtmp_mp4_time_entry_t *te;
|
||||
uint32_t dt;
|
||||
ngx_uint_t dn;
|
||||
|
||||
if (t->times == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
@ -1232,9 +1178,9 @@ ngx_rtmp_mp4_seek_time(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t,
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dn = (timestamp - cr->timestamp) / ngx_rtmp_r32(te->sample_delta);
|
||||
cr->timestamp += ngx_rtmp_r32(te->sample_delta) * dn;
|
||||
cr->pos += dn;
|
||||
cr->time_count = (timestamp - cr->timestamp) / ngx_rtmp_r32(te->sample_delta);
|
||||
cr->timestamp += ngx_rtmp_r32(te->sample_delta) * cr->time_count;
|
||||
cr->pos += cr->time_count;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1758,12 +1704,18 @@ ngx_rtmp_mp4_seek_delay(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t)
|
|||
static ngx_int_t
|
||||
ngx_rtmp_mp4_next(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t)
|
||||
{
|
||||
return ngx_rtmp_mp4_next_time(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_key(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_chunk(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_size(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_delay(s, t) != NGX_OK
|
||||
? NGX_ERROR : NGX_OK;
|
||||
if (ngx_rtmp_mp4_next_time(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_key(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_chunk(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_size(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_next_delay(s, t) != NGX_OK)
|
||||
{
|
||||
t->cursor.valid = 0;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
t->cursor.valid = 1;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1868,8 +1820,8 @@ ngx_rtmp_mp4_send_meta(ngx_rtmp_session_t *s)
|
|||
|
||||
ngx_memzero(&h, sizeof(h));
|
||||
|
||||
h.csid = NGX_RTMP_LIVE_CSID_META;
|
||||
h.msid = NGX_RTMP_LIVE_MSID;
|
||||
h.csid = NGX_RTMP_CSID_AMF;
|
||||
h.msid = NGX_RTMP_MSID;
|
||||
h.type = NGX_RTMP_MSG_AMF_META;
|
||||
|
||||
ngx_rtmp_prepare_message(s, &h, NULL, out);
|
||||
|
@ -1928,7 +1880,7 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
for (n = 0; n < ctx->ntracks; ++n, ++t) {
|
||||
cr = &t->cursor;
|
||||
|
||||
if (cr->size == 0) {
|
||||
if (!cr->valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1946,7 +1898,7 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
|
||||
ngx_memzero(&h, sizeof(h));
|
||||
|
||||
h.msid = NGX_RTMP_LIVE_MSID;
|
||||
h.msid = NGX_RTMP_MSID;
|
||||
h.type = t->type;
|
||||
h.csid = t->csid;
|
||||
|
||||
|
@ -1989,8 +1941,7 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: track#%ui read frame "
|
||||
"offset=%O, size=%uz, timestamp=%uD, duration=%uD",
|
||||
t->id, cr->offset, cr->size, timestamp,
|
||||
cr->duration);
|
||||
t->id, cr->offset, cr->size, timestamp, duration);
|
||||
|
||||
fhdr_size = (t->header ? 5 : 1);
|
||||
|
||||
|
@ -2012,8 +1963,14 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
|
||||
ngx_rtmp_mp4_buffer[0] = t->fhdr;
|
||||
|
||||
if (cr->key) {
|
||||
ngx_rtmp_mp4_buffer[0] |= 0x10;
|
||||
if (h.type == NGX_RTMP_MSG_VIDEO) {
|
||||
if (cr->key) {
|
||||
ngx_rtmp_mp4_buffer[0] |= 0x10;
|
||||
} else if (cr->delay) {
|
||||
ngx_rtmp_mp4_buffer[0] |= 0x20;
|
||||
} else {
|
||||
ngx_rtmp_mp4_buffer[0] |= 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
if (fhdr_size > 1) {
|
||||
|
@ -2057,7 +2014,12 @@ next:
|
|||
again:
|
||||
if (active) {
|
||||
ngx_post_event(e, &ngx_posted_events);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_MSID);
|
||||
|
||||
ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stopped");
|
||||
}
|
||||
|
||||
|
||||
|
@ -2070,13 +2032,18 @@ ngx_rtmp_mp4_seek_track(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t,
|
|||
cr = &t->cursor;
|
||||
ngx_memzero(cr, sizeof(*cr));
|
||||
|
||||
return ngx_rtmp_mp4_seek_time(s, t, ngx_rtmp_mp4_from_rtmp_timestamp(
|
||||
if (ngx_rtmp_mp4_seek_time(s, t, ngx_rtmp_mp4_from_rtmp_timestamp(
|
||||
t, timestamp)) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_key(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_chunk(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_size(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_delay(s, t) != NGX_OK
|
||||
? NGX_ERROR : NGX_OK;
|
||||
ngx_rtmp_mp4_seek_key(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_chunk(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_size(s, t) != NGX_OK ||
|
||||
ngx_rtmp_mp4_seek_delay(s, t) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cr->valid = 1;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2097,6 +2064,10 @@ ngx_rtmp_mp4_start(ngx_rtmp_session_t *s, ngx_int_t timestamp)
|
|||
|
||||
ngx_rtmp_mp4_stop(s);
|
||||
|
||||
if (timestamp < 0) {
|
||||
timestamp = 0;
|
||||
}
|
||||
|
||||
for (n = 0; n < ctx->ntracks; ++n) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: track#%ui seek", n);
|
||||
|
|
|
@ -453,7 +453,8 @@ ngx_rtmp_play_send(ngx_event_t *e)
|
|||
if (n != sizeof(ngx_rtmp_play_header)) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"play: could not read flv tag header");
|
||||
ngx_rtmp_send_user_stream_eof(s, 1);
|
||||
ngx_rtmp_send_user_stream_eof(s, NGX_RTMP_MSID);
|
||||
ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stopped");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ngx_rtmp.h"
|
||||
#include "ngx_rtmp_amf.h"
|
||||
#include "ngx_rtmp_streams.h"
|
||||
|
||||
|
||||
#define NGX_RTMP_USER_START(s, tp) \
|
||||
|
@ -262,7 +263,9 @@ ngx_rtmp_append_amf(ngx_rtmp_session_t *s,
|
|||
return rc;
|
||||
}
|
||||
|
||||
ngx_int_t ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
||||
|
||||
ngx_int_t
|
||||
ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
||||
ngx_rtmp_amf_elt_t *elts, size_t nelts)
|
||||
{
|
||||
ngx_chain_t *first;
|
||||
|
@ -287,3 +290,59 @@ done:
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_rtmp_send_status(ngx_rtmp_session_t *s, char *code, char* level, char *desc)
|
||||
{
|
||||
ngx_rtmp_header_t h;
|
||||
static double trans;
|
||||
|
||||
static ngx_rtmp_amf_elt_t out_inf[] = {
|
||||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_string("code"),
|
||||
NULL, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_string("level"),
|
||||
NULL, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_string("description"),
|
||||
NULL, 0 },
|
||||
};
|
||||
|
||||
static ngx_rtmp_amf_elt_t out_elts[] = {
|
||||
|
||||
{ NGX_RTMP_AMF_STRING,
|
||||
ngx_null_string,
|
||||
"onStatus", 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NUMBER,
|
||||
ngx_null_string,
|
||||
&trans, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_NULL,
|
||||
ngx_null_string,
|
||||
NULL, 0 },
|
||||
|
||||
{ NGX_RTMP_AMF_OBJECT,
|
||||
ngx_null_string,
|
||||
out_inf,
|
||||
sizeof(out_inf) },
|
||||
};
|
||||
|
||||
|
||||
out_inf[0].data = code;
|
||||
out_inf[1].data = level;
|
||||
out_inf[2].data = desc;
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
|
||||
h.type = NGX_RTMP_MSG_AMF_CMD;
|
||||
h.csid = NGX_RTMP_CSID_AMF;
|
||||
h.msid = NGX_RTMP_MSID;
|
||||
|
||||
return ngx_rtmp_send_amf(s, &h, out_elts,
|
||||
sizeof(out_elts) / sizeof(out_elts[0]));
|
||||
}
|
||||
|
|
28
ngx_rtmp_streams.h
Normal file
28
ngx_rtmp_streams.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Roman Arutyunyan
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RTMP_STREAMS_H_INCLUDED_
|
||||
#define _NGX_RTMP_STREAMS_H_INCLUDED_
|
||||
|
||||
|
||||
#define NGX_RTMP_MSID 1
|
||||
|
||||
#define NGX_RTMP_CSID_AMF_INI 3
|
||||
#define NGX_RTMP_CSID_AMF 5
|
||||
#define NGX_RTMP_CSID_AUDIO 6
|
||||
#define NGX_RTMP_CSID_VIDEO 7
|
||||
|
||||
|
||||
/*legacy*/
|
||||
#define NGX_RTMP_CMD_CSID_AMF_INI NGX_RTMP_CSID_AMF_INI
|
||||
#define NGX_RTMP_CMD_CSID_AMF NGX_RTMP_CSID_AMF
|
||||
#define NGX_RTMP_CMD_MSID NGX_RTMP_MSID
|
||||
#define NGX_RTMP_LIVE_CSID_META NGX_RTMP_CSID_AMF
|
||||
#define NGX_RTMP_LIVE_CSID_AUDIO NGX_RTMP_CSID_AUDIO
|
||||
#define NGX_RTMP_LIVE_CSID_VIDEO NGX_RTMP_CSID_VIDEO
|
||||
#define NGX_RTMP_LIVE_MSID NGX_RTMP_MSID
|
||||
|
||||
|
||||
#endif /* _NGX_RTMP_STREAMS_H_INCLUDED_ */
|
Loading…
Reference in a new issue