ngx_int_t ngx_rtmp_aggregate_message_handler(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { uint32_t base_time, timestamp, prev_size; size_t len; ngx_int_t first; u_char *last; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, *next; ngx_rtmp_header_t ch; ch = *h; first = 1; base_time = 0; while (in) { if (ngx_rtmp_fetch_uint8(&in, &ch.type) != NGX_OK) { return NGX_OK; } if (ngx_rtmp_fetch_uint32(&in, &ch.mlen, 3) != NGX_OK) { return NGX_ERROR; } if (ngx_rtmp_fetch_uint32(&in, ×tamp, 3) != NGX_OK) { return NGX_ERROR; } if (ngx_rtmp_fetch_uint8(&in, (uint8_t *) ×tamp + 3) != NGX_OK) { return NGX_ERROR; } if (ngx_rtmp_fetch_uint32(&in, &ch.msid, 3) != NGX_OK) { return NGX_ERROR; } if (first) { base_time = timestamp; first = 0; } ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "RTMP aggregate %s (%d) len=%uD time=%uD (+%D) msid=%uD", ngx_rtmp_message_type(ch.type), (ngx_int_t) ch.type, ch.mlen, ch.timestamp, timestamp - base_time, ch.msid); /* limit chain */ len = 0; cl = in; while (cl) { b = cl->buf; len += (b->last - b->pos); if (len > ch.mlen) { break; } cl = cl->next; } if (cl == NULL) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "RTMP error parsing aggregate"); return NGX_ERROR; } next = cl->next; cl->next = NULL; b = cl->buf; last = b->last; b->last -= (len - ch.mlen); /* handle aggregated message */ ch.timestamp = h->timestamp + timestamp - base_time; rc = ngx_rtmp_receive_message(s, &ch, in); /* restore chain before checking the result */ in = cl; in->next = next; b->pos = b->last; b->last = last; if (rc != NGX_OK) { return rc; } /* read 32-bit previous tag size */ if (ngx_rtmp_fetch_uint32(&in, &prev_size, 4) != NGX_OK) { return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "RTMP aggregate prev_size=%uD", prev_size); } return NGX_OK; }
static void ngx_live_relay_httpflv_recv_body(void *request, ngx_http_request_t *hcr) { ngx_int_t n; ngx_rtmp_session_t *s; ngx_chain_t *cl, *l, *in; ngx_rtmp_header_t *h; ngx_rtmp_stream_t *st = NULL; s = request; n = ngx_http_client_read_body(hcr, &cl); if (n == 0 || n == NGX_ERROR) { s->finalize_reason = n == 0? NGX_LIVE_NORMAL_CLOSE: NGX_LIVE_FLV_RECV_ERR; ngx_log_error(NGX_LOG_INFO, s->log, ngx_errno, "http relay, recv body error"); ngx_rtmp_finalize_session(s); return; } l = cl; for (;;) { if (l && l->buf->pos == l->buf->last) { l = l->next; } if (l == NULL) { return; } n = ngx_live_relay_httpflv_parse(s, l->buf); if (n == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, s->log, 0, "http relay, parse flv frame failed in state %d", s->flv_state); ngx_http_client_finalize_request(hcr, 1); return; } if (n == NGX_AGAIN) { continue; } /* NGX_OK */ st = &s->in_streams[0]; h = &st->hdr; in = st->in; if (ngx_rtmp_receive_message(s, h, in) != NGX_OK) { ngx_rtmp_finalize_session(s); return; } ngx_put_chainbufs(st->in); st->in = NULL; } }