LCOV - code coverage report
Current view: top level - isomedia - drm_sample.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 655 871 75.2 %
Date: 2021-04-29 23:48:07 Functions: 37 41 90.2 %

          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*/

Generated by: LCOV version 1.13