From c18fd3aad4aae5aedc26f00f703ea9bd813bf55c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 12 Nov 2013 17:20:16 +0400 Subject: [PATCH] video & audio working --- dash/ngx_rtmp_dash_module.c | 75 +++++----- dash/ngx_rtmp_mp4.c | 274 +++++++++++++++++++++--------------- dash/ngx_rtmp_mp4.h | 18 ++- 3 files changed, 209 insertions(+), 158 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index e8c1290..a1e4d5a 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -31,6 +31,7 @@ typedef struct { ngx_uint_t opened; ngx_uint_t mdat_size; ngx_uint_t sample_count; + ngx_uint_t sample_mask; ngx_fd_t fd; char type; uint32_t earliest_pres_time; @@ -170,7 +171,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) ngx_fd_t fd; ngx_str_t playlist, playlist_bak; ngx_rtmp_dash_ctx_t *ctx; - ngx_rtmp_live_ctx_t *live_ctx; ngx_rtmp_codec_ctx_t *codec_ctx; ngx_rtmp_dash_app_conf_t *dacf; @@ -179,11 +179,8 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); - live_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); - if (dacf == NULL || ctx == NULL || codec_ctx == NULL || - live_ctx == NULL || live_ctx->stream == NULL) - { + if (dacf == NULL || ctx == NULL || codec_ctx == NULL) { return NGX_ERROR; } @@ -228,9 +225,9 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) " frameRate=\"%ui\"\n" \ " sar=\"1:1\"\n" \ " startWithSAP=\"1\"\n" \ - " bandwidth=\"%ui\">\n" \ + " bandwidth=\"0\">\n" \ " \n" \ + " bandwidth=\"0\">\n" \ " width, codec_ctx->height, codec_ctx->frame_rate, - (ngx_uint_t) (live_ctx->stream->bw_in.bandwidth * 8), - (ngx_uint_t) 0,//ctx->video.earliest_pres_time, (ngx_uint_t) dacf->fraglen, &ctx->name, &ctx->name); @@ -294,11 +289,7 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC ? "40.2" : "6b", codec_ctx->sample_rate, - (ngx_uint_t) (ctx->audio.earliest_pres_time * - (float) codec_ctx->sample_rate / 1000), - codec_ctx->sample_rate, - (ngx_uint_t) (dacf->fraglen * codec_ctx->sample_rate - / 1000), + (ngx_uint_t) dacf->fraglen, &ctx->name, &ctx->name); n = ngx_write_fd(fd, buffer, p - buffer); @@ -372,6 +363,7 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) metadata.audio = 0; metadata.video = 1; + /*TODO: buffer control*/ ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); ngx_rtmp_mp4_write_moov(s, &b, &metadata); @@ -401,6 +393,7 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) metadata.video = 0; metadata.audio = 1; + /*TODO: buffer control*/ ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); ngx_rtmp_mp4_write_moov(s, &b, &metadata); @@ -417,8 +410,7 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) static void -ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, - ngx_uint_t sample_rate) +ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t) { u_char *pos, *pos1; size_t left; @@ -451,13 +443,12 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, "dash: fragment earliest pts: %uD", t->earliest_pres_time); ngx_rtmp_mp4_write_moof(&b, t->earliest_pres_time, t->sample_count, - t->samples, t->id, sample_rate); + t->samples, t->sample_mask, t->id); pos1 = b.last; b.last = pos; - ngx_rtmp_mp4_write_sidx(s, &b, t->mdat_size + 8 + (pos1 - (pos + 44)), - t->earliest_pres_time, t->latest_pres_time, - sample_rate); + ngx_rtmp_mp4_write_sidx(&b, t->mdat_size + 8 + (pos1 - (pos + 44)), + t->earliest_pres_time, t->latest_pres_time); b.last = pos1; ngx_rtmp_mp4_write_mdat(&b, t->mdat_size + 8); @@ -518,21 +509,19 @@ done: static ngx_int_t ngx_rtmp_dash_close_fragments(ngx_rtmp_session_t *s) { - ngx_rtmp_dash_ctx_t *ctx; - ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_dash_ctx_t *ctx; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "dash: close fragments"); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); - codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); if (!ctx->opened) { return NGX_OK; } - ngx_rtmp_dash_close_fragment(s, &ctx->video, 0); - ngx_rtmp_dash_close_fragment(s, &ctx->audio, codec_ctx->sample_rate); + ngx_rtmp_dash_close_fragment(s, &ctx->video); + ngx_rtmp_dash_close_fragment(s, &ctx->audio); ngx_rtmp_dash_write_playlist(s); @@ -574,6 +563,16 @@ ngx_rtmp_dash_open_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, t->mdat_size = 0; t->opened = 1; + if (type == 'v') { + t->sample_mask = NGX_RTMP_MP4_SAMPLE_SIZE| + NGX_RTMP_MP4_SAMPLE_DURATION| + NGX_RTMP_MP4_SAMPLE_DELAY| + NGX_RTMP_MP4_SAMPLE_KEY; + } else { + t->sample_mask = NGX_RTMP_MP4_SAMPLE_SIZE| + NGX_RTMP_MP4_SAMPLE_DURATION; + } + return NGX_OK; } @@ -774,7 +773,7 @@ ngx_rtmp_dash_update_fragments(ngx_rtmp_session_t *s, ngx_int_t boundary, static ngx_int_t ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, - ngx_rtmp_dash_track_t *t, ngx_int_t boundary, uint32_t timestamp) + ngx_rtmp_dash_track_t *t, ngx_int_t key, uint32_t timestamp) { u_char *p; size_t size, bsize; @@ -798,23 +797,18 @@ ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, size += bsize; } - t->latest_pres_time = timestamp; - - if (t->sample_count > 0) { - t->samples[t->sample_count - 1].duration = timestamp - - t->samples[t->sample_count - 1].timestamp; - } - if (!ctx->opened) { ngx_rtmp_dash_open_fragments(s); } - ngx_rtmp_dash_update_fragments(s, boundary, timestamp); + ngx_rtmp_dash_update_fragments(s, key, timestamp); if (t->sample_count == 0) { t->earliest_pres_time = timestamp; } + t->latest_pres_time = timestamp; + if (t->sample_count < NGX_RTMP_DASH_MAX_SAMPLES) { if (ngx_write_fd(t->fd, buffer, size) == NGX_ERROR) { @@ -827,7 +821,12 @@ ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, t->samples[t->sample_count].size = (uint32_t) size; t->samples[t->sample_count].duration = 0; t->samples[t->sample_count].timestamp = timestamp; - t->samples[t->sample_count].key = (boundary ? 1 : 0); + t->samples[t->sample_count].key = (key ? 1 : 0); + + if (t->sample_count > 0) { + t->samples[t->sample_count - 1].duration = timestamp - + t->samples[t->sample_count - 1].timestamp; + } t->sample_count++; t->mdat_size += (ngx_uint_t) size; diff --git a/dash/ngx_rtmp_mp4.c b/dash/ngx_rtmp_mp4.c index 45d9184..6611302 100644 --- a/dash/ngx_rtmp_mp4.c +++ b/dash/ngx_rtmp_mp4.c @@ -178,7 +178,7 @@ ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, ngx_rtmp_mp4_metadata_t *metadata) { - u_char *pos; + u_char *pos; pos = b->last; @@ -303,26 +303,37 @@ ngx_rtmp_mp4_write_tkhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) static ngx_int_t -ngx_rtmp_mp4_write_mdhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_mdhd(ngx_buf_t *b) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "mdhd", sizeof("mdhd")-1); + b->last = ngx_cpymem(b->last, "mdhd", sizeof("mdhd") - 1); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + /* creation time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* modification time */ + ngx_rtmp_mp4_field_32(b, 0); - ngx_rtmp_mp4_field_32(b, 0); /* version */ - ngx_rtmp_mp4_field_32(b, 0); /* creation time */ - ngx_rtmp_mp4_field_32(b, 0); /* modification time */ /* time scale*/ - ngx_rtmp_mp4_field_32(b, metadata->audio == 1 ? metadata->sample_rate : - NGX_RTMP_MP4_TIMESCALE); - ngx_rtmp_mp4_field_32(b, 0); /* duration */ - ngx_rtmp_mp4_field_16(b, 0x15C7); /* language */ - ngx_rtmp_mp4_field_16(b, 0); /* reserved */ + ngx_rtmp_mp4_field_32(b, NGX_RTMP_MP4_TIMESCALE); + + /* duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* lanuguage */ + ngx_rtmp_mp4_field_16(b, 0x15C7); + + /* reserved */ + ngx_rtmp_mp4_field_16(b, 0); ngx_rtmp_mp4_update_box_size(b, pos); @@ -786,14 +797,14 @@ static ngx_int_t ngx_rtmp_mp4_write_minf(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "minf", sizeof("minf")-1); + b->last = ngx_cpymem(b->last, "minf", sizeof("minf") - 1); if (metadata->video == 1) { ngx_rtmp_mp4_write_vmhd(b); @@ -815,16 +826,16 @@ static ngx_int_t ngx_rtmp_mp4_write_mdia(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "mdia", sizeof("mdia")-1); + b->last = ngx_cpymem(b->last, "mdia", sizeof("mdia") - 1); - ngx_rtmp_mp4_write_mdhd(b, metadata); + ngx_rtmp_mp4_write_mdhd(b); ngx_rtmp_mp4_write_hdlr(b, metadata); ngx_rtmp_mp4_write_minf(s, b, metadata); @@ -837,14 +848,14 @@ static ngx_int_t ngx_rtmp_mp4_write_trak(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "trak", sizeof("trak")-1); + b->last = ngx_cpymem(b->last, "trak", sizeof("trak") - 1); ngx_rtmp_mp4_write_tkhd(b, metadata); ngx_rtmp_mp4_write_mdia(s, b, metadata); @@ -858,23 +869,14 @@ ngx_rtmp_mp4_write_trak(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t ngx_rtmp_mp4_write_mvex(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) { - u_char *pos; - uint32_t sample_dur; - - if (metadata->video == 1) { - sample_dur = metadata->frame_rate > 0 ? NGX_RTMP_MP4_TIMESCALE / - metadata->frame_rate : NGX_RTMP_MP4_TIMESCALE; - } - else { - sample_dur = metadata->audio_codec == NGX_RTMP_AUDIO_AAC ? 1024 : 1152; - } + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "mvex", sizeof("mvex")-1); + b->last = ngx_cpymem(b->last, "mvex", sizeof("mvex") - 1); /* just write the trex and mehd in here too */ #if 0 @@ -885,17 +887,28 @@ ngx_rtmp_mp4_write_mvex(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) ngx_rtmp_mp4_field_32(b, 0); /* version & flags */ ngx_rtmp_mp4_field_32(b, 0x000D8D2A); /* frag duration */ #endif + ngx_rtmp_mp4_field_32(b, 0x20); - b->last = ngx_cpymem(b->last, "trex", sizeof("trex")-1); + b->last = ngx_cpymem(b->last, "trex", sizeof("trex") - 1); - ngx_rtmp_mp4_field_32(b, 0); /* version & flags */ - ngx_rtmp_mp4_field_32(b, 1); /* track id */ - ngx_rtmp_mp4_field_32(b, 1); /* default sample description index */ - ngx_rtmp_mp4_field_32(b, sample_dur); /* default sample duration */ - ngx_rtmp_mp4_field_32(b, 0); /* default sample size */ - /* default sample flags */ - ngx_rtmp_mp4_field_32(b, metadata->audio == 1 ? 0 : 0x00010000); + /* version & flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* track id */ + ngx_rtmp_mp4_field_32(b, 1); + + /* default sample description index */ + ngx_rtmp_mp4_field_32(b, 1); + + /* default sample duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* default sample size, 1024 for AAC */ + ngx_rtmp_mp4_field_32(b, 1024); + + /* default sample flags, key on */ + ngx_rtmp_mp4_field_32(b, 0); ngx_rtmp_mp4_update_box_size(b, pos); @@ -927,7 +940,7 @@ ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_tfhd(ngx_buf_t *b, ngx_uint_t sample_rate) +ngx_rtmp_mp4_write_tfhd(ngx_buf_t *b) { u_char *pos; @@ -939,11 +952,10 @@ ngx_rtmp_mp4_write_tfhd(ngx_buf_t *b, ngx_uint_t sample_rate) b->last = ngx_cpymem(b->last, "tfhd", sizeof("tfhd")-1); /* version & flags */ - ngx_rtmp_mp4_field_32(b, sample_rate > 0 ? 0x00020020 : 0x00020000); - ngx_rtmp_mp4_field_32(b, 1); /* track id */ - if (sample_rate > 0) { - ngx_rtmp_mp4_field_32(b, 0x02000000); - } + ngx_rtmp_mp4_field_32(b, 0x00020000); + + /* track id */ + ngx_rtmp_mp4_field_32(b, 1); ngx_rtmp_mp4_update_box_size(b, pos); @@ -952,29 +964,20 @@ ngx_rtmp_mp4_write_tfhd(ngx_buf_t *b, ngx_uint_t sample_rate) static ngx_int_t -ngx_rtmp_mp4_write_tfdt(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - ngx_uint_t sample_rate) +ngx_rtmp_mp4_write_tfdt(ngx_buf_t *b, uint32_t earliest_pres_time) { - u_char *pos; - float multiplier; - - if (sample_rate > 0) { - multiplier = (float)sample_rate/(float)NGX_RTMP_MP4_TIMESCALE; - } - else { - multiplier = 1; - } + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "tfdt", sizeof("tfdt")-1); + b->last = ngx_cpymem(b->last, "tfdt", sizeof("tfdt") - 1); - ngx_rtmp_mp4_field_32(b, 0x00000000); /* version == 1 aka 64 bit integer */ - /* earliest presentation time */ - ngx_rtmp_mp4_field_32(b, (uint32_t)((float)earliest_pres_time*multiplier)); + /* version == 1 aka 64 bit integer */ + ngx_rtmp_mp4_field_32(b, 0x00000000); + ngx_rtmp_mp4_field_32(b, earliest_pres_time); ngx_rtmp_mp4_update_box_size(b, pos); @@ -984,29 +987,66 @@ ngx_rtmp_mp4_write_tfdt(ngx_buf_t *b, ngx_uint_t earliest_pres_time, static ngx_int_t ngx_rtmp_mp4_write_trun(ngx_buf_t *b, uint32_t sample_count, - ngx_rtmp_mp4_sample_t *samples, u_char *moof_pos) + ngx_rtmp_mp4_sample_t *samples, ngx_uint_t sample_mask, u_char *moof_pos) { u_char *pos; - uint32_t i, offset; + uint32_t i, offset, nitems, flags; pos = b->last; - offset = (pos - moof_pos) + 20 + (sample_count * 4 * 4) + 8; + nitems = 0; + + /* data offset present */ + flags = 0x01; + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DURATION) { + nitems++; + flags |= 0x000100; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_SIZE) { + nitems++; + flags |= 0x000200; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_KEY) { + nitems++; + flags |= 0x000400; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DELAY) { + nitems++; + flags |= 0x000800; + } + + offset = (pos - moof_pos) + 20 + (sample_count * nitems * 4) + 8; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); b->last = ngx_cpymem(b->last, "trun", sizeof("trun") - 1); - ngx_rtmp_mp4_field_32(b, 0x00000f01); + ngx_rtmp_mp4_field_32(b, flags); ngx_rtmp_mp4_field_32(b, sample_count); ngx_rtmp_mp4_field_32(b, offset); - for (i = 0; i < sample_count; i++) { - ngx_rtmp_mp4_field_32(b, samples[i].duration); - ngx_rtmp_mp4_field_32(b, samples[i].size); - ngx_rtmp_mp4_field_32(b, samples[i].key ? 0x00000000 : 0x00010000); - ngx_rtmp_mp4_field_32(b, samples[i].delay); + for (i = 0; i < sample_count; i++, samples++) { + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DURATION) { + ngx_rtmp_mp4_field_32(b, samples->duration); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_SIZE) { + ngx_rtmp_mp4_field_32(b, samples->size); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_KEY) { + ngx_rtmp_mp4_field_32(b, samples->key ? 0x00000000 : 0x00010000); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DELAY) { + ngx_rtmp_mp4_field_32(b, samples->delay); + } } ngx_rtmp_mp4_update_box_size(b, pos); @@ -1016,22 +1056,22 @@ ngx_rtmp_mp4_write_trun(ngx_buf_t *b, uint32_t sample_count, static ngx_int_t -ngx_rtmp_mp4_write_traf(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, u_char *moof_pos, - ngx_uint_t sample_rate) +ngx_rtmp_mp4_write_traf(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, u_char *moof_pos) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "traf", sizeof("traf")-1); + b->last = ngx_cpymem(b->last, "traf", sizeof("traf") - 1); - ngx_rtmp_mp4_write_tfhd(b, sample_rate); - ngx_rtmp_mp4_write_tfdt(b, earliest_pres_time, sample_rate); - ngx_rtmp_mp4_write_trun(b, sample_count, samples, moof_pos); + ngx_rtmp_mp4_write_tfhd(b); + ngx_rtmp_mp4_write_tfdt(b, earliest_pres_time); + ngx_rtmp_mp4_write_trun(b, sample_count, samples, sample_mask, moof_pos); ngx_rtmp_mp4_update_box_size(b, pos); @@ -1051,8 +1091,11 @@ ngx_rtmp_mp4_write_mfhd(ngx_buf_t *b, uint32_t index) b->last = ngx_cpymem(b->last, "mfhd", sizeof("mfhd")-1); - ngx_rtmp_mp4_field_32(b, 0); /* don't know what this is */ - ngx_rtmp_mp4_field_32(b, index); /* fragment index. */ + /* don't know what this is */ + ngx_rtmp_mp4_field_32(b, 0); + + /* fragment index. */ + ngx_rtmp_mp4_field_32(b, index); ngx_rtmp_mp4_update_box_size(b, pos); @@ -1061,49 +1104,52 @@ ngx_rtmp_mp4_write_mfhd(ngx_buf_t *b, uint32_t index) ngx_int_t -ngx_rtmp_mp4_write_sidx(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_uint_t reference_size, ngx_uint_t earliest_pres_time, - ngx_uint_t latest_pres_time, ngx_uint_t sample_rate) +ngx_rtmp_mp4_write_sidx(ngx_buf_t *b, ngx_uint_t reference_size, + uint32_t earliest_pres_time, uint32_t latest_pres_time) { - u_char *pos; - uint32_t ept, dur; + u_char *pos; + uint32_t duration; - if (sample_rate > 0) { - ept = (uint32_t)((float)earliest_pres_time*((float)sample_rate / - (float)NGX_RTMP_MP4_TIMESCALE)); - dur = (uint32_t)((float)(latest_pres_time-earliest_pres_time) * - ((float)sample_rate/(float)NGX_RTMP_MP4_TIMESCALE)); - } - else { - ept = earliest_pres_time; - dur = (latest_pres_time-earliest_pres_time); - } - - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "dash: buffered dash range start: %uL, duration: %uL", - ept, dur); + duration = latest_pres_time - earliest_pres_time; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "sidx", sizeof("sidx")-1); + b->last = ngx_cpymem(b->last, "sidx", sizeof("sidx") - 1); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + /* reference id */ + ngx_rtmp_mp4_field_32(b, 1); - ngx_rtmp_mp4_field_32(b, 0); /* version */ - ngx_rtmp_mp4_field_32(b, 1); /* reference id */ /* timescale */ - ngx_rtmp_mp4_field_32(b, sample_rate > 0 ? sample_rate : - NGX_RTMP_MP4_TIMESCALE); - ngx_rtmp_mp4_field_32(b, ept); /* earliest presentation time */ - ngx_rtmp_mp4_field_32(b, 0); /* first offset */ - ngx_rtmp_mp4_field_16(b, 0); /* reserved */ - ngx_rtmp_mp4_field_16(b, 1); /* reference count (=1) */ + ngx_rtmp_mp4_field_32(b, NGX_RTMP_MP4_TIMESCALE); + + /* earliest presentation time */ + ngx_rtmp_mp4_field_32(b, earliest_pres_time); + + /* first offset */ + ngx_rtmp_mp4_field_32(b, duration); /*TODO*/ + + /* reserved */ + ngx_rtmp_mp4_field_16(b, 0); + + /* reference count = 1 */ + ngx_rtmp_mp4_field_16(b, 1); + /* 1st bit is reference type, the rest is reference size */ ngx_rtmp_mp4_field_32(b, reference_size); - ngx_rtmp_mp4_field_32(b, dur); /* subsegment duration */ + + /* subsegment duration */ + ngx_rtmp_mp4_field_32(b, duration); + /* first bit is startsWithSAP (=1), next 3 bits are SAP type (=001) */ ngx_rtmp_mp4_field_8(b, 0x90); - ngx_rtmp_mp4_field_24(b, 0); /* SAP delta time */ + + /* SAP delta time */ + ngx_rtmp_mp4_field_24(b, 0); ngx_rtmp_mp4_update_box_size(b, pos); @@ -1112,22 +1158,22 @@ ngx_rtmp_mp4_write_sidx(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_int_t -ngx_rtmp_mp4_write_moof(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, uint32_t index, - ngx_uint_t sample_rate) +ngx_rtmp_mp4_write_moof(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, uint32_t index) { - u_char *pos; + u_char *pos; pos = b->last; /* box size placeholder */ ngx_rtmp_mp4_field_32(b, 0); - b->last = ngx_cpymem(b->last, "moof", sizeof("moof")-1); + b->last = ngx_cpymem(b->last, "moof", sizeof("moof") - 1); ngx_rtmp_mp4_write_mfhd(b, index); ngx_rtmp_mp4_write_traf(b, earliest_pres_time, sample_count, samples, - pos, sample_rate); + sample_mask, pos); ngx_rtmp_mp4_update_box_size(b, pos); diff --git a/dash/ngx_rtmp_mp4.h b/dash/ngx_rtmp_mp4.h index 233fa6f..dddc844 100644 --- a/dash/ngx_rtmp_mp4.h +++ b/dash/ngx_rtmp_mp4.h @@ -9,6 +9,12 @@ #include +#define NGX_RTMP_MP4_SAMPLE_SIZE 0x01 +#define NGX_RTMP_MP4_SAMPLE_DURATION 0x02 +#define NGX_RTMP_MP4_SAMPLE_DELAY 0x04 +#define NGX_RTMP_MP4_SAMPLE_KEY 0x08 + + typedef struct { uint32_t size; uint32_t duration; @@ -39,12 +45,12 @@ ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, ngx_rtmp_mp4_metadata_t *metadata); ngx_int_t ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata); -ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, ngx_uint_t earliest_pres_time, - uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, uint32_t index, - ngx_uint_t sample_rate); -ngx_int_t ngx_rtmp_mp4_write_sidx(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_uint_t reference_size, ngx_uint_t earliest_pres_time, - ngx_uint_t latest_pres_time, ngx_uint_t sample_rate); +ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, uint32_t index); +ngx_int_t ngx_rtmp_mp4_write_sidx(ngx_buf_t *b, + ngx_uint_t reference_size, uint32_t earliest_pres_time, + uint32_t latest_pres_time); ngx_uint_t ngx_rtmp_mp4_write_mdat(ngx_buf_t *b, ngx_uint_t size);