mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-05-15 08:21:09 +02:00
implemented MPEG ES descriptor parser; AAC is now fully supported
This commit is contained in:
parent
a92d23d530
commit
7f447bbe95
|
@ -289,6 +289,32 @@ static ngx_rtmp_mp4_box_t ngx_rtmp_mp4_boxes[] = {
|
|||
};
|
||||
|
||||
|
||||
static ngx_int_t ngx_rtmp_mp4_parse_descr(ngx_rtmp_session_t *s, u_char *pos,
|
||||
u_char *last);
|
||||
static ngx_int_t ngx_rtmp_mp4_parse_es(ngx_rtmp_session_t *s, u_char *pos,
|
||||
u_char *last);
|
||||
static ngx_int_t ngx_rtmp_mp4_parse_dc(ngx_rtmp_session_t *s, u_char *pos,
|
||||
u_char *last);
|
||||
static ngx_int_t ngx_rtmp_mp4_parse_ds(ngx_rtmp_session_t *s, u_char *pos,
|
||||
u_char *last);
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_rtmp_mp4_descriptor_pt)(ngx_rtmp_session_t *s,
|
||||
u_char *pos, u_char *last);
|
||||
|
||||
typedef struct {
|
||||
uint8_t tag;
|
||||
ngx_rtmp_mp4_descriptor_pt handler;
|
||||
} ngx_rtmp_mp4_descriptor_t;
|
||||
|
||||
|
||||
static ngx_rtmp_mp4_descriptor_t ngx_rtmp_mp4_descriptors[] = {
|
||||
{ 0x03, ngx_rtmp_mp4_parse_es }, /* MPEG ES Descriptor */
|
||||
{ 0x04, ngx_rtmp_mp4_parse_dc }, /* MPEG DecoderConfig Descriptor */
|
||||
{ 0x05, ngx_rtmp_mp4_parse_ds } /* MPEG DecoderSpecific Descriptor */
|
||||
};
|
||||
|
||||
|
||||
static ngx_command_t ngx_rtmp_mp4_commands[] = {
|
||||
|
||||
{ ngx_string("play_mp4"),
|
||||
|
@ -526,13 +552,17 @@ ngx_rtmp_mp4_parse_video(ngx_rtmp_session_t *s, u_char *pos, u_char *last,
|
|||
|
||||
pos += 52;
|
||||
|
||||
ctx->track->fhdr = codec;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: video settings codec=%i, width=%ui, height=%ui",
|
||||
codec, ctx->width, ctx->height);
|
||||
|
||||
return ngx_rtmp_mp4_parse(s, pos, last);
|
||||
if (ngx_rtmp_mp4_parse(s, pos, last) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx->track->fhdr = ctx->track->codec;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,14 +625,18 @@ ngx_rtmp_mp4_parse_audio(ngx_rtmp_session_t *s, u_char *pos, u_char *last,
|
|||
break;
|
||||
}
|
||||
|
||||
*p |= (codec << 4);
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: audio settings codec=%i, nchannels==%ui, "
|
||||
"sample_size=%ui, sample_rate=%ui",
|
||||
codec, ctx->nchannels, ctx->sample_size, ctx->sample_rate);
|
||||
|
||||
return ngx_rtmp_mp4_parse(s, pos, last);
|
||||
if (ngx_rtmp_mp4_parse(s, pos, last) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*p |= (ctx->track->codec << 4);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -647,33 +681,190 @@ ngx_rtmp_mp4_parse_mp4a(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_esds(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
ngx_rtmp_mp4_parse_ds(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
ngx_rtmp_mp4_ctx_t *ctx;
|
||||
|
||||
if (pos == last) {
|
||||
return NGX_OK;
|
||||
}
|
||||
ngx_rtmp_mp4_ctx_t *ctx;
|
||||
ngx_rtmp_mp4_track_t *t;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module);
|
||||
|
||||
if (ctx->track == NULL || ctx->track->codec != NGX_RTMP_AUDIO_AAC) {
|
||||
t = ctx->track;
|
||||
|
||||
if (t == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/*TODO: parse AAC header? */
|
||||
|
||||
ctx->track->header = pos;
|
||||
ctx->track->header_size = (size_t) (last - pos);
|
||||
t->header = pos;
|
||||
t->header_size = (size_t) (last - pos);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: audio AAC header size=%uz",
|
||||
ctx->track->header_size);
|
||||
"mp4: decoder header size=%uz", t->header_size);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_dc(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
uint8_t id;
|
||||
ngx_rtmp_mp4_ctx_t *ctx;
|
||||
ngx_int_t *pc;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module);
|
||||
|
||||
if (ctx->track == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (pos + 13 > last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
id = * (uint8_t *) pos;
|
||||
pos += 13;
|
||||
pc = &ctx->track->codec;
|
||||
|
||||
switch (id) {
|
||||
case 0x21:
|
||||
*pc = NGX_RTMP_VIDEO_H264;
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x66:
|
||||
case 0x67:
|
||||
case 0x68:
|
||||
*pc = NGX_RTMP_AUDIO_AAC;
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
case 0x6b:
|
||||
*pc = NGX_RTMP_AUDIO_MP3;
|
||||
break;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: decoder descriptor id=%i codec=%i",
|
||||
(ngx_int_t) id, *pc);
|
||||
|
||||
return ngx_rtmp_mp4_parse_descr(s, pos, last);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_es(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
uint16_t id;
|
||||
uint8_t flags;
|
||||
|
||||
if (pos + 3 > last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
id = ngx_rtmp_r16(*(uint16_t *) pos);
|
||||
pos += 2;
|
||||
|
||||
flags = *(uint8_t *) pos;
|
||||
++pos;
|
||||
|
||||
if (flags & 0x80) { /* streamDependenceFlag */
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if (flags & 0x40) { /* URL_FLag */
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (flags & 0x20) { /* OCRstreamFlag */
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if (pos > last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
(void) id;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: es descriptor es id=%i flags=%i",
|
||||
(ngx_int_t) id, (ngx_int_t) flags);
|
||||
|
||||
return ngx_rtmp_mp4_parse_descr(s, pos, last);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_descr(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
uint8_t tag, v;
|
||||
uint32_t size;
|
||||
ngx_uint_t n, ndesc;
|
||||
ngx_rtmp_mp4_descriptor_t *ds;
|
||||
|
||||
ndesc = sizeof(ngx_rtmp_mp4_descriptors)
|
||||
/ sizeof(ngx_rtmp_mp4_descriptors[0]);
|
||||
|
||||
while (pos < last) {
|
||||
tag = *(uint8_t *) pos++;
|
||||
|
||||
for (size = 0, n = 0; n < 4; ++n) {
|
||||
if (pos == last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
v = *(uint8_t *) pos++;
|
||||
|
||||
size = (size << 7) | (v & 0x7f);
|
||||
|
||||
if (!(v & 0x80)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos + size > last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ds = ngx_rtmp_mp4_descriptors;;
|
||||
|
||||
for (n = 0; n < ndesc; ++n, ++ds) {
|
||||
if (tag == ds->tag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == ndesc) {
|
||||
ds = NULL;
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: descriptor%s tag=%i size=%uD",
|
||||
ds ? "" : " unhandled", (ngx_int_t) tag, size);
|
||||
|
||||
if (ds && ds->handler(s, pos, pos + size) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pos += size;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_esds(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
if (pos + 4 > last) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pos += 4; /* version */
|
||||
|
||||
return ngx_rtmp_mp4_parse_descr(s, pos, last);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_parse_mp3(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
||||
{
|
||||
|
@ -1914,12 +2105,20 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
"mp4: track#%ui sending header of size=%uz",
|
||||
t->id, t->header_size);
|
||||
|
||||
fhdr[0] = t->fhdr | 0x10;
|
||||
fhdr[1] = fhdr[2] = fhdr[3] = fhdr[4] = 0;
|
||||
fhdr[0] = t->fhdr;
|
||||
fhdr[1] = 0;
|
||||
|
||||
if (t->type == NGX_RTMP_MSG_VIDEO) {
|
||||
fhdr[0] |= 0x10;
|
||||
fhdr[2] = fhdr[3] = fhdr[4] = 0;
|
||||
fhdr_size = 5;
|
||||
} else {
|
||||
fhdr_size = 2;
|
||||
}
|
||||
|
||||
in.buf = &in_buf;
|
||||
in_buf.pos = fhdr;
|
||||
in_buf.last = fhdr + 5;
|
||||
in_buf.last = fhdr + fhdr_size;
|
||||
|
||||
out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in);
|
||||
|
||||
|
@ -1943,7 +2142,32 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
"offset=%O, size=%uz, timestamp=%uD, duration=%uD",
|
||||
t->id, cr->offset, cr->size, timestamp, duration);
|
||||
|
||||
fhdr_size = (t->header ? 5 : 1);
|
||||
ngx_rtmp_mp4_buffer[0] = t->fhdr;
|
||||
fhdr_size = 1;
|
||||
|
||||
if (t->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 (t->header) {
|
||||
fhdr_size = 5;
|
||||
ngx_rtmp_mp4_buffer[1] = 1;
|
||||
ngx_rtmp_mp4_buffer[2] = cr->delay & 0xf00;
|
||||
ngx_rtmp_mp4_buffer[3] = cr->delay & 0x0f0;
|
||||
ngx_rtmp_mp4_buffer[4] = cr->delay & 0x00f;
|
||||
}
|
||||
|
||||
} else { /* NGX_RTMP_MSG_AUDIO */
|
||||
if (t->header) {
|
||||
fhdr_size = 2;
|
||||
ngx_rtmp_mp4_buffer[1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cr->size + fhdr_size > sizeof(ngx_rtmp_mp4_buffer)) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
|
@ -1961,25 +2185,6 @@ ngx_rtmp_mp4_send(ngx_event_t *e)
|
|||
continue;
|
||||
}
|
||||
|
||||
ngx_rtmp_mp4_buffer[0] = t->fhdr;
|
||||
|
||||
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) {
|
||||
ngx_rtmp_mp4_buffer[1] = 1;
|
||||
ngx_rtmp_mp4_buffer[2] = cr->delay & 0xf00;
|
||||
ngx_rtmp_mp4_buffer[3] = cr->delay & 0x0f0;
|
||||
ngx_rtmp_mp4_buffer[4] = cr->delay & 0x00f;
|
||||
}
|
||||
|
||||
in.buf = &in_buf;
|
||||
in_buf.pos = ngx_rtmp_mp4_buffer;
|
||||
in_buf.last = ngx_rtmp_mp4_buffer + cr->size + fhdr_size;
|
||||
|
|
Loading…
Reference in a new issue