Merge branch 'dash'

This commit is contained in:
Roman Arutyunyan 2013-11-28 22:17:17 +04:00
commit 5bd02e7ed3
5 changed files with 2830 additions and 97 deletions

4
config
View file

@ -19,6 +19,7 @@ CORE_MODULES="$CORE_MODULES
ngx_rtmp_log_module \
ngx_rtmp_limit_module \
ngx_rtmp_hls_module \
ngx_rtmp_dash_module \
"
@ -43,6 +44,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
$ngx_addon_dir/ngx_rtmp_relay_module.h \
$ngx_addon_dir/ngx_rtmp_streams.h \
$ngx_addon_dir/hls/ngx_rtmp_mpegts.h \
$ngx_addon_dir/dash/ngx_rtmp_mp4.h \
"
@ -76,7 +78,9 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
$ngx_addon_dir/ngx_rtmp_log_module.c \
$ngx_addon_dir/ngx_rtmp_limit_module.c \
$ngx_addon_dir/hls/ngx_rtmp_hls_module.c \
$ngx_addon_dir/dash/ngx_rtmp_dash_module.c \
$ngx_addon_dir/hls/ngx_rtmp_mpegts.c \
$ngx_addon_dir/dash/ngx_rtmp_mp4.c \
"
CFLAGS="$CFLAGS -I$ngx_addon_dir"

1527
dash/ngx_rtmp_dash_module.c Normal file

File diff suppressed because it is too large Load diff

1115
dash/ngx_rtmp_mp4.c Normal file

File diff suppressed because it is too large Load diff

57
dash/ngx_rtmp_mp4.h Normal file
View file

@ -0,0 +1,57 @@
#ifndef _NGX_RTMP_MP4_H_INCLUDED_
#define _NGX_RTMP_MP4_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#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;
uint32_t delay;
uint32_t timestamp;
unsigned key:1;
} ngx_rtmp_mp4_sample_t;
typedef struct {
ngx_uint_t width;
ngx_uint_t height;
ngx_uint_t audio;
ngx_uint_t video;
ngx_uint_t sample_rate;
ngx_uint_t frame_rate;
ngx_uint_t audio_codec;
} ngx_rtmp_mp4_metadata_t;
enum {
NGX_RTMP_MP4_FILETYPE_INIT = 0,
NGX_RTMP_MP4_FILETYPE_SEG
};
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, 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);
#endif /* _NGX_RTMP_MP4_H_INCLUDED_ */

View file

@ -295,61 +295,6 @@ ngx_module_t ngx_rtmp_hls_module = {
};
static ngx_int_t
ngx_rtmp_hls_create_parent_dir(ngx_rtmp_session_t *s)
{
ngx_rtmp_hls_app_conf_t *hacf;
ngx_rtmp_hls_ctx_t *ctx;
ngx_err_t err;
size_t len;
static u_char path[NGX_MAX_PATH + 1];
hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module);
if (hacf->path.len == 0) {
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: creating target folder: '%V'", &hacf->path);
if (ngx_create_dir(hacf->path.data, NGX_RTMP_HLS_DIR_ACCESS) != NGX_OK) {
err = ngx_errno;
if (err != NGX_EEXIST) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, err,
"hls: error creating target folder: '%V'",
&hacf->path);
return NGX_ERROR;
}
}
if (!hacf->nested) {
return NGX_OK;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
len = hacf->path.len;
if (hacf->path.data[len - 1] == '/') {
len--;
}
*ngx_snprintf(path, sizeof(path) - 1, "%*s/%V", len, hacf->path.data,
&ctx->name) = 0;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: creating nested folder: '%s'", path);
if (ngx_create_dir(path, NGX_RTMP_HLS_DIR_ACCESS) != NGX_OK) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: error creating nested folder: '%s'", path);
return NGX_ERROR;
}
return NGX_OK;
}
static ngx_rtmp_hls_frag_t *
ngx_rtmp_hls_get_frag(ngx_rtmp_session_t *s, ngx_int_t n)
{
@ -472,10 +417,10 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s)
ngx_close_file(fd);
rc = ngx_rtmp_hls_rename_file(ctx->var_playlist_bak.data,
ctx->var_playlist.data);
if (rc != NGX_OK) {
if (ngx_rtmp_hls_rename_file(ctx->var_playlist_bak.data,
ctx->var_playlist.data)
== NGX_FILE_ERROR)
{
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: rename failed: '%V'->'%V'",
&ctx->var_playlist_bak, &ctx->var_playlist);
@ -495,7 +440,6 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
ngx_rtmp_hls_ctx_t *ctx;
ssize_t n;
ngx_rtmp_hls_app_conf_t *hacf;
ngx_int_t nretry, rc;
ngx_rtmp_hls_frag_t *f;
ngx_uint_t i, max_frag;
ngx_str_t name_part;
@ -505,26 +449,13 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s)
hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
nretry = 0;
retry:
fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY,
NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS);
if (fd == NGX_INVALID_FILE) {
if (ngx_errno == NGX_ENOENT && nretry == 0 &&
ngx_rtmp_hls_create_parent_dir(s) == NGX_OK)
{
nretry++;
goto retry;
}
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: " ngx_open_file_n " failed: '%V'",
&ctx->playlist_bak);
return NGX_ERROR;
}
@ -590,9 +521,9 @@ retry:
ngx_close_file(fd);
rc = ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data);
if (rc != NGX_OK) {
if (ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data)
== NGX_FILE_ERROR)
{
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: rename failed: '%V'->'%V'",
&ctx->playlist_bak, &ctx->playlist);
@ -842,7 +773,6 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts,
{
ngx_rtmp_hls_ctx_t *ctx;
ngx_rtmp_hls_frag_t *f;
ngx_uint_t nretry;
uint64_t id;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
@ -865,22 +795,10 @@ ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts,
ngx_str_set(&ctx->file.name, "hls");
nretry = 0;
retry:
ctx->file.fd = ngx_open_file(ctx->stream.data, NGX_FILE_WRONLY,
NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS);
if (ctx->file.fd == NGX_INVALID_FILE) {
if (ngx_errno == NGX_ENOENT && nretry == 0 &&
ngx_rtmp_hls_create_parent_dir(s) == NGX_OK)
{
nretry++;
goto retry;
}
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: error creating fragment file");
return NGX_ERROR;
@ -1057,6 +975,103 @@ done:
}
static ngx_int_t
ngx_rtmp_hls_ensure_directory(ngx_rtmp_session_t *s)
{
size_t len;
ngx_file_info_t fi;
ngx_rtmp_hls_ctx_t *ctx;
ngx_rtmp_hls_app_conf_t *hacf;
static u_char path[NGX_MAX_PATH + 1];
hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module);
*ngx_snprintf(path, sizeof(path) - 1, "%V", &hacf->path) = 0;
if (ngx_file_info(path, &fi) == NGX_FILE_ERROR) {
if (ngx_errno != NGX_ENOENT) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: " ngx_file_info_n " failed on '%V'",
&hacf->path);
return NGX_ERROR;
}
/* ENOENT */
if (ngx_create_dir(path, NGX_RTMP_HLS_DIR_ACCESS) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: " ngx_create_dir_n " failed on '%V'",
&hacf->path);
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: directory '%V' created", &hacf->path);
} else {
if (!ngx_is_dir(&fi)) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"hls: '%V' exists and is not a directory",
&hacf->path);
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: directory '%V' exists", &hacf->path);
}
if (!hacf->nested) {
return NGX_OK;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
len = hacf->path.len;
if (hacf->path.data[len - 1] == '/') {
len--;
}
*ngx_snprintf(path, sizeof(path) - 1, "%*s/%V", len, hacf->path.data,
&ctx->name) = 0;
if (ngx_file_info(path, &fi) != NGX_FILE_ERROR) {
if (ngx_is_dir(&fi)) {
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: directory '%s' exists", path);
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"hls: '%s' exists and is not a directory", path);
return NGX_ERROR;
}
if (ngx_errno != NGX_ENOENT) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: " ngx_file_info_n " failed on '%s'", path);
return NGX_ERROR;
}
/* NGX_ENOENT */
if (ngx_create_dir(path, NGX_RTMP_HLS_DIR_ACCESS) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
"hls: " ngx_create_dir_n " failed on '%s'", path);
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"hls: directory '%s' created", path);
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
{
@ -1142,9 +1157,11 @@ ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
p = ngx_cpymem(p, ctx->name.data, ctx->name.len);
/* ctx->stream_path holds initial part of stream file path
/*
* ctx->stream holds initial part of stream file path
* however the space for the whole stream path
* is allocated */
* is allocated
*/
ctx->stream.len = p - ctx->playlist.data + 1;
ctx->stream.data = ngx_palloc(s->connection->pool,
@ -1228,6 +1245,10 @@ ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
ngx_rtmp_hls_restore_stream(s);
}
if (ngx_rtmp_hls_ensure_directory(s) != NGX_OK) {
return NGX_ERROR;
}
next:
return next_publish(s, v);
}
@ -1920,7 +1941,7 @@ ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, err,
"hls: cleanup " ngx_read_dir_n
" \"%V\" failed", ppath);
" '%V' failed", ppath);
return NGX_ERROR;
}
@ -1939,7 +1960,7 @@ ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
nentries++;
if (ngx_de_info(path, &dir) == NGX_FILE_ERROR) {
if (!dir.valid_info && ngx_de_info(path, &dir) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
"hls: cleanup " ngx_de_info_n " \"%V\" failed",
&spath);
@ -1953,9 +1974,17 @@ ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
"hls: cleanup dir '%V'", &name);
if (ngx_delete_dir(spath.data) != NGX_OK) {
/*
* null-termination gets spoiled in win32
* version of ngx_open_dir
*/
*p = 0;
if (ngx_delete_dir(path) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
"hls: cleanup dir error '%V'", &spath);
"hls: cleanup " ngx_delete_dir_n
" failed on '%V'", &spath);
} else {
nerased++;
}
@ -1997,9 +2026,10 @@ ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
"hls: cleanup '%V' mtime=%T age=%T",
&name, mtime, ngx_cached_time->sec - mtime);
if (ngx_delete_file(spath.data) != NGX_OK) {
if (ngx_delete_file(path) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
"hls: cleanup error '%V'", &spath);
"hls: cleanup " ngx_delete_file_n " failed on '%V'",
&spath);
continue;
}