static vod_status_t manifest_utils_build_request_params_string_per_sequence_tracks( request_context_t* request_context, uint32_t segment_index, uint32_t sequences_mask, uint32_t* sequence_tracks_mask, vod_str_t* result) { u_char* p; size_t result_size; uint32_t* tracks_mask; uint32_t i; result_size = 0; // segment index if (segment_index != INVALID_SEGMENT_INDEX) { result_size += 1 + vod_get_int_print_len(segment_index + 1); } for (i = 0, tracks_mask = sequence_tracks_mask; i < MAX_SEQUENCES; i++, tracks_mask += MEDIA_TYPE_COUNT) { if ((sequences_mask & (1 << i)) == 0) { continue; } // sequence result_size += sizeof("-f32") - 1; // video tracks if (tracks_mask[MEDIA_TYPE_VIDEO] == 0xffffffff) { result_size += sizeof("-v0") - 1; } else { result_size += vod_get_number_of_set_bits(tracks_mask[MEDIA_TYPE_VIDEO]) * (sizeof("-v32") - 1); } // audio tracks if (tracks_mask[MEDIA_TYPE_AUDIO] == 0xffffffff) { result_size += sizeof("-a0") - 1; } else { result_size += vod_get_number_of_set_bits(tracks_mask[MEDIA_TYPE_AUDIO]) * (sizeof("-a32") - 1); } } p = vod_alloc(request_context->pool, result_size + 1); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "manifest_utils_build_request_params_string_per_sequence_tracks: vod_alloc failed"); return VOD_ALLOC_FAILED; } result->data = p; // segment index if (segment_index != INVALID_SEGMENT_INDEX) { p = vod_sprintf(p, "-%uD", segment_index + 1); } for (i = 0, tracks_mask = sequence_tracks_mask; i < MAX_SEQUENCES; i++, tracks_mask += MEDIA_TYPE_COUNT) { if ((sequences_mask & (1 << i)) == 0) { continue; } // sequence p = vod_sprintf(p, "-f%uD", i + 1); // video tracks switch (tracks_mask[MEDIA_TYPE_VIDEO]) { case 0xffffffff: p = vod_copy(p, "-v0", sizeof("-v0") - 1); break; case 0: break; default: p = manifest_utils_write_bitmask(p, tracks_mask[MEDIA_TYPE_VIDEO], 'v'); break; } // audio tracks switch (tracks_mask[MEDIA_TYPE_AUDIO]) { case 0xffffffff: p = vod_copy(p, "-a0", sizeof("-a0") - 1); break; case 0: break; default: p = manifest_utils_write_bitmask(p, tracks_mask[MEDIA_TYPE_AUDIO], 'a'); break; } } result->len = p - result->data; if (result->len > result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "manifest_utils_build_request_params_string_per_sequence_tracks: result length %uz exceeded allocated length %uz", result->len, result_size); return VOD_UNEXPECTED; } return VOD_OK; }
vod_status_t manifest_utils_build_request_params_string( request_context_t* request_context, uint32_t* has_tracks, uint32_t segment_index, uint32_t sequences_mask, uint32_t* sequence_tracks_mask, uint32_t* tracks_mask, vod_str_t* suffix, vod_str_t* args_str, vod_str_t* result) { u_char* p; size_t result_size; bool_t newline_shift = FALSE; if (sequence_tracks_mask != NULL) { return manifest_utils_build_request_params_string_per_sequence_tracks( request_context, segment_index, sequences_mask, sequence_tracks_mask, result); } result_size = suffix->len + args_str->len; if (suffix->data[suffix->len - 1] == '\n') { newline_shift = TRUE; } // segment index if (segment_index != INVALID_SEGMENT_INDEX) { result_size += 1 + vod_get_int_print_len(segment_index + 1); } // sequence mask if (sequences_mask != 0xffffffff) { result_size += vod_get_number_of_set_bits(sequences_mask) * (sizeof("-f32") - 1); } // video tracks if (tracks_mask[MEDIA_TYPE_VIDEO] == 0xffffffff) { result_size += sizeof("-v0") - 1; } else { result_size += vod_get_number_of_set_bits(tracks_mask[MEDIA_TYPE_VIDEO]) * (sizeof("-v32") - 1); } // audio tracks if (tracks_mask[MEDIA_TYPE_AUDIO] == 0xffffffff) { result_size += sizeof("-a0") - 1; } else { result_size += vod_get_number_of_set_bits(tracks_mask[MEDIA_TYPE_AUDIO]) * (sizeof("-a32") - 1); } p = vod_alloc(request_context->pool, result_size + 1); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "manifest_utils_build_request_params_string: vod_alloc failed"); return VOD_ALLOC_FAILED; } result->data = p; // segment index if (segment_index != INVALID_SEGMENT_INDEX) { p = vod_sprintf(p, "-%uD", segment_index + 1); } // sequence mask if (sequences_mask != 0xffffffff) { p = manifest_utils_write_bitmask(p, sequences_mask, 'f'); } // video tracks if (has_tracks[MEDIA_TYPE_VIDEO]) { if (tracks_mask[MEDIA_TYPE_VIDEO] == 0xffffffff) { p = vod_copy(p, "-v0", sizeof("-v0") - 1); } else { p = manifest_utils_write_bitmask(p, tracks_mask[MEDIA_TYPE_VIDEO], 'v'); } } // audio tracks if (has_tracks[MEDIA_TYPE_AUDIO]) { if (tracks_mask[MEDIA_TYPE_AUDIO] == 0xffffffff) { p = vod_copy(p, "-a0", sizeof("-a0") - 1); } else { p = manifest_utils_write_bitmask(p, tracks_mask[MEDIA_TYPE_AUDIO], 'a'); } } p = vod_copy(p, suffix->data, newline_shift ? suffix->len - 1 : suffix->len); p = vod_copy(p, args_str->data, args_str->len); if (newline_shift) { *p++ = '\n'; } result->len = p - result->data; if (result->len > result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "manifest_utils_build_request_params_string: result length %uz exceeded allocated length %uz", result->len, result_size); return VOD_UNEXPECTED; } return VOD_OK; }
ngx_int_t ngx_http_vod_parse_uri_path( ngx_http_request_t* r, ngx_str_t* multi_uri_suffix, ngx_hash_t* params_hash, ngx_str_t* uri, request_params_t* request_params, media_set_t* media_set) { media_sequence_t* cur_sequence; media_clip_source_t** cur_source_ptr; media_clip_source_t* cur_source; ngx_http_vod_multi_uri_t multi_uri; media_clip_t** cur_clip_ptr; media_clip_t* cur_clip; ngx_str_t parts[3]; ngx_str_t cur_uri; ngx_int_t rc; uint32_t sequences_mask; uint32_t parts_mask; uint32_t clip_id = 1; uint32_t i; int uri_count; rc = ngx_http_vod_parse_multi_uri(r, uri, multi_uri_suffix, &multi_uri); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_parse_multi_uri failed", rc); return rc; } if (multi_uri.parts_count > 1) { sequences_mask = request_params->sequences_mask; request_params->sequences_mask = 0xffffffff; // reset the sequences mask so that it won't be applied again on the mapping request } else { sequences_mask = 0xffffffff; } parts_mask = (1 << multi_uri.parts_count) - 1; uri_count = vod_get_number_of_set_bits(sequences_mask & parts_mask); if (uri_count == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: request has no uris"); return NGX_HTTP_BAD_REQUEST; } cur_sequence = ngx_palloc(r->pool, (sizeof(*cur_sequence) + sizeof(*cur_source_ptr) + sizeof(*cur_source) + sizeof(*cur_clip_ptr)) * uri_count); if (cur_sequence == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_palloc failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } media_set->sequences = cur_sequence; cur_source_ptr = (void*)(cur_sequence + uri_count); media_set->sources = cur_source_ptr; cur_source = (void*)(cur_source_ptr + uri_count); cur_clip_ptr = (void*)(cur_source + uri_count); parts[0] = multi_uri.prefix; parts[2] = multi_uri.postfix; for (i = 0; i < multi_uri.parts_count; i++) { if ((sequences_mask & (1 << i)) == 0) { continue; } parts[1] = multi_uri.middle_parts[i]; rc = ngx_http_vod_merge_string_parts(r, parts, 3, &cur_uri); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_merge_string_parts failed", rc); return rc; } rc = ngx_http_vod_extract_uri_params(r, params_hash, &cur_uri, cur_sequence, &clip_id, cur_source, &cur_clip); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_extract_uri_params failed", rc); return rc; } if ((cur_source->tracks_mask[MEDIA_TYPE_AUDIO] & request_params->tracks_mask[MEDIA_TYPE_AUDIO]) == 0 && (cur_source->tracks_mask[MEDIA_TYPE_VIDEO] & request_params->tracks_mask[MEDIA_TYPE_VIDEO]) == 0) { continue; } *cur_clip_ptr = cur_clip; *cur_source_ptr = cur_source; cur_sequence->clips = cur_clip_ptr; cur_sequence->index = i; cur_sequence->stripped_uri = cur_source->stripped_uri; cur_sequence->mapped_uri = cur_source->stripped_uri; cur_source++; cur_source_ptr++; cur_sequence++; cur_clip_ptr++; } // need to test again since we filtered sub uris that didn't have any required tracks media_set->sequence_count = cur_sequence - media_set->sequences; if (media_set->sequence_count <= 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: request has no uris after track filtering"); return NGX_HTTP_BAD_REQUEST; } media_set->sequences_end = cur_sequence; media_set->has_multi_sequences = (multi_uri.parts_count > 1); media_set->sources_end = cur_source_ptr; media_set->total_clip_count = 1; media_set->clip_count = 1; media_set->durations = NULL; return NGX_OK; }
static vod_status_t m3u8_builder_build_required_tracks_string( request_context_t* request_context, media_set_t* media_set, uint32_t sequence_index, request_params_t* request_params, vod_str_t* tracks_spec) { u_char* p; size_t result_size; uint32_t i; result_size = 0; if (request_params->tracks_mask[MEDIA_TYPE_VIDEO] != 0xffffffff) { result_size += vod_get_number_of_set_bits(request_params->tracks_mask[MEDIA_TYPE_VIDEO]) * (sizeof("-v32") - 1); } if (request_params->tracks_mask[MEDIA_TYPE_AUDIO] != 0xffffffff) { result_size += vod_get_number_of_set_bits(request_params->tracks_mask[MEDIA_TYPE_AUDIO]) * (sizeof("-a32") - 1); } if (sequence_index != INVALID_SEQUENCE_INDEX) { result_size += sizeof("-f") - 1 + vod_get_int_print_len(sequence_index + 1); } p = vod_alloc(request_context->pool, result_size + 1); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "m3u8_builder_build_required_tracks_string: vod_alloc failed"); return VOD_ALLOC_FAILED; } tracks_spec->data = p; if (sequence_index != INVALID_SEQUENCE_INDEX) { p = vod_sprintf(p, "-f%uD", sequence_index + 1); } if (media_set->track_count[MEDIA_TYPE_VIDEO] != 0) { if (request_params->tracks_mask[MEDIA_TYPE_VIDEO] == 0xffffffff) { p = vod_copy(p, "-v0", sizeof("-v0") - 1); } else { for (i = 0; i < 32; i++) { if ((request_params->tracks_mask[MEDIA_TYPE_VIDEO] & (1 << i)) == 0) { continue; } p = vod_sprintf(p, "-v%uD", i + 1); } } } if (media_set->track_count[MEDIA_TYPE_AUDIO] != 0) { if (request_params->tracks_mask[MEDIA_TYPE_AUDIO] == 0xffffffff) { p = vod_copy(p, "-a0", sizeof("-a0") - 1); } else { for (i = 0; i < 32; i++) { if ((request_params->tracks_mask[MEDIA_TYPE_AUDIO] & (1 << i)) == 0) { continue; } p = vod_sprintf(p, "-a%uD", i + 1); } } } tracks_spec->len = p - tracks_spec->data; if (tracks_spec->len > result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "m3u8_builder_build_required_tracks_string: result length %uz exceeded allocated length %uz", tracks_spec->len, result_size); return VOD_UNEXPECTED; } return VOD_OK; }
ngx_int_t ngx_http_vod_parse_uri_path( ngx_http_request_t* r, ngx_str_t* multi_uri_suffix, ngx_hash_t* params_hash, ngx_str_t* uri, request_params_t* request_params, media_set_t* media_set) { media_sequence_t* cur_sequence; media_clip_source_t* cur_source; media_clip_source_t* sources_head; ngx_http_vod_multi_uri_t multi_uri; media_clip_t** cur_clip_ptr; media_clip_t* cur_clip; ngx_str_t parts[3]; ngx_str_t cur_uri; ngx_int_t rc; uint32_t sequences_mask; uint32_t parts_mask; uint32_t media_type; uint32_t clip_id = 1; uint32_t i; bool_t has_tracks; int uri_count; media_set->uri = *uri; // must save the uri before calling ngx_http_vod_parse_multi_uri as it may change rc = ngx_http_vod_parse_multi_uri(r, uri, multi_uri_suffix, &multi_uri); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_parse_multi_uri failed", rc); return rc; } if (multi_uri.parts_count > 1) { sequences_mask = request_params->sequences_mask; request_params->sequences_mask = 0xffffffff; // reset the sequences mask so that it won't be applied again on the mapping request } else { sequences_mask = 0xffffffff; } parts_mask = (1 << multi_uri.parts_count) - 1; uri_count = vod_get_number_of_set_bits(sequences_mask & parts_mask); if (uri_count == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: request has no uris"); return NGX_HTTP_BAD_REQUEST; } cur_sequence = ngx_palloc(r->pool, (sizeof(*cur_sequence) + sizeof(*cur_source) + sizeof(*cur_clip_ptr)) * uri_count); if (cur_sequence == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_palloc failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } media_set->sequences = cur_sequence; cur_source = (void*)(cur_sequence + uri_count); cur_clip_ptr = (void*)(cur_source + uri_count); sources_head = NULL; parts[0] = multi_uri.prefix; parts[2] = multi_uri.postfix; for (i = 0; i < multi_uri.parts_count; i++) { if ((sequences_mask & (1 << i)) == 0) { continue; } parts[1] = multi_uri.middle_parts[i]; rc = ngx_http_vod_merge_string_parts(r, parts, 3, &cur_uri); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_merge_string_parts failed", rc); return rc; } rc = ngx_http_vod_extract_uri_params(r, params_hash, &cur_uri, cur_sequence, &clip_id, cur_source, &cur_clip); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_parse_uri_path: ngx_http_vod_extract_uri_params failed", rc); return rc; } has_tracks = FALSE; for (media_type = 0; media_type < MEDIA_TYPE_COUNT; media_type++) { if ((cur_source->tracks_mask[media_type] & request_params->tracks_mask[media_type]) != 0) { has_tracks = TRUE; break; } } if (!has_tracks) { continue; } *cur_clip_ptr = cur_clip; cur_source->next = sources_head; sources_head = cur_source; cur_sequence->clips = cur_clip_ptr; cur_sequence->index = i; cur_sequence->stripped_uri = cur_source->stripped_uri; cur_sequence->mapped_uri = cur_source->stripped_uri; cur_sequence->id.len = 0; cur_sequence->language = 0; cur_sequence->label.len = 0; cur_sequence->first_key_frame_offset = 0; cur_sequence->key_frame_durations = NULL; cur_source++; cur_sequence++; cur_clip_ptr++; } // need to test again since we filtered sub uris that didn't have any required tracks media_set->sequence_count = cur_sequence - media_set->sequences; if (media_set->sequence_count <= 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_parse_uri_path: request has no uris after track filtering"); return NGX_HTTP_BAD_REQUEST; } media_set->sources_head = sources_head; media_set->sequences_end = cur_sequence; media_set->has_multi_sequences = (multi_uri.parts_count > 1); media_set->total_clip_count = 1; media_set->clip_count = 1; media_set->presentation_end = TRUE; return NGX_OK; }