From 8341644121b4dfa54c1b64013ea4142d59607cfa Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Fri, 3 Jul 2015 01:03:39 +0300 Subject: [PATCH] Backport support MP3 for HLS from abandoned pull request --- hls/ngx_rtmp_hls_module.c | 89 +++++++++++++++++++++++++-------------- hls/ngx_rtmp_mpegts.c | 37 ++++++++++++---- hls/ngx_rtmp_mpegts.h | 2 +- 3 files changed, 87 insertions(+), 41 deletions(-) diff --git a/hls/ngx_rtmp_hls_module.c b/hls/ngx_rtmp_hls_module.c index 7c573a3..8fe9970 100644 --- a/hls/ngx_rtmp_hls_module.c +++ b/hls/ngx_rtmp_hls_module.c @@ -848,6 +848,7 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts, ngx_fd_t fd; ngx_uint_t g; ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; ngx_rtmp_hls_frag_t *f; ngx_rtmp_hls_app_conf_t *hacf; @@ -943,8 +944,10 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts, return NGX_ERROR; } + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ngx_rtmp_mpegts_open_file(&ctx->file, ctx->stream.data, - s->connection->log) + s->connection->log, &codec_ctx->audio_codec_id) != NGX_OK) { return NGX_ERROR; @@ -1687,7 +1690,7 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, size_t bsize; ngx_buf_t *b; u_char *p; - ngx_uint_t objtype, srindex, chconf, size; + ngx_uint_t objtype, srindex, chconf, size, samples_per_frame; hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); @@ -1701,8 +1704,14 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } - if (codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_AAC || - codec_ctx->aac_header == NULL || ngx_rtmp_is_codec_header(in)) + if (codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_AAC && + codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_MP3) + { + return NGX_OK; + } + + if ((codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC && + codec_ctx->aac_header == NULL) || ngx_rtmp_is_codec_header(in)) { return NGX_OK; } @@ -1727,7 +1736,7 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, b->pos = b->last = b->start; } - size = h->mlen - 2 + 7; + size = codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_MP3 ? h->mlen - 1 : h->mlen - 2 + 7; pts = (uint64_t) h->timestamp * 90; if (b->start + size > b->end) { @@ -1751,14 +1760,22 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "hls: audio pts=%uL", pts); - if (b->last + 7 > b->end) { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "hls: not enough buffer for audio header"); - return NGX_OK; - } - p = b->last; - b->last += 5; + if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) { + if (b->last + 7 > b->end) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: not enough buffer for audio header"); + return NGX_OK; + } + b->last += 5; + } + else { + /* For some reason the pointer is already incremented past the rest + of the RTMP frame header. I'm not sure where in the code this is + being done. Regardless, there's an extra byte that needs to be skipped + for MP3. */ + in->buf->pos += 1; + } /* copy payload */ @@ -1774,28 +1791,30 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, /* make up ADTS header */ - if (ngx_rtmp_hls_parse_aac_header(s, &objtype, &srindex, &chconf) - != NGX_OK) - { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "hls: aac header error"); - return NGX_OK; - } + if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) { + if (ngx_rtmp_hls_parse_aac_header(s, &objtype, &srindex, &chconf) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: aac header error"); + return NGX_OK; + } - /* we have 5 free bytes + 2 bytes of RTMP frame header */ + /* we have 5 free bytes + 2 bytes of RTMP frame header */ - p[0] = 0xff; - p[1] = 0xf1; - p[2] = (u_char) (((objtype - 1) << 6) | (srindex << 2) | - ((chconf & 0x04) >> 2)); - p[3] = (u_char) (((chconf & 0x03) << 6) | ((size >> 11) & 0x03)); - p[4] = (u_char) (size >> 3); - p[5] = (u_char) ((size << 5) | 0x1f); - p[6] = 0xfc; + p[0] = 0xff; + p[1] = 0xf1; + p[2] = (u_char) (((objtype - 1) << 6) | (srindex << 2) | + ((chconf & 0x04) >> 2)); + p[3] = (u_char) (((chconf & 0x03) << 6) | ((size >> 11) & 0x03)); + p[4] = (u_char) (size >> 3); + p[5] = (u_char) ((size << 5) | 0x1f); + p[6] = 0xfc; - if (p != b->start) { - ctx->aframe_num++; - return NGX_OK; + if (p != b->start) { + ctx->aframe_num++; + return NGX_OK; + } } ctx->aframe_pts = pts; @@ -1809,7 +1828,9 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, /* TODO: We assume here AAC frame size is 1024 * Need to handle AAC frames with frame size of 960 */ - est_pts = ctx->aframe_base + ctx->aframe_num * 90000 * 1024 / + samples_per_frame = codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC ? 1024 : 1152; + + est_pts = ctx->aframe_base + ctx->aframe_num * 90000 * samples_per_frame / codec_ctx->sample_rate; dpts = (int64_t) (est_pts - pts); @@ -1822,6 +1843,10 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, { ctx->aframe_num++; ctx->aframe_pts = est_pts; + + if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_MP3) { + ngx_rtmp_hls_flush_audio(s); + } return NGX_OK; } diff --git a/hls/ngx_rtmp_mpegts.c b/hls/ngx_rtmp_mpegts.c index ae66f71..9660807 100644 --- a/hls/ngx_rtmp_mpegts.c +++ b/hls/ngx_rtmp_mpegts.c @@ -8,6 +8,7 @@ #include #include "ngx_rtmp_mpegts.h" +#include "ngx_rtmp_codec_module.h" static u_char ngx_rtmp_mpegts_header[] = { @@ -46,11 +47,9 @@ static u_char ngx_rtmp_mpegts_header[] = { 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264 */ - 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac */ - /*0x03, 0xe1, 0x01, 0xf0, 0x00,*/ /* mp3 */ - /* CRC */ - 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */ - /*0x4e, 0x59, 0x3d, 0x1e,*/ /* crc for mp3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, /* audio placeholder */ + 0x00, 0x00, 0x00, 0x00, /* audio crc placeholder */ + /* stuffing 157 bytes */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -70,6 +69,17 @@ static u_char ngx_rtmp_mpegts_header[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static u_char ngx_rtmp_mpegts_header_mp3[] = { + 0x03, 0xe1, 0x01, 0xf0, 0x00, /* mp3 */ + /* CRC */ + 0xd7, 0x86, 0x44, 0x5c, /* crc for mp3 */ +}; + +static u_char ngx_rtmp_mpegts_header_aac[] = { + 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac */ + /* CRC */ + 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */ +}; /* 700 ms PCR delay */ #define NGX_RTMP_HLS_DELAY 63000 @@ -155,8 +165,19 @@ ngx_rtmp_mpegts_write_file(ngx_rtmp_mpegts_file_t *file, u_char *in, static ngx_int_t -ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file) +ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file, ngx_uint_t *audio_codec_id) { + + if (*audio_codec_id == NGX_RTMP_AUDIO_AAC) { + ngx_memcpy(ngx_rtmp_mpegts_header+210, ngx_rtmp_mpegts_header_aac, + sizeof(ngx_rtmp_mpegts_header_aac)); + } + //if (*audio_codec_id == NGX_RTMP_AUDIO_MP3) { + else { + ngx_memcpy(ngx_rtmp_mpegts_header+210, ngx_rtmp_mpegts_header_mp3, + sizeof(ngx_rtmp_mpegts_header_mp3)); + } + return ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header, sizeof(ngx_rtmp_mpegts_header)); } @@ -350,7 +371,7 @@ ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file, ngx_int_t ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, - ngx_log_t *log) + ngx_log_t *log, ngx_uint_t *audio_codec_id) { file->log = log; @@ -365,7 +386,7 @@ ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, file->size = 0; - if (ngx_rtmp_mpegts_write_header(file) != NGX_OK) { + if (ngx_rtmp_mpegts_write_header(file, audio_codec_id) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, log, ngx_errno, "hls: error writing fragment header"); ngx_close_file(file->fd); diff --git a/hls/ngx_rtmp_mpegts.h b/hls/ngx_rtmp_mpegts.h index c128a51..1acde62 100644 --- a/hls/ngx_rtmp_mpegts.h +++ b/hls/ngx_rtmp_mpegts.h @@ -37,7 +37,7 @@ typedef struct { ngx_int_t ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file, u_char *key, size_t key_len, uint64_t iv); ngx_int_t ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, - ngx_log_t *log); + ngx_log_t *log, ngx_uint_t *audio_codec_id); ngx_int_t ngx_rtmp_mpegts_close_file(ngx_rtmp_mpegts_file_t *file); ngx_int_t ngx_rtmp_mpegts_write_frame(ngx_rtmp_mpegts_file_t *file, ngx_rtmp_mpegts_frame_t *f, ngx_buf_t *b);