static bool_t dash_packager_compare_tracks(uintptr_t bitrate_threshold, const media_info_t* mi1, const media_info_t* mi2) { if (mi1->bitrate == 0 || mi2->bitrate == 0 || mi1->bitrate + bitrate_threshold <= mi2->bitrate || mi2->bitrate + bitrate_threshold <= mi1->bitrate) { return FALSE; } if (mi1->codec_name.len != mi2->codec_name.len || vod_memcmp(mi1->codec_name.data, mi2->codec_name.data, mi2->codec_name.len) != 0) { return FALSE; } if (mi1->media_type == MEDIA_TYPE_VIDEO) { return (mi1->u.video.width == mi2->u.video.width) && (mi1->u.video.height == mi2->u.video.height); } return TRUE; }
static u_char* edash_packager_write_content_protection(void* ctx, u_char* p, media_track_t* track) { write_content_protection_context_t* context = ctx; drm_info_t* drm_info = (drm_info_t*)track->file_info.drm_info; drm_system_info_t* cur_info; vod_str_t base64; vod_str_t pssh; p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC) - 1); for (cur_info = drm_info->pssh_array.first; cur_info < drm_info->pssh_array.last; cur_info++) { if (vod_memcmp(cur_info->system_id, edash_playready_system_id, sizeof(edash_playready_system_id)) == 0) { if (context->write_playready_kid) { p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART1, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART1) - 1); p = mp4_encrypt_write_guid(p, cur_info->system_id); p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART2, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART2) - 1); p = mp4_encrypt_write_guid(p, drm_info->key_id); } else { p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART1, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART1) - 1); p = mp4_encrypt_write_guid(p, cur_info->system_id); } p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART3, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART3) - 1); base64.data = p; vod_encode_base64(&base64, &cur_info->data); p += base64.len; p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART4, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART4) - 1); } else { p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART1, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART1) - 1); p = mp4_encrypt_write_guid(p, cur_info->system_id); p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART2, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART2) - 1); p = mp4_encrypt_write_guid(p, drm_info->key_id); p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART3, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART3) - 1); pssh.data = context->temp_buffer; pssh.len = edash_packager_write_pssh(pssh.data, cur_info) - pssh.data; base64.data = p; vod_encode_base64(&base64, &pssh); p += base64.len; p = vod_copy(p, VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART4, sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART4) - 1); } } return p; }
static int track_group_key_compare(track_group_key_t* key1, track_group_key_t* key2) { if (key1->codec_id != key2->codec_id) { return key1->codec_id < key2->codec_id ? -1 : 1; } if (key1->label.len != key2->label.len) { return key1->label.len < key2->label.len ? -1 : 1; } if (key1->label.data != key2->label.data) { return vod_memcmp(key1->label.data, key2->label.data, key1->label.len); } return 0; }
vod_status_t edash_packager_build_mpd( request_context_t* request_context, dash_manifest_config_t* conf, vod_str_t* base_url, media_set_t* media_set, vod_str_t* result) { media_sequence_t* cur_sequence; drm_system_info_t* cur_info; drm_info_t* drm_info; u_char* pssh_temp_buffer = NULL; size_t representation_tags_size; size_t cur_drm_tags_size; size_t cur_pssh_size; size_t max_pssh_size = 0; vod_status_t rc; representation_tags_size = 0; for (cur_sequence = media_set->sequences; cur_sequence < media_set->sequences_end; cur_sequence++) { drm_info = (drm_info_t*)cur_sequence->drm_info; cur_drm_tags_size = sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC) - 1; for (cur_info = drm_info->pssh_array.first; cur_info < drm_info->pssh_array.last; cur_info++) { if (vod_memcmp(cur_info->system_id, edash_playready_system_id, sizeof(edash_playready_system_id)) == 0) { cur_drm_tags_size += sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART1) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART2) - 1 + vod_base64_encoded_length(cur_info->data.len) + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART3) - 1; } else { cur_pssh_size = ATOM_HEADER_SIZE + sizeof(pssh_atom_t) + cur_info->data.len; if (cur_pssh_size > max_pssh_size) { max_pssh_size = cur_pssh_size; } cur_drm_tags_size += sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART1) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART2) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART3) - 1 + vod_base64_encoded_length(cur_pssh_size) + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART4) - 1; continue; } } representation_tags_size += cur_drm_tags_size * cur_sequence->total_track_count; } if (max_pssh_size > 0) { pssh_temp_buffer = vod_alloc(request_context->pool, max_pssh_size); if (pssh_temp_buffer == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "edash_packager_build_mpd: vod_alloc failed"); return VOD_ALLOC_FAILED; } } rc = dash_packager_build_mpd( request_context, conf, base_url, media_set, representation_tags_size, edash_packager_write_content_protection, pssh_temp_buffer, result); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "edash_packager_build_mpd: dash_packager_build_mpd failed %i", rc); return rc; } return VOD_OK; }
vod_status_t edash_packager_build_mpd( request_context_t* request_context, dash_manifest_config_t* conf, vod_str_t* base_url, media_set_t* media_set, bool_t drm_single_key, vod_str_t* result) { write_content_protection_context_t context; dash_manifest_extensions_t extensions; media_sequence_t* cur_sequence; drm_system_info_t* cur_info; tags_writer_t content_prot_writer; drm_info_t* drm_info; size_t representation_tags_size; size_t cur_drm_tags_size; size_t cur_pssh_size; size_t max_pssh_size = 0; vod_status_t rc; representation_tags_size = 0; for (cur_sequence = media_set->sequences; cur_sequence < media_set->sequences_end; cur_sequence++) { drm_info = (drm_info_t*)cur_sequence->drm_info; cur_drm_tags_size = sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC) - 1; for (cur_info = drm_info->pssh_array.first; cur_info < drm_info->pssh_array.last; cur_info++) { if (vod_memcmp(cur_info->system_id, edash_playready_system_id, sizeof(edash_playready_system_id)) == 0) { cur_drm_tags_size += sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART1) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_V2_PART2) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART3) - 1 + vod_base64_encoded_length(cur_info->data.len) + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_PLAYREADY_PART4) - 1; } else { cur_pssh_size = ATOM_HEADER_SIZE + sizeof(pssh_atom_t) + cur_info->data.len; if (cur_pssh_size > max_pssh_size) { max_pssh_size = cur_pssh_size; } cur_drm_tags_size += sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART1) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART2) - 1 + VOD_GUID_LENGTH + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART3) - 1 + vod_base64_encoded_length(cur_pssh_size) + sizeof(VOD_EDASH_MANIFEST_CONTENT_PROTECTION_CENC_PART4) - 1; continue; } } representation_tags_size += cur_drm_tags_size * cur_sequence->total_track_count; } context.write_playready_kid = conf->write_playready_kid; if (max_pssh_size > 0) { context.temp_buffer = vod_alloc(request_context->pool, max_pssh_size); if (context.temp_buffer == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "edash_packager_build_mpd: vod_alloc failed"); return VOD_ALLOC_FAILED; } } content_prot_writer.size = representation_tags_size; content_prot_writer.write = edash_packager_write_content_protection; content_prot_writer.context = &context; if (drm_single_key) { // write the ContentProtection tags under AdaptationSet extensions.adaptation_set = content_prot_writer; vod_memzero(&extensions.representation, sizeof(extensions.representation)); } else { // write the ContentProtection tags under Representation vod_memzero(&extensions.adaptation_set, sizeof(extensions.adaptation_set)); extensions.representation = content_prot_writer; } rc = dash_packager_build_mpd( request_context, conf, base_url, media_set, &extensions, result); if (rc != VOD_OK) { vod_log_debug1(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "edash_packager_build_mpd: dash_packager_build_mpd failed %i", rc); return rc; } return VOD_OK; }