Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Cyril Concolato / Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2005-2020
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ISO Media File Format 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 : #include <gpac/internal/isomedia_dev.h>
27 :
28 : #ifndef GPAC_DISABLE_ISOM
29 :
30 1864 : GF_ISMASample *gf_isom_ismacryp_new_sample()
31 : {
32 1864 : GF_ISMASample *tmp = (GF_ISMASample *) gf_malloc(sizeof(GF_ISMASample));
33 1864 : if (!tmp) return NULL;
34 : memset(tmp, 0, sizeof(GF_ISMASample));
35 1864 : return tmp;
36 : }
37 : GF_EXPORT
38 1864 : void gf_isom_ismacryp_delete_sample(GF_ISMASample *samp)
39 : {
40 1864 : if (!samp) return;
41 1864 : if (samp->data && samp->dataLength) gf_free(samp->data);
42 1864 : if (samp->key_indicator) gf_free(samp->key_indicator);
43 1864 : gf_free(samp);
44 : }
45 :
46 :
47 1864 : GF_ISMASample *gf_isom_ismacryp_sample_from_data(u8 *data, u32 dataLength, Bool use_selective_encryption, u8 KI_length, u8 IV_length)
48 : {
49 : GF_ISMASample *s;
50 : GF_BitStream *bs;
51 : /*empty text sample*/
52 1864 : if (!data || !dataLength) {
53 0 : return gf_isom_ismacryp_new_sample();
54 : }
55 :
56 1864 : s = gf_isom_ismacryp_new_sample();
57 :
58 : /*empty sample*/
59 : if (!data || !dataLength) return s;
60 :
61 1864 : bs = gf_bs_new(data, dataLength, GF_BITSTREAM_READ);
62 :
63 1864 : s->dataLength = dataLength;
64 1864 : s->IV_length = IV_length;
65 1864 : s->KI_length = KI_length;
66 :
67 1864 : if (use_selective_encryption) {
68 0 : s->flags = GF_ISOM_ISMA_USE_SEL_ENC;
69 0 : if (s->dataLength < 1) goto exit;
70 0 : if (gf_bs_read_int(bs, 1)) s->flags |= GF_ISOM_ISMA_IS_ENCRYPTED;
71 0 : gf_bs_read_int(bs, 7);
72 0 : s->dataLength -= 1;
73 : } else {
74 1864 : s->flags = GF_ISOM_ISMA_IS_ENCRYPTED;
75 : }
76 1864 : if (s->flags & GF_ISOM_ISMA_IS_ENCRYPTED) {
77 1864 : if (IV_length != 0) {
78 1864 : if (s->dataLength < IV_length) goto exit;
79 1864 : s->IV = gf_bs_read_long_int(bs, 8*IV_length);
80 1864 : s->dataLength -= IV_length;
81 : }
82 1864 : if (KI_length) {
83 0 : if (s->dataLength < KI_length) goto exit;
84 0 : s->key_indicator = (u8 *)gf_malloc(KI_length);
85 0 : if (!s->key_indicator) goto exit;
86 0 : gf_bs_read_data(bs, (char*)s->key_indicator, KI_length);
87 0 : s->dataLength -= KI_length;
88 : }
89 : }
90 1864 : s->data = (char*)gf_malloc(sizeof(char)*s->dataLength);
91 1864 : if (!s->data) goto exit;
92 1864 : gf_bs_read_data(bs, s->data, s->dataLength);
93 1864 : gf_bs_del(bs);
94 1864 : return s;
95 :
96 0 : exit:
97 0 : gf_isom_ismacryp_delete_sample(s);
98 0 : return NULL;
99 : }
100 :
101 : #if 0 //unused
102 : /*! rewrites ISMA sample as an ISO sample
103 : \param s the ISMA sample to rewrite
104 : \param dest the destination ISO sample
105 : \return error if any
106 : */
107 : GF_Err gf_isom_ismacryp_sample_to_sample(const GF_ISMASample *s, GF_ISOSample *dest)
108 : {
109 : GF_BitStream *bs;
110 : if (!s || !dest) return GF_BAD_PARAM;
111 :
112 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
113 :
114 : if (s->flags & GF_ISOM_ISMA_USE_SEL_ENC) {
115 : gf_bs_write_int(bs, (s->flags & GF_ISOM_ISMA_IS_ENCRYPTED) ? 1 : 0, 1);
116 : gf_bs_write_int(bs, 0, 7);
117 : }
118 : if (s->flags & GF_ISOM_ISMA_IS_ENCRYPTED) {
119 : if (s->IV_length) gf_bs_write_long_int(bs, (s64) s->IV, 8*s->IV_length);
120 : if (s->KI_length) gf_bs_write_data(bs, (char*)s->key_indicator, s->KI_length);
121 : }
122 : gf_bs_write_data(bs, s->data, s->dataLength);
123 : if (dest->data) gf_free(dest->data);
124 : dest->data = NULL;
125 : dest->dataLength = 0;
126 : gf_bs_get_content(bs, &dest->data, &dest->dataLength);
127 : gf_bs_del(bs);
128 : return GF_OK;
129 : }
130 : #endif
131 :
132 :
133 284182 : static GF_ProtectionSchemeInfoBox *isom_get_sinf_entry(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 scheme_type, GF_SampleEntryBox **out_sea)
134 : {
135 284182 : u32 i=0;
136 284182 : GF_SampleEntryBox *sea=NULL;
137 : GF_ProtectionSchemeInfoBox *sinf;
138 :
139 284182 : Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL);
140 284182 : if (!sea) return NULL;
141 :
142 284177 : i = 0;
143 815010 : while ((sinf = (GF_ProtectionSchemeInfoBox*)gf_list_enum(sea->child_boxes, &i))) {
144 667957 : if (sinf->type != GF_ISOM_BOX_TYPE_SINF) continue;
145 :
146 252395 : if (sinf->original_format && sinf->scheme_type && sinf->info) {
147 252395 : if (!scheme_type || (sinf->scheme_type->scheme_type == scheme_type)) {
148 137124 : if (out_sea)
149 5 : *out_sea = sea;
150 : return sinf;
151 : }
152 : }
153 : }
154 : return NULL;
155 : }
156 :
157 : GF_EXPORT
158 1864 : GF_ISMASample *gf_isom_get_ismacryp_sample(GF_ISOFile *the_file, u32 trackNumber, const GF_ISOSample *samp, u32 sampleDescriptionIndex)
159 : {
160 : GF_TrackBox *trak;
161 : GF_ISMASampleFormatBox *fmt;
162 : GF_ProtectionSchemeInfoBox *sinf;
163 :
164 1864 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
165 1864 : if (!trak) return NULL;
166 :
167 1864 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, 0, NULL);
168 1864 : if (!sinf) return NULL;
169 :
170 : /*ISMA*/
171 1864 : if (sinf->scheme_type->scheme_type == GF_ISOM_ISMACRYP_SCHEME) {
172 1864 : fmt = sinf->info->isfm;
173 1864 : if (!fmt) return NULL;
174 1864 : return gf_isom_ismacryp_sample_from_data(samp->data, samp->dataLength, sinf->info->isfm->selective_encryption, sinf->info->isfm->key_indicator_length, sinf->info->isfm->IV_length);
175 : }
176 : /*OMA*/
177 0 : else if (sinf->scheme_type->scheme_type == GF_ISOM_OMADRM_SCHEME ) {
178 0 : if (!sinf->info->odkm) return NULL;
179 0 : fmt = sinf->info->odkm->fmt;
180 :
181 0 : if (fmt) {
182 0 : return gf_isom_ismacryp_sample_from_data(samp->data, samp->dataLength, fmt->selective_encryption, fmt->key_indicator_length, fmt->IV_length);
183 : }
184 : /*OMA default: no selective encryption, one key, 128 bit IV*/
185 0 : return gf_isom_ismacryp_sample_from_data(samp->data, samp->dataLength, GF_FALSE, 0, 128);
186 : }
187 : return NULL;
188 : }
189 :
190 :
191 : GF_EXPORT
192 5840 : u32 gf_isom_is_media_encrypted(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
193 : {
194 : GF_TrackBox *trak;
195 : u32 i, count;
196 : GF_ProtectionSchemeInfoBox *sinf;
197 :
198 5840 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
199 5840 : if (!trak) return 0;
200 5840 : count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
201 8123 : for (i=0; i<count; i++) {
202 6401 : if (sampleDescriptionIndex && (i+1 != sampleDescriptionIndex))
203 560 : continue;
204 :
205 5841 : sinf = isom_get_sinf_entry(trak, i+1, 0, NULL);
206 5841 : if (!sinf) continue;
207 :
208 : /*non-encrypted or non-ISMA*/
209 4118 : if (!sinf->scheme_type) return 0;
210 4118 : if (sinf->scheme_type->scheme_type == GF_ISOM_PIFF_SCHEME) return GF_ISOM_CENC_SCHEME;
211 4117 : return sinf->scheme_type->scheme_type;
212 : }
213 : return 0;
214 : }
215 :
216 : GF_EXPORT
217 395 : Bool gf_isom_is_ismacryp_media(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
218 : {
219 : GF_TrackBox *trak;
220 : GF_ProtectionSchemeInfoBox *sinf;
221 :
222 395 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
223 395 : if (!trak) return GF_FALSE;
224 :
225 395 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ISMACRYP_SCHEME, NULL);
226 395 : if (!sinf) return GF_FALSE;
227 :
228 : /*non-encrypted or non-ISMA*/
229 27 : if (!sinf->info || !sinf->info->ikms || !sinf->info->isfm )
230 : return GF_FALSE;
231 :
232 27 : return GF_TRUE;
233 : }
234 :
235 : GF_EXPORT
236 368 : Bool gf_isom_is_omadrm_media(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
237 : {
238 : GF_TrackBox *trak;
239 : GF_ProtectionSchemeInfoBox *sinf;
240 :
241 368 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
242 368 : if (!trak) return GF_FALSE;
243 :
244 368 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_OMADRM_SCHEME, NULL);
245 368 : if (!sinf) return GF_FALSE;
246 :
247 : /*non-encrypted or non-OMA*/
248 0 : if (!sinf->info || !sinf->info->odkm || !sinf->info->odkm->hdr)
249 : return GF_FALSE;
250 :
251 0 : return GF_TRUE;
252 : }
253 :
254 : /*retrieves ISMACryp info for the given track & SDI*/
255 : GF_EXPORT
256 32 : GF_Err gf_isom_get_ismacryp_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion, const char **outSchemeURI, const char **outKMS_URI, Bool *outSelectiveEncryption, u32 *outIVLength, u32 *outKeyIndicationLength)
257 : {
258 : GF_TrackBox *trak;
259 : GF_ProtectionSchemeInfoBox *sinf;
260 :
261 32 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
262 32 : if (!trak) return GF_BAD_PARAM;
263 :
264 32 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ISMACRYP_SCHEME, NULL);
265 32 : if (!sinf) return GF_OK;
266 :
267 32 : if (outOriginalFormat) {
268 5 : *outOriginalFormat = sinf->original_format->data_format;
269 5 : if (IsMP4Description(sinf->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4;
270 : }
271 32 : if (outSchemeType) *outSchemeType = sinf->scheme_type->scheme_type;
272 32 : if (outSchemeVersion) *outSchemeVersion = sinf->scheme_type->scheme_version;
273 32 : if (outSchemeURI) *outSchemeURI = sinf->scheme_type->URI;
274 :
275 32 : if (sinf->info && sinf->info->ikms) {
276 32 : if (outKMS_URI) *outKMS_URI = sinf->info->ikms->URI;
277 : } else {
278 0 : if (outKMS_URI) *outKMS_URI = NULL;
279 : }
280 32 : if (sinf->info && sinf->info->isfm) {
281 32 : if (outSelectiveEncryption) *outSelectiveEncryption = sinf->info->isfm->selective_encryption;
282 32 : if (outIVLength) *outIVLength = sinf->info->isfm->IV_length;
283 32 : if (outKeyIndicationLength) *outKeyIndicationLength = sinf->info->isfm->key_indicator_length;
284 : } else {
285 0 : if (outSelectiveEncryption) *outSelectiveEncryption = GF_FALSE;
286 0 : if (outIVLength) *outIVLength = 0;
287 0 : if (outKeyIndicationLength) *outKeyIndicationLength = 0;
288 : }
289 : return GF_OK;
290 : }
291 :
292 :
293 : /*retrieves ISMACryp info for the given track & SDI*/
294 : GF_EXPORT
295 0 : GF_Err gf_isom_get_omadrm_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat,
296 : u32 *outSchemeType, u32 *outSchemeVersion,
297 : const char **outContentID, const char **outRightsIssuerURL, const char **outTextualHeaders, u32 *outTextualHeadersLen, u64 *outPlaintextLength, u32 *outEncryptionType, Bool *outSelectiveEncryption, u32 *outIVLength, u32 *outKeyIndicationLength)
298 : {
299 : GF_TrackBox *trak;
300 : GF_ProtectionSchemeInfoBox *sinf;
301 :
302 0 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
303 0 : if (!trak) return GF_BAD_PARAM;
304 :
305 0 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_OMADRM_SCHEME, NULL);
306 0 : if (!sinf) return GF_OK;
307 :
308 0 : if (!sinf->info || !sinf->info->odkm || !sinf->info->odkm->hdr) return GF_NON_COMPLIANT_BITSTREAM;
309 :
310 0 : if (outOriginalFormat) {
311 0 : *outOriginalFormat = sinf->original_format->data_format;
312 0 : if (IsMP4Description(sinf->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4;
313 : }
314 0 : if (outSchemeType) *outSchemeType = sinf->scheme_type->scheme_type;
315 0 : if (outSchemeVersion) *outSchemeVersion = sinf->scheme_type->scheme_version;
316 0 : if (outContentID) *outContentID = sinf->info->odkm->hdr->ContentID;
317 0 : if (outRightsIssuerURL) *outRightsIssuerURL = sinf->info->odkm->hdr->RightsIssuerURL;
318 0 : if (outTextualHeaders) {
319 0 : *outTextualHeaders = sinf->info->odkm->hdr->TextualHeaders;
320 0 : if (outTextualHeadersLen) *outTextualHeadersLen = sinf->info->odkm->hdr->TextualHeadersLen;
321 : }
322 0 : if (outPlaintextLength) *outPlaintextLength = sinf->info->odkm->hdr->PlaintextLength;
323 0 : if (outEncryptionType) *outEncryptionType = sinf->info->odkm->hdr->EncryptionMethod;
324 :
325 0 : if (sinf->info && sinf->info->odkm && sinf->info->odkm->fmt) {
326 0 : if (outSelectiveEncryption) *outSelectiveEncryption = sinf->info->odkm->fmt->selective_encryption;
327 0 : if (outIVLength) *outIVLength = sinf->info->odkm->fmt->IV_length;
328 0 : if (outKeyIndicationLength) *outKeyIndicationLength = sinf->info->odkm->fmt->key_indicator_length;
329 : } else {
330 0 : if (outSelectiveEncryption) *outSelectiveEncryption = GF_FALSE;
331 0 : if (outIVLength) *outIVLength = 0;
332 0 : if (outKeyIndicationLength) *outKeyIndicationLength = 0;
333 : }
334 : return GF_OK;
335 : }
336 :
337 : #ifndef GPAC_DISABLE_ISOM_WRITE
338 :
339 : #if 0 //unused
340 : /*! removes protection info (does not perform decryption), for ISMA, OMA and CENC of a sample description
341 : \param isom_file the target ISO file
342 : \param trackNumber the target track
343 : \param sampleDescriptionIndex the sample description index
344 : \return error if any
345 : */
346 : GF_Err gf_isom_remove_track_protection(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
347 : {
348 : GF_TrackBox *trak;
349 : GF_Err e;
350 : GF_SampleEntryBox *sea;
351 : GF_ProtectionSchemeInfoBox *sinf;
352 :
353 : e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
354 : if (e) return e;
355 :
356 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
357 : if (!trak || !trak->Media || !sampleDescriptionIndex) return GF_BAD_PARAM;
358 :
359 : sea = NULL;
360 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENC_SCHEME, &sea);
361 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBC_SCHEME, &sea);
362 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENS_SCHEME, &sea);
363 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBCS_SCHEME, &sea);
364 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ISMACRYP_SCHEME, &sea);
365 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_OMADRM_SCHEME, &sea);
366 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ADOBE_SCHEME, &sea);
367 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_PIFF_SCHEME, &sea);
368 : if (!sinf) return GF_OK;
369 :
370 : sea->type = sinf->original_format->data_format;
371 : while (1) {
372 : GF_Box *b = gf_isom_box_find_child(sea->child_boxes, GF_ISOM_BOX_TYPE_SINF);
373 : if (!b) break;
374 : gf_isom_box_del_parent(&sea->child_boxes, b);
375 : }
376 : if (sea->type == GF_ISOM_BOX_TYPE_264B) sea->type = GF_ISOM_BOX_TYPE_AVC1;
377 : if (sea->type == GF_ISOM_BOX_TYPE_265B) sea->type = GF_ISOM_BOX_TYPE_HVC1;
378 : return GF_OK;
379 : }
380 : #endif
381 :
382 : GF_EXPORT
383 5 : GF_Err gf_isom_change_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, char *scheme_uri, char *kms_uri)
384 : {
385 : GF_TrackBox *trak;
386 : GF_Err e;
387 : GF_SampleEntryBox *sea;
388 : GF_ProtectionSchemeInfoBox *sinf;
389 :
390 5 : e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
391 5 : if (e) return e;
392 :
393 5 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
394 5 : if (!trak || !trak->Media || !sampleDescriptionIndex) return GF_BAD_PARAM;
395 :
396 5 : sea = NULL;
397 5 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ISMACRYP_SCHEME, &sea);
398 5 : if (!sinf) return GF_OK;
399 :
400 5 : if (scheme_uri) {
401 0 : gf_free(sinf->scheme_type->URI);
402 0 : sinf->scheme_type->URI = gf_strdup(scheme_uri);
403 : }
404 5 : if (kms_uri) {
405 5 : gf_free(sinf->info->ikms->URI);
406 5 : sinf->info->ikms->URI = gf_strdup(kms_uri);
407 : }
408 : return GF_OK;
409 : }
410 :
411 :
412 229 : static GF_Err isom_set_protected_entry(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index, u8 version, u32 flags,
413 : u32 scheme_type, u32 scheme_version, char *scheme_uri, Bool is_isma, GF_ProtectionSchemeInfoBox **out_sinf)
414 : {
415 : u32 original_format;
416 : GF_Err e;
417 : GF_SampleEntryBox *sea;
418 : GF_ProtectionSchemeInfoBox *sinf;
419 229 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
420 229 : if (!trak) return GF_BAD_PARAM;
421 :
422 229 : e = Media_GetSampleDesc(trak->Media, desc_index, &sea, NULL);
423 229 : if (e) return e;
424 :
425 229 : original_format = sea->type;
426 229 : if (original_format==GF_ISOM_BOX_TYPE_GNRA) {
427 0 : original_format = ((GF_GenericAudioSampleEntryBox*)sea)->EntryType;
428 229 : } else if (original_format==GF_ISOM_BOX_TYPE_GNRV) {
429 0 : original_format = ((GF_GenericVisualSampleEntryBox*)sea)->EntryType;
430 229 : } else if (original_format==GF_ISOM_BOX_TYPE_GNRM) {
431 0 : original_format = ((GF_GenericSampleEntryBox*)sea)->EntryType;
432 : }
433 :
434 : /* Replacing the Media Type */
435 229 : switch (sea->type) {
436 40 : case GF_ISOM_BOX_TYPE_MP4A:
437 : case GF_ISOM_BOX_TYPE_DAMR:
438 : case GF_ISOM_BOX_TYPE_DEVC:
439 : case GF_ISOM_BOX_TYPE_DQCP:
440 : case GF_ISOM_BOX_TYPE_DSMV:
441 : case GF_ISOM_BOX_TYPE_AC3:
442 : case GF_ISOM_BOX_TYPE_EC3:
443 40 : sea->type = GF_ISOM_BOX_TYPE_ENCA;
444 40 : break;
445 0 : case GF_ISOM_BOX_TYPE_MP4V:
446 : case GF_ISOM_BOX_TYPE_D263:
447 0 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
448 0 : break;
449 : /*special case for AVC1*/
450 78 : case GF_ISOM_BOX_TYPE_AVC1:
451 : case GF_ISOM_BOX_TYPE_AVC2:
452 : case GF_ISOM_BOX_TYPE_AVC3:
453 : case GF_ISOM_BOX_TYPE_AVC4:
454 : case GF_ISOM_BOX_TYPE_SVC1:
455 : case GF_ISOM_BOX_TYPE_MVC1:
456 78 : if (is_isma)
457 : original_format = GF_ISOM_BOX_TYPE_264B;
458 78 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
459 78 : break;
460 35 : case GF_ISOM_BOX_TYPE_HVC1:
461 : case GF_ISOM_BOX_TYPE_HEV1:
462 : case GF_ISOM_BOX_TYPE_HVC2:
463 : case GF_ISOM_BOX_TYPE_HEV2:
464 : case GF_ISOM_BOX_TYPE_LHE1:
465 : case GF_ISOM_BOX_TYPE_LHV1:
466 : case GF_ISOM_BOX_TYPE_HVT1:
467 35 : if (is_isma)
468 : original_format = GF_ISOM_BOX_TYPE_265B;
469 35 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
470 35 : break;
471 0 : case GF_ISOM_BOX_TYPE_VVC1:
472 : case GF_ISOM_BOX_TYPE_VVI1:
473 0 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
474 0 : break;
475 16 : case GF_ISOM_BOX_TYPE_VP09:
476 16 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
477 16 : break;
478 60 : case GF_ISOM_BOX_TYPE_AV01:
479 60 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
480 60 : break;
481 0 : case GF_ISOM_BOX_TYPE_MP4S:
482 : case GF_ISOM_BOX_TYPE_LSR1:
483 0 : sea->type = GF_ISOM_BOX_TYPE_ENCS;
484 0 : break;
485 0 : case GF_ISOM_BOX_TYPE_STXT:
486 : case GF_ISOM_BOX_TYPE_WVTT:
487 : case GF_ISOM_BOX_TYPE_STPP:
488 0 : sea->type = GF_ISOM_BOX_TYPE_ENCT;
489 0 : break;
490 0 : case GF_ISOM_BOX_TYPE_ENCA:
491 : case GF_ISOM_BOX_TYPE_ENCV:
492 : case GF_ISOM_BOX_TYPE_ENCT:
493 : case GF_ISOM_BOX_TYPE_ENCM:
494 : case GF_ISOM_BOX_TYPE_ENCF:
495 : case GF_ISOM_BOX_TYPE_ENCS:
496 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] cannot set protection entry: file is already encrypted.\n"));
497 : return GF_BAD_PARAM;
498 0 : default:
499 0 : if (sea->internal_type == GF_ISOM_SAMPLE_ENTRY_AUDIO) {
500 0 : sea->type = GF_ISOM_BOX_TYPE_ENCA;
501 0 : } else if (sea->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
502 0 : sea->type = GF_ISOM_BOX_TYPE_ENCV;
503 : } else {
504 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] unsupported entry type %s for CENC.\n", gf_4cc_to_str(sea->type) ));
505 : return GF_BAD_PARAM;
506 : }
507 : }
508 :
509 229 : sinf = (GF_ProtectionSchemeInfoBox *)gf_isom_box_new_parent(&sea->child_boxes, GF_ISOM_BOX_TYPE_SINF);
510 229 : if (!sinf) return GF_OUT_OF_MEM;
511 :
512 229 : sinf->scheme_type = (GF_SchemeTypeBox *)gf_isom_box_new_parent(&sinf->child_boxes, GF_ISOM_BOX_TYPE_SCHM);
513 229 : if (!sinf->scheme_type) return GF_OUT_OF_MEM;
514 :
515 229 : sinf->scheme_type->version = version;
516 229 : sinf->scheme_type->flags = flags;
517 229 : sinf->scheme_type->scheme_type = scheme_type;
518 229 : sinf->scheme_type->scheme_version = scheme_version;
519 229 : if (scheme_uri && (sinf->scheme_type->flags == 1)) {
520 0 : sinf->scheme_type->URI = (char *)gf_malloc(sizeof(char)*strlen(scheme_uri));
521 0 : if (!sinf->scheme_type->URI) return GF_OUT_OF_MEM;
522 0 : memmove(sinf->scheme_type->URI, scheme_uri, strlen(scheme_uri));
523 : }
524 :
525 229 : sinf->original_format = (GF_OriginalFormatBox *)gf_isom_box_new_parent(&sinf->child_boxes, GF_ISOM_BOX_TYPE_FRMA);
526 229 : if (!sinf->original_format) return GF_OUT_OF_MEM;
527 229 : sinf->original_format->data_format = original_format;
528 :
529 : //common to isma, cenc and oma
530 229 : sinf->info = (GF_SchemeInformationBox *)gf_isom_box_new_parent(&sinf->child_boxes, GF_ISOM_BOX_TYPE_SCHI);
531 :
532 229 : *out_sinf = sinf;
533 229 : return GF_OK;
534 : }
535 :
536 : GF_EXPORT
537 11 : GF_Err gf_isom_set_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index, u32 scheme_type,
538 : u32 scheme_version, char *scheme_uri, char *kms_URI,
539 : Bool selective_encryption, u32 KI_length, u32 IV_length)
540 : {
541 : GF_Err e;
542 : GF_ProtectionSchemeInfoBox *sinf;
543 :
544 : //setup generic protection
545 11 : e = isom_set_protected_entry(the_file, trackNumber, desc_index, 0, 0, scheme_type, scheme_version, NULL, GF_TRUE, &sinf);
546 11 : if (e) return e;
547 :
548 11 : if (scheme_uri) {
549 11 : sinf->scheme_type->flags |= 0x000001;
550 11 : sinf->scheme_type->URI = gf_strdup(scheme_uri);
551 : }
552 :
553 11 : sinf->info->ikms = (GF_ISMAKMSBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_IKMS);
554 11 : if (!sinf->info->ikms) return GF_OUT_OF_MEM;
555 11 : sinf->info->ikms->URI = gf_strdup(kms_URI);
556 11 : if (!sinf->info->ikms->URI) return GF_OUT_OF_MEM;
557 :
558 11 : sinf->info->isfm = (GF_ISMASampleFormatBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_ISFM);
559 11 : if (!sinf->info->isfm) return GF_OUT_OF_MEM;
560 :
561 11 : sinf->info->isfm->selective_encryption = selective_encryption;
562 11 : sinf->info->isfm->key_indicator_length = KI_length;
563 11 : sinf->info->isfm->IV_length = IV_length;
564 11 : return GF_OK;
565 : }
566 :
567 0 : GF_Err gf_isom_set_oma_protection(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index,
568 : char *contentID, char *kms_URI, u32 encryption_type, u64 plainTextLength, char *textual_headers, u32 textual_headers_len,
569 : Bool selective_encryption, u32 KI_length, u32 IV_length)
570 : {
571 : GF_ProtectionSchemeInfoBox *sinf;
572 : GF_Err e;
573 :
574 : //setup generic protection
575 0 : e = isom_set_protected_entry(the_file, trackNumber, desc_index, 0, 0, GF_ISOM_OMADRM_SCHEME, 0x00000200, NULL, GF_FALSE, &sinf);
576 0 : if (e) return e;
577 :
578 0 : sinf->info->odkm = (GF_OMADRMKMSBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_ODKM);
579 0 : if (!sinf->info->odkm) return GF_OUT_OF_MEM;
580 0 : sinf->info->odkm->fmt = (GF_OMADRMAUFormatBox*)gf_isom_box_new_parent(&sinf->info->odkm->child_boxes, GF_ISOM_BOX_TYPE_ODAF);
581 0 : if (!sinf->info->odkm->fmt) return GF_OUT_OF_MEM;
582 0 : sinf->info->odkm->fmt->selective_encryption = selective_encryption;
583 0 : sinf->info->odkm->fmt->key_indicator_length = KI_length;
584 0 : sinf->info->odkm->fmt->IV_length = IV_length;
585 :
586 0 : sinf->info->odkm->hdr = (GF_OMADRMCommonHeaderBox*)gf_isom_box_new_parent(&sinf->info->odkm->child_boxes, GF_ISOM_BOX_TYPE_OHDR);
587 0 : if (!sinf->info->odkm->hdr) return GF_OUT_OF_MEM;
588 0 : sinf->info->odkm->hdr->EncryptionMethod = encryption_type;
589 0 : sinf->info->odkm->hdr->PaddingScheme = (encryption_type==0x01) ? 1 : 0;
590 0 : sinf->info->odkm->hdr->PlaintextLength = plainTextLength;
591 0 : if (contentID) sinf->info->odkm->hdr->ContentID = gf_strdup(contentID);
592 0 : if (kms_URI) sinf->info->odkm->hdr->RightsIssuerURL = gf_strdup(kms_URI);
593 0 : if (textual_headers) {
594 0 : sinf->info->odkm->hdr->TextualHeaders = (char*)gf_malloc(sizeof(char)*textual_headers_len);
595 0 : if (!sinf->info->odkm->hdr->TextualHeaders) return GF_OUT_OF_MEM;
596 : memcpy(sinf->info->odkm->hdr->TextualHeaders, textual_headers, sizeof(char)*textual_headers_len);
597 0 : sinf->info->odkm->hdr->TextualHeadersLen = textual_headers_len;
598 : }
599 : return GF_OK;
600 : }
601 :
602 0 : GF_Err gf_isom_set_generic_protection(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index, u32 scheme_type, u32 scheme_version, char *scheme_uri, char *kms_URI)
603 : {
604 : GF_Err e;
605 : GF_ProtectionSchemeInfoBox *sinf;
606 :
607 : //setup generic protection
608 0 : e = isom_set_protected_entry(the_file, trackNumber, desc_index, 0, 0, scheme_type, scheme_version, NULL, GF_TRUE, &sinf);
609 0 : if (e) return e;
610 :
611 0 : if (scheme_uri) {
612 0 : sinf->scheme_type->flags |= 0x000001;
613 0 : sinf->scheme_type->URI = gf_strdup(scheme_uri);
614 : }
615 :
616 0 : if (kms_URI) {
617 0 : sinf->info->ikms = (GF_ISMAKMSBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_IKMS);
618 0 : sinf->info->ikms->URI = gf_strdup(kms_URI);
619 : }
620 : return GF_OK;
621 : }
622 : #endif // GPAC_DISABLE_ISOM_WRITE
623 :
624 : GF_EXPORT
625 330 : GF_Err gf_isom_get_original_format_type(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat)
626 : {
627 : GF_TrackBox *trak;
628 : GF_SampleEntryBox *sea;
629 : GF_ProtectionSchemeInfoBox *sinf;
630 : u32 i, count;
631 :
632 330 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
633 330 : if (!trak) return GF_BAD_PARAM;
634 :
635 330 : count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
636 334 : for (i=0; i<count; i++) {
637 334 : if (sampleDescriptionIndex && (i+1 != sampleDescriptionIndex)) continue;
638 :
639 330 : Media_GetSampleDesc(trak->Media, i+1, &sea, NULL);
640 330 : if (!sea) return GF_BAD_PARAM;
641 330 : sinf = (GF_ProtectionSchemeInfoBox*) gf_isom_box_find_child(sea->child_boxes, GF_ISOM_BOX_TYPE_SINF);
642 330 : if (!sinf) continue;
643 :
644 330 : if (outOriginalFormat && sinf->original_format) {
645 330 : *outOriginalFormat = sinf->original_format->data_format;
646 : }
647 : return GF_OK;
648 : }
649 0 : if (outOriginalFormat) *outOriginalFormat = 0;
650 : return GF_OK;
651 : }
652 :
653 :
654 : /* Common Encryption*/
655 : GF_EXPORT
656 47937 : Bool gf_isom_is_cenc_media(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
657 : {
658 : GF_TrackBox *trak;
659 : GF_ProtectionSchemeInfoBox *sinf;
660 : u32 i, count;
661 :
662 47937 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
663 47937 : if (!trak) return GF_FALSE;
664 :
665 47937 : count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
666 58247 : for (i=0; i<count; i++) {
667 48737 : if (sampleDescriptionIndex && (i+1 != sampleDescriptionIndex)) continue;
668 :
669 47937 : sinf = isom_get_sinf_entry(trak, i+1, GF_ISOM_CENC_SCHEME, NULL);
670 47937 : if (!sinf) sinf = isom_get_sinf_entry(trak, i+1, GF_ISOM_CBC_SCHEME, NULL);
671 47937 : if (!sinf) sinf = isom_get_sinf_entry(trak, i+1, GF_ISOM_CENS_SCHEME, NULL);
672 47937 : if (!sinf) sinf = isom_get_sinf_entry(trak, i+1, GF_ISOM_CBCS_SCHEME, NULL);
673 47937 : if (!sinf) sinf = isom_get_sinf_entry(trak, i+1, GF_ISOM_PIFF_SCHEME, NULL);
674 :
675 47937 : if (!sinf) continue;
676 :
677 : /*non-encrypted or non-CENC*/
678 38427 : if (!sinf->scheme_type)
679 : return GF_FALSE;
680 :
681 38427 : switch (sinf->scheme_type->scheme_type) {
682 : case GF_ISOM_CENC_SCHEME:
683 : case GF_ISOM_CBC_SCHEME:
684 : case GF_ISOM_CENS_SCHEME:
685 : case GF_ISOM_CBCS_SCHEME:
686 : case GF_ISOM_SVE1_SCHEME:
687 : return GF_TRUE;
688 0 : default:
689 0 : return GF_FALSE;
690 : }
691 : return GF_TRUE;
692 : }
693 : return GF_FALSE;
694 :
695 : }
696 :
697 : GF_EXPORT
698 35179 : GF_Err gf_isom_get_cenc_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion)
699 : {
700 : GF_TrackBox *trak;
701 : GF_ProtectionSchemeInfoBox *sinf;
702 :
703 35179 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
704 35179 : if (!trak) return GF_BAD_PARAM;
705 :
706 :
707 35179 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENC_SCHEME, NULL);
708 35179 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBC_SCHEME, NULL);
709 35179 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENS_SCHEME, NULL);
710 35179 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBCS_SCHEME, NULL);
711 35179 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_PIFF_SCHEME, NULL);
712 :
713 35179 : if (!sinf) return GF_BAD_PARAM;
714 :
715 35175 : if (outOriginalFormat) {
716 77 : *outOriginalFormat = sinf->original_format->data_format;
717 77 : if (IsMP4Description(sinf->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4;
718 : }
719 35175 : if (outSchemeType) *outSchemeType = sinf->scheme_type->scheme_type;
720 35175 : if (outSchemeVersion) *outSchemeVersion = sinf->scheme_type->scheme_version;
721 : return GF_OK;
722 : }
723 :
724 :
725 : #ifndef GPAC_DISABLE_ISOM_WRITE
726 :
727 208 : GF_Err gf_isom_set_cenc_protection(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index, u32 scheme_type,
728 : u32 scheme_version, u32 default_IsEncrypted, u8 default_crypt_byte_block, u8 default_skip_byte_block,
729 : u8 *key_info, u32 key_info_size)
730 : {
731 : GF_Err e;
732 : GF_ProtectionSchemeInfoBox *sinf;
733 :
734 208 : if (!gf_cenc_validate_key_info(key_info, key_info_size))
735 : return GF_BAD_PARAM;
736 :
737 : //setup generic protection
738 208 : e = isom_set_protected_entry(the_file, trackNumber, desc_index, 0, 0, scheme_type, scheme_version, NULL, GF_FALSE, &sinf);
739 208 : if (e) return e;
740 :
741 208 : if (scheme_type==GF_ISOM_PIFF_SCHEME) {
742 0 : sinf->info->piff_tenc = (GF_PIFFTrackEncryptionBox *) gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_UUID_TENC);
743 0 : if (!sinf->info->piff_tenc) return GF_OUT_OF_MEM;
744 0 : sinf->info->piff_tenc->AlgorithmID = 1;
745 0 : sinf->info->piff_tenc->key_info[0] = 0;
746 0 : sinf->info->piff_tenc->key_info[1] = 0;
747 0 : sinf->info->piff_tenc->key_info[2] = 0;
748 0 : sinf->info->piff_tenc->key_info[3] = key_info[3];
749 0 : memcpy(sinf->info->piff_tenc->key_info+4, key_info+4, 16*sizeof(char));
750 : }
751 : //tenc only for mkey
752 208 : else if (!key_info[0]) {
753 205 : if (key_info_size<20) return GF_BAD_PARAM;
754 205 : sinf->info->tenc = (GF_TrackEncryptionBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_TENC);
755 205 : if (!sinf->info->tenc) return GF_OUT_OF_MEM;
756 :
757 205 : sinf->info->tenc->isProtected = default_IsEncrypted;
758 205 : if ((scheme_type == GF_ISOM_CENS_SCHEME) || (scheme_type == GF_ISOM_CBCS_SCHEME)) {
759 49 : sinf->info->tenc->version = 1;
760 49 : sinf->info->tenc->crypt_byte_block = default_crypt_byte_block;
761 49 : sinf->info->tenc->skip_byte_block = default_skip_byte_block;
762 : }
763 205 : if (key_info_size>37) key_info_size = 37;
764 205 : memcpy(sinf->info->tenc->key_info, key_info, key_info_size);
765 : }
766 : return GF_OK;
767 : }
768 :
769 :
770 : #if 0
771 : /*! removes CENC SAI size info
772 : \param isom_file the target ISO file
773 : \param trackNumber the target track
774 : \return error if any
775 : */
776 : GF_Err gf_isom_remove_cenc_saiz(GF_ISOFile *the_file, u32 trackNumber)
777 : {
778 : u32 i;
779 : GF_SampleTableBox *stbl;
780 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
781 : if (!trak) return GF_BAD_PARAM;
782 :
783 : stbl = trak->Media->information->sampleTable;
784 : if (!stbl)
785 : return GF_BAD_PARAM;
786 :
787 : for (i = 0; i < gf_list_count(stbl->sai_sizes); i++) {
788 : GF_SampleAuxiliaryInfoSizeBox *saiz = (GF_SampleAuxiliaryInfoSizeBox *)gf_list_get(stbl->sai_sizes, i);
789 : switch (saiz->aux_info_type) {
790 : case GF_ISOM_CENC_SCHEME:
791 : case GF_ISOM_CENS_SCHEME:
792 : case GF_ISOM_CBC_SCHEME:
793 : case GF_ISOM_CBCS_SCHEME:
794 : case 0:
795 : break;
796 : default:
797 : continue;
798 : }
799 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)saiz);
800 : gf_list_rem(stbl->sai_sizes, i);
801 : i--;
802 : }
803 :
804 : if (!gf_list_count(stbl->sai_sizes)) {
805 : gf_list_del(stbl->sai_sizes);
806 : stbl->sai_sizes = NULL;
807 : }
808 :
809 : return GF_OK;
810 : }
811 :
812 : /*! removes CENC SAI offset info
813 : \param isom_file the target ISO file
814 : \param trackNumber the target track
815 : \return error if any
816 : */
817 : GF_Err gf_isom_remove_cenc_saio(GF_ISOFile *the_file, u32 trackNumber)
818 : {
819 : u32 i;
820 : GF_SampleTableBox *stbl;
821 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
822 : if (!trak) return GF_BAD_PARAM;
823 :
824 : stbl = trak->Media->information->sampleTable;
825 : if (!stbl)
826 : return GF_BAD_PARAM;
827 :
828 : for (i = 0; i < gf_list_count(stbl->sai_offsets); i++) {
829 : GF_SampleAuxiliaryInfoOffsetBox *saio = (GF_SampleAuxiliaryInfoOffsetBox *)gf_list_get(stbl->sai_offsets, i);
830 : switch (saio->aux_info_type) {
831 : case GF_ISOM_CENC_SCHEME:
832 : case GF_ISOM_CENS_SCHEME:
833 : case GF_ISOM_CBC_SCHEME:
834 : case GF_ISOM_CBCS_SCHEME:
835 : case 0:
836 : break;
837 : default:
838 : continue;
839 : }
840 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)saio);
841 : gf_list_rem(stbl->sai_offsets, i);
842 : i--;
843 : }
844 :
845 : if (!gf_list_count(stbl->sai_offsets)) {
846 : gf_list_del(stbl->sai_offsets);
847 : stbl->sai_offsets = NULL;
848 : }
849 :
850 : return GF_OK;
851 : }
852 : #endif
853 :
854 314 : GF_Err gf_cenc_set_pssh(GF_ISOFile *file, bin128 systemID, u32 version, u32 KID_count, bin128 *KIDs, u8 *data, u32 len, u32 pssh_mode)
855 : {
856 : GF_ProtectionSystemHeaderBox *pssh = NULL;
857 : GF_PIFFProtectionSystemHeaderBox *pssh_piff = NULL;
858 314 : u32 i=0;
859 : GF_Box *a;
860 : GF_List **child_boxes = NULL;
861 :
862 314 : if (pssh_mode==2) {
863 33 : if (!file->meta) return GF_BAD_PARAM;
864 33 : if (!file->meta->child_boxes) file->meta->child_boxes = gf_list_new();
865 33 : child_boxes = &file->meta->child_boxes;
866 281 : } else if (file->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) {
867 0 : if (!file->moof) return GF_BAD_PARAM;
868 0 : if (!file->moof->PSSHs) file->moof->PSSHs = gf_list_new();
869 0 : child_boxes = &file->moof->PSSHs;
870 : } else {
871 281 : if (!file->moov) return GF_BAD_PARAM;
872 281 : if (!file->moov->child_boxes) file->moov->child_boxes = gf_list_new();
873 281 : child_boxes = &file->moov->child_boxes;
874 : }
875 :
876 1061 : while ((a = gf_list_enum(*child_boxes, &i))) {
877 : GF_UUIDBox *uuid = (GF_UUIDBox *)a;
878 747 : if (a->type==GF_ISOM_BOX_TYPE_PSSH) {
879 : pssh = (GF_ProtectionSystemHeaderBox *)a;
880 84 : if (!memcmp(pssh->SystemID, systemID, sizeof(bin128))) break;
881 : pssh = NULL;
882 663 : } else if ((a->type==GF_ISOM_BOX_TYPE_UUID) && (uuid->internal_4cc==GF_ISOM_BOX_UUID_PSSH)) {
883 : pssh_piff = (GF_PIFFProtectionSystemHeaderBox *)a;
884 0 : if (!memcmp(pssh_piff->SystemID, systemID, sizeof(bin128))) break;
885 : pssh_piff = NULL;
886 : }
887 : }
888 : //we had a pssh with same ID but different private data, keep both...
889 314 : if (pssh && pssh->private_data && len && memcmp(pssh->private_data, data, sizeof(char)*len) ) {
890 : pssh = NULL;
891 : }
892 314 : else if (pssh_piff && pssh_piff->private_data && len && memcmp(pssh_piff->private_data, data, sizeof(char)*len) ) {
893 : pssh_piff = NULL;
894 : }
895 :
896 314 : if (!pssh && !pssh_piff) {
897 314 : if (pssh_mode==1) {
898 0 : pssh_piff = (GF_PIFFProtectionSystemHeaderBox *)gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_UUID_PSSH);
899 0 : if (!pssh_piff) return GF_IO_ERR;
900 0 : memcpy((char *)pssh_piff->SystemID, systemID, sizeof(bin128));
901 0 : pssh_piff->version = version;
902 : } else {
903 314 : pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_TYPE_PSSH);
904 314 : if (!pssh) return GF_IO_ERR;
905 314 : memcpy((char *)pssh->SystemID, systemID, sizeof(bin128));
906 314 : pssh->version = version;
907 : }
908 : }
909 :
910 314 : if (pssh && KID_count) {
911 : u32 j;
912 290 : for (j=0; j<KID_count; j++) {
913 : Bool found = GF_FALSE;
914 389 : for (i=0; i<pssh->KID_count; i++) {
915 99 : if (!memcmp(pssh->KIDs[i], KIDs[j], sizeof(bin128))) found = GF_TRUE;
916 : }
917 :
918 290 : if (!found) {
919 290 : pssh->KIDs = gf_realloc(pssh->KIDs, sizeof(bin128) * (pssh->KID_count+1));
920 290 : if (!pssh->KIDs) return GF_OUT_OF_MEM;
921 290 : memcpy(pssh->KIDs[pssh->KID_count], KIDs[j], sizeof(bin128));
922 290 : pssh->KID_count++;
923 : }
924 : }
925 230 : if (!pssh->version)
926 0 : pssh->version = 1;
927 : }
928 :
929 314 : if (pssh) {
930 314 : if (!pssh->private_data_size) {
931 314 : pssh->private_data_size = len;
932 314 : if (len) {
933 314 : if (!pssh->private_data) {
934 314 : pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
935 314 : if (!pssh->private_data) return GF_OUT_OF_MEM;
936 : }
937 314 : memcpy((char *)pssh->private_data, data, pssh->private_data_size);
938 : }
939 : }
940 0 : } else if (pssh_piff) {
941 0 : if (!pssh_piff->private_data_size) {
942 0 : pssh_piff->private_data_size = len;
943 0 : if (len) {
944 0 : if (!pssh_piff->private_data) {
945 0 : pssh_piff->private_data = (u8 *)gf_malloc(pssh_piff->private_data_size*sizeof(char));
946 0 : if (!pssh_piff->private_data) return GF_OUT_OF_MEM;
947 : }
948 0 : memcpy((char *)pssh_piff->private_data, data, pssh_piff->private_data_size);
949 : }
950 : }
951 : }
952 : return GF_OK;
953 : }
954 :
955 :
956 :
957 1252 : GF_Err gf_isom_remove_samp_enc_box(GF_ISOFile *the_file, u32 trackNumber)
958 : {
959 : u32 i;
960 : GF_SampleTableBox *stbl;
961 1252 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
962 1252 : if (!trak) return GF_BAD_PARAM;
963 1252 : stbl = trak->Media->information->sampleTable;
964 1252 : if (!stbl)
965 : return GF_BAD_PARAM;
966 :
967 6386 : for (i = 0; i < gf_list_count(stbl->child_boxes); i++) {
968 6386 : GF_Box *a = (GF_Box *)gf_list_get(stbl->child_boxes, i);
969 6386 : if ((a->type ==GF_ISOM_BOX_TYPE_UUID) && (((GF_UUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC)) {
970 0 : gf_isom_box_del_parent(&stbl->child_boxes, a);
971 0 : i--;
972 : }
973 6386 : else if (a->type == GF_ISOM_BOX_TYPE_SENC) {
974 0 : gf_isom_box_del_parent(&stbl->child_boxes, a);
975 0 : i--;
976 : }
977 : }
978 :
979 1252 : if (!gf_list_count(stbl->child_boxes)) {
980 0 : gf_list_del(stbl->child_boxes);
981 0 : stbl->child_boxes = NULL;
982 : }
983 2650 : for (i = 0; i < gf_list_count(trak->child_boxes); i++) {
984 2650 : GF_Box *a = (GF_Box *)gf_list_get(trak->child_boxes, i);
985 2650 : if ((a->type ==GF_ISOM_BOX_TYPE_UUID) && (((GF_UUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC)) {
986 0 : gf_isom_box_del_parent(&trak->child_boxes, a);
987 0 : i--;
988 : }
989 2650 : else if (a->type == GF_ISOM_BOX_TYPE_SENC) {
990 0 : gf_isom_box_del_parent(&trak->child_boxes, a);
991 0 : i--;
992 : }
993 : }
994 : return GF_OK;
995 : }
996 :
997 1252 : GF_Err gf_isom_remove_samp_group_box(GF_ISOFile *the_file, u32 trackNumber)
998 : {
999 : u32 i;
1000 : GF_SampleTableBox *stbl;
1001 1252 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1002 1252 : if (!trak) return GF_BAD_PARAM;
1003 1252 : stbl = trak->Media->information->sampleTable;
1004 1252 : if (!stbl)
1005 : return GF_BAD_PARAM;
1006 :
1007 87 : for (i = 0; i < gf_list_count(stbl->sampleGroupsDescription); i++) {
1008 87 : GF_SampleGroupDescriptionBox *a = (GF_SampleGroupDescriptionBox *)gf_list_get(stbl->sampleGroupsDescription, i);
1009 87 : if (a->grouping_type == GF_ISOM_SAMPLE_GROUP_SEIG) {
1010 17 : gf_list_rem(stbl->sampleGroupsDescription, i);
1011 17 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) a);
1012 17 : i--;
1013 : }
1014 : }
1015 1252 : if (!gf_list_count(stbl->sampleGroupsDescription)) {
1016 1186 : gf_list_del(stbl->sampleGroupsDescription);
1017 1186 : stbl->sampleGroupsDescription = NULL;
1018 : }
1019 :
1020 6 : for (i = 0; i < gf_list_count(stbl->sampleGroups); i++) {
1021 6 : GF_SampleGroupBox *a = (GF_SampleGroupBox *)gf_list_get(stbl->sampleGroups, i);
1022 6 : if (a->grouping_type == GF_ISOM_SAMPLE_GROUP_SEIG) {
1023 0 : gf_list_rem(stbl->sampleGroups, i);
1024 0 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) a);
1025 0 : i--;
1026 : }
1027 : }
1028 1252 : if (!gf_list_count(stbl->sampleGroups)) {
1029 1246 : gf_list_del(stbl->sampleGroups);
1030 1246 : stbl->sampleGroups = NULL;
1031 : }
1032 :
1033 : return GF_OK;
1034 : }
1035 :
1036 : #if 0 //unused
1037 : /*! removes CENC PSSH box
1038 : \param isom_file the target ISO file
1039 : \return error if any
1040 : */
1041 : GF_Err gf_isom_remove_pssh_box(GF_ISOFile *the_file)
1042 : {
1043 : u32 i;
1044 : for (i = 0; i < gf_list_count(the_file->moov->child_boxes); i++) {
1045 : GF_Box *a = (GF_Box *)gf_list_get(the_file->moov->child_boxes, i);
1046 : GF_UUIDBox *uuid = (GF_UUIDBox *)a;
1047 : if ((a->type == GF_ISOM_BOX_TYPE_PSSH)
1048 : || ((a->type == GF_ISOM_BOX_TYPE_UUID) && (uuid->internal_4cc == GF_ISOM_BOX_UUID_PSSH))
1049 : ) {
1050 : gf_isom_box_del_parent(&the_file->moov->child_boxes, a);
1051 : i--;
1052 : }
1053 : }
1054 :
1055 : if (!gf_list_count(the_file->moov->child_boxes)) {
1056 : gf_list_del(the_file->moov->child_boxes);
1057 : the_file->moov->child_boxes = NULL;
1058 : }
1059 :
1060 : return GF_OK;
1061 : }
1062 : #endif
1063 :
1064 :
1065 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1066 :
1067 26 : GF_SampleEncryptionBox * gf_isom_create_piff_psec_box(u8 version, u32 flags, u32 AlgorithmID, u8 IV_size, bin128 KID)
1068 : {
1069 : GF_SampleEncryptionBox *psec;
1070 :
1071 26 : psec = (GF_SampleEncryptionBox *) gf_isom_box_new(GF_ISOM_BOX_UUID_PSEC);
1072 26 : if (!psec)
1073 : return NULL;
1074 26 : psec->version = version;
1075 26 : psec->flags = flags;
1076 26 : psec->piff_type = 1;
1077 26 : if (psec->flags & 0x1) {
1078 0 : psec->AlgorithmID = AlgorithmID;
1079 0 : psec->IV_size = IV_size;
1080 0 : strcpy((char *)psec->KID, (const char *)KID);
1081 : }
1082 26 : psec->samp_aux_info = gf_list_new();
1083 :
1084 26 : return psec;
1085 : }
1086 :
1087 600 : GF_SampleEncryptionBox * gf_isom_create_samp_enc_box(u8 version, u32 flags)
1088 : {
1089 : GF_SampleEncryptionBox *senc;
1090 :
1091 600 : senc = (GF_SampleEncryptionBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SENC);
1092 600 : if (!senc)
1093 : return NULL;
1094 600 : senc->version = version;
1095 600 : senc->flags = flags;
1096 600 : senc->samp_aux_info = gf_list_new();
1097 :
1098 600 : return senc;
1099 : }
1100 :
1101 198 : GF_Err gf_isom_cenc_allocate_storage(GF_ISOFile *the_file, u32 trackNumber)
1102 : {
1103 198 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1104 198 : if (!trak) return GF_BAD_PARAM;
1105 :
1106 198 : if (trak->sample_encryption) return GF_OK;
1107 198 : trak->sample_encryption = (GF_SampleEncryptionBox *)gf_isom_create_samp_enc_box(0, 0);
1108 : //senc will be written and destroyed with the other boxes
1109 198 : if (!trak->child_boxes) trak->child_boxes = gf_list_new();
1110 198 : return gf_list_add(trak->child_boxes, trak->sample_encryption);
1111 : }
1112 :
1113 12 : GF_Err gf_isom_piff_allocate_storage(GF_ISOFile *the_file, u32 trackNumber, u32 AlgorithmID, u8 IV_size, bin128 KID)
1114 : {
1115 12 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1116 12 : if (!trak) return GF_BAD_PARAM;
1117 :
1118 12 : if (trak->sample_encryption) return GF_OK;
1119 12 : trak->sample_encryption = (GF_SampleEncryptionBox *)gf_isom_create_piff_psec_box(1, 0, AlgorithmID, IV_size, KID);
1120 : //senc will be written and destroyed with the other boxes
1121 12 : if (!trak->child_boxes) trak->child_boxes = gf_list_new();
1122 12 : return gf_list_add(trak->child_boxes, trak->sample_encryption);
1123 : }
1124 :
1125 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1126 42321 : void gf_isom_cenc_set_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 len, Bool saio_32bits, Bool use_multikey)
1127 : {
1128 : u32 i;
1129 42321 : GF_List **child_boxes = stbl ? &stbl->child_boxes : &traf->child_boxes;
1130 42321 : if (!senc->cenc_saiz) {
1131 440 : senc->cenc_saiz = (GF_SampleAuxiliaryInfoSizeBox *) gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_TYPE_SAIZ);
1132 440 : if (!senc->cenc_saiz) return;
1133 : //as per 3rd edition of cenc "so content SHOULD be created omitting these optional fields" ...
1134 440 : senc->cenc_saiz->aux_info_type = 0;
1135 440 : senc->cenc_saiz->aux_info_type_parameter = use_multikey ? 1 : 0;
1136 440 : if (stbl)
1137 96 : stbl_on_child_box((GF_Box*)stbl, (GF_Box *)senc->cenc_saiz, GF_FALSE);
1138 : else
1139 344 : traf_on_child_box((GF_Box*)traf, (GF_Box *)senc->cenc_saiz, GF_FALSE);
1140 : }
1141 42321 : if (!senc->cenc_saio) {
1142 440 : senc->cenc_saio = (GF_SampleAuxiliaryInfoOffsetBox *) gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_TYPE_SAIO);
1143 440 : if (!senc->cenc_saio) return;
1144 : //force using version 1 for saio box, it could be redundant when we use 64 bits for offset
1145 440 : senc->cenc_saio->version = saio_32bits ? 0 : 1;
1146 : //as per 3rd edition of cenc "so content SHOULD be created omitting these optional fields" ...
1147 440 : senc->cenc_saio->aux_info_type = 0;
1148 440 : senc->cenc_saiz->aux_info_type_parameter = use_multikey ? 1 : 0;
1149 440 : senc->cenc_saio->entry_count = 1;
1150 440 : if (stbl)
1151 96 : stbl_on_child_box((GF_Box*)stbl, (GF_Box *)senc->cenc_saio, GF_FALSE);
1152 : else
1153 344 : traf_on_child_box((GF_Box*)traf, (GF_Box *)senc->cenc_saio, GF_FALSE);
1154 : }
1155 :
1156 42321 : if (!senc->cenc_saiz->sample_count || ((senc->cenc_saiz->default_sample_info_size==len) && len) ) {
1157 31971 : senc->cenc_saiz->sample_count ++;
1158 31971 : senc->cenc_saiz->default_sample_info_size = len;
1159 : } else {
1160 10350 : if (senc->cenc_saiz->sample_count + 1 > senc->cenc_saiz->sample_alloc) {
1161 678 : if (!senc->cenc_saiz->sample_alloc) senc->cenc_saiz->sample_alloc = senc->cenc_saiz->sample_count+1;
1162 540 : else senc->cenc_saiz->sample_alloc *= 2;
1163 :
1164 678 : senc->cenc_saiz->sample_info_size = (u8*)gf_realloc(senc->cenc_saiz->sample_info_size, sizeof(u8)*(senc->cenc_saiz->sample_alloc));
1165 : }
1166 :
1167 10350 : if (senc->cenc_saiz->default_sample_info_size || (senc->cenc_saiz->sample_count==1)) {
1168 3438 : for (i=0; i<senc->cenc_saiz->sample_count; i++)
1169 3438 : senc->cenc_saiz->sample_info_size[i] = senc->cenc_saiz->default_sample_info_size;
1170 138 : senc->cenc_saiz->default_sample_info_size = 0;
1171 : }
1172 10350 : senc->cenc_saiz->sample_info_size[senc->cenc_saiz->sample_count] = len;
1173 10350 : senc->cenc_saiz->sample_count++;
1174 : }
1175 : }
1176 :
1177 4169 : GF_Err gf_isom_cenc_merge_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, u64 offset, u32 len)
1178 : {
1179 : u32 i;
1180 : assert(stbl);
1181 4169 : if (!senc->cenc_saiz) {
1182 70 : senc->cenc_saiz = (GF_SampleAuxiliaryInfoSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SAIZ);
1183 70 : if (!senc->cenc_saiz) return GF_OUT_OF_MEM;
1184 70 : senc->cenc_saiz->aux_info_type = GF_ISOM_CENC_SCHEME;
1185 70 : senc->cenc_saiz->aux_info_type_parameter = 0;
1186 70 : stbl_on_child_box((GF_Box*)stbl, (GF_Box *)senc->cenc_saiz, GF_FALSE);
1187 : }
1188 4169 : if (!senc->cenc_saio) {
1189 70 : senc->cenc_saio = (GF_SampleAuxiliaryInfoOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_SAIO);
1190 70 : if (!senc->cenc_saio) return GF_OUT_OF_MEM;
1191 : //force using version 1 for saio box, it could be redundant when we use 64 bits for offset
1192 70 : senc->cenc_saio->version = 1;
1193 70 : senc->cenc_saio->aux_info_type = GF_ISOM_CENC_SCHEME;
1194 70 : senc->cenc_saio->aux_info_type_parameter = 0;
1195 70 : stbl_on_child_box((GF_Box*)stbl, (GF_Box *)senc->cenc_saio, GF_FALSE);
1196 : }
1197 :
1198 4169 : if (!senc->cenc_saiz->sample_count || (!senc->cenc_saiz->sample_alloc && (senc->cenc_saiz->default_sample_info_size==len))) {
1199 3449 : senc->cenc_saiz->sample_count ++;
1200 3449 : senc->cenc_saiz->default_sample_info_size = len;
1201 : } else {
1202 720 : if (senc->cenc_saiz->sample_count + 1 > senc->cenc_saiz->sample_alloc) {
1203 150 : if (!senc->cenc_saiz->sample_alloc) senc->cenc_saiz->sample_alloc = senc->cenc_saiz->sample_count + 1;
1204 120 : else senc->cenc_saiz->sample_alloc *= 2;
1205 150 : senc->cenc_saiz->sample_info_size = (u8*)gf_realloc(senc->cenc_saiz->sample_info_size, sizeof(u8)*(senc->cenc_saiz->sample_alloc));
1206 150 : if (!senc->cenc_saiz->sample_info_size) return GF_OUT_OF_MEM;
1207 : }
1208 :
1209 720 : if (senc->cenc_saiz->default_sample_info_size) {
1210 30 : for (i=0; i<senc->cenc_saiz->sample_count; i++)
1211 30 : senc->cenc_saiz->sample_info_size[i] = senc->cenc_saiz->default_sample_info_size;
1212 30 : senc->cenc_saiz->default_sample_info_size = 0;
1213 : }
1214 720 : senc->cenc_saiz->sample_info_size[senc->cenc_saiz->sample_count] = len;
1215 720 : senc->cenc_saiz->sample_count++;
1216 : }
1217 :
1218 4169 : if (!senc->cenc_saio->entry_count) {
1219 70 : senc->cenc_saio->offsets = (u64 *)gf_malloc(sizeof(u64));
1220 70 : if (!senc->cenc_saio->offsets) return GF_OUT_OF_MEM;
1221 70 : senc->cenc_saio->offsets[0] = offset;
1222 70 : senc->cenc_saio->entry_count ++;
1223 70 : senc->cenc_saio->entry_alloc = 1;
1224 : } else {
1225 4099 : if (senc->cenc_saio->entry_count >= senc->cenc_saio->entry_alloc) {
1226 104 : senc->cenc_saio->entry_alloc += 50;
1227 104 : senc->cenc_saio->offsets = (u64*)gf_realloc(senc->cenc_saio->offsets, sizeof(u64)*(senc->cenc_saio->entry_alloc));
1228 104 : if (!senc->cenc_saio->offsets) return GF_OUT_OF_MEM;
1229 : }
1230 4099 : senc->cenc_saio->offsets[senc->cenc_saio->entry_count] = offset;
1231 4099 : senc->cenc_saio->entry_count++;
1232 : }
1233 4169 : if (offset > 0xFFFFFFFFUL)
1234 0 : senc->cenc_saio->version=1;
1235 : return GF_OK;
1236 : }
1237 : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
1238 :
1239 21925 : GF_Err gf_isom_track_cenc_add_sample_info(GF_ISOFile *the_file, u32 trackNumber, u32 container_type, u8 *buf, u32 len, Bool use_subsamples, Bool use_saio_32bit, Bool use_multikey)
1240 : {
1241 : GF_SampleEncryptionBox *senc;
1242 : GF_CENCSampleAuxInfo *sai;
1243 : GF_SampleTableBox *stbl;
1244 21925 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1245 21925 : if (!trak) return GF_BAD_PARAM;
1246 21925 : stbl = trak->Media->information->sampleTable;
1247 21925 : if (!stbl) return GF_BAD_PARAM;
1248 :
1249 21925 : switch (container_type) {
1250 21925 : case GF_ISOM_BOX_UUID_PSEC:
1251 : case GF_ISOM_BOX_TYPE_SENC:
1252 : case 0:
1253 21925 : senc = trak->sample_encryption;
1254 : break;
1255 : default:
1256 : return GF_NOT_SUPPORTED;
1257 : }
1258 :
1259 21925 : if (len && buf) {
1260 19348 : GF_SAFEALLOC(sai, GF_CENCSampleAuxInfo);
1261 19348 : if (!sai) return GF_OUT_OF_MEM;
1262 19348 : sai->cenc_data_size = len;
1263 19348 : sai->cenc_data = gf_malloc(sizeof(u8) * len);
1264 19348 : if (!sai->cenc_data) {
1265 0 : gf_free(sai);
1266 0 : return GF_OUT_OF_MEM;
1267 : }
1268 : memcpy(sai->cenc_data, buf, len);
1269 :
1270 19348 : gf_list_add(senc->samp_aux_info, sai);
1271 : } else {
1272 2577 : GF_SAFEALLOC(sai, GF_CENCSampleAuxInfo);
1273 2577 : if (!sai) return GF_OUT_OF_MEM;
1274 2577 : gf_list_add(senc->samp_aux_info, sai);
1275 2577 : sai->isNotProtected = 1;
1276 : }
1277 21925 : if (use_subsamples)
1278 17965 : senc->flags = 0x00000002;
1279 21925 : if (use_multikey)
1280 2250 : senc->version = 1;
1281 :
1282 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1283 21925 : gf_isom_cenc_set_saiz_saio(senc, stbl, NULL, sai->cenc_data_size, use_saio_32bit, use_multikey);
1284 : #endif
1285 :
1286 21925 : return GF_OK;
1287 : }
1288 :
1289 :
1290 : GF_EXPORT
1291 58195 : void gf_isom_cenc_samp_aux_info_del(GF_CENCSampleAuxInfo *samp)
1292 : {
1293 58195 : if (!samp) return;
1294 58195 : if (samp->cenc_data) gf_free(samp->cenc_data);
1295 58195 : gf_free(samp);
1296 : }
1297 :
1298 34819 : Bool gf_isom_cenc_has_saiz_saio_full(GF_SampleTableBox *stbl, void *_traf, u32 scheme_type)
1299 : {
1300 : u32 i, c1, c2;
1301 : GF_List *sai_sizes, *sai_offsets;
1302 : u32 sinf_fmt = 0;
1303 : Bool has_saiz, has_saio;
1304 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1305 : GF_TrackFragmentBox *traf=(GF_TrackFragmentBox *)_traf;
1306 : #endif
1307 : has_saiz = has_saio = GF_FALSE;
1308 :
1309 34819 : if (stbl) {
1310 34678 : if (!stbl->patch_piff_psec) {
1311 177 : stbl->patch_piff_psec = gf_opts_get_bool("core", "piff-force-subsamples") ? 2 : 1;
1312 : }
1313 34678 : if (stbl->patch_piff_psec==2)
1314 : return GF_FALSE;
1315 34678 : sai_sizes = stbl->sai_sizes;
1316 34678 : sai_offsets = stbl->sai_offsets;
1317 : }
1318 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1319 141 : else if (_traf) {
1320 141 : if (traf->trex && traf->trex->track && traf->trex->track->Media->information->sampleTable) {
1321 : GF_SampleTableBox *_stbl = traf->trex->track->Media->information->sampleTable;
1322 141 : if (!_stbl->patch_piff_psec) {
1323 32 : _stbl->patch_piff_psec = gf_opts_get_bool("core", "piff-force-subsamples") ? 2 : 1;
1324 : }
1325 141 : if (_stbl->patch_piff_psec==2)
1326 : return GF_FALSE;
1327 : }
1328 141 : sai_sizes = traf->sai_sizes;
1329 141 : sai_offsets = traf->sai_offsets;
1330 : }
1331 : #endif
1332 : else
1333 : return GF_FALSE;
1334 :
1335 34819 : c1 = gf_list_count(sai_sizes);
1336 34819 : c2 = gf_list_count(sai_offsets);
1337 68975 : for (i = 0; i < c1; i++) {
1338 34156 : GF_SampleAuxiliaryInfoSizeBox *saiz = (GF_SampleAuxiliaryInfoSizeBox *)gf_list_get(sai_sizes, i);
1339 34156 : u32 saiz_aux_info_type = saiz->aux_info_type;
1340 34156 : if (!saiz_aux_info_type) saiz_aux_info_type = scheme_type;
1341 :
1342 :
1343 34156 : if (!saiz_aux_info_type) {
1344 : GF_SampleEntryBox *entry = NULL;
1345 : GF_ProtectionSchemeInfoBox *sinf = NULL;
1346 0 : if (stbl) {
1347 0 : entry = gf_list_get(stbl->SampleDescription->child_boxes, 0);
1348 : } else {
1349 0 : entry = gf_list_get(traf->trex->track->Media->information->sampleTable->SampleDescription->child_boxes, 0);
1350 : }
1351 :
1352 0 : if (entry)
1353 0 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1354 :
1355 0 : if (sinf && sinf->scheme_type) {
1356 0 : saiz_aux_info_type = sinf_fmt = sinf->scheme_type->scheme_type;
1357 : }
1358 : }
1359 34156 : if (!saiz_aux_info_type && (c1==1) && (c2==1)) {
1360 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] saiz box without flags nor aux info type and no default scheme, ignoring\n"));
1361 0 : continue;
1362 : }
1363 :
1364 34156 : switch (saiz_aux_info_type) {
1365 34156 : case GF_ISOM_CENC_SCHEME:
1366 : case GF_ISOM_CBC_SCHEME:
1367 : case GF_ISOM_CENS_SCHEME:
1368 : case GF_ISOM_CBCS_SCHEME:
1369 : case GF_ISOM_PIFF_SCHEME:
1370 : has_saiz = GF_TRUE;
1371 34156 : break;
1372 : }
1373 : }
1374 :
1375 34156 : for (i = 0; i < c2; i++) {
1376 34156 : GF_SampleAuxiliaryInfoOffsetBox *saio = (GF_SampleAuxiliaryInfoOffsetBox *)gf_list_get(sai_offsets, i);
1377 34156 : u32 saio_aux_info_type = saio->aux_info_type;
1378 34156 : if (!saio_aux_info_type) saio_aux_info_type = scheme_type;
1379 34156 : if (!saio_aux_info_type) saio_aux_info_type = sinf_fmt;
1380 :
1381 34156 : if (!saio_aux_info_type) {
1382 : GF_SampleEntryBox *entry = NULL;
1383 : GF_ProtectionSchemeInfoBox *sinf = NULL;
1384 0 : if (stbl) {
1385 0 : entry = gf_list_get(stbl->SampleDescription->child_boxes, 0);
1386 : } else {
1387 0 : entry = gf_list_get(traf->trex->track->Media->information->sampleTable->SampleDescription->child_boxes, 0);
1388 : }
1389 0 : if (entry)
1390 0 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1391 :
1392 0 : if (sinf && sinf->scheme_type) {
1393 0 : saio_aux_info_type = sinf_fmt = sinf->scheme_type->scheme_type;
1394 : }
1395 : }
1396 34156 : if (!saio_aux_info_type && (c1==1) && (c2==1)) {
1397 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] saio box without flags nor aux info type and no default scheme, ignoring\n"));
1398 0 : continue;
1399 : }
1400 : //special case for query on a file that has just been imported but not yet written: saio offset is NULL, we must use senc
1401 34156 : if (saio->entry_count && !saio->offsets)
1402 0 : continue;
1403 34156 : switch (saio_aux_info_type) {
1404 34156 : case GF_ISOM_CENC_SCHEME:
1405 : case GF_ISOM_CBC_SCHEME:
1406 : case GF_ISOM_CENS_SCHEME:
1407 : case GF_ISOM_CBCS_SCHEME:
1408 : case GF_ISOM_PIFF_SCHEME:
1409 : has_saio = GF_TRUE;
1410 34156 : break;
1411 : }
1412 : }
1413 34819 : return (has_saiz && has_saio);
1414 : }
1415 :
1416 0 : Bool gf_isom_cenc_has_saiz_saio_track(GF_SampleTableBox *stbl, u32 scheme_type)
1417 : {
1418 34678 : return gf_isom_cenc_has_saiz_saio_full(stbl, NULL, scheme_type);
1419 : }
1420 :
1421 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1422 141 : Bool gf_isom_cenc_has_saiz_saio_traf(GF_TrackFragmentBox *traf, u32 scheme_type)
1423 : {
1424 141 : return gf_isom_cenc_has_saiz_saio_full(NULL, traf, scheme_type);
1425 : }
1426 : #endif
1427 :
1428 :
1429 34017 : static GF_Err isom_cenc_get_sai_by_saiz_saio(GF_MediaBox *mdia, u32 sampleNumber, u32 scheme_type, u8 **out_buffer, u32 *out_size)
1430 : {
1431 : u32 prev_sai_size, size, i, j, nb_saio;
1432 : u64 cur_position, offset;
1433 : GF_Err e = GF_OK;
1434 : GF_SampleAuxiliaryInfoOffsetBox *saio_cenc=NULL;
1435 : GF_SampleAuxiliaryInfoSizeBox *saiz_cenc=NULL;
1436 : nb_saio = size = prev_sai_size = 0;
1437 : offset = 0;
1438 :
1439 34017 : if (! out_buffer || !out_size) return GF_BAD_PARAM;
1440 :
1441 34017 : for (i = 0; i < gf_list_count(mdia->information->sampleTable->sai_offsets); i++) {
1442 34017 : GF_SampleAuxiliaryInfoOffsetBox *saio = (GF_SampleAuxiliaryInfoOffsetBox *)gf_list_get(mdia->information->sampleTable->sai_offsets, i);
1443 34017 : u32 aux_info_type = saio->aux_info_type;
1444 34017 : if (!aux_info_type) aux_info_type = scheme_type;
1445 :
1446 34017 : switch (aux_info_type) {
1447 : case GF_ISOM_CENC_SCHEME:
1448 : case GF_ISOM_CBC_SCHEME:
1449 : case GF_ISOM_CENS_SCHEME:
1450 : case GF_ISOM_CBCS_SCHEME:
1451 : case GF_ISOM_PIFF_SCHEME:
1452 : break;
1453 0 : default:
1454 0 : continue;
1455 : }
1456 :
1457 34017 : if (saio->entry_count == 1)
1458 30912 : offset = saio->offsets[0];
1459 : else
1460 3105 : offset = saio->offsets[sampleNumber-1];
1461 : nb_saio = saio->entry_count;
1462 : saio_cenc = saio;
1463 : break;
1464 : }
1465 34017 : if (!saio_cenc) return GF_ISOM_INVALID_FILE;
1466 :
1467 34017 : for (i = 0; i < gf_list_count(mdia->information->sampleTable->sai_sizes); i++) {
1468 34017 : GF_SampleAuxiliaryInfoSizeBox *saiz = (GF_SampleAuxiliaryInfoSizeBox *)gf_list_get(mdia->information->sampleTable->sai_sizes, i);
1469 34017 : u32 aux_info_type = saiz->aux_info_type;
1470 34017 : if (!aux_info_type) aux_info_type = scheme_type;
1471 :
1472 34017 : switch (aux_info_type) {
1473 : case GF_ISOM_CENC_SCHEME:
1474 : case GF_ISOM_CBC_SCHEME:
1475 : case GF_ISOM_CENS_SCHEME:
1476 : case GF_ISOM_CBCS_SCHEME:
1477 : case GF_ISOM_PIFF_SCHEME:
1478 : break;
1479 0 : default:
1480 0 : continue;
1481 : }
1482 34017 : if (sampleNumber>saiz->sample_count) {
1483 : return GF_NON_COMPLIANT_BITSTREAM;
1484 : }
1485 34017 : if ((nb_saio==1) && !saio_cenc->total_size) {
1486 39222 : for (j = 0; j < saiz->sample_count; j++) {
1487 39222 : saio_cenc->total_size += saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[j];
1488 : }
1489 : }
1490 34017 : if (saiz->cached_sample_num+1== sampleNumber) {
1491 33903 : prev_sai_size = saiz->cached_prev_size;
1492 : } else {
1493 21676 : for (j = 0; j < sampleNumber-1; j++)
1494 21676 : prev_sai_size += saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[j];
1495 : }
1496 34017 : size = saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[sampleNumber-1];
1497 : saiz_cenc=saiz;
1498 : break;
1499 : }
1500 34017 : if (!saiz_cenc) return GF_BAD_PARAM;
1501 :
1502 34017 : saiz_cenc->cached_sample_num = sampleNumber;
1503 34017 : saiz_cenc->cached_prev_size = prev_sai_size + size;
1504 :
1505 34017 : if (saio_cenc->total_size) {
1506 30912 : if (!saio_cenc->cached_data) {
1507 174 : saio_cenc->cached_data = gf_malloc(sizeof(u8)*saio_cenc->total_size);
1508 174 : if (!saio_cenc->cached_data) return GF_OUT_OF_MEM;
1509 174 : cur_position = gf_bs_get_position(mdia->information->dataHandler->bs);
1510 174 : gf_bs_seek(mdia->information->dataHandler->bs, offset);
1511 174 : gf_bs_read_data(mdia->information->dataHandler->bs, saio_cenc->cached_data, saio_cenc->total_size);
1512 174 : gf_bs_seek(mdia->information->dataHandler->bs, cur_position);
1513 : }
1514 30912 : if (out_size) {
1515 30912 : if (out_buffer) {
1516 30912 : if ((*out_size) < size) {
1517 218 : (*out_buffer) = gf_realloc((*out_buffer), sizeof(char)*(size) );
1518 218 : if (! *out_buffer) return GF_OUT_OF_MEM;
1519 : }
1520 30912 : memcpy((*out_buffer), saio_cenc->cached_data + prev_sai_size, size);
1521 : }
1522 30912 : (*out_size) = size;
1523 : }
1524 : return GF_OK;
1525 : }
1526 :
1527 3105 : offset += (nb_saio == 1) ? prev_sai_size : 0;
1528 3105 : cur_position = gf_bs_get_position(mdia->information->dataHandler->bs);
1529 3105 : gf_bs_seek(mdia->information->dataHandler->bs, offset);
1530 :
1531 3105 : if (out_buffer) {
1532 3105 : if ((*out_size) < size) {
1533 21 : (*out_buffer) = gf_realloc((*out_buffer), sizeof(char)*(size) );
1534 21 : if (! *out_buffer) return GF_OUT_OF_MEM;
1535 : }
1536 3105 : gf_bs_read_data(mdia->information->dataHandler->bs, (*out_buffer), size);
1537 : }
1538 3105 : (*out_size) = size;
1539 :
1540 3105 : gf_bs_seek(mdia->information->dataHandler->bs, cur_position);
1541 :
1542 : return e;
1543 : }
1544 :
1545 : GF_EXPORT
1546 34680 : GF_Err gf_isom_cenc_get_sample_aux_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 sampleDescIndex, u32 *container_type, u8 **out_buffer, u32 *outSize)
1547 : {
1548 : GF_TrackBox *trak;
1549 : GF_SampleTableBox *stbl;
1550 : GF_SampleEncryptionBox *senc = NULL;
1551 34680 : u32 type, scheme_type = -1;
1552 : GF_CENCSampleAuxInfo *a_sai;
1553 :
1554 34680 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1555 34680 : if (!trak) return GF_BAD_PARAM;
1556 34680 : stbl = trak->Media->information->sampleTable;
1557 34680 : if (!stbl)
1558 : return GF_BAD_PARAM;
1559 :
1560 : type = 0;
1561 34680 : senc = trak->sample_encryption;
1562 : //no senc is OK
1563 34680 : if (senc) {
1564 34019 : if ((senc->type == GF_ISOM_BOX_TYPE_UUID) && (((GF_UUIDBox *)senc)->internal_4cc == GF_ISOM_BOX_UUID_PSEC)) {
1565 : type = GF_ISOM_BOX_UUID_PSEC;
1566 31651 : } else if (senc->type == GF_ISOM_BOX_TYPE_SENC) {
1567 : type = GF_ISOM_BOX_TYPE_SENC;
1568 : }
1569 :
1570 34019 : if (container_type) *container_type = type;
1571 : }
1572 :
1573 34680 : if (!out_buffer) return GF_OK; /*we need only container_type*/
1574 :
1575 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1576 34678 : sampleNumber -= trak->sample_count_at_seg_start;
1577 : #endif
1578 :
1579 34678 : gf_isom_get_cenc_info(the_file, trackNumber, sampleDescIndex, NULL, &scheme_type, NULL);
1580 :
1581 : /*get sample auxiliary information by saiz/saio rather than by parsing senc box*/
1582 69356 : if (gf_isom_cenc_has_saiz_saio_track(stbl, scheme_type)) {
1583 34017 : return isom_cenc_get_sai_by_saiz_saio(trak->Media, sampleNumber, scheme_type, out_buffer, outSize);
1584 : }
1585 661 : if (!senc)
1586 : return GF_OK;
1587 :
1588 : //senc is not loaded by default, do it now
1589 0 : if (!gf_list_count(senc->samp_aux_info)) {
1590 0 : GF_Err e = senc_Parse(trak->Media->information->dataHandler->bs, trak, NULL, senc);
1591 0 : if (e) return e;
1592 : }
1593 :
1594 : a_sai = NULL;
1595 0 : switch (type) {
1596 : case GF_ISOM_BOX_UUID_PSEC:
1597 : if (senc)
1598 0 : a_sai = (GF_CENCSampleAuxInfo *)gf_list_get(senc->samp_aux_info, sampleNumber-1);
1599 : break;
1600 : case GF_ISOM_BOX_TYPE_SENC:
1601 : if (senc)
1602 0 : a_sai = (GF_CENCSampleAuxInfo *)gf_list_get(senc->samp_aux_info, sampleNumber-1);
1603 : break;
1604 : }
1605 : //not present, check we use constant IV and no IV size
1606 0 : if (!a_sai) {
1607 0 : const u8 *key_info=NULL;
1608 0 : u32 key_info_size=0;
1609 : u8 IV_size=0, constant_IV_size=0;
1610 : Bool is_Protected;
1611 :
1612 0 : gf_isom_get_sample_cenc_info_internal(trak, NULL, senc, sampleNumber, &is_Protected, NULL, NULL, &key_info, &key_info_size);
1613 0 : if (!key_info) {
1614 0 : IV_size = key_info_size; //piff default
1615 : } else {
1616 0 : IV_size = key_info[3];
1617 0 : if (!IV_size)
1618 0 : constant_IV_size = key_info[20];
1619 : }
1620 0 : if (!IV_size && constant_IV_size)
1621 : return GF_OK;
1622 0 : return GF_NOT_FOUND;
1623 : }
1624 :
1625 0 : if (*outSize < a_sai->cenc_data_size) {
1626 0 : *out_buffer = gf_realloc(*out_buffer, sizeof(char) * a_sai->cenc_data_size);
1627 0 : if (! *out_buffer) return GF_OUT_OF_MEM;
1628 0 : *outSize = a_sai->cenc_data_size;
1629 : }
1630 0 : memcpy(*out_buffer, a_sai->cenc_data, a_sai->cenc_data_size);
1631 0 : return GF_OK;
1632 : }
1633 :
1634 : u32 gf_isom_has_cenc_sample_group_ex(GF_TrackBox *trak);
1635 :
1636 57835 : void gf_isom_cenc_get_default_info_internal(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
1637 : {
1638 : GF_ProtectionSchemeInfoBox *sinf;
1639 :
1640 :
1641 : //setup all default as not encrypted
1642 57835 : if (default_IsEncrypted) *default_IsEncrypted = GF_FALSE;
1643 57835 : if (crypt_byte_block) *crypt_byte_block = 0;
1644 57835 : if (skip_byte_block) *skip_byte_block = 0;
1645 57835 : if (container_type) *container_type = 0;
1646 57835 : if (key_info) *key_info = NULL;
1647 57835 : if (key_info_size) *key_info_size = 0;
1648 :
1649 57835 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENC_SCHEME, NULL);
1650 57835 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBC_SCHEME, NULL);
1651 57835 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CENS_SCHEME, NULL);
1652 57835 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_CBCS_SCHEME, NULL);
1653 57835 : if (!sinf) sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_PIFF_SCHEME, NULL);
1654 :
1655 57835 : if (!sinf) {
1656 389 : u32 i, nb_stsd = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
1657 1116 : for (i=0; i<nb_stsd; i++) {
1658 : GF_ProtectionSchemeInfoBox *a_sinf;
1659 : GF_SampleEntryBox *sentry=NULL;
1660 439 : if (i+1==sampleDescriptionIndex) continue;
1661 101 : sentry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
1662 101 : a_sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(sentry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1663 101 : if (!a_sinf) continue;
1664 : //signal default (not encrypted)
1665 : return;
1666 : }
1667 : }
1668 :
1669 57734 : if (sinf && sinf->info && sinf->info->tenc) {
1670 55190 : if (default_IsEncrypted) *default_IsEncrypted = sinf->info->tenc->isProtected;
1671 55190 : if (crypt_byte_block) *crypt_byte_block = sinf->info->tenc->crypt_byte_block;
1672 55190 : if (skip_byte_block) *skip_byte_block = sinf->info->tenc->skip_byte_block;
1673 55190 : if (key_info) *key_info = sinf->info->tenc->key_info;
1674 55190 : if (key_info_size) {
1675 55180 : *key_info_size = 20;
1676 55180 : if (!sinf->info->tenc->key_info[3])
1677 2482 : *key_info_size += 1 + sinf->info->tenc->key_info[20];
1678 : }
1679 :
1680 : //set default value, overwritten below
1681 55190 : if (container_type) *container_type = GF_ISOM_BOX_TYPE_SENC;
1682 2544 : } else if (sinf && sinf->info && sinf->info->piff_tenc) {
1683 0 : if (default_IsEncrypted) *default_IsEncrypted = GF_TRUE;
1684 0 : if (key_info) *key_info = sinf->info->piff_tenc->key_info;
1685 0 : if (key_info_size) *key_info_size = 19;
1686 : //set default value, overwritten below
1687 0 : if (container_type) *container_type = GF_ISOM_BOX_UUID_PSEC;
1688 : } else {
1689 : u32 i, count = 0;
1690 : GF_CENCSampleEncryptionGroupEntry *seig_entry = NULL;
1691 :
1692 2544 : if (!trak->moov->mov->is_smooth)
1693 2262 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
1694 :
1695 5088 : for (i=0; i<count; i++) {
1696 2256 : GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
1697 2256 : if (sgdesc->grouping_type!=GF_ISOM_SAMPLE_GROUP_SEIG) continue;
1698 2256 : if (sgdesc->default_description_index)
1699 0 : seig_entry = gf_list_get(sgdesc->group_descriptions, sgdesc->default_description_index-1);
1700 : else
1701 2256 : seig_entry = gf_list_get(sgdesc->group_descriptions, 0);
1702 2256 : if (seig_entry && !seig_entry->key_info[0])
1703 : seig_entry = NULL;
1704 : break;
1705 : }
1706 2544 : if (seig_entry) {
1707 2256 : if (default_IsEncrypted) *default_IsEncrypted = seig_entry->IsProtected;
1708 2256 : if (crypt_byte_block) *crypt_byte_block = seig_entry->crypt_byte_block;
1709 2256 : if (skip_byte_block) *skip_byte_block = seig_entry->skip_byte_block;
1710 2256 : if (key_info) *key_info = seig_entry->key_info;
1711 2256 : if (key_info_size) *key_info_size = seig_entry->key_info_size;
1712 2256 : if (container_type) *container_type = GF_ISOM_BOX_TYPE_SENC;
1713 : } else {
1714 288 : if (! trak->moov->mov->is_smooth ) {
1715 6 : trak->moov->mov->is_smooth = GF_TRUE;
1716 6 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] senc box without tenc, assuming MS smooth+piff\n"));
1717 : }
1718 288 : if (default_IsEncrypted) *default_IsEncrypted = GF_TRUE;
1719 : //set default value, overwritten below
1720 288 : if (container_type) *container_type = GF_ISOM_BOX_UUID_PSEC;
1721 : }
1722 : }
1723 :
1724 57734 : if (container_type && trak->sample_encryption) {
1725 161 : if (trak->sample_encryption->type == GF_ISOM_BOX_TYPE_SENC) *container_type = GF_ISOM_BOX_TYPE_SENC;
1726 12 : else if (trak->sample_encryption->type == GF_ISOM_BOX_TYPE_UUID) *container_type = ((GF_UUIDBox*)trak->sample_encryption)->internal_4cc;
1727 : }
1728 : }
1729 :
1730 : GF_EXPORT
1731 270 : GF_Err gf_isom_cenc_get_default_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
1732 : {
1733 270 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1734 270 : if (!trak) return GF_BAD_PARAM;
1735 270 : gf_isom_cenc_get_default_info_internal(trak, sampleDescriptionIndex, container_type, default_IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
1736 270 : return GF_OK;
1737 : }
1738 :
1739 : /*
1740 : Adobe'protection scheme
1741 : */
1742 10 : GF_Err gf_isom_set_adobe_protection(GF_ISOFile *the_file, u32 trackNumber, u32 desc_index, u32 scheme_type, u32 scheme_version, Bool is_selective_enc, char *metadata, u32 len)
1743 : {
1744 : GF_ProtectionSchemeInfoBox *sinf;
1745 :
1746 : //setup generic protection
1747 : #ifndef GPAC_DISABLE_ISOM_WRITE
1748 : GF_Err e;
1749 10 : e = isom_set_protected_entry(the_file, trackNumber, desc_index, 1, 0, scheme_type, scheme_version, NULL, GF_FALSE, &sinf);
1750 10 : if (e) return e;
1751 : #else
1752 : return GF_NOT_SUPPORTED;
1753 : #endif
1754 :
1755 10 : sinf->info->adkm = (GF_AdobeDRMKeyManagementSystemBox *)gf_isom_box_new_parent(&sinf->info->child_boxes, GF_ISOM_BOX_TYPE_ADKM);
1756 10 : if (!sinf->info->adkm) return GF_OUT_OF_MEM;
1757 :
1758 10 : sinf->info->adkm->header = (GF_AdobeDRMHeaderBox *)gf_isom_box_new_parent(&sinf->info->adkm->child_boxes, GF_ISOM_BOX_TYPE_AHDR);
1759 10 : if (!sinf->info->adkm->header) return GF_OUT_OF_MEM;
1760 :
1761 10 : sinf->info->adkm->header->std_enc_params = (GF_AdobeStdEncryptionParamsBox *)gf_isom_box_new_parent(& sinf->info->adkm->header->child_boxes, GF_ISOM_BOX_TYPE_APRM);
1762 10 : if (!sinf->info->adkm->header->std_enc_params) return GF_OUT_OF_MEM;
1763 :
1764 10 : sinf->info->adkm->header->std_enc_params->enc_info = (GF_AdobeEncryptionInfoBox *)gf_isom_box_new_parent(&sinf->info->adkm->header->std_enc_params->child_boxes, GF_ISOM_BOX_TYPE_AEIB);
1765 10 : if (!sinf->info->adkm->header->std_enc_params->enc_info) return GF_OUT_OF_MEM;
1766 :
1767 10 : sinf->info->adkm->header->std_enc_params->enc_info->enc_algo = (char *)gf_malloc(8*sizeof(char));
1768 10 : if (!sinf->info->adkm->header->std_enc_params->enc_info->enc_algo) return GF_OUT_OF_MEM;
1769 :
1770 : strcpy(sinf->info->adkm->header->std_enc_params->enc_info->enc_algo, "AES-CBC");
1771 10 : sinf->info->adkm->header->std_enc_params->enc_info->key_length = 16;
1772 :
1773 10 : sinf->info->adkm->header->std_enc_params->key_info = (GF_AdobeKeyInfoBox *)gf_isom_box_new_parent(&sinf->info->adkm->header->std_enc_params->child_boxes, GF_ISOM_BOX_TYPE_AKEY);
1774 10 : if (!sinf->info->adkm->header->std_enc_params->key_info) return GF_OUT_OF_MEM;
1775 :
1776 10 : sinf->info->adkm->header->std_enc_params->key_info->params = (GF_AdobeFlashAccessParamsBox *)gf_isom_box_new_parent(&sinf->info->adkm->header->std_enc_params->key_info->child_boxes, GF_ISOM_BOX_TYPE_FLXS);
1777 10 : if (!sinf->info->adkm->header->std_enc_params->key_info->params) return GF_OUT_OF_MEM;
1778 :
1779 10 : if (metadata && len) {
1780 10 : sinf->info->adkm->header->std_enc_params->key_info->params->metadata = (char *)gf_malloc((len+1)*sizeof(char));
1781 10 : if (!sinf->info->adkm->header->std_enc_params->key_info->params->metadata) return GF_OUT_OF_MEM;
1782 :
1783 10 : strncpy(sinf->info->adkm->header->std_enc_params->key_info->params->metadata, metadata, len);
1784 10 : sinf->info->adkm->header->std_enc_params->key_info->params->metadata[len] = 0;
1785 : }
1786 :
1787 10 : sinf->info->adkm->au_format = (GF_AdobeDRMAUFormatBox *)gf_isom_box_new_parent(&sinf->info->adkm->child_boxes, GF_ISOM_BOX_TYPE_ADAF);
1788 10 : if (!sinf->info->adkm->au_format) return GF_OUT_OF_MEM;
1789 :
1790 10 : sinf->info->adkm->au_format->selective_enc = is_selective_enc ? 0x10 : 0x00;
1791 10 : sinf->info->adkm->au_format->IV_length = 16;
1792 :
1793 10 : return GF_OK;
1794 : }
1795 :
1796 : GF_EXPORT
1797 25 : Bool gf_isom_is_adobe_protection_media(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
1798 : {
1799 : GF_TrackBox *trak;
1800 : GF_ProtectionSchemeInfoBox *sinf;
1801 :
1802 25 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1803 25 : if (!trak) return GF_FALSE;
1804 :
1805 25 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ADOBE_SCHEME, NULL);
1806 :
1807 25 : if (!sinf) return GF_FALSE;
1808 :
1809 : /*non-encrypted or non-ADOBE*/
1810 15 : if (!sinf->info || !sinf->info->adkm)
1811 : return GF_FALSE;
1812 :
1813 15 : return GF_TRUE;
1814 : }
1815 :
1816 : GF_EXPORT
1817 15 : GF_Err gf_isom_get_adobe_protection_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion, const char **outMetadata)
1818 : {
1819 : GF_TrackBox *trak;
1820 : GF_ProtectionSchemeInfoBox *sinf;
1821 :
1822 15 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1823 15 : if (!trak) return GF_BAD_PARAM;
1824 :
1825 15 : sinf = isom_get_sinf_entry(trak, sampleDescriptionIndex, GF_ISOM_ADOBE_SCHEME, NULL);
1826 :
1827 15 : if (!sinf) return GF_BAD_PARAM;
1828 :
1829 15 : if (outOriginalFormat) {
1830 10 : *outOriginalFormat = sinf->original_format->data_format;
1831 10 : if (IsMP4Description(sinf->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4;
1832 : }
1833 15 : if (outSchemeType) *outSchemeType = sinf->scheme_type->scheme_type;
1834 15 : if (outSchemeVersion) *outSchemeVersion = sinf->scheme_type->scheme_version;
1835 :
1836 15 : if (outMetadata) {
1837 10 : *outMetadata = NULL;
1838 10 : if (sinf->info && sinf->info->adkm && sinf->info->adkm->header && sinf->info->adkm->header->std_enc_params && sinf->info->adkm->header->std_enc_params->key_info
1839 10 : && sinf->info->adkm->header->std_enc_params->key_info->params && sinf->info->adkm->header->std_enc_params->key_info->params->metadata)
1840 : {
1841 10 : *outMetadata = sinf->info->adkm->header->std_enc_params->key_info->params->metadata;
1842 : }
1843 : }
1844 :
1845 : return GF_OK;
1846 : }
1847 :
1848 :
1849 : #if 0 //unused
1850 : /*! removes the IPMPX tools from files
1851 : \param isom_file the target ISO file
1852 : */
1853 : void gf_isom_ipmpx_remove_tool_list(GF_ISOFile *the_file)
1854 : {
1855 : /*remove IPMPToolList if any*/
1856 : if (the_file && the_file->moov && the_file->moov->iods && (the_file ->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) ) {
1857 : GF_IsomInitialObjectDescriptor *iod = (GF_IsomInitialObjectDescriptor *)the_file ->moov->iods->descriptor;
1858 : if (iod->IPMPToolList) gf_odf_desc_del((GF_Descriptor*) iod->IPMPToolList);
1859 : iod->IPMPToolList = NULL;
1860 : }
1861 : }
1862 : #endif
1863 :
1864 :
1865 827 : Bool gf_cenc_validate_key_info(const u8 *key_info, u32 key_info_size)
1866 : {
1867 : u32 i, n_keys, kpos, nb_missing = 19;
1868 827 : if (!key_info|| (key_info_size<19))
1869 : goto exit;
1870 :
1871 : n_keys = 1;
1872 827 : if (key_info[0]) {
1873 41 : n_keys = key_info[1];
1874 41 : n_keys <<= 8;
1875 41 : n_keys |= key_info[2];
1876 : }
1877 : kpos=3;
1878 1675 : for (i=0;i<n_keys; i++) {
1879 : u8 iv_size;
1880 848 : if (kpos + 17 > key_info_size) {
1881 0 : nb_missing = kpos + 17 - key_info_size;
1882 0 : goto exit;
1883 : }
1884 848 : iv_size = key_info[kpos];
1885 : kpos += 17;
1886 848 : if (!iv_size) {
1887 37 : if (kpos + 1 > key_info_size) {
1888 0 : nb_missing = kpos + 1 - key_info_size;
1889 0 : goto exit;
1890 : }
1891 37 : iv_size = key_info[kpos];
1892 37 : if (kpos + 1 + iv_size > key_info_size) {
1893 0 : nb_missing = kpos + 1 + iv_size - key_info_size;
1894 0 : goto exit;
1895 : }
1896 : kpos += 1 + iv_size;
1897 : }
1898 : }
1899 : return GF_TRUE;
1900 :
1901 0 : exit:
1902 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Invalid key info format, missing %d bytes\n", nb_missing));
1903 : return GF_FALSE;
1904 : }
1905 :
1906 :
1907 : #endif /*GPAC_DISABLE_ISOM*/
|