Exemplo n.º 1
0
static ngx_int_t
ngx_http_vod_hls_handle_master_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;

	if (submodule_context->conf->hls.absolute_master_urls)
	{
		ngx_http_vod_get_base_url(submodule_context->r, &submodule_context->conf->https_header_name, NULL, 0, &empty_string, &base_url);
	}

	rc = m3u8_builder_build_master_playlist(
		&submodule_context->request_context,
		&submodule_context->conf->hls.m3u8_config,
		&base_url,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_master_playlist: m3u8_builder_build_master_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;
	
	return NGX_OK;
}
Exemplo n.º 2
0
static ngx_int_t 
ngx_http_vod_hds_handle_manifest(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;

	rc = hds_packager_build_manifest(
		&submodule_context->request_context,
		&submodule_context->conf->hds.manifest_config,
		&submodule_context->r->uri,
		&submodule_context->conf->segmenter,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hds_handle_manifest: hds_packager_build_manifest failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = f4m_content_type;
	content_type->len = sizeof(f4m_content_type) - 1;

	return NGX_OK;
}
static ngx_int_t 
ngx_http_vod_dash_handle_manifest(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;
	ngx_str_t file_uri;

	if (submodule_context->conf->dash.absolute_manifest_urls)
	{
		if (submodule_context->conf->dash.mpd_config.manifest_format == FORMAT_SEGMENT_LIST)
		{
			file_uri.data = NULL;
			file_uri.len = 0;
		}
		else
		{
			file_uri = submodule_context->r->uri;
		}

		ngx_http_vod_get_base_url(submodule_context->r, &submodule_context->conf->https_header_name, NULL, 0, &file_uri, &base_url);
	}

	if (submodule_context->conf->drm_enabled)
	{
		rc = edash_packager_build_mpd(
			&submodule_context->request_context,
			&submodule_context->conf->dash.mpd_config,
			&base_url,
			&submodule_context->media_set,
			response);
	}
	else
	{
		rc = dash_packager_build_mpd(
			&submodule_context->request_context,
			&submodule_context->conf->dash.mpd_config,
			&base_url,
			&submodule_context->media_set,
			0,
			NULL,
			NULL,
			response);
	}

	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_dash_handle_manifest: (e)dash_packager_build_mpd failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = mpd_content_type;
	content_type->len = sizeof(mpd_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 4
0
static ngx_int_t
ngx_http_vod_hds_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	hds_muxer_state_t* state;
	hds_encryption_params_t encryption_params;
	vod_status_t rc;
	drm_info_t* drm_info;

	if (submodule_context->conf->drm_enabled)
	{
		drm_info = submodule_context->media_set.sequences[0].drm_info;

		encryption_params.type = HDS_ENC_SELECTIVE;
		encryption_params.key = drm_info->key;
		encryption_params.iv = submodule_context->media_set.sequences[0].encryption_key;
	}
	else
	{
		encryption_params.type = HDS_ENC_NONE;
	}

	rc = hds_muxer_init_fragment(
		&submodule_context->request_context,
		&submodule_context->conf->hds.fragment_config,
		&encryption_params,
		submodule_context->request_params.segment_index,
		&submodule_context->media_set,
		segment_writer->write_tail,
		segment_writer->context,
		ngx_http_vod_submodule_size_only(submodule_context),
		output_buffer,
		response_size,
		&state);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hds_init_frame_processor: hds_muxer_init_fragment failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(submodule_context->r, rc);
	}

	*frame_processor = (ngx_http_vod_frame_processor_t)hds_muxer_process_frames;
	*frame_processor_state = state;

	// set the 'Content-type' header
	content_type->len = sizeof(f4f_content_type) - 1;
	content_type->data = (u_char *)f4f_content_type;

	return NGX_OK;
}
Exemplo n.º 5
0
static ngx_int_t
ngx_http_vod_hls_handle_iframe_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_http_vod_loc_conf_t* conf = submodule_context->conf;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;
	
	if (conf->hls.encryption_method != HLS_ENC_NONE)
	{
		ngx_log_error(NGX_LOG_ERR, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_iframe_playlist: iframes playlist not supported with encryption");
		return NGX_HTTP_BAD_REQUEST;
	}

	if (submodule_context->media_set.audio_filtering_needed)
	{
		ngx_log_error(NGX_LOG_ERR, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_iframe_playlist: iframes playlist not supported with audio filtering");
		return NGX_HTTP_BAD_REQUEST;
	}

	if (conf->hls.absolute_iframe_urls)
	{
		rc = ngx_http_vod_get_base_url(submodule_context->r, conf->base_url, &submodule_context->r->uri, &base_url);
		if (rc != NGX_OK)
		{
			return rc;
		}
	}

	rc = m3u8_builder_build_iframe_playlist(
		&submodule_context->request_context,
		&conf->hls.m3u8_config,
		&conf->hls.muxer_config,
		&base_url,
		&submodule_context->request_params,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_iframe_playlist: m3u8_builder_build_iframe_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;
	
	return NGX_OK;
}
static ngx_int_t
ngx_http_vod_hls_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	read_cache_state_t* read_cache_state,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	hls_muxer_state_t* state;
	vod_status_t rc;
	bool_t simulation_supported;

	state = ngx_pcalloc(submodule_context->request_context.pool, sizeof(hls_muxer_state_t));
	if (state == NULL)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_init_frame_processor: ngx_pcalloc failed");
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}

	rc = hls_muxer_init(
		state,
		&submodule_context->request_context,
		submodule_context->request_params.segment_index,
		&submodule_context->mpeg_metadata,
		read_cache_state,
		segment_writer->write_tail,
		segment_writer->context,
		&simulation_supported);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_init_frame_processor: hls_muxer_init failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	if (simulation_supported)
	{
		*response_size = hls_muxer_simulate_get_segment_size(state);
		hls_muxer_simulation_reset(state);
	}

	*frame_processor = (ngx_http_vod_frame_processor_t)hls_muxer_process;
	*frame_processor_state = state;

	content_type->len = sizeof(mpeg_ts_content_type) - 1;
	content_type->data = (u_char *)mpeg_ts_content_type;

	return NGX_OK;
}
Exemplo n.º 7
0
static ngx_int_t 
ngx_http_vod_hls_handle_index_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	hls_encryption_params_t encryption_params;
	ngx_str_t segments_base_url = ngx_null_string;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;
	u_char iv[AES_BLOCK_SIZE];

	if (submodule_context->conf->hls.absolute_index_urls)
	{
		ngx_http_vod_get_base_url(submodule_context->r, &submodule_context->conf->https_header_name, NULL, 0, &submodule_context->r->uri, &base_url);

		ngx_http_vod_get_base_url(
			submodule_context->r, 
			&submodule_context->conf->https_header_name, 
			&submodule_context->conf->segments_base_url, 
			submodule_context->conf->segments_base_url_has_scheme, 
			&submodule_context->r->uri, 
			&segments_base_url);
	}

	ngx_http_vod_hls_init_encryption_params(&encryption_params, submodule_context, iv);

	rc = m3u8_builder_build_index_playlist(
		&submodule_context->request_context,
		&submodule_context->conf->hls.m3u8_config,
		&base_url,
		&segments_base_url,
		&submodule_context->request_params,
		&encryption_params,
		&submodule_context->conf->segmenter,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_index_playlist: m3u8_builder_build_index_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;
	
	return NGX_OK;
}
Exemplo n.º 8
0
static ngx_int_t
ngx_http_vod_dash_handle_init_segment(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;

	if (submodule_context->conf->drm_enabled)
	{
		rc = edash_packager_build_init_mp4(
			&submodule_context->request_context,
			&submodule_context->media_set,
			submodule_context->conf->drm_clear_lead_segment_count > 0,
			ngx_http_vod_submodule_size_only(submodule_context),
			response);
	}
	else
	{
		rc = dash_packager_build_init_mp4(
			&submodule_context->request_context,
			&submodule_context->media_set,
			ngx_http_vod_submodule_size_only(submodule_context),
			NULL,
			NULL,
			response);
	}

	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_dash_handle_init_segment: (e)dash_packager_build_init_mp4 failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	if (submodule_context->media_set.track_count[MEDIA_TYPE_VIDEO] != 0)
	{
		content_type->data = mp4_video_content_type;
		content_type->len = sizeof(mp4_video_content_type) - 1;
	}
	else
	{
		content_type->data = mp4_audio_content_type;
		content_type->len = sizeof(mp4_audio_content_type) - 1;
	}

	return NGX_OK;
}
static ngx_int_t
ngx_http_vod_hls_handle_iframe_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	mpeg_stream_metadata_t* cur_stream;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;

	for (cur_stream = submodule_context->mpeg_metadata.first_stream;
		cur_stream < submodule_context->mpeg_metadata.last_stream;
		cur_stream++)
	{
		if (cur_stream->media_info.media_type == MEDIA_TYPE_AUDIO &&
			cur_stream->media_info.speed_nom != cur_stream->media_info.speed_denom)
		{
			ngx_log_error(NGX_LOG_ERR, submodule_context->request_context.log, 0,
				"ngx_http_vod_hls_handle_iframe_playlist: iframes playlist not supported with audio speed change");
			return NGX_HTTP_BAD_REQUEST;
		}
	}

	if (submodule_context->conf->hls.absolute_iframe_urls)
	{
		ngx_http_vod_get_base_url(submodule_context->r, &submodule_context->conf->https_header_name, NULL, 0, &submodule_context->r->uri, &base_url);
	}

	rc = m3u8_builder_build_iframe_playlist(
		&submodule_context->request_context,
		&submodule_context->conf->hls.m3u8_config,
		&base_url,
		submodule_context->request_params.uses_multi_uri && submodule_context->request_params.required_files != 0xffffffff,
		&submodule_context->conf->segmenter,
		&submodule_context->mpeg_metadata,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_iframe_playlist: m3u8_builder_build_iframe_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 10
0
static ngx_int_t 
ngx_http_vod_hls_handle_index_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_str_t segments_base_url = ngx_null_string;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;

	if (submodule_context->conf->hls.absolute_index_urls)
	{
		ngx_http_vod_get_base_url(submodule_context->r, &submodule_context->conf->https_header_name, NULL, 0, &submodule_context->r->uri, &base_url);

		ngx_http_vod_get_base_url(
			submodule_context->r, 
			&submodule_context->conf->https_header_name, 
			&submodule_context->conf->segments_base_url, 
			submodule_context->conf->segments_base_url_has_scheme, 
			&submodule_context->r->uri, 
			&segments_base_url);
	}

	rc = m3u8_builder_build_index_playlist(
		&submodule_context->request_context,
		&submodule_context->conf->hls.m3u8_config,
		&base_url,
		&segments_base_url,
		submodule_context->request_params.uses_multi_uri && submodule_context->request_params.required_files != 0xffffffff,
		submodule_context->conf->secret_key.len != 0,
		&submodule_context->conf->segmenter,
		&submodule_context->mpeg_metadata,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_index_playlist: m3u8_builder_build_index_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 11
0
static ngx_int_t
ngx_http_vod_dash_webm_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	vod_status_t rc;

	rc = mkv_builder_frame_writer_init(
		&submodule_context->request_context,
		submodule_context->media_set.sequences,
		segment_writer->write_tail,
		segment_writer->context,
		FALSE,
		output_buffer,
		response_size,
		frame_processor_state);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_dash_webm_init_frame_processor: mkv_builder_frame_writer_init failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	*frame_processor = (ngx_http_vod_frame_processor_t)mkv_builder_frame_writer_process;

	// set the 'Content-type' header
	if (submodule_context->media_set.track_count[MEDIA_TYPE_VIDEO] != 0)
	{
		content_type->len = sizeof(webm_video_content_type) - 1;
		content_type->data = (u_char *)webm_video_content_type;
	}
	else
	{
		content_type->len = sizeof(webm_audio_content_type) - 1;
		content_type->data = (u_char *)webm_audio_content_type;
	}

	return NGX_OK;
}
Exemplo n.º 12
0
static ngx_int_t
ngx_http_vod_dash_webm_handle_init_segment(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;
	ngx_md5_t md5;
	ngx_str_t* uri;
	uint64_t track_uid;
	u_char uri_key[16];

	// calculate a uid for track based on the request uri
	uri = &submodule_context->r->uri;
	ngx_md5_init(&md5);
	ngx_md5_update(&md5, uri->data, uri->len);
	ngx_md5_final(uri_key, &md5);
	ngx_memcpy(&track_uid, uri_key, sizeof(track_uid));

	rc = mkv_build_init_segment(
		&submodule_context->request_context,
		submodule_context->media_set.sequences[0].filtered_clips[0].first_track,
		track_uid,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_dash_webm_handle_init_segment: mkv_build_init_segment failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	if (submodule_context->media_set.track_count[MEDIA_TYPE_VIDEO] != 0)
	{
		content_type->data = webm_video_content_type;
		content_type->len = sizeof(webm_video_content_type) - 1;
	}
	else
	{
		content_type->data = webm_audio_content_type;
		content_type->len = sizeof(webm_audio_content_type) - 1;
	}

	return NGX_OK;
}
Exemplo n.º 13
0
static ngx_int_t
ngx_http_vod_hls_init_ts_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	hls_encryption_params_t encryption_params;
	hls_muxer_state_t* state;
	vod_status_t rc;
	u_char iv[AES_BLOCK_SIZE];

	ngx_http_vod_hls_init_encryption_params(&encryption_params, submodule_context, iv);

	rc = hls_muxer_init_segment(
		&submodule_context->request_context,
		&submodule_context->conf->hls.muxer_config,
		&encryption_params,
		submodule_context->request_params.segment_index,
		&submodule_context->media_set,
		segment_writer->write_tail,
		segment_writer->context,
		response_size, 
		output_buffer,
		&state);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_init_ts_frame_processor: hls_muxer_init failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	*frame_processor = (ngx_http_vod_frame_processor_t)hls_muxer_process;
	*frame_processor_state = state;

	content_type->len = sizeof(mpeg_ts_content_type) - 1;
	content_type->data = (u_char *)mpeg_ts_content_type;

	return NGX_OK;
}
Exemplo n.º 14
0
static ngx_int_t
ngx_http_vod_hds_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	hds_muxer_state_t* state;
	vod_status_t rc;	
	
	rc = hds_muxer_init_fragment(
		&submodule_context->request_context,
		&submodule_context->conf->hds.fragment_config,
		submodule_context->request_params.segment_index,
		submodule_context->media_set.sequences,
		segment_writer->write_tail,
		segment_writer->context,
		ngx_http_vod_submodule_size_only(submodule_context),
		output_buffer,
		response_size,
		&state);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hds_init_frame_processor: hds_muxer_init_fragment failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	*frame_processor = (ngx_http_vod_frame_processor_t)hds_muxer_process_frames;
	*frame_processor_state = state;

	// set the 'Content-type' header
	content_type->len = sizeof(f4f_content_type) - 1;
	content_type->data = (u_char *)f4f_content_type;

	return NGX_OK;
}
Exemplo n.º 15
0
static ngx_int_t 
ngx_http_vod_mss_handle_manifest(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;

	if (submodule_context->conf->drm_enabled)
	{
		rc = mss_playready_build_manifest(
			&submodule_context->request_context,
			&submodule_context->conf->segmenter,
			&submodule_context->mpeg_metadata,
			response);
	}
	else
	{
		rc = mss_packager_build_manifest(
			&submodule_context->request_context,
			&submodule_context->conf->segmenter,
			&submodule_context->mpeg_metadata,
			0,
			NULL,
			NULL,
			response);
	}
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_mss_handle_manifest: mss_packager_build_manifest failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = manifest_content_type;
	content_type->len = sizeof(manifest_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 16
0
static ngx_int_t 
ngx_http_vod_hds_handle_manifest(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_http_vod_loc_conf_t* conf = submodule_context->conf;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;

	if (conf->hds.absolute_manifest_urls)
	{
		rc = ngx_http_vod_get_base_url(submodule_context->r, conf->base_url, &submodule_context->r->uri, &base_url);
		if (rc != NGX_OK)
		{
			return rc;
		}
	}

	rc = hds_packager_build_manifest(
		&submodule_context->request_context,
		&conf->hds.manifest_config,
		&base_url,
		&submodule_context->r->uri,
		&submodule_context->media_set,
		conf->drm_enabled,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hds_handle_manifest: hds_packager_build_manifest failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(submodule_context->r, rc);
	}

	content_type->data = f4m_content_type;
	content_type->len = sizeof(f4m_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 17
0
static ngx_int_t
ngx_http_vod_hls_handle_vtt_segment(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;
	
	rc = webvtt_builder_build(
		&submodule_context->request_context,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_vtt_segment: webvtt_builder_build failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->len = sizeof(vtt_content_type) - 1;
	content_type->data = (u_char *)vtt_content_type;

	return NGX_OK;
}
Exemplo n.º 18
0
static ngx_int_t
ngx_http_vod_hds_handle_bootstrap(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	vod_status_t rc;
	
	rc = hds_packager_build_bootstrap(
		&submodule_context->request_context,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hds_handle_bootstrap: hds_packager_build_bootstrap failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(submodule_context->r, rc);
	}

	content_type->data = abst_content_type;
	content_type->len = sizeof(abst_content_type) - 1;

	return NGX_OK;
}
Exemplo n.º 19
0
static ngx_int_t
ngx_http_vod_mss_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	read_cache_state_t* read_cache_state,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	fragment_writer_state_t* state;
	segment_writer_t drm_writer;
	vod_status_t rc;
	bool_t size_only = ngx_http_vod_submodule_size_only(submodule_context);

	if (submodule_context->conf->drm_enabled)
	{
		rc = mss_playready_get_fragment_writer(
			&drm_writer,
			&submodule_context->request_context,
			submodule_context->mpeg_metadata.first_stream,
			submodule_context->request_params.segment_index,
			segment_writer,
			submodule_context->cur_suburi->file_key,		// iv
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mss_playready_get_fragment_writer failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		segment_writer = &drm_writer;
	}
	else
	{
		rc = mss_packager_build_fragment_header(
			&submodule_context->request_context,
			submodule_context->mpeg_metadata.first_stream,
			submodule_context->request_params.segment_index,
			0,
			NULL,
			NULL,
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mss_packager_build_fragment_header failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}
	}

	if (!size_only || *response_size == 0)
	{
		rc = mp4_builder_frame_writer_init(
			&submodule_context->request_context,
			submodule_context->mpeg_metadata.first_stream,
			read_cache_state,
			segment_writer->write_tail,
			segment_writer->context,
			&state);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mp4_builder_frame_writer_init failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		*frame_processor = (ngx_http_vod_frame_processor_t)mp4_builder_frame_writer_process;
		*frame_processor_state = state;
	}

	// set the 'Content-type' header
	if (submodule_context->mpeg_metadata.stream_count[MEDIA_TYPE_VIDEO])
	{
		content_type->len = sizeof(mp4_video_content_type) - 1;
		content_type->data = mp4_video_content_type;
	}
	else
	{
		content_type->len = sizeof(mp4_audio_content_type) - 1;
		content_type->data = mp4_audio_content_type;
	}

	return NGX_OK;
}
Exemplo n.º 20
0
static ngx_int_t 
ngx_http_vod_hls_handle_index_playlist(
	ngx_http_vod_submodule_context_t* submodule_context,
	ngx_str_t* response,
	ngx_str_t* content_type)
{
	ngx_http_vod_loc_conf_t* conf = submodule_context->conf;
	hls_encryption_params_t encryption_params;
	ngx_str_t segments_base_url = ngx_null_string;
	ngx_str_t base_url = ngx_null_string;
	vod_status_t rc;
	u_char iv[AES_BLOCK_SIZE];

	if (conf->hls.absolute_index_urls)
	{
		rc = ngx_http_vod_get_base_url(submodule_context->r, conf->base_url, &submodule_context->r->uri, &base_url);
		if (rc != NGX_OK)
		{
			return rc;
		}

		if (conf->segments_base_url != NULL)
		{
			rc = ngx_http_vod_get_base_url(
				submodule_context->r, 
				conf->segments_base_url,
				&submodule_context->r->uri, 
				&segments_base_url);
			if (rc != NGX_OK)
			{
				return rc;
			}
		}
		else
		{
			segments_base_url = base_url;
		}
	}

	ngx_http_vod_hls_init_encryption_params(&encryption_params, submodule_context, iv);

	if (encryption_params.type != HLS_ENC_NONE)
	{
		if (conf->hls.encryption_key_uri != NULL)
		{
			if (ngx_http_complex_value(
				submodule_context->r,
				conf->hls.encryption_key_uri,
				&encryption_params.key_uri) != NGX_OK)
			{
				ngx_log_debug0(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
					"ngx_http_vod_hls_handle_index_playlist: ngx_http_complex_value failed");
				return NGX_ERROR;
			}
		}
		else
		{
			encryption_params.key_uri.len = 0;
		}
	}

	rc = m3u8_builder_build_index_playlist(
		&submodule_context->request_context,
		&conf->hls.m3u8_config,
		&base_url,
		&segments_base_url,
		&submodule_context->request_params,
		&encryption_params,
		&submodule_context->media_set,
		response);
	if (rc != VOD_OK)
	{
		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
			"ngx_http_vod_hls_handle_index_playlist: m3u8_builder_build_index_playlist failed %i", rc);
		return ngx_http_vod_status_to_ngx_error(rc);
	}

	content_type->data = m3u8_content_type;
	content_type->len = sizeof(m3u8_content_type) - 1;
	
	return NGX_OK;
}
static ngx_int_t
ngx_http_vod_parse_multi_uri(
	ngx_http_request_t* r,
	ngx_str_t* uri,
	ngx_str_t* multi_uri_suffix,
	ngx_http_vod_multi_uri_t* result)
{
	u_char* cur_pos;
	u_char* end_pos;
	u_char* last_comma_pos;
	uint32_t part_index;

	result->prefix.data = uri->data;
	result->prefix.len = uri->len;
	result->postfix.data = NULL;
	result->postfix.len = 0;

	if (uri->len < multi_uri_suffix->len ||
		ngx_memcmp(multi_uri_suffix->data, uri->data + uri->len - multi_uri_suffix->len, multi_uri_suffix->len) != 0)
	{
		// not a multi uri
		result->middle_parts[0].data = NULL;
		result->middle_parts[0].len = 0;
		result->parts_count = 1;
		return NGX_OK;
	}

	uri->len -= multi_uri_suffix->len;

	end_pos = uri->data + uri->len;
	last_comma_pos = NULL;
	part_index = 0;
	for (cur_pos = uri->data; cur_pos < end_pos; cur_pos++)
	{
		if (*cur_pos != ',')
		{
			continue;
		}

		if (last_comma_pos == NULL)
		{
			result->prefix.len = cur_pos - uri->data;
		}
		else
		{
			if (part_index >= MAX_SUB_URIS)
			{
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"ngx_http_vod_parse_multi_uri: number of url parts exceeds the limit");
				return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
			}

			result->middle_parts[part_index].data = last_comma_pos;
			result->middle_parts[part_index].len = cur_pos - last_comma_pos;
			part_index++;
		}

		last_comma_pos = cur_pos + 1;
	}

	if (last_comma_pos == NULL)
	{
		// no commas at all
		result->postfix.data = NULL;
		result->postfix.len = 0;
	}
	else
	{
		// 1 comma or more
		result->postfix.data = last_comma_pos;
		result->postfix.len = end_pos - last_comma_pos;
	}

	if (part_index == 0)
	{
		// no commas at all or a single comma
		result->middle_parts[0].data = NULL;
		result->middle_parts[0].len = 0;
		result->parts_count = 1;
	}
	else
	{
		// 2 commas or more
		result->parts_count = part_index;
	}

	return NGX_OK;
}
static ngx_int_t
ngx_http_vod_extract_uri_params(
	ngx_http_request_t* r,
	ngx_hash_t* params_hash,
	ngx_str_t* uri,
	media_sequence_t* sequence,
	uint32_t* clip_id,
	media_clip_source_t* source_clip,
	media_clip_t** result)
{
	ngx_http_vod_uri_param_def_t* param_def = NULL;
	request_context_t request_context;
	media_clip_t* rate_filter = NULL;
	ngx_uint_t  cur_key_hash = 0;
	ngx_str_t cur_param;
	ngx_int_t rc;
	uint32_t parsed_params_mask = 0;
	uint32_t param_index;
	u_char param_name[MAX_URI_PARAM_NAME_LEN + 1];
	u_char* param_name_end = param_name + sizeof(param_name);
	u_char* param_name_pos = param_name;
	u_char* copy_start = uri->data;
	u_char* cur_pos;
	u_char* end_pos = uri->data + uri->len;
	u_char* last_slash = NULL;
	u_char* p;

	// set the source defaults
	vod_memzero(source_clip, sizeof(*source_clip));

	source_clip->base.type = MEDIA_CLIP_SOURCE;
	source_clip->base.id = (*clip_id)++;

	source_clip->clip_to = UINT_MAX;
	source_clip->tracks_mask[MEDIA_TYPE_AUDIO] = 0xffffffff;
	source_clip->tracks_mask[MEDIA_TYPE_VIDEO] = 0xffffffff;
	source_clip->uri = *uri;
	source_clip->sequence = sequence;
	
	*result = &source_clip->base;

	// allocate the stripped uri
	p = ngx_palloc(r->pool, uri->len + 1);
	if (p == NULL)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
			"ngx_http_vod_extract_uri_params: ngx_palloc failed (1)");
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}
	source_clip->stripped_uri.data = p;

	for (cur_pos = uri->data; cur_pos <= end_pos; cur_pos++)
	{
		if (cur_pos < end_pos && *cur_pos != '/')
		{
			if (param_name_pos < param_name_end)
			{
				*param_name_pos = ngx_tolower(*cur_pos);
				cur_key_hash = ngx_hash(cur_key_hash, *param_name_pos);
				param_name_pos++;
			}
			continue;
		}

		if (last_slash == NULL)
		{
			last_slash = cur_pos;
			cur_key_hash = 0;
			param_name_pos = param_name;
			continue;
		}

		if (param_def == NULL)
		{
			param_def = ngx_hash_find(params_hash, cur_key_hash, param_name, param_name_pos - param_name);
			if (param_def != NULL)
			{
				p = ngx_copy(p, copy_start, last_slash - copy_start);
				copy_start = last_slash;
			}
		}
		else
		{
			param_index = param_def - uri_param_defs;
			if ((parsed_params_mask & (1 << param_index)) == 0)		// first instance of a param takes priority
			{
				parsed_params_mask |= (1 << param_index);
				cur_param.data = last_slash + 1;
				cur_param.len = cur_pos - (last_slash + 1);

				if (param_def->name_conf_offset == offsetof(ngx_http_vod_loc_conf_t, speed_param_name))
				{
					request_context.pool = r->pool;
					request_context.log = r->connection->log;

					rc = rate_filter_create_from_string(
						&request_context,
						&cur_param,
						&source_clip->base, 
						&rate_filter);
					if (rc != VOD_OK)
					{
						return ngx_http_vod_status_to_ngx_error(rc);
					}

					rate_filter->id = (*clip_id)++;
					*result = rate_filter;
				}
				else
				{
					rc = param_def->parser(&cur_param, source_clip, param_def->target_offset);
					if (rc != NGX_OK)
					{
						ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
							"ngx_http_vod_extract_uri_params: %s parser failed %i", param_def->name, rc);
						return rc;
					}
				}
			}
			copy_start = cur_pos;
			param_def = NULL;
		}

		last_slash = cur_pos;
		cur_key_hash = 0;
		param_name_pos = param_name;
	}

	if (source_clip->clip_from >= source_clip->clip_to)
	{
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
			"ngx_http_vod_extract_uri_params: clip from %uD is larger than clip to %uD", source_clip->clip_from, source_clip->clip_to);
		return NGX_HTTP_BAD_REQUEST;
	}

	p = ngx_copy(p, copy_start, end_pos - copy_start);
	*p = '\0';

	source_clip->stripped_uri.len = p - source_clip->stripped_uri.data;
	source_clip->mapped_uri = source_clip->stripped_uri;

	return NGX_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

	multi_uri.parts_count = 0;

	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 %i", rc);
		return rc;
	}

	if (multi_uri.parts_count > 1 && 
		request_params->sequence_ids[0].len == 0)
	{
		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_vod_status_to_ngx_error(r, VOD_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_vod_status_to_ngx_error(r, VOD_ALLOC_FAILED);
	}
	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;
		}

		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_sequence->drm_info = NULL;
		vod_memzero(cur_sequence->bitrate, sizeof(cur_sequence->bitrate));

		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 %i", 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 %i", 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_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_vod_status_to_ngx_error(r, VOD_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->timing.total_count = 1;
	media_set->clip_count = 1;
	media_set->presentation_end = TRUE;

	return NGX_OK;
}
Exemplo n.º 24
0
static ngx_int_t
ngx_http_vod_hds_parse_uri_file_name(
	ngx_http_request_t *r,
	ngx_http_vod_loc_conf_t *conf,
	u_char* start_pos,
	u_char* end_pos,
	request_params_t* request_params,
	const ngx_http_vod_request_t** request)
{
	uint32_t flags = 0;
	ngx_int_t rc;

	// fragment request
	if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hds.manifest_config.fragment_file_name_prefix))
	{
		// sample fragment file name: frag-f3-v1-a1-Seg1-Frag1
		start_pos += conf->hds.manifest_config.fragment_file_name_prefix.len;

		// parse the fragment index
		end_pos = ngx_http_vod_extract_uint32_token_reverse(start_pos, end_pos, &request_params->segment_index);
		if (request_params->segment_index == 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_hds_parse_uri_file_name: failed to parse fragment index");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}

		request_params->segment_index--;		// convert to 0-based

		// extract the '-Seg1-Frag' part
		end_pos -= sizeof("-Seg1-Frag") - 1;
		if (end_pos < start_pos ||
			ngx_memcmp(end_pos, "-Seg1-Frag", sizeof("-Seg1-Frag") - 1) != 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_hds_parse_uri_file_name: invalid segment / fragment requested");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}

		*request = &hds_fragment_request;
	}
	// bootstrap request
	else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hds.manifest_config.bootstrap_file_name_prefix, bootstrap_file_ext))
	{
		start_pos += conf->hds.manifest_config.bootstrap_file_name_prefix.len;
		end_pos -= (sizeof(bootstrap_file_ext) - 1);
		*request = &hds_bootstrap_request;
	}
	// manifest request
	else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hds.manifest_file_name_prefix, manifest_file_ext))
	{
		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
	{
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
			"ngx_http_vod_hds_parse_uri_file_name: unidentified request");
		return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
	}

	// parse the required tracks string
	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,
			"ngx_http_vod_hds_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc);
		return rc;
	}

	return NGX_OK;
}
Exemplo n.º 25
0
static ngx_int_t
ngx_http_vod_dash_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	read_cache_state_t* read_cache_state,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	dash_fragment_header_extensions_t header_extensions;
	fragment_writer_state_t* state;
	segment_writer_t edash_writer;
	vod_status_t rc;
	bool_t size_only = ngx_http_vod_submodule_size_only(submodule_context);

	if (submodule_context->conf->drm_enabled && 
		submodule_context->request_params.segment_index >= submodule_context->conf->drm_clear_lead_segment_count)
	{
		// encyrpted fragment
		rc = edash_packager_get_fragment_writer(
			&edash_writer,
			&submodule_context->request_context,
			&submodule_context->media_set,
			submodule_context->request_params.segment_index,
			segment_writer,
			submodule_context->media_set.sequences[0].encryption_key,		// iv
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_dash_init_frame_processor: edash_packager_get_fragment_writer failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		segment_writer = &edash_writer;
	}
	else
	{
		// unencrypted
		ngx_memzero(&header_extensions, sizeof(header_extensions));

		rc = dash_packager_build_fragment_header(
			&submodule_context->request_context,
			&submodule_context->media_set,
			submodule_context->request_params.segment_index,
			submodule_context->conf->drm_enabled ? 2 : 0,	// sample description index
			&header_extensions,
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_dash_init_frame_processor: dash_packager_build_fragment_header failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}
	}

	// initialize the frame processor
	if (!size_only || *response_size == 0)
	{
		rc = mp4_builder_frame_writer_init(
			&submodule_context->request_context,
			submodule_context->media_set.sequences,
			read_cache_state,
			segment_writer->write_tail,
			segment_writer->context,
			&state);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_dash_init_frame_processor: mp4_builder_frame_writer_init failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		*frame_processor = (ngx_http_vod_frame_processor_t)mp4_builder_frame_writer_process;
		*frame_processor_state = state;
	}

	// set the 'Content-type' header
	if (submodule_context->media_set.track_count[MEDIA_TYPE_VIDEO] != 0)
	{
		content_type->len = sizeof(mp4_video_content_type) - 1;
		content_type->data = (u_char *)mp4_video_content_type;
	}
	else
	{
		content_type->len = sizeof(mp4_audio_content_type) - 1;
		content_type->data = (u_char *)mp4_audio_content_type;
	}

	return NGX_OK;
}
Exemplo n.º 26
0
static ngx_int_t
ngx_http_vod_mss_init_frame_processor(
	ngx_http_vod_submodule_context_t* submodule_context,
	segment_writer_t* segment_writer,
	ngx_http_vod_frame_processor_t* frame_processor,
	void** frame_processor_state,
	ngx_str_t* output_buffer,
	size_t* response_size,
	ngx_str_t* content_type)
{
	fragment_writer_state_t* state;
	segment_writer_t drm_writer;
	vod_status_t rc;
	bool_t reuse_buffers = FALSE;
	bool_t size_only = ngx_http_vod_submodule_size_only(submodule_context);

	if (submodule_context->conf->drm_enabled)
	{
		rc = mss_playready_get_fragment_writer(
			&drm_writer,
			&submodule_context->request_context,
			&submodule_context->media_set,
			submodule_context->request_params.segment_index,
			segment_writer,
			submodule_context->media_set.sequences[0].encryption_key,		// iv
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mss_playready_get_fragment_writer failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		if (drm_writer.write_tail != NULL)
		{
			segment_writer = &drm_writer;
			reuse_buffers = TRUE;		// mp4_encrypt allocates new buffers
		}
	}
	else
	{
		rc = mss_packager_build_fragment_header(
			&submodule_context->request_context,
			&submodule_context->media_set,
			submodule_context->request_params.segment_index,
			0,
			NULL,
			NULL,
			size_only,
			output_buffer,
			response_size);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mss_packager_build_fragment_header failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}
	}

	if (!size_only || *response_size == 0)
	{
		rc = mp4_builder_frame_writer_init(
			&submodule_context->request_context,
			submodule_context->media_set.sequences,
			segment_writer->write_tail,
			segment_writer->context,
			reuse_buffers,
			&state);
		if (rc != VOD_OK)
		{
			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, submodule_context->request_context.log, 0,
				"ngx_http_vod_mss_init_frame_processor: mp4_builder_frame_writer_init failed %i", rc);
			return ngx_http_vod_status_to_ngx_error(rc);
		}

		*frame_processor = (ngx_http_vod_frame_processor_t)mp4_builder_frame_writer_process;
		*frame_processor_state = state;
	}

	// set the 'Content-type' header
	if (submodule_context->media_set.track_count[MEDIA_TYPE_VIDEO])
	{
		content_type->len = sizeof(mp4_video_content_type) - 1;
		content_type->data = mp4_video_content_type;
	}
	else
	{
		content_type->len = sizeof(mp4_audio_content_type) - 1;
		content_type->data = mp4_audio_content_type;
	}

	return NGX_OK;
}
ngx_int_t
ngx_http_vod_parse_uri_file_name(
	ngx_http_request_t* r,
	u_char* start_pos,
	u_char* end_pos,
	uint32_t flags,
	request_params_t* result)
{
	sequence_tracks_mask_t* sequence_tracks_mask_end;
	sequence_tracks_mask_t* sequence_tracks_mask;
	ngx_str_t* cur_sequence_id;
	ngx_str_t* last_sequence_id;
	uint32_t default_tracks_mask;
	uint32_t* tracks_mask;
	uint32_t segment_index_shift;
	uint32_t sequence_index;
	uint32_t clip_index;
	uint32_t media_type;
	uint32_t pts_delay;
	uint32_t version;
	bool_t tracks_mask_updated;
	language_id_t lang_id;

	default_tracks_mask = (flags & PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE) ? 0xffffffff : 1;
	for (media_type = 0; media_type < MEDIA_TYPE_COUNT; media_type++)
	{
		result->tracks_mask[media_type] = default_tracks_mask;
	}
	result->sequences_mask = 0xffffffff;
	result->clip_index = INVALID_CLIP_INDEX;

	// segment index
	if ((flags & PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX) != 0)
	{
		if (start_pos < end_pos && *start_pos == '-')
		{
			start_pos++;		// skip the -
		}

		start_pos = parse_utils_extract_uint32_token(start_pos, end_pos, &result->segment_index);
		if (result->segment_index <= 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_parse_uri_file_name: failed to parse segment index");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}
		result->segment_index--;		// convert to 0-based

		skip_dash(start_pos, end_pos);

		// index shift
		if (*start_pos == 'i')
		{
			start_pos++;		// skip the i

			start_pos = parse_utils_extract_uint32_token(start_pos, end_pos, &segment_index_shift);
			if (segment_index_shift <= 0)
			{
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"ngx_http_vod_parse_uri_file_name: failed to parse segment index shift");
				return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
			}

			result->segment_index += segment_index_shift;

			skip_dash(start_pos, end_pos);
		}
	}
	else
	{
		skip_dash(start_pos, end_pos);
	}

	// clip index
	if (*start_pos == 'c' && (flags & PARSE_FILE_NAME_ALLOW_CLIP_INDEX) != 0)
	{
		start_pos++;		// skip the c

		start_pos = parse_utils_extract_uint32_token(start_pos, end_pos, &clip_index);
		if (clip_index <= 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_parse_uri_file_name: failed to parse clip index");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}

		result->clip_index = clip_index - 1;

		skip_dash(start_pos, end_pos);
	}

	// sequence (file) index
	if (*start_pos == 'f' || *start_pos == 's')
	{
		result->sequences_mask = 0;
		cur_sequence_id = result->sequence_ids;
		last_sequence_id = cur_sequence_id + MAX_SEQUENCE_IDS;
		sequence_tracks_mask = NULL;
		sequence_tracks_mask_end = NULL;
		tracks_mask_updated = FALSE;

		for (;;)
		{
			if (*start_pos == 'f')
			{
				// sequence index
				start_pos++;		// skip the f

				if (start_pos >= end_pos || *start_pos < '1' || *start_pos > '9')
				{
					ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
						"ngx_http_vod_parse_uri_file_name: missing index following sequence selector");
					return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
				}

				sequence_index = *start_pos - '0';
				start_pos++;		// skip the digit

				if (start_pos < end_pos && *start_pos >= '0' && *start_pos <= '9')
				{
					sequence_index = sequence_index * 10 + *start_pos - '0';
					if (sequence_index > MAX_SEQUENCES)
					{
						ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
							"ngx_http_vod_parse_uri_file_name: sequence index too big");
						return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
					}
					start_pos++;		// skip the digit
				}

				sequence_index--;		// Note: sequence_index cannot be 0 here
				result->sequences_mask |= (1 << sequence_index);
			}
			else
			{
				// sequence id
				start_pos++;		// skip the s

				if (cur_sequence_id >= last_sequence_id)
				{
					ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
						"ngx_http_vod_parse_uri_file_name: the number of sequence ids exceeds the limit");
					return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
				}

				cur_sequence_id->data = start_pos;

				while (start_pos < end_pos && *start_pos != '-')
				{
					start_pos++;
				}

				cur_sequence_id->len = start_pos - cur_sequence_id->data;

				cur_sequence_id++;
				sequence_index = -(cur_sequence_id - result->sequence_ids);
			}

			skip_dash(start_pos, end_pos);

			// tracks spec
			if (*start_pos == 'v' || *start_pos == 'a')
			{
				if (sequence_tracks_mask != NULL)
				{
					if (sequence_tracks_mask >= sequence_tracks_mask_end)
					{
						ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
							"ngx_http_vod_parse_uri_file_name: the number of track specs exceeds the limit");
						return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
					}

					sequence_tracks_mask->index = sequence_index;
					tracks_mask = sequence_tracks_mask->tracks_mask;
					sequence_tracks_mask++;
					result->sequence_tracks_mask_end = sequence_tracks_mask;
				}
				else
				{
					tracks_mask_updated = TRUE;
					tracks_mask = result->tracks_mask;
				}

				start_pos = ngx_http_vod_extract_track_tokens(
					start_pos, 
					end_pos, 
					tracks_mask);
				if (start_pos == NULL)
				{
					return NGX_OK;
				}
			}

			if (*start_pos != 'f' && *start_pos != 's')
			{
				break;
			}

			if (sequence_tracks_mask != NULL)
			{
				continue;
			}

			// more than one sequence, allocate the per sequence tracks mask
			sequence_tracks_mask = ngx_palloc(r->pool, 
				sizeof(sequence_tracks_mask[0]) * MAX_SEQUENCE_TRACKS_MASKS);
			if (sequence_tracks_mask == NULL)
			{
				ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
					"ngx_http_vod_parse_uri_file_name: ngx_palloc failed");
				return ngx_http_vod_status_to_ngx_error(r, VOD_ALLOC_FAILED);
			}

			sequence_tracks_mask_end = sequence_tracks_mask + MAX_SEQUENCE_TRACKS_MASKS;

			result->sequence_tracks_mask = sequence_tracks_mask;
			result->sequence_tracks_mask_end = sequence_tracks_mask;

			if (tracks_mask_updated)
			{
				// add the currently parsed mask to the array
				sequence_tracks_mask->index = sequence_index;
				ngx_memcpy(sequence_tracks_mask->tracks_mask, result->tracks_mask, sizeof(sequence_tracks_mask->tracks_mask));
				sequence_tracks_mask++;
				result->sequence_tracks_mask_end = sequence_tracks_mask;

				// restore the global mask to the default
				for (media_type = 0; media_type < MEDIA_TYPE_COUNT; media_type++)
				{
					result->tracks_mask[media_type] = default_tracks_mask;
				}
			}
		}
	}
	else if (*start_pos == 'v' || *start_pos == 'a')
	{
		// tracks
		start_pos = ngx_http_vod_extract_track_tokens(start_pos, end_pos, result->tracks_mask);
		if (start_pos == NULL)
		{
			return NGX_OK;
		}
	}

	// pts delay
	if (*start_pos == 'p')
	{
		start_pos++;		// skip the p

		start_pos = parse_utils_extract_uint32_token(start_pos, end_pos, &pts_delay);
		if (pts_delay <= 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_parse_uri_file_name: failed to parse pts delay");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}

		result->pts_delay = pts_delay;

		skip_dash(start_pos, end_pos);
	}

	// languages
	if (*start_pos == 'l')
	{
		result->langs_mask = ngx_pnalloc(r->pool, LANG_MASK_SIZE);
		if (result->langs_mask == NULL)
		{
			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
				"ngx_http_vod_parse_uri_file_name: ngx_pnalloc failed");
			return ngx_http_vod_status_to_ngx_error(r, VOD_ALLOC_FAILED);
		}

		ngx_memzero(result->langs_mask, LANG_MASK_SIZE);

		for (;;)
		{
			start_pos++;		// skip the l
			if (start_pos + LANG_ISO639_3_LEN > end_pos)
			{
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"ngx_http_vod_parse_uri_file_name: language specifier length must be 3 characters");
				return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
			}

			lang_id = lang_parse_iso639_3_code(iso639_3_str_to_int(start_pos));
			if (lang_id == 0)
			{
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"ngx_http_vod_parse_uri_file_name: failed to parse language specifier %*s", (size_t)3, start_pos);
				return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
			}

			vod_set_bit(result->langs_mask, lang_id);

			start_pos += LANG_ISO639_3_LEN;

			skip_dash(start_pos, end_pos);

			if (*start_pos != 'l')
			{
				break;
			}
		}
	}

	// version
	if (*start_pos == 'x')
	{
		start_pos++;		// skip the x

		start_pos = parse_utils_extract_uint32_token(start_pos, end_pos, &version);
		if (version <= 0)
		{
			ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"ngx_http_vod_parse_uri_file_name: failed to parse version");
			return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
		}

		result->version = version - 1;

		skip_dash(start_pos, end_pos);
	}

	ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
		"ngx_http_vod_parse_uri_file_name: did not consume the whole name");
	return ngx_http_vod_status_to_ngx_error(r, VOD_BAD_REQUEST);
}