diff --git a/ngx_rtmp_relay_module.c b/ngx_rtmp_relay_module.c index 4713f18..155378c 100644 --- a/ngx_rtmp_relay_module.c +++ b/ngx_rtmp_relay_module.c @@ -8,6 +8,7 @@ #include #include "ngx_rtmp_relay_module.h" #include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_codec_module.h" static ngx_rtmp_publish_pt next_publish; @@ -1231,12 +1232,150 @@ ngx_rtmp_relay_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } +static ngx_int_t +ngx_rtmp_relay_send_set_data_frame(ngx_rtmp_session_t *s) +{ + ngx_rtmp_relay_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_header_t hdr; + + static struct { + double width; + double height; + double duration; + double frame_rate; + double video_data_rate; + double video_codec_id; + double audio_data_rate; + double audio_codec_id; + u_char profile[32]; + u_char level[32]; + } v; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("Server"), + "NGINX RTMP (github.com/arut/nginx-rtmp-module)", 0 }, + + { 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("displayWidth"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("displayHeight"), + &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("fps"), + &v.frame_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videodatarate"), + &v.video_data_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videocodecid"), + &v.video_codec_id, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiodatarate"), + &v.audio_data_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiocodecid"), + &v.audio_codec_id, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("profile"), + &v.profile, sizeof(v.profile) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) } + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "@setDataFrame", 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onMetaData", 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, sizeof(out_inf) } + }; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: couldn't get relay context"); + return NGX_OK; + } + + /* we need to get the codec context from the incoming publisher in order to + * send the metadata along */ + codec_ctx = ngx_rtmp_get_module_ctx(ctx->publish->session, ngx_rtmp_codec_module); + if (codec_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: couldn't get codec context"); + return NGX_OK; + } + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: data frame from codec context: " + "width=%ui height=%ui duration=%ui frame_rate=%ui " + "video_codec_id=%ui audio_codec_id=%ui", + codec_ctx->width, codec_ctx->height, codec_ctx->duration, + codec_ctx->frame_rate, codec_ctx->video_codec_id, + codec_ctx->audio_codec_id); + + v.width = codec_ctx->width; + v.height = codec_ctx->height; + v.duration = codec_ctx->duration; + v.frame_rate = codec_ctx->frame_rate; + v.video_data_rate = codec_ctx->video_data_rate; + v.video_codec_id = codec_ctx->video_codec_id; + v.audio_data_rate = codec_ctx->audio_data_rate; + v.audio_codec_id = codec_ctx->audio_codec_id; + ngx_memcpy(v.profile, codec_ctx->profile, sizeof(codec_ctx->profile)); + ngx_memcpy(v.level, codec_ctx->level, sizeof(codec_ctx->level)); + + ngx_memzero(&hdr, sizeof(hdr)); + hdr.csid = NGX_RTMP_RELAY_CSID_AMF_INI; + hdr.msid = NGX_RTMP_RELAY_MSID; + hdr.type = NGX_RTMP_MSG_AMF_META; + + return ngx_rtmp_send_amf(s, &hdr, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} static ngx_int_t ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { ngx_rtmp_relay_ctx_t *ctx; + static struct { double trans; u_char level[32]; @@ -1300,6 +1439,18 @@ ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, "relay: onStatus: level='%s' code='%s' description='%s'", v.level, v.code, v.desc); + /* when doing a push to Adobe Media Server, we have to use the + * @setDataFrame command to send the metadata + * see: http://help.adobe.com/en_US/adobemediaserver/devguide/WS5b3ccc516d4fbf351e63e3d11a0773d56e-7ff6Dev.2.3.html + */ + if (!ngx_strncasecmp(v.code, (u_char *)"NetStream.Publish.Start", + ngx_strlen("NetStream.Publish.Start"))) { + if (ngx_rtmp_relay_send_set_data_frame(s) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: unable to send metadata via @setDataFrame"); + } + } + return NGX_OK; }