static vod_status_t mss_playready_audio_build_fragment_header( mp4_encrypt_state_t* state, bool_t size_only, vod_str_t* fragment_header, size_t* total_fragment_size) { vod_status_t rc; mss_playready_audio_extra_traf_atoms_context writer_context; writer_context.uuid_piff_atom_size = ATOM_HEADER_SIZE + sizeof(uuid_piff_atom_t) + mp4_encrypt_audio_get_auxiliary_data_size(state); writer_context.state = state; rc = mss_packager_build_fragment_header( state->request_context, state->media_set, state->segment_index, writer_context.uuid_piff_atom_size + state->saiz_atom_size + state->saio_atom_size, mss_playready_audio_write_extra_traf_atoms, &writer_context, size_only, fragment_header, total_fragment_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0, "mss_playready_audio_build_fragment_header: mss_packager_build_fragment_header failed %i", rc); return rc; } return VOD_OK; }
static vod_status_t mss_playready_video_write_fragment_header(mp4_encrypt_video_state_t* state) { mss_playready_video_extra_traf_atoms_context writer_context; vod_str_t fragment_header; size_t total_fragment_size; bool_t reuse_buffer; vod_status_t rc; writer_context.uuid_piff_atom_size = ATOM_HEADER_SIZE + sizeof(uuid_piff_atom_t) + state->auxiliary_data.pos - state->auxiliary_data.start; writer_context.state = state; rc = mss_packager_build_fragment_header( state->base.request_context, state->base.sequence, state->base.segment_index, writer_context.uuid_piff_atom_size + state->base.saiz_atom_size + state->base.saio_atom_size, mss_playready_video_write_extra_traf_atoms, &writer_context, FALSE, &fragment_header, &total_fragment_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0, "mss_playready_video_write_fragment_header: mss_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, "mss_playready_video_write_fragment_header: write_head failed %i", rc); return rc; } return VOD_OK; }
vod_status_t mss_playready_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) { 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, "mss_playready_get_fragment_writer: using encryption passthrough"); // build the fragment header rc = mss_packager_build_fragment_header( request_context, media_set, segment_index, passthrough_context.total_size + ATOM_HEADER_SIZE + sizeof(uuid_piff_atom_t), mss_playready_passthrough_write_encryption_atoms, &passthrough_context, size_only, fragment_header, total_fragment_size); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "mss_playready_get_fragment_writer: mss_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, mss_playready_video_write_fragment_header, segment_writer, iv); 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 = mss_playready_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, "mss_playready_get_fragment_writer: invalid media type %uD", media_type); return VOD_UNEXPECTED; }
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; }
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; }