diff --git a/ngx_rtmp_codec_module.c b/ngx_rtmp_codec_module.c
index 3ec3950..a727f50 100644
--- a/ngx_rtmp_codec_module.c
+++ b/ngx_rtmp_codec_module.c
@@ -146,11 +146,31 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_rtmp_header_t ch, lh;
ngx_uint_t *version;
+
+ if (h->type != NGX_RTMP_MSG_AUDIO && h->type != NGX_RTMP_MSG_VIDEO) {
+ return NGX_OK;
+ }
+
+ ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
+ if (ctx == NULL) {
+ ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t));
+ ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module);
+ }
+
+ /* save codec */
+ if (in->buf->last - in->buf->pos < 1) {
+ return NGX_OK;
+ }
+
+ fmt = in->buf->pos[0];
+ if (h->type == NGX_RTMP_MSG_AUDIO) {
+ ctx->audio_codec_id = (fmt & 0xf0) >> 4;
+ } else {
+ ctx->video_codec_id = (fmt & 0x0f);
+ }
+
/* save AVC/AAC header */
- if ((h->type != NGX_RTMP_MSG_AUDIO
- && h->type != NGX_RTMP_MSG_VIDEO)
- || in->buf->last - in->buf->pos < 2)
- {
+ if (in->buf->last - in->buf->pos < 2) {
return NGX_OK;
}
@@ -160,16 +180,9 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
}
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
- ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
- if (ctx == NULL) {
- ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t));
- ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module);
- }
-
- fmt = in->buf->pos[0];
header = NULL;
if (h->type == NGX_RTMP_MSG_AUDIO) {
- if (((fmt & 0xf0) >> 4) == NGX_RTMP_AUDIO_AAC) {
+ if (ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) {
header = &ctx->aac_header;
pheader = &ctx->aac_pheader;
version = &ctx->aac_version;
@@ -177,7 +190,7 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
"codec: AAC header arrived");
}
} else {
- if ((fmt & 0x0f) == NGX_RTMP_VIDEO_H264) {
+ if (ctx->video_codec_id == NGX_RTMP_VIDEO_H264) {
header = &ctx->avc_header;
pheader = &ctx->avc_pheader;
version = &ctx->avc_version;
@@ -219,11 +232,148 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
}
+static ngx_int_t
+ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
+ ngx_chain_t *in)
+{
+ ngx_rtmp_codec_ctx_t *ctx;
+ ngx_uint_t skip;
+
+ static struct {
+ double width;
+ double height;
+ double duration;
+ double frame_rate;
+ double video_data_rate;
+ double video_codec_id_n;
+ u_char video_codec_id_s[32];
+ double audio_data_rate;
+ double audio_codec_id_n;
+ u_char audio_codec_id_s[32];
+ } v;
+
+ static ngx_rtmp_amf_elt_t in_video_codec_id[] = {
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_null_string,
+ &v.video_codec_id_n, 0 },
+
+ { NGX_RTMP_AMF_STRING,
+ ngx_null_string,
+ &v.video_codec_id_s, sizeof(v.video_codec_id_s) },
+ };
+
+ static ngx_rtmp_amf_elt_t in_audio_codec_id[] = {
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_null_string,
+ &v.audio_codec_id_n, 0 },
+
+ { NGX_RTMP_AMF_STRING,
+ ngx_null_string,
+ &v.audio_codec_id_s, sizeof(v.audio_codec_id_s) },
+ };
+
+ static ngx_rtmp_amf_elt_t in_inf[] = {
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("width"),
+ &v.width, 0 },
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("height"),
+ &v.height, 0 },
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("duration"),
+ &v.duration, 0 },
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("framerate"),
+ &v.frame_rate, 0 },
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("videodatarate"),
+ &v.video_data_rate, 0 },
+
+ { NGX_RTMP_AMF_VARIANT,
+ ngx_string("videocodecid"),
+ in_video_codec_id, sizeof(in_video_codec_id) },
+
+ { NGX_RTMP_AMF_NUMBER,
+ ngx_string("audiodatarate"),
+ &v.audio_data_rate, 0 },
+
+ { NGX_RTMP_AMF_VARIANT,
+ ngx_string("audiocodecid"),
+ in_audio_codec_id, sizeof(in_audio_codec_id) },
+ };
+
+ static ngx_rtmp_amf_elt_t in_elts[] = {
+
+ { NGX_RTMP_AMF_STRING,
+ ngx_null_string,
+ NULL, 0 },
+
+ { NGX_RTMP_AMF_OBJECT,
+ ngx_null_string,
+ in_inf, sizeof(in_inf) },
+ };
+
+ ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
+ if (ctx == NULL) {
+ ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t));
+ ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module);
+ }
+
+ ngx_memzero(&v, sizeof(v));
+
+ /* use -1 as a sign of unchanged data;
+ * 0 is a valid value for uncompressed audio */
+ v.audio_codec_id_n = -1;
+
+ /* FFmpeg sends a string in front of actal metadata; ignore it */
+ skip = !(in->buf->last > in->buf->pos
+ && *in->buf->pos == NGX_RTMP_AMF_STRING);
+ if (ngx_rtmp_receive_amf(s, in, in_elts + skip,
+ sizeof(in_elts) / sizeof(in_elts[0]) - skip))
+ {
+ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+ "codec: error parsing data frame");
+ return NGX_OK;
+ }
+
+ ctx->width = v.width;
+ ctx->height = v.height;
+ ctx->duration = v.duration;
+ ctx->frame_rate = v.frame_rate;
+ ctx->video_data_rate = v.video_data_rate;
+ ctx->video_codec_id = v.video_codec_id_n;
+ ctx->audio_data_rate = v.audio_data_rate;
+ ctx->audio_codec_id = (v.audio_codec_id_n == -1
+ ? 0 : v.audio_codec_id_n == 0
+ ? NGX_RTMP_AUDIO_UNCOMPRESSED : v.audio_codec_id_n);
+
+ ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
+ "codec: data frame: "
+ "width=%ui height=%ui duration=%ui frame_rate=%ui "
+ "video=%s (%ui) audio=%s (%ui)",
+ ctx->width, ctx->height, ctx->duration, ctx->frame_rate,
+ ngx_rtmp_get_video_codec_name(ctx->video_codec_id),
+ ctx->video_codec_id,
+ ngx_rtmp_get_audio_codec_name(ctx->audio_codec_id),
+ ctx->audio_codec_id);
+
+ return NGX_OK;
+}
+
+
static ngx_int_t
ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf)
{
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_handler_pt *h;
+ ngx_rtmp_amf_handler_t *ch;
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);
@@ -236,5 +386,21 @@ ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf)
h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]);
*h = ngx_rtmp_codec_disconnect;
+ /* register metadata handler */
+ ch = ngx_array_push(&cmcf->amf);
+ if (ch == NULL) {
+ return NGX_ERROR;
+ }
+ ngx_str_set(&ch->name, "@setDataFrame");
+ ch->handler = ngx_rtmp_codec_meta_data;
+
+ ch = ngx_array_push(&cmcf->amf);
+ if (ch == NULL) {
+ return NGX_ERROR;
+ }
+ ngx_str_set(&ch->name, "onMetaData");
+ ch->handler = ngx_rtmp_codec_meta_data;
+
+
return NGX_OK;
}
diff --git a/ngx_rtmp_codec_module.h b/ngx_rtmp_codec_module.h
index 1d2d308..0b802e1 100644
--- a/ngx_rtmp_codec_module.h
+++ b/ngx_rtmp_codec_module.h
@@ -47,6 +47,15 @@ u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id);
typedef struct {
+ ngx_uint_t width;
+ ngx_uint_t height;
+ ngx_uint_t duration;
+ ngx_uint_t frame_rate;
+ ngx_uint_t video_data_rate;
+ ngx_uint_t video_codec_id;
+ ngx_uint_t audio_data_rate;
+ ngx_uint_t audio_codec_id;
+
ngx_uint_t avc_version;
ngx_uint_t aac_version;
diff --git a/ngx_rtmp_live_module.c b/ngx_rtmp_live_module.c
index fc3f45a..198f898 100644
--- a/ngx_rtmp_live_module.c
+++ b/ngx_rtmp_live_module.c
@@ -290,7 +290,6 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_rtmp_header_t ch, lh;
ngx_uint_t prio, peer_prio;
ngx_uint_t peers, dropped_peers;
- uint8_t flv_fmt;
size_t header_offset;
ngx_uint_t header_version;
@@ -351,15 +350,6 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
peers = 0;
dropped_peers = 0;
- if (in->buf->last - in->buf->pos >= 1) {
- flv_fmt = *in->buf->pos;
- if (h->type == NGX_RTMP_MSG_AUDIO) {
- ctx->stream->meta.audio_codec_id = (flv_fmt & 0xf0) >> 4;
- } else {
- ctx->stream->meta.video_codec_id = (flv_fmt & 0x0f);
- }
- }
-
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
header_out = NULL;
pheader_out = NULL;
@@ -489,192 +479,14 @@ next:
}
-static ngx_int_t
-ngx_rtmp_live_ext_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
- ngx_chain_t *in, ngx_uint_t skip)
-{
- ngx_rtmp_live_app_conf_t *lacf;
- ngx_rtmp_live_ctx_t *ctx;
- ngx_rtmp_live_meta_t *meta;
-
- static struct {
- double width;
- double height;
- double duration;
- double frame_rate;
- double video_data_rate;
- double video_codec_id_n;
- u_char video_codec_id_s[32];
- double audio_data_rate;
- double audio_codec_id_n;
- u_char audio_codec_id_s[32];
- } v;
-
- static ngx_rtmp_amf_elt_t in_video_codec_id[] = {
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_null_string,
- &v.video_codec_id_n, 0 },
-
- { NGX_RTMP_AMF_STRING,
- ngx_null_string,
- &v.video_codec_id_s, sizeof(v.video_codec_id_s) },
- };
-
- static ngx_rtmp_amf_elt_t in_audio_codec_id[] = {
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_null_string,
- &v.audio_codec_id_n, 0 },
-
- { NGX_RTMP_AMF_STRING,
- ngx_null_string,
- &v.audio_codec_id_s, sizeof(v.audio_codec_id_s) },
- };
-
- static ngx_rtmp_amf_elt_t in_inf[] = {
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("width"),
- &v.width, 0 },
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("height"),
- &v.height, 0 },
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("duration"),
- &v.duration, 0 },
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("framerate"),
- &v.frame_rate, 0 },
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("videodatarate"),
- &v.video_data_rate, 0 },
-
- { NGX_RTMP_AMF_VARIANT,
- ngx_string("videocodecid"),
- in_video_codec_id, sizeof(in_video_codec_id) },
-
- { NGX_RTMP_AMF_NUMBER,
- ngx_string("audiodatarate"),
- &v.audio_data_rate, 0 },
-
- { NGX_RTMP_AMF_VARIANT,
- ngx_string("audiocodecid"),
- in_audio_codec_id, sizeof(in_audio_codec_id) },
- };
-
- static ngx_rtmp_amf_elt_t in_elts[] = {
-
- { NGX_RTMP_AMF_STRING,
- ngx_null_string,
- NULL, 0 },
-
- { NGX_RTMP_AMF_OBJECT,
- ngx_null_string,
- in_inf, sizeof(in_inf) },
- };
-
-
- lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module);
- if (lacf == NULL || !lacf->live) {
- return NGX_OK;
- }
-
- ngx_memzero(&v, sizeof(v));
-
- /* use -1 as a sign of unchanged data;
- * 0 is a valid value for uncompressed audio */
- v.audio_codec_id_n = -1;
-
- if (ngx_rtmp_receive_amf(s, in, in_elts + skip,
- sizeof(in_elts) / sizeof(in_elts[0]) - skip))
- {
- ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
- "live: error parsing data frame");
- return NGX_OK;
- }
-
- ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module);
- if (ctx == NULL) {
- return NGX_OK;
- }
-
- if ((ctx->flags & NGX_RTMP_LIVE_PUBLISHING) == 0) {
- ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
- "live: received data stream from non-publisher");
- return NGX_OK;
- }
-
- meta = &ctx->stream->meta;
- meta->width = v.width;
- meta->height = v.height;
- meta->duration = v.duration;
- meta->frame_rate = v.frame_rate;
- meta->video_data_rate = v.video_data_rate;
- meta->video_codec_id = v.video_codec_id_n;
- meta->audio_data_rate = v.audio_data_rate;
- meta->audio_codec_id = (v.audio_codec_id_n == -1
- ? 0 : v.audio_codec_id_n == 0
- ? NGX_RTMP_AUDIO_UNCOMPRESSED : v.audio_codec_id_n);
-
- ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
- "live: data frame: "
- "width=%ui height=%ui duration=%ui frame_rate=%ui "
- "video=%s (%ui) audio=%s (%ui)",
- meta->width, meta->height, meta->duration, meta->frame_rate,
- ngx_rtmp_get_video_codec_name(meta->video_codec_id),
- meta->video_codec_id,
- ngx_rtmp_get_audio_codec_name(meta->audio_codec_id),
- meta->audio_codec_id);
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_rtmp_live_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
- ngx_chain_t *in)
-{
- return ngx_rtmp_live_ext_meta_data(s, h, in, 0);
-}
-
-
-static ngx_int_t
-ngx_rtmp_live_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
- ngx_chain_t *in)
-{
- return ngx_rtmp_live_ext_meta_data(s, h, in, 1);
-}
-
-
static ngx_int_t
ngx_rtmp_live_postconfiguration(ngx_conf_t *cf)
{
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_handler_pt *h;
- ngx_rtmp_amf_handler_t *ch;
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);
- /* register metadata handler */
- ch = ngx_array_push(&cmcf->amf);
- if (ch == NULL) {
- return NGX_ERROR;
- }
- ngx_str_set(&ch->name, "@setDataFrame");
- ch->handler = ngx_rtmp_live_data_frame;
-
- ch = ngx_array_push(&cmcf->amf);
- if (ch == NULL) {
- return NGX_ERROR;
- }
- ngx_str_set(&ch->name, "onMetaData");
- ch->handler = ngx_rtmp_live_meta_data;
-
/* register raw event handlers */
h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]);
*h = ngx_rtmp_live_av;
diff --git a/ngx_rtmp_live_module.h b/ngx_rtmp_live_module.h
index ac5e7ac..73b64ef 100644
--- a/ngx_rtmp_live_module.h
+++ b/ngx_rtmp_live_module.h
@@ -22,18 +22,6 @@
#define NGX_RTMP_LIVE_MSID 1
-typedef struct {
- ngx_uint_t width;
- ngx_uint_t height;
- ngx_uint_t duration;
- ngx_uint_t frame_rate;
- ngx_uint_t video_data_rate;
- ngx_uint_t video_codec_id;
- ngx_uint_t audio_data_rate;
- ngx_uint_t audio_codec_id;
-} ngx_rtmp_live_meta_t;
-
-
typedef struct ngx_rtmp_live_ctx_s ngx_rtmp_live_ctx_t;
typedef struct ngx_rtmp_live_stream_s ngx_rtmp_live_stream_t;
@@ -61,7 +49,6 @@ struct ngx_rtmp_live_stream_s {
ngx_uint_t flags;
ngx_rtmp_bandwidth_t bw_in;
ngx_rtmp_bandwidth_t bw_out;
- ngx_rtmp_live_meta_t meta;
ngx_msec_t epoch;
};
diff --git a/ngx_rtmp_stat_module.c b/ngx_rtmp_stat_module.c
index f55cc90..f3b609f 100644
--- a/ngx_rtmp_stat_module.c
+++ b/ngx_rtmp_stat_module.c
@@ -250,7 +250,7 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
ngx_rtmp_live_app_conf_t *lacf)
{
ngx_rtmp_live_stream_t *stream;
- ngx_rtmp_live_meta_t *meta;
+ ngx_rtmp_codec_ctx_t *codec;
ngx_rtmp_live_ctx_t *ctx;
ngx_rtmp_session_t *s;
ngx_int_t n;
@@ -258,7 +258,7 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
ngx_int_t publishing;
u_char buf[NGX_OFF_T_LEN + 1];
ngx_rtmp_stat_loc_conf_t *slcf;
- u_char *codec;
+ u_char *cname;
slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module);
@@ -279,36 +279,12 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
"%M", ngx_current_msec - stream->epoch) - buf);
NGX_RTMP_STAT_L("");
- meta = &stream->meta;
- NGX_RTMP_STAT_L("");
- NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
- "%ui", meta->width) - buf);
- NGX_RTMP_STAT_L("");
- NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
- "%ui", meta->height) - buf);
- NGX_RTMP_STAT_L("");
- NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
- "%ui", meta->frame_rate) - buf);
- NGX_RTMP_STAT_L("\r\n");
-
ngx_rtmp_stat_bw(r, lll, &stream->bw_in, &stream->bw_out);
nclients = 0;
+ codec = NULL;
for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) {
s = ctx->session;
- /* TODO: add
- * 1) session start time
- * 2) drop stats */
if (slcf->stat & NGX_RTMP_STAT_CLIENTS) {
NGX_RTMP_STAT_L("");
@@ -356,10 +332,34 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
}
if (ctx->flags & NGX_RTMP_LIVE_PUBLISHING) {
publishing = 1;
+ codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
}
}
total_nclients += nclients;
+ if (codec) {
+ NGX_RTMP_STAT_L("");
+ NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
+ "%ui", codec->width) - buf);
+ NGX_RTMP_STAT_L("");
+ NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
+ "%ui", codec->height) - buf);
+ NGX_RTMP_STAT_L("");
+ NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
+ "%ui", codec->frame_rate) - buf);
+ NGX_RTMP_STAT_L("\r\n");
+ }
+
NGX_RTMP_STAT_L("");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%uz", nclients) - buf);