diff --git a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.c b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.c index 89883ad3..2ed441c6 100644 --- a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.c +++ b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.c @@ -33,10 +33,10 @@ #define NGX_RTMP_AVC_SEQUENCE_HEADER 0 #define NGX_RTMP_AVC_NALU 1 -#define NGX_RTMP_EXT_HEADER_SIZE 8 /* (frame | packet type), pts_delay, fourcc */ +#define NGX_RTMP_EXT_HEADER_SIZE 5 /* (frame | packet type), fourcc */ +#define NGX_RTMP_EXT_HEADER_SIZE_NALU 8 /* + pts_delay */ #define NGX_RTMP_EXT_SEQUENCE_HEADER 0 #define NGX_RTMP_EXT_NALU 1 -static const uint32_t NGX_RTMP_EXT_FOURCC_HVC1 = 0x31637668; /* audio */ #define NGX_RTMP_AAC_HEADER_SIZE 2 /* sound_info + packet_type */ @@ -57,7 +57,7 @@ static const uint32_t NGX_RTMP_EXT_FOURCC_HVC1 = 0x31637668; #define NGX_RTMP_FRAME_HEADER_MAX_SIZE (NGX_RTMP_HEADER_0_SIZE \ - + NGX_RTMP_EXT_TIMESTAMP_SIZE + NGX_RTMP_EXT_HEADER_SIZE) + + NGX_RTMP_EXT_TIMESTAMP_SIZE + NGX_RTMP_EXT_HEADER_SIZE_NALU) #define ngx_kmp_rtmp_chunk_count(mlen, chunk_size) \ @@ -489,10 +489,6 @@ static ngx_kmp_rtmp_amf_field_t ngx_kmp_rtmp_amf_onfi[] = { }; -static u_char * -ngx_kmp_rtmp_encoder_ext_header_write(uint32_t codec_id, u_char *p, u_char packet_type, - u_char key_frame, uint32_t pts_delay); - static ngx_inline u_char * ngx_kmp_rtmp_encoder_write_header(u_char *p, ngx_kmp_rtmp_header_t *h) { @@ -901,6 +897,66 @@ ngx_kmp_rtmp_encoder_avc_sequence_write(u_char *p, } +static u_char * +ngx_kmp_rtmp_encoder_ext_header_write(u_char *p, u_char packet_type, + u_char key_frame, uint32_t fourcc, uint32_t pts_delay) +{ + u_char frame_type; + + frame_type = key_frame ? NGX_RTMP_FRAME_TYPE_KEY + : NGX_RTMP_FRAME_TYPE_INTER; + + *p++ = 0x80 | (frame_type << 4) | packet_type; + + p = ngx_copy(p, &fourcc, sizeof(fourcc)); + + if (packet_type == NGX_RTMP_EXT_NALU) { + ngx_kmp_rtmp_amf_write_be24(p, pts_delay); + } + + return p; +} + + +size_t +ngx_kmp_rtmp_encoder_ext_sequence_get_size(ngx_kmp_rtmp_stream_ctx_t *sc, + ngx_str_t *extra_data) +{ + size_t mlen; + + mlen = NGX_RTMP_EXT_HEADER_SIZE + extra_data->len; + + return NGX_RTMP_HEADER_0_SIZE + mlen + + (ngx_kmp_rtmp_chunk_count(mlen, sc->chunk_size) - 1) + * NGX_RTMP_HEADER_3_SIZE; +} + + +u_char * +ngx_kmp_rtmp_encoder_ext_sequence_write(u_char *p, + ngx_kmp_rtmp_stream_ctx_t *sc, uint32_t fourcc, ngx_str_t *extra_data) +{ + u_char *body; + ngx_kmp_rtmp_header_t h; + + ngx_memzero(&h, sizeof(h)); + h.csid = sc->csid; + h.mlen = NGX_RTMP_EXT_HEADER_SIZE + extra_data->len; + h.type = NGX_RTMP_MSG_VIDEO; + h.msid = sc->msid; + + p = ngx_kmp_rtmp_encoder_write_header(p, &h); + + body = p; + p = ngx_kmp_rtmp_encoder_ext_header_write(p, NGX_RTMP_EXT_SEQUENCE_HEADER, + 1, fourcc, 0); + ngx_memcpy(p, extra_data->data, extra_data->len); + + return ngx_kmp_rtmp_encoder_add_chunk_headers(body, h.mlen, sc->chunk_size, + h.csid); +} + + static u_char * ngx_kmp_rtmp_encoder_aac_header_write(u_char *p, u_char sound_info, u_char packet_type) @@ -1014,6 +1070,7 @@ ngx_kmp_rtmp_encoder_frame_write(ngx_kmp_rtmp_stream_ctx_t *sc, h.timestamp = NGX_RTMP_EXT_TIMESTAMP; } + /* TODO: add support for "vp09" and "av01" */ switch (codec_id) { case KMP_CODEC_VIDEO_H264: @@ -1025,11 +1082,12 @@ ngx_kmp_rtmp_encoder_frame_write(ngx_kmp_rtmp_stream_ctx_t *sc, break; case KMP_CODEC_VIDEO_H265: - header_size = NGX_RTMP_EXT_HEADER_SIZE - 4; + header_size = NGX_RTMP_EXT_HEADER_SIZE_NALU; h.type = NGX_RTMP_MSG_VIDEO; - p = ngx_kmp_rtmp_encoder_ext_header_write(codec_id, p, NGX_RTMP_AVC_NALU, - frame->flags & KMP_FRAME_FLAG_KEY, frame->pts_delay); + p = ngx_kmp_rtmp_encoder_ext_header_write(p, NGX_RTMP_EXT_NALU, + frame->flags & KMP_FRAME_FLAG_KEY, NGX_RTMP_EXT_FOURCC_HVC1, + frame->pts_delay); break; case KMP_CODEC_AUDIO_MP3: @@ -1115,65 +1173,3 @@ ngx_kmp_rtmp_encoder_frame_write(ngx_kmp_rtmp_stream_ctx_t *sc, return NGX_OK; } - - -size_t -ngx_kmp_rtmp_encoder_ext_sequence_get_size(ngx_kmp_rtmp_stream_ctx_t *sc, - ngx_str_t *extra_data) -{ - size_t mlen; - - mlen = NGX_RTMP_EXT_HEADER_SIZE - 3 + extra_data->len; - - return NGX_RTMP_HEADER_0_SIZE + mlen - + (ngx_kmp_rtmp_chunk_count(mlen, sc->chunk_size) - 1) - * NGX_RTMP_HEADER_3_SIZE; -} - - -u_char * -ngx_kmp_rtmp_encoder_ext_sequence_write(uint32_t codec_id, u_char *p, - ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data) -{ - u_char *body; - ngx_kmp_rtmp_header_t h; - - - ngx_memzero(&h, sizeof(h)); - h.csid = sc->csid; - h.mlen = NGX_RTMP_EXT_HEADER_SIZE - 3 + extra_data->len; - h.type = NGX_RTMP_MSG_VIDEO; - h.msid = sc->msid; - - p = ngx_kmp_rtmp_encoder_write_header(p, &h); - - body = p; - p = ngx_kmp_rtmp_encoder_ext_header_write(codec_id, p, NGX_RTMP_EXT_SEQUENCE_HEADER, - 1, 0); - ngx_memcpy(p, extra_data->data, extra_data->len); - - return ngx_kmp_rtmp_encoder_add_chunk_headers(body, h.mlen, sc->chunk_size, - h.csid); -} - - -static u_char * -ngx_kmp_rtmp_encoder_ext_header_write(uint32_t codec_id, u_char *p, u_char packet_type, - u_char key_frame, uint32_t pts_delay) -{ - u_char frame_type; - - frame_type = key_frame ? NGX_RTMP_FRAME_TYPE_KEY - : NGX_RTMP_FRAME_TYPE_INTER; - - *p++ = (frame_type << 4) | 0x80 | packet_type; - - // TODO: support for “vp09” and “av01” - p = ngx_copy(p, &NGX_RTMP_EXT_FOURCC_HVC1, 4); - - if(packet_type == NGX_RTMP_EXT_NALU) { - ngx_kmp_rtmp_amf_write_be24(p, pts_delay); - } - - return p; -} diff --git a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.h b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.h index 1cfba51b..7ac6c89b 100644 --- a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.h +++ b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_encoder.h @@ -14,6 +14,8 @@ #define NGX_KMP_RTMP_TIMESCALE (1000) +#define NGX_RTMP_EXT_FOURCC_HVC1 0x31637668 + typedef ngx_int_t (*ngx_kmp_rtmp_write_pt)(void *data, void *buf, size_t size); @@ -95,6 +97,11 @@ size_t ngx_kmp_rtmp_encoder_avc_sequence_get_size( u_char *ngx_kmp_rtmp_encoder_avc_sequence_write(u_char *p, ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data); +size_t ngx_kmp_rtmp_encoder_ext_sequence_get_size( + ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data); +u_char *ngx_kmp_rtmp_encoder_ext_sequence_write(u_char *p, + ngx_kmp_rtmp_stream_ctx_t *sc, uint32_t fourcc, ngx_str_t *extra_data); + size_t ngx_kmp_rtmp_encoder_aac_sequence_get_size( ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data); u_char *ngx_kmp_rtmp_encoder_aac_sequence_write(u_char *p, @@ -110,11 +117,4 @@ ngx_int_t ngx_kmp_rtmp_encoder_frame_write(ngx_kmp_rtmp_stream_ctx_t *sc, ngx_kmp_rtmp_frame_t *frame, uint32_t codec_id, ngx_kmp_rtmp_write_pt write, void *data); - -size_t ngx_kmp_rtmp_encoder_ext_sequence_get_size( - ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data); -u_char *ngx_kmp_rtmp_encoder_ext_sequence_write(uint32_t codec_id, u_char *p, - ngx_kmp_rtmp_stream_ctx_t *sc, ngx_str_t *extra_data); - - #endif /* _NGX_KMP_RTMP_ENCODER_H_INCLUDED_ */ diff --git a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_stream.c b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_stream.c index 7bb393ec..e79eeb16 100644 --- a/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_stream.c +++ b/nginx-kmp-rtmp-module/src/ngx_kmp_rtmp_stream.c @@ -185,13 +185,17 @@ ngx_kmp_rtmp_stream_write_meta(ngx_kmp_rtmp_stream_t *stream) size = ngx_kmp_rtmp_encoder_metadata_get_size(&stream->ctx, &meta); - if (meta.mi[KMP_MEDIA_VIDEO].codec_id == KMP_CODEC_VIDEO_H264) { + switch (meta.mi[KMP_MEDIA_VIDEO].codec_id) { + + case KMP_CODEC_VIDEO_H264: size += ngx_kmp_rtmp_encoder_avc_sequence_get_size( &stream->ctx, &extra_data[KMP_MEDIA_VIDEO]); - } + break; - if (meta.mi[KMP_MEDIA_VIDEO].codec_id == KMP_CODEC_VIDEO_H265) { - size += ngx_kmp_rtmp_encoder_ext_sequence_get_size(&stream->ctx, &extra_data[KMP_MEDIA_VIDEO]); + case KMP_CODEC_VIDEO_H265: + size += ngx_kmp_rtmp_encoder_ext_sequence_get_size( + &stream->ctx, &extra_data[KMP_MEDIA_VIDEO]); + break; } if (meta.mi[KMP_MEDIA_AUDIO].codec_id == KMP_CODEC_AUDIO_AAC) { @@ -208,14 +212,17 @@ ngx_kmp_rtmp_stream_write_meta(ngx_kmp_rtmp_stream_t *stream) p = ngx_kmp_rtmp_encoder_metadata_write(start, &stream->ctx, &meta); - if (meta.mi[KMP_MEDIA_VIDEO].codec_id == KMP_CODEC_VIDEO_H264) { + switch (meta.mi[KMP_MEDIA_VIDEO].codec_id) { + + case KMP_CODEC_VIDEO_H264: p = ngx_kmp_rtmp_encoder_avc_sequence_write(p, &stream->ctx, &extra_data[KMP_MEDIA_VIDEO]); - } + break; - if (meta.mi[KMP_MEDIA_VIDEO].codec_id == KMP_CODEC_VIDEO_H265) { - p = ngx_kmp_rtmp_encoder_ext_sequence_write(meta.mi[KMP_MEDIA_VIDEO].codec_id, - p, &stream->ctx, &extra_data[KMP_MEDIA_VIDEO]); + case KMP_CODEC_VIDEO_H265: + p = ngx_kmp_rtmp_encoder_ext_sequence_write(p, &stream->ctx, + NGX_RTMP_EXT_FOURCC_HVC1, &extra_data[KMP_MEDIA_VIDEO]); + break; } if (meta.mi[KMP_MEDIA_AUDIO].codec_id == KMP_CODEC_AUDIO_AAC) { diff --git a/nginx-rtmp-kmp-module/src/ngx_rtmp_kmp_track.c b/nginx-rtmp-kmp-module/src/ngx_rtmp_kmp_track.c index 0fd6d94e..8ebe5b2c 100644 --- a/nginx-rtmp-kmp-module/src/ngx_rtmp_kmp_track.c +++ b/nginx-rtmp-kmp-module/src/ngx_rtmp_kmp_track.c @@ -162,16 +162,18 @@ ngx_rtmp_kmp_track_send_media_info(ngx_kmp_out_track_t *track, switch (media_info->media_type) { case KMP_MEDIA_VIDEO: - /* KMP video codec ids match NGX_RTMP_VIDEO_XXX */ - switch(codec_ctx->video_codec_id) { - case NGX_RTMP_CODEC_FOURCC_HVC1: - case NGX_RTMP_CODEC_FOURCC_HEV1: - media_info->codec_id = KMP_CODEC_VIDEO_H265; - break; - default: - media_info->codec_id = codec_ctx->video_codec_id; - break; - }; + switch (codec_ctx->video_codec_id) { + + case NGX_RTMP_CODEC_FOURCC_HVC1: + case NGX_RTMP_CODEC_FOURCC_HEV1: + media_info->codec_id = KMP_CODEC_VIDEO_H265; + break; + + default: + /* KMP video codec ids match NGX_RTMP_VIDEO_XXX */ + media_info->codec_id = codec_ctx->video_codec_id; + break; + } media_info->bitrate = codec_ctx->video_data_rate * 1000; @@ -217,13 +219,14 @@ ngx_rtmp_kmp_track_init_frame(ngx_kmp_out_track_t *track, { u_char frame_info; u_char packet_type; - uint32_t codec_id = 0; + u_char comp_time[3]; int32_t pts_delay; + uint32_t codec_id; uint32_t rtmpscale; ngx_int_t rc; - ngx_rtmp_kmp_track_ctx_t *ctx = track->ctx; ngx_flag_t ext_header; - u_char comp_time[3]; + ngx_flag_t has_pts_delay; + ngx_rtmp_kmp_track_ctx_t *ctx = track->ctx; *sequence_header = 0; @@ -235,10 +238,6 @@ ngx_rtmp_kmp_track_init_frame(ngx_kmp_out_track_t *track, return NGX_ERROR; } - ext_header = (frame_info & NGX_RTMP_EXT_HEADER_MASK) ? 1 : 0; - - frame_info &= ~NGX_RTMP_EXT_HEADER_MASK; - rtmpscale = track->media_info.timescale / NGX_RTMP_TIMESCALE; ngx_memzero(frame, sizeof(*frame)); @@ -246,16 +245,13 @@ ngx_rtmp_kmp_track_init_frame(ngx_kmp_out_track_t *track, frame->header.packet_type = KMP_PACKET_FRAME; frame->header.header_size = sizeof(*frame); - if ((frame_info >> 4) == NGX_RTMP_KEY_FRAME) { - frame->f.flags |= KMP_FRAME_FLAG_KEY; - } - switch (h->type) { case NGX_RTMP_MSG_VIDEO: - if(!ext_header) { - codec_id = frame_info & 0x0f; + ext_header = (frame_info & NGX_RTMP_EXT_HEADER_MASK) ? 1 : 0; + if (!ext_header) { + codec_id = frame_info & 0x0f; if (codec_id != NGX_RTMP_VIDEO_H264) { break; } @@ -264,36 +260,50 @@ ngx_rtmp_kmp_track_init_frame(ngx_kmp_out_track_t *track, sizeof(packet_type), in); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_NOTICE, &track->log, 0, - "ngx_rtmp_kmp_track_init_frame: failed to read packet_type"); + "ngx_rtmp_kmp_track_init_frame: " + "failed to read packet_type"); ngx_kmp_out_track_set_error_reason(track, "rtmp_bad_data"); return NGX_ERROR; } frame->header.data_size -= sizeof(packet_type); + has_pts_delay = 1; + } else { - packet_type = (frame_info & 0x0f); - } - if (packet_type == NGX_RTMP_AVC_SEQUENCE_HEADER) { - *sequence_header = 1; - } + frame_info &= ~NGX_RTMP_EXT_HEADER_MASK; + packet_type = (frame_info & 0x0f); - if(ext_header) { rc = ngx_rtmp_kmp_copy(&track->log, &codec_id, src, sizeof(codec_id), in); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_NOTICE, &track->log, 0, - "ngx_rtmp_kmp_track_init_frame: extended rtmp. failed to read codec_id"); + "ngx_rtmp_kmp_track_init_frame: " + "failed to read extended codec_id"); ngx_kmp_out_track_set_error_reason(track, "rtmp_bad_data"); return NGX_ERROR; } frame->header.data_size -= sizeof(codec_id); + switch (codec_id) { + + case NGX_RTMP_CODEC_FOURCC_HVC1: + case NGX_RTMP_CODEC_FOURCC_HEV1: + has_pts_delay = packet_type == NGX_RTMP_PKT_TYPE_CODED_FRAMES; + break; + + default: + has_pts_delay = 0; + } + } + + if ((frame_info >> 4) == NGX_RTMP_KEY_FRAME) { + frame->f.flags |= KMP_FRAME_FLAG_KEY; } - if(codec_id == NGX_RTMP_VIDEO_H264 || ((codec_id == NGX_RTMP_CODEC_FOURCC_HVC1 || codec_id == NGX_RTMP_CODEC_FOURCC_HEV1) && packet_type == PacketTypeCodedFrames)) { + if (has_pts_delay) { rc = ngx_rtmp_kmp_copy(&track->log, &comp_time, src, sizeof(comp_time), in); if (rc != NGX_OK) { @@ -316,17 +326,13 @@ ngx_rtmp_kmp_track_init_frame(ngx_kmp_out_track_t *track, } frame->f.pts_delay = pts_delay * rtmpscale; - - } else { - frame->f.pts_delay = 0; } ngx_log_debug5(NGX_LOG_DEBUG_RTMP, &track->log, 0, - "ngx_rtmp_kmp_track_init_frame: %s rtmp. codec id: %ui data size: %ui packet type: %ui pts delay %uD", - ext_header ? "extended" : "", - codec_id, - frame->header.data_size, - packet_type, + "ngx_rtmp_kmp_track_init_frame: %s rtmp, codec_id: 0x%uxD, " + "data_size: %uD, packet_type: %uD, pts_delay: %D", + ext_header ? "extended" : "", codec_id, + frame->header.data_size, (uint32_t) packet_type, frame->f.pts_delay); break; diff --git a/nginx-rtmp-module/src/ngx_rtmp_codec_module.c b/nginx-rtmp-module/src/ngx_rtmp_codec_module.c index 8a49daaa..52b71e2f 100644 --- a/nginx-rtmp-module/src/ngx_rtmp_codec_module.c +++ b/nginx-rtmp-module/src/ngx_rtmp_codec_module.c @@ -17,9 +17,12 @@ #define NGX_RTMP_CODEC_META_ON 1 #define NGX_RTMP_CODEC_META_COPY 2 - #define NGX_RTMP_CODEC_CAPTION_TRIES 10 +#define HEVC_HVCC_HEADER_SIZE 22 +#define HEVC_HVCC_NAL_SEI_PREFIX 39 +#define HEVC_HVCC_NAL_SEI_SUFFIX 40 + static void *ngx_rtmp_codec_create_app_conf(ngx_conf_t *cf); static char *ngx_rtmp_codec_merge_app_conf(ngx_conf_t *cf, @@ -43,14 +46,11 @@ static ngx_int_t ngx_rtmp_codec_parse_extended_header(ngx_rtmp_session_t *s, static ngx_int_t ngx_rtmp_codec_parse_hevc_header(ngx_rtmp_session_t *s, ngx_chain_t *in); #if (NGX_DEBUG) -static size_t codec_config_hvcc_nal_units_get_size(ngx_log_t *log, ngx_rtmp_codec_ctx_t *ctx, ngx_chain_t *in); +static size_t codec_config_hvcc_nal_units_get_size(ngx_log_t *log, + ngx_rtmp_codec_ctx_t *ctx, ngx_chain_t *in); #endif -#define HEVC_HVCC_HEADER_SIZE 22 -#define HEVC_HVCC_NAL_SEI_PREFIX 39 -#define HEVC_HVCC_NAL_SEI_SUFFIX 40 - typedef struct { ngx_uint_t meta; } ngx_rtmp_codec_app_conf_t; @@ -149,18 +149,20 @@ ngx_rtmp_get_audio_codec_name(ngx_uint_t id) } -static -const char * +static const char * ngx_rtmp_get_video_codec_name_from_fourcc(ngx_uint_t id) { - switch(id){ + switch (id) { + case NGX_RTMP_CODEC_FOURCC_HEV1: return "HEV1"; + case NGX_RTMP_CODEC_FOURCC_HVC1: return "HVC1"; + default: return ""; - }; + } } @@ -314,10 +316,13 @@ ngx_rtmp_codec_detect_cea(ngx_rtmp_session_t *s, ngx_chain_t *in) { u_char nal_type; u_char *nalp; - uint32_t size, - /* frame info, packet type, comp time (3 bytes) */ - nal_offset = 5, - sei_type = 6; + u_char frame_info; + u_char packet_type; + uint32_t size; + uint32_t skip_size; + uint32_t sei_type; + uint32_t nal_type_shift; + uint32_t nal_type_mask; ngx_rtmp_codec_ctx_t *ctx; ngx_rtmp_chain_reader_t reader; ngx_rtmp_chain_reader_ep_t nal_reader; @@ -332,37 +337,49 @@ ngx_rtmp_codec_detect_cea(ngx_rtmp_session_t *s, ngx_chain_t *in) ngx_rtmp_chain_reader_init(&reader, in); - /* frame info, packet type, comp time (3 bytes) and additional 4 bytes for fourcc in case of ext header*/ - u_char frame_info; - if (ngx_rtmp_chain_reader_read(&reader,&frame_info, sizeof(frame_info)) != NGX_OK) { + if (ngx_rtmp_chain_reader_read(&reader, &frame_info, sizeof(frame_info)) + != NGX_OK) + { ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, "ngx_rtmp_codec_detect_cea: read frame_info failed"); return 0; } - // ext header bit set - if(frame_info & NGX_RTMP_EXT_HEADER_MASK) { - nal_offset = 0; - uint8_t packet_type = frame_info & 0x0f; - switch(packet_type){ - case PacketTypeCodedFrames: - // add CompositionTime (SI24) - 3 bytes - nal_offset += 3; - case PacketTypeCodedFramesX: + if (frame_info & NGX_RTMP_EXT_HEADER_MASK) { + + /* extended header */ + skip_size = 4; /* fourcc */ + packet_type = frame_info & 0x0f; + switch (packet_type) { + + case NGX_RTMP_PKT_TYPE_CODED_FRAMES: + skip_size += 3; /* pts_delay */ + break; + + case NGX_RTMP_PKT_TYPE_CODED_FRAMES_X: break; + default: ngx_log_debug1(NGX_LOG_WARN, s->connection->log, 0, - "ngx_rtmp_codec_detect_cea: skipping packet type %ui", packet_type); + "ngx_rtmp_codec_detect_cea: skipping packet type %uD", + (uint32_t) packet_type); return 0; - }; - // add Video FourCC (UI32) - 4 bytes - nal_offset += 4; + } + sei_type = HEVC_HVCC_NAL_SEI_PREFIX; + nal_type_shift = 1; + nal_type_mask = 0x3f; + + } else { + skip_size = 4; /* packet_type + pts_delay */ + sei_type = 6; + nal_type_shift = 0; + nal_type_mask = 0x1f; } - if (ngx_rtmp_chain_reader_skip(&reader, nal_offset) != NGX_OK) { + if (ngx_rtmp_chain_reader_skip(&reader, skip_size) != NGX_OK) { ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, - "ngx_rtmp_codec_detect_cea: skip avc header failed"); + "ngx_rtmp_codec_detect_cea: skip codec header failed"); return 0; } @@ -408,7 +425,8 @@ ngx_rtmp_codec_detect_cea(ngx_rtmp_session_t *s, ngx_chain_t *in) break; } - if ((nal_type & 0x1f) != sei_type) { /* nal_type = SEI */ + nal_type = (nal_type >> nal_type_shift) & nal_type_mask; + if (nal_type != sei_type) { continue; } @@ -424,49 +442,50 @@ ngx_rtmp_codec_detect_cea(ngx_rtmp_session_t *s, ngx_chain_t *in) static ngx_int_t -ngx_rtmp_codec_parse_extended_header(ngx_rtmp_session_t *s, ngx_chain_t *in, ngx_uint_t packet_type) +ngx_rtmp_codec_parse_extended_header(ngx_rtmp_session_t *s, ngx_chain_t *in, + ngx_uint_t packet_type) { - if(packet_type > PacketTypeCodedFramesX) { - //TODO: handle metadata AMF here + ngx_rtmp_codec_ctx_t *ctx; + + if (packet_type > NGX_RTMP_PKT_TYPE_CODED_FRAMES_X) { + /* TODO: handle metadata AMF here */ ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, - "ngx_rtmp_codec_parse_extended_header. handling metadata is not supported"); + "ngx_rtmp_codec_parse_extended_header: " + "metadata is not supported"); return NGX_OK; } - // VideoTagHeader size > 4cc implication - if(in->buf->last - in->buf->pos > 4) { + if (in->buf->last - in->buf->pos <= 4) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "ngx_rtmp_codec_parse_extended_header: buffer size too small %ui", + in->buf->last - in->buf->pos); + return NGX_OK; + } - ngx_rtmp_codec_ctx_t *ctx; + ctx = ngx_rtmp_stream_get_module_ctx(s, ngx_rtmp_codec_module); - ctx = ngx_rtmp_stream_get_module_ctx(s, ngx_rtmp_codec_module); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "ngx_rtmp_codec_parse_extended_header: codec_id: %ui, packet_type %ui", + ctx->video_codec_id, packet_type); - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "ngx_rtmp_codec_parse_extended_header. codec id: %ui packet type %ui", - ctx->video_codec_id, packet_type); + switch (ctx->video_codec_id) { - switch(ctx->video_codec_id) { - case NGX_RTMP_CODEC_FOURCC_HEV1: - case NGX_RTMP_CODEC_FOURCC_HVC1: - if(packet_type == PacketTypeSequenceStart) { - if(ngx_rtmp_codec_parse_hevc_header(s, in) < 0) { - return NGX_ERROR; - } + case NGX_RTMP_CODEC_FOURCC_HEV1: + case NGX_RTMP_CODEC_FOURCC_HVC1: + if (packet_type == NGX_RTMP_PKT_TYPE_SEQUENCE_START) { + if(ngx_rtmp_codec_parse_hevc_header(s, in) < 0) { + return NGX_ERROR; } - break; - default: - ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "ngx_rtmp_codec_parse_extended_header. unsupported codec fourcc: %ui (%4s) packet_type %ui", - ctx->video_codec_id, - &ctx->video_codec_id, - packet_type); - break; - }; + } - } else { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "ngx_rtmp_codec_parse_extended_header. buffer size too small: %ui", - in->buf->last - in->buf->pos); - return NGX_OK; + break; + + default: + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "ngx_rtmp_codec_parse_extended_header: " + "unsupported codec fourcc: 0x%uxD (%4s) packet_type %ui", + ctx->video_codec_id, &ctx->video_codec_id, packet_type); + break; } return NGX_OK; @@ -477,14 +496,16 @@ static ngx_int_t ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_chain_reader_t reader; ngx_rtmp_codec_ctx_t *ctx; ngx_chain_t **header; + ngx_uint_t packet_type; + ngx_flag_t is_ext_header; + uint32_t fourcc; uint8_t fmt; static ngx_uint_t sample_rates[] = { 5512, 11025, 22050, 44100 }; - ngx_flag_t is_ext_header = 0; - if (h->type != NGX_RTMP_MSG_AUDIO && h->type != NGX_RTMP_MSG_VIDEO) { return NGX_OK; } @@ -515,6 +536,8 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) fmt = in->buf->pos[0]; if (h->type == NGX_RTMP_MSG_AUDIO) { + is_ext_header = 0; + ctx->audio_codec_id = (fmt & 0xf0) >> 4; ctx->audio_channels = (fmt & 0x01) + 1; ctx->sample_size = (fmt & 0x02) ? 2 : 1; @@ -526,25 +549,28 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) } else { is_ext_header = (fmt & NGX_RTMP_EXT_HEADER_MASK); - if(!is_ext_header) { + if (!is_ext_header) { ctx->video_codec_id = (fmt & 0x0f); } else { - ngx_rtmp_chain_reader_t reader; ngx_rtmp_chain_reader_init(&reader, in); /* frame info - 1 byte */ if (ngx_rtmp_chain_reader_skip(&reader, 1) != NGX_OK) { ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, - "ngx_rtmp_codec_av. failed to skip frame info"); + "codec: av failed to skip frame info"); return NGX_ERROR; } - if (ngx_rtmp_chain_reader_read(&reader, &ctx->video_codec_id, 4) != NGX_OK) { + if (ngx_rtmp_chain_reader_read(&reader, &fourcc, sizeof(fourcc)) + != NGX_OK) + { ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, - "ngx_rtmp_codec_av. failed to read video_codec_id"); + "codec: av failed to read fourcc"); return NGX_ERROR; } + + ctx->video_codec_id = fourcc; } } @@ -554,34 +580,45 @@ ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) } /* no conf */ - if (h->type == NGX_RTMP_MSG_VIDEO && !ngx_rtmp_is_codec_header(ctx->video_codec_id, in)) + if (h->type == NGX_RTMP_MSG_VIDEO + && !ngx_rtmp_is_codec_header(ctx->video_codec_id, in)) { - if (ctx->video_captions_tries > 0 && (ctx->video_codec_id == NGX_RTMP_VIDEO_H264 - || ctx->video_codec_id == NGX_RTMP_CODEC_FOURCC_HVC1 - || ctx->video_codec_id == NGX_RTMP_CODEC_FOURCC_HEV1 - )) - { - if (ngx_rtmp_codec_detect_cea(s, in)) { - ctx->video_captions = 1; - ctx->video_captions_tries = 0; + if (ctx->video_captions_tries <= 0) { + return NGX_OK; + } + + switch (ctx->video_codec_id) { + + case NGX_RTMP_VIDEO_H264: + case NGX_RTMP_CODEC_FOURCC_HVC1: + case NGX_RTMP_CODEC_FOURCC_HEV1: + if (ngx_rtmp_codec_detect_cea(s, in)) { + ctx->video_captions = 1; + ctx->video_captions_tries = 0; } else { ctx->video_captions_tries--; } - } - return NGX_OK; + break; + + default: + ctx->video_captions_tries = 0; + } + + return NGX_OK; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); header = NULL; - if(is_ext_header){ - ngx_uint_t packet_type = (fmt & 0x0f); + if (is_ext_header) { + packet_type = (fmt & 0x0f); - header = &ctx->avc_header; - if(ngx_rtmp_codec_parse_extended_header(s, in, packet_type) < 0) { - header = NULL; + if (ngx_rtmp_codec_parse_extended_header(s, in, packet_type) + == NGX_OK) + { + header = &ctx->avc_header; } } else if (h->type == NGX_RTMP_MSG_AUDIO) { @@ -906,53 +943,44 @@ ngx_rtmp_codec_parse_avc_header(ngx_rtmp_session_t *s, ngx_chain_t *in) } -#define bit_reader_check(expr) \ - if(ngx_rtmp_bit_read_err(&br) || ngx_rtmp_bit_read_eof(&br)) { \ - err_msg = #expr; \ - goto error; \ - } \ - \ - expr; - - static ngx_int_t ngx_rtmp_codec_parse_hevc_header(ngx_rtmp_session_t *s, ngx_chain_t *in) { - #if (NGX_DEBUG) + ngx_uint_t size; + ngx_uint_t narrs; ngx_uint_t nal_type; ngx_uint_t i, j, nnal, nnall; - ngx_uint_t narrs; #endif ngx_rtmp_codec_ctx_t *ctx; ngx_rtmp_bit_reader_t br; - char const *err_msg; #if (NGX_DEBUG) ngx_rtmp_codec_dump_header(s, "ngx_rtmp_codec_parse_hevc_header in:", in); #endif - // HEVCDecoderConfigurationRecord - // http://ffmpeg.org/doxygen/trunk/hevc_8c_source.html#l00040 + + /* HEVCDecoderConfigurationRecord */ + /* http://ffmpeg.org/doxygen/trunk/hevc_8c_source.html#l00040 */ ctx = ngx_rtmp_stream_get_module_ctx(s, ngx_rtmp_codec_module); ngx_rtmp_bit_init_reader(&br, in->buf->pos, in->buf->last); - //skip tag header and configurationVersion(1 byte) - bit_reader_check(ngx_rtmp_bit_read(&br, 48)); + /* skip tag header and configurationVersion(1 byte) */ + ngx_rtmp_bit_read(&br, 48); /* unsigned int(2) general_profile_space; */ /* unsigned int(1) general_tier_flag; */ /* unsigned int(5) general_profile_idc; */ - bit_reader_check(ctx->avc_profile = (ngx_uint_t) (ngx_rtmp_bit_read_8(&br) & 0x1f)); + ctx->avc_profile = (ngx_uint_t) (ngx_rtmp_bit_read_8(&br) & 0x1f); - //unsigned int(32) general_profile_compatibility_flags; - bit_reader_check(ctx->avc_compat = (ngx_uint_t) ngx_rtmp_bit_read_32(&br)); - //unsigned int(48) general_constraint_indicator_flags; - bit_reader_check(ngx_rtmp_bit_read(&br, 48)); - //unsigned int(8) general_level_idc; - bit_reader_check(ctx->avc_level = (ngx_uint_t) ngx_rtmp_bit_read_8(&br)); + /* unsigned int(32) general_profile_compatibility_flags; */ + ctx->avc_compat = (ngx_uint_t) ngx_rtmp_bit_read_32(&br); + /* unsigned int(48) general_constraint_indicator_flags; */ + ngx_rtmp_bit_read(&br, 48); + /* unsigned int(8) general_level_idc; */ + ctx->avc_level = (ngx_uint_t) ngx_rtmp_bit_read_8(&br); /* bit(4) reserved = ‘1111’b; */ /* unsigned int(12) min_spatial_segmentation_idc; */ @@ -968,79 +996,81 @@ ngx_rtmp_codec_parse_hevc_header(ngx_rtmp_session_t *s, ngx_chain_t *in) /* bit(2) constantFrameRate; */ /* bit(3) numTemporalLayers; */ /* bit(1) temporalIdNested; */ - bit_reader_check(ngx_rtmp_bit_read(&br, 70)); + ngx_rtmp_bit_read(&br, 70); /* unsigned int(2) lengthSizeMinusOne; */ - bit_reader_check(ctx->avc_nal_bytes = (ngx_uint_t) ngx_rtmp_bit_read(&br, 2) + 1); + ctx->avc_nal_bytes = (ngx_uint_t) ngx_rtmp_bit_read(&br, 2) + 1; #if (NGX_DEBUG) /* unsigned int(8) numOfArrays; 04 */ - bit_reader_check(narrs = (ngx_uint_t) ngx_rtmp_bit_read_8(&br)); - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "codec: hevc header narrs=%ui ", narrs); - - - //parse vps sps pps .. - for ( j = 0; j < narrs; j++) { - //bit(1) array_completeness; - bit_reader_check(nal_type = (ngx_uint_t) ngx_rtmp_bit_read_8(&br) & 0x3f); - bit_reader_check(nnal = (ngx_uint_t) ngx_rtmp_bit_read_16(&br)); - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "codec: hevc nal_type=%ui nnal=%ui", nal_type, nnal); - for (i = 0; i < nnal; i++) { - bit_reader_check(nnall = (ngx_uint_t) ngx_rtmp_bit_read_16(&br)); - bit_reader_check(ngx_rtmp_bit_read(&br, nnall * 8)); - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "codec: hevc nnall=%ui", nnall); - // vps: 32 sps: 33 pps: 34 - } - } + narrs = (ngx_uint_t) ngx_rtmp_bit_read_8(&br); + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: hevc header narrs=%ui", narrs); - ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: hevc header " - "profile=%ui, compat=%ui, level=%ui, " - "nal_bytes=%ui, ref_frames=%ui, frame_rate=%.2f, width=%ui, height=%ui", - ctx->avc_profile, ctx->avc_compat, ctx->avc_level, - ctx->avc_nal_bytes, ctx->avc_ref_frames, ctx->frame_rate, - ctx->width, ctx->height); + /* parse vps sps pps .. */ + for (j = 0; j < narrs && !ngx_rtmp_bit_read_err(&br); j++) { + /* bit(1) array_completeness; */ + nal_type = (ngx_uint_t) ngx_rtmp_bit_read_8(&br) & 0x3f; + nnal = (ngx_uint_t) ngx_rtmp_bit_read_16(&br); + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: hevc nal_type=%ui nnal=%ui", nal_type, nnal); + for (i = 0; i < nnal && !ngx_rtmp_bit_read_err(&br); i++) { + nnall = (ngx_uint_t) ngx_rtmp_bit_read_16(&br); + ngx_rtmp_bit_read(&br, nnall * 8); - ngx_uint_t size = codec_config_hvcc_nal_units_get_size(s->connection->log, ctx, in); + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: hevc nnall=%ui", nnall); + /* vps: 32 sps : 33 pps : 34 */ + } + } + + size = codec_config_hvcc_nal_units_get_size(s->connection->log, ctx, in); if (size <= 0) { ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, - "ngx_rtmp_codec_parse_hevc_header: codec_config_hvcc_nal_units_get_size failed"); + "ngx_rtmp_codec_parse_hevc_header: " + "codec_config_hvcc_nal_units_get_size failed"); return NGX_ERROR; } #endif - return NGX_OK; + if (ngx_rtmp_bit_read_err(&br)) { + ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, + "codec: failed to parse hevc header"); + return NGX_ERROR; + } -error: + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: hevc header " + "profile=%ui, compat=%ui, level=%ui, nal_bytes=%ui, ref_frames=%ui, " + "frame_rate=%.2f, width=%ui, height=%ui", + ctx->avc_profile, ctx->avc_compat, ctx->avc_level, ctx->avc_nal_bytes, + ctx->avc_ref_frames, ctx->frame_rate, ctx->width, ctx->height); - ngx_log_error(NGX_LOG_NOTICE, s->connection->log, 0, - "%s failed ", err_msg ); - return NGX_ERROR; + return NGX_OK; } + #if (NGX_DEBUG) static void -ngx_rtmp_codec_dump_header(ngx_rtmp_session_t *s, const char *msg, ngx_chain_t *in) +ngx_rtmp_codec_dump_header(ngx_rtmp_session_t *s, const char *msg, + ngx_chain_t *in) { - u_char buf[257], *pp, *p = in->buf->pos; - u_char hex[] = "0123456789abcdef"; + u_char buf[257], *pp, *p; + u_char hex[] = "0123456789abcdef"; - ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - msg); + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, msg); - while(p < in->buf->last) { - for (pp = buf; p < in->buf->last && pp < (buf + sizeof(buf) - 3); - ++p) - { + for (p = in->buf->pos; p < in->buf->last; ) { + for (pp = buf; p < in->buf->last && pp < buf + sizeof(buf) - 3; ++p) { *pp++ = hex[*p >> 4]; *pp++ = hex[*p & 0x0f]; } *pp = 0; - ngx_log_debug(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - (const char *)buf); + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "%s", buf); } } #endif @@ -1473,88 +1503,94 @@ ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf) #if (NGX_DEBUG) -#define parse_be16(p) ( ((uint16_t) ((u_char *)(p))[0] << 8) | (((u_char *)(p))[1]) ) -#define parse_be32(p) ( ((uint32_t) ((u_char *)(p))[0] << 24) | (((u_char *)(p))[1] << 16) | (((u_char *)(p))[2] << 8) | (((u_char *)(p))[3]) ) +#define parse_be16(p) \ + ( ((uint16_t) ((u_char *) (p))[0] << 8) | (((u_char *) (p))[1]) ) +#define parse_be32(p) \ + ( ((uint32_t) ((u_char *)(p))[0] << 24) | (((u_char *)(p))[1] << 16) \ + | (((u_char *)(p))[2] << 8) | (((u_char *)(p))[3]) ) -#define read_be16(p, v) { v = parse_be16(&(p)); } -#define read_be32(p, v) { v = parse_be32(&(p)); } +#define read_be16(p, v) { v = parse_be16(&(p)); } +#define read_be32(p, v) { v = parse_be32(&(p)); } -static -size_t -codec_config_hvcc_nal_units_get_size(ngx_log_t *log, ngx_rtmp_codec_ctx_t *ctx, ngx_chain_t *in) +static size_t +codec_config_hvcc_nal_units_get_size(ngx_log_t *log, ngx_rtmp_codec_ctx_t *ctx, + ngx_chain_t *in) { + size_t size; + u_char *nalp; + u_char type_count; + u_char nal_unit_size; + uint16_t count; + uint32_t unit_size; + ngx_rtmp_chain_reader_t reader; - uint32_t unit_size; - uint16_t count; - uint8_t type_count; - size_t size; - ngx_rtmp_chain_reader_t reader; - uint8_t nal_unit_size = sizeof(uint16_t); - uint8_t *nalp = (u_char *) &unit_size + sizeof(unit_size) - nal_unit_size; ngx_rtmp_chain_reader_init(&reader, in); - - if (ngx_rtmp_chain_reader_skip(&reader, 5) < 0) - { + if (ngx_rtmp_chain_reader_skip(&reader, 5) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: failed to skip to start of extra data"); + "codec_config_hvcc_nal_units_get_size: " + "failed to skip to start of extra data"); return 0; } - if (ngx_rtmp_chain_reader_skip(&reader, HEVC_HVCC_HEADER_SIZE) < 0) - { + if (ngx_rtmp_chain_reader_skip(&reader, HEVC_HVCC_HEADER_SIZE) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: extra data size <= %uz too small", HEVC_HVCC_HEADER_SIZE); + "codec_config_hvcc_nal_units_get_size: " + "extra data size <= %uz too small", HEVC_HVCC_HEADER_SIZE); return 0; } - size = 0; - if (ngx_rtmp_chain_reader_read(&reader, &type_count, 1) < 0) - { + if (ngx_rtmp_chain_reader_read(&reader, &type_count, 1) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: failed to read %d bytes: type_count ", sizeof(type_count)); + "codec_config_hvcc_nal_units_get_size: " + "failed to read %d bytes: type_count ", sizeof(type_count)); return 0; } + size = 0; + nal_unit_size = sizeof(uint16_t); + nalp = (u_char *) &unit_size + sizeof(unit_size) - nal_unit_size; + for (; type_count > 0; type_count--) { - if (ngx_rtmp_chain_reader_skip(&reader, 1) < 0) - { + if (ngx_rtmp_chain_reader_skip(&reader, 1) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, "codec_config_hvcc_nal_units_get_size: failed to skip 1 byte"); return 0; } - if (ngx_rtmp_chain_reader_read(&reader, &count, sizeof (count)) < 0) - { + if (ngx_rtmp_chain_reader_read(&reader, &count, sizeof(count)) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: failed to read NAL count %uD", sizeof (count)); + "codec_config_hvcc_nal_units_get_size: " + "failed to read NAL count %uD", sizeof(count)); return 0; } read_be16(count, count); - for (; count > 0; count--) - { + for (; count > 0; count--) { + unit_size = 0; - if (ngx_rtmp_chain_reader_read(&reader, nalp , nal_unit_size) < 0) - { + if (ngx_rtmp_chain_reader_read(&reader, nalp, nal_unit_size) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: failed to read %uD bytes unit_size", sizeof (unit_size)); + "codec_config_hvcc_nal_units_get_size: " + "failed to read %uD bytes unit_size", + (uint32_t) sizeof(unit_size)); return 0; } read_be32(unit_size, unit_size); - if (ngx_rtmp_chain_reader_skip(&reader, unit_size) < 0) - { + if (ngx_rtmp_chain_reader_skip(&reader, unit_size) < 0) { ngx_log_error(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: failed to skip NAL unit of size %uD", unit_size); + "codec_config_hvcc_nal_units_get_size: " + "failed to skip NAL unit of size %uD", unit_size); return 0; } ngx_log_debug1(NGX_LOG_NOTICE, log, 0, - "codec_config_hvcc_nal_units_get_size: skipped NAL unit of size %uD", unit_size); + "codec_config_hvcc_nal_units_get_size: " + "skipped NAL unit of size %uD", unit_size); size += nal_unit_size + 1 + unit_size; } diff --git a/nginx-rtmp-module/src/ngx_rtmp_codec_module.h b/nginx-rtmp-module/src/ngx_rtmp_codec_module.h index c7bcaf95..be0f97e6 100644 --- a/nginx-rtmp-module/src/ngx_rtmp_codec_module.h +++ b/nginx-rtmp-module/src/ngx_rtmp_codec_module.h @@ -33,20 +33,16 @@ enum { }; -// extension packetType as defined in "https://veovera.org/docs/enhanced/enhanced-rtmp-v1" -typedef enum { - PacketTypeSequenceStart, - PacketTypeCodedFrames, - PacketTypeSequenceEnd, - PacketTypeCodedFramesX, - PacketTypeMetadata, - PacketTypeMPEG2TSSequenceStart, - PacketTypeLastReserved = 15 -} ngx_rtmp_v1_packet_type_t; - -#define NGX_RTMP_CODEC_FOURCC_HEV1 (0x31766568) -#define NGX_RTMP_CODEC_FOURCC_HVC1 (0x31637668) -#define NGX_RTMP_EXT_HEADER_MASK (0x80) +#define NGX_RTMP_EXT_HEADER_MASK (0x80) + +/* https://veovera.org/docs/enhanced/enhanced-rtmp-v1 */ +enum { + NGX_RTMP_PKT_TYPE_SEQUENCE_START, + NGX_RTMP_PKT_TYPE_CODED_FRAMES, + NGX_RTMP_PKT_TYPE_SEQUENCE_END, + NGX_RTMP_PKT_TYPE_CODED_FRAMES_X, +}; + /* Video codecs */ enum { @@ -59,6 +55,9 @@ enum { NGX_RTMP_VIDEO_H264 = 7 }; +#define NGX_RTMP_CODEC_FOURCC_HEV1 (0x31766568) +#define NGX_RTMP_CODEC_FOURCC_HVC1 (0x31637668) + u_char *ngx_rtmp_get_audio_codec_name(ngx_uint_t id); u_char *ngx_rtmp_get_video_codec_name(ngx_uint_t id); @@ -101,11 +100,14 @@ typedef struct { static ngx_inline ngx_int_t ngx_rtmp_is_codec_header(ngx_uint_t codec_id, ngx_chain_t *in) { - switch(codec_id){ + switch (codec_id) { + case NGX_RTMP_CODEC_FOURCC_HEV1: case NGX_RTMP_CODEC_FOURCC_HVC1: - //HEVCDecoderConfigurationRecord configurationVersion byte - return in->buf->pos < in->buf->last && (in->buf->pos[0] & 0xf) == PacketTypeSequenceStart; + /* HEVCDecoderConfigurationRecord configurationVersion byte */ + return in->buf->pos < in->buf->last + && (in->buf->pos[0] & 0xf) == NGX_RTMP_PKT_TYPE_SEQUENCE_START; + default: return in->buf->pos + 1 < in->buf->last && in->buf->pos[1] == 0; }