1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2020
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
cryptinfo_get_crypt_type(char * cr_type)38 static u32 cryptinfo_get_crypt_type(char *cr_type)
39 {
40 if (!stricmp(cr_type, "ISMA") || !stricmp(cr_type, "iAEC"))
41 return GF_CRYPT_TYPE_ISMA;
42 else if (!stricmp(cr_type, "CENC AES-CTR") || !stricmp(cr_type, "cenc"))
43 return GF_CRYPT_TYPE_CENC;
44 else if (!stricmp(cr_type, "piff"))
45 return GF_CRYPT_TYPE_PIFF;
46 else if (!stricmp(cr_type, "CENC AES-CBC") || !stricmp(cr_type, "cbc1"))
47 return GF_CRYPT_TYPE_CBC1;
48 else if (!stricmp(cr_type, "ADOBE") || !stricmp(cr_type, "adkm"))
49 return GF_CRYPT_TYPE_ADOBE;
50 else if (!stricmp(cr_type, "CENC AES-CTR Pattern") || !stricmp(cr_type, "cens"))
51 return GF_CRYPT_TYPE_CENS;
52 else if (!stricmp(cr_type, "CENC AES-CBC Pattern") || !stricmp(cr_type, "cbcs"))
53 return GF_CRYPT_TYPE_CBCS;
54 else if (!stricmp(cr_type, "OMA"))
55 return GF_ISOM_OMADRM_SCHEME;
56
57 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Unrecognized crypto type %s\n", cr_type));
58 return 0;
59 }
60
cryptinfo_node_start(void * sax_cbck,const char * node_name,const char * name_space,const GF_XMLAttribute * attributes,u32 nb_attributes)61 static void cryptinfo_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
62 {
63 GF_XMLAttribute *att;
64 GF_TrackCryptInfo *tkc;
65 u32 i;
66 GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
67
68 if (!strcmp(node_name, "OMATextHeader")) {
69 info->in_text_header = 1;
70 return;
71 }
72 if (!strcmp(node_name, "GPACDRM")) {
73 for (i=0; i<nb_attributes; i++) {
74 att = (GF_XMLAttribute *) &attributes[i];
75 if (!stricmp(att->name, "type")) {
76 info->def_crypt_type = cryptinfo_get_crypt_type(att->value);
77 }
78 }
79 return;
80 }
81 if (!strcmp(node_name, "CrypTrack")) {
82 Bool has_common_key = GF_TRUE;
83 GF_SAFEALLOC(tkc, GF_TrackCryptInfo);
84 if (!tkc) {
85 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Cannnot allocate crypt track, skipping\n"));
86 return;
87 }
88 //by default track is encrypted
89 tkc->IsEncrypted = 1;
90 tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
91 tkc->scheme_type = info->def_crypt_type;
92 gf_list_add(info->tcis, tkc);
93
94 for (i=0; i<nb_attributes; i++) {
95 att = (GF_XMLAttribute *) &attributes[i];
96 if (!stricmp(att->name, "trackID") || !stricmp(att->name, "ID")) {
97 if (!strcmp(att->value, "*")) info->has_common_key = 1;
98 else {
99 tkc->trackID = atoi(att->value);
100 has_common_key = GF_FALSE;
101 }
102 }
103 else if (!stricmp(att->name, "type")) {
104 tkc->scheme_type = cryptinfo_get_crypt_type(att->value);
105 }
106 else if (!stricmp(att->name, "forceType")) {
107 tkc->force_type = GF_TRUE;
108 }
109 else if (!stricmp(att->name, "key")) {
110 GF_Err e;
111 if (!tkc->keys) {
112 tkc->KID_count = 1;
113 tkc->keys = gf_malloc(sizeof(bin128));
114 }
115 e = gf_bin128_parse(att->value, tkc->keys[0] );
116 if (e != GF_OK) {
117 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value in CrypTrack\n"));
118 return;
119 }
120 }
121 else if (!stricmp(att->name, "salt")) {
122 u32 len, j;
123 char *sKey = att->value;
124 if (!strnicmp(sKey, "0x", 2)) sKey += 2;
125 len = (u32) strlen(sKey);
126 for (j=0; j<len; j+=2) {
127 char szV[5];
128 u32 v;
129 sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
130 sscanf(szV, "%x", &v);
131 tkc->first_IV[j/2] = v;
132 if (j>=30) break;
133 }
134 }
135 else if (!stricmp(att->name, "kms_URI") || !stricmp(att->name, "rightsIssuerURL")) {
136 if (tkc->KMS_URI) gf_free(tkc->KMS_URI);
137 tkc->KMS_URI = gf_strdup(att->value);
138 }
139 else if (!stricmp(att->name, "scheme_URI") || !stricmp(att->name, "contentID")) {
140 if (tkc->Scheme_URI) gf_free(tkc->Scheme_URI);
141 tkc->Scheme_URI = gf_strdup(att->value);
142 }
143 else if (!stricmp(att->name, "selectiveType")) {
144 if (!stricmp(att->value, "Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAP;
145 else if (!stricmp(att->value, "Non-Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_NON_RAP;
146 else if (!stricmp(att->value, "Rand")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAND;
147 else if (!strnicmp(att->value, "Rand", 4)) {
148 tkc->sel_enc_type = GF_CRYPT_SELENC_RAND_RANGE;
149 tkc->sel_enc_range = atoi(&att->value[4]);
150 }
151 else if (sscanf(att->value, "%u", &tkc->sel_enc_range)==1) {
152 if (tkc->sel_enc_range==1) tkc->sel_enc_range = 0;
153 else tkc->sel_enc_type = GF_CRYPT_SELENC_RANGE;
154 }
155 else if (!strnicmp(att->value, "Preview", 7)) {
156 tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
157 }
158 else if (!strnicmp(att->value, "Clear", 5)) {
159 tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR;
160 }
161 else if (!strnicmp(att->value, "ForceClear", 10)) {
162 char *sep = strchr(att->value, '=');
163 if (sep) tkc->sel_enc_range = atoi(sep+1);
164 tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR_FORCED;
165 }
166 else if (!stricmp(att->value, "None")) {
167 } else {
168 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized selective mode %s, ignoring\n", att->value));
169 }
170 }
171 else if (!stricmp(att->name, "clearStsd")) {
172 if (!strcmp(att->value, "none")) tkc->force_clear_stsd_idx = 0;
173 else if (!strcmp(att->value, "before")) tkc->force_clear_stsd_idx = 1;
174 else if (!strcmp(att->value, "after")) tkc->force_clear_stsd_idx = 2;
175 else {
176 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized clear stsd type %s, defaulting to no stsd for clear samples\n", att->value));
177 }
178 }
179 else if (!stricmp(att->name, "Preview")) {
180 tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
181 sscanf(att->value, "%u", &tkc->sel_enc_range);
182 }
183 else if (!stricmp(att->name, "ipmpType")) {
184 if (!stricmp(att->value, "None")) tkc->ipmp_type = 0;
185 else if (!stricmp(att->value, "IPMP")) tkc->sel_enc_type = 1;
186 else if (!stricmp(att->value, "IPMPX")) tkc->sel_enc_type = 2;
187 }
188 else if (!stricmp(att->name, "ipmpDescriptorID")) tkc->ipmp_desc_id = atoi(att->value);
189 else if (!stricmp(att->name, "encryptionMethod")) {
190 if (!strcmp(att->value, "AES_128_CBC")) tkc->encryption = 1;
191 else if (!strcmp(att->value, "None")) tkc->encryption = 0;
192 else if (!strcmp(att->value, "AES_128_CTR") || !strcmp(att->value, "default")) tkc->encryption = 2;
193 else {
194 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized encryption algo %s, ignoring\n", att->value));
195 }
196 }
197 else if (!stricmp(att->name, "transactionID")) {
198 if (strlen(att->value)<=16) strcpy(tkc->TransactionID, att->value);
199 }
200 else if (!stricmp(att->name, "textualHeaders")) {
201 }
202 else if (!stricmp(att->name, "IsEncrypted")) {
203 if (!stricmp(att->value, "1"))
204 tkc->IsEncrypted = 1;
205 else
206 tkc->IsEncrypted = 0;
207 }
208 else if (!stricmp(att->name, "IV_size")) {
209 tkc->IV_size = atoi(att->value);
210 }
211 else if (!stricmp(att->name, "first_IV")) {
212 char *sKey = att->value;
213 if (!strnicmp(sKey, "0x", 2)) sKey += 2;
214 if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
215 u32 j;
216 for (j=0; j<strlen(sKey); j+=2) {
217 u32 v;
218 char szV[5];
219 sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
220 sscanf(szV, "%x", &v);
221 tkc->first_IV[j/2] = v;
222 }
223 if (!tkc->IV_size) tkc->IV_size = (u8) strlen(sKey) / 2;
224 }
225 }
226 else if (!stricmp(att->name, "saiSavedBox")) {
227 if (!stricmp(att->value, "uuid_psec")) tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
228 else if (!stricmp(att->value, "senc")) tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
229 else {
230 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized SAI location %s, ignoring\n", att->value));
231 }
232 }
233 else if (!stricmp(att->name, "keyRoll")) {
234 if (!strncmp(att->value, "idx=", 4))
235 tkc->defaultKeyIdx = atoi(att->value+4);
236 else if (!strncmp(att->value, "roll=", 5))
237 tkc->keyRoll = atoi(att->value+5);
238 else {
239 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized roll parameter %s, ignoring\n", att->value));
240 }
241 }
242 else if (!stricmp(att->name, "metadata")) {
243 u32 l = 2 * (u32) strlen(att->value);
244 tkc->metadata = gf_malloc(sizeof(char) * l);
245 l = gf_base64_encode(att->value, (u32) strlen(att->value), tkc->metadata, l);
246 tkc->metadata[l] = 0;
247 }
248 else if (!stricmp(att->name, "crypt_byte_block")) {
249 tkc->crypt_byte_block = atoi(att->value);
250 }
251 else if (!stricmp(att->name, "skip_byte_block")) {
252 tkc->skip_byte_block = atoi(att->value);
253 }
254 else if (!stricmp(att->name, "clear_bytes")) {
255 tkc->clear_bytes = atoi(att->value);
256 }
257 else if (!stricmp(att->name, "constant_IV_size")) {
258 tkc->constant_IV_size = atoi(att->value);
259 assert((tkc->constant_IV_size == 8) || (tkc->constant_IV_size == 16));
260 }
261 else if (!stricmp(att->name, "constant_IV")) {
262 char *sKey = att->value;
263 if (!strnicmp(sKey, "0x", 2)) sKey += 2;
264 if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
265 u32 j;
266 for (j=0; j<strlen(sKey); j+=2) {
267 u32 v;
268 char szV[5];
269 sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
270 sscanf(szV, "%x", &v);
271 tkc->constant_IV[j/2] = v;
272 }
273 }
274 if (!tkc->constant_IV_size) tkc->constant_IV_size = (u8) strlen(sKey) / 2;
275 }
276 else if (!stricmp(att->name, "encryptSliceHeader")) {
277 tkc->allow_encrypted_slice_header = !strcmp(att->value, "yes") ? GF_TRUE : GF_FALSE;
278 }
279 else if (!stricmp(att->name, "blockAlign")) {
280 if (!strcmp(att->value, "disable")) tkc->block_align = 1;
281 else if (!strcmp(att->value, "always")) tkc->block_align = 2;
282 else tkc->block_align = 0;
283 }
284 }
285 if (tkc->scheme_type==GF_CRYPT_TYPE_PIFF) {
286 tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
287 }
288 if (has_common_key) info->has_common_key = 1;
289
290 if ((tkc->IV_size != 0) && (tkc->IV_size != 8) && (tkc->IV_size != 16)) {
291 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] wrong IV size %d for AES-128, using 16\n", (u32) tkc->IV_size));
292 tkc->IV_size = 16;
293 }
294
295 if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1)) {
296 if (tkc->crypt_byte_block || tkc->skip_byte_block) {
297 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Using scheme type %s, crypt_byte_block and skip_byte_block shall be 0\n", gf_4cc_to_str(tkc->scheme_type) ));
298 tkc->crypt_byte_block = tkc->skip_byte_block = 0;
299 }
300 }
301
302 if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1) || (tkc->scheme_type == GF_CRYPT_TYPE_CENS)) {
303 if (tkc->constant_IV_size) {
304 if (!tkc->IV_size) {
305 tkc->IV_size = tkc->constant_IV_size;
306 memcpy(tkc->first_IV, tkc->constant_IV, 16);
307 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[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)));
308 tkc->constant_IV_size = 0;
309 } else {
310 tkc->constant_IV_size = 0;
311 memset(tkc->constant_IV, 0, 16);
312 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Using scheme type %s, constant IV shall not be used, ignoring\n", gf_4cc_to_str(tkc->scheme_type)));
313 }
314 }
315 }
316 if (tkc->scheme_type == GF_ISOM_OMADRM_SCHEME) {
317 /*default to AES 128 in OMA*/
318 tkc->encryption = 2;
319 }
320
321 }
322
323 if (!strcmp(node_name, "key")) {
324 tkc = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
325 tkc->KIDs = (bin128 *)gf_realloc(tkc->KIDs, sizeof(bin128)*(tkc->KID_count+1));
326 tkc->keys = (bin128 *)gf_realloc(tkc->keys, sizeof(bin128)*(tkc->KID_count+1));
327
328 for (i=0; i<nb_attributes; i++) {
329 att = (GF_XMLAttribute *) &attributes[i];
330
331 if (!stricmp(att->name, "KID")) {
332 GF_Err e = gf_bin128_parse(att->value, tkc->KIDs[tkc->KID_count]);
333 if (e != GF_OK) {
334 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse KID\n"));
335 return;
336 }
337 }
338 else if (!stricmp(att->name, "value")) {
339 GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->KID_count]);
340 if (e != GF_OK) {
341 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value\n"));
342 return;
343 }
344 }
345 }
346 tkc->KID_count++;
347 }
348 }
349
cryptinfo_node_end(void * sax_cbck,const char * node_name,const char * name_space)350 static void cryptinfo_node_end(void *sax_cbck, const char *node_name, const char *name_space)
351 {
352 GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
353 if (!strcmp(node_name, "OMATextHeader")) {
354 info->in_text_header = 0;
355 return;
356 }
357 }
358
cryptinfo_text(void * sax_cbck,const char * text,Bool is_cdata)359 static void cryptinfo_text(void *sax_cbck, const char *text, Bool is_cdata)
360 {
361 u32 len, len2;
362 GF_TrackCryptInfo *tkc;
363 GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
364
365 if (!info->in_text_header) return;
366
367 tkc = (GF_TrackCryptInfo *) gf_list_last(info->tcis);
368 len = (u32) strlen(text);
369 len2 = tkc->TextualHeaders ? (u32) strlen(tkc->TextualHeaders) : 0;
370
371 tkc->TextualHeaders = gf_realloc(tkc->TextualHeaders, sizeof(char) * (len+len2+1));
372 if (!len2) strcpy(tkc->TextualHeaders, "");
373 strcat(tkc->TextualHeaders, text);
374 }
375
gf_crypt_info_del(GF_CryptInfo * info)376 void gf_crypt_info_del(GF_CryptInfo *info)
377 {
378 while (gf_list_count(info->tcis)) {
379 GF_TrackCryptInfo *tci = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
380 if (tci->KIDs) gf_free(tci->KIDs);
381 if (tci->keys) gf_free(tci->keys);
382 if (tci->metadata) gf_free(tci->metadata);
383 if (tci->KMS_URI) gf_free(tci->KMS_URI);
384 if (tci->Scheme_URI) gf_free(tci->Scheme_URI);
385 if (tci->TextualHeaders) gf_free(tci->TextualHeaders);
386 gf_list_rem_last(info->tcis);
387 gf_free(tci);
388 }
389 gf_list_del(info->tcis);
390 gf_free(info);
391 }
392
gf_crypt_info_load(const char * file,GF_Err * out_err)393 GF_CryptInfo *gf_crypt_info_load(const char *file, GF_Err *out_err)
394 {
395 GF_Err e;
396 GF_CryptInfo *info;
397 GF_SAXParser *sax;
398 GF_SAFEALLOC(info, GF_CryptInfo);
399 if (!info) {
400 if (out_err) *out_err = GF_OUT_OF_MEM;
401 return NULL;
402 }
403 info->tcis = gf_list_new();
404 sax = gf_xml_sax_new(cryptinfo_node_start, cryptinfo_node_end, cryptinfo_text, info);
405 e = gf_xml_sax_parse_file(sax, file, NULL);
406 if (e<0) {
407 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[DRM] Failed to parse DRM config file: %s", gf_xml_sax_get_error(sax) ));
408 if (out_err) *out_err = e;
409 gf_crypt_info_del(info);
410 info = NULL;
411 } else {
412 if (out_err) *out_err = GF_OK;
413 }
414 gf_xml_sax_del(sax);
415 return info;
416 }
417
on_decrypt_event(void * _udta,GF_Event * evt)418 static Bool on_decrypt_event(void *_udta, GF_Event *evt)
419 {
420 Double progress;
421 u32 *prev_progress = (u32 *)_udta;
422 if (!_udta) return GF_FALSE;
423 if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
424 if (!evt->progress.total) return GF_FALSE;
425
426 progress = (Double) (100*evt->progress.done) / evt->progress.total;
427 if ((u32) progress==*prev_progress)
428 return GF_FALSE;
429
430 *prev_progress = (u32) progress;
431 #ifndef GPAC_DISABLE_LOG
432 GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Decrypting: % 2.2f %%\r", progress));
433 #else
434 fprintf(stderr, "Decrypting: % 2.2f %%\r", progress);
435 #endif
436 return GF_FALSE;
437 }
438
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)439 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)
440 {
441 char szArgs[4096];
442 GF_Filter *src, *dst, *dcrypt;
443 GF_FilterSession *fsess;
444 GF_Err e = GF_OK;
445 u32 progress = (u32) -1;
446
447 fsess = gf_fs_new_defaults(0);
448 if (!fsess) {
449 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Failed to create filter session\n"));
450 return GF_OUT_OF_MEM;
451 }
452 sprintf(szArgs, "mp4dmx:mov=%p", mp4);
453 if (fragment_name) {
454 strcat(szArgs, ":sigfrag:catseg=");
455 strcat(szArgs, fragment_name);
456 }
457 src = gf_fs_load_filter(fsess, szArgs, &e);
458 if (!src) {
459 gf_fs_del(fsess);
460 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load demux filter for source file\n"));
461 return e;
462 }
463
464 sprintf(szArgs, "cdcrypt:FID=1:cfile=%s", drm_file);
465 dcrypt = gf_fs_load_filter(fsess, szArgs, &e);
466 if (!dcrypt) {
467 gf_fs_del(fsess);
468 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load decryptor filter\n"));
469 return e;
470 }
471
472 sprintf(szArgs, "SID=1");
473 if (fragment_name) {
474 strcat(szArgs, ":sseg:noinit:store=frag:cdur=1000000000");
475 } else {
476 if (interleave_time) {
477 char an_arg[100];
478 sprintf(an_arg, ":cdur=%g", interleave_time);
479 strcat(szArgs, an_arg);
480 } else {
481 strcat(szArgs, ":store=flat");
482 }
483 }
484
485 dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
486 if (!dst) {
487 gf_fs_del(fsess);
488 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load destination muxer\n"));
489 return GF_FILTER_NOT_FOUND;
490 }
491
492 if (!gf_sys_is_test_mode()
493 #ifndef GPAC_DISABLE_LOG
494 && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
495 #endif
496 && !gf_sys_is_quiet()
497 ) {
498 gf_fs_enable_reporting(fsess, GF_TRUE);
499 gf_fs_set_ui_callback(fsess, on_decrypt_event, &progress);
500 }
501 #ifdef GPAC_ENABLE_COVERAGE
502 else if (gf_sys_is_cov_mode()) {
503 on_decrypt_event(NULL, NULL);
504 }
505 #endif //GPAC_ENABLE_COVERAGE
506
507 e = gf_fs_run(fsess);
508 if (e>GF_OK) e = GF_OK;
509 if (!e) e = gf_fs_get_last_connect_error(fsess);
510 if (!e) e = gf_fs_get_last_process_error(fsess);
511
512 if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
513 if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
514
515 gf_fs_del(fsess);
516 return e;
517 }
518
519 GF_EXPORT
gf_decrypt_fragment(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,const char * fragment_name,u32 fs_dump_flags)520 GF_Err gf_decrypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
521 {
522 return gf_decrypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
523 }
524 GF_EXPORT
gf_decrypt_file(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,Double interleave_time,u32 fs_dump_flags)525 GF_Err gf_decrypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
526 {
527 return gf_decrypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
528 }
on_crypt_event(void * _udta,GF_Event * evt)529 static Bool on_crypt_event(void *_udta, GF_Event *evt)
530 {
531 Double progress;
532 u32 *prev_progress = (u32 *)_udta;
533 if (!_udta) return GF_FALSE;
534 if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
535 if (!evt->progress.total) return GF_FALSE;
536
537 progress = (Double) (100*evt->progress.done) / evt->progress.total;
538 if ((u32) progress==*prev_progress)
539 return GF_FALSE;
540
541 *prev_progress = (u32) progress;
542 #ifndef GPAC_DISABLE_LOG
543 GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Encrypting: % 2.2f %%\r", progress));
544 #else
545 fprintf(stderr, "Encrypting: % 2.2f %%\r", progress);
546 #endif
547 return GF_FALSE;
548 }
549
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)550 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)
551 {
552 char *szArgs=NULL;
553 char an_arg[100];
554 char *arg_dst=NULL;
555 u32 progress = (u32) -1;
556 GF_Filter *src, *dst, *crypt;
557 GF_FilterSession *fsess;
558 GF_Err e = GF_OK;
559
560 fsess = gf_fs_new_defaults(0);
561 if (!fsess) {
562 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Failed to create filter session\n"));
563 return GF_OUT_OF_MEM;
564 }
565
566 sprintf(an_arg, "mp4dmx:mov=%p", mp4);
567 gf_dynstrcat(&szArgs, an_arg, NULL);
568 if (fragment_name) {
569 gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL);
570 gf_dynstrcat(&szArgs, fragment_name, NULL);
571 }
572 src = gf_fs_load_filter(fsess, szArgs, &e);
573
574 gf_free(szArgs);
575 szArgs = NULL;
576
577 if (!src) {
578 gf_fs_del(fsess);
579 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load demux for source file: %s\n", gf_error_to_string(e)));
580 return e;
581 }
582
583 gf_dynstrcat(&szArgs, "cecrypt:FID=1:cfile=", NULL);
584 gf_dynstrcat(&szArgs, drm_file, NULL);
585 crypt = gf_fs_load_filter(fsess, szArgs, &e);
586
587 gf_free(szArgs);
588 szArgs = NULL;
589
590 if (!crypt) {
591 gf_fs_del(fsess);
592 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load encryptor: %s\n", gf_error_to_string(e) ));
593 return e;
594 }
595
596 gf_dynstrcat(&szArgs, "SID=1", NULL);
597 if (fragment_name) {
598 gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:cdur=1000000000", NULL);
599 } else {
600 if (interleave_time) {
601 sprintf(an_arg, ":cdur=%g", interleave_time);
602 gf_dynstrcat(&szArgs, an_arg, NULL);
603 } else {
604 gf_dynstrcat(&szArgs, ":store=flat", NULL);
605 }
606 }
607
608 arg_dst = gf_url_colon_suffix(dst_file);
609 if (arg_dst) {
610 gf_dynstrcat(&szArgs, arg_dst, NULL);
611 arg_dst[0]=0;
612 }
613 dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
614
615 gf_free(szArgs);
616 szArgs = NULL;
617 if (!dst) {
618 gf_fs_del(fsess);
619 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load destination muxer\n"));
620 return GF_FILTER_NOT_FOUND;
621 }
622
623 if (!gf_sys_is_test_mode()
624 #ifndef GPAC_DISABLE_LOG
625 && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
626 #endif
627 && !gf_sys_is_quiet()
628 ) {
629 gf_fs_enable_reporting(fsess, GF_TRUE);
630 gf_fs_set_ui_callback(fsess, on_crypt_event, &progress);
631 }
632 #ifdef GPAC_ENABLE_COVERAGE
633 else if (gf_sys_is_cov_mode()) {
634 on_crypt_event(NULL, NULL);
635 }
636 #endif //GPAC_ENABLE_COVERAGE
637 e = gf_fs_run(fsess);
638 if (e>GF_OK) e = GF_OK;
639 if (!e) e = gf_fs_get_last_connect_error(fsess);
640 if (!e) e = gf_fs_get_last_process_error(fsess);
641
642 if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
643 if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
644 gf_fs_del(fsess);
645 return e;
646 }
647
648 GF_EXPORT
gf_crypt_fragment(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,const char * fragment_name,u32 fs_dump_flags)649 GF_Err gf_crypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
650 {
651 return gf_crypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
652 }
653
654 GF_EXPORT
gf_crypt_file(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,Double interleave_time,u32 fs_dump_flags)655 GF_Err gf_crypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
656 {
657 return gf_crypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
658
659 }
660 #endif /* !defined(GPAC_DISABLE_ISOM_WRITE)*/
661
662