Skip to content

Commit

Permalink
Merge pull request #1119 from kaltura/dash-smpte-subtitles
Browse files Browse the repository at this point in the history
dash: support smpte-tt subtitle output
  • Loading branch information
erankor authored Apr 14, 2020
2 parents 92eb457 + 62e8fd8 commit c907037
Show file tree
Hide file tree
Showing 14 changed files with 439 additions and 68 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,15 @@ Sets the MPD format, available options are:
* `segmenttemplate` - uses SegmentTemplate, reporting a single duration for all fragments
* `segmenttimeline` - uses SegmentTemplate and SegmentTimeline to explicitly set the duration of the fragments

#### vod_dash_subtitle_format
* **syntax**: `vod_dash_subtitle_format format`
* **default**: `webvtt`
* **context**: `http`, `server`, `location`

Sets the format of the subtitles returned in the MPD, available options are:
* `webvtt` - WebVTT
* `smpte-tt` - SMPTE Timed Text

#### vod_dash_init_mp4_pssh
* **syntax**: `vod_dash_init_mp4_pssh on/off`
* **default**: `on`
Expand Down
68 changes: 66 additions & 2 deletions ngx_http_vod_dash.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "vod/mp4/mp4_fragment.h"
#include "vod/mp4/mp4_init_segment.h"
#include "vod/subtitle/webvtt_builder.h"
#include "vod/subtitle/ttml_builder.h"
#include "vod/udrm.h"

#if (NGX_HAVE_OPENSSL_EVP)
Expand All @@ -25,6 +26,12 @@ ngx_conf_enum_t dash_manifest_formats[] = {
{ ngx_null_string, 0 }
};

ngx_conf_enum_t dash_subtitle_formats[] = {
{ ngx_string("webvtt"), SUBTITLE_FORMAT_WEBVTT },
{ ngx_string("smpte-tt"), SUBTITLE_FORMAT_SMPTE_TT },
{ ngx_null_string, 0 }
};

// content types
static u_char mpd_content_type[] = "application/dash+xml";
static u_char webm_audio_content_type[] = "audio/webm";
Expand All @@ -37,6 +44,7 @@ static const u_char init_segment_file_ext[] = ".mp4";
static const u_char fragment_file_ext[] = ".m4s";
static const u_char webm_file_ext[] = ".webm";
static const u_char vtt_file_ext[] = ".vtt";
static const u_char ttml_file_ext[] = ".ttml";

static ngx_int_t
ngx_http_vod_dash_handle_manifest(
Expand Down Expand Up @@ -386,7 +394,7 @@ ngx_http_vod_dash_handle_vtt_file(
ngx_str_t* content_type)
{
vod_status_t rc;

rc = webvtt_builder_build(
&submodule_context->request_context,
&submodule_context->media_set,
Expand All @@ -404,6 +412,42 @@ ngx_http_vod_dash_handle_vtt_file(
return NGX_OK;
}

static ngx_int_t
ngx_http_vod_dash_handle_ttml_fragment(
ngx_http_vod_submodule_context_t* submodule_context,
ngx_str_t* response,
ngx_str_t* content_type)
{
dash_fragment_header_extensions_t header_extensions;
vod_status_t rc;
size_t ignore;

ngx_memzero(&header_extensions, sizeof(header_extensions));

header_extensions.mdat_atom_max_size = ttml_builder_get_max_size(&submodule_context->media_set);
header_extensions.write_mdat_atom_callback = (dash_write_mdat_atom_callback_t)ttml_builder_write;
header_extensions.write_mdat_atom_context = &submodule_context->media_set;

rc = dash_packager_build_fragment_header(
&submodule_context->request_context,
&submodule_context->media_set,
submodule_context->request_params.segment_index,
0,
&header_extensions,
FALSE,
response,
&ignore);
if (rc != VOD_OK)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
"ngx_http_vod_dash_handle_ttml_fragment: dash_packager_build_fragment_header failed %i", rc);
return ngx_http_vod_status_to_ngx_error(submodule_context->r, rc);
}

mp4_fragment_get_content_type(TRUE, content_type);
return NGX_OK;
}

static const ngx_http_vod_request_t dash_manifest_request = {
REQUEST_FLAG_TIME_DEPENDENT_ON_LIVE,
PARSE_FLAG_DURATION_LIMITS_AND_TOTAL_SIZE | PARSE_FLAG_INITIAL_PTS_DELAY | PARSE_FLAG_CODEC_NAME,
Expand All @@ -418,7 +462,7 @@ static const ngx_http_vod_request_t dash_mp4_init_request = {
REQUEST_FLAG_SINGLE_TRACK,
PARSE_BASIC_METADATA_ONLY | PARSE_FLAG_SAVE_RAW_ATOMS,
REQUEST_CLASS_OTHER,
SUPPORTED_CODECS_MP4,
SUPPORTED_CODECS_MP4 | VOD_CODEC_FLAG(WEBVTT),
DASH_TIMESCALE,
ngx_http_vod_dash_mp4_handle_init_segment,
NULL,
Expand Down Expand Up @@ -474,6 +518,16 @@ static const ngx_http_vod_request_t dash_webvtt_file_request = {
NULL,
};

static const ngx_http_vod_request_t dash_ttml_request = {
REQUEST_FLAG_SINGLE_TRACK,
PARSE_FLAG_FRAMES_ALL | PARSE_FLAG_EXTRA_DATA,
REQUEST_CLASS_SEGMENT,
VOD_CODEC_FLAG(WEBVTT),
TTML_TIMESCALE,
ngx_http_vod_dash_handle_ttml_fragment,
NULL,
};

static void
ngx_http_vod_dash_create_loc_conf(
ngx_conf_t *cf,
Expand All @@ -482,6 +536,7 @@ ngx_http_vod_dash_create_loc_conf(
conf->absolute_manifest_urls = NGX_CONF_UNSET;
conf->init_mp4_pssh = NGX_CONF_UNSET;
conf->mpd_config.manifest_format = NGX_CONF_UNSET_UINT;
conf->mpd_config.subtitle_format = NGX_CONF_UNSET_UINT;
conf->mpd_config.duplicate_bitrate_threshold = NGX_CONF_UNSET_UINT;
conf->mpd_config.write_playready_kid = NGX_CONF_UNSET;
conf->mpd_config.use_base_url_tag = NGX_CONF_UNSET;
Expand All @@ -503,6 +558,7 @@ ngx_http_vod_dash_merge_loc_conf(
ngx_conf_merge_str_value(conf->mpd_config.fragment_file_name_prefix, prev->mpd_config.fragment_file_name_prefix, "fragment");
ngx_conf_merge_str_value(conf->mpd_config.subtitle_file_name_prefix, prev->mpd_config.subtitle_file_name_prefix, "sub");
ngx_conf_merge_uint_value(conf->mpd_config.manifest_format, prev->mpd_config.manifest_format, FORMAT_SEGMENT_TIMELINE);
ngx_conf_merge_uint_value(conf->mpd_config.subtitle_format, prev->mpd_config.subtitle_format, SUBTITLE_FORMAT_WEBVTT);
ngx_conf_merge_uint_value(conf->mpd_config.duplicate_bitrate_threshold, prev->mpd_config.duplicate_bitrate_threshold, 4096);
ngx_conf_merge_value(conf->mpd_config.write_playready_kid, prev->mpd_config.write_playready_kid, 0);
ngx_conf_merge_value(conf->mpd_config.use_base_url_tag, prev->mpd_config.use_base_url_tag, 0);
Expand Down Expand Up @@ -568,6 +624,14 @@ ngx_http_vod_dash_parse_uri_file_name(
*request = &dash_manifest_request;
flags = PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE;
}
// smpte fragment
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.fragment_file_name_prefix, ttml_file_ext))
{
start_pos += conf->dash.mpd_config.fragment_file_name_prefix.len;
end_pos -= (sizeof(ttml_file_ext) - 1);
*request = &dash_ttml_request;
flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX;
}
// webvtt file
else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->dash.mpd_config.subtitle_file_name_prefix, vtt_file_ext))
{
Expand Down
7 changes: 7 additions & 0 deletions ngx_http_vod_dash_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@
BASE_OFFSET + offsetof(ngx_http_vod_dash_loc_conf_t, mpd_config.manifest_format),
dash_manifest_formats },

{ ngx_string("vod_dash_subtitle_format"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
BASE_OFFSET + offsetof(ngx_http_vod_dash_loc_conf_t, mpd_config.subtitle_format),
dash_subtitle_formats },

{ ngx_string("vod_dash_duplicate_bitrate_threshold"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
Expand Down
2 changes: 2 additions & 0 deletions ngx_http_vod_dash_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ typedef struct
// globals
extern ngx_conf_enum_t dash_manifest_formats[];

extern ngx_conf_enum_t dash_subtitle_formats[];

#endif // _NGX_HTTP_VOD_DASH_CONF_H_INCLUDED_
1 change: 1 addition & 0 deletions ngx_http_vod_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,7 @@ ngx_http_vod_init_parse_params_frames(
ctx->submodule_context.media_set.segment_duration =
clip_ranges.clip_ranges->end - clip_ranges.clip_ranges->start;
}
ctx->submodule_context.media_set.segment_start_time = clip_ranges.clip_ranges->start;

parse_params->range = clip_ranges.clip_ranges;
parse_params->range->start = (parse_params->range->start * rate.num) / rate.denom;
Expand Down
Loading

0 comments on commit c907037

Please sign in to comment.