diff --git a/README.md b/README.md index aa982906..ddf2fda7 100644 --- a/README.md +++ b/README.md @@ -571,6 +571,7 @@ Mandatory fields: an empty captions file (useful in case only some videos in a playlist have captions) Optional fields: +* `id` - a string that identifies the source clip (maximum 32 bytes) * `sourceType` - sets the interface that should be used to read the MP4 file, allowed values are: `file` and `http`. By default, the module uses `http` if `vod_remote_upstream_location` is set, and `file` otherwise. diff --git a/vod/hls/hls_muxer.c b/vod/hls/hls_muxer.c index 26630ddc..4cb271f0 100644 --- a/vod/hls/hls_muxer.c +++ b/vod/hls/hls_muxer.c @@ -11,8 +11,10 @@ #define ID3_TEXT_JSON_FORMAT "{\"timestamp\":%uL}%Z" #define ID3_TEXT_JSON_SEQUENCE_ID_PREFIX_FORMAT "{\"timestamp\":%uL,\"sequenceId\":\"" +#define ID3_TEXT_JSON_CLIP_ID_FORMAT "\",\"clipId\":\"" #define ID3_TEXT_JSON_SEQUENCE_ID_SUFFIX "\"}" + // from ffmpeg mpegtsenc #define DEFAULT_PES_HEADER_FREQ 16 #define DEFAULT_PES_PAYLOAD_SIZE ((DEFAULT_PES_HEADER_FREQ - 1) * 184 + 170) @@ -171,6 +173,7 @@ hls_muxer_init_id3_stream( size_t data_size; int64_t timestamp; void* frames_source_context; + vod_str_t clip_id; cur_stream = state->last_stream; @@ -196,8 +199,9 @@ hls_muxer_init_id3_stream( if (sequence_id->len != 0) { sequence_id_escape = vod_escape_json(NULL, sequence_id->data, sequence_id->len); - data_size = sizeof(ID3_TEXT_JSON_SEQUENCE_ID_PREFIX_FORMAT) + VOD_INT64_LEN + + data_size = sizeof(ID3_TEXT_JSON_SEQUENCE_ID_PREFIX_FORMAT) + VOD_INT64_LEN + sequence_id->len + sequence_id_escape + + sizeof(ID3_TEXT_JSON_CLIP_ID_FORMAT) + CLIP_ID_MAX_SIZE + sizeof(ID3_TEXT_JSON_SEQUENCE_ID_SUFFIX); } else @@ -268,6 +272,14 @@ hls_muxer_init_id3_stream( { p = vod_copy(p, sequence_id->data, sequence_id->len); } + + clip_id = ref_track->file_info.source->id; + if (clip_id.len != 0) + { + p = vod_copy(p, ID3_TEXT_JSON_CLIP_ID_FORMAT, sizeof(ID3_TEXT_JSON_CLIP_ID_FORMAT) - 1); + p = vod_copy(p, clip_id.data, clip_id.len); + } + p = vod_copy(p, ID3_TEXT_JSON_SEQUENCE_ID_SUFFIX, sizeof(ID3_TEXT_JSON_SEQUENCE_ID_SUFFIX)); } diff --git a/vod/media_clip.h b/vod/media_clip.h index 6fe34886..c8ab87e2 100644 --- a/vod/media_clip.h +++ b/vod/media_clip.h @@ -65,6 +65,7 @@ typedef struct ngx_http_vod_reader_s ngx_http_vod_reader_t; struct media_clip_source_s { // base media_clip_t base; + vod_str_t id; int64_t clip_time; media_range_t* range; media_track_array_t track_array; diff --git a/vod/media_set.h b/vod/media_set.h index dff42ee7..a791c832 100644 --- a/vod/media_set.h +++ b/vod/media_set.h @@ -18,6 +18,7 @@ #define MAX_CLOSED_CAPTIONS (67) #define MAX_CLIPS (128) #define MAX_CLIPS_PER_REQUEST (16) +#define CLIP_ID_MAX_SIZE (32) #define MAX_SEQUENCES (32) #define MAX_SEQUENCE_IDS (4) #define MAX_SEQUENCE_TRACKS_MASKS (2) diff --git a/vod/media_set_parser.c b/vod/media_set_parser.c index a1a0e7ff..ba25ae23 100644 --- a/vod/media_set_parser.c +++ b/vod/media_set_parser.c @@ -105,6 +105,7 @@ static vod_status_t media_set_parse_source(void* ctx, vod_json_object_t* element static vod_status_t media_set_parse_clips_array(void* ctx, vod_json_value_t* value, void* dest); static vod_status_t media_set_parse_bitrate(void* ctx, vod_json_value_t* value, void* dest); static vod_status_t media_set_parse_source_type(void* ctx, vod_json_value_t* value, void* dest); +static vod_status_t media_set_parse_source_clip_id(void* ctx, vod_json_value_t* value, void* dest); // constants static json_parser_union_type_def_t media_clip_union_params[] = { @@ -119,6 +120,7 @@ static json_parser_union_type_def_t media_clip_union_params[] = { }; static json_object_value_def_t media_clip_source_params[] = { + { vod_string("id"), VOD_JSON_STRING, offsetof(media_clip_source_t, id), media_set_parse_source_clip_id }, { vod_string("path"), VOD_JSON_STRING, offsetof(media_clip_source_t, mapped_uri), media_set_parse_null_term_string }, { vod_string("tracks"), VOD_JSON_STRING, offsetof(media_clip_source_t, tracks_mask), media_set_parse_tracks_spec }, { vod_string("clipFrom"), VOD_JSON_INT, offsetof(media_clip_source_t, clip_from), media_set_parse_int64 }, @@ -320,6 +322,29 @@ media_set_parse_int64( return VOD_OK; } +static vod_status_t +media_set_parse_source_clip_id( + void* ctx, + vod_json_value_t* value, + void* dest) +{ + media_filter_parse_context_t* context = ctx; + vod_status_t rc; + if (value->v.str.len > CLIP_ID_MAX_SIZE) + { + vod_log_error(VOD_LOG_ERR, context->request_context->log, 0, + "media_set_parse_source_clip_id: invalid size of id: %uz", value->v.str.len); + return VOD_BAD_MAPPING; + } + + rc = media_set_parse_null_term_string(context, value, dest); + if (rc != VOD_OK) + { + return rc; + } + return VOD_OK; +} + static vod_status_t media_set_parse_source_type( void* ctx,