/src/gpac/src/media_tools/crypt_tools.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2024 |
6 | | * All rights reserved |
7 | | * |
8 | | * This file is part of GPAC / Media Tools sub-project |
9 | | * |
10 | | * GPAC is free software; you can redistribute it and/or modify |
11 | | * it under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2, or (at your option) |
13 | | * any later version. |
14 | | * |
15 | | * GPAC is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; see the file COPYING. If not, write to |
22 | | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | | * |
24 | | */ |
25 | | |
26 | | |
27 | | |
28 | | #include <gpac/crypt_tools.h> |
29 | | #include <gpac/xml.h> |
30 | | #include <gpac/base_coding.h> |
31 | | #include <gpac/constants.h> |
32 | | #include <gpac/filters.h> |
33 | | #include <gpac/network.h> |
34 | | |
35 | | |
36 | | #if !defined(GPAC_DISABLE_CRYPTO) |
37 | | |
38 | | static u32 cryptinfo_get_crypt_type(char *cr_type) |
39 | 0 | { |
40 | 0 | if (!stricmp(cr_type, "ISMA") || !stricmp(cr_type, "iAEC")) |
41 | 0 | return GF_CRYPT_TYPE_ISMA; |
42 | 0 | else if (!stricmp(cr_type, "CENC AES-CTR") || !stricmp(cr_type, "cenc")) |
43 | 0 | return GF_CRYPT_TYPE_CENC; |
44 | 0 | else if (!stricmp(cr_type, "piff")) |
45 | 0 | return GF_CRYPT_TYPE_PIFF; |
46 | 0 | else if (!stricmp(cr_type, "CENC AES-CBC") || !stricmp(cr_type, "cbc1")) |
47 | 0 | return GF_CRYPT_TYPE_CBC1; |
48 | 0 | else if (!stricmp(cr_type, "ADOBE") || !stricmp(cr_type, "adkm")) |
49 | 0 | return GF_CRYPT_TYPE_ADOBE; |
50 | 0 | else if (!stricmp(cr_type, "CENC AES-CTR Pattern") || !stricmp(cr_type, "cens")) |
51 | 0 | return GF_CRYPT_TYPE_CENS; |
52 | 0 | else if (!stricmp(cr_type, "CENC AES-CBC Pattern") || !stricmp(cr_type, "cbcs")) |
53 | 0 | return GF_CRYPT_TYPE_CBCS; |
54 | 0 | else if (!stricmp(cr_type, "OMA")) |
55 | 0 | return GF_ISOM_OMADRM_SCHEME; |
56 | 0 | else if (!stricmp(cr_type, "HLS SAES")) |
57 | 0 | return GF_HLS_SAMPLE_AES_SCHEME; |
58 | | |
59 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Unrecognized crypto type %s\n", cr_type)); |
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | | static void cryptinfo_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes) |
64 | 0 | { |
65 | 0 | GF_XMLAttribute *att; |
66 | 0 | GF_TrackCryptInfo *tkc; |
67 | 0 | u32 i; |
68 | 0 | GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck; |
69 | |
|
70 | 0 | if (!strcmp(node_name, "OMATextHeader")) { |
71 | 0 | info->in_text_header = 1; |
72 | 0 | return; |
73 | 0 | } |
74 | 0 | if (!strcmp(node_name, "GPACDRM")) { |
75 | 0 | for (i=0; i<nb_attributes; i++) { |
76 | 0 | att = (GF_XMLAttribute *) &attributes[i]; |
77 | 0 | if (!stricmp(att->name, "type")) { |
78 | 0 | info->def_crypt_type = cryptinfo_get_crypt_type(att->value); |
79 | 0 | } |
80 | 0 | } |
81 | 0 | return; |
82 | 0 | } |
83 | | |
84 | | |
85 | 0 | if (!strcmp(node_name, "CrypTrack")) { |
86 | 0 | Bool has_key = GF_FALSE; |
87 | 0 | Bool has_common_key = GF_TRUE; |
88 | 0 | GF_SAFEALLOC(tkc, GF_TrackCryptInfo); |
89 | 0 | if (!tkc) { |
90 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Cannnot allocate crypt track, skipping\n")); |
91 | 0 | info->last_parse_error = GF_OUT_OF_MEM; |
92 | 0 | return; |
93 | 0 | } |
94 | | //by default track is encrypted |
95 | 0 | tkc->IsEncrypted = 1; |
96 | 0 | tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC; |
97 | 0 | tkc->scheme_type = info->def_crypt_type; |
98 | | |
99 | | //allocate a key to store the default values in single-key mode |
100 | 0 | tkc->keys = gf_malloc(sizeof(GF_CryptKeyInfo)); |
101 | 0 | if (!tkc->keys) { |
102 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Cannnot allocate key IDs\n")); |
103 | 0 | gf_free(tkc); |
104 | 0 | info->last_parse_error = GF_OUT_OF_MEM; |
105 | 0 | return; |
106 | 0 | } |
107 | 0 | memset(tkc->keys, 0, sizeof(GF_CryptKeyInfo)); |
108 | 0 | gf_list_add(info->tcis, tkc); |
109 | |
|
110 | 0 | for (i=0; i<nb_attributes; i++) { |
111 | 0 | att = (GF_XMLAttribute *) &attributes[i]; |
112 | 0 | if (!stricmp(att->name, "trackID") || !stricmp(att->name, "ID")) { |
113 | 0 | if (!strcmp(att->value, "*")) info->has_common_key = 1; |
114 | 0 | else { |
115 | 0 | tkc->trackID = atoi(att->value); |
116 | 0 | has_common_key = GF_FALSE; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | else if (!stricmp(att->name, "type")) { |
120 | 0 | tkc->scheme_type = cryptinfo_get_crypt_type(att->value); |
121 | 0 | } |
122 | 0 | else if (!stricmp(att->name, "forceType")) { |
123 | 0 | tkc->force_type = GF_TRUE; |
124 | 0 | } |
125 | 0 | else if (!stricmp(att->name, "key")) { |
126 | 0 | GF_Err e; |
127 | 0 | has_key = GF_TRUE; |
128 | 0 | e = gf_bin128_parse(att->value, tkc->keys[0].key ); |
129 | 0 | if (e != GF_OK) { |
130 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Cannnot parse key value in CrypTrack\n")); |
131 | 0 | info->last_parse_error = GF_BAD_PARAM; |
132 | 0 | return; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | else if (!stricmp(att->name, "salt")) { |
136 | 0 | u32 len, j; |
137 | 0 | char *sKey = att->value; |
138 | 0 | if (!strnicmp(sKey, "0x", 2)) sKey += 2; |
139 | 0 | len = (u32) strlen(sKey); |
140 | 0 | for (j=0; j<len; j+=2) { |
141 | 0 | char szV[5]; |
142 | 0 | u32 v; |
143 | 0 | sprintf(szV, "%c%c", sKey[j], sKey[j+1]); |
144 | 0 | sscanf(szV, "%x", &v); |
145 | 0 | tkc->keys[0].IV[j/2] = v; |
146 | 0 | if (j>=30) break; |
147 | 0 | } |
148 | 0 | } |
149 | 0 | else if (!stricmp(att->name, "kms_URI") || !stricmp(att->name, "rightsIssuerURL")) { |
150 | 0 | if (tkc->KMS_URI) gf_free(tkc->KMS_URI); |
151 | 0 | tkc->KMS_URI = gf_strdup(att->value); |
152 | 0 | } |
153 | 0 | else if (!stricmp(att->name, "scheme_URI") || !stricmp(att->name, "contentID")) { |
154 | 0 | if (tkc->Scheme_URI) gf_free(tkc->Scheme_URI); |
155 | 0 | tkc->Scheme_URI = gf_strdup(att->value); |
156 | 0 | } |
157 | 0 | else if (!stricmp(att->name, "selectiveType")) { |
158 | 0 | if (!stricmp(att->value, "Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAP; |
159 | 0 | else if (!stricmp(att->value, "Non-Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_NON_RAP; |
160 | 0 | else if (!stricmp(att->value, "Rand")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAND; |
161 | 0 | else if (!strnicmp(att->value, "Rand", 4)) { |
162 | 0 | tkc->sel_enc_type = GF_CRYPT_SELENC_RAND_RANGE; |
163 | 0 | tkc->sel_enc_range = atoi(&att->value[4]); |
164 | 0 | } |
165 | 0 | else if (sscanf(att->value, "%u", &tkc->sel_enc_range)==1) { |
166 | 0 | if (tkc->sel_enc_range==1) tkc->sel_enc_range = 0; |
167 | 0 | else tkc->sel_enc_type = GF_CRYPT_SELENC_RANGE; |
168 | 0 | } |
169 | 0 | else if (!strnicmp(att->value, "Preview", 7)) { |
170 | 0 | tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW; |
171 | 0 | } |
172 | 0 | else if (!strnicmp(att->value, "Clear", 5)) { |
173 | 0 | tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR; |
174 | 0 | } |
175 | 0 | else if (!strnicmp(att->value, "ForceClear", 10)) { |
176 | 0 | char *sep = strchr(att->value, '='); |
177 | 0 | tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR_FORCED; |
178 | 0 | if (sep) { |
179 | 0 | tkc->sel_enc_range = atoi(sep+1); |
180 | | //if set to 0, move to no selective encryption |
181 | 0 | if (!tkc->sel_enc_range) tkc->sel_enc_type = GF_CRYPT_SELENC_NONE; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | else if (!stricmp(att->value, "None")) { |
185 | 0 | } else { |
186 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized selective mode %s, ignoring\n", att->value)); |
187 | 0 | } |
188 | 0 | } |
189 | 0 | else if (!stricmp(att->name, "clearStsd")) { |
190 | 0 | if (!strcmp(att->value, "none")) tkc->force_clear_stsd_idx = 0; |
191 | 0 | else if (!strcmp(att->value, "before")) tkc->force_clear_stsd_idx = 1; |
192 | 0 | else if (!strcmp(att->value, "after")) tkc->force_clear_stsd_idx = 2; |
193 | 0 | else { |
194 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized clear stsd type %s, defaulting to no stsd for clear samples\n", att->value)); |
195 | 0 | } |
196 | 0 | } |
197 | 0 | else if (!stricmp(att->name, "Preview")) { |
198 | 0 | tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW; |
199 | 0 | sscanf(att->value, "%u", &tkc->sel_enc_range); |
200 | 0 | } |
201 | 0 | else if (!stricmp(att->name, "ipmpType")) { |
202 | 0 | if (!stricmp(att->value, "None")) tkc->ipmp_type = 0; |
203 | 0 | else if (!stricmp(att->value, "IPMP")) tkc->sel_enc_type = 1; |
204 | 0 | else if (!stricmp(att->value, "IPMPX")) tkc->sel_enc_type = 2; |
205 | 0 | } |
206 | 0 | else if (!stricmp(att->name, "ipmpDescriptorID")) tkc->ipmp_desc_id = atoi(att->value); |
207 | 0 | else if (!stricmp(att->name, "encryptionMethod")) { |
208 | 0 | if (!strcmp(att->value, "AES_128_CBC")) tkc->encryption = 1; |
209 | 0 | else if (!strcmp(att->value, "None")) tkc->encryption = 0; |
210 | 0 | else if (!strcmp(att->value, "AES_128_CTR") || !strcmp(att->value, "default")) tkc->encryption = 2; |
211 | 0 | else { |
212 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized encryption algo %s, ignoring\n", att->value)); |
213 | 0 | } |
214 | 0 | } |
215 | 0 | else if (!stricmp(att->name, "transactionID")) { |
216 | 0 | if (strlen(att->value)<=16) strcpy(tkc->TransactionID, att->value); |
217 | 0 | } |
218 | 0 | else if (!stricmp(att->name, "textualHeaders")) { |
219 | 0 | } |
220 | 0 | else if (!stricmp(att->name, "IsEncrypted")) { |
221 | 0 | if (!stricmp(att->value, "1")) |
222 | 0 | tkc->IsEncrypted = 1; |
223 | 0 | else |
224 | 0 | tkc->IsEncrypted = 0; |
225 | 0 | } |
226 | 0 | else if (!stricmp(att->name, "IV_size") && (tkc->scheme_type != GF_CRYPT_TYPE_CBCS)) { |
227 | 0 | tkc->keys[0].IV_size = atoi(att->value); |
228 | 0 | } |
229 | 0 | else if (!stricmp(att->name, "first_IV") && (tkc->scheme_type != GF_CRYPT_TYPE_CBCS)) { |
230 | 0 | char *sKey = att->value; |
231 | 0 | if (!strnicmp(sKey, "0x", 2)) sKey += 2; |
232 | 0 | if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) { |
233 | 0 | u32 j; |
234 | 0 | for (j=0; j<strlen(sKey); j+=2) { |
235 | 0 | u32 v; |
236 | 0 | char szV[5]; |
237 | 0 | sprintf(szV, "%c%c", sKey[j], sKey[j+1]); |
238 | 0 | sscanf(szV, "%x", &v); |
239 | 0 | tkc->keys[0].IV[j/2] = v; |
240 | 0 | } |
241 | 0 | if (!tkc->keys[0].IV_size) tkc->keys[0].IV_size = (u8) strlen(sKey) / 2; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | else if (!stricmp(att->name, "saiSavedBox")) { |
245 | 0 | if (!stricmp(att->value, "uuid_psec")) tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC; |
246 | 0 | else if (!stricmp(att->value, "senc")) tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC; |
247 | 0 | else { |
248 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized SAI location %s, ignoring\n", att->value)); |
249 | 0 | } |
250 | 0 | } |
251 | 0 | else if (!stricmp(att->name, "keyRoll")) { |
252 | 0 | if (!strncmp(att->value, "idx=", 4)) |
253 | 0 | tkc->defaultKeyIdx = atoi(att->value+4); |
254 | 0 | else if (!strncmp(att->value, "roll", 4) || !strncmp(att->value, "samp", 4)) { |
255 | 0 | tkc->roll_type = GF_KEYROLL_SAMPLES; |
256 | 0 | if (att->value[4]=='=') tkc->keyRoll = atoi(att->value+5); |
257 | 0 | if (!tkc->keyRoll) tkc->keyRoll = 1; |
258 | 0 | } |
259 | 0 | else if (!strncmp(att->value, "seg", 3)) { |
260 | 0 | tkc->roll_type = GF_KEYROLL_SEGMENTS; |
261 | 0 | if (att->value[3]=='=') tkc->keyRoll = atoi(att->value+4); |
262 | 0 | if (!tkc->keyRoll) tkc->keyRoll = 1; |
263 | 0 | } else if (!strncmp(att->value, "period", 6)) { |
264 | 0 | tkc->roll_type = GF_KEYROLL_PERIODS; |
265 | 0 | if (att->value[6]=='=') tkc->keyRoll = atoi(att->value+7); |
266 | 0 | if (!tkc->keyRoll) tkc->keyRoll = 1; |
267 | 0 | } else if (!strcmp(att->value, "rap")) { |
268 | 0 | tkc->roll_type = GF_KEYROLL_SAPS; |
269 | 0 | if (att->value[3]=='=') tkc->keyRoll = atoi(att->value+4); |
270 | 0 | if (!tkc->keyRoll) tkc->keyRoll = 1; |
271 | 0 | } else { |
272 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized roll parameter %s, ignoring\n", att->value)); |
273 | 0 | } |
274 | 0 | } |
275 | 0 | else if (!stricmp(att->name, "random")) { |
276 | 0 | if (!strcmp(att->value, "true") || !strcmp(att->value, "1") || !strcmp(att->value, "yes")) { |
277 | 0 | tkc->rand_keys=GF_TRUE; |
278 | 0 | } |
279 | 0 | else if (!strcmp(att->value, "false") || !strcmp(att->value, "0") || !strcmp(att->value, "no")) { |
280 | 0 | tkc->rand_keys=GF_FALSE; |
281 | 0 | } |
282 | 0 | else { |
283 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Unrecognized random parameter %s, ignoring\n", att->value)); |
284 | 0 | } |
285 | 0 | } |
286 | 0 | else if (!stricmp(att->name, "metadata")) { |
287 | 0 | u32 l = 2 * (u32) strlen(att->value) + 3; |
288 | 0 | tkc->metadata = gf_malloc(sizeof(char) * l); |
289 | 0 | l = gf_base64_encode(att->value, (u32) strlen(att->value), tkc->metadata, l); |
290 | 0 | tkc->metadata[l] = 0; |
291 | 0 | } |
292 | 0 | else if (!stricmp(att->name, "crypt_byte_block")) { |
293 | 0 | tkc->crypt_byte_block = atoi(att->value); |
294 | 0 | } |
295 | 0 | else if (!stricmp(att->name, "skip_byte_block")) { |
296 | 0 | tkc->skip_byte_block = atoi(att->value); |
297 | 0 | } |
298 | 0 | else if (!stricmp(att->name, "clear_bytes")) { |
299 | 0 | tkc->clear_bytes = atoi(att->value); |
300 | 0 | } |
301 | 0 | else if (!stricmp(att->name, "byte_offset")) { |
302 | 0 | tkc->crypt_byte_offset = atoi(att->value); |
303 | 0 | } |
304 | 0 | else if (!stricmp(att->name, "constant_IV_size") |
305 | 0 | || (!stricmp(att->name, "IV_size") && (tkc->scheme_type == GF_CRYPT_TYPE_CBCS)) |
306 | 0 | ) { |
307 | 0 | tkc->keys[0].constant_IV_size = atoi(att->value); |
308 | 0 | if ((tkc->keys[0].constant_IV_size != 8) && (tkc->keys[0].constant_IV_size != 16)) { |
309 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Constant IV size %d is not 8 or 16\n", att->value)); |
310 | 0 | info->last_parse_error = GF_BAD_PARAM; |
311 | 0 | } |
312 | 0 | } |
313 | 0 | else if (!stricmp(att->name, "constant_IV") |
314 | 0 | || (!stricmp(att->name, "first_IV") && (tkc->scheme_type == GF_CRYPT_TYPE_CBCS)) |
315 | 0 | ) { |
316 | 0 | char *sKey = att->value; |
317 | 0 | if (!strnicmp(sKey, "0x", 2)) sKey += 2; |
318 | 0 | if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) { |
319 | 0 | u32 j; |
320 | 0 | for (j=0; j<strlen(sKey); j+=2) { |
321 | 0 | u32 v; |
322 | 0 | char szV[5]; |
323 | 0 | sprintf(szV, "%c%c", sKey[j], sKey[j+1]); |
324 | 0 | sscanf(szV, "%x", &v); |
325 | 0 | tkc->keys[0].IV[j/2] = v; |
326 | 0 | } |
327 | 0 | if (!tkc->keys[0].constant_IV_size) tkc->keys[0].constant_IV_size = (u8) strlen(sKey) / 2; |
328 | 0 | } |
329 | 0 | } |
330 | 0 | else if (!stricmp(att->name, "encryptSliceHeader")) { |
331 | 0 | tkc->allow_encrypted_slice_header = !strcmp(att->value, "yes") ? GF_TRUE : GF_FALSE; |
332 | 0 | } |
333 | 0 | else if (!stricmp(att->name, "encryptNonVCLs")) { |
334 | 0 | if (!strcmp(att->value, "yes")) |
335 | 0 | tkc->allow_encrypted_nonVCLs = GF_CRYPT_NONVCL_CLEAR_NONE; |
336 | 0 | else if (!strcmp(att->value, "no")) |
337 | 0 | tkc->allow_encrypted_nonVCLs = GF_CRYPT_NONVCL_CLEAR_ALL; |
338 | 0 | else |
339 | 0 | tkc->allow_encrypted_nonVCLs = GF_CRYPT_NONVCL_CLEAR_SEI_AUD; |
340 | 0 | } |
341 | 0 | else if (!stricmp(att->name, "blockAlign")) { |
342 | 0 | if (!strcmp(att->value, "disable")) tkc->block_align = 1; |
343 | 0 | else if (!strcmp(att->value, "always")) tkc->block_align = 2; |
344 | 0 | else tkc->block_align = 0; |
345 | 0 | } |
346 | 0 | else if (!stricmp(att->name, "subsamples")) { |
347 | 0 | char *val = att->value; |
348 | 0 | while (val) { |
349 | 0 | char *sep = strchr(val, ';'); |
350 | 0 | if (sep) sep[0] = 0; |
351 | 0 | if (!strncmp(val, "subs=", 5)) { |
352 | 0 | if (tkc->subs_crypt) gf_free(tkc->subs_crypt); |
353 | 0 | tkc->subs_crypt = gf_strdup(val+4); |
354 | 0 | } |
355 | 0 | else if (!strncmp(val, "rand", 4)) { |
356 | 0 | tkc->subs_rand = 2; |
357 | 0 | if (val[4]=='=') |
358 | 0 | tkc->subs_rand = atoi(val+5); |
359 | 0 | } |
360 | 0 | else { |
361 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] unrecognized attribute value %s for `subsamples`, ignoring\n", val)); |
362 | 0 | } |
363 | 0 | if (!sep) break; |
364 | 0 | sep[0] = ';'; |
365 | 0 | val = sep+1; |
366 | 0 | } |
367 | 0 | } |
368 | 0 | else if (!stricmp(att->name, "multiKey")) { |
369 | 0 | if (!strcmp(att->value, "all") || !strcmp(att->value, "on")) tkc->multi_key = GF_TRUE; |
370 | 0 | else if (!strcmp(att->value, "no")) tkc->multi_key = GF_FALSE; |
371 | 0 | else { |
372 | 0 | char *val = att->value; |
373 | 0 | tkc->multi_key = GF_TRUE; |
374 | 0 | while (val) { |
375 | 0 | char *sep = strchr(val, ';'); |
376 | 0 | if (sep) sep[0] = 0; |
377 | 0 | if (!strncmp(val, "roll=", 5)) { |
378 | 0 | tkc->mkey_roll_plus_one = 1 + atoi(val+5); |
379 | 0 | } |
380 | 0 | else if (!strncmp(val, "subs=", 5)) { |
381 | 0 | if (tkc->mkey_subs) gf_free(tkc->mkey_subs); |
382 | 0 | tkc->mkey_subs = gf_strdup(val+5); |
383 | 0 | } |
384 | 0 | else { |
385 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] unrecognized attribute value %s for `multiKey`, ignoring\n", val)); |
386 | 0 | tkc->multi_key = GF_FALSE; |
387 | 0 | if (sep) sep[0] = ';'; |
388 | 0 | break; |
389 | 0 | } |
390 | 0 | if (!sep) break; |
391 | 0 | sep[0] = ';'; |
392 | 0 | val = sep+1; |
393 | 0 | } |
394 | 0 | } |
395 | 0 | } |
396 | 0 | } |
397 | 0 | if (tkc->scheme_type==GF_CRYPT_TYPE_PIFF) { |
398 | 0 | tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC; |
399 | 0 | } |
400 | 0 | if (has_common_key) info->has_common_key = 1; |
401 | |
|
402 | 0 | if ((tkc->keys[0].IV_size != 0) && (tkc->keys[0].IV_size != 8) && (tkc->keys[0].IV_size != 16)) { |
403 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] wrong IV size %d for AES-128, using 16\n", (u32) tkc->keys[0].IV_size)); |
404 | 0 | tkc->keys[0].IV_size = 16; |
405 | 0 | } |
406 | |
|
407 | 0 | if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1)) { |
408 | 0 | if (tkc->crypt_byte_block || tkc->skip_byte_block) { |
409 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Using scheme type %s, crypt_byte_block and skip_byte_block shall be 0\n", gf_4cc_to_str(tkc->scheme_type) )); |
410 | 0 | tkc->crypt_byte_block = tkc->skip_byte_block = 0; |
411 | 0 | } |
412 | 0 | } |
413 | |
|
414 | 0 | if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1) || (tkc->scheme_type == GF_CRYPT_TYPE_CENS)) { |
415 | 0 | if (tkc->keys[0].constant_IV_size) { |
416 | 0 | if (!tkc->keys[0].IV_size) { |
417 | 0 | tkc->keys[0].IV_size = tkc->keys[0].constant_IV_size; |
418 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Using scheme type %s, constant IV shall not be used, using constant IV as first IV\n", gf_4cc_to_str(tkc->scheme_type))); |
419 | 0 | tkc->keys[0].constant_IV_size = 0; |
420 | 0 | } else { |
421 | 0 | tkc->keys[0].constant_IV_size = 0; |
422 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] Using scheme type %s, constant IV shall not be used, ignoring\n", gf_4cc_to_str(tkc->scheme_type))); |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | 0 | if (tkc->scheme_type == GF_ISOM_OMADRM_SCHEME) { |
427 | | /*default to AES 128 in OMA*/ |
428 | 0 | tkc->encryption = 2; |
429 | 0 | } |
430 | |
|
431 | 0 | if (has_key) tkc->nb_keys = 1; |
432 | 0 | } |
433 | | |
434 | 0 | if (!strcmp(node_name, "key")) { |
435 | 0 | u32 IV_size, const_IV_size; |
436 | 0 | Bool kas_civ = GF_FALSE; |
437 | 0 | tkc = (GF_TrackCryptInfo *)gf_list_last(info->tcis); |
438 | 0 | if (!tkc) return; |
439 | | //only realloc for 2nd and more |
440 | 0 | if (tkc->nb_keys) { |
441 | 0 | tkc->keys = (GF_CryptKeyInfo *)gf_realloc(tkc->keys, sizeof(GF_CryptKeyInfo)*(tkc->nb_keys+1)); |
442 | 0 | memset(&tkc->keys[tkc->nb_keys], 0, sizeof(GF_CryptKeyInfo)); |
443 | 0 | } |
444 | 0 | IV_size = tkc->keys[0].IV_size; |
445 | 0 | const_IV_size = tkc->keys[0].constant_IV_size; |
446 | |
|
447 | 0 | for (i=0; i<nb_attributes; i++) { |
448 | 0 | att = (GF_XMLAttribute *) &attributes[i]; |
449 | |
|
450 | 0 | if (!stricmp(att->name, "KID")) { |
451 | 0 | GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->nb_keys].KID); |
452 | 0 | if (e != GF_OK) { |
453 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Cannnot parse KID\n")); |
454 | 0 | info->last_parse_error = GF_BAD_PARAM; |
455 | 0 | return; |
456 | 0 | } |
457 | 0 | } |
458 | 0 | else if (!stricmp(att->name, "value")) { |
459 | 0 | GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->nb_keys].key); |
460 | 0 | if (e != GF_OK) { |
461 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Cannnot parse key value\n")); |
462 | 0 | info->last_parse_error = GF_BAD_PARAM; |
463 | 0 | return; |
464 | 0 | } |
465 | 0 | } |
466 | 0 | else if (!stricmp(att->name, "hlsInfo")) { |
467 | 0 | if (!strstr(att->value, "URI=\"")) { |
468 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[CENC] Missing URI in HLS info %s\n", att->value)); |
469 | 0 | info->last_parse_error = GF_BAD_PARAM; |
470 | 0 | return; |
471 | 0 | } |
472 | 0 | if (tkc->keys[tkc->nb_keys].hls_info) gf_free(tkc->keys[tkc->nb_keys].hls_info); |
473 | 0 | tkc->keys[tkc->nb_keys].hls_info = gf_strdup(att->value); |
474 | 0 | } |
475 | 0 | else if (!stricmp(att->name, "IV_size")) { |
476 | 0 | IV_size = atoi(att->value); |
477 | 0 | } |
478 | 0 | else if (!stricmp(att->name, "constant_IV")) { |
479 | 0 | char *sKey = att->value; |
480 | 0 | if (!strnicmp(sKey, "0x", 2)) sKey += 2; |
481 | 0 | if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) { |
482 | 0 | u32 j; |
483 | 0 | for (j=0; j<strlen(sKey); j+=2) { |
484 | 0 | u32 v; |
485 | 0 | char szV[5]; |
486 | 0 | sprintf(szV, "%c%c", sKey[j], sKey[j+1]); |
487 | 0 | sscanf(szV, "%x", &v); |
488 | 0 | tkc->keys[tkc->nb_keys].IV[j/2] = v; |
489 | 0 | } |
490 | 0 | const_IV_size = (u8) strlen(sKey) / 2; |
491 | 0 | kas_civ = GF_TRUE; |
492 | 0 | } |
493 | 0 | } |
494 | 0 | else if (!stricmp(att->name, "rep")) { |
495 | 0 | if (tkc->keys[tkc->nb_keys].repID) gf_free(tkc->keys[tkc->nb_keys].repID); |
496 | 0 | tkc->keys[tkc->nb_keys].repID = gf_strdup(att->value); |
497 | 0 | } |
498 | 0 | else if (!stricmp(att->name, "period")) { |
499 | 0 | if (tkc->keys[tkc->nb_keys].periodID) gf_free(tkc->keys[tkc->nb_keys].periodID); |
500 | 0 | tkc->keys[tkc->nb_keys].periodID = gf_strdup(att->value); |
501 | 0 | } |
502 | 0 | else if (!stricmp(att->name, "as")) { |
503 | 0 | tkc->keys[tkc->nb_keys].ASID = atoi(att->value); |
504 | 0 | } else { |
505 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[CENC] unrecognized attribute %s for `key`, ignoring\n", att->name)); |
506 | 0 | } |
507 | 0 | } |
508 | 0 | tkc->keys[tkc->nb_keys].IV_size = IV_size; |
509 | 0 | tkc->keys[tkc->nb_keys].constant_IV_size = const_IV_size; |
510 | 0 | if (!kas_civ && tkc->nb_keys) |
511 | 0 | memcpy(tkc->keys[tkc->nb_keys].IV, tkc->keys[0].IV, 16); |
512 | 0 | tkc->nb_keys++; |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | | static void cryptinfo_node_end(void *sax_cbck, const char *node_name, const char *name_space) |
517 | 0 | { |
518 | 0 | GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck; |
519 | 0 | if (!strcmp(node_name, "OMATextHeader")) { |
520 | 0 | info->in_text_header = 0; |
521 | 0 | return; |
522 | 0 | } |
523 | 0 | } |
524 | | |
525 | | static void cryptinfo_text(void *sax_cbck, const char *text, Bool is_cdata) |
526 | 0 | { |
527 | 0 | u32 len, len2; |
528 | 0 | GF_TrackCryptInfo *tkc; |
529 | 0 | GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck; |
530 | |
|
531 | 0 | if (!info->in_text_header) return; |
532 | | |
533 | 0 | tkc = (GF_TrackCryptInfo *) gf_list_last(info->tcis); |
534 | 0 | len = (u32) strlen(text); |
535 | 0 | len2 = tkc->TextualHeaders ? (u32) strlen(tkc->TextualHeaders) : 0; |
536 | |
|
537 | 0 | tkc->TextualHeaders = gf_realloc(tkc->TextualHeaders, sizeof(char) * (len+len2+1)); |
538 | 0 | if (!len2) strcpy(tkc->TextualHeaders, ""); |
539 | 0 | strcat(tkc->TextualHeaders, text); |
540 | 0 | } |
541 | | |
542 | | void gf_crypt_info_del(GF_CryptInfo *info) |
543 | 0 | { |
544 | 0 | while (gf_list_count(info->tcis)) { |
545 | 0 | u32 i; |
546 | 0 | GF_TrackCryptInfo *tci = (GF_TrackCryptInfo *)gf_list_last(info->tcis); |
547 | 0 | for (i=0; i<tci->nb_keys; i++) { |
548 | 0 | if (tci->keys[i].hls_info) |
549 | 0 | gf_free(tci->keys[i].hls_info); |
550 | 0 | if (tci->keys[i].repID) |
551 | 0 | gf_free(tci->keys[i].repID); |
552 | 0 | if (tci->keys[i].periodID) |
553 | 0 | gf_free(tci->keys[i].periodID); |
554 | 0 | } |
555 | 0 | if (tci->keys) gf_free(tci->keys); |
556 | 0 | if (tci->metadata) gf_free(tci->metadata); |
557 | 0 | if (tci->KMS_URI) gf_free(tci->KMS_URI); |
558 | 0 | if (tci->Scheme_URI) gf_free(tci->Scheme_URI); |
559 | 0 | if (tci->TextualHeaders) gf_free(tci->TextualHeaders); |
560 | 0 | if (tci->subs_crypt) gf_free(tci->subs_crypt); |
561 | 0 | if (tci->mkey_subs) gf_free(tci->mkey_subs); |
562 | 0 | gf_list_rem_last(info->tcis); |
563 | 0 | gf_free(tci); |
564 | 0 | } |
565 | 0 | gf_list_del(info->tcis); |
566 | 0 | gf_free(info); |
567 | 0 | } |
568 | | |
569 | | GF_CryptInfo *gf_crypt_info_load(const char *file, GF_Err *out_err) |
570 | 0 | { |
571 | 0 | GF_Err e; |
572 | 0 | GF_CryptInfo *info; |
573 | 0 | GF_SAXParser *sax; |
574 | 0 | GF_SAFEALLOC(info, GF_CryptInfo); |
575 | 0 | if (!info) { |
576 | 0 | if (out_err) *out_err = GF_OUT_OF_MEM; |
577 | 0 | return NULL; |
578 | 0 | } |
579 | 0 | info->tcis = gf_list_new(); |
580 | 0 | sax = gf_xml_sax_new(cryptinfo_node_start, cryptinfo_node_end, cryptinfo_text, info); |
581 | 0 | e = gf_xml_sax_parse_file(sax, file, NULL); |
582 | 0 | if (e<0) { |
583 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[DRM] Failed to parse DRM config file: %s", gf_xml_sax_get_error(sax) )); |
584 | 0 | if (out_err) *out_err = e; |
585 | 0 | gf_crypt_info_del(info); |
586 | 0 | info = NULL; |
587 | 0 | } else if (info->last_parse_error) { |
588 | 0 | if (out_err) *out_err = info->last_parse_error; |
589 | 0 | gf_crypt_info_del(info); |
590 | 0 | info = NULL; |
591 | 0 | } else { |
592 | 0 | if (out_err) *out_err = GF_OK; |
593 | 0 | } |
594 | 0 | gf_xml_sax_del(sax); |
595 | 0 | return info; |
596 | 0 | } |
597 | | |
598 | | #ifndef GPAC_DISABLE_ISOM |
599 | | |
600 | | extern char gf_prog_lf; |
601 | | |
602 | | static Bool on_decrypt_event(void *_udta, GF_Event *evt) |
603 | 0 | { |
604 | 0 | Double progress; |
605 | 0 | u32 *prev_progress = (u32 *)_udta; |
606 | 0 | if (!_udta) return GF_FALSE; |
607 | 0 | if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE; |
608 | 0 | if (!evt->progress.total) return GF_FALSE; |
609 | | |
610 | 0 | progress = (Double) (100*evt->progress.done) / evt->progress.total; |
611 | 0 | if ((u32) progress==*prev_progress) |
612 | 0 | return GF_FALSE; |
613 | | |
614 | 0 | *prev_progress = (u32) progress; |
615 | 0 | #ifndef GPAC_DISABLE_LOG |
616 | 0 | GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Decrypting: % 2.2f %%%c", progress, gf_prog_lf)); |
617 | | #else |
618 | | fprintf(stderr, "Decrypting: % 2.2f %%%c", progress, gf_prog_lf); |
619 | | #endif |
620 | 0 | return GF_FALSE; |
621 | 0 | } |
622 | | |
623 | | static GF_Err gf_decrypt_file_ex(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, const char *fragment_name, u32 fs_dump_flags) |
624 | 0 | { |
625 | 0 | char *szArgs = NULL; |
626 | 0 | char an_arg[100]; |
627 | 0 | GF_Filter *src, *dst, *dcrypt; |
628 | 0 | GF_FilterSession *fsess; |
629 | 0 | GF_Err e = GF_OK; |
630 | 0 | u32 progress = (u32) -1; |
631 | |
|
632 | 0 | fsess = gf_fs_new_defaults(0); |
633 | 0 | if (!fsess) { |
634 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Decrypter] Failed to create filter session\n")); |
635 | 0 | return GF_OUT_OF_MEM; |
636 | 0 | } |
637 | | |
638 | | //we use implicit mode, don't set any filter ID |
639 | | |
640 | 0 | sprintf(an_arg, "mp4dmx:mov=%p", mp4); |
641 | 0 | gf_dynstrcat(&szArgs, an_arg, NULL); |
642 | 0 | if (fragment_name) { |
643 | 0 | gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL); |
644 | 0 | gf_dynstrcat(&szArgs, fragment_name, NULL); |
645 | 0 | } |
646 | 0 | src = gf_fs_load_filter(fsess, szArgs, &e); |
647 | 0 | gf_free(szArgs); |
648 | 0 | szArgs = NULL; |
649 | |
|
650 | 0 | if (!src) { |
651 | 0 | gf_fs_del(fsess); |
652 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Decrypter] Cannot load demux filter for source file\n")); |
653 | 0 | return e; |
654 | 0 | } |
655 | | |
656 | 0 | gf_dynstrcat(&szArgs, "cdcrypt", NULL); |
657 | 0 | if (drm_file) { |
658 | 0 | gf_dynstrcat(&szArgs, ":cfile=", NULL); |
659 | 0 | gf_dynstrcat(&szArgs, drm_file, NULL); |
660 | 0 | } |
661 | 0 | dcrypt = gf_fs_load_filter(fsess, szArgs, &e); |
662 | 0 | gf_free(szArgs); |
663 | 0 | szArgs = NULL; |
664 | 0 | if (!dcrypt) { |
665 | 0 | gf_fs_del(fsess); |
666 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Decrypter] Cannot load decryptor filter\n")); |
667 | 0 | return e; |
668 | 0 | } |
669 | | |
670 | 0 | gf_dynstrcat(&szArgs, "xps_inband=auto", NULL); |
671 | 0 | if (fragment_name) { |
672 | 0 | gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:refrag:cdur=1000000000", NULL); |
673 | 0 | } else { |
674 | 0 | if (interleave_time) { |
675 | 0 | sprintf(an_arg, ":cdur=%g", interleave_time); |
676 | 0 | gf_dynstrcat(&szArgs, an_arg, NULL); |
677 | 0 | } else { |
678 | 0 | gf_dynstrcat(&szArgs, ":store=flat", NULL); |
679 | 0 | } |
680 | 0 | } |
681 | |
|
682 | 0 | if (gf_isom_has_keep_utc_times(mp4)) |
683 | 0 | gf_dynstrcat(&szArgs, ":keep_utc", NULL); |
684 | |
|
685 | 0 | dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e); |
686 | 0 | gf_free(szArgs); |
687 | 0 | szArgs = NULL; |
688 | |
|
689 | 0 | if (!dst) { |
690 | 0 | gf_fs_del(fsess); |
691 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Decrypter] Cannot load destination muxer\n")); |
692 | 0 | return GF_FILTER_NOT_FOUND; |
693 | 0 | } |
694 | | |
695 | 0 | if (!gf_sys_is_test_mode() |
696 | 0 | #ifndef GPAC_DISABLE_LOG |
697 | 0 | && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET) |
698 | 0 | #endif |
699 | 0 | && !gf_sys_is_quiet() |
700 | 0 | ) { |
701 | 0 | gf_fs_enable_reporting(fsess, GF_TRUE); |
702 | 0 | gf_fs_set_ui_callback(fsess, on_decrypt_event, &progress); |
703 | 0 | } |
704 | | #ifdef GPAC_ENABLE_COVERAGE |
705 | | else if (gf_sys_is_cov_mode()) { |
706 | | on_decrypt_event(NULL, NULL); |
707 | | } |
708 | | #endif //GPAC_ENABLE_COVERAGE |
709 | |
|
710 | 0 | e = gf_fs_run(fsess); |
711 | 0 | if (e>GF_OK) e = GF_OK; |
712 | 0 | if (!e) e = gf_fs_get_last_connect_error(fsess); |
713 | 0 | if (!e) e = gf_fs_get_last_process_error(fsess); |
714 | |
|
715 | 0 | if (!e) gf_fs_print_unused_args(fsess, NULL); |
716 | 0 | gf_fs_print_non_connected(fsess); |
717 | 0 | if (fs_dump_flags & 1) gf_fs_print_stats(fsess); |
718 | 0 | if (fs_dump_flags & 2) gf_fs_print_connections(fsess); |
719 | |
|
720 | 0 | gf_fs_del(fsess); |
721 | 0 | return e; |
722 | 0 | } |
723 | | |
724 | | GF_EXPORT |
725 | | GF_Err gf_decrypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags) |
726 | 0 | { |
727 | 0 | return gf_decrypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags); |
728 | 0 | } |
729 | | GF_EXPORT |
730 | | GF_Err gf_decrypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags) |
731 | 0 | { |
732 | 0 | return gf_decrypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags); |
733 | 0 | } |
734 | | static Bool on_crypt_event(void *_udta, GF_Event *evt) |
735 | 0 | { |
736 | 0 | Double progress; |
737 | 0 | u32 *prev_progress = (u32 *)_udta; |
738 | 0 | if (!_udta) return GF_FALSE; |
739 | 0 | if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE; |
740 | 0 | if (!evt->progress.total) return GF_FALSE; |
741 | | |
742 | 0 | progress = (Double) (100*evt->progress.done) / evt->progress.total; |
743 | 0 | if ((u32) progress==*prev_progress) |
744 | 0 | return GF_FALSE; |
745 | | |
746 | 0 | *prev_progress = (u32) progress; |
747 | 0 | #ifndef GPAC_DISABLE_LOG |
748 | 0 | GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Encrypting: % 2.2f %%%c", progress, gf_prog_lf)); |
749 | | #else |
750 | | fprintf(stderr, "Encrypting: % 2.2f %%%c", progress, gf_prog_lf); |
751 | | #endif |
752 | 0 | return GF_FALSE; |
753 | 0 | } |
754 | | |
755 | | static GF_Err gf_crypt_file_ex(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, const char *fragment_name, u32 fs_dump_flags) |
756 | 0 | { |
757 | 0 | char *szArgs=NULL; |
758 | 0 | char an_arg[100]; |
759 | 0 | char *arg_dst=NULL; |
760 | 0 | u32 progress = (u32) -1; |
761 | 0 | GF_Filter *src, *dst, *cryptf; |
762 | 0 | GF_FilterSession *fsess; |
763 | 0 | GF_Err e = GF_OK; |
764 | |
|
765 | 0 | fsess = gf_fs_new_defaults(0); |
766 | 0 | if (!fsess) { |
767 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Encrypter] Failed to create filter session\n")); |
768 | 0 | return GF_OUT_OF_MEM; |
769 | 0 | } |
770 | | |
771 | 0 | sprintf(an_arg, "mp4dmx:mov=%p", mp4); |
772 | 0 | gf_dynstrcat(&szArgs, an_arg, NULL); |
773 | 0 | if (fragment_name) { |
774 | 0 | gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL); |
775 | 0 | gf_dynstrcat(&szArgs, fragment_name, NULL); |
776 | 0 | } |
777 | 0 | src = gf_fs_load_filter(fsess, szArgs, &e); |
778 | |
|
779 | 0 | gf_free(szArgs); |
780 | 0 | szArgs = NULL; |
781 | |
|
782 | 0 | if (!src) { |
783 | 0 | gf_fs_del(fsess); |
784 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Encrypter] Cannot load demux for source file: %s\n", gf_error_to_string(e))); |
785 | 0 | return e; |
786 | 0 | } |
787 | | |
788 | 0 | gf_dynstrcat(&szArgs, "cecrypt:FID=1:cfile=", NULL); |
789 | 0 | gf_dynstrcat(&szArgs, drm_file, NULL); |
790 | 0 | cryptf = gf_fs_load_filter(fsess, szArgs, &e); |
791 | |
|
792 | 0 | gf_free(szArgs); |
793 | 0 | szArgs = NULL; |
794 | |
|
795 | 0 | if (!cryptf) { |
796 | 0 | gf_fs_del(fsess); |
797 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Encrypter] Cannot load encryptor: %s\n", gf_error_to_string(e) )); |
798 | 0 | return e; |
799 | 0 | } |
800 | | |
801 | 0 | gf_dynstrcat(&szArgs, "SID=1", NULL); |
802 | 0 | if (fragment_name) { |
803 | 0 | gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:refrag:cdur=1000000000", NULL); |
804 | 0 | } else { |
805 | 0 | if (interleave_time) { |
806 | 0 | sprintf(an_arg, ":cdur=%g", interleave_time); |
807 | 0 | gf_dynstrcat(&szArgs, an_arg, NULL); |
808 | 0 | } else { |
809 | 0 | gf_dynstrcat(&szArgs, ":store=flat", NULL); |
810 | 0 | } |
811 | 0 | } |
812 | 0 | gf_dynstrcat(&szArgs, ":xps_inband=auto", NULL); |
813 | |
|
814 | 0 | if (gf_isom_has_keep_utc_times(mp4)) |
815 | 0 | gf_dynstrcat(&szArgs, ":keep_utc", NULL); |
816 | |
|
817 | 0 | arg_dst = gf_url_colon_suffix(dst_file, '='); |
818 | 0 | if (arg_dst) { |
819 | 0 | gf_dynstrcat(&szArgs, arg_dst, NULL); |
820 | 0 | arg_dst[0]=0; |
821 | 0 | } |
822 | 0 | dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e); |
823 | |
|
824 | 0 | gf_free(szArgs); |
825 | 0 | szArgs = NULL; |
826 | 0 | if (!dst) { |
827 | 0 | gf_fs_del(fsess); |
828 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Encrypter] Cannot load destination muxer\n")); |
829 | 0 | return GF_FILTER_NOT_FOUND; |
830 | 0 | } |
831 | | |
832 | 0 | if (!gf_sys_is_test_mode() |
833 | 0 | #ifndef GPAC_DISABLE_LOG |
834 | 0 | && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET) |
835 | 0 | #endif |
836 | 0 | && !gf_sys_is_quiet() |
837 | 0 | ) { |
838 | 0 | gf_fs_enable_reporting(fsess, GF_TRUE); |
839 | 0 | gf_fs_set_ui_callback(fsess, on_crypt_event, &progress); |
840 | 0 | } |
841 | | #ifdef GPAC_ENABLE_COVERAGE |
842 | | else if (gf_sys_is_cov_mode()) { |
843 | | on_crypt_event(NULL, NULL); |
844 | | } |
845 | | #endif //GPAC_ENABLE_COVERAGE |
846 | 0 | e = gf_fs_run(fsess); |
847 | 0 | if (e>GF_OK) e = GF_OK; |
848 | 0 | if (!e) e = gf_fs_get_last_connect_error(fsess); |
849 | 0 | if (!e) e = gf_fs_get_last_process_error(fsess); |
850 | |
|
851 | 0 | if (!e) gf_fs_print_unused_args(fsess, NULL); |
852 | 0 | gf_fs_print_non_connected(fsess); |
853 | 0 | if (fs_dump_flags & 1) gf_fs_print_stats(fsess); |
854 | 0 | if (fs_dump_flags & 2) gf_fs_print_connections(fsess); |
855 | 0 | gf_fs_del(fsess); |
856 | 0 | return e; |
857 | 0 | } |
858 | | |
859 | | GF_EXPORT |
860 | | GF_Err gf_crypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags) |
861 | 0 | { |
862 | 0 | return gf_crypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags); |
863 | 0 | } |
864 | | |
865 | | GF_EXPORT |
866 | | GF_Err gf_crypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags) |
867 | 0 | { |
868 | 0 | return gf_crypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags); |
869 | |
|
870 | 0 | } |
871 | | #endif //GPAC_DISABLE_ISOM |
872 | | |
873 | | |
874 | | #endif /* !defined(GPAC_DISABLE_CRYPTO)*/ |
875 | | |