It's possible that we'll receive NetStream.Publish.Start _before_ the codec

module has parsed the meta data. To handle that case, we'll also try to call
@setDataFrame when we receive the @setDataFrame from the publisher.
This commit is contained in:
Jeffrey Wescott 2014-10-30 10:18:37 -07:00
parent 2a54c8e089
commit 1d21d68c3c

View file

@ -1327,7 +1327,7 @@ ngx_rtmp_relay_send_set_data_frame(ngx_rtmp_session_t *s)
};
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
if (ctx == NULL) {
if (ctx == NULL || !s->relay) {
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"relay: couldn't get relay context");
return NGX_OK;
@ -1335,14 +1335,15 @@ ngx_rtmp_relay_send_set_data_frame(ngx_rtmp_session_t *s)
/* 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);
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,
ngx_log_error(NGX_LOG_INFO, 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",
@ -1350,24 +1351,33 @@ ngx_rtmp_relay_send_set_data_frame(ngx_rtmp_session_t *s)
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));
/* we only want to send the metadata if the codec module has already
* parsed it -- is there a better way to check this? */
if (codec_ctx->width > 0 && codec_ctx->height > 0) {
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;
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]));
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"relay: sending @setDataFrame");
return ngx_rtmp_send_amf(s, &hdr, out_elts,
sizeof(out_elts) / sizeof(out_elts[0]));
}
return NGX_OK;
}
static ngx_int_t
@ -1445,8 +1455,12 @@ ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
*/
if (!ngx_strncasecmp(v.code, (u_char *)"NetStream.Publish.Start",
ngx_strlen("NetStream.Publish.Start"))) {
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"relay: sending metadata from NetStream.Publish.Start from player");
if (ngx_rtmp_relay_send_set_data_frame(s) != NGX_OK) {
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"relay: unable to send metadata via @setDataFrame");
}
}
@ -1454,6 +1468,26 @@ ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_relay_on_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_chain_t *in)
{
/* when we receive onMetaData, the session (s) is our incoming publisher's
* session, so we need to send the @setDataFrame to our ctx->play->session */
ngx_rtmp_relay_ctx_t *ctx;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
if (ctx == NULL || !ctx->play->session->relay) {
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"relay: not sending metadata from @setDataFrame event from publisher");
return NGX_OK;
}
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"relay: sending metadata from @setDataFrame event from publisher");
return ngx_rtmp_relay_send_set_data_frame(ctx->play->session);
}
static ngx_int_t
ngx_rtmp_relay_handshake_done(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
@ -1838,5 +1872,9 @@ ngx_rtmp_relay_postconfiguration(ngx_conf_t *cf)
ngx_str_set(&ch->name, "onStatus");
ch->handler = ngx_rtmp_relay_on_status;
ch = ngx_array_push(&cmcf->amf);
ngx_str_set(&ch->name, "@setDataFrame");
ch->handler = ngx_rtmp_relay_on_meta_data;
return NGX_OK;
}