From 96e60a4ac090cae09d95c9705b7463b56f762e62 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Sat, 30 Nov 2013 01:38:57 +0400 Subject: [PATCH] fixed dash mp4 format & writer style --- dash/ngx_rtmp_dash_module.c | 57 +++++++-------- dash/ngx_rtmp_mp4.c | 141 +++++++++++++++++++----------------- dash/ngx_rtmp_mp4.h | 27 ++++--- 3 files changed, 114 insertions(+), 111 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 9301e69..7be4132 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -457,14 +457,13 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) static ngx_int_t ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) { - ngx_fd_t fd; - ngx_int_t rc; - ngx_buf_t b; - ngx_rtmp_dash_ctx_t *ctx; - ngx_rtmp_codec_ctx_t *codec_ctx; - ngx_rtmp_mp4_metadata_t metadata; + ngx_fd_t fd; + ngx_int_t rc; + ngx_buf_t b; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; - static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); @@ -473,9 +472,6 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) return NGX_ERROR; } - metadata.width = codec_ctx->width; - metadata.height = codec_ctx->height; - /* init video */ *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4v") = 0; @@ -493,10 +489,9 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) b.end = b.start + sizeof(buffer); b.pos = b.last = b.start; - metadata.video = 1; - - ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); - ngx_rtmp_mp4_write_moov(s, &b, &metadata); + ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, + NGX_RTMP_MP4_VIDEO_TRACK); + ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_VIDEO_TRACK); rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); if (rc == NGX_ERROR) { @@ -521,10 +516,9 @@ ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) b.pos = b.last = b.start; - metadata.video = 0; - - ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, &metadata); - ngx_rtmp_mp4_write_moov(s, &b, &metadata); + ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_INIT, + NGX_RTMP_MP4_AUDIO_TRACK); + ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_AUDIO_TRACK); rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); if (rc == NGX_ERROR) { @@ -565,7 +559,9 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t) b.end = buffer + sizeof(buffer); b.pos = b.last = b.start; - ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_SEG, NULL); + ngx_rtmp_mp4_write_ftyp(&b, NGX_RTMP_MP4_FILETYPE_SEG, t->type == 'v' ? + NGX_RTMP_MP4_VIDEO_TRACK : + NGX_RTMP_MP4_AUDIO_TRACK); pos = b.last; b.last += 44; /* leave room for sidx */ @@ -1046,10 +1042,11 @@ 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 key, uint32_t timestamp, uint32_t delay) { - u_char *p; - size_t size, bsize; + u_char *p; + size_t size, bsize; + ngx_rtmp_mp4_sample_t *smpl; - static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; p = buffer; size = 0; @@ -1081,15 +1078,17 @@ ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, return NGX_ERROR; } - t->samples[t->sample_count].delay = delay; - 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 = (key ? 1 : 0); + smpl = &t->samples[t->sample_count]; + + smpl->delay = delay; + smpl->size = (uint32_t) size; + smpl->duration = 0; + smpl->timestamp = timestamp; + smpl->key = (key ? 1 : 0); if (t->sample_count > 0) { - t->samples[t->sample_count - 1].duration = timestamp - - t->samples[t->sample_count - 1].timestamp; + smpl = &t->samples[t->sample_count - 1]; + smpl->duration = timestamp - smpl->timestamp; } t->sample_count++; diff --git a/dash/ngx_rtmp_mp4.c b/dash/ngx_rtmp_mp4.c index 7feb3c4..945cacd 100644 --- a/dash/ngx_rtmp_mp4.c +++ b/dash/ngx_rtmp_mp4.c @@ -183,12 +183,12 @@ ngx_rtmp_mp4_write_matrix(ngx_buf_t *buf, uint32_t a, uint32_t b, uint32_t c, ngx_int_t -ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, ngx_rtmp_mp4_file_type_t ftype, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; - switch (type) { + switch (ftype) { case NGX_RTMP_MP4_FILETYPE_INIT: @@ -197,7 +197,7 @@ ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, ngx_rtmp_mp4_box(b, "iso5"); ngx_rtmp_mp4_field_32(b, 1); - if (metadata != NULL && metadata->video) { + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { ngx_rtmp_mp4_box(b, "avc1"); } @@ -225,7 +225,7 @@ ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, int type, static ngx_int_t -ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b) { u_char *pos; @@ -273,9 +273,13 @@ ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) static ngx_int_t -ngx_rtmp_mp4_write_tkhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_tkhd(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { - u_char *pos; + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); pos = ngx_rtmp_mp4_start_box(b, "tkhd"); @@ -306,16 +310,16 @@ ngx_rtmp_mp4_write_tkhd(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) ngx_rtmp_mp4_field_32(b, 0); /* reserved */ - ngx_rtmp_mp4_field_16(b, metadata->video ? 0 : 0x0100); + ngx_rtmp_mp4_field_16(b, ttype == NGX_RTMP_MP4_VIDEO_TRACK ? 0 : 0x0100); /* reserved */ ngx_rtmp_mp4_field_16(b, 0); ngx_rtmp_mp4_write_matrix(b, 1, 0, 0, 1, 0, 0); - if (metadata->video) { - ngx_rtmp_mp4_field_32(b, (uint32_t) metadata->width << 16); - ngx_rtmp_mp4_field_32(b, (uint32_t) metadata->height << 16); + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_field_32(b, (uint32_t) codec_ctx->width << 16); + ngx_rtmp_mp4_field_32(b, (uint32_t) codec_ctx->height << 16); } else { ngx_rtmp_mp4_field_32(b, 0); ngx_rtmp_mp4_field_32(b, 0); @@ -362,7 +366,7 @@ ngx_rtmp_mp4_write_mdhd(ngx_buf_t *b) static ngx_int_t -ngx_rtmp_mp4_write_hdlr(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_hdlr(ngx_buf_t *b, ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; @@ -374,7 +378,7 @@ ngx_rtmp_mp4_write_hdlr(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) /* pre defined */ ngx_rtmp_mp4_field_32(b, 0); - if (metadata->video) { + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { ngx_rtmp_mp4_box(b, "vide"); } else { ngx_rtmp_mp4_box(b, "soun"); @@ -385,11 +389,10 @@ ngx_rtmp_mp4_write_hdlr(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) ngx_rtmp_mp4_field_32(b, 0); ngx_rtmp_mp4_field_32(b, 0); - if (metadata->video) { + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { /* video handler string, NULL-terminated */ ngx_rtmp_mp4_data(b, "VideoHandler", sizeof("VideoHandler")); - } - else { + } else { /* sound handler string, NULL-terminated */ ngx_rtmp_mp4_data(b, "SoundHandler", sizeof("SoundHandler")); } @@ -439,7 +442,7 @@ ngx_rtmp_mp4_write_smhd(ngx_buf_t *b) static ngx_int_t -ngx_rtmp_mp4_write_dref(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_dref(ngx_buf_t *b) { u_char *pos; @@ -466,13 +469,13 @@ ngx_rtmp_mp4_write_dref(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) static ngx_int_t -ngx_rtmp_mp4_write_dinf(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_dinf(ngx_buf_t *b) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "dinf"); - ngx_rtmp_mp4_write_dref(b, metadata); + ngx_rtmp_mp4_write_dref(b); ngx_rtmp_mp4_update_box_size(b, pos); @@ -481,8 +484,7 @@ ngx_rtmp_mp4_write_dinf(ngx_buf_t *b, ngx_rtmp_mp4_metadata_t *metadata) static ngx_int_t -ngx_rtmp_mp4_write_avcc(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_avcc(ngx_rtmp_session_t *s, ngx_buf_t *b) { u_char *pos, *p; ngx_chain_t *in; @@ -524,10 +526,12 @@ ngx_rtmp_mp4_write_avcc(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b) { - u_char *pos; + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); pos = ngx_rtmp_mp4_start_box(b, "avc1"); @@ -548,8 +552,8 @@ ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_field_32(b, 0); /* width & height */ - ngx_rtmp_mp4_field_16(b, (uint16_t) metadata->width); - ngx_rtmp_mp4_field_16(b, (uint16_t) metadata->height); + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->width); + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->height); /* horizontal & vertical resolutions 72 dpi */ ngx_rtmp_mp4_field_32(b, 0x00480000); @@ -575,7 +579,7 @@ ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_field_16(b, 0x18); ngx_rtmp_mp4_field_16(b, 0xffff); - ngx_rtmp_mp4_write_avcc(s, b, metadata); + ngx_rtmp_mp4_write_avcc(s, b); ngx_rtmp_mp4_update_box_size(b, pos); @@ -584,8 +588,7 @@ ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_esds(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_esds(ngx_rtmp_session_t *s, ngx_buf_t *b) { size_t dsi_len; u_char *pos, *dsi; @@ -665,10 +668,12 @@ ngx_rtmp_mp4_write_esds(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b) { - u_char *pos; + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); pos = ngx_rtmp_mp4_start_box(b, "mp4a"); @@ -683,11 +688,11 @@ ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b, ngx_rtmp_mp4_field_32(b, 0); ngx_rtmp_mp4_field_32(b, 0); - /* reserved = 2*/ - ngx_rtmp_mp4_field_16(b, 2); + /* channel count */ + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->audio_channels); - /* reserved = 16 */ - ngx_rtmp_mp4_field_16(b, 16); + /* sample size */ + ngx_rtmp_mp4_field_16(b, (uint16_t) (codec_ctx->sample_size * 8)); /* reserved */ ngx_rtmp_mp4_field_32(b, 0); @@ -695,17 +700,17 @@ ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b, /* time scale */ ngx_rtmp_mp4_field_16(b, 1000); - /* reserved */ - ngx_rtmp_mp4_field_16(b, 0); - - ngx_rtmp_mp4_write_esds(s, b, metadata); + /* sample rate */ + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->sample_rate); + ngx_rtmp_mp4_write_esds(s, b); +#if 0 /* tag size*/ ngx_rtmp_mp4_field_32(b, 8); /* null tag */ ngx_rtmp_mp4_field_32(b, 0); - +#endif ngx_rtmp_mp4_update_box_size(b, pos); return NGX_OK; @@ -713,8 +718,8 @@ ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_stsd(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_stsd(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; @@ -726,10 +731,10 @@ ngx_rtmp_mp4_write_stsd(ngx_rtmp_session_t *s, ngx_buf_t *b, /* entry count */ ngx_rtmp_mp4_field_32(b, 1); - if (metadata->video) { - ngx_rtmp_mp4_write_video(s, b, metadata); + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_write_video(s, b); } else { - ngx_rtmp_mp4_write_audio(s, b, metadata); + ngx_rtmp_mp4_write_audio(s, b); } ngx_rtmp_mp4_update_box_size(b, pos); @@ -804,14 +809,14 @@ ngx_rtmp_mp4_write_stco(ngx_buf_t *b) static ngx_int_t -ngx_rtmp_mp4_write_stbl(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_stbl(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "stbl"); - ngx_rtmp_mp4_write_stsd(s, b, metadata); + ngx_rtmp_mp4_write_stsd(s, b, ttype); ngx_rtmp_mp4_write_stts(b); ngx_rtmp_mp4_write_stsc(b); ngx_rtmp_mp4_write_stsz(b); @@ -824,21 +829,21 @@ ngx_rtmp_mp4_write_stbl(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_minf(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_minf(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "minf"); - if (metadata->video) { + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { ngx_rtmp_mp4_write_vmhd(b); } else { ngx_rtmp_mp4_write_smhd(b); } - ngx_rtmp_mp4_write_dinf(b, metadata); - ngx_rtmp_mp4_write_stbl(s, b, metadata); + ngx_rtmp_mp4_write_dinf(b); + ngx_rtmp_mp4_write_stbl(s, b, ttype); ngx_rtmp_mp4_update_box_size(b, pos); @@ -847,16 +852,16 @@ ngx_rtmp_mp4_write_minf(ngx_rtmp_session_t *s, ngx_buf_t *b, static ngx_int_t -ngx_rtmp_mp4_write_mdia(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_mdia(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "mdia"); ngx_rtmp_mp4_write_mdhd(b); - ngx_rtmp_mp4_write_hdlr(b, metadata); - ngx_rtmp_mp4_write_minf(s, b, metadata); + ngx_rtmp_mp4_write_hdlr(b, ttype); + ngx_rtmp_mp4_write_minf(s, b, ttype); ngx_rtmp_mp4_update_box_size(b, pos); @@ -864,15 +869,15 @@ ngx_rtmp_mp4_write_mdia(ngx_rtmp_session_t *s, ngx_buf_t *b, } static ngx_int_t -ngx_rtmp_mp4_write_trak(ngx_rtmp_session_t *s, ngx_buf_t *b, - ngx_rtmp_mp4_metadata_t *metadata) +ngx_rtmp_mp4_write_trak(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "trak"); - ngx_rtmp_mp4_write_tkhd(b, metadata); - ngx_rtmp_mp4_write_mdia(s, b, metadata); + ngx_rtmp_mp4_write_tkhd(s, b, ttype); + ngx_rtmp_mp4_write_mdia(s, b, ttype); ngx_rtmp_mp4_update_box_size(b, pos); @@ -881,7 +886,7 @@ 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) +ngx_rtmp_mp4_write_mvex(ngx_buf_t *b) { u_char *pos; @@ -916,16 +921,16 @@ ngx_rtmp_mp4_write_mvex(ngx_buf_t *b, 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_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "moov"); - ngx_rtmp_mp4_write_mvhd(b, metadata); - ngx_rtmp_mp4_write_mvex(b, metadata); - ngx_rtmp_mp4_write_trak(s, b, metadata); + ngx_rtmp_mp4_write_mvhd(b); + ngx_rtmp_mp4_write_mvex(b); + ngx_rtmp_mp4_write_trak(s, b, ttype); ngx_rtmp_mp4_update_box_size(b, pos); diff --git a/dash/ngx_rtmp_mp4.h b/dash/ngx_rtmp_mp4.h index 31e6e02..9e19586 100644 --- a/dash/ngx_rtmp_mp4.h +++ b/dash/ngx_rtmp_mp4.h @@ -24,23 +24,22 @@ typedef struct { } ngx_rtmp_mp4_sample_t; -typedef struct { - ngx_uint_t width; - ngx_uint_t height; - ngx_uint_t video; -} ngx_rtmp_mp4_metadata_t; - - -enum { - NGX_RTMP_MP4_FILETYPE_INIT = 0, +typedef enum { + NGX_RTMP_MP4_FILETYPE_INIT, NGX_RTMP_MP4_FILETYPE_SEG -}; +} ngx_rtmp_mp4_file_type_t; -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); +typedef enum { + NGX_RTMP_MP4_VIDEO_TRACK, + NGX_RTMP_MP4_AUDIO_TRACK +} ngx_rtmp_mp4_track_type_t; + + +ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b, ngx_rtmp_mp4_file_type_t ftype, + ngx_rtmp_mp4_track_type_t ttype); +ngx_int_t ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype); 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);