video & audio working

This commit is contained in:
Roman Arutyunyan 2013-11-12 17:20:16 +04:00
parent 6caee7cb88
commit c18fd3aad4
3 changed files with 209 additions and 158 deletions

View file

@ -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" \
" <SegmentTemplate\n" \
" presentationTimeOffset=\"%ui\"\n" \
" presentationTimeOffset=\"0\"\n" \
" timescale=\"1000\"\n" \
" duration=\"%ui\"\n" \
" media=\"%V-$Number$.m4v\"\n" \
@ -253,10 +250,10 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
" codecs=\"mp4a.%s\"\n" \
" audioSamplingRate=\"%ui\"\n" \
" startWithSAP=\"1\"\n" \
" bandwidth=\"130685\">\n" \
" bandwidth=\"0\">\n" \
" <SegmentTemplate\n" \
" presentationTimeOffset=\"%ui\"\n" \
" timescale=\"%ui\"\n" \
" presentationTimeOffset=\"0\"\n" \
" timescale=\"1000\"\n" \
" duration=\"%ui\"\n" \
" media=\"%V-$Number$.m4a\"\n" \
" startNumber=\"0\"\n" \
@ -281,8 +278,6 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
codec_ctx->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;

View file

@ -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);

View file

@ -9,6 +9,12 @@
#include <ngx_rtmp.h>
#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);