From c11797815d23585cd2a28ca0e62877821008f26b Mon Sep 17 00:00:00 2001 From: Chris Wiggins Date: Wed, 13 Apr 2016 17:17:21 +1200 Subject: [PATCH] Fix single-track HLS MPEG-TS streams --- hls/ngx_rtmp_hls_module.c | 2 +- hls/ngx_rtmp_mpegts.c | 82 ++++++++++++++++++++++++++++++--------- hls/ngx_rtmp_mpegts.h | 4 +- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/hls/ngx_rtmp_hls_module.c b/hls/ngx_rtmp_hls_module.c index 4299ac8..4ae6a6e 100644 --- a/hls/ngx_rtmp_hls_module.c +++ b/hls/ngx_rtmp_hls_module.c @@ -1049,7 +1049,7 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts, 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, &codec_ctx->audio_codec_id, mpegts_cc) + s->connection->log, codec_ctx, mpegts_cc) != NGX_OK) { return NGX_ERROR; diff --git a/hls/ngx_rtmp_mpegts.c b/hls/ngx_rtmp_mpegts.c index 71bb766..7f77c26 100644 --- a/hls/ngx_rtmp_mpegts.c +++ b/hls/ngx_rtmp_mpegts.c @@ -173,27 +173,73 @@ 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_uint_t *audio_codec_id, ngx_uint_t mpegts_cc) +ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc) { + ngx_int_t rc; - 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 there's both audio and video present + if (codec_ctx->audio_codec_id && codec_ctx->video_codec_id) + { + if (codec_ctx->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)); + } + + // Truncate counter to 4 bits here + mpegts_cc %= 0x0f; + // And fill headers + ngx_rtmp_mpegts_header[3] = (ngx_rtmp_mpegts_header[3] & 0xf0) + (u_char)mpegts_cc; + ngx_rtmp_mpegts_header[191] = (ngx_rtmp_mpegts_header[191] & 0xf0) + (u_char)mpegts_cc; + + rc = ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header, + sizeof(ngx_rtmp_mpegts_header)); } - //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)); + else + { + //Just video or just audio + u_char buf[sizeof(ngx_rtmp_mpegts_header)]; + + ngx_memcpy(buf, ngx_rtmp_mpegts_header, sizeof(ngx_rtmp_mpegts_header)); + + /* Fix the section length */ + buf[195] = 0x12; + + if (codec_ctx->audio_codec_id) + { + /* Set the PCR PID to the audio PID */ + buf[202] = 0x01; + + /* Move the audio description over the video description */ + ngx_memcpy(buf + 205, buf + 210, 5); + + /* Fix the CRC partially overwriting the audio description */ + buf[210] = 0xec; + buf[211] = 0xe2; + buf[212] = 0xb0; + buf[213] = 0x94; + } + else + { + /* Fix the CRC partially overwriting the audio description */ + buf[210] = 0x15; + buf[211] = 0xbd; + buf[212] = 0x4d; + buf[213] = 0x56; + } + + /* Clear the last byte of the audio description and the old CRC */ + ngx_memset(buf + 214, 0xff, 5); + + rc = ngx_rtmp_mpegts_write_file(file, buf, sizeof(buf)); } - // Truncate counter to 4 bits here - mpegts_cc %= 0x0f; - // And fill headers - ngx_rtmp_mpegts_header[3] = (ngx_rtmp_mpegts_header[3] & 0xf0) + (u_char)mpegts_cc; - ngx_rtmp_mpegts_header[191] = (ngx_rtmp_mpegts_header[191] & 0xf0) + (u_char)mpegts_cc; - - return ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header, - sizeof(ngx_rtmp_mpegts_header)); + return rc; + } @@ -383,7 +429,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_uint_t *audio_codec_id, ngx_uint_t mpegts_cc) + ngx_log_t *log, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc) { file->log = log; @@ -398,7 +444,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, audio_codec_id, mpegts_cc) != NGX_OK) { + if (ngx_rtmp_mpegts_write_header(file, codec_ctx, mpegts_cc) != 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 8c8cb1b..355b5a5 100644 --- a/hls/ngx_rtmp_mpegts.h +++ b/hls/ngx_rtmp_mpegts.h @@ -12,6 +12,8 @@ #include #include +#include + typedef struct { ngx_fd_t fd; @@ -37,7 +39,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_uint_t *audio_codec_id, ngx_uint_t mpegts_cc); + ngx_log_t *log, ngx_rtmp_codec_ctx_t *codec_ctx, ngx_uint_t mpegts_cc); 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);