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); }
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; }
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; }