static vod_status_t
edash_packager_video_build_fragment_header(
	mp4_encrypt_video_state_t* state,
	vod_str_t* fragment_header)
{
	dash_fragment_header_extensions_t header_extensions;
	size_t total_fragment_size;

	// get the header extensions
	header_extensions.extra_traf_atoms_size = 
		state->base.saiz_atom_size + 
		state->base.saio_atom_size + 
		ATOM_HEADER_SIZE + sizeof(senc_atom_t) + state->auxiliary_data.pos - state->auxiliary_data.start;
	header_extensions.write_extra_traf_atoms_callback = edash_packager_video_write_encryption_atoms;
	header_extensions.write_extra_traf_atoms_context = state;

	// build the fragment header
	return dash_packager_build_fragment_header(
		state->base.request_context,
		state->base.media_set,
		state->base.segment_index,
		0,
		&header_extensions,
		FALSE,
		fragment_header,
		&total_fragment_size);
}
Beispiel #2
0
static vod_status_t
edash_packager_video_write_fragment_header(mp4_encrypt_video_state_t* state)
{
	dash_fragment_header_extensions_t header_extensions;
	atom_writer_t auxiliary_data_writer;
	vod_str_t fragment_header;
	vod_status_t rc;
	size_t total_fragment_size;
	bool_t reuse_buffer;

	// get the auxiliary data writer
	auxiliary_data_writer.atom_size = state->auxiliary_data.pos - state->auxiliary_data.start;
	auxiliary_data_writer.write = edash_packager_video_write_auxiliary_data;
	auxiliary_data_writer.context = state;

	header_extensions.extra_traf_atoms_size = state->base.saiz_atom_size + state->base.saio_atom_size;
	header_extensions.write_extra_traf_atoms_callback = (write_extra_traf_atoms_callback_t)mp4_encrypt_video_write_saiz_saio;
	header_extensions.write_extra_traf_atoms_context = state;
	header_extensions.mdat_prefix_writer = &auxiliary_data_writer;

	// build the fragment header
	rc = dash_packager_build_fragment_header(
		state->base.request_context,
		state->base.media_set,
		state->base.segment_index,
		0,
		&header_extensions,
		FALSE,
		&fragment_header,
		&total_fragment_size);
	if (rc != VOD_OK)
	{
		vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0,
			"edash_packager_video_write_fragment_header: dash_packager_build_fragment_header failed %i", rc);
		return rc;
	}

	rc = state->base.segment_writer.write_head(
		state->base.segment_writer.context,
		fragment_header.data, 
		fragment_header.len, 
		&reuse_buffer);
	if (rc != VOD_OK)
	{
		vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0,
			"edash_packager_video_write_fragment_header: write_head failed %i", rc);
		return rc;
	}

	return VOD_OK;
}
Beispiel #3
0
static vod_status_t
edash_packager_audio_build_fragment_header(
	mp4_encrypt_state_t* state,
	bool_t size_only,
	vod_str_t* fragment_header,
	size_t* total_fragment_size)
{
	dash_fragment_header_extensions_t header_extensions;
	atom_writer_t auxiliary_data_writer;
	vod_status_t rc;

	auxiliary_data_writer.atom_size = MP4_ENCRYPT_IV_SIZE * state->sequence->total_frame_count;
	auxiliary_data_writer.write = (atom_writer_func_t)mp4_encrypt_audio_write_auxiliary_data;
	auxiliary_data_writer.context = state;

	header_extensions.extra_traf_atoms_size = state->saiz_atom_size + state->saio_atom_size;
	header_extensions.write_extra_traf_atoms_callback = (write_extra_traf_atoms_callback_t)mp4_encrypt_audio_write_saiz_saio;
	header_extensions.write_extra_traf_atoms_context = state;
	header_extensions.mdat_prefix_writer = &auxiliary_data_writer;

	rc = dash_packager_build_fragment_header(
		state->request_context,
		state->media_set,
		state->segment_index,
		0,
		&header_extensions,
		size_only,
		fragment_header,
		total_fragment_size);
	if (rc != VOD_OK)
	{
		vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0,
			"edash_packager_audio_build_fragment_header: dash_packager_build_fragment_header failed %i", rc);
		return rc;
	}

	return VOD_OK;
}
static vod_status_t
edash_packager_audio_build_fragment_header(
	mp4_encrypt_state_t* state,
	bool_t size_only,
	vod_str_t* fragment_header,
	size_t* total_fragment_size)
{
	dash_fragment_header_extensions_t header_extensions;
	vod_status_t rc;

	// get the header extensions
	header_extensions.extra_traf_atoms_size =
		state->saiz_atom_size + 
		state->saio_atom_size + 
		ATOM_HEADER_SIZE + sizeof(senc_atom_t) + MP4_AES_CTR_IV_SIZE * state->sequence->total_frame_count;
	header_extensions.write_extra_traf_atoms_callback = edash_packager_audio_write_encryption_atoms;
	header_extensions.write_extra_traf_atoms_context = state;

	// build the fragment header
	rc = dash_packager_build_fragment_header(
		state->request_context,
		state->media_set,
		state->segment_index,
		0,
		&header_extensions,
		size_only,
		fragment_header,
		total_fragment_size);
	if (rc != VOD_OK)
	{
		vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0,
			"edash_packager_audio_build_fragment_header: dash_packager_build_fragment_header failed %i", rc);
		return rc;
	}

	return VOD_OK;
}
vod_status_t
edash_packager_get_fragment_writer(
	segment_writer_t* result,
	request_context_t* request_context,
	media_set_t* media_set,
	uint32_t segment_index,
	segment_writer_t* segment_writer,
	const u_char* iv,
	bool_t size_only,
	vod_str_t* fragment_header,
	size_t* total_fragment_size)
{
	dash_fragment_header_extensions_t header_extensions;
	mp4_encrypt_passthrough_context_t passthrough_context;
	uint32_t media_type = media_set->sequences[0].media_type;
	vod_status_t rc;

	if (mp4_encrypt_passthrough_init(&passthrough_context, media_set->sequences))
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"edash_packager_get_fragment_writer: using encryption passthrough");

		// get the header extensions
		header_extensions.extra_traf_atoms_size = passthrough_context.total_size + ATOM_HEADER_SIZE + sizeof(senc_atom_t);
		header_extensions.write_extra_traf_atoms_callback = edash_packager_passthrough_write_encryption_atoms;
		header_extensions.write_extra_traf_atoms_context = &passthrough_context;

		// build the fragment header
		rc = dash_packager_build_fragment_header(
			request_context,
			media_set,
			segment_index,
			0,
			&header_extensions,
			size_only,
			fragment_header,
			total_fragment_size);
		if (rc != VOD_OK)
		{
			vod_log_debug1(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
				"edash_packager_get_fragment_writer: dash_packager_build_fragment_header failed %i", rc);
			return rc;
		}

		// use original writer
		vod_memzero(result, sizeof(*result));

		return VOD_OK;
	}

	switch (media_type)
	{
	case MEDIA_TYPE_VIDEO:
		return mp4_encrypt_video_get_fragment_writer(
			result, 
			request_context, 
			media_set, 
			segment_index, 
			edash_packager_video_build_fragment_header,
			segment_writer, 
			iv, 
			fragment_header,
			total_fragment_size);

	case MEDIA_TYPE_AUDIO:
		rc = mp4_encrypt_audio_get_fragment_writer(
			result, 
			request_context, 
			media_set,
			segment_index, 
			segment_writer, 
			iv);
		if (rc != VOD_OK)
		{
			return rc;
		}

		rc = edash_packager_audio_build_fragment_header(
			result->context,
			size_only,
			fragment_header,
			total_fragment_size);
		if (rc != VOD_OK)
		{
			return rc;
		}

		return VOD_OK;
	}

	vod_log_error(VOD_LOG_ERR, request_context->log, 0,
		"edash_packager_get_fragment_writer: invalid media type %uD", media_type);
	return VOD_UNEXPECTED;
}
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;
}