Skip to content

Commit

Permalink
support alternative audio renditions
Browse files Browse the repository at this point in the history
also:
- support single adaptive bitrate mp4 file across all protocols (was only
  HLS before)
- mp4 parser - multiple stsd entries bug fix
- fix compilation on 32 bit
- readme comment about segment duration and gop size
  • Loading branch information
erankor committed May 2, 2016
1 parent c85d083 commit ff38d96
Show file tree
Hide file tree
Showing 34 changed files with 2,544 additions and 850 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@

* Audio only/video only files

* Alternative audio renditions - supporting both:
1. Generation of manifest with different audio renditions, allowing selection on the client side
2. Muxing together audio and video streams from separate files / tracks - provides the ability
to serve different audio renditions of a single video, without the need for any special support
on the client side.

* Track selection for multi audio/video MP4 files

* Playback rate change - 0.5x up to 2x (requires libavcodec and libavfilter)
Expand All @@ -41,8 +47,6 @@ without the overhead of short segments for the whole duration of the video

* MSS: PlayReady encryption support

* HLS: Mux audio and video streams from separate MP4 files (HLS/HDS)

* HLS: Generation of I-frames playlist (EXT-X-I-FRAMES-ONLY)

* HLS: support for AES-128 / SAMPLE-AES encryption
Expand Down Expand Up @@ -159,7 +163,7 @@ The following parameters are supported on the URL path:
#### Filename structure

The structure of filename is:
`<basename>[<fileparams>][<trackparams>].<extension>`
`<basename>[<fileparams>][<trackparams>][<langparams>].<extension>`

Where:
* basename + extension - the set of options is packager specific (the list below applies to the default settings):
Expand All @@ -174,6 +178,8 @@ Where:
For example, manifest-a1.f4m will return an F4M containing only the first audio stream.
The default is to include the first audio and first video tracks of each file.
The tracks selected on the file name are AND-ed with the tracks selected with the /tracks/ path parameter.
* langparams - can be used to filter audio tracks according to their language.
For example, master-leng.m3u8 will return only english audio tracks.

### Mapping response format

Expand Down Expand Up @@ -409,6 +415,11 @@ Mandatory fields:

Optional fields:
* `id` - a string that identifies the sequence. The id can be retrieved by `$vod_sequence_id`.
* `language` - a 3-letter (ISO-639-2) language code, this field takes priority over any language
specified on the media file (MP4 mdhd atom)
* `label` - a friendly string that identifies the sequence. if a language is specified,
a default label will be automatically derived by it - e.g. if language is `ita`,
by default `italiano` will be used as the label.

#### Clip (abstract)

Expand Down Expand Up @@ -694,7 +705,10 @@ http://host/hls/common-prefix,bitrate1,bitrate2,common-suffix.urlset/master.m3u8
* **default**: `10s`
* **context**: `http`, `server`, `location`

Sets the segment duration in milliseconds.
Sets the segment duration in milliseconds. It is highly recommended to use a segment duration that is a multiple of the GOP duration.
If the segment duration is not a multiple of GOP duration, and `vod_align_segments_to_key_frames` is enabled, there could be significant
differences between the segment duration that is reported in the manifest and the actual segment duration. This could also lead to
the appearance of empty segments within the stream.

#### vod_live_segment_count
* **syntax**: `vod_live_segment_count count`
Expand Down
3 changes: 3 additions & 0 deletions config
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
$ngx_addon_dir/vod/input/frames_source_memory.h \
$ngx_addon_dir/vod/input/read_cache.h \
$ngx_addon_dir/vod/json_parser.h \
$ngx_addon_dir/vod/language_code.h \
$ngx_addon_dir/vod/languages_x.h \
$ngx_addon_dir/vod/list_entry.h \
$ngx_addon_dir/vod/manifest_utils.h \
$ngx_addon_dir/vod/media_clip.h \
Expand Down Expand Up @@ -213,6 +215,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
$ngx_addon_dir/vod/input/frames_source_memory.c \
$ngx_addon_dir/vod/input/read_cache.c \
$ngx_addon_dir/vod/json_parser.c \
$ngx_addon_dir/vod/language_code.c \
$ngx_addon_dir/vod/manifest_utils.c \
$ngx_addon_dir/vod/media_format.c \
$ngx_addon_dir/vod/media_set_parser.c \
Expand Down
4 changes: 2 additions & 2 deletions ngx_buffer_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ ngx_buffer_cache_free_oldest_entry(ngx_buffer_cache_sh_t *cache, uint32_t expira
}

// make sure the entry is expired, if that is the requirement
if (expiration && ngx_time() < entry->write_time + expiration)
if (expiration && ngx_time() < (time_t)(entry->write_time + expiration))
{
return NULL;
}
Expand Down Expand Up @@ -339,7 +339,7 @@ ngx_buffer_cache_fetch(
{
entry = ngx_buffer_cache_rbtree_lookup(&sh->rbtree, key, hash);
if (entry != NULL && entry->state == CES_READY &&
(cache->expiration == 0 || ngx_time() < entry->write_time + cache->expiration))
(cache->expiration == 0 || ngx_time() < (time_t)(entry->write_time + cache->expiration)))
{
result = 1;

Expand Down
14 changes: 7 additions & 7 deletions ngx_http_vod_dash.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,47 +442,47 @@ ngx_http_vod_dash_parse_uri_file_name(
const ngx_http_vod_request_t** request)
{
ngx_int_t rc;
bool_t expect_segment_index;
uint32_t flags;

// fragment
if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.fragment_file_name_prefix, fragment_file_ext))
{
start_pos += conf->dash.mpd_config.fragment_file_name_prefix.len;
end_pos -= (sizeof(fragment_file_ext) - 1);
*request = conf->drm_enabled ? &edash_mp4_fragment_request : &dash_mp4_fragment_request;
expect_segment_index = TRUE;
flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX;
}
// init segment
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.init_file_name_prefix, init_segment_file_ext))
{
start_pos += conf->dash.mpd_config.init_file_name_prefix.len;
end_pos -= (sizeof(init_segment_file_ext) - 1);
*request = &dash_mp4_init_request;
expect_segment_index = FALSE;
flags = 0;
}
// webm fragment
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.fragment_file_name_prefix, webm_file_ext))
{
start_pos += conf->dash.mpd_config.fragment_file_name_prefix.len;
end_pos -= (sizeof(webm_file_ext) - 1);
*request = &dash_webm_fragment_request;
expect_segment_index = TRUE;
flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX;
}
// webm init segment
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.init_file_name_prefix, webm_file_ext))
{
start_pos += conf->dash.mpd_config.init_file_name_prefix.len;
end_pos -= (sizeof(webm_file_ext) - 1);
*request = &dash_webm_init_request;
expect_segment_index = FALSE;
flags = 0;
}
// manifest
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.manifest_file_name_prefix, manifest_file_ext))
{
start_pos += conf->dash.manifest_file_name_prefix.len;
end_pos -= (sizeof(manifest_file_ext) - 1);
*request = &dash_manifest_request;
expect_segment_index = FALSE;
flags = PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE;
}
else
{
Expand All @@ -492,7 +492,7 @@ ngx_http_vod_dash_parse_uri_file_name(
}

// parse the required tracks string
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, expect_segment_index, request_params);
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, flags, request_params);
if (rc != NGX_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Expand Down
6 changes: 4 additions & 2 deletions ngx_http_vod_hds.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ ngx_http_vod_hds_init_frame_processor(
&submodule_context->conf->hds.fragment_config,
&encryption_params,
submodule_context->request_params.segment_index,
submodule_context->media_set.sequences,
&submodule_context->media_set,
segment_writer->write_tail,
segment_writer->context,
ngx_http_vod_submodule_size_only(submodule_context),
Expand Down Expand Up @@ -195,6 +195,7 @@ ngx_http_vod_hds_parse_uri_file_name(
request_params_t* request_params,
const ngx_http_vod_request_t** request)
{
uint32_t flags = 0;
ngx_int_t rc;

// fragment request
Expand Down Expand Up @@ -239,6 +240,7 @@ ngx_http_vod_hds_parse_uri_file_name(
start_pos += conf->hds.manifest_file_name_prefix.len;
end_pos -= (sizeof(manifest_file_ext) - 1);
*request = &hds_manifest_request;
flags = PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE;
}
else
{
Expand All @@ -248,7 +250,7 @@ ngx_http_vod_hds_parse_uri_file_name(
}

// parse the required tracks string
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, FALSE, request_params);
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, flags, request_params);
if (rc != NGX_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Expand Down
13 changes: 7 additions & 6 deletions ngx_http_vod_hls.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ ngx_http_vod_hls_parse_uri_file_name(
request_params_t* request_params,
const ngx_http_vod_request_t** request)
{
bool_t expect_segment_index;
uint32_t flags;
ngx_int_t rc;

// segment
Expand All @@ -437,7 +437,7 @@ ngx_http_vod_hls_parse_uri_file_name(
start_pos += conf->hls.m3u8_config.segment_file_name_prefix.len;
end_pos -= (sizeof(ts_file_ext) - 1);
*request = &hls_segment_request;
expect_segment_index = TRUE;
flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX;
}
// manifest
else if (ngx_http_vod_ends_with_static(start_pos, end_pos, m3u8_file_ext))
Expand All @@ -449,25 +449,26 @@ ngx_http_vod_hls_parse_uri_file_name(
{
*request = &hls_index_request;
start_pos += conf->hls.m3u8_config.index_file_name_prefix.len;
flags = 0;
}
else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.iframes_file_name_prefix))
{
*request = &hls_iframes_request;
start_pos += conf->hls.iframes_file_name_prefix.len;
flags = 0;
}
else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.master_file_name_prefix))
{
*request = &hls_master_request;
start_pos += conf->hls.master_file_name_prefix.len;
flags = PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE;
}
else
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_vod_hls_parse_uri_file_name: unidentified m3u8 request");
return NGX_HTTP_BAD_REQUEST;
}

expect_segment_index = FALSE;
}
// encryption key
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.encryption_key_file_name, key_file_ext) &&
Expand All @@ -476,7 +477,7 @@ ngx_http_vod_hls_parse_uri_file_name(
start_pos += conf->hls.m3u8_config.encryption_key_file_name.len;
end_pos -= (sizeof(key_file_ext) - 1);
*request = &hls_enc_key_request;
expect_segment_index = FALSE;
flags = 0;
}
else
{
Expand All @@ -486,7 +487,7 @@ ngx_http_vod_hls_parse_uri_file_name(
}

// parse the required tracks string
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, expect_segment_index, request_params);
rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, flags, request_params);
if (rc != NGX_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Expand Down
Loading

0 comments on commit ff38d96

Please sign in to comment.