root/src/isomedia/box_code_base.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. co64_del
  2. co64_Read
  3. co64_New
  4. co64_Write
  5. co64_Size
  6. cprt_del
  7. chpl_New
  8. chpl_del
  9. chpl_Read
  10. chpl_Write
  11. chpl_Size
  12. cprt_Read
  13. cprt_New
  14. cprt_Write
  15. cprt_Size
  16. kind_del
  17. kind_Read
  18. kind_New
  19. kind_Write
  20. kind_Size
  21. ctts_del
  22. ctts_Read
  23. ctts_New
  24. ctts_Write
  25. ctts_Size
  26. cslg_del
  27. cslg_Read
  28. cslg_New
  29. cslg_Write
  30. cslg_Size
  31. ccst_del
  32. ccst_Read
  33. ccst_New
  34. ccst_Write
  35. ccst_Size
  36. url_del
  37. url_Read
  38. url_New
  39. url_Write
  40. url_Size
  41. urn_del
  42. urn_Read
  43. urn_New
  44. urn_Write
  45. urn_Size
  46. unkn_del
  47. unkn_Read
  48. unkn_New
  49. unkn_Write
  50. unkn_Size
  51. def_cont_box_del
  52. def_cont_box_Read
  53. def_cont_box_New
  54. def_cont_box_Write
  55. def_cont_box_Size
  56. uuid_del
  57. uuid_Read
  58. uuid_New
  59. uuid_Write
  60. uuid_Size
  61. dinf_del
  62. dinf_AddBox
  63. dinf_Read
  64. dinf_New
  65. dinf_Write
  66. dinf_Size
  67. dref_del
  68. dref_AddDataEntry
  69. dref_Read
  70. dref_New
  71. dref_Write
  72. dref_Size
  73. edts_del
  74. edts_AddBox
  75. edts_Read
  76. edts_New
  77. edts_Write
  78. edts_Size
  79. elst_del
  80. elst_Read
  81. elst_New
  82. elst_Write
  83. elst_Size
  84. esds_del
  85. esds_Read
  86. esds_New
  87. esds_Write
  88. esds_Size
  89. free_del
  90. free_Read
  91. free_New
  92. free_Write
  93. free_Size
  94. ftyp_del
  95. ftyp_New
  96. ftyp_Read
  97. ftyp_Write
  98. ftyp_Size
  99. gnrm_del
  100. gnrm_New
  101. gnrm_Read
  102. gnrm_Write
  103. gnrm_Size
  104. gnrv_del
  105. gnrv_New
  106. gnrv_Read
  107. gnrv_Write
  108. gnrv_Size
  109. gnra_del
  110. gnra_New
  111. gnra_Read
  112. gnra_Write
  113. gnra_Size
  114. hdlr_del
  115. hdlr_Read
  116. hdlr_New
  117. hdlr_Write
  118. hdlr_Size
  119. hinf_del
  120. hinf_New
  121. hinf_AddBox
  122. hinf_Read
  123. hinf_Write
  124. hinf_Size
  125. hmhd_del
  126. hmhd_Read
  127. hmhd_New
  128. hmhd_Write
  129. hmhd_Size
  130. hnti_New
  131. hnti_del
  132. hnti_AddBox
  133. hnti_Read
  134. hnti_Write
  135. hnti_Size
  136. sdp_del
  137. sdp_Read
  138. sdp_New
  139. sdp_Write
  140. sdp_Size
  141. rtp_hnti_del
  142. rtp_hnti_Read
  143. rtp_hnti_New
  144. rtp_hnti_Write
  145. rtp_hnti_Size
  146. trpy_del
  147. trpy_Read
  148. trpy_New
  149. trpy_Write
  150. trpy_Size
  151. totl_del
  152. totl_Read
  153. totl_New
  154. totl_Write
  155. totl_Size
  156. nump_del
  157. nump_Read
  158. nump_New
  159. nump_Write
  160. nump_Size
  161. npck_del
  162. npck_Read
  163. npck_New
  164. npck_Write
  165. npck_Size
  166. tpyl_del
  167. tpyl_Read
  168. tpyl_New
  169. tpyl_Write
  170. tpyl_Size
  171. tpay_del
  172. tpay_Read
  173. tpay_New
  174. tpay_Write
  175. tpay_Size
  176. maxr_del
  177. maxr_Read
  178. maxr_New
  179. maxr_Write
  180. maxr_Size
  181. dmed_del
  182. dmed_Read
  183. dmed_New
  184. dmed_Write
  185. dmed_Size
  186. dimm_del
  187. dimm_Read
  188. dimm_New
  189. dimm_Write
  190. dimm_Size
  191. drep_del
  192. drep_Read
  193. drep_New
  194. drep_Write
  195. drep_Size
  196. tmin_del
  197. tmin_Read
  198. tmin_New
  199. tmin_Write
  200. tmin_Size
  201. tmax_del
  202. tmax_Read
  203. tmax_New
  204. tmax_Write
  205. tmax_Size
  206. pmax_del
  207. pmax_Read
  208. pmax_New
  209. pmax_Write
  210. pmax_Size
  211. dmax_del
  212. dmax_Read
  213. dmax_New
  214. dmax_Write
  215. dmax_Size
  216. payt_del
  217. payt_Read
  218. payt_New
  219. payt_Write
  220. payt_Size
  221. name_del
  222. name_Read
  223. name_New
  224. name_Write
  225. name_Size
  226. tssy_del
  227. tssy_Read
  228. tssy_New
  229. tssy_Write
  230. tssy_Size
  231. srpp_del
  232. srpp_AddBox
  233. srpp_Read
  234. srpp_New
  235. srpp_Write
  236. srpp_Size
  237. rssr_del
  238. rssr_Read
  239. rssr_New
  240. rssr_Write
  241. rssr_Size
  242. iods_del
  243. iods_Read
  244. iods_New
  245. iods_Write
  246. iods_Size
  247. mdat_del
  248. mdat_Read
  249. mdat_New
  250. mdat_Write
  251. mdat_Size
  252. mdhd_del
  253. mdhd_Read
  254. mdhd_New
  255. mdhd_Write
  256. mdhd_Size
  257. mdia_del
  258. mdia_AddBox
  259. mdia_Read
  260. mdia_New
  261. mdia_Write
  262. mdia_Size
  263. mfra_del
  264. mfra_New
  265. mfra_AddBox
  266. mfra_Read
  267. mfra_Write
  268. mfra_Size
  269. tfra_del
  270. tfra_New
  271. tfra_Read
  272. tfra_Write
  273. tfra_Size
  274. mfro_del
  275. mfro_New
  276. mfro_Read
  277. mfro_Write
  278. mfro_Size
  279. elng_del
  280. elng_Read
  281. elng_New
  282. elng_Write
  283. elng_Size
  284. mfhd_del
  285. mfhd_Read
  286. mfhd_New
  287. mfhd_Write
  288. mfhd_Size
  289. minf_del
  290. minf_AddBox
  291. minf_Read
  292. minf_New
  293. minf_Write
  294. minf_Size
  295. moof_del
  296. moof_AddBox
  297. moof_Read
  298. moof_New
  299. moof_Write
  300. moof_Size
  301. moov_del
  302. moov_AddBox
  303. moov_Read
  304. moov_New
  305. moov_Write
  306. moov_Size
  307. audio_sample_entry_del
  308. audio_sample_entry_AddBox
  309. audio_sample_entry_Read
  310. audio_sample_entry_New
  311. enca_New
  312. audio_sample_entry_Write
  313. audio_sample_entry_Size
  314. mp4s_del
  315. mp4s_AddBox
  316. mp4s_Read
  317. mp4s_New
  318. encs_New
  319. mp4s_Write
  320. mp4s_Size
  321. video_sample_entry_del
  322. video_sample_entry_AddBox
  323. video_sample_entry_Read
  324. video_sample_entry_New
  325. video_sample_entry_Write
  326. video_sample_entry_Size
  327. mvex_del
  328. mvex_AddBox
  329. mvex_Read
  330. mvex_New
  331. mvex_Write
  332. mvex_Size
  333. mehd_New
  334. mehd_del
  335. mehd_Read
  336. mehd_Write
  337. mehd_Size
  338. mvhd_del
  339. mvhd_Read
  340. mvhd_New
  341. mvhd_Write
  342. mvhd_Size
  343. nmhd_del
  344. nmhd_Read
  345. nmhd_New
  346. nmhd_Write
  347. nmhd_Size
  348. padb_del
  349. padb_Read
  350. padb_New
  351. padb_Write
  352. padb_Size
  353. rely_del
  354. rely_Read
  355. rely_New
  356. rely_Write
  357. rely_Size
  358. rtpo_del
  359. rtpo_Read
  360. rtpo_New
  361. rtpo_Write
  362. rtpo_Size
  363. smhd_del
  364. smhd_Read
  365. smhd_New
  366. smhd_Write
  367. smhd_Size
  368. snro_del
  369. snro_Read
  370. snro_New
  371. snro_Write
  372. snro_Size
  373. stbl_del
  374. stbl_AddBox
  375. stbl_Read
  376. stbl_New
  377. stbl_Write
  378. stbl_Size
  379. stco_del
  380. stco_Read
  381. stco_New
  382. stco_Write
  383. stco_Size
  384. stdp_del
  385. stdp_Read
  386. stdp_New
  387. stdp_Write
  388. stdp_Size
  389. stsc_del
  390. stsc_Read
  391. stsc_New
  392. stsc_Write
  393. stsc_Size
  394. stsd_del
  395. stsd_AddBox
  396. stsd_Read
  397. stsd_New
  398. stsd_Write
  399. stsd_Size
  400. stsf_del
  401. stsf_Read
  402. stsf_New
  403. stsf_Write
  404. stsf_Size
  405. stsh_del
  406. stsh_Read
  407. stsh_New
  408. stsh_Write
  409. stsh_Size
  410. stss_del
  411. stss_Read
  412. stss_New
  413. stss_Write
  414. stss_Size
  415. stsz_del
  416. stsz_Read
  417. stsz_New
  418. stsz_Write
  419. stsz_Size
  420. stts_del
  421. stts_Read
  422. stts_New
  423. stts_Write
  424. stts_Size
  425. tfhd_del
  426. tfhd_Read
  427. tfhd_New
  428. tfhd_Write
  429. tfhd_Size
  430. tims_del
  431. tims_Read
  432. tims_New
  433. tims_Write
  434. tims_Size
  435. tkhd_del
  436. tkhd_Read
  437. tkhd_New
  438. tkhd_Write
  439. tkhd_Size
  440. traf_del
  441. traf_AddBox
  442. traf_Read
  443. traf_New
  444. tfxd_New
  445. tfxd_del
  446. tfxd_Read
  447. tfxd_Write
  448. tfxd_Size
  449. traf_Write
  450. traf_Size
  451. trak_del
  452. gf_isom_check_sample_desc
  453. trak_AddBox
  454. trak_Read
  455. trak_New
  456. trak_Write
  457. trak_Size
  458. stri_del
  459. stri_Read
  460. stri_New
  461. stri_Write
  462. stri_Size
  463. stsg_del
  464. stsg_Read
  465. stsg_New
  466. stsg_Write
  467. stsg_Size
  468. strk_del
  469. strk_AddBox
  470. strk_Read
  471. strk_New
  472. strk_Write
  473. strk_Size
  474. tref_AddBox
  475. tref_del
  476. tref_Read
  477. tref_New
  478. tref_Write
  479. tref_Size
  480. reftype_del
  481. reftype_Read
  482. reftype_New
  483. reftype_AddRefTrack
  484. reftype_Write
  485. reftype_Size
  486. trex_del
  487. trex_Read
  488. trex_New
  489. trex_Write
  490. trex_Size
  491. trep_del
  492. trep_Read
  493. trep_New
  494. trep_Write
  495. trep_Size
  496. trun_del
  497. trun_Read
  498. trun_New
  499. trun_Write
  500. trun_Size
  501. tsro_del
  502. tsro_Read
  503. tsro_New
  504. tsro_Write
  505. tsro_Size
  506. udta_del
  507. udta_getEntry
  508. udta_AddBox
  509. udta_Read
  510. udta_New
  511. udta_Write
  512. udta_Size
  513. vmhd_del
  514. vmhd_Read
  515. vmhd_New
  516. vmhd_Write
  517. vmhd_Size
  518. void_del
  519. void_Read
  520. void_New
  521. void_Write
  522. void_Size
  523. pdin_New
  524. pdin_del
  525. pdin_Read
  526. pdin_Write
  527. pdin_Size
  528. sdtp_New
  529. sdtp_del
  530. sdtp_Read
  531. sdtp_Write
  532. sdtp_Size
  533. pasp_New
  534. pasp_del
  535. pasp_Read
  536. pasp_Write
  537. pasp_Size
  538. clap_New
  539. clap_del
  540. clap_Read
  541. clap_Write
  542. clap_Size
  543. metx_New
  544. metx_del
  545. metx_AddBox
  546. metx_Read
  547. metx_Write
  548. metx_Size
  549. txtc_New
  550. txtc_del
  551. txtc_Read
  552. txtc_Write
  553. txtc_Size
  554. dac3_New
  555. dec3_New
  556. dac3_del
  557. dac3_Read
  558. dac3_Write
  559. dac3_Size
  560. lsrc_del
  561. lsrc_Read
  562. lsrc_New
  563. lsrc_Write
  564. lsrc_Size
  565. lsr1_del
  566. lsr1_AddBox
  567. lsr1_Read
  568. lsr1_New
  569. lsr1_Write
  570. lsr1_Size
  571. sidx_del
  572. sidx_Read
  573. sidx_New
  574. sidx_Write
  575. sidx_Size
  576. ssix_del
  577. ssix_Read
  578. ssix_New
  579. ssix_Write
  580. ssix_Size
  581. leva_del
  582. leva_Read
  583. leva_New
  584. leva_Write
  585. leva_Size
  586. pcrb_New
  587. pcrb_del
  588. pcrb_Read
  589. pcrb_Write
  590. pcrb_Size
  591. subs_New
  592. subs_del
  593. subs_Write
  594. subs_Size
  595. subs_Read
  596. tfdt_New
  597. tfdt_del
  598. tfdt_Read
  599. tfdt_Write
  600. tfdt_Size
  601. rvcc_New
  602. rvcc_del
  603. rvcc_Read
  604. rvcc_Write
  605. rvcc_Size
  606. sbgp_New
  607. sbgp_del
  608. sbgp_Read
  609. sbgp_Write
  610. sbgp_Size
  611. sgpd_parse_entry
  612. sgpd_del_entry
  613. sgpd_write_entry
  614. sgpd_size_entry
  615. sgpd_New
  616. sgpd_del
  617. sgpd_Read
  618. sgpd_Write
  619. sgpd_Size
  620. saiz_del
  621. saiz_Read
  622. saiz_New
  623. saiz_Write
  624. saiz_Size
  625. saio_del
  626. saio_Read
  627. saio_New
  628. saio_Write
  629. saio_Size
  630. prft_del
  631. prft_Read
  632. prft_New
  633. prft_Write
  634. prft_Size
  635. trgr_New
  636. trgr_del
  637. trgr_AddBox
  638. trgr_Read
  639. trgr_Write
  640. trgr_Size
  641. trgt_New
  642. trgt_del
  643. trgt_Read
  644. trgt_Write
  645. trgt_Size
  646. stvi_New
  647. stvi_del
  648. stvi_Read
  649. stvi_Write
  650. stvi_Size
  651. fiin_New
  652. fiin_del
  653. fiin_AddBox
  654. fiin_Read
  655. fiin_Write
  656. fiin_Size
  657. paen_New
  658. paen_del
  659. paen_AddBox
  660. paen_Read
  661. paen_Write
  662. paen_Size
  663. fpar_New
  664. fpar_del
  665. gf_isom_read_null_terminated_string
  666. fpar_Read
  667. fpar_Write
  668. fpar_Size
  669. fecr_New
  670. fecr_del
  671. fecr_Read
  672. fecr_Write
  673. fecr_Size
  674. segr_New
  675. segr_del
  676. segr_Read
  677. segr_Write
  678. segr_Size
  679. gitn_New
  680. gitn_del
  681. gitn_Read
  682. gitn_Write
  683. gitn_Size
  684. fdpa_New
  685. fdpa_del
  686. fdpa_Read
  687. fdpa_Write
  688. fdpa_Size
  689. extr_New
  690. extr_del
  691. extr_Read
  692. extr_Write
  693. extr_Size
  694. fdsa_New
  695. fdsa_del
  696. fdsa_AddBox
  697. fdsa_Read
  698. fdsa_Write
  699. fdsa_Size
  700. trik_del
  701. trik_Read
  702. trik_New
  703. trik_Write
  704. trik_Size
  705. bloc_del
  706. bloc_Read
  707. bloc_New
  708. bloc_Write
  709. bloc_Size
  710. ainf_del
  711. ainf_Read
  712. ainf_New
  713. ainf_Write
  714. ainf_Size

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / ISO Media File Format sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <gpac/internal/isomedia_dev.h>



#ifndef GPAC_DISABLE_ISOM

void co64_del(GF_Box *s)
{
        GF_ChunkLargeOffsetBox *ptr;
        ptr = (GF_ChunkLargeOffsetBox *) s;
        if (ptr == NULL) return;
        if (ptr->offsets) gf_free(ptr->offsets);
        gf_free(ptr);
}

GF_Err co64_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 entries;
        GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s;
        ptr->nb_entries = gf_bs_read_u32(bs);

        ISOM_DECREASE_SIZE(ptr, 4)

        if (ptr->nb_entries > ptr->size / 8) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in co64\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        ptr->offsets = (u64 *) gf_malloc(ptr->nb_entries * sizeof(u64) );
        if (ptr->offsets == NULL) return GF_OUT_OF_MEM;
        ptr->alloc_size = ptr->nb_entries;
        for (entries = 0; entries < ptr->nb_entries; entries++) {
                ptr->offsets[entries] = gf_bs_read_u64(bs);
        }
        return GF_OK;
}

GF_Box *co64_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ChunkLargeOffsetBox, GF_ISOM_BOX_TYPE_CO64);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err co64_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i = 0; i < ptr->nb_entries; i++ ) {
                gf_bs_write_u64(bs, ptr->offsets[i]);
        }
        return GF_OK;
}

GF_Err co64_Size(GF_Box *s)
{
        GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s;

        ptr->size += 4 + (8 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void cprt_del(GF_Box *s)
{
        GF_CopyrightBox *ptr = (GF_CopyrightBox *) s;
        if (ptr == NULL) return;
        if (ptr->notice)
                gf_free(ptr->notice);
        gf_free(ptr);
}


GF_Box *chpl_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ChapterListBox, GF_ISOM_BOX_TYPE_CHPL);
        tmp->list = gf_list_new();
        tmp->version = 1;
        return (GF_Box *)tmp;
}

void chpl_del(GF_Box *s)
{
        GF_ChapterListBox *ptr = (GF_ChapterListBox *) s;
        if (ptr == NULL) return;
        while (gf_list_count(ptr->list)) {
                GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, 0);
                if (ce->name) gf_free(ce->name);
                gf_free(ce);
                gf_list_rem(ptr->list, 0);
        }
        gf_list_del(ptr->list);
        gf_free(ptr);
}

/*this is using chpl format according to some NeroRecode samples*/
GF_Err chpl_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_ChapterEntry *ce;
        u32 nb_chaps, len, i, count;
        GF_ChapterListBox *ptr = (GF_ChapterListBox *)s;

        /*reserved or ???*/
        gf_bs_read_u32(bs);
        nb_chaps = gf_bs_read_u8(bs);

        count = 0;
        while (nb_chaps) {
                GF_SAFEALLOC(ce, GF_ChapterEntry);
                if (!ce) return GF_OUT_OF_MEM;
                ce->start_time = gf_bs_read_u64(bs);
                len = gf_bs_read_u8(bs);
                if (len) {
                        ce->name = (char *)gf_malloc(sizeof(char)*(len+1));
                        gf_bs_read_data(bs, ce->name, len);
                        ce->name[len] = 0;
                } else {
                        ce->name = gf_strdup("");
                }

                for (i=0; i<count; i++) {
                        GF_ChapterEntry *ace = (GF_ChapterEntry *) gf_list_get(ptr->list, i);
                        if (ace->start_time >= ce->start_time) {
                                gf_list_insert(ptr->list, ce, i);
                                ce = NULL;
                                break;
                        }
                }
                if (ce) gf_list_add(ptr->list, ce);
                count++;
                nb_chaps--;
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err chpl_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 count, i;
        GF_ChapterListBox *ptr = (GF_ChapterListBox *) s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        count = gf_list_count(ptr->list);
        gf_bs_write_u32(bs, 0);
        gf_bs_write_u8(bs, count);
        for (i=0; i<count; i++) {
                u32 len;
                GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, i);
                gf_bs_write_u64(bs, ce->start_time);
                if (ce->name) {
                        len = (u32) strlen(ce->name);
                        if (len>255) len = 255;
                        gf_bs_write_u8(bs, len);
                        gf_bs_write_data(bs, ce->name, len);
                } else {
                        gf_bs_write_u8(bs, 0);
                }
        }
        return GF_OK;
}

GF_Err chpl_Size(GF_Box *s)
{
        u32 count, i;
        GF_ChapterListBox *ptr = (GF_ChapterListBox *)s;

        ptr->size += 5;

        count = gf_list_count(ptr->list);
        for (i=0; i<count; i++) {
                GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, i);
                ptr->size += 9; /*64bit time stamp + 8bit str len*/
                if (ce->name) ptr->size += strlen(ce->name);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Err cprt_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_CopyrightBox *ptr = (GF_CopyrightBox *)s;

        gf_bs_read_int(bs, 1);
        //the spec is unclear here, just says "the value 0 is interpreted as undetermined"
        ptr->packedLanguageCode[0] = gf_bs_read_int(bs, 5);
        ptr->packedLanguageCode[1] = gf_bs_read_int(bs, 5);
        ptr->packedLanguageCode[2] = gf_bs_read_int(bs, 5);
        ISOM_DECREASE_SIZE(ptr, 2);

        //but before or after compaction ?? We assume before
        if (ptr->packedLanguageCode[0] || ptr->packedLanguageCode[1] || ptr->packedLanguageCode[2]) {
                ptr->packedLanguageCode[0] += 0x60;
                ptr->packedLanguageCode[1] += 0x60;
                ptr->packedLanguageCode[2] += 0x60;
        } else {
                ptr->packedLanguageCode[0] = 'u';
                ptr->packedLanguageCode[1] = 'n';
                ptr->packedLanguageCode[2] = 'd';
        }
        if (ptr->size) {
                u32 bytesToRead = (u32) ptr->size;
                ptr->notice = (char*)gf_malloc(bytesToRead * sizeof(char));
                if (ptr->notice == NULL) return GF_OUT_OF_MEM;
                gf_bs_read_data(bs, ptr->notice, bytesToRead);
        }
        return GF_OK;
}

GF_Box *cprt_New()
{
        ISOM_DECL_BOX_ALLOC(GF_CopyrightBox, GF_ISOM_BOX_TYPE_CPRT);
        tmp->packedLanguageCode[0] = 'u';
        tmp->packedLanguageCode[1] = 'n';
        tmp->packedLanguageCode[2] = 'd';

        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err cprt_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_CopyrightBox *ptr = (GF_CopyrightBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, 0, 1);
        if (ptr->packedLanguageCode[0]) {
                gf_bs_write_int(bs, ptr->packedLanguageCode[0] - 0x60, 5);
                gf_bs_write_int(bs, ptr->packedLanguageCode[1] - 0x60, 5);
                gf_bs_write_int(bs, ptr->packedLanguageCode[2] - 0x60, 5);
        } else {
                gf_bs_write_int(bs, 0, 15);
        }
        if (ptr->notice) {
                gf_bs_write_data(bs, ptr->notice, (u32) (strlen(ptr->notice) + 1) );
        }
        return GF_OK;
}

GF_Err cprt_Size(GF_Box *s)
{
        GF_CopyrightBox *ptr = (GF_CopyrightBox *)s;

        ptr->size += 2;
        if (ptr->notice)
                ptr->size += strlen(ptr->notice) + 1;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void kind_del(GF_Box *s)
{
        GF_KindBox *ptr = (GF_KindBox *) s;
        if (ptr == NULL) return;
        if (ptr->schemeURI) gf_free(ptr->schemeURI);
        if (ptr->value) gf_free(ptr->value);
        gf_free(ptr);
}

GF_Err kind_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_KindBox *ptr = (GF_KindBox *)s;

        if (ptr->size) {
                u32 bytesToRead = (u32) ptr->size;
                char *data;
                u32 schemeURIlen;
                data = (char*)gf_malloc(bytesToRead * sizeof(char));
                if (data == NULL) return GF_OUT_OF_MEM;
                gf_bs_read_data(bs, data, bytesToRead);
                /*safety check in case the string is not null-terminated*/
                if (data[bytesToRead-1]) {
                        char *str = (char*)gf_malloc((u32) bytesToRead + 1);
                        memcpy(str, data, (u32) bytesToRead);
                        str[ptr->size] = 0;
                        gf_free(data);
                        data = str;
                        bytesToRead++;
                }
                ptr->schemeURI = gf_strdup(data);
                schemeURIlen = (u32) strlen(data);
                if (bytesToRead > schemeURIlen+1) {
                        /* read the value */
                        char *data_value = data + schemeURIlen +1;
                        ptr->value = gf_strdup(data_value);
                }
                gf_free(data);
        }
        return GF_OK;
}

GF_Box *kind_New()
{
        ISOM_DECL_BOX_ALLOC(GF_KindBox, GF_ISOM_BOX_TYPE_KIND);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err kind_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_KindBox *ptr = (GF_KindBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_data(bs, ptr->schemeURI, (u32) (strlen(ptr->schemeURI) + 1 ));
        if (ptr->value) {
                gf_bs_write_data(bs, ptr->value, (u32) (strlen(ptr->value) + 1) );
        }
        return GF_OK;
}

GF_Err kind_Size(GF_Box *s)
{
        GF_KindBox *ptr = (GF_KindBox *)s;

        ptr->size += strlen(ptr->schemeURI) + 1;
        if (ptr->value) {
                ptr->size += strlen(ptr->value) + 1;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void ctts_del(GF_Box *s)
{
        GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}



GF_Err ctts_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        u32 sampleCount;
        GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s;

        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->nb_entries > ptr->size / 8) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        ptr->alloc_size = ptr->nb_entries;
        ptr->entries = (GF_DttsEntry *)gf_malloc(sizeof(GF_DttsEntry)*ptr->alloc_size);
        if (!ptr->entries) return GF_OUT_OF_MEM;
        sampleCount = 0;
        for (i=0; i<ptr->nb_entries; i++) {
                ptr->entries[i].sampleCount = gf_bs_read_u32(bs);
                if (ptr->version)
                        ptr->entries[i].decodingOffset = gf_bs_read_int(bs, 32);
                else
                        ptr->entries[i].decodingOffset = (s32) gf_bs_read_u32(bs);
                sampleCount += ptr->entries[i].sampleCount;
        }
#ifndef GPAC_DISABLE_ISOM_WRITE
        ptr->w_LastSampleNumber = sampleCount;
#endif
        return GF_OK;
}

GF_Box *ctts_New()
{
        ISOM_DECL_BOX_ALLOC(GF_CompositionOffsetBox, GF_ISOM_BOX_TYPE_CTTS);
        return (GF_Box *) tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err ctts_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i=0; i<ptr->nb_entries; i++ ) {
                gf_bs_write_u32(bs, ptr->entries[i].sampleCount);
                if (ptr->version) {
                        gf_bs_write_int(bs, ptr->entries[i].decodingOffset, 32);
                } else {
                        gf_bs_write_u32(bs, (u32) ptr->entries[i].decodingOffset);
                }
        }
        return GF_OK;
}

GF_Err ctts_Size(GF_Box *s)
{
        GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *) s;

        ptr->size += 4 + (8 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void cslg_del(GF_Box *s)
{
        GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
        return;
}

GF_Err cslg_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s;

        ptr->compositionToDTSShift = gf_bs_read_int(bs, 32);
        ptr->leastDecodeToDisplayDelta = gf_bs_read_int(bs, 32);
        ptr->greatestDecodeToDisplayDelta = gf_bs_read_int(bs, 32);
        ptr->compositionStartTime = gf_bs_read_int(bs, 32);
        ptr->compositionEndTime = gf_bs_read_int(bs, 32);
        return GF_OK;
}

GF_Box *cslg_New()
{
        ISOM_DECL_BOX_ALLOC(GF_CompositionToDecodeBox, GF_ISOM_BOX_TYPE_CSLG);
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err cslg_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, ptr->compositionToDTSShift, 32);
        gf_bs_write_int(bs, ptr->leastDecodeToDisplayDelta, 32);
        gf_bs_write_int(bs, ptr->greatestDecodeToDisplayDelta, 32);
        gf_bs_write_int(bs, ptr->compositionStartTime, 32);
        gf_bs_write_int(bs, ptr->compositionEndTime, 32);
        return GF_OK;
}

GF_Err cslg_Size(GF_Box *s)
{
        GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s;

        ptr->size += 20;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

void ccst_del(GF_Box *s)
{
        GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;
        if (ptr) gf_free(ptr);
        return;
}

GF_Err ccst_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;

        ISOM_DECREASE_SIZE(ptr, 4);
        ptr->all_ref_pics_intra = gf_bs_read_int(bs, 1);
        ptr->intra_pred_used = gf_bs_read_int(bs, 1);
        ptr->max_ref_per_pic = gf_bs_read_int(bs, 4);
        ptr->reserved = gf_bs_read_int(bs, 26);
        return GF_OK;
}

GF_Box *ccst_New()
{
        ISOM_DECL_BOX_ALLOC(GF_CodingConstraintsBox, GF_ISOM_BOX_TYPE_CCST);
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err ccst_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, ptr->all_ref_pics_intra, 1);
        gf_bs_write_int(bs, ptr->intra_pred_used, 1);
        gf_bs_write_int(bs, ptr->max_ref_per_pic, 4);
        gf_bs_write_int(bs, 0, 26);
        return GF_OK;
}

GF_Err ccst_Size(GF_Box *s)
{
        GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;
        ptr->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void url_del(GF_Box *s)
{
        GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s;
        if (ptr == NULL) return;
        if (ptr->location) gf_free(ptr->location);
        gf_free(ptr);
        return;
}


GF_Err url_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s;

        if (ptr->size) {
                ptr->location = (char*)gf_malloc((u32) ptr->size);
                if (! ptr->location) return GF_OUT_OF_MEM;
                gf_bs_read_data(bs, ptr->location, (u32)ptr->size);
        }
        return GF_OK;
}

GF_Box *url_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DataEntryURLBox, GF_ISOM_BOX_TYPE_URL);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err url_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        //the flag set indicates we have a string (WE HAVE TO for URLs)
        if ( !(ptr->flags & 1)) {
                if (ptr->location) {
                        gf_bs_write_data(bs, ptr->location, (u32)strlen(ptr->location) + 1);
                }
        }
        return GF_OK;
}

GF_Err url_Size(GF_Box *s)
{
        GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s;

        if ( !(ptr->flags & 1)) {
                if (ptr->location) ptr->size += 1 + strlen(ptr->location);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void urn_del(GF_Box *s)
{
        GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s;
        if (ptr == NULL) return;
        if (ptr->location) gf_free(ptr->location);
        if (ptr->nameURN) gf_free(ptr->nameURN);
        gf_free(ptr);
}


GF_Err urn_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i, to_read;
        char *tmpName;
        GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s;
        if (! ptr->size ) return GF_OK;

        //here we have to handle that in a clever way
        to_read = (u32) ptr->size;
        tmpName = (char*)gf_malloc(sizeof(char) * to_read);
        if (!tmpName) return GF_OUT_OF_MEM;
        //get the data
        gf_bs_read_data(bs, tmpName, to_read);

        //then get the break
        i = 0;
        while ( (tmpName[i] != 0) && (i < to_read) ) {
                i++;
        }
        //check the data is consistent
        if (i == to_read) {
                gf_free(tmpName);
                return GF_ISOM_INVALID_FILE;
        }
        //no NULL char, URL is not specified
        if (i == to_read - 1) {
                ptr->nameURN = tmpName;
                ptr->location = NULL;
                return GF_OK;
        }
        //OK, this has both URN and URL
        ptr->nameURN = (char*)gf_malloc(sizeof(char) * (i+1));
        if (!ptr->nameURN) {
                gf_free(tmpName);
                return GF_OUT_OF_MEM;
        }
        ptr->location = (char*)gf_malloc(sizeof(char) * (to_read - i - 1));
        if (!ptr->location) {
                gf_free(tmpName);
                gf_free(ptr->nameURN);
                ptr->nameURN = NULL;
                return GF_OUT_OF_MEM;
        }
        memcpy(ptr->nameURN, tmpName, i + 1);
        memcpy(ptr->location, tmpName + i + 1, (to_read - i - 1));
        gf_free(tmpName);
        return GF_OK;
}

GF_Box *urn_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DataEntryURNBox, GF_ISOM_BOX_TYPE_URN);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err urn_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        //the flag set indicates we have a string (WE HAVE TO for URLs)
        if ( !(ptr->flags & 1)) {
                //to check, the spec says: First name, then location
                if (ptr->nameURN) {
                        gf_bs_write_data(bs, ptr->nameURN, (u32)strlen(ptr->nameURN) + 1);
                }
                if (ptr->location) {
                        gf_bs_write_data(bs, ptr->location, (u32)strlen(ptr->location) + 1);
                }
        }
        return GF_OK;
}

GF_Err urn_Size(GF_Box *s)
{
        GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s;

        if ( !(ptr->flags & 1)) {
                if (ptr->nameURN) ptr->size += 1 + strlen(ptr->nameURN);
                if (ptr->location) ptr->size += 1 + strlen(ptr->location);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void unkn_del(GF_Box *s)
{
        GF_UnknownBox *ptr = (GF_UnknownBox *) s;
        if (!s) return;
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}


GF_Err unkn_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 bytesToRead, sub_size, sub_a;
        GF_BitStream *sub_bs;
        GF_UnknownBox *ptr = (GF_UnknownBox *)s;
        if (ptr->size > 0xFFFFFFFF) return GF_ISOM_INVALID_FILE;
        bytesToRead = (u32) (ptr->size);

        if (!bytesToRead) return GF_OK;
        if (bytesToRead>1000000) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Unknown box %s (0x%08X) with payload larger than 1 MBytes, ignoring\n", gf_4cc_to_str(ptr->type), ptr->type ));
                gf_bs_skip_bytes(bs, ptr->dataSize);
                return GF_OK;
        }

        ptr->data = (char*)gf_malloc(bytesToRead);
        if (ptr->data == NULL ) return GF_OUT_OF_MEM;
        ptr->dataSize = bytesToRead;
        gf_bs_read_data(bs, ptr->data, ptr->dataSize);

        //try to parse container boxes, check if next 8 bytes match a subbox
        sub_bs = gf_bs_new(ptr->data, ptr->dataSize, GF_BITSTREAM_READ);
        sub_size = gf_bs_read_u32(sub_bs);
        sub_a = gf_bs_read_u8(sub_bs);
        e = (sub_size && (sub_size <= ptr->dataSize)) ? GF_OK : GF_NOT_SUPPORTED;
        if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED;
        sub_a = gf_bs_read_u8(sub_bs);
        if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED;
        sub_a = gf_bs_read_u8(sub_bs);
        if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED;
        sub_a = gf_bs_read_u8(sub_bs);
        if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED;

        if (e == GF_OK) {
                gf_bs_seek(sub_bs, 0);
                e = gf_isom_box_array_read(s, sub_bs, gf_isom_box_add_default);
        }
        gf_bs_del(sub_bs);
        if (e==GF_OK) {
                gf_free(ptr->data);
                ptr->data = NULL;
                ptr->dataSize = 0;
        } else if (s->other_boxes) {
                gf_isom_box_array_del(s->other_boxes);
                s->other_boxes=NULL;
        }

        return GF_OK;
}

GF_Box *unkn_New(u32 box_type)
{
        ISOM_DECL_BOX_ALLOC(GF_UnknownBox, GF_ISOM_BOX_TYPE_UNKNOWN);
        tmp->original_4cc = box_type;
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err unkn_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 type = s->type;
        GF_UnknownBox *ptr = (GF_UnknownBox *)s;
        if (!s) return GF_BAD_PARAM;
        s->type = ptr->original_4cc;
        e = gf_isom_box_write_header(s, bs);
        s->type = type;
        if (e) return e;

        if (ptr->dataSize && ptr->data) {
                gf_bs_write_data(bs, ptr->data, ptr->dataSize);
        }
        return GF_OK;
}

GF_Err unkn_Size(GF_Box *s)
{
        GF_UnknownBox *ptr = (GF_UnknownBox *)s;

        if (ptr->dataSize && ptr->data) {
                ptr->size += ptr->dataSize;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void def_cont_box_del(GF_Box *s)
{
        if (s) gf_free(s);
}


GF_Err def_cont_box_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, gf_isom_box_add_default);
}

GF_Box *def_cont_box_New()
{
        ISOM_DECL_BOX_ALLOC(GF_Box, 0);
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITEHintSa

GF_Err def_cont_box_Write(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_write_header(s, bs);
}

GF_Err def_cont_box_Size(GF_Box *s)
{
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void uuid_del(GF_Box *s)
{
        GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox *) s;
        if (!s) return;
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}


GF_Err uuid_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 bytesToRead;
        GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox *)s;
        if (ptr->size > 0xFFFFFFFF) return GF_ISOM_INVALID_FILE;
        bytesToRead = (u32) (ptr->size);

        if (bytesToRead) {
                ptr->data = (char*)gf_malloc(bytesToRead);
                if (ptr->data == NULL ) return GF_OUT_OF_MEM;
                ptr->dataSize = bytesToRead;
                gf_bs_read_data(bs, ptr->data, ptr->dataSize);
        }
        return GF_OK;
}

GF_Box *uuid_New()
{
        ISOM_DECL_BOX_ALLOC(GF_UnknownUUIDBox, GF_ISOM_BOX_TYPE_UUID);
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err uuid_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox*)s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        if (ptr->data) {
                gf_bs_write_data(bs, ptr->data, ptr->dataSize);
        }
        return GF_OK;
}

GF_Err uuid_Size(GF_Box *s)
{
        GF_UnknownUUIDBox*ptr = (GF_UnknownUUIDBox*)s;
        ptr->size += ptr->dataSize;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void dinf_del(GF_Box *s)
{
        GF_DataInformationBox *ptr = (GF_DataInformationBox *)s;
        if (ptr == NULL) return;
        gf_isom_box_del((GF_Box *)ptr->dref);
        gf_free(ptr);
}


GF_Err dinf_AddBox(GF_Box *s, GF_Box *a)
{
        GF_DataInformationBox *ptr = (GF_DataInformationBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_DREF:
                if (ptr->dref) ERROR_ON_DUPLICATED_BOX(a, ptr)

                        ptr->dref = (GF_DataReferenceBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err dinf_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e = gf_isom_box_array_read(s, bs, dinf_AddBox);
        if (e) {
                return e;
        }
        if (!((GF_DataInformationBox *)s)->dref) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing dref box in dinf\n"));
                ((GF_DataInformationBox *)s)->dref = (GF_DataReferenceBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DREF);
        }
        return GF_OK;
}

GF_Box *dinf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DataInformationBox, GF_ISOM_BOX_TYPE_DINF);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err dinf_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DataInformationBox *ptr = (GF_DataInformationBox *)s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        if (ptr->dref) {
                e = gf_isom_box_write((GF_Box *)ptr->dref, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err dinf_Size(GF_Box *s)
{
        GF_Err e;
        GF_DataInformationBox *ptr = (GF_DataInformationBox *)s;
        if (ptr->dref) {
                e = gf_isom_box_size((GF_Box *) ptr->dref);
                if (e) return e;
                ptr->size += ptr->dref->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void dref_del(GF_Box *s)
{
        GF_DataReferenceBox *ptr = (GF_DataReferenceBox *) s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err dref_AddDataEntry(GF_Box *ptr, GF_Box *entry)
{
        if (entry->type==GF_4CC('a','l','i','s')) {
                GF_DataEntryURLBox *urle = (GF_DataEntryURLBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_URL);
                urle->flags = 1;
                gf_isom_box_del(entry);
                gf_isom_box_add_default(ptr, (GF_Box *)urle);
                GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] Apple \'alis\' box found, not supported - converting to self-pointing \'url \' \n" ));
        } else {
                return gf_isom_box_add_default(ptr, entry);
        }
        return GF_OK;
}

GF_Err dref_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s;

        if (ptr == NULL) return GF_BAD_PARAM;
        gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        return gf_isom_box_array_read(s, bs, dref_AddDataEntry);
}

GF_Box *dref_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DataReferenceBox, GF_ISOM_BOX_TYPE_DREF);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err dref_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 count;
        GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        count = ptr->other_boxes ? gf_list_count(ptr->other_boxes) : 0;
        gf_bs_write_u32(bs, count);
        return GF_OK;
}

GF_Err dref_Size(GF_Box *s)
{
        GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s;
        if (!s) return GF_BAD_PARAM;

        ptr->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void edts_del(GF_Box *s)
{
        GF_EditBox *ptr = (GF_EditBox *) s;
        gf_isom_box_del((GF_Box *)ptr->editList);
        gf_free(ptr);
}


GF_Err edts_AddBox(GF_Box *s, GF_Box *a)
{
        GF_EditBox *ptr = (GF_EditBox *)s;
        if (a->type == GF_ISOM_BOX_TYPE_ELST) {
                if (ptr->editList) return GF_BAD_PARAM;
                ptr->editList = (GF_EditListBox *)a;
                return GF_OK;
        } else {
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err edts_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, edts_AddBox);
}

GF_Box *edts_New()
{
        ISOM_DECL_BOX_ALLOC(GF_EditBox, GF_ISOM_BOX_TYPE_EDTS);
        return (GF_Box *) tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err edts_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_EditBox *ptr = (GF_EditBox *)s;

        //here we have a trick: if editList is empty, skip the box
        if (ptr->editList && gf_list_count(ptr->editList->entryList)) {
                e = gf_isom_box_write_header(s, bs);
                if (e) return e;
                e = gf_isom_box_write((GF_Box *) ptr->editList, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err edts_Size(GF_Box *s)
{
        GF_Err e;
        GF_EditBox *ptr = (GF_EditBox *)s;

        //here we have a trick: if editList is empty, skip the box
        if (!ptr->editList || ! gf_list_count(ptr->editList->entryList)) {
                ptr->size = 0;
        } else {
                e = gf_isom_box_size((GF_Box *)ptr->editList);
                if (e) return e;
                ptr->size += ptr->editList->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void elst_del(GF_Box *s)
{
        GF_EditListBox *ptr;
        GF_EdtsEntry *p;
        u32 nb_entries;
        u32 i;

        ptr = (GF_EditListBox *)s;
        if (ptr == NULL) return;
        nb_entries = gf_list_count(ptr->entryList);
        for (i = 0; i < nb_entries; i++) {
                p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i);
                if (p) gf_free(p);
        }
        gf_list_del(ptr->entryList);
        gf_free(ptr);
}




GF_Err elst_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 entries;
        s32 tr;
        u32 nb_entries;
        GF_EdtsEntry *p;
        GF_EditListBox *ptr = (GF_EditListBox *)s;

        nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->version == 1) {
                if (nb_entries > ptr->size / 20) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", nb_entries));
                        return GF_ISOM_INVALID_FILE;
                }
        } else {
                if (nb_entries > ptr->size / 12) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", nb_entries));
                        return GF_ISOM_INVALID_FILE;
                }
        }


        for (entries = 0; entries < nb_entries; entries++ ) {
                p = (GF_EdtsEntry *) gf_malloc(sizeof(GF_EdtsEntry));
                if (!p) return GF_OUT_OF_MEM;
                if (ptr->version == 1) {
                        p->segmentDuration = gf_bs_read_u64(bs);
                        p->mediaTime = (s64) gf_bs_read_u64(bs);
                } else {
                        p->segmentDuration = gf_bs_read_u32(bs);
                        tr = gf_bs_read_u32(bs);
                        p->mediaTime = (s64) tr;
                }
                p->mediaRate = gf_bs_read_u16(bs);
                gf_bs_read_u16(bs);
                gf_list_add(ptr->entryList, p);
        }
        return GF_OK;
}

GF_Box *elst_New()
{
        ISOM_DECL_BOX_ALLOC(GF_EditListBox, GF_ISOM_BOX_TYPE_ELST);
        tmp->entryList = gf_list_new();
        if (!tmp->entryList) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err elst_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        u32 nb_entries;
        GF_EdtsEntry *p;
        GF_EditListBox *ptr = (GF_EditListBox *)s;
        if (!ptr) return GF_BAD_PARAM;

        nb_entries = gf_list_count(ptr->entryList);
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, nb_entries);
        for (i = 0; i < nb_entries; i++ ) {
                p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i);
                if (ptr->version == 1) {
                        gf_bs_write_u64(bs, p->segmentDuration);
                        gf_bs_write_u64(bs, p->mediaTime);
                } else {
                        gf_bs_write_u32(bs, (u32) p->segmentDuration);
                        gf_bs_write_u32(bs, (s32) p->mediaTime);
                }
                gf_bs_write_u16(bs, p->mediaRate);
                gf_bs_write_u16(bs, 0);
        }
        return GF_OK;
}

GF_Err elst_Size(GF_Box *s)
{
        u32 durtimebytes;
        u32 i, nb_entries;
        GF_EditListBox *ptr = (GF_EditListBox *)s;

        //entry count
        ptr->size += 4;
        nb_entries = gf_list_count(ptr->entryList);
        ptr->version = 0;
        for (i=0; i<nb_entries; i++) {
                GF_EdtsEntry *p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i);
                if ((p->segmentDuration>0xFFFFFFFF) || (p->mediaTime>0xFFFFFFFF)) {
                        ptr->version = 1;
                        break;
                }
        }
        durtimebytes = (ptr->version == 1 ? 16 : 8) + 4;
        ptr->size += (nb_entries * durtimebytes);
        return GF_OK;
}


#endif /*GPAC_DISABLE_ISOM_WRITE*/

void esds_del(GF_Box *s)
{
        GF_ESDBox *ptr = (GF_ESDBox *)s;
        if (ptr == NULL)        return;
        if (ptr->desc) gf_odf_desc_del((GF_Descriptor *)ptr->desc);
        gf_free(ptr);
}


GF_Err esds_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e=GF_OK;
        u32 descSize;
        char *enc_desc;
        u32 SLIsPredefined(GF_SLConfig *sl);
        GF_ESDBox *ptr = (GF_ESDBox *)s;

        descSize = (u32) (ptr->size);

        if (descSize) {
                enc_desc = (char*)gf_malloc(sizeof(char) * descSize);
                if (!enc_desc) return GF_OUT_OF_MEM;
                //get the payload
                gf_bs_read_data(bs, enc_desc, descSize);
                //send it to the OD Codec
                e = gf_odf_desc_read(enc_desc, descSize, (GF_Descriptor **) &ptr->desc);
                //OK, free our desc
                gf_free(enc_desc);

                if (ptr->desc && (ptr->desc->tag!=GF_ODF_ESD_TAG) ) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid descriptor tag 0x%x in esds\n", ptr->desc->tag));
                        gf_odf_desc_del((GF_Descriptor*)ptr->desc);
                        ptr->desc=NULL;
                        return GF_ISOM_INVALID_FILE;
                }

                if (e) {
                        ptr->desc = NULL;
                } else {
                        /*fix broken files*/
                        if (!ptr->desc->URLString) {
                                if (!ptr->desc->slConfig) {
                                        ptr->desc->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
                                        ptr->desc->slConfig->predefined = SLPredef_MP4;
                                } else if (ptr->desc->slConfig->predefined != SLPredef_MP4) {
                                        ptr->desc->slConfig->predefined = SLPredef_MP4;
                                        gf_odf_slc_set_pref(ptr->desc->slConfig);
                                }
                        }
                }
        }
        return e;
}

GF_Box *esds_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ESDBox, GF_ISOM_BOX_TYPE_ESDS);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err esds_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        char *enc_desc;
        u32 descSize = 0;
        GF_ESDBox *ptr = (GF_ESDBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        e = gf_odf_desc_write((GF_Descriptor *)ptr->desc, &enc_desc, &descSize);
        if (e) return e;
        gf_bs_write_data(bs, enc_desc, descSize);
        //free our buffer
        gf_free(enc_desc);
        return GF_OK;
}

GF_Err esds_Size(GF_Box *s)
{
        u32 descSize = 0;
        GF_ESDBox *ptr = (GF_ESDBox *)s;
        descSize = gf_odf_desc_size((GF_Descriptor *)ptr->desc);
        ptr->size += descSize;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void free_del(GF_Box *s)
{
        GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}


GF_Err free_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 bytesToRead;
        GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;

        if (ptr->size > 0xFFFFFFFF) return GF_IO_ERR;

        bytesToRead = (u32) (ptr->size);

        if (bytesToRead) {
                ptr->data = (char*)gf_malloc(bytesToRead * sizeof(char));
                gf_bs_read_data(bs, ptr->data, bytesToRead);
                ptr->dataSize = bytesToRead;
        }
        return GF_OK;
}

GF_Box *free_New()
{
        ISOM_DECL_BOX_ALLOC(GF_FreeSpaceBox, GF_ISOM_BOX_TYPE_FREE);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err free_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;
        if (ptr->original_4cc) {
                u32 t = s->type;
                s->type=ptr->original_4cc;
                e = gf_isom_box_write_header(s, bs);
                s->type=t;
        } else {
                e = gf_isom_box_write_header(s, bs);
        }
        if (e) return e;
        if (ptr->dataSize)      {
                if (ptr->data) {
                        gf_bs_write_data(bs, ptr->data, ptr->dataSize);
                } else {
                        u32 i = 0;
                        while (i<ptr->dataSize) {
                                gf_bs_write_u8(bs, 0);
                                i++;
                        }
                }
        }
        return GF_OK;
}

GF_Err free_Size(GF_Box *s)
{
        GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;
        ptr->size += ptr->dataSize;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void ftyp_del(GF_Box *s)
{
        GF_FileTypeBox *ptr = (GF_FileTypeBox *) s;
        if (ptr->altBrand) gf_free(ptr->altBrand);
        gf_free(ptr);
}

GF_Box *ftyp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_FileTypeBox, GF_ISOM_BOX_TYPE_FTYP);
        return (GF_Box *)tmp;
}

GF_Err ftyp_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 i;
        GF_FileTypeBox *ptr = (GF_FileTypeBox *)s;

        if (ptr->size < 8) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Found ftyp with size < 8, likely broken!\n"));
                return GF_BAD_PARAM;
        }
        ptr->majorBrand = gf_bs_read_u32(bs);
        ptr->minorVersion = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 8);

        ptr->altCount = ( (u32) (ptr->size)) / 4;
        if (!ptr->altCount) return GF_OK;
        if (ptr->altCount * 4 != (u32) (ptr->size)) return GF_ISOM_INVALID_FILE;

        ptr->altBrand = (u32*)gf_malloc(sizeof(u32)*ptr->altCount);
        for (i = 0; i<ptr->altCount; i++) {
                ptr->altBrand[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err ftyp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_FileTypeBox *ptr = (GF_FileTypeBox *) s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->majorBrand);
        gf_bs_write_u32(bs, ptr->minorVersion);
        for (i=0; i<ptr->altCount; i++) {
                gf_bs_write_u32(bs, ptr->altBrand[i]);
        }
        return GF_OK;
}

GF_Err ftyp_Size(GF_Box *s)
{
        GF_FileTypeBox *ptr = (GF_FileTypeBox *)s;

        ptr->size += 8 + ptr->altCount * 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void gnrm_del(GF_Box *s)
{
        GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr);
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}

GF_Box *gnrm_New()
{
        ISOM_DECL_BOX_ALLOC(GF_GenericSampleEntryBox, GF_ISOM_BOX_TYPE_GNRM);

        gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}

//dummy
GF_Err gnrm_Read(GF_Box *s, GF_BitStream *bs)
{
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err gnrm_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s;

        //carefull we are not writing the box type but the entry type so switch for write
        ptr->type = ptr->EntryType;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        ptr->type = GF_ISOM_BOX_TYPE_GNRM;
        gf_bs_write_data(bs, ptr->reserved, 6);
        gf_bs_write_u16(bs, ptr->dataReferenceIndex);
        gf_bs_write_data(bs,  ptr->data, ptr->data_size);
        return GF_OK;
}

GF_Err gnrm_Size(GF_Box *s)
{
        GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s;
        s->type = GF_ISOM_BOX_TYPE_GNRM;
        ptr->size += 8+ptr->data_size;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void gnrv_del(GF_Box *s)
{
        GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr);
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}

GF_Box *gnrv_New()
{
        ISOM_DECL_BOX_ALLOC(GF_GenericVisualSampleEntryBox, GF_ISOM_BOX_TYPE_GNRV);
        gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox*) tmp);
        return (GF_Box *)tmp;
}
//dummy
GF_Err gnrv_Read(GF_Box *s, GF_BitStream *bs)
{
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err gnrv_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s;

        //carefull we are not writing the box type but the entry type so switch for write
        ptr->type = ptr->EntryType;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        ptr->type = GF_ISOM_BOX_TYPE_GNRV;

        gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)ptr, bs);
        gf_bs_write_data(bs,  ptr->data, ptr->data_size);
        return GF_OK;
}

GF_Err gnrv_Size(GF_Box *s)
{
        GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s;
        s->type = GF_ISOM_BOX_TYPE_GNRV;
        gf_isom_video_sample_entry_size((GF_VisualSampleEntryBox *)s);
        ptr->size += ptr->data_size;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void gnra_del(GF_Box *s)
{
        GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr);
        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}

GF_Box *gnra_New()
{
        ISOM_DECL_BOX_ALLOC(GF_GenericAudioSampleEntryBox, GF_ISOM_BOX_TYPE_GNRA);
        gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*) tmp);
        return (GF_Box *)tmp;
}
//dummy
GF_Err gnra_Read(GF_Box *s, GF_BitStream *bs)
{
        return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err gnra_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s;

        //carefull we are not writing the box type but the entry type so switch for write
        ptr->type = ptr->EntryType;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        ptr->type = GF_ISOM_BOX_TYPE_GNRA;

        gf_isom_audio_sample_entry_write((GF_AudioSampleEntryBox *)ptr, bs);
        if (ptr->data) {
                gf_bs_write_data(bs,  ptr->data, ptr->data_size);
        }
        return GF_OK;
}

GF_Err gnra_Size(GF_Box *s)
{
        GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s;
        s->type = GF_ISOM_BOX_TYPE_GNRA;
        gf_isom_audio_sample_entry_size((GF_AudioSampleEntryBox *)s);
        ptr->size += ptr->data_size;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void hdlr_del(GF_Box *s)
{
        GF_HandlerBox *ptr = (GF_HandlerBox *)s;
        if (ptr == NULL) return;
        if (ptr->nameUTF8) gf_free(ptr->nameUTF8);
        gf_free(ptr);
}


GF_Err hdlr_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_HandlerBox *ptr = (GF_HandlerBox *)s;

        ptr->reserved1 = gf_bs_read_u32(bs);
        ptr->handlerType = gf_bs_read_u32(bs);
        gf_bs_read_data(bs, (char*)ptr->reserved2, 12);

        ISOM_DECREASE_SIZE(ptr, 20);

        if (ptr->size) {
                size_t len;
                ptr->nameUTF8 = (char*)gf_malloc((u32) ptr->size);
                if (ptr->nameUTF8 == NULL) return GF_OUT_OF_MEM;
                gf_bs_read_data(bs, ptr->nameUTF8, (u32) ptr->size);
                /*safety check in case the string is not null-terminated*/
                if (ptr->nameUTF8[ptr->size-1]) {
                        char *str = (char*)gf_malloc((u32) ptr->size + 1);
                        memcpy(str, ptr->nameUTF8, (u32) ptr->size);
                        str[ptr->size] = 0;
                        gf_free(ptr->nameUTF8);
                        ptr->nameUTF8 = str;
                }
                //patch for old QT files
                if (ptr->size > 1 && ptr->nameUTF8[0] == ptr->size-1) {
                        len = strlen(ptr->nameUTF8 + 1);
                        memmove(ptr->nameUTF8, ptr->nameUTF8+1, len );
                        ptr->nameUTF8[len] = 0;
                        ptr->store_counted_string = GF_TRUE;
                }
        }
        return GF_OK;
}

GF_Box *hdlr_New()
{
        ISOM_DECL_BOX_ALLOC(GF_HandlerBox, GF_ISOM_BOX_TYPE_HDLR);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err hdlr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_HandlerBox *ptr = (GF_HandlerBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->reserved1);
        gf_bs_write_u32(bs, ptr->handlerType);
        gf_bs_write_data(bs, (char*)ptr->reserved2, 12);

        if (ptr->nameUTF8) {
                u32 len = (u32)strlen(ptr->nameUTF8);
                if (ptr->store_counted_string) {
                        gf_bs_write_u8(bs, len);
                        gf_bs_write_data(bs, ptr->nameUTF8, len);
                } else {
                        gf_bs_write_data(bs, ptr->nameUTF8, len);
                        gf_bs_write_u8(bs, 0);
                }
        } else {
                gf_bs_write_u8(bs, 0);
        }
        return GF_OK;
}

GF_Err hdlr_Size(GF_Box *s)
{
        GF_HandlerBox *ptr = (GF_HandlerBox *)s;
        ptr->size += 20 + 1; //null term or counted string
        if (ptr->nameUTF8) {
                ptr->size += strlen(ptr->nameUTF8);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void hinf_del(GF_Box *s)
{
        GF_HintInfoBox *hinf = (GF_HintInfoBox *)s;
        gf_free(hinf);
}

GF_Box *hinf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_HintInfoBox, GF_ISOM_BOX_TYPE_HINF);

        tmp->other_boxes = gf_list_new();
        return (GF_Box *)tmp;
}

GF_Err hinf_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MAXRBox *maxR;
        GF_HintInfoBox *hinf = (GF_HintInfoBox *)s;
        u32 i;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_MAXR:
                i=0;
                while ((maxR = (GF_MAXRBox *)gf_list_enum(hinf->other_boxes, &i))) {
                        if ((maxR->type==GF_ISOM_BOX_TYPE_MAXR) && (maxR->granularity == ((GF_MAXRBox *)a)->granularity))
                                return GF_ISOM_INVALID_FILE;
                }
                break;
        }
        return gf_isom_box_add_default(s, a);
}


GF_Err hinf_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, hinf_AddBox);
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err hinf_Write(GF_Box *s, GF_BitStream *bs)
{
//      GF_HintInfoBox *ptr = (GF_HintInfoBox *)s;
        if (!s) return GF_BAD_PARAM;
        return gf_isom_box_write_header(s, bs);
}

GF_Err hinf_Size(GF_Box *s)
{
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

void hmhd_del(GF_Box *s)
{
        GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err hmhd_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s;

        ptr->maxPDUSize = gf_bs_read_u16(bs);
        ptr->avgPDUSize = gf_bs_read_u16(bs);
        ptr->maxBitrate = gf_bs_read_u32(bs);
        ptr->avgBitrate = gf_bs_read_u32(bs);
        ptr->slidingAverageBitrate = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *hmhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_HintMediaHeaderBox, GF_ISOM_BOX_TYPE_HMHD);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err hmhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u16(bs, ptr->maxPDUSize);
        gf_bs_write_u16(bs, ptr->avgPDUSize);
        gf_bs_write_u32(bs, ptr->maxBitrate);
        gf_bs_write_u32(bs, ptr->avgBitrate);
        gf_bs_write_u32(bs, ptr->slidingAverageBitrate);
        return GF_OK;
}

GF_Err hmhd_Size(GF_Box *s)
{
        GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s;
        ptr->size += 16;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Box *hnti_New()
{
        ISOM_DECL_BOX_ALLOC(GF_HintTrackInfoBox, GF_ISOM_BOX_TYPE_HNTI);
        return (GF_Box *)tmp;
}

void hnti_del(GF_Box *a)
{
        gf_free(a);
}

GF_Err hnti_AddBox(GF_Box *s, GF_Box *a)
{
        GF_HintTrackInfoBox *hnti = (GF_HintTrackInfoBox *)s;
        if (!hnti || !a) return GF_BAD_PARAM;

        switch (a->type) {
        //this is the value for GF_RTPBox - same as HintSampleEntry for RTP !!!
        case GF_ISOM_BOX_TYPE_RTP:
        case GF_ISOM_BOX_TYPE_SDP:
                if (hnti->SDP) return GF_BAD_PARAM;
                hnti->SDP = a;
                break;
        default:
                break;
        }
        return gf_isom_box_add_default(s, a);
}

GF_Err hnti_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read_ex(s, bs, hnti_AddBox, s->type);
}

#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err hnti_Write(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_write_header(s, bs);
}


GF_Err hnti_Size(GF_Box *s)
{
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

/**********************************************************
                GF_SDPBox
**********************************************************/

void sdp_del(GF_Box *s)
{
        GF_SDPBox *ptr = (GF_SDPBox *)s;
        if (ptr->sdpText) gf_free(ptr->sdpText);
        gf_free(ptr);

}
GF_Err sdp_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 length;
        GF_SDPBox *ptr = (GF_SDPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        length = (u32) (ptr->size);
        //sdp text has no delimiter !!!
        ptr->sdpText = (char*)gf_malloc(sizeof(char) * (length+1));
        if (!ptr->sdpText) return GF_OUT_OF_MEM;

        gf_bs_read_data(bs, ptr->sdpText, length);
        ptr->sdpText[length] = 0;
        return GF_OK;
}
GF_Box *sdp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SDPBox, GF_ISOM_BOX_TYPE_SDP);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err sdp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SDPBox *ptr = (GF_SDPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        //don't write the NULL char!!!
        gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText));
        return GF_OK;
}
GF_Err sdp_Size(GF_Box *s)
{
        GF_SDPBox *ptr = (GF_SDPBox *)s;
        //don't count the NULL char!!!
        ptr->size += strlen(ptr->sdpText);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/




void rtp_hnti_del(GF_Box *s)
{
        GF_RTPBox *ptr = (GF_RTPBox *)s;
        if (ptr->sdpText) gf_free(ptr->sdpText);
        gf_free(ptr);

}
GF_Err rtp_hnti_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 length;
        GF_RTPBox *ptr = (GF_RTPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        ISOM_DECREASE_SIZE(ptr, 4)
        ptr->subType = gf_bs_read_u32(bs);

        length = (u32) (ptr->size);
        //sdp text has no delimiter !!!
        ptr->sdpText = (char*)gf_malloc(sizeof(char) * (length+1));
        if (!ptr->sdpText) return GF_OUT_OF_MEM;

        gf_bs_read_data(bs, ptr->sdpText, length);
        ptr->sdpText[length] = 0;
        return GF_OK;
}

GF_Box *rtp_hnti_New()
{
        ISOM_DECL_BOX_ALLOC(GF_RTPBox, GF_ISOM_BOX_TYPE_RTP);
        tmp->subType = GF_ISOM_BOX_TYPE_SDP;
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err rtp_hnti_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_RTPBox *ptr = (GF_RTPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->subType);
        //don't write the NULL char!!!
        gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText));
        return GF_OK;
}

GF_Err rtp_hnti_Size(GF_Box *s)
{
        GF_RTPBox *ptr = (GF_RTPBox *)s;
        ptr->size += 4 + strlen(ptr->sdpText);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                TRPY GF_Box
**********************************************************/

void trpy_del(GF_Box *s)
{
        gf_free((GF_TRPYBox *)s);
}
GF_Err trpy_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TRPYBox *ptr = (GF_TRPYBox *)s;
        ptr->nbBytes = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *trpy_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TRPYBox, GF_ISOM_BOX_TYPE_TRPY);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err trpy_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TRPYBox *ptr = (GF_TRPYBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err trpy_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

/**********************************************************
                TOTL GF_Box
**********************************************************/

void totl_del(GF_Box *s)
{
        gf_free((GF_TRPYBox *)s);
}
GF_Err totl_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TOTLBox *ptr = (GF_TOTLBox *)s;
        ptr->nbBytes = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *totl_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TOTLBox, GF_ISOM_BOX_TYPE_TOTL);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err totl_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TOTLBox *ptr = (GF_TOTLBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err totl_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                NUMP GF_Box
**********************************************************/

void nump_del(GF_Box *s)
{
        gf_free((GF_NUMPBox *)s);
}
GF_Err nump_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_NUMPBox *ptr = (GF_NUMPBox *)s;
        ptr->nbPackets = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *nump_New()
{
        ISOM_DECL_BOX_ALLOC(GF_NUMPBox, GF_ISOM_BOX_TYPE_NUMP);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err nump_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_NUMPBox *ptr = (GF_NUMPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbPackets);
        return GF_OK;
}
GF_Err nump_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                NPCK GF_Box
**********************************************************/

void npck_del(GF_Box *s)
{
        gf_free((GF_NPCKBox *)s);
}
GF_Err npck_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_NPCKBox *ptr = (GF_NPCKBox *)s;
        ptr->nbPackets = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *npck_New()
{
        ISOM_DECL_BOX_ALLOC(GF_NPCKBox, GF_ISOM_BOX_TYPE_NPCK);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err npck_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_NPCKBox *ptr = (GF_NPCKBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nbPackets);
        return GF_OK;
}
GF_Err npck_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                TPYL GF_Box
**********************************************************/

void tpyl_del(GF_Box *s)
{
        gf_free((GF_NTYLBox *)s);
}
GF_Err tpyl_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_NTYLBox *ptr = (GF_NTYLBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        ptr->nbBytes = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *tpyl_New()
{
        ISOM_DECL_BOX_ALLOC(GF_NTYLBox, GF_ISOM_BOX_TYPE_TPYL);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tpyl_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_NTYLBox *ptr = (GF_NTYLBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err tpyl_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

/**********************************************************
                TPAY GF_Box
**********************************************************/

void tpay_del(GF_Box *s)
{
        gf_free((GF_TPAYBox *)s);
}
GF_Err tpay_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TPAYBox *ptr = (GF_TPAYBox *)s;
        ptr->nbBytes = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *tpay_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TPAYBox, GF_ISOM_BOX_TYPE_TPAY);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tpay_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TPAYBox *ptr = (GF_TPAYBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err tpay_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                MAXR GF_Box
**********************************************************/

void maxr_del(GF_Box *s)
{
        gf_free((GF_MAXRBox *)s);
}
GF_Err maxr_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MAXRBox *ptr = (GF_MAXRBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        ptr->granularity = gf_bs_read_u32(bs);
        ptr->maxDataRate = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *maxr_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MAXRBox, GF_ISOM_BOX_TYPE_MAXR);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err maxr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MAXRBox *ptr = (GF_MAXRBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->granularity);
        gf_bs_write_u32(bs, ptr->maxDataRate);
        return GF_OK;
}
GF_Err maxr_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                DMED GF_Box
**********************************************************/

void dmed_del(GF_Box *s)
{
        gf_free((GF_DMEDBox *)s);
}
GF_Err dmed_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DMEDBox *ptr = (GF_DMEDBox *)s;
        ptr->nbBytes = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *dmed_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DMEDBox, GF_ISOM_BOX_TYPE_DMED);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dmed_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DMEDBox *ptr = (GF_DMEDBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err dmed_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

/**********************************************************
                DIMM GF_Box
**********************************************************/

void dimm_del(GF_Box *s)
{
        gf_free((GF_DIMMBox *)s);
}
GF_Err dimm_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DIMMBox *ptr = (GF_DIMMBox *)s;
        ptr->nbBytes = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *dimm_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DIMMBox, GF_ISOM_BOX_TYPE_DIMM);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dimm_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DIMMBox *ptr = (GF_DIMMBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err dimm_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

/**********************************************************
                DREP GF_Box
**********************************************************/

void drep_del(GF_Box *s)
{
        gf_free((GF_DREPBox *)s);
}
GF_Err drep_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DREPBox *ptr = (GF_DREPBox *)s;
        ptr->nbBytes = gf_bs_read_u64(bs);
        return GF_OK;
}
GF_Box *drep_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DREPBox, GF_ISOM_BOX_TYPE_DREP);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err drep_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DREPBox *ptr = (GF_DREPBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->nbBytes);
        return GF_OK;
}
GF_Err drep_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/



/**********************************************************
                TMIN GF_Box
**********************************************************/

void tmin_del(GF_Box *s)
{
        gf_free((GF_TMINBox *)s);
}
GF_Err tmin_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TMINBox *ptr = (GF_TMINBox *)s;
        ptr->minTime = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *tmin_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TMINBox, GF_ISOM_BOX_TYPE_TMIN);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tmin_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TMINBox *ptr = (GF_TMINBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->minTime);
        return GF_OK;
}
GF_Err tmin_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                TMAX GF_Box
**********************************************************/

void tmax_del(GF_Box *s)
{
        gf_free((GF_TMAXBox *)s);
}
GF_Err tmax_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TMAXBox *ptr = (GF_TMAXBox *)s;
        ptr->maxTime = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *tmax_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TMAXBox, GF_ISOM_BOX_TYPE_TMAX);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tmax_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TMAXBox *ptr = (GF_TMAXBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->maxTime);
        return GF_OK;
}
GF_Err tmax_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                PMAX GF_Box
**********************************************************/

void pmax_del(GF_Box *s)
{
        gf_free((GF_PMAXBox *)s);
}
GF_Err pmax_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_PMAXBox *ptr = (GF_PMAXBox *)s;
        ptr->maxSize = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *pmax_New()
{
        ISOM_DECL_BOX_ALLOC(GF_PMAXBox, GF_ISOM_BOX_TYPE_PMAX);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err pmax_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_PMAXBox *ptr = (GF_PMAXBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->maxSize);
        return GF_OK;
}
GF_Err pmax_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                DMAX GF_Box
**********************************************************/

void dmax_del(GF_Box *s)
{
        gf_free((GF_DMAXBox *)s);
}
GF_Err dmax_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_DMAXBox *ptr = (GF_DMAXBox *)s;
        ptr->maxDur = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *dmax_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DMAXBox, GF_ISOM_BOX_TYPE_DMAX);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dmax_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_DMAXBox *ptr = (GF_DMAXBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->maxDur);
        return GF_OK;
}
GF_Err dmax_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                PAYT GF_Box
**********************************************************/

void payt_del(GF_Box *s)
{
        GF_PAYTBox *payt = (GF_PAYTBox *)s;
        if (payt->payloadString) gf_free(payt->payloadString);
        gf_free(payt);
}
GF_Err payt_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 length;
        GF_PAYTBox *ptr = (GF_PAYTBox *)s;

        ptr->payloadCode = gf_bs_read_u32(bs);
        length = gf_bs_read_u8(bs);
        ptr->payloadString = (char*)gf_malloc(sizeof(char) * (length+1) );
        if (! ptr->payloadString) return GF_OUT_OF_MEM;
        gf_bs_read_data(bs, ptr->payloadString, length);
        ptr->payloadString[length] = 0;

        ISOM_DECREASE_SIZE(ptr, (4+length+1) );
        return GF_OK;
}
GF_Box *payt_New()
{
        ISOM_DECL_BOX_ALLOC(GF_PAYTBox, GF_ISOM_BOX_TYPE_PAYT);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err payt_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 len;
        GF_Err e;
        GF_PAYTBox *ptr = (GF_PAYTBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->payloadCode);
        len = (u32) strlen(ptr->payloadString);
        gf_bs_write_u8(bs, len);
        if (len) gf_bs_write_data(bs, ptr->payloadString, len);
        return GF_OK;
}
GF_Err payt_Size(GF_Box *s)
{
        GF_PAYTBox *ptr = (GF_PAYTBox *)s;
        s->size += 4;
        if (ptr->payloadString) ptr->size += strlen(ptr->payloadString) + 1;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


/**********************************************************
                PAYT GF_Box
**********************************************************/

void name_del(GF_Box *s)
{
        GF_NameBox *name = (GF_NameBox *)s;
        if (name->string) gf_free(name->string);
        gf_free(name);
}
GF_Err name_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 length;
        GF_NameBox *ptr = (GF_NameBox *)s;

        length = (u32) (ptr->size);
        ptr->string = (char*)gf_malloc(sizeof(char) * (length+1));
        if (! ptr->string) return GF_OUT_OF_MEM;

        gf_bs_read_data(bs, ptr->string, length);
        ptr->string[length] = 0;
        return GF_OK;
}
GF_Box *name_New()
{
        ISOM_DECL_BOX_ALLOC(GF_NameBox, GF_ISOM_BOX_TYPE_NAME);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err name_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_NameBox *ptr = (GF_NameBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        if (ptr->string) {
                gf_bs_write_data(bs, ptr->string, (u32) strlen(ptr->string) + 1);
        }
        return GF_OK;
}
GF_Err name_Size(GF_Box *s)
{
        GF_NameBox *ptr = (GF_NameBox *)s;
        if (ptr->string) ptr->size += strlen(ptr->string) + 1;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


void tssy_del(GF_Box *s)
{
        gf_free(s);
}
GF_Err tssy_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TimeStampSynchronyBox *ptr = (GF_TimeStampSynchronyBox *)s;
        gf_bs_read_int(bs, 6);
        ptr->timestamp_sync = gf_bs_read_int(bs, 2);
        return GF_OK;
}
GF_Box *tssy_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TimeStampSynchronyBox, GF_ISOM_BOX_TYPE_TSSY);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tssy_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TimeStampSynchronyBox *ptr = (GF_TimeStampSynchronyBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, 0, 6);
        gf_bs_write_int(bs, ptr->timestamp_sync, 2);
        return GF_OK;
}
GF_Err tssy_Size(GF_Box *s)
{
        s->size += 1;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


void srpp_del(GF_Box *s)
{
        GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s;
        if (ptr->info) gf_isom_box_del((GF_Box*)ptr->info);
        if (ptr->scheme_type) gf_isom_box_del((GF_Box*)ptr->scheme_type);
        gf_free(s);
}

GF_Err srpp_AddBox(GF_Box *s, GF_Box *a)
{
        GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_SCHI:
                if (ptr->info) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->info = (GF_SchemeInformationBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SCHM:
                if (ptr->scheme_type) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->scheme_type = (GF_SchemeTypeBox *)a;
                return GF_OK;
        }
        return gf_isom_box_add_default(s, a);
}

GF_Err srpp_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s;

        ISOM_DECREASE_SIZE(s, 16)
        ptr->encryption_algorithm_rtp = gf_bs_read_u32(bs);
        ptr->encryption_algorithm_rtcp = gf_bs_read_u32(bs);
        ptr->integrity_algorithm_rtp = gf_bs_read_u32(bs);
        ptr->integrity_algorithm_rtp = gf_bs_read_u32(bs);
        return gf_isom_box_array_read(s, bs, gf_isom_box_add_default);
}
GF_Box *srpp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SRTPProcessBox, GF_ISOM_BOX_TYPE_SRPP);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err srpp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->encryption_algorithm_rtp);
        gf_bs_write_u32(bs, ptr->encryption_algorithm_rtcp);
        gf_bs_write_u32(bs, ptr->integrity_algorithm_rtp);
        gf_bs_write_u32(bs, ptr->integrity_algorithm_rtcp);
        if (ptr->info) {
                e = gf_isom_box_write((GF_Box*)ptr->info, bs);
                if (e) return e;
        }
        if (ptr->scheme_type) {
                e = gf_isom_box_write((GF_Box*)ptr->scheme_type, bs);
                if (e) return e;
        }
        return GF_OK;
}
GF_Err srpp_Size(GF_Box *s)
{
        GF_Err e;
        GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s;

        s->size += 16;
        if (ptr->info) {
                e = gf_isom_box_size((GF_Box*)ptr->info);
                if (e) return e;
                ptr->size += ptr->info->size;
        }
        if (ptr->scheme_type) {
                e = gf_isom_box_size((GF_Box*)ptr->scheme_type);
                if (e) return e;
                ptr->size += ptr->scheme_type->size;
        }
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/



void rssr_del(GF_Box *s)
{
        gf_free(s);
}
GF_Err rssr_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_ReceivedSsrcBox *ptr = (GF_ReceivedSsrcBox *)s;
        ptr->ssrc = gf_bs_read_u32(bs);
        return GF_OK;
}
GF_Box *rssr_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ReceivedSsrcBox, GF_ISOM_BOX_TYPE_RSSR);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err rssr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_ReceivedSsrcBox *ptr = (GF_ReceivedSsrcBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->ssrc);
        return GF_OK;
}
GF_Err rssr_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/




void iods_del(GF_Box *s)
{
        GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s;
        if (ptr == NULL) return;
        if (ptr->descriptor) gf_odf_desc_del(ptr->descriptor);
        gf_free(ptr);
}


GF_Err iods_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 descSize;
        char *desc;
        GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s;

        //use the OD codec...
        descSize = (u32) (ptr->size);
        desc = (char*)gf_malloc(sizeof(char) * descSize);
        gf_bs_read_data(bs, desc, descSize);
        e = gf_odf_desc_read(desc, descSize, &ptr->descriptor);
        //OK, free our desc
        gf_free(desc);
        return e;
}

GF_Box *iods_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ObjectDescriptorBox, GF_ISOM_BOX_TYPE_IODS);
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err iods_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 descSize;
        char *desc;
        GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        //call our OD codec
        e = gf_odf_desc_write(ptr->descriptor, &desc, &descSize);
        if (e) return e;
        gf_bs_write_data(bs, desc, descSize);
        //and free our stuff maybe!!
        gf_free(desc);
        return GF_OK;
}

GF_Err iods_Size(GF_Box *s)
{
        GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s;

        ptr->size += gf_odf_desc_size(ptr->descriptor);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void mdat_del(GF_Box *s)
{
        GF_MediaDataBox *ptr = (GF_MediaDataBox *)s;
        if (!s) return;

        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}


GF_Err mdat_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MediaDataBox *ptr = (GF_MediaDataBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        ptr->dataSize = s->size;
        //then skip these bytes
        gf_bs_skip_bytes(bs, ptr->dataSize);
        return GF_OK;
}

GF_Box *mdat_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MediaDataBox, GF_ISOM_BOX_TYPE_MDAT);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mdat_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MediaDataBox *ptr = (GF_MediaDataBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        //make sure we have some data ...
        //if not, we handle that independantly (edit files)
        if (ptr->data) {
                gf_bs_write_data(bs, ptr->data, (u32) ptr->dataSize);
        }
        return GF_OK;
}

GF_Err mdat_Size(GF_Box *s)
{
        GF_MediaDataBox *ptr = (GF_MediaDataBox *)s;
        ptr->size += ptr->dataSize;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void mdhd_del(GF_Box *s)
{
        GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Err mdhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s;

        if (ptr->version == 1) {
                ptr->creationTime = gf_bs_read_u64(bs);
                ptr->modificationTime = gf_bs_read_u64(bs);
                ptr->timeScale = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u64(bs);
        } else {
                ptr->creationTime = gf_bs_read_u32(bs);
                ptr->modificationTime = gf_bs_read_u32(bs);
                ptr->timeScale = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u32(bs);
        }
        if (!ptr->timeScale) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Media header timescale is 0 - defaulting to 90000\n" ));
                ptr->timeScale = 90000;
        }

        ptr->original_duration = ptr->duration;

        //our padding bit
        gf_bs_read_int(bs, 1);
        //the spec is unclear here, just says "the value 0 is interpreted as undetermined"
        ptr->packedLanguage[0] = gf_bs_read_int(bs, 5);
        ptr->packedLanguage[1] = gf_bs_read_int(bs, 5);
        ptr->packedLanguage[2] = gf_bs_read_int(bs, 5);
        //but before or after compaction ?? We assume before
        if (ptr->packedLanguage[0] || ptr->packedLanguage[1] || ptr->packedLanguage[2]) {
                ptr->packedLanguage[0] += 0x60;
                ptr->packedLanguage[1] += 0x60;
                ptr->packedLanguage[2] += 0x60;
        } else {
                ptr->packedLanguage[0] = 'u';
                ptr->packedLanguage[1] = 'n';
                ptr->packedLanguage[2] = 'd';
        }
        ptr->reserved = gf_bs_read_u16(bs);
        return GF_OK;
}

GF_Box *mdhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MediaHeaderBox, GF_ISOM_BOX_TYPE_MDHD);

        tmp->packedLanguage[0] = 'u';
        tmp->packedLanguage[1] = 'n';
        tmp->packedLanguage[2] = 'd';
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mdhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        if (ptr->version == 1) {
                gf_bs_write_u64(bs, ptr->creationTime);
                gf_bs_write_u64(bs, ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->timeScale);
                gf_bs_write_u64(bs, ptr->duration);
        } else {
                gf_bs_write_u32(bs, (u32) ptr->creationTime);
                gf_bs_write_u32(bs, (u32) ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->timeScale);
                gf_bs_write_u32(bs, (u32) ptr->duration);
        }
        //SPECS: BIT(1) of padding
        gf_bs_write_int(bs, 0, 1);
        gf_bs_write_int(bs, ptr->packedLanguage[0] - 0x60, 5);
        gf_bs_write_int(bs, ptr->packedLanguage[1] - 0x60, 5);
        gf_bs_write_int(bs, ptr->packedLanguage[2] - 0x60, 5);
        gf_bs_write_u16(bs, ptr->reserved);
        return GF_OK;
}

GF_Err mdhd_Size(GF_Box *s)
{
        GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s;
        ptr->version = (ptr->duration>0xFFFFFFFF) ? 1 : 0;

        ptr->size += 4;
        ptr->size += (ptr->version == 1) ? 28 : 16;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void mdia_del(GF_Box *s)
{
        GF_MediaBox *ptr = (GF_MediaBox *)s;
        if (ptr == NULL) return;
        if (ptr->mediaHeader) gf_isom_box_del((GF_Box *)ptr->mediaHeader);
        if (ptr->information) gf_isom_box_del((GF_Box *)ptr->information);
        if (ptr->handler) gf_isom_box_del((GF_Box *)ptr->handler);
        gf_free(ptr);
}


GF_Err mdia_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MediaBox *ptr = (GF_MediaBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_MDHD:
                if (ptr->mediaHeader) ERROR_ON_DUPLICATED_BOX(a, ptr)

                        ptr->mediaHeader = (GF_MediaHeaderBox *)a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_HDLR:
                if (ptr->handler) ERROR_ON_DUPLICATED_BOX(a, ptr)

                        ptr->handler = (GF_HandlerBox *)a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_MINF:
                if (ptr->information) ERROR_ON_DUPLICATED_BOX(a, ptr)

                        ptr->information = (GF_MediaInformationBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err mdia_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e = gf_isom_box_array_read(s, bs, mdia_AddBox);
        if (e) return e;
        if (!((GF_MediaBox *)s)->information) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaInformationBox\n"));
                return GF_ISOM_INVALID_FILE;
        }
        if (!((GF_MediaBox *)s)->handler) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing HandlerBox\n"));
                return GF_ISOM_INVALID_FILE;
        }
        if (!((GF_MediaBox *)s)->mediaHeader) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaHeaderBox\n"));
                return GF_ISOM_INVALID_FILE;
        }
        return GF_OK;
}

GF_Box *mdia_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_MDIA);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mdia_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MediaBox *ptr = (GF_MediaBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        //Header first
        if (ptr->mediaHeader) {
                e = gf_isom_box_write((GF_Box *) ptr->mediaHeader, bs);
                if (e) return e;
        }
        //then handler
        if (ptr->handler) {
                e = gf_isom_box_write((GF_Box *) ptr->handler, bs);
                if (e) return e;
        }
        if (ptr->information) {
                e = gf_isom_box_write((GF_Box *) ptr->information, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err mdia_Size(GF_Box *s)
{
        GF_Err e;
        GF_MediaBox *ptr = (GF_MediaBox *)s;

        if (ptr->mediaHeader) {
                e = gf_isom_box_size((GF_Box *) ptr->mediaHeader);
                if (e) return e;
                ptr->size += ptr->mediaHeader->size;
        }
        if (ptr->handler) {
                e = gf_isom_box_size((GF_Box *) ptr->handler);
                if (e) return e;
                ptr->size += ptr->handler->size;
        }
        if (ptr->information) {
                e = gf_isom_box_size((GF_Box *) ptr->information);
                if (e) return e;
                ptr->size += ptr->information->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void mfra_del(GF_Box *s)
{
        GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s;
        if (ptr == NULL) return;
        if (ptr->mfro) gf_isom_box_del((GF_Box*)ptr->mfro);
        gf_isom_box_array_del(ptr->tfra_list);
        gf_free(ptr);
}

GF_Box *mfra_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieFragmentRandomAccessBox, GF_ISOM_BOX_TYPE_MFRA);
        tmp->tfra_list = gf_list_new();
        return (GF_Box *)tmp;
}

GF_Err mfra_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_TFRA:
                return gf_list_add(ptr->tfra_list, a);
        case GF_ISOM_BOX_TYPE_MFRO:
                if (ptr->mfro) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->mfro = (GF_MovieFragmentRandomAccessOffsetBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err mfra_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, mfra_AddBox);
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mfra_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s;

        e = gf_isom_box_array_write(s, ptr->tfra_list, bs);
        if (e) return e;
        if (ptr->mfro) {
                e = gf_isom_box_write((GF_Box *) ptr->mfro, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err mfra_Size(GF_Box *s)
{
        GF_Err e;
        GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s;

        if (ptr->mfro) {
                e = gf_isom_box_size((GF_Box *)ptr->mfro);
                if (e) return e;
                ptr->size += ptr->mfro->size;
        }
        return gf_isom_box_array_size(s, ptr->tfra_list);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void tfra_del(GF_Box *s)
{
        GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s;
        if (ptr == NULL) return;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}

GF_Box *tfra_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackFragmentRandomAccessBox, GF_ISOM_BOX_TYPE_TFRA);
        return (GF_Box *)tmp;
}

GF_Err tfra_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_RandomAccessEntry *p = 0;
        GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s;

        if (ptr->size<12) return GF_ISOM_INVALID_FILE;

        ptr->track_id = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (gf_bs_read_int(bs, 26) !=0) return GF_ISOM_INVALID_FILE;
        ptr->traf_bits = (gf_bs_read_int(bs, 2)+1)*8;
        ptr->trun_bits = (gf_bs_read_int(bs, 2)+1)*8;
        ptr->sample_bits = (gf_bs_read_int(bs, 2)+1)*8;
        ISOM_DECREASE_SIZE(ptr, 4);

        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->version==1) {
                if (ptr->nb_entries > ptr->size / (16+(ptr->traf_bits+ptr->trun_bits+ptr->sample_bits)/8)) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in traf\n", ptr->nb_entries));
                        return GF_ISOM_INVALID_FILE;
                }
        } else {
                if (ptr->nb_entries > ptr->size / (8+(ptr->traf_bits+ptr->trun_bits+ptr->sample_bits)/8)) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in traf\n", ptr->nb_entries));
                        return GF_ISOM_INVALID_FILE;
                }
        }

        if (ptr->nb_entries)
        {
                p = (GF_RandomAccessEntry *) gf_malloc(sizeof(GF_RandomAccessEntry) * ptr->nb_entries);
                if (!p) return GF_OUT_OF_MEM;
        }

        ptr->entries = p;

        for (i=0; i<ptr->nb_entries; i++) {
                memset(p, 0, sizeof(GF_RandomAccessEntry));

                if (ptr->version==1) {
                        p->time = gf_bs_read_u64(bs);
                        p->moof_offset = gf_bs_read_u64(bs);
                }
                else
                {
                        p->time = gf_bs_read_u32(bs);
                        p->moof_offset = gf_bs_read_u32(bs);
                }
                p->traf_number = gf_bs_read_int(bs, ptr->traf_bits);
                p->trun_number = gf_bs_read_int(bs, ptr->trun_bits);
                p->sample_number = gf_bs_read_int(bs, ptr->sample_bits);

                ++p;
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err tfra_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->track_id);
        gf_bs_write_int(bs, 0, 26);

        gf_bs_write_int(bs, ptr->traf_bits/8 - 1, 2);
        gf_bs_write_int(bs, ptr->trun_bits/8 - 1, 2);
        gf_bs_write_int(bs, ptr->sample_bits/8 - 1, 2);

        gf_bs_write_u32(bs, ptr->nb_entries);

        for (i=0; i<ptr->nb_entries; i++) {
                GF_RandomAccessEntry *p = &ptr->entries[i];;
                if (ptr->version==1) {
                        gf_bs_write_u64(bs, p->time);
                        gf_bs_write_u64(bs, p->moof_offset);
                } else {
                        gf_bs_write_u32(bs, (u32) p->time);
                        gf_bs_write_u32(bs, (u32) p->moof_offset);
                }
                gf_bs_write_int(bs, p->traf_number, ptr->traf_bits);
                gf_bs_write_int(bs, p->trun_number, ptr->trun_bits);
                gf_bs_write_int(bs, p->sample_number, ptr->sample_bits);
        }
        return GF_OK;
}

GF_Err tfra_Size(GF_Box *s)
{
        GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s;

        ptr->size += 12;

        ptr->size += ptr->nb_entries * ( ((ptr->version==1) ? 16 : 8 ) + ptr->traf_bits + ptr->trun_bits + ptr->sample_bits);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void mfro_del(GF_Box *s)
{
        GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Box *mfro_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieFragmentRandomAccessOffsetBox, GF_ISOM_BOX_TYPE_MFRO);
        return (GF_Box *)tmp;
}

GF_Err mfro_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s;

        ptr->container_size = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mfro_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->container_size);
        return GF_OK;
}

GF_Err mfro_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void elng_del(GF_Box *s)
{
        GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s;
        if (ptr == NULL) return;
        if (ptr->extended_language) gf_free(ptr->extended_language);
        gf_free(ptr);
}

GF_Err elng_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s;

        if (ptr->size) {
                ptr->extended_language = (char*)gf_malloc((u32) ptr->size);
                if (ptr->extended_language == NULL) return GF_OUT_OF_MEM;
                gf_bs_read_data(bs, ptr->extended_language, (u32) ptr->size);
                /*safety check in case the string is not null-terminated*/
                if (ptr->extended_language[ptr->size-1]) {
                        char *str = (char*)gf_malloc((u32) ptr->size + 1);
                        memcpy(str, ptr->extended_language, (u32) ptr->size);
                        str[ptr->size] = 0;
                        gf_free(ptr->extended_language);
                        ptr->extended_language = str;
                }
        }
        return GF_OK;
}

GF_Box *elng_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_ELNG);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err elng_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        if (ptr->extended_language) {
                gf_bs_write_data(bs, ptr->extended_language, (u32)(strlen(ptr->extended_language)+1));
        }
        return GF_OK;
}

GF_Err elng_Size(GF_Box *s)
{
        GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s;

        if (ptr->extended_language) {
                ptr->size += strlen(ptr->extended_language)+1;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void mfhd_del(GF_Box *s)
{
        GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Err mfhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *)s;
        ptr->sequence_number = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *mfhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieFragmentHeaderBox, GF_ISOM_BOX_TYPE_MFHD);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err mfhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->sequence_number);
        return GF_OK;
}

GF_Err mfhd_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


void minf_del(GF_Box *s)
{
        GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
        if (ptr == NULL) return;

        //if we have a Handler not self-contained, delete it (the self-contained belongs to the movie)
        if (ptr->dataHandler) {
                gf_isom_datamap_close(ptr);
        }
        if (ptr->InfoHeader) gf_isom_box_del((GF_Box *)ptr->InfoHeader);
        if (ptr->dataInformation) gf_isom_box_del((GF_Box *)ptr->dataInformation);
        if (ptr->sampleTable) gf_isom_box_del((GF_Box *)ptr->sampleTable);
        gf_free(ptr);
}

GF_Err minf_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_NMHD:
        case GF_ISOM_BOX_TYPE_STHD:
        case GF_ISOM_BOX_TYPE_VMHD:
        case GF_ISOM_BOX_TYPE_SMHD:
        case GF_ISOM_BOX_TYPE_HMHD:
        case GF_ISOM_BOX_TYPE_GMHD:
                if (ptr->InfoHeader) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->InfoHeader = a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_DINF:
                if (ptr->dataInformation) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->dataInformation = (GF_DataInformationBox *)a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_STBL:
                if (ptr->sampleTable ) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->sampleTable = (GF_SampleTableBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err minf_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
        GF_Err e;
        e = gf_isom_box_array_read(s, bs, minf_AddBox);
        if (! ptr->dataInformation) {
                GF_Box *dinf, *dref, *url;
                Bool dump_mode = GF_FALSE;
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing DataInformationBox\n"));
                //commented on purpose, we are still able to handle the file, we only throw an error but keep processing
//              e = GF_ISOM_INVALID_FILE;

                //add a dinf box to avoid any access to a null dinf
                dinf = gf_isom_box_new(GF_ISOM_BOX_TYPE_DINF);
                if (!dinf) return GF_OUT_OF_MEM;
                if (ptr->InfoHeader && gf_list_find(ptr->other_boxes, ptr->InfoHeader)>=0) dump_mode = GF_TRUE;
                if (ptr->sampleTable && gf_list_find(ptr->other_boxes, ptr->sampleTable)>=0) dump_mode = GF_TRUE;

                ptr->dataInformation = (GF_DataInformationBox *)dinf;

                dref = gf_isom_box_new(GF_ISOM_BOX_TYPE_DREF);
                if (!dref) return GF_OUT_OF_MEM;
                e = dinf_AddBox(dinf, dref);

                url = gf_isom_box_new(GF_ISOM_BOX_TYPE_URL);
                if (!url) return GF_OUT_OF_MEM;
                ((GF_FullBox*)url)->flags = 1;
                e = gf_isom_box_add_default(dref, url);

                if (dump_mode) {
                        gf_list_add(ptr->other_boxes, ptr->dataInformation);
                        if (!dinf->other_boxes) dinf->other_boxes = gf_list_new();
                        gf_list_add(dinf->other_boxes, dref);
                }
        }
        return e;
}

GF_Box *minf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MediaInformationBox, GF_ISOM_BOX_TYPE_MINF);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err minf_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        //Header first
        if (ptr->InfoHeader) {
                e = gf_isom_box_write((GF_Box *) ptr->InfoHeader, bs);
                if (e) return e;
        }
        //then dataInfo
        if (ptr->dataInformation) {
                e = gf_isom_box_write((GF_Box *) ptr->dataInformation, bs);
                if (e) return e;
        }
        //then sampleTable
        if (ptr->sampleTable) {
                e = gf_isom_box_write((GF_Box *) ptr->sampleTable, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err minf_Size(GF_Box *s)
{
        GF_Err e;
        GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;

        if (ptr->InfoHeader) {
                e = gf_isom_box_size((GF_Box *) ptr->InfoHeader);
                if (e) return e;
                ptr->size += ptr->InfoHeader->size;
        }
        if (ptr->dataInformation) {
                e = gf_isom_box_size((GF_Box *) ptr->dataInformation);
                if (e) return e;
                ptr->size += ptr->dataInformation->size;
        }
        if (ptr->sampleTable) {
                e = gf_isom_box_size((GF_Box *) ptr->sampleTable);
                if (e) return e;
                ptr->size += ptr->sampleTable->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void moof_del(GF_Box *s)
{
        GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s;
        if (ptr == NULL) return;

        if (ptr->mfhd) gf_isom_box_del((GF_Box *) ptr->mfhd);
        gf_isom_box_array_del(ptr->TrackList);
        if (ptr->mdat) gf_free(ptr->mdat);
        gf_free(ptr);
}

GF_Err moof_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_MFHD:
                if (ptr->mfhd) ERROR_ON_DUPLICATED_BOX(a, ptr)

                        ptr->mfhd = (GF_MovieFragmentHeaderBox *) a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_TRAF:
                return gf_list_add(ptr->TrackList, a);
        case GF_ISOM_BOX_TYPE_PSSH:
        default:
                return gf_isom_box_add_default(s, a);
        }
}

GF_Err moof_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, moof_AddBox);
}

GF_Box *moof_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieFragmentBox, GF_ISOM_BOX_TYPE_MOOF);
        tmp->TrackList = gf_list_new();
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err moof_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        //Header First
        if (ptr->mfhd) {
                e = gf_isom_box_write((GF_Box *) ptr->mfhd, bs);
                if (e) return e;
        }
//then the track list
return gf_isom_box_array_write(s, ptr->TrackList, bs);
}

GF_Err moof_Size(GF_Box *s)
{
        GF_Err e;
        GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s;

        if (ptr->mfhd) {
                e = gf_isom_box_size((GF_Box *)ptr->mfhd);
                if (e) return e;
                ptr->size += ptr->mfhd->size;
        }
        return gf_isom_box_array_size(s, ptr->TrackList);
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/

void moov_del(GF_Box *s)
{
        GF_MovieBox *ptr = (GF_MovieBox *)s;
        if (ptr == NULL) return;

        if (ptr->mvhd) gf_isom_box_del((GF_Box *)ptr->mvhd);
        if (ptr->meta) gf_isom_box_del((GF_Box *)ptr->meta);
        if (ptr->iods) gf_isom_box_del((GF_Box *)ptr->iods);
        if (ptr->udta) gf_isom_box_del((GF_Box *)ptr->udta);
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
        if (ptr->mvex) gf_isom_box_del((GF_Box *)ptr->mvex);
#endif

        gf_isom_box_array_del(ptr->trackList);
        gf_free(ptr);
}


GF_Err moov_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MovieBox *ptr = (GF_MovieBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_IODS:
                if (ptr->iods) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->iods = (GF_ObjectDescriptorBox *)a;
                //if no IOD, delete the box
                if (!ptr->iods->descriptor) {
                        ptr->iods = NULL;
                        gf_isom_box_del(a);
                }
                return GF_OK;

        case GF_ISOM_BOX_TYPE_MVHD:
                if (ptr->mvhd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->mvhd = (GF_MovieHeaderBox *)a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_UDTA:
                if (ptr->udta) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->udta = (GF_UserDataBox *)a;
                return GF_OK;

#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
        case GF_ISOM_BOX_TYPE_MVEX:
                if (ptr->mvex) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->mvex = (GF_MovieExtendsBox *)a;
                ptr->mvex->mov = ptr->mov;
                return GF_OK;
#endif

        case GF_ISOM_BOX_TYPE_META:
                if (ptr->meta) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->meta = (GF_MetaBox *)a;
                return GF_OK;

        case GF_ISOM_BOX_TYPE_TRAK:
                //set our pointer to this obj
                ((GF_TrackBox *)a)->moov = ptr;
                return gf_list_add(ptr->trackList, a);
        case GF_ISOM_BOX_TYPE_PSSH:
        default:
                return gf_isom_box_add_default(s, a);
        }
}


GF_Err moov_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        e = gf_isom_box_array_read(s, bs, moov_AddBox);
        if (e) {
                return e;
        }
        else {
                if (!((GF_MovieBox *)s)->mvhd) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MovieHeaderBox\n"));
                        return GF_ISOM_INVALID_FILE;
                }
        }
        return e;
}

GF_Box *moov_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieBox, GF_ISOM_BOX_TYPE_MOOV);
        tmp->trackList = gf_list_new();
        if (!tmp->trackList) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err moov_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieBox *ptr = (GF_MovieBox *)s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        if (ptr->mvhd) {
                e = gf_isom_box_write((GF_Box *) ptr->mvhd, bs);
                if (e) return e;
        }
        if (ptr->iods) {
                e = gf_isom_box_write((GF_Box *) ptr->iods, bs);
                if (e) return e;
        }
        if (ptr->meta) {
                e = gf_isom_box_write((GF_Box *) ptr->meta, bs);
                if (e) return e;
        }
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
        if (ptr->mvex) {
                e = gf_isom_box_write((GF_Box *) ptr->mvex, bs);
                if (e) return e;
        }
#endif

        e = gf_isom_box_array_write(s, ptr->trackList, bs);
        if (e) return e;

        if (ptr->udta) {
                e = gf_isom_box_write((GF_Box *) ptr->udta, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err moov_Size(GF_Box *s)
{
        GF_Err e;
        GF_MovieBox *ptr = (GF_MovieBox *)s;

        if (ptr->mvhd) {
                e = gf_isom_box_size((GF_Box *) ptr->mvhd);
                if (e) return e;
                ptr->size += ptr->mvhd->size;
        }
        if (ptr->iods) {
                e = gf_isom_box_size((GF_Box *) ptr->iods);
                if (e) return e;
                ptr->size += ptr->iods->size;
        }
        if (ptr->udta) {
                e = gf_isom_box_size((GF_Box *) ptr->udta);
                if (e) return e;
                ptr->size += ptr->udta->size;
        }
        if (ptr->meta) {
                e = gf_isom_box_size((GF_Box *) ptr->meta);
                if (e) return e;
                ptr->size += ptr->meta->size;
        }
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
        if (ptr->mvex) {
                e = gf_isom_box_size((GF_Box *) ptr->mvex);
                if (e) return e;
                ptr->size += ptr->mvex->size;
        }
#endif

        return gf_isom_box_array_size(s, ptr->trackList);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void audio_sample_entry_del(GF_Box *s)
{
        GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;
        if (ptr == NULL) return;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

        if (ptr->esd) gf_isom_box_del((GF_Box *)ptr->esd);
        if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
        if (ptr->cfg_ac3) gf_isom_box_del((GF_Box *)ptr->cfg_ac3);
        if (ptr->cfg_3gpp) gf_isom_box_del((GF_Box *)ptr->cfg_3gpp);
        gf_free(ptr);
}

GF_Err audio_sample_entry_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_ESDS:
                if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->esd = (GF_ESDBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_SINF:
                gf_list_add(ptr->protections, a);
                break;
        case GF_ISOM_BOX_TYPE_DAMR:
        case GF_ISOM_BOX_TYPE_DEVC:
        case GF_ISOM_BOX_TYPE_DQCP:
        case GF_ISOM_BOX_TYPE_DSMV:
                ptr->cfg_3gpp = (GF_3GPPConfigBox *) a;
                /*for 3GP config, remember sample entry type in config*/
                ptr->cfg_3gpp->cfg.type = ptr->type;
                break;

        case GF_ISOM_BOX_TYPE_DAC3:
                ptr->cfg_ac3 = (GF_AC3ConfigBox *) a;
                break;
        case GF_ISOM_BOX_TYPE_DEC3:
                ptr->cfg_ac3 = (GF_AC3ConfigBox *) a;
                break;

        case GF_ISOM_BOX_TYPE_UNKNOWN:
                if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        /*HACK for QT files: get the esds box from the track*/
                {
                        GF_UnknownBox *wave = (GF_UnknownBox *)a;
                        if (wave->original_4cc == GF_4CC('w','a','v','e')) {
                                u32 offset = 0;
                                while ((wave->data[offset + 4] != 'e') && (wave->data[offset + 5] != 's')) {
                                        offset++;
                                        if (offset == wave->dataSize) break;
                                }
                                if (offset < wave->dataSize) {
                                        GF_Box *a;
                                        GF_Err e;
                                        GF_BitStream *bs = gf_bs_new(wave->data + offset, wave->dataSize - offset, GF_BITSTREAM_READ);
                                        e = gf_isom_box_parse(&a, bs);
                                        gf_bs_del(bs);
                                        if (e) return e;
                                        ptr->esd = (GF_ESDBox *)a;
                                        gf_isom_box_add_for_dump_mode((GF_Box *)ptr, a);

                                }
                        }
                        else {
                                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Cannot process box %s\n!", gf_4cc_to_str(a->type)));
                        }
                        gf_isom_box_del(a);
                        return GF_ISOM_INVALID_MEDIA;
                }
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}
GF_Err audio_sample_entry_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MPEGAudioSampleEntryBox *ptr;
        char *data;
        u32 i, size;
        GF_Err e;
        u64 pos;

        e = gf_isom_audio_sample_entry_read((GF_AudioSampleEntryBox*)s, bs);
        if (e) return e;
        pos = gf_bs_get_position(bs);
        size = (u32) s->size;

        e = gf_isom_box_array_read(s, bs, audio_sample_entry_AddBox);
        if (!e) return GF_OK;
        if (size<8) return GF_ISOM_INVALID_FILE;

        /*hack for some weird files (possibly recorded with live.com tools, needs further investigations)*/
        ptr = (GF_MPEGAudioSampleEntryBox *)s;
        gf_bs_seek(bs, pos);
        data = (char*)gf_malloc(sizeof(char) * size);
        gf_bs_read_data(bs, data, size);
        for (i=0; i<size-8; i++) {
                if (GF_4CC(data[i+4], data[i+5], data[i+6], data[i+7]) == GF_ISOM_BOX_TYPE_ESDS) {
                        GF_BitStream *mybs = gf_bs_new(data + i, size - i, GF_BITSTREAM_READ);
                        e = gf_isom_box_parse((GF_Box **)&ptr->esd, mybs);
                        gf_bs_del(mybs);
                        break;
                }
        }
        gf_free(data);
        return e;
}

GF_Box *audio_sample_entry_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MPEGAudioSampleEntryBox, GF_ISOM_BOX_TYPE_MP4A);
        gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}

GF_Box *enca_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MPEGAudioSampleEntryBox, GF_ISOM_BOX_TYPE_ENCA);
        gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err audio_sample_entry_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_isom_audio_sample_entry_write((GF_AudioSampleEntryBox*)s, bs);
        if (ptr->esd) {
                e = gf_isom_box_write((GF_Box *)ptr->esd, bs);
                if (e) return e;
        }
        if (ptr->cfg_3gpp) {
                e = gf_isom_box_write((GF_Box *)ptr->cfg_3gpp, bs);
                if (e) return e;
        }
        if (ptr->cfg_ac3) {
                e = gf_isom_box_write((GF_Box *)ptr->cfg_ac3, bs);
                if (e) return e;
        }
        return gf_isom_box_array_write(s, ptr->protections, bs);
}

GF_Err audio_sample_entry_Size(GF_Box *s)
{
        GF_Err e;
        GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;

        gf_isom_audio_sample_entry_size((GF_AudioSampleEntryBox*)s);
        if (ptr->esd) {
                e = gf_isom_box_size((GF_Box *)ptr->esd);
                if (e) return e;
                ptr->size += ptr->esd->size;
        }
        if (ptr->cfg_3gpp) {
                e = gf_isom_box_size((GF_Box *)ptr->cfg_3gpp);
                if (e) return e;
                ptr->size += ptr->cfg_3gpp->size;
        }
        if (ptr->cfg_ac3) {
                e = gf_isom_box_size((GF_Box *)ptr->cfg_ac3);
                if (e) return e;
                ptr->size += ptr->cfg_ac3->size;
        }
        return gf_isom_box_array_size(s, ptr->protections);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void mp4s_del(GF_Box *s)
{
        GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;
        if (ptr == NULL) return;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

        if (ptr->esd) gf_isom_box_del((GF_Box *)ptr->esd);
        if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
        gf_free(ptr);
}

GF_Err mp4s_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_ESDS:
                if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->esd = (GF_ESDBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_SINF:
                gf_list_add(ptr->protections, a);
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err mp4s_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;

        e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
        if (e) return e;

        ISOM_DECREASE_SIZE(ptr, 8);
        return gf_isom_box_array_read(s, bs, mp4s_AddBox);
}

GF_Box *mp4s_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MPEGSampleEntryBox, GF_ISOM_BOX_TYPE_MP4S);
        gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}

GF_Box *encs_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MPEGSampleEntryBox, GF_ISOM_BOX_TYPE_ENCS);
        gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mp4s_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_data(bs, ptr->reserved, 6);
        gf_bs_write_u16(bs, ptr->dataReferenceIndex);
        e = gf_isom_box_write((GF_Box *)ptr->esd, bs);
        if (e) return e;
        return gf_isom_box_array_write(s, ptr->protections, bs);
}

GF_Err mp4s_Size(GF_Box *s)
{
        GF_Err e;
        GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;

        ptr->size += 8;
        e = gf_isom_box_size((GF_Box *)ptr->esd);
        if (e) return e;
        ptr->size += ptr->esd->size;
        return gf_isom_box_array_size(s, ptr->protections);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void video_sample_entry_del(GF_Box *s)
{
        GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;
        if (ptr == NULL) return;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

        if (ptr->esd) gf_isom_box_del((GF_Box *)ptr->esd);
        if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
        /*for publishing*/
        if (ptr->emul_esd) gf_odf_desc_del((GF_Descriptor *)ptr->emul_esd);

        if (ptr->avc_config) gf_isom_box_del((GF_Box *) ptr->avc_config);
        if (ptr->svc_config) gf_isom_box_del((GF_Box *) ptr->svc_config);
        if (ptr->mvc_config) gf_isom_box_del((GF_Box *) ptr->mvc_config);
        if (ptr->hevc_config) gf_isom_box_del((GF_Box *) ptr->hevc_config);
        if (ptr->lhvc_config) gf_isom_box_del((GF_Box *) ptr->lhvc_config);
        if (ptr->cfg_3gpp) gf_isom_box_del((GF_Box *)ptr->cfg_3gpp);

        if (ptr->descr) gf_isom_box_del((GF_Box *) ptr->descr);
        if (ptr->ipod_ext) gf_isom_box_del((GF_Box *)ptr->ipod_ext);

        if (ptr->pasp) gf_isom_box_del((GF_Box *)ptr->pasp);
        if (ptr->clap) gf_isom_box_del((GF_Box *)ptr->clap);
        if (ptr->rinf) gf_isom_box_del((GF_Box *)ptr->rinf);

        if (ptr->rvcc) gf_isom_box_del((GF_Box *)ptr->rvcc);

        gf_free(ptr);
}

GF_Err video_sample_entry_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_ESDS:
                if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->esd = (GF_ESDBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_SINF:
                gf_list_add(ptr->protections, a);
                break;
        case GF_ISOM_BOX_TYPE_RINF:
                if (ptr->rinf) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->rinf = (GF_RestrictedSchemeInfoBox *) a;
                break;
        case GF_ISOM_BOX_TYPE_AVCC:
                if (ptr->avc_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->avc_config = (GF_AVCConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_HVCC:
                if (ptr->hevc_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->hevc_config = (GF_HEVCConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_SVCC:
                if (ptr->svc_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->svc_config = (GF_AVCConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_MVCC:
                if (ptr->mvc_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->mvc_config = (GF_AVCConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_LHVC:
                if (ptr->lhvc_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->lhvc_config = (GF_HEVCConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_M4DS:
                if (ptr->descr) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->descr = (GF_MPEG4ExtensionDescriptorsBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_UUID:
                if (! memcmp(((GF_UnknownUUIDBox*)a)->uuid, GF_ISOM_IPOD_EXT, 16)) {
                        if (ptr->ipod_ext) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->ipod_ext = (GF_UnknownUUIDBox *)a;
                } else {
                        return gf_isom_box_add_default(s, a);
                }
                break;
        case GF_ISOM_BOX_TYPE_D263:
                ptr->cfg_3gpp = (GF_3GPPConfigBox *)a;
                /*for 3GP config, remember sample entry type in config*/
                ptr->cfg_3gpp->cfg.type = ptr->type;
                break;
                break;

        case GF_ISOM_BOX_TYPE_PASP:
                if (ptr->pasp) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->pasp = (GF_PixelAspectRatioBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_CLAP:
                if (ptr->clap) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->clap = (GF_CleanAppertureBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_RVCC:
                if (ptr->rvcc) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->rvcc = (GF_RVCConfigurationBox *)a;
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err video_sample_entry_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MPEGVisualSampleEntryBox *mp4v = (GF_MPEGVisualSampleEntryBox*)s;
        GF_Err e;
        e = gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *)s, bs);
        if (e) return e;
        e = gf_isom_box_array_read(s, bs, video_sample_entry_AddBox);
        if (e) return e;
        /*this is an AVC sample desc*/
        if (mp4v->avc_config || mp4v->svc_config || mp4v->mvc_config) AVC_RewriteESDescriptor(mp4v);
        /*this is an HEVC sample desc*/
        if (mp4v->hevc_config || mp4v->lhvc_config || (mp4v->type==GF_ISOM_BOX_TYPE_HVT1))
                HEVC_RewriteESDescriptor(mp4v);
        return GF_OK;
}

GF_Box *video_sample_entry_New()
{
        GF_MPEGVisualSampleEntryBox *tmp;
        GF_SAFEALLOC(tmp, GF_MPEGVisualSampleEntryBox);
        if (tmp == NULL) return NULL;

        gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox *)tmp);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err video_sample_entry_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)s, bs);

        /*mp4v*/
        if (ptr->esd) {
                e = gf_isom_box_write((GF_Box *)ptr->esd, bs);
                if (e) return e;
        }
        /*mp4v*/
        else if (ptr->cfg_3gpp) {
                e = gf_isom_box_write((GF_Box *)ptr->cfg_3gpp, bs);
                if (e) return e;
        }
        /*avc or hevc*/
        else {
                if (ptr->avc_config && ptr->avc_config->config) {
                        e = gf_isom_box_write((GF_Box *) ptr->avc_config, bs);
                        if (e) return e;
                }
                if (ptr->hevc_config && ptr->hevc_config->config) {
                        e = gf_isom_box_write((GF_Box *) ptr->hevc_config, bs);
                        if (e) return e;
                }
                if (ptr->ipod_ext)      {
                        e = gf_isom_box_write((GF_Box *) ptr->ipod_ext, bs);
                        if (e) return e;
                }
                if (ptr->descr) {
                        e = gf_isom_box_write((GF_Box *) ptr->descr, bs);
                        if (e) return e;
                }
                if (ptr->svc_config && ptr->svc_config->config) {
                        e = gf_isom_box_write((GF_Box *) ptr->svc_config, bs);
                        if (e) return e;
                }
                if (ptr->mvc_config && ptr->mvc_config->config) {
                        e = gf_isom_box_write((GF_Box *) ptr->mvc_config, bs);
                        if (e) return e;
                }
                if (ptr->lhvc_config && ptr->lhvc_config->config) {
                        e = gf_isom_box_write((GF_Box *) ptr->lhvc_config, bs);
                        if (e) return e;
                }
        }
        if (ptr->pasp) {
                e = gf_isom_box_write((GF_Box *)ptr->pasp, bs);
                if (e) return e;
        }
        if (ptr->clap) {
                e = gf_isom_box_write((GF_Box *)ptr->clap, bs);
                if (e) return e;
        }
        if (ptr->rvcc) {
                e = gf_isom_box_write((GF_Box *)ptr->rvcc, bs);
                if (e) return e;
        }
        if (ptr->rinf) {
                e = gf_isom_box_write((GF_Box *)ptr->rinf, bs);
                if (e) return e;
        }
        return gf_isom_box_array_write(s, ptr->protections, bs);
}

GF_Err video_sample_entry_Size(GF_Box *s)
{
        GF_Err e;
        GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;

        gf_isom_video_sample_entry_size((GF_VisualSampleEntryBox *)s);

        if (ptr->esd) {
                e = gf_isom_box_size((GF_Box *)ptr->esd);
                if (e) return e;
                ptr->size += ptr->esd->size;
        } else if (ptr->cfg_3gpp) {
                e = gf_isom_box_size((GF_Box *)ptr->cfg_3gpp);
                if (e) return e;
                ptr->size += ptr->cfg_3gpp->size;
        } else {
                if (!ptr->avc_config && !ptr->svc_config && !ptr->hevc_config && !ptr->lhvc_config && (ptr->type!=GF_ISOM_BOX_TYPE_HVT1) ) {
                        return GF_ISOM_INVALID_FILE;
                }

                if (ptr->hevc_config && ptr->hevc_config->config) {
                        e = gf_isom_box_size((GF_Box *)ptr->hevc_config);
                        if (e) return e;
                        ptr->size += ptr->hevc_config->size;
                }

                if (ptr->avc_config && ptr->avc_config->config) {
                        e = gf_isom_box_size((GF_Box *) ptr->avc_config);
                        if (e) return e;
                        ptr->size += ptr->avc_config->size;
                }

                if (ptr->svc_config && ptr->svc_config->config) {
                        e = gf_isom_box_size((GF_Box *) ptr->svc_config);
                        if (e) return e;
                        ptr->size += ptr->svc_config->size;
                }

                if (ptr->mvc_config && ptr->mvc_config->config) {
                        e = gf_isom_box_size((GF_Box *) ptr->mvc_config);
                        if (e) return e;
                        ptr->size += ptr->mvc_config->size;
                }

                if (ptr->lhvc_config && ptr->lhvc_config->config) {
                        e = gf_isom_box_size((GF_Box *) ptr->lhvc_config);
                        if (e) return e;
                        ptr->size += ptr->lhvc_config->size;
                }

                if (ptr->ipod_ext) {
                        e = gf_isom_box_size((GF_Box *) ptr->ipod_ext);
                        if (e) return e;
                        ptr->size += ptr->ipod_ext->size;
                }
                if (ptr->descr) {
                        e = gf_isom_box_size((GF_Box *) ptr->descr);
                        if (e) return e;
                        ptr->size += ptr->descr->size;
                }
        }
        if (ptr->pasp) {
                e = gf_isom_box_size((GF_Box *)ptr->pasp);
                if (e) return e;
                ptr->size += ptr->pasp->size;
        }
        if (ptr->clap) {
                e = gf_isom_box_size((GF_Box *)ptr->clap);
                if (e) return e;
                ptr->size += ptr->clap->size;
        }
        if (ptr->rvcc) {
                e = gf_isom_box_size((GF_Box *)ptr->rvcc);
                if (e) return e;
                ptr->size += ptr->rvcc->size;
        }
        if (ptr->rinf) {
                e = gf_isom_box_size((GF_Box *)ptr->rinf);
                if (e) return e;
                ptr->size += ptr->rinf->size;
        }
        return gf_isom_box_array_size(s, ptr->protections);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void mvex_del(GF_Box *s)
{
        GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s;
        if (ptr == NULL) return;
        if (ptr->mehd) gf_isom_box_del((GF_Box*)ptr->mehd);
        gf_isom_box_array_del(ptr->TrackExList);
        gf_isom_box_array_del(ptr->TrackExPropList);
        gf_free(ptr);
}


GF_Err mvex_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s;

        switch (a->type) {
        case GF_ISOM_BOX_TYPE_TREX:
                return gf_list_add(ptr->TrackExList, a);
        case GF_ISOM_BOX_TYPE_TREP:
                return gf_list_add(ptr->TrackExPropList, a);
        case GF_ISOM_BOX_TYPE_MEHD:
                if (ptr->mehd) break;
                ptr->mehd = (GF_MovieExtendsHeaderBox*)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}



GF_Err mvex_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, mvex_AddBox);
}

GF_Box *mvex_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieExtendsBox, GF_ISOM_BOX_TYPE_MVEX);
        tmp->TrackExList = gf_list_new();
        if (!tmp->TrackExList) {
                gf_free(tmp);
                return NULL;
        }
        tmp->TrackExPropList = gf_list_new();
        if (!tmp->TrackExPropList) {
                gf_list_del(tmp->TrackExList);
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err mvex_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        if (ptr->mehd) {
                e = gf_isom_box_write((GF_Box *)ptr->mehd, bs);
                if (e) return e;
        }
        e = gf_isom_box_array_write(s, ptr->TrackExList, bs);
        if (e) return e;
        return gf_isom_box_array_write(s, ptr->TrackExPropList, bs);
}

GF_Err mvex_Size(GF_Box *s)
{
        GF_Err e;
        GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s;

        if (ptr->mehd) {
                e = gf_isom_box_size((GF_Box *)ptr->mehd);
                if (e) return e;
                ptr->size += ptr->mehd->size;
        }
        e = gf_isom_box_array_size(s, ptr->TrackExList);
        if (e) return e;
        return gf_isom_box_array_size(s, ptr->TrackExPropList);
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Box *mehd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieExtendsHeaderBox, GF_ISOM_BOX_TYPE_MEHD);
        return (GF_Box *)tmp;
}
void mehd_del(GF_Box *s)
{
        gf_free(s);
}
GF_Err mehd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s;

        if (ptr->version==1) {
                ptr->fragment_duration = gf_bs_read_u64(bs);
        } else {
                ptr->fragment_duration = (u64) gf_bs_read_u32(bs);
        }
        return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err mehd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s;
        GF_Err e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        if (ptr->version == 1) {
                gf_bs_write_u64(bs, ptr->fragment_duration);
        } else {
                gf_bs_write_u32(bs, (u32) ptr->fragment_duration);
        }
        return GF_OK;
}
GF_Err mehd_Size(GF_Box *s)
{
        GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s;
        ptr->version = (ptr->fragment_duration>0xFFFFFFFF) ? 1 : 0;
        s->size += (ptr->version == 1) ? 8 : 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


void mvhd_del(GF_Box *s)
{
        GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err mvhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        if (ptr->version == 1) {
                ptr->creationTime = gf_bs_read_u64(bs);
                ptr->modificationTime = gf_bs_read_u64(bs);
                ptr->timeScale = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u64(bs);
        } else {
                ptr->creationTime = gf_bs_read_u32(bs);
                ptr->modificationTime = gf_bs_read_u32(bs);
                ptr->timeScale = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u32(bs);
        }
        if (!ptr->timeScale) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Movie header timescale is invalid (0) - defaulting to 600\n" ));
                ptr->timeScale = 600;
        }
        ptr->preferredRate = gf_bs_read_u32(bs);
        ptr->preferredVolume = gf_bs_read_u16(bs);
        gf_bs_read_data(bs, ptr->reserved, 10);
        ptr->matrixA = gf_bs_read_u32(bs);
        ptr->matrixB = gf_bs_read_u32(bs);
        ptr->matrixU = gf_bs_read_u32(bs);
        ptr->matrixC = gf_bs_read_u32(bs);
        ptr->matrixD = gf_bs_read_u32(bs);
        ptr->matrixV = gf_bs_read_u32(bs);
        ptr->matrixX = gf_bs_read_u32(bs);
        ptr->matrixY = gf_bs_read_u32(bs);
        ptr->matrixW = gf_bs_read_u32(bs);
        ptr->previewTime = gf_bs_read_u32(bs);
        ptr->previewDuration = gf_bs_read_u32(bs);
        ptr->posterTime = gf_bs_read_u32(bs);
        ptr->selectionTime = gf_bs_read_u32(bs);
        ptr->selectionDuration = gf_bs_read_u32(bs);
        ptr->currentTime = gf_bs_read_u32(bs);
        ptr->nextTrackID = gf_bs_read_u32(bs);
        ptr->original_duration = ptr->duration;
        return GF_OK;
}

GF_Box *mvhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MovieHeaderBox, GF_ISOM_BOX_TYPE_MVHD);

        tmp->preferredRate = (1<<16);
        tmp->preferredVolume = (1<<8);

        tmp->matrixA = (1<<16);
        tmp->matrixD = (1<<16);
        tmp->matrixW = (1<<30);

        tmp->nextTrackID = 1;

        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err mvhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        if (ptr->version == 1) {
                gf_bs_write_u64(bs, ptr->creationTime);
                gf_bs_write_u64(bs, ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->timeScale);
                gf_bs_write_u64(bs, ptr->duration);
        } else {
                gf_bs_write_u32(bs, (u32) ptr->creationTime);
                gf_bs_write_u32(bs, (u32) ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->timeScale);
                gf_bs_write_u32(bs, (u32) ptr->duration);
        }
        gf_bs_write_u32(bs, ptr->preferredRate);
        gf_bs_write_u16(bs, ptr->preferredVolume);
        gf_bs_write_data(bs, ptr->reserved, 10);
        gf_bs_write_u32(bs, ptr->matrixA);
        gf_bs_write_u32(bs, ptr->matrixB);
        gf_bs_write_u32(bs, ptr->matrixU);
        gf_bs_write_u32(bs, ptr->matrixC);
        gf_bs_write_u32(bs, ptr->matrixD);
        gf_bs_write_u32(bs, ptr->matrixV);
        gf_bs_write_u32(bs, ptr->matrixX);
        gf_bs_write_u32(bs, ptr->matrixY);
        gf_bs_write_u32(bs, ptr->matrixW);
        gf_bs_write_u32(bs, ptr->previewTime);
        gf_bs_write_u32(bs, ptr->previewDuration);
        gf_bs_write_u32(bs, ptr->posterTime);
        gf_bs_write_u32(bs, ptr->selectionTime);
        gf_bs_write_u32(bs, ptr->selectionDuration);
        gf_bs_write_u32(bs, ptr->currentTime);
        gf_bs_write_u32(bs, ptr->nextTrackID);
        return GF_OK;
}

GF_Err mvhd_Size(GF_Box *s)
{
        GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s;
        if (ptr->duration==(u64) -1) ptr->version = 0;
        else ptr->version = (ptr->duration>0xFFFFFFFF) ? 1 : 0;

        ptr->size += (ptr->version == 1) ? 28 : 16;
        ptr->size += 80;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void nmhd_del(GF_Box *s)
{
        GF_MPEGMediaHeaderBox *ptr = (GF_MPEGMediaHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}



GF_Err nmhd_Read(GF_Box *s, GF_BitStream *bs)
{
        return GF_OK;
}

GF_Box *nmhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MPEGMediaHeaderBox, GF_ISOM_BOX_TYPE_NMHD);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err nmhd_Write(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_full_box_write(s, bs);
}

GF_Err nmhd_Size(GF_Box *s)
{
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void padb_del(GF_Box *s)
{
        GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *) s;
        if (ptr == NULL) return;
        if (ptr->padbits) gf_free(ptr->padbits);
        gf_free(ptr);
}


GF_Err padb_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 i;
        GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *)s;

        ptr->SampleCount = gf_bs_read_u32(bs);

        ptr->padbits = (u8 *)gf_malloc(sizeof(u8)*ptr->SampleCount);
        for (i=0; i<ptr->SampleCount; i += 2) {
                gf_bs_read_int(bs, 1);
                if (i+1 < ptr->SampleCount) {
                        ptr->padbits[i+1] = gf_bs_read_int(bs, 3);
                } else {
                        gf_bs_read_int(bs, 3);
                }
                gf_bs_read_int(bs, 1);
                ptr->padbits[i] = gf_bs_read_int(bs, 3);
        }
        return GF_OK;
}

GF_Box *padb_New()
{
        ISOM_DECL_BOX_ALLOC(GF_PaddingBitsBox, GF_ISOM_BOX_TYPE_PADB);
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err padb_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_Err e;
        GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, ptr->SampleCount, 32);

        for (i=0 ; i<ptr->SampleCount; i += 2) {
                gf_bs_write_int(bs, 0, 1);
                if (i+1 < ptr->SampleCount) {
                        gf_bs_write_int(bs, ptr->padbits[i+1], 3);
                } else {
                        gf_bs_write_int(bs, 0, 3);
                }
                gf_bs_write_int(bs, 0, 1);
                gf_bs_write_int(bs, ptr->padbits[i], 3);
        }
        return GF_OK;
}

GF_Err padb_Size(GF_Box *s)
{
        GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *)s;
        ptr->size += 4;
        if (ptr->SampleCount) ptr->size += (ptr->SampleCount + 1) / 2;

        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void rely_del(GF_Box *s)
{
        GF_RelyHintBox *rely = (GF_RelyHintBox *)s;
        gf_free(rely);
}

GF_Err rely_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_RelyHintBox *ptr = (GF_RelyHintBox *)s;
        ptr->reserved = gf_bs_read_int(bs, 6);
        ptr->prefered = gf_bs_read_int(bs, 1);
        ptr->required = gf_bs_read_int(bs, 1);
        return GF_OK;
}

GF_Box *rely_New()
{
        ISOM_DECL_BOX_ALLOC(GF_RelyHintBox, GF_ISOM_BOX_TYPE_RELY);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err rely_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_RelyHintBox *ptr = (GF_RelyHintBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_int(bs, ptr->reserved, 6);
        gf_bs_write_int(bs, ptr->prefered, 1);
        gf_bs_write_int(bs, ptr->required, 1);
        return GF_OK;
}

GF_Err rely_Size(GF_Box *s)
{
        s->size += 1;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


void rtpo_del(GF_Box *s)
{
        GF_RTPOBox *rtpo = (GF_RTPOBox *)s;
        gf_free(rtpo);
}

GF_Err rtpo_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_RTPOBox *ptr = (GF_RTPOBox *)s;
        ptr->timeOffset = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *rtpo_New()
{
        ISOM_DECL_BOX_ALLOC(GF_RTPOBox, GF_ISOM_BOX_TYPE_RTPO);
        return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err rtpo_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_RTPOBox *ptr = (GF_RTPOBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        //here we have no pb, just remembed that some entries will have to
        //be 4-bytes aligned ...
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->timeOffset);
        return GF_OK;
}

GF_Err rtpo_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

void smhd_del(GF_Box *s)
{
        GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s;
        if (ptr == NULL ) return;
        gf_free(ptr);
}


GF_Err smhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s;
        ptr->balance = gf_bs_read_u16(bs);
        ptr->reserved = gf_bs_read_u16(bs);
        return GF_OK;
}

GF_Box *smhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SoundMediaHeaderBox, GF_ISOM_BOX_TYPE_SMHD);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err smhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u16(bs, ptr->balance);
        gf_bs_write_u16(bs, ptr->reserved);
        return GF_OK;
}

GF_Err smhd_Size(GF_Box *s)
{
        GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s;

        ptr->reserved = 0;
        ptr->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void snro_del(GF_Box *s)
{
        GF_SeqOffHintEntryBox *snro = (GF_SeqOffHintEntryBox *)s;
        gf_free(snro);
}

GF_Err snro_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s;
        ptr->SeqOffset = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *snro_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SeqOffHintEntryBox, GF_ISOM_BOX_TYPE_SNRO);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err snro_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->SeqOffset);
        return GF_OK;
}

GF_Err snro_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


#define WRITE_SAMPLE_FRAGMENTS          1

void stbl_del(GF_Box *s)
{
        GF_SampleTableBox *ptr = (GF_SampleTableBox *)s;
        if (ptr == NULL) return;

        if (ptr->ChunkOffset) gf_isom_box_del(ptr->ChunkOffset);
        if (ptr->CompositionOffset) gf_isom_box_del((GF_Box *) ptr->CompositionOffset);
        if (ptr->CompositionToDecode) gf_isom_box_del((GF_Box *) ptr->CompositionToDecode);
        if (ptr->DegradationPriority) gf_isom_box_del((GF_Box *) ptr->DegradationPriority);
        if (ptr->SampleDescription) gf_isom_box_del((GF_Box *) ptr->SampleDescription);
        if (ptr->SampleSize) gf_isom_box_del((GF_Box *) ptr->SampleSize);
        if (ptr->SampleToChunk) gf_isom_box_del((GF_Box *) ptr->SampleToChunk);
        if (ptr->ShadowSync) gf_isom_box_del((GF_Box *) ptr->ShadowSync);
        if (ptr->SyncSample) gf_isom_box_del((GF_Box *) ptr->SyncSample);
        if (ptr->TimeToSample) gf_isom_box_del((GF_Box *) ptr->TimeToSample);
        if (ptr->SampleDep) gf_isom_box_del((GF_Box *) ptr->SampleDep);
        if (ptr->PaddingBits) gf_isom_box_del((GF_Box *) ptr->PaddingBits);
        if (ptr->Fragments) gf_isom_box_del((GF_Box *) ptr->Fragments);
        if (ptr->sub_samples) gf_isom_box_array_del(ptr->sub_samples);
        if (ptr->sampleGroups) gf_isom_box_array_del(ptr->sampleGroups);
        if (ptr->sampleGroupsDescription) gf_isom_box_array_del(ptr->sampleGroupsDescription);

        if (ptr->sai_sizes) gf_isom_box_array_del(ptr->sai_sizes);
        if (ptr->sai_offsets) gf_isom_box_array_del(ptr->sai_offsets);

        gf_free(ptr);
}

GF_Err stbl_AddBox(GF_Box *s, GF_Box *a)
{
        GF_SampleTableBox *ptr = (GF_SampleTableBox *)s;
        if (!a) return GF_OK;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_STTS:
                if (ptr->TimeToSample) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->TimeToSample = (GF_TimeToSampleBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_CTTS:
                if (ptr->CompositionOffset) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->CompositionOffset = (GF_CompositionOffsetBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_CSLG:
                if (ptr->CompositionToDecode) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->CompositionToDecode = (GF_CompositionToDecodeBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_STSS:
                if (ptr->SyncSample) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->SyncSample = (GF_SyncSampleBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_STSD:
                if (ptr->SampleDescription) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->SampleDescription  =(GF_SampleDescriptionBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_STZ2:
        case GF_ISOM_BOX_TYPE_STSZ:
                if (ptr->SampleSize) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->SampleSize = (GF_SampleSizeBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_STSC:
                if (ptr->SampleToChunk) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->SampleToChunk = (GF_SampleToChunkBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_PADB:
                if (ptr->PaddingBits) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->PaddingBits = (GF_PaddingBitsBox *) a;
                break;

        //WARNING: AS THIS MAY CHANGE DYNAMICALLY DURING EDIT,
        case GF_ISOM_BOX_TYPE_CO64:
        case GF_ISOM_BOX_TYPE_STCO:
                if (ptr->ChunkOffset) {
                        gf_isom_box_del(ptr->ChunkOffset);
                }
                ptr->ChunkOffset = a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_STSH:
                if (ptr->ShadowSync) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->ShadowSync = (GF_ShadowSyncBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_STDP:
                if (ptr->DegradationPriority) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->DegradationPriority = (GF_DegradationPriorityBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_SDTP:
                if (ptr->SampleDep) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->SampleDep= (GF_SampleDependencyTypeBox *)a;
                break;

        case GF_ISOM_BOX_TYPE_STSF:
                if (ptr->Fragments) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->Fragments = (GF_SampleFragmentBox *)a;
                break;

        case GF_ISOM_BOX_TYPE_SUBS:
                if (!ptr->sub_samples) ptr->sub_samples = gf_list_new();
                gf_list_add(ptr->sub_samples, a);
                //check subsample box
                {
                        GF_SubSampleInformationBox *subs = (GF_SubSampleInformationBox *)a;
                        GF_SubSampleInfoEntry *ent = gf_list_get(subs->Samples, 0);
                        if (ent->sample_delta==0) {
                                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] first entry in SubSample in track SampleTable has sample_delta of 0, should be one. Fixing\n"));
                                ent->sample_delta = 1;
                        }
                }
                break;

        case GF_ISOM_BOX_TYPE_SBGP:
                if (!ptr->sampleGroups) ptr->sampleGroups = gf_list_new();
                gf_list_add(ptr->sampleGroups, a);
                break;
        case GF_ISOM_BOX_TYPE_SGPD:
                if (!ptr->sampleGroupsDescription) ptr->sampleGroupsDescription = gf_list_new();
                gf_list_add(ptr->sampleGroupsDescription, a);
                break;

        case GF_ISOM_BOX_TYPE_SAIZ:
                if (!ptr->sai_sizes) ptr->sai_sizes = gf_list_new();
                gf_list_add(ptr->sai_sizes, a);
                break;
        case GF_ISOM_BOX_TYPE_SAIO:
                if (!ptr->sai_offsets) ptr->sai_offsets = gf_list_new();
                gf_list_add(ptr->sai_offsets, a);
                break;
        default:
                return gf_isom_box_add_default((GF_Box *)ptr, a);
        }
        return GF_OK;
}




GF_Err stbl_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        //we need to parse DegPrior in a special way
        GF_SampleTableBox *ptr = (GF_SampleTableBox *)s;

        e = gf_isom_box_array_read(s, bs, stbl_AddBox);
        if (e) return e;

        if (!ptr->SyncSample)
                ptr->no_sync_found = 1;

        ptr->nb_sgpd_in_stbl = gf_list_count(ptr->sampleGroupsDescription);
        ptr->nb_other_boxes_in_stbl = gf_list_count(ptr->other_boxes);

        return GF_OK;
}

GF_Box *stbl_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleTableBox, GF_ISOM_BOX_TYPE_STBL);
        //maxSamplePer chunk is 10 by default
        tmp->MaxSamplePerChunk = 10;
        tmp->groupID = 1;
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stbl_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SampleTableBox *ptr = (GF_SampleTableBox *)s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        if (ptr->SampleDescription) {
                e = gf_isom_box_write((GF_Box *) ptr->SampleDescription, bs);
                if (e) return e;
        }
        if (ptr->TimeToSample) {
                e = gf_isom_box_write((GF_Box *) ptr->TimeToSample, bs);
                if (e) return e;
        }
        if (ptr->CompositionOffset)     {
                e = gf_isom_box_write((GF_Box *) ptr->CompositionOffset, bs);
                if (e) return e;
        }
        if (ptr->CompositionToDecode)   {
                e = gf_isom_box_write((GF_Box *) ptr->CompositionToDecode, bs);
                if (e) return e;
        }
        if (ptr->SyncSample) {
                e = gf_isom_box_write((GF_Box *) ptr->SyncSample, bs);
                if (e) return e;
        }
        if (ptr->ShadowSync) {
                e = gf_isom_box_write((GF_Box *) ptr->ShadowSync, bs);
                if (e) return e;
        }
        if (ptr->SampleToChunk) {
                e = gf_isom_box_write((GF_Box *) ptr->SampleToChunk, bs);
                if (e) return e;
        }
        if (ptr->SampleSize) {
                e = gf_isom_box_write((GF_Box *) ptr->SampleSize, bs);
                if (e) return e;
        }
        if (ptr->ChunkOffset) {
                e = gf_isom_box_write(ptr->ChunkOffset, bs);
                if (e) return e;
        }
        if (ptr->DegradationPriority) {
                e = gf_isom_box_write((GF_Box *) ptr->DegradationPriority, bs);
                if (e) return e;
        }
        if (ptr->SampleDep && ptr->SampleDep->sampleCount) {
                e = gf_isom_box_write((GF_Box *) ptr->SampleDep, bs);
                if (e) return e;
        }
        if (ptr->PaddingBits) {
                e = gf_isom_box_write((GF_Box *) ptr->PaddingBits, bs);
                if (e) return e;
        }
        if (ptr->sub_samples) {
                e = gf_isom_box_array_write(s, ptr->sub_samples, bs);
                if (e) return e;
        }
        if (ptr->sampleGroupsDescription) {
                e = gf_isom_box_array_write(s, ptr->sampleGroupsDescription, bs);
                if (e) return e;
        }
        if (ptr->sampleGroups) {
                e = gf_isom_box_array_write(s, ptr->sampleGroups, bs);
                if (e) return e;
        }
        if (ptr->sai_sizes) {
                e = gf_isom_box_array_write(s, ptr->sai_sizes, bs);
                if (e) return e;
        }
        if (ptr->sai_offsets) {
                e = gf_isom_box_array_write(s, ptr->sai_offsets, bs);
                if (e) return e;
        }

#if WRITE_SAMPLE_FRAGMENTS
        //sampleFragments
        if (ptr->Fragments) {
                e = gf_isom_box_write((GF_Box *) ptr->Fragments, bs);
                if (e) return e;
        }
#endif
        return GF_OK;
}

GF_Err stbl_Size(GF_Box *s)
{
        GF_Err e;
        GF_SampleTableBox *ptr = (GF_SampleTableBox *)s;

        //Mandatory boxs (but not internally :)
        if (ptr->SampleDescription) {
                e = gf_isom_box_size((GF_Box *) ptr->SampleDescription);
                if (e) return e;
                ptr->size += ptr->SampleDescription->size;
        }
        if (ptr->SampleSize) {
                e = gf_isom_box_size((GF_Box *) ptr->SampleSize);
                if (e) return e;
                ptr->size += ptr->SampleSize->size;
        }
        if (ptr->SampleToChunk) {
                e = gf_isom_box_size((GF_Box *) ptr->SampleToChunk);
                if (e) return e;
                ptr->size += ptr->SampleToChunk->size;
        }
        if (ptr->TimeToSample) {
                e = gf_isom_box_size((GF_Box *) ptr->TimeToSample);
                if (e) return e;
                ptr->size += ptr->TimeToSample->size;
        }
        if (ptr->ChunkOffset) {
                e = gf_isom_box_size(ptr->ChunkOffset);
                if (e) return e;
                ptr->size += ptr->ChunkOffset->size;
        }

        //optional boxs
        if (ptr->CompositionOffset)     {
                e = gf_isom_box_size((GF_Box *) ptr->CompositionOffset);
                if (e) return e;
                ptr->size += ptr->CompositionOffset->size;
        }
        if (ptr->CompositionToDecode)   {
                e = gf_isom_box_size((GF_Box *) ptr->CompositionToDecode);
                if (e) return e;
                ptr->size += ptr->CompositionToDecode->size;
        }
        if (ptr->DegradationPriority) {
                e = gf_isom_box_size((GF_Box *) ptr->DegradationPriority);
                if (e) return e;
                ptr->size += ptr->DegradationPriority->size;
        }
        if (ptr->ShadowSync) {
                e = gf_isom_box_size((GF_Box *) ptr->ShadowSync);
                if (e) return e;
                ptr->size += ptr->ShadowSync->size;
        }
        if (ptr->SyncSample) {
                e = gf_isom_box_size((GF_Box *) ptr->SyncSample);
                if (e) return e;
                ptr->size += ptr->SyncSample->size;
        }
        if (ptr->SampleDep && ptr->SampleDep->sampleCount) {
                e = gf_isom_box_size((GF_Box *) ptr->SampleDep);
                if (e) return e;
                ptr->size += ptr->SampleDep->size;
        }
        //padb
        if (ptr->PaddingBits) {
                e = gf_isom_box_size((GF_Box *) ptr->PaddingBits);
                if (e) return e;
                ptr->size += ptr->PaddingBits->size;
        }
#if WRITE_SAMPLE_FRAGMENTS
        //sample fragments
        if (ptr->Fragments) {
                e = gf_isom_box_size((GF_Box *) ptr->Fragments);
                if (e) return e;
                ptr->size += ptr->Fragments->size;
        }
#endif

        if (ptr->sub_samples) {
                e = gf_isom_box_array_size(s, ptr->sub_samples);
                if (e) return e;
        }
        if (ptr->sampleGroups) {
                e = gf_isom_box_array_size(s, ptr->sampleGroups);
                if (e) return e;
        }
        if (ptr->sampleGroupsDescription) {
                e = gf_isom_box_array_size(s, ptr->sampleGroupsDescription);
                if (e) return e;
        }
        if (ptr->sai_sizes) {
                e = gf_isom_box_array_size(s, ptr->sai_sizes);
                if (e) return e;
        }
        if (ptr->sai_offsets) {
                e = gf_isom_box_array_size(s, ptr->sai_offsets);
                if (e) return e;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void stco_del(GF_Box *s)
{
        GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s;
        if (ptr == NULL) return;
        if (ptr->offsets) gf_free(ptr->offsets);
        gf_free(ptr);
}


GF_Err stco_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 entries;
        GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s;

        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);
        if (ptr->nb_entries > ptr->size / 4) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stco\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        if (ptr->nb_entries) {
                ptr->offsets = (u32 *) gf_malloc(ptr->nb_entries * sizeof(u32) );
                if (ptr->offsets == NULL) return GF_OUT_OF_MEM;
                ptr->alloc_size = ptr->nb_entries;

                for (entries = 0; entries < ptr->nb_entries; entries++) {
                        ptr->offsets[entries] = gf_bs_read_u32(bs);
                }
        }
        return GF_OK;
}

GF_Box *stco_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ChunkOffsetBox, GF_ISOM_BOX_TYPE_STCO);
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stco_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i = 0; i < ptr->nb_entries; i++) {
                gf_bs_write_u32(bs, ptr->offsets[i]);
        }
        return GF_OK;
}


GF_Err stco_Size(GF_Box *s)
{
        GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s;

        ptr->size += 4 + (4 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void stdp_del(GF_Box *s)
{
        GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s;
        if (ptr == NULL ) return;
        if (ptr->priorities) gf_free(ptr->priorities);
        gf_free(ptr);
}

//this is called through stbl_read...
GF_Err stdp_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 entry;
        GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s;

        /*out-of-order stdp, assume no padding at the end and take the entire remaining data for entries*/
        if (!ptr->nb_entries) ptr->nb_entries = (u32) ptr->size / 2;
        else if (ptr->nb_entries > ptr->size / 2) return GF_ISOM_INVALID_FILE;

        ptr->priorities = (u16 *) gf_malloc(ptr->nb_entries * sizeof(u16));
        if (ptr->priorities == NULL) return GF_OUT_OF_MEM;
        for (entry = 0; entry < ptr->nb_entries; entry++) {
                ptr->priorities[entry] = gf_bs_read_u16(bs);
        }
        ISOM_DECREASE_SIZE(ptr, (2*ptr->nb_entries) );
        return GF_OK;
}

GF_Box *stdp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_DegradationPriorityBox, GF_ISOM_BOX_TYPE_STDP);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stdp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        for (i = 0; i < ptr->nb_entries; i++) {
                gf_bs_write_u16(bs, ptr->priorities[i]);
        }
        return GF_OK;
}

GF_Err stdp_Size(GF_Box *s)
{
        GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s;

        ptr->size += (2 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void stsc_del(GF_Box *s)
{
        GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;
        if (ptr == NULL) return;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}


GF_Err stsc_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;

        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);
        if (ptr->nb_entries > ptr->size / 12) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsc\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        ptr->alloc_size = ptr->nb_entries;
        ptr->entries = gf_malloc(sizeof(GF_StscEntry)*ptr->alloc_size);
        if (!ptr->entries) return GF_OUT_OF_MEM;

        for (i = 0; i < ptr->nb_entries; i++) {
                ptr->entries[i].firstChunk = gf_bs_read_u32(bs);
                ptr->entries[i].samplesPerChunk = gf_bs_read_u32(bs);
                ptr->entries[i].sampleDescriptionIndex = gf_bs_read_u32(bs);
                ptr->entries[i].isEdited = 0;
                ptr->entries[i].nextChunk = 0;
                if (!ptr->entries[i].firstChunk) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] invalid first chunk 0 in stsc entry\n", ptr->nb_entries));
                        return GF_ISOM_INVALID_FILE;
                }

                //update the next chunk in the previous entry
                if (i) ptr->entries[i-1].nextChunk = ptr->entries[i].firstChunk;
        }
        ptr->currentIndex = 0;
        ptr->firstSampleInCurrentChunk = 0;
        ptr->currentChunk = 0;
        ptr->ghostNumber = 0;
        return GF_OK;
}

GF_Box *stsc_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleToChunkBox, GF_ISOM_BOX_TYPE_STSC);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsc_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i=0; i<ptr->nb_entries; i++) {
                gf_bs_write_u32(bs, ptr->entries[i].firstChunk);
                gf_bs_write_u32(bs, ptr->entries[i].samplesPerChunk);
                gf_bs_write_u32(bs, ptr->entries[i].sampleDescriptionIndex);
        }
        return GF_OK;
}

GF_Err stsc_Size(GF_Box *s)
{
        GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;

        ptr->size += 4 + (12 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void stsd_del(GF_Box *s)
{
        GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Err stsd_AddBox(GF_Box *s, GF_Box *a)
{
        GF_UnknownBox *def;
        GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s;
        if (!a) return GF_OK;

        switch (a->type) {
        case GF_ISOM_BOX_TYPE_MP4S:
        case GF_ISOM_BOX_TYPE_ENCS:
        case GF_ISOM_BOX_TYPE_MP4A:
        case GF_ISOM_BOX_TYPE_ENCA:
        case GF_ISOM_BOX_TYPE_MP4V:
        case GF_ISOM_BOX_TYPE_ENCV:
        case GF_ISOM_BOX_TYPE_RESV:
        case GF_ISOM_BOX_TYPE_GHNT:
        case GF_ISOM_BOX_TYPE_RTP_STSD:
        case GF_ISOM_BOX_TYPE_SRTP_STSD:
        case GF_ISOM_BOX_TYPE_FDP_STSD:
        case GF_ISOM_BOX_TYPE_RRTP_STSD:
        case GF_ISOM_BOX_TYPE_RTCP_STSD:
        case GF_ISOM_BOX_TYPE_AVC1:
        case GF_ISOM_BOX_TYPE_AVC2:
        case GF_ISOM_BOX_TYPE_AVC3:
        case GF_ISOM_BOX_TYPE_AVC4:
        case GF_ISOM_BOX_TYPE_SVC1:
        case GF_ISOM_BOX_TYPE_MVC1:
        case GF_ISOM_BOX_TYPE_HVC1:
        case GF_ISOM_BOX_TYPE_HEV1:
        case GF_ISOM_BOX_TYPE_HVC2:
        case GF_ISOM_BOX_TYPE_HEV2:
        case GF_ISOM_BOX_TYPE_HVT1:
        case GF_ISOM_BOX_TYPE_LHV1:
        case GF_ISOM_BOX_TYPE_LHE1:
        case GF_ISOM_BOX_TYPE_TX3G:
        case GF_ISOM_BOX_TYPE_TEXT:
        case GF_ISOM_BOX_TYPE_ENCT:
        case GF_ISOM_BOX_TYPE_METX:
        case GF_ISOM_BOX_TYPE_METT:
        case GF_ISOM_BOX_TYPE_STXT:
        case GF_ISOM_BOX_TYPE_DIMS:
        case GF_ISOM_BOX_TYPE_AC3:
        case GF_ISOM_BOX_TYPE_EC3:
        case GF_ISOM_BOX_TYPE_LSR1:
        case GF_ISOM_BOX_TYPE_WVTT:
        case GF_ISOM_BOX_TYPE_STPP:
        case GF_ISOM_BOX_TYPE_SBTT:
        case GF_ISOM_BOX_TYPE_ELNG:
        case GF_ISOM_BOX_TYPE_MP3:
        case GF_ISOM_SUBTYPE_3GP_AMR:
        case GF_ISOM_SUBTYPE_3GP_AMR_WB:
        case GF_ISOM_SUBTYPE_3GP_EVRC:
        case GF_ISOM_SUBTYPE_3GP_QCELP:
        case GF_ISOM_SUBTYPE_3GP_SMV:
        case GF_ISOM_SUBTYPE_3GP_H263:
                return gf_isom_box_add_default((GF_Box*)ptr, a);

        //unknown sample description: we need a specific box to handle the data ref index
        //rather than a default box ...
        case GF_ISOM_BOX_TYPE_UNKNOWN:
                def = (GF_UnknownBox *)a;
                /*we need at least 8 bytes for unknown sample entries*/
                if (def->dataSize < 8) {
                        gf_isom_box_del(a);
                        return GF_OK;
                }
                return gf_isom_box_add_default((GF_Box*)ptr, a);

        default:
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Cannot process box of type %s\n", gf_4cc_to_str(a->type)));
                return GF_ISOM_INVALID_FILE;
        }
}


GF_Err stsd_Read(GF_Box *s, GF_BitStream *bs)
{
        gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(s, 4)

        return gf_isom_box_array_read(s, bs, stsd_AddBox);
}

GF_Box *stsd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleDescriptionBox, GF_ISOM_BOX_TYPE_STSD);
        tmp->other_boxes = gf_list_new();
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 nb_entries;
        GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        nb_entries = gf_list_count(ptr->other_boxes);
        gf_bs_write_u32(bs, nb_entries);
        return GF_OK;
}

GF_Err stsd_Size(GF_Box *s)
{
        GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s;
        ptr->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void stsf_del(GF_Box *s)
{
        u32 nb_entries;
        u32 i;
        GF_StsfEntry *pe;
        GF_SampleFragmentBox *ptr = (GF_SampleFragmentBox *)s;
        if (ptr == NULL) return;

        if (ptr->entryList) {
                nb_entries = gf_list_count(ptr->entryList);
                for ( i = 0; i < nb_entries; i++ ) {
                        pe = (GF_StsfEntry*)gf_list_get(ptr->entryList, i);
                        if (pe->fragmentSizes) gf_free(pe->fragmentSizes);
                        gf_free(pe);
                }
                gf_list_del(ptr->entryList);
        }
        gf_free(ptr);
}



GF_Err stsf_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 entries, i;
        u32 nb_entries;
        GF_StsfEntry *p;
        GF_SampleFragmentBox *ptr = (GF_SampleFragmentBox *)s;

        p = NULL;
        if (!ptr) return GF_BAD_PARAM;
        nb_entries = gf_bs_read_u32(bs);

        p = NULL;
        for ( entries = 0; entries < nb_entries; entries++ ) {
                p = (GF_StsfEntry *) gf_malloc(sizeof(GF_StsfEntry));
                if (!p) return GF_OUT_OF_MEM;
                p->SampleNumber = gf_bs_read_u32(bs);
                p->fragmentCount = gf_bs_read_u32(bs);
                p->fragmentSizes = (u16*)gf_malloc(sizeof(GF_StsfEntry) * p->fragmentCount);
                for (i=0; i<p->fragmentCount; i++) {
                        p->fragmentSizes[i] = gf_bs_read_u16(bs);
                }
                gf_list_add(ptr->entryList, p);
        }
#ifndef GPAC_DISABLE_ISOM_WRITE
        ptr->w_currentEntry = p;
        ptr->w_currentEntryIndex = nb_entries-1;
#endif
        return GF_OK;
}

GF_Box *stsf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleFragmentBox, GF_ISOM_BOX_TYPE_STSF);

        tmp->entryList = gf_list_new();
        if (! tmp->entryList) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *) tmp;
}




#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsf_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i, j;
        u32 nb_entries;
        GF_StsfEntry *p;
        GF_SampleFragmentBox *ptr = (GF_SampleFragmentBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        nb_entries = gf_list_count(ptr->entryList);
        gf_bs_write_u32(bs, nb_entries);
        for ( i = 0; i < nb_entries; i++ ) {
                p = (GF_StsfEntry*)gf_list_get(ptr->entryList, i);
                gf_bs_write_u32(bs, p->SampleNumber);
                gf_bs_write_u32(bs, p->fragmentCount);
                for (j=0; j<p->fragmentCount; j++) {
                        gf_bs_write_u16(bs, p->fragmentSizes[j]);
                }
        }
        return GF_OK;
}

GF_Err stsf_Size(GF_Box *s)
{
        GF_StsfEntry *p;
        u32 nb_entries, i;
        GF_SampleFragmentBox *ptr = (GF_SampleFragmentBox *) s;

        nb_entries = gf_list_count(ptr->entryList);
        ptr->size += 4;
        for (i=0; i<nb_entries; i++) {
                p = (GF_StsfEntry *)gf_list_get(ptr->entryList, i);
                ptr->size += 8 + 2*p->fragmentCount;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void stsh_del(GF_Box *s)
{
        u32 i = 0;
        GF_StshEntry *ent;
        GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s;
        if (ptr == NULL) return;
        while ( (ent = (GF_StshEntry *)gf_list_enum(ptr->entries, &i)) ) {
                gf_free(ent);
        }
        gf_list_del(ptr->entries);
        gf_free(ptr);
}



GF_Err stsh_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 count, i;
        GF_StshEntry *ent;
        GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s;

        count = gf_bs_read_u32(bs);

        for (i = 0; i < count; i++) {
                ent = (GF_StshEntry *) gf_malloc(sizeof(GF_StshEntry));
                if (!ent) return GF_OUT_OF_MEM;
                ent->shadowedSampleNumber = gf_bs_read_u32(bs);
                ent->syncSampleNumber = gf_bs_read_u32(bs);
                e = gf_list_add(ptr->entries, ent);
                if (e) return e;
        }
        return GF_OK;
}

GF_Box *stsh_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ShadowSyncBox, GF_ISOM_BOX_TYPE_STSH);

        tmp->entries = gf_list_new();
        if (!tmp->entries) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsh_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_StshEntry *ent;
        GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, gf_list_count(ptr->entries));
        i=0;
        while ((ent = (GF_StshEntry *)gf_list_enum(ptr->entries, &i))) {
                gf_bs_write_u32(bs, ent->shadowedSampleNumber);
                gf_bs_write_u32(bs, ent->syncSampleNumber);
        }
        return GF_OK;
}

GF_Err stsh_Size(GF_Box *s)
{
        GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s;
        ptr->size += 4 + (8 * gf_list_count(ptr->entries));
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void stss_del(GF_Box *s)
{
        GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s;
        if (ptr == NULL) return;
        if (ptr->sampleNumbers) gf_free(ptr->sampleNumbers);
        gf_free(ptr);
}

GF_Err stss_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s;

        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);
        if (ptr->nb_entries > ptr->size / 4) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stss\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        ptr->alloc_size = ptr->nb_entries;
        ptr->sampleNumbers = (u32 *) gf_malloc( ptr->alloc_size * sizeof(u32));
        if (ptr->sampleNumbers == NULL) return GF_OUT_OF_MEM;

        for (i = 0; i < ptr->nb_entries; i++) {
                ptr->sampleNumbers[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}

GF_Box *stss_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SyncSampleBox, GF_ISOM_BOX_TYPE_STSS);
        return (GF_Box*)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stss_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i = 0; i < ptr->nb_entries; i++) {
                gf_bs_write_u32(bs, ptr->sampleNumbers[i]);
        }
        return GF_OK;
}

GF_Err stss_Size(GF_Box *s)
{
        GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s;
        ptr->size += 4 + (4 * ptr->nb_entries);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void stsz_del(GF_Box *s)
{
        GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s;
        if (ptr == NULL) return;
        if (ptr->sizes) gf_free(ptr->sizes);
        gf_free(ptr);
}


GF_Err stsz_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i, estSize;
        GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        //support for CompactSizes
        if (s->type == GF_ISOM_BOX_TYPE_STSZ) {
                ptr->sampleSize = gf_bs_read_u32(bs);
                ptr->sampleCount = gf_bs_read_u32(bs);

                ISOM_DECREASE_SIZE(ptr, 8);
        } else {
                //24-reserved
                gf_bs_read_int(bs, 24);
                i = gf_bs_read_u8(bs);
                ptr->sampleCount = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 8);
                switch (i) {
                case 4:
                case 8:
                case 16:
                        ptr->sampleSize = i;
                        break;
                default:
                        //try to fix the file
                        //no samples, no parsing pb
                        if (!ptr->sampleCount) {
                                ptr->sampleSize = 16;
                                return GF_OK;
                        }
                        estSize = (u32) (ptr->size) / ptr->sampleCount;
                        if (!estSize && ((ptr->sampleCount+1)/2 == (ptr->size)) ) {
                                ptr->sampleSize = 4;
                                break;
                        } else if (estSize == 1 || estSize == 2) {
                                ptr->sampleSize = 8 * estSize;
                        } else {
                                return GF_ISOM_INVALID_FILE;
                        }
                }
        }
        if (s->type == GF_ISOM_BOX_TYPE_STSZ) {
                if (! ptr->sampleSize && ptr->sampleCount) {
                        if (ptr->sampleCount > ptr->size / 4) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount));
                                return GF_ISOM_INVALID_FILE;
                        }
                        ptr->sizes = (u32 *) gf_malloc(ptr->sampleCount * sizeof(u32));
                        ptr->alloc_size = ptr->sampleCount;
                        if (! ptr->sizes) return GF_OUT_OF_MEM;
                        for (i = 0; i < ptr->sampleCount; i++) {
                                ptr->sizes[i] = gf_bs_read_u32(bs);
                        }
                }
        } else {
                if (ptr->sampleSize==4) {
                        if (ptr->sampleCount / 2 > ptr->size) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount));
                                return GF_ISOM_INVALID_FILE;
                        }
                } else {
                        if (ptr->sampleCount > ptr->size / (ptr->sampleSize/8)) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount));
                                return GF_ISOM_INVALID_FILE;
                        }
                }
                //note we could optimize the mem usage by keeping the table compact
                //in memory. But that would complicate both caching and editing
                //we therefore keep all sizes as u32 and uncompress the table
                ptr->sizes = (u32 *) gf_malloc(ptr->sampleCount * sizeof(u32));
                if (! ptr->sizes) return GF_OUT_OF_MEM;
                ptr->alloc_size = ptr->sampleCount;

                for (i = 0; i < ptr->sampleCount; ) {
                        switch (ptr->sampleSize) {
                        case 4:
                                ptr->sizes[i] = gf_bs_read_int(bs, 4);
                                if (i+1 < ptr->sampleCount) {
                                        ptr->sizes[i+1] = gf_bs_read_int(bs, 4);
                                } else {
                                        //0 padding in odd sample count
                                        gf_bs_read_int(bs, 4);
                                }
                                i += 2;
                                break;
                        default:
                                ptr->sizes[i] = gf_bs_read_int(bs, ptr->sampleSize);
                                i += 1;
                                break;
                        }
                }
        }
        return GF_OK;
}

GF_Box *stsz_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleSizeBox, 0);

        //type is unknown here, can be regular or compact table
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsz_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        //in both versions this is still valid
        if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) {
                gf_bs_write_u32(bs, ptr->sampleSize);
        } else {
                gf_bs_write_u24(bs, 0);
                gf_bs_write_u8(bs, ptr->sampleSize);
        }
        gf_bs_write_u32(bs, ptr->sampleCount);

        if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) {
                if (! ptr->sampleSize) {
                        for (i = 0; i < ptr->sampleCount; i++) {
                                gf_bs_write_u32(bs, ptr->sizes ? ptr->sizes[i] : 0);
                        }
                }
        } else {
                for (i = 0; i < ptr->sampleCount; ) {
                        switch (ptr->sampleSize) {
                        case 4:
                                gf_bs_write_int(bs, ptr->sizes[i], 4);
                                if (i+1 < ptr->sampleCount) {
                                        gf_bs_write_int(bs, ptr->sizes[i+1], 4);
                                } else {
                                        //0 padding in odd sample count
                                        gf_bs_write_int(bs, 0, 4);
                                }
                                i += 2;
                                break;
                        default:
                                gf_bs_write_int(bs, ptr->sizes[i], ptr->sampleSize);
                                i += 1;
                                break;
                        }
                }
        }
        return GF_OK;
}

GF_Err stsz_Size(GF_Box *s)
{
        u32 i, fieldSize, size;
        GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s;

        ptr->size += 8;
        if (!ptr->sampleCount) return GF_OK;

        //regular table
        if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) {
                if (ptr->sampleSize) return GF_OK;
                ptr->size += (4 * ptr->sampleCount);
                return GF_OK;
        }

        fieldSize = 4;
        size = ptr->sizes[0];

        for (i=0; i < ptr->sampleCount; i++) {
                if (ptr->sizes[i] <= 0xF) continue;
                //switch to 8-bit table
                else if (ptr->sizes[i] <= 0xFF) {
                        fieldSize = 8;
                }
                //switch to 16-bit table
                else if (ptr->sizes[i] <= 0xFFFF) {
                        fieldSize = 16;
                }
                //switch to 32-bit table
                else {
                        fieldSize = 32;
                }

                //check the size
                if (size != ptr->sizes[i]) size = 0;
        }
        //if all samples are of the same size, switch to regular (more compact)
        if (size) {
                ptr->type = GF_ISOM_BOX_TYPE_STSZ;
                ptr->sampleSize = size;
                gf_free(ptr->sizes);
                ptr->sizes = NULL;
        }

        if (fieldSize == 32) {
                //oops, doesn't fit in a compact table
                ptr->type = GF_ISOM_BOX_TYPE_STSZ;
                ptr->size += (4 * ptr->sampleCount);
                return GF_OK;
        }

        //make sure we are a compact table (no need to change the mem representation)
        ptr->type = GF_ISOM_BOX_TYPE_STZ2;
        ptr->sampleSize = fieldSize;
        if (fieldSize == 4) {
                //do not forget the 0 padding field for odd count
                ptr->size += (ptr->sampleCount + 1) / 2;
        } else {
                ptr->size += (ptr->sampleCount) * (fieldSize/8);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void stts_del(GF_Box *s)
{
        GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}


GF_Err stts_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;

#ifndef GPAC_DISABLE_ISOM_WRITE
        ptr->w_LastDTS = 0;
#endif
        ptr->nb_entries = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);
        if (ptr->nb_entries > ptr->size / 8) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stts\n", ptr->nb_entries));
                return GF_ISOM_INVALID_FILE;
        }

        ptr->alloc_size = ptr->nb_entries;
        ptr->entries = gf_malloc(sizeof(GF_SttsEntry)*ptr->alloc_size);
        if (!ptr->entries) return GF_OUT_OF_MEM;
        for (i=0; i<ptr->nb_entries; i++) {
                ptr->entries[i].sampleCount = gf_bs_read_u32(bs);
                ptr->entries[i].sampleDelta = gf_bs_read_u32(bs);
#ifndef GPAC_DISABLE_ISOM_WRITE
                ptr->w_currentSampleNum += ptr->entries[i].sampleCount;
                ptr->w_LastDTS += ptr->entries[i].sampleCount * ptr->entries[i].sampleDelta;
#endif

                if (!ptr->entries[i].sampleDelta) {
                        if ((i+1<ptr->nb_entries) ) {
                                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Found stts entry with sample_delta=0 - forbidden ! Fixing to 1\n" ));
                                ptr->entries[i].sampleDelta = 1;
                        } else if (ptr->entries[i].sampleCount>1) {
                                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] more than one stts entry at the end of the track with sample_delta=0 - forbidden ! Fixing to 1\n" ));
                                ptr->entries[i].sampleDelta = 1;
                        }
                } else if ((s32) ptr->entries[i].sampleDelta < 0) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] stts entry %d has negative duration %d - forbidden ! Fixing to 1, sync may get lost (consider reimport raw media)\n", i, (s32) ptr->entries[i].sampleDelta ));
                        ptr->entries[i].sampleDelta = 1;
                }
        }
        if (ptr->size<(ptr->nb_entries*8)) return GF_ISOM_INVALID_FILE;
        ISOM_DECREASE_SIZE(ptr, ptr->nb_entries*8);

        //remove the last sample delta.
#ifndef GPAC_DISABLE_ISOM_WRITE
        if (ptr->nb_entries) ptr->w_LastDTS -= ptr->entries[ptr->nb_entries-1].sampleDelta;
#endif
        return GF_OK;
}

GF_Box *stts_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TimeToSampleBox, GF_ISOM_BOX_TYPE_STTS);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stts_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->nb_entries);
        for (i=0; i<ptr->nb_entries; i++) {
                gf_bs_write_u32(bs, ptr->entries[i].sampleCount);
                gf_bs_write_u32(bs, ptr->entries[i].sampleDelta);
        }
        return GF_OK;
}

GF_Err stts_Size(GF_Box *s)
{
        GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;
        ptr->size += 4 + (8 * ptr->nb_entries);
        return GF_OK;
}


#endif /*GPAC_DISABLE_ISOM_WRITE*/


#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void tfhd_del(GF_Box *s)
{
        GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Err tfhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s;

        ptr->trackID = gf_bs_read_u32(bs);

        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) {
                ptr->base_data_offset = gf_bs_read_u64(bs);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) {
                ptr->sample_desc_index = gf_bs_read_u32(bs);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) {
                ptr->def_sample_duration = gf_bs_read_u32(bs);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) {
                ptr->def_sample_size = gf_bs_read_u32(bs);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) {
                ptr->def_sample_flags = gf_bs_read_u32(bs);
        }
        return GF_OK;
}

GF_Box *tfhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackFragmentHeaderBox, GF_ISOM_BOX_TYPE_TFHD);
        //NO FLAGS SET BY DEFAULT
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err tfhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->trackID);

        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) {
                gf_bs_write_u64(bs, ptr->base_data_offset);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) {
                gf_bs_write_u32(bs, ptr->sample_desc_index);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) {
                gf_bs_write_u32(bs, ptr->def_sample_duration);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) {
                gf_bs_write_u32(bs, ptr->def_sample_size);
        }
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) {
                gf_bs_write_u32(bs, ptr->def_sample_flags);
        }
        return GF_OK;
}

GF_Err tfhd_Size(GF_Box *s)
{
        GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s;
        ptr->size += 4;

        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) ptr->size += 8;
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) ptr->size += 4;
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) ptr->size += 4;
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) ptr->size += 4;
        if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) ptr->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


void tims_del(GF_Box *s)
{
        GF_TSHintEntryBox *tims = (GF_TSHintEntryBox *)s;
        gf_free(tims);
}

GF_Err tims_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s;
        ptr->timeScale = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *tims_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TSHintEntryBox, GF_ISOM_BOX_TYPE_TIMS);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err tims_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->timeScale);
        return GF_OK;
}

GF_Err tims_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void tkhd_del(GF_Box *s)
{
        GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
        return;
}


GF_Err tkhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;

        if (ptr->version == 1) {
                ptr->creationTime = gf_bs_read_u64(bs);
                ptr->modificationTime = gf_bs_read_u64(bs);
                ptr->trackID = gf_bs_read_u32(bs);
                ptr->reserved1 = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u64(bs);
        } else {
                ptr->creationTime = gf_bs_read_u32(bs);
                ptr->modificationTime = gf_bs_read_u32(bs);
                ptr->trackID = gf_bs_read_u32(bs);
                ptr->reserved1 = gf_bs_read_u32(bs);
                ptr->duration = gf_bs_read_u32(bs);
        }
        ptr->reserved2[0] = gf_bs_read_u32(bs);
        ptr->reserved2[1] = gf_bs_read_u32(bs);
        ptr->layer = gf_bs_read_u16(bs);
        ptr->alternate_group = gf_bs_read_u16(bs);
        ptr->volume = gf_bs_read_u16(bs);
        ptr->reserved3 = gf_bs_read_u16(bs);
        ptr->matrix[0] = gf_bs_read_u32(bs);
        ptr->matrix[1] = gf_bs_read_u32(bs);
        ptr->matrix[2] = gf_bs_read_u32(bs);
        ptr->matrix[3] = gf_bs_read_u32(bs);
        ptr->matrix[4] = gf_bs_read_u32(bs);
        ptr->matrix[5] = gf_bs_read_u32(bs);
        ptr->matrix[6] = gf_bs_read_u32(bs);
        ptr->matrix[7] = gf_bs_read_u32(bs);
        ptr->matrix[8] = gf_bs_read_u32(bs);
        ptr->width = gf_bs_read_u32(bs);
        ptr->height = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *tkhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackHeaderBox, GF_ISOM_BOX_TYPE_TKHD);
        tmp->matrix[0] = 0x00010000;
        tmp->matrix[4] = 0x00010000;
        tmp->matrix[8] = 0x40000000;
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err tkhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        if (ptr->version == 1) {
                gf_bs_write_u64(bs, ptr->creationTime);
                gf_bs_write_u64(bs, ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->trackID);
                gf_bs_write_u32(bs, ptr->reserved1);
                gf_bs_write_u64(bs, ptr->duration);
        } else {
                gf_bs_write_u32(bs, (u32) ptr->creationTime);
                gf_bs_write_u32(bs, (u32) ptr->modificationTime);
                gf_bs_write_u32(bs, ptr->trackID);
                gf_bs_write_u32(bs, ptr->reserved1);
                gf_bs_write_u32(bs, (u32) ptr->duration);
        }
        gf_bs_write_u32(bs, ptr->reserved2[0]);
        gf_bs_write_u32(bs, ptr->reserved2[1]);
        gf_bs_write_u16(bs, ptr->layer);
        gf_bs_write_u16(bs, ptr->alternate_group);
        gf_bs_write_u16(bs, ptr->volume);
        gf_bs_write_u16(bs, ptr->reserved3);
        gf_bs_write_u32(bs, ptr->matrix[0]);
        gf_bs_write_u32(bs, ptr->matrix[1]);
        gf_bs_write_u32(bs, ptr->matrix[2]);
        gf_bs_write_u32(bs, ptr->matrix[3]);
        gf_bs_write_u32(bs, ptr->matrix[4]);
        gf_bs_write_u32(bs, ptr->matrix[5]);
        gf_bs_write_u32(bs, ptr->matrix[6]);
        gf_bs_write_u32(bs, ptr->matrix[7]);
        gf_bs_write_u32(bs, ptr->matrix[8]);
        gf_bs_write_u32(bs, ptr->width);
        gf_bs_write_u32(bs, ptr->height);
        return GF_OK;
}

GF_Err tkhd_Size(GF_Box *s)
{
        GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;

        if (ptr->duration==(u64) -1) ptr->version = 0;
        else ptr->version = (ptr->duration>0xFFFFFFFF) ? 1 : 0;
        ptr->size += (ptr->version == 1) ? 32 : 20;
        ptr->size += 60;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void traf_del(GF_Box *s)
{
        GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;
        if (ptr == NULL) return;
        if (ptr->tfhd) gf_isom_box_del((GF_Box *) ptr->tfhd);
        if (ptr->sdtp) gf_isom_box_del((GF_Box *) ptr->sdtp);
        if (ptr->sub_samples) gf_isom_box_array_del(ptr->sub_samples);
        if (ptr->tfdt) gf_isom_box_del((GF_Box *) ptr->tfdt);
        if (ptr->sample_encryption) gf_isom_box_del((GF_Box *) ptr->sample_encryption);
        gf_isom_box_array_del(ptr->TrackRuns);
        if (ptr->sampleGroups) gf_isom_box_array_del(ptr->sampleGroups);
        if (ptr->sampleGroupsDescription) gf_isom_box_array_del(ptr->sampleGroupsDescription);
        if (ptr->sai_sizes) gf_isom_box_array_del(ptr->sai_sizes);
        if (ptr->sai_offsets) gf_isom_box_array_del(ptr->sai_offsets);
        gf_free(ptr);
}

GF_Err traf_AddBox(GF_Box *s, GF_Box *a)
{
        GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;

        switch (a->type) {
        case GF_ISOM_BOX_TYPE_TFHD:
                if (ptr->tfhd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->tfhd = (GF_TrackFragmentHeaderBox *) a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_TRUN:
                return gf_list_add(ptr->TrackRuns, a);
        case GF_ISOM_BOX_TYPE_SDTP:
                if (ptr->sdtp) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->sdtp = (GF_SampleDependencyTypeBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_TFDT:
                if (ptr->tfdt) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->tfdt = (GF_TFBaseMediaDecodeTimeBox*) a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SUBS:
                if (!ptr->sub_samples) ptr->sub_samples = gf_list_new();
                return gf_list_add(ptr->sub_samples, a);
        case GF_ISOM_BOX_TYPE_SBGP:
                if (!ptr->sampleGroups) ptr->sampleGroups = gf_list_new();
                gf_list_add(ptr->sampleGroups, a);
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SGPD:
                if (!ptr->sampleGroupsDescription) ptr->sampleGroupsDescription = gf_list_new();
                gf_list_add(ptr->sampleGroupsDescription, a);
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SAIZ:
                if (!ptr->sai_sizes) ptr->sai_sizes = gf_list_new();
                gf_list_add(ptr->sai_sizes, a);
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SAIO:
                if (!ptr->sai_offsets) ptr->sai_offsets = gf_list_new();
                gf_list_add(ptr->sai_offsets, a);
                return GF_OK;
        //we will throw an error if both PIFF_PSEC and SENC are found. Not such files seen yet
        case GF_ISOM_BOX_TYPE_UUID:
                if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_PSEC) {
                        if (ptr->sample_encryption) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->sample_encryption = (GF_SampleEncryptionBox *)a;
                        ptr->sample_encryption->traf = ptr;
                        return GF_OK;
                } else {
                        return gf_isom_box_add_default(s, a);
                }
        case GF_ISOM_BOX_TYPE_SENC:
                if (ptr->sample_encryption) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->sample_encryption = (GF_SampleEncryptionBox *)a;
                ptr->sample_encryption->traf = ptr;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err traf_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;
        GF_Err e = gf_isom_box_array_read(s, bs, traf_AddBox);
        if (e) return e;

        if (!ptr->tfhd) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing TrackFragmentHeaderBox \n"));
                return GF_ISOM_INVALID_FILE;
        }
        return GF_OK;
}

GF_Box *traf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackFragmentBox, GF_ISOM_BOX_TYPE_TRAF);
        tmp->TrackRuns = gf_list_new();
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Box *tfxd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_MSSTimeExtBox, GF_ISOM_BOX_TYPE_UUID);
        tmp->internal_4cc = GF_ISOM_BOX_UUID_TFXD;
        return (GF_Box *)tmp;
}

void tfxd_del(GF_Box *s)
{
        gf_free(s);
}


GF_Err tfxd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox *)s;
        if (ptr->size<4) return GF_ISOM_INVALID_FILE;
        ptr->version = gf_bs_read_u8(bs);
        ptr->flags = gf_bs_read_u24(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->version == 0x01) {
                ptr->absolute_time_in_track_timescale = gf_bs_read_u64(bs);
                ptr->fragment_duration_in_track_timescale = gf_bs_read_u64(bs);
        } else {
                ptr->absolute_time_in_track_timescale = gf_bs_read_u32(bs);
                ptr->fragment_duration_in_track_timescale = gf_bs_read_u32(bs);
        }

        return GF_OK;
}

GF_Err tfxd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e = GF_OK;
        GF_MSSTimeExtBox *uuid = (GF_MSSTimeExtBox*)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        gf_bs_write_u8(bs, 1);
        gf_bs_write_u24(bs, 0);
        gf_bs_write_u64(bs, uuid->absolute_time_in_track_timescale);
        gf_bs_write_u64(bs, uuid->fragment_duration_in_track_timescale);

        return GF_OK;
}

GF_Err tfxd_Size(GF_Box *s)
{
        s->size += 20;
        return GF_OK;
}

GF_Err traf_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        //Header first
        if (ptr->tfhd) {
                e = gf_isom_box_write((GF_Box *) ptr->tfhd, bs);
                if (e) return e;
        }
        if (ptr->sub_samples) {
                e = gf_isom_box_array_write(s, ptr->sub_samples, bs);
                if (e) return e;
        }
        if (ptr->tfdt) {
                e = gf_isom_box_write((GF_Box *) ptr->tfdt, bs);
                if (e) return e;
        }
        if (ptr->sdtp) {
                e = gf_isom_box_write((GF_Box *) ptr->sdtp, bs);
                if (e) return e;
        }
        if (ptr->sampleGroupsDescription) {
                e = gf_isom_box_array_write(s, ptr->sampleGroupsDescription, bs);
                if (e) return e;
        }
        if (ptr->sampleGroups) {
                e = gf_isom_box_array_write(s, ptr->sampleGroups, bs);
                if (e) return e;
        }
        if (ptr->sai_sizes) {
                e = gf_isom_box_array_write(s, ptr->sai_sizes, bs);
                if (e) return e;
        }
        if (ptr->sai_offsets) {
                e = gf_isom_box_array_write(s, ptr->sai_offsets, bs);
                if (e) return e;
        }
        e = gf_isom_box_array_write(s, ptr->TrackRuns, bs);
        if (e) return e;

        if (ptr->sample_encryption) {
                e = gf_isom_box_write((GF_Box *) ptr->sample_encryption, bs);
                if (e) return e;
        }
        //tfxd should be last ...
        if (ptr->tfxd) {
                e = gf_isom_box_write((GF_Box *) ptr->tfxd, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err traf_Size(GF_Box *s)
{
        GF_Err e;
        GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;

        if (ptr->tfhd) {
                e = gf_isom_box_size((GF_Box *) ptr->tfhd);
                if (e) return e;
                ptr->size += ptr->tfhd->size;
        }
        if (ptr->sub_samples) {
                e = gf_isom_box_array_size(s, ptr->sub_samples);
                if (e) return e;
        }
        if (ptr->sdtp) {
                e = gf_isom_box_size((GF_Box *) ptr->sdtp);
                if (e) return e;
                ptr->size += ptr->sdtp->size;
        }
        if (ptr->tfdt) {
                e = gf_isom_box_size((GF_Box *) ptr->tfdt);
                if (e) return e;
                ptr->size += ptr->tfdt->size;
        }

        if (ptr->sampleGroups) {
                e = gf_isom_box_array_size(s, ptr->sampleGroups);
                if (e) return e;
        }
        if (ptr->sampleGroupsDescription) {
                e = gf_isom_box_array_size(s, ptr->sampleGroupsDescription);
                if (e) return e;
        }
        if (ptr->sai_sizes) {
                e = gf_isom_box_array_size(s, ptr->sai_sizes);
                if (e) return e;
        }
        if (ptr->sai_offsets) {
                e = gf_isom_box_array_size(s, ptr->sai_offsets);
                if (e) return e;
        }
        if (ptr->sample_encryption) {
                e = gf_isom_box_size((GF_Box *) ptr->sample_encryption);
                if (e) return e;
                ptr->size += ptr->sample_encryption->size;
        }
        if (ptr->tfxd) {
                e = gf_isom_box_size((GF_Box *)ptr->tfxd);
                if (e) return e;
                s->size += ptr->tfxd->size;
        }
        return gf_isom_box_array_size(s, ptr->TrackRuns);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


void trak_del(GF_Box *s)
{
        GF_TrackBox *ptr = (GF_TrackBox *) s;
        if (ptr == NULL) return;

        if (ptr->Header) gf_isom_box_del((GF_Box *)ptr->Header);
        if (ptr->udta) gf_isom_box_del((GF_Box *)ptr->udta);
        if (ptr->Media) gf_isom_box_del((GF_Box *)ptr->Media);
        if (ptr->References) gf_isom_box_del((GF_Box *)ptr->References);
        if (ptr->editBox) gf_isom_box_del((GF_Box *)ptr->editBox);
        if (ptr->meta) gf_isom_box_del((GF_Box *)ptr->meta);
        if (ptr->name) gf_free(ptr->name);
        if (ptr->groups) gf_isom_box_del((GF_Box *)ptr->groups);
        gf_free(ptr);
}

static void gf_isom_check_sample_desc(GF_TrackBox *trak)
{
        GF_BitStream *bs;
        GF_UnknownBox *a;
        u32 i;

        if (!trak->Media || !trak->Media->information) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no media box !\n" ));
                return;
        }
        if (!trak->Media->information->sampleTable) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no sample table !\n" ));
                trak->Media->information->sampleTable = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
        }

        if (!trak->Media->information->sampleTable->SampleDescription) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no sample description box !\n" ));
                trak->Media->information->sampleTable->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSD);
                return;
        }

        i=0;
        while ((a = (GF_UnknownBox*)gf_list_enum(trak->Media->information->sampleTable->SampleDescription->other_boxes, &i))) {
                switch (a->type) {
                case GF_ISOM_BOX_TYPE_MP4S:
                case GF_ISOM_BOX_TYPE_ENCS:
                case GF_ISOM_BOX_TYPE_MP4A:
                case GF_ISOM_BOX_TYPE_ENCA:
                case GF_ISOM_BOX_TYPE_MP4V:
                case GF_ISOM_BOX_TYPE_ENCV:
                case GF_ISOM_BOX_TYPE_RESV:
                case GF_ISOM_SUBTYPE_3GP_AMR:
                case GF_ISOM_SUBTYPE_3GP_AMR_WB:
                case GF_ISOM_SUBTYPE_3GP_EVRC:
                case GF_ISOM_SUBTYPE_3GP_QCELP:
                case GF_ISOM_SUBTYPE_3GP_SMV:
                case GF_ISOM_SUBTYPE_3GP_H263:
                case GF_ISOM_BOX_TYPE_GHNT:
                case GF_ISOM_BOX_TYPE_RTP_STSD:
                case GF_ISOM_BOX_TYPE_SRTP_STSD:
                case GF_ISOM_BOX_TYPE_FDP_STSD:
                case GF_ISOM_BOX_TYPE_RRTP_STSD:
                case GF_ISOM_BOX_TYPE_RTCP_STSD:
                case GF_ISOM_BOX_TYPE_METX:
                case GF_ISOM_BOX_TYPE_METT:
                case GF_ISOM_BOX_TYPE_STXT:
                case GF_ISOM_BOX_TYPE_AVC1:
                case GF_ISOM_BOX_TYPE_AVC2:
                case GF_ISOM_BOX_TYPE_AVC3:
                case GF_ISOM_BOX_TYPE_AVC4:
                case GF_ISOM_BOX_TYPE_SVC1:
                case GF_ISOM_BOX_TYPE_MVC1:
                case GF_ISOM_BOX_TYPE_HVC1:
                case GF_ISOM_BOX_TYPE_HEV1:
                case GF_ISOM_BOX_TYPE_HVC2:
                case GF_ISOM_BOX_TYPE_HEV2:
                case GF_ISOM_BOX_TYPE_HVT1:
                case GF_ISOM_BOX_TYPE_LHV1:
                case GF_ISOM_BOX_TYPE_LHE1:
                case GF_ISOM_BOX_TYPE_TX3G:
                case GF_ISOM_BOX_TYPE_TEXT:
                case GF_ISOM_BOX_TYPE_ENCT:
                case GF_ISOM_BOX_TYPE_DIMS:
                case GF_ISOM_BOX_TYPE_AC3:
                case GF_ISOM_BOX_TYPE_EC3:
                case GF_ISOM_BOX_TYPE_LSR1:
                case GF_ISOM_BOX_TYPE_WVTT:
                case GF_ISOM_BOX_TYPE_STPP:
                case GF_ISOM_BOX_TYPE_SBTT:
                case GF_ISOM_BOX_TYPE_MP3:
                        continue;
                case GF_ISOM_BOX_TYPE_UNKNOWN:
                        break;
                default:
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Unexpected box %s in stsd!\n", gf_4cc_to_str(a->type)));
                        continue;
                }
                //we are sure to have an unknown box here
                assert(a->type==GF_ISOM_BOX_TYPE_UNKNOWN);

                if (!a->data || (a->dataSize<8) ) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Sample description %s does not have at least 8 bytes!\n", gf_4cc_to_str(a->original_4cc) ));
                        continue;
                }
                else if (a->dataSize > a->size) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Sample description %s has wrong data size %d!\n", gf_4cc_to_str(a->original_4cc), a->dataSize));
                        continue;
                }

                /*only process visual or audio*/
                switch (trak->Media->handler->handlerType) {
                case GF_ISOM_MEDIA_VISUAL:
                {
                        GF_GenericVisualSampleEntryBox *genv;
                        /*remove entry*/
                        gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1);
                        genv = (GF_GenericVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV);
                        bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ);
                        genv->size = a->size-8;
                        gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *) genv, bs);

                        if (gf_bs_available(bs)) {
                                u64 pos = gf_bs_get_position(bs);
                                //try to parse as boxes
                                GF_Err e = gf_isom_box_array_read((GF_Box *) genv, bs, gf_isom_box_add_default);
                                if (e) {
                                        gf_bs_seek(bs, pos);
                                        genv->data_size = (u32) gf_bs_available(bs);
                                        if (genv->data_size) {
                                                genv->data = a->data;
                                                a->data = NULL;
                                                memmove(genv->data, genv->data + pos, genv->data_size);
                                        }
                                } else {
                                        genv->data_size = 0;
                                }
                        }
                        gf_bs_del(bs);
                        if (!genv->data_size && genv->data) {
                                gf_free(genv->data);
                                genv->data = NULL;
                        }

                        genv->size = 0;
                        genv->EntryType = a->original_4cc;
                        gf_isom_box_del((GF_Box *)a);
                        gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, genv, i-1);
                }
                break;
                case GF_ISOM_MEDIA_AUDIO:
                {
                        GF_GenericAudioSampleEntryBox *gena;
                        /*remove entry*/
                        gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1);
                        gena = (GF_GenericAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA);
                        gena->size = a->size-8;
                        bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ);
                        gf_isom_audio_sample_entry_read((GF_AudioSampleEntryBox *) gena, bs);

                        if (gf_bs_available(bs)) {
                                u64 pos = gf_bs_get_position(bs);
                                //try to parse as boxes
                                GF_Err e = gf_isom_box_array_read((GF_Box *) gena, bs, gf_isom_box_add_default);
                                if (e) {
                                        gf_bs_seek(bs, pos);
                                        gena->data_size = (u32) gf_bs_available(bs);
                                        if (gena->data_size) {
                                                gena->data = a->data;
                                                a->data = NULL;
                                                memmove(gena->data, gena->data + pos, gena->data_size);
                                        }
                                } else {
                                        gena->data_size = 0;
                                }
                        }
                        gf_bs_del(bs);
                        if (!gena->data_size && gena->data) {
                                gf_free(gena->data);
                                gena->data = NULL;
                        }
                        gena->size = 0;
                        gena->EntryType = a->original_4cc;
                        gf_isom_box_del((GF_Box *)a);
                        gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, gena, i-1);
                }
                break;

                default:
                {
                        GF_Err e;
                        GF_GenericSampleEntryBox *genm;
                        /*remove entry*/
                        gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1);
                        genm = (GF_GenericSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM);
                        genm->size = a->size-8;
                        bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ);

                        e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)genm, bs);
                        if (e) return;

                        genm->size -= 8;

                        if (gf_bs_available(bs)) {
                                u64 pos = gf_bs_get_position(bs);
                                //try to parse as boxes
                                GF_Err e = gf_isom_box_array_read((GF_Box *) genm, bs, gf_isom_box_add_default);
                                if (e) {
                                        gf_bs_seek(bs, pos);
                                        genm->data_size = (u32) gf_bs_available(bs);
                                        if (genm->data_size) {
                                                genm->data = a->data;
                                                a->data = NULL;
                                                memmove(genm->data, genm->data + pos, genm->data_size);
                                        }
                                } else {
                                        genm->data_size = 0;
                                }
                        }
                        gf_bs_del(bs);
                        if (!genm->data_size && genm->data) {
                                gf_free(genm->data);
                                genm->data = NULL;
                        }
                        genm->size = 0;

                        genm->EntryType = a->original_4cc;
                        gf_isom_box_del((GF_Box *)a);
                        gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, genm, i-1);
                }
                break;
                }

        }
}


GF_Err trak_AddBox(GF_Box *s, GF_Box *a)
{
        GF_TrackBox *ptr = (GF_TrackBox *)s;
        if (!a) return GF_OK;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_TKHD:
                if (ptr->Header) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->Header = (GF_TrackHeaderBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_EDTS:
                if (ptr->editBox) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->editBox = (GF_EditBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_UDTA:
                if (ptr->udta) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->udta = (GF_UserDataBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_META:
                if (ptr->meta) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->meta = (GF_MetaBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_TREF:
                if (ptr->References) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->References = (GF_TrackReferenceBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_MDIA:
                if (ptr->Media) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->Media = (GF_MediaBox *)a;
                ((GF_MediaBox *)a)->mediaTrack = ptr;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_TRGR:
                if (ptr->groups) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->groups = (GF_TrackGroupBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_SENC:
                ptr->sample_encryption = (GF_SampleEncryptionBox*)a;
                return gf_isom_box_add_default((GF_Box *)ptr, a);
        case GF_ISOM_BOX_TYPE_UUID:
                if (((GF_UnknownUUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC) {
                        ptr->sample_encryption = (GF_SampleEncryptionBox*) a;
                        return gf_isom_box_add_default((GF_Box *)ptr, a);
                }

        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err trak_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackBox *ptr = (GF_TrackBox *)s;
        e = gf_isom_box_array_read(s, bs, trak_AddBox);
        if (e) return e;
        gf_isom_check_sample_desc(ptr);

        if (!ptr->Header) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing TrackHeaderBox\n"));
                return GF_ISOM_INVALID_FILE;
        }
        if (!ptr->Media) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaBox\n"));
                return GF_ISOM_INVALID_FILE;
        }

        return e;
}

GF_Box *trak_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackBox, GF_ISOM_BOX_TYPE_TRAK);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err trak_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackBox *ptr = (GF_TrackBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        if (ptr->Header) {
                e = gf_isom_box_write((GF_Box *) ptr->Header, bs);
                if (e) return e;
        }
        if (ptr->References) {
                e = gf_isom_box_write((GF_Box *) ptr->References, bs);
                if (e) return e;
        }
        if (ptr->editBox) {
                e = gf_isom_box_write((GF_Box *) ptr->editBox, bs);
                if (e) return e;
        }
        if (ptr->Media) {
                e = gf_isom_box_write((GF_Box *) ptr->Media, bs);
                if (e) return e;
        }
        if (ptr->meta) {
                e = gf_isom_box_write((GF_Box *) ptr->meta, bs);
                if (e) return e;
        }
        if (ptr->groups) {
                e = gf_isom_box_write((GF_Box *) ptr->groups, bs);
                if (e) return e;
        }
        if (ptr->udta) {
                e = gf_isom_box_write((GF_Box *) ptr->udta, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err trak_Size(GF_Box *s)
{
        GF_Err e;
        GF_TrackBox *ptr = (GF_TrackBox *)s;

        if (ptr->Header) {
                e = gf_isom_box_size((GF_Box *) ptr->Header);
                if (e) return e;
                ptr->size += ptr->Header->size;
        }
        if (ptr->udta) {
                e = gf_isom_box_size((GF_Box *) ptr->udta);
                if (e) return e;
                ptr->size += ptr->udta->size;
        }
        if (ptr->References) {
                e = gf_isom_box_size((GF_Box *) ptr->References);
                if (e) return e;
                ptr->size += ptr->References->size;
        }
        if (ptr->editBox) {
                e = gf_isom_box_size((GF_Box *) ptr->editBox);
                if (e) return e;
                ptr->size += ptr->editBox->size;
        }
        if (ptr->Media) {
                e = gf_isom_box_size((GF_Box *) ptr->Media);
                if (e) return e;
                ptr->size += ptr->Media->size;
        }
        if (ptr->meta) {
                e = gf_isom_box_size((GF_Box *) ptr->meta);
                if (e) return e;
                ptr->size += ptr->meta->size;
        }
        if (ptr->groups) {
                e = gf_isom_box_size((GF_Box *) ptr->groups);
                if (e) return e;
                ptr->size += ptr->groups->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void stri_del(GF_Box *s)
{
        GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s;
        if (ptr == NULL) return;
        if (ptr->attribute_list) gf_free(ptr->attribute_list);
        gf_free(ptr);
}

GF_Err stri_Read(GF_Box *s, GF_BitStream *bs)
{
        size_t i;
        GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s;
        ptr->switch_group = gf_bs_read_u16(bs);
        ptr->alternate_group = gf_bs_read_u16(bs);
        ptr->sub_track_id = gf_bs_read_u32(bs);
        ptr->size -= 8;
        ptr->attribute_count = ptr->size / 4;
        GF_SAFE_ALLOC_N(ptr->attribute_list, (size_t)ptr->attribute_count, u32);
        if (!ptr->attribute_list) return GF_OUT_OF_MEM;
        for (i = 0; i < ptr->attribute_count; i++) {
                ptr->attribute_list[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}

GF_Box *stri_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SubTrackInformationBox, GF_ISOM_BOX_TYPE_STRI);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stri_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u16(bs, ptr->switch_group);
        gf_bs_write_u16(bs, ptr->alternate_group);
        gf_bs_write_u32(bs, ptr->sub_track_id);
        for (i = 0; i < ptr->attribute_count; i++) {
                gf_bs_write_u32(bs, ptr->attribute_list[i]);
        }
        return GF_OK;
}

GF_Err stri_Size(GF_Box *s)
{
        GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s;

        ptr->size += 8 + 4 * ptr->attribute_count;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void stsg_del(GF_Box *s)
{
        GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s;
        if (ptr == NULL) return;
        if (ptr->group_description_index) gf_free(ptr->group_description_index);
        gf_free(ptr);
}

GF_Err stsg_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s;
        ISOM_DECREASE_SIZE(s, 6);
        ptr->grouping_type = gf_bs_read_u32(bs);
        ptr->nb_groups = gf_bs_read_u16(bs);
        ISOM_DECREASE_SIZE(s, ptr->nb_groups*4);
        GF_SAFE_ALLOC_N(ptr->group_description_index, ptr->nb_groups, u32);
        if (!ptr->group_description_index) return GF_OUT_OF_MEM;
        for (i = 0; i < ptr->nb_groups; i++) {
                ptr->group_description_index[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}

GF_Box *stsg_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SubTrackSampleGroupBox, GF_ISOM_BOX_TYPE_STSG);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stsg_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->grouping_type);
        gf_bs_write_u16(bs, ptr->nb_groups);
        for (i = 0; i < ptr->nb_groups; i++) {
                gf_bs_write_u32(bs, ptr->group_description_index[i]);
        }
        return GF_OK;
}

GF_Err stsg_Size(GF_Box *s)
{
        GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s;
        ptr->size += 6 + 4 * ptr->nb_groups;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void strk_del(GF_Box *s)
{
        GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;
        if (ptr == NULL) return;
        if (ptr->info) gf_isom_box_del((GF_Box *)ptr->info);
        gf_free(ptr);
}

GF_Err strk_AddBox(GF_Box *s, GF_Box *a)
{
        GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;
        if (!a) return GF_OK;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_STRI:
                if (ptr->info) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->info = (GF_SubTrackInformationBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_STRD:
                if (ptr->strd) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->strd = a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}


GF_Err strk_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;
        e = gf_isom_box_array_read(s, bs, strk_AddBox);
        if (e) return e;

        if (!ptr->info) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing SubTrackInformationBox\n"));
                return GF_ISOM_INVALID_FILE;
        }
        return e;
}

GF_Box *strk_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SubTrackBox, GF_ISOM_BOX_TYPE_STRK);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err strk_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        if (ptr->info) {
                e = gf_isom_box_write((GF_Box *)ptr->info, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err strk_Size(GF_Box *s)
{
        GF_Err e;
        GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;

        if (ptr->info) {
                e = gf_isom_box_size((GF_Box *)ptr->info);
                if (e) return e;
                ptr->size += ptr->info->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Err tref_AddBox(GF_Box *ptr, GF_Box *a)
{
        return gf_isom_box_add_default(ptr, a);
}

void tref_del(GF_Box *s)
{
        GF_TrackReferenceBox *ptr = (GF_TrackReferenceBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err tref_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read_ex(s, bs, gf_isom_box_add_default, s->type);
}

GF_Box *tref_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackReferenceBox, GF_ISOM_BOX_TYPE_TREF);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err tref_Write(GF_Box *s, GF_BitStream *bs)
{
//      GF_TrackReferenceBox *ptr = (GF_TrackReferenceBox *)s;
        return gf_isom_box_write_header(s, bs);
}

GF_Err tref_Size(GF_Box *s)
{
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void reftype_del(GF_Box *s)
{
        GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s;
        if (!ptr) return;
        if (ptr->trackIDs) gf_free(ptr->trackIDs);
        gf_free(ptr);
}


GF_Err reftype_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 bytesToRead;
        u32 i;
        GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s;

        bytesToRead = (u32) (ptr->size);
        if (!bytesToRead) return GF_OK;

        ptr->trackIDCount = (u32) (bytesToRead) / sizeof(u32);
        ptr->trackIDs = (u32 *) gf_malloc(ptr->trackIDCount * sizeof(u32));
        if (!ptr->trackIDs) return GF_OUT_OF_MEM;

        for (i = 0; i < ptr->trackIDCount; i++) {
                ptr->trackIDs[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}

GF_Box *reftype_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackReferenceTypeBox, GF_ISOM_BOX_TYPE_REFT);
        return (GF_Box *)tmp;
}


GF_Err reftype_AddRefTrack(GF_TrackReferenceTypeBox *ref, u32 trackID, u16 *outRefIndex)
{
        u32 i;
        if (!ref || !trackID) return GF_BAD_PARAM;

        if (outRefIndex) *outRefIndex = 0;
        //don't add a dep if already here !!
        for (i = 0; i < ref->trackIDCount; i++) {
                if (ref->trackIDs[i] == trackID) {
                        if (outRefIndex) *outRefIndex = i+1;
                        return GF_OK;
                }
        }

        ref->trackIDs = (u32 *) gf_realloc(ref->trackIDs, (ref->trackIDCount + 1) * sizeof(u32) );
        if (!ref->trackIDs) return GF_OUT_OF_MEM;
        ref->trackIDs[ref->trackIDCount] = trackID;
        ref->trackIDCount++;
        if (outRefIndex) *outRefIndex = ref->trackIDCount;
        return GF_OK;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err reftype_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s;
        ptr->type = ptr->reference_type;
        if (!ptr->trackIDCount) return GF_OK;

        e = gf_isom_box_write_header(s, bs);
        ptr->type = GF_ISOM_BOX_TYPE_REFT;
        if (e) return e;
        for (i = 0; i < ptr->trackIDCount; i++) {
                gf_bs_write_u32(bs, ptr->trackIDs[i]);
        }
        return GF_OK;
}


GF_Err reftype_Size(GF_Box *s)
{
        GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s;
        if (!ptr->trackIDCount)
                ptr->size=0;
        else
                ptr->size += (ptr->trackIDCount * sizeof(u32));
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void trex_del(GF_Box *s)
{
        GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err trex_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s;

        ptr->trackID = gf_bs_read_u32(bs);
        ptr->def_sample_desc_index = gf_bs_read_u32(bs);
        ptr->def_sample_duration = gf_bs_read_u32(bs);
        ptr->def_sample_size = gf_bs_read_u32(bs);
        ptr->def_sample_flags = gf_bs_read_u32(bs);

        if (!ptr->def_sample_desc_index) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] TREX with default sample description set to 0, likely broken ! Fixing to 1\n" ));
                ptr->def_sample_desc_index = 1;
        }
        return GF_OK;
}

GF_Box *trex_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackExtendsBox, GF_ISOM_BOX_TYPE_TREX);
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err trex_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->trackID);
        gf_bs_write_u32(bs, ptr->def_sample_desc_index);
        gf_bs_write_u32(bs, ptr->def_sample_duration);
        gf_bs_write_u32(bs, ptr->def_sample_size);
        gf_bs_write_u32(bs, ptr->def_sample_flags);
        return GF_OK;
}

GF_Err trex_Size(GF_Box *s)
{
        GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s;
        ptr->size += 20;
        return GF_OK;
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/



void trep_del(GF_Box *s)
{
        GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err trep_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s;

        ptr->trackID = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        return gf_isom_box_array_read(s, bs, gf_isom_box_add_default);
}

GF_Box *trep_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackExtensionPropertiesBox, GF_ISOM_BOX_TYPE_TREP);
        tmp->other_boxes = gf_list_new();
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err trep_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->trackID);
        return GF_OK;
}

GF_Err trep_Size(GF_Box *s)
{
        GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s;
        ptr->size += 4;
        return GF_OK;
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/



#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

void trun_del(GF_Box *s)
{
        GF_TrunEntry *p;
        GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s;
        if (ptr == NULL) return;

        while (gf_list_count(ptr->entries)) {
                p = (GF_TrunEntry*)gf_list_get(ptr->entries, 0);
                gf_list_rem(ptr->entries, 0);
                gf_free(p);
        }
        gf_list_del(ptr->entries);
        if (ptr->cache) gf_bs_del(ptr->cache);
        gf_free(ptr);
}

GF_Err trun_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_TrunEntry *p;
        GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s;

        //check this is a good file
        if ((ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) && (ptr->flags & GF_ISOM_TRUN_FLAGS))
                return GF_ISOM_INVALID_FILE;

        ptr->sample_count = gf_bs_read_u32(bs);

        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) {
                ptr->data_offset = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 4);
        }
        if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) {
                ptr->first_sample_flags = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 4);
        }

        //read each entry (even though nothing may be written)
        for (i=0; i<ptr->sample_count; i++) {
                u32 trun_size = 0;
                p = (GF_TrunEntry *) gf_malloc(sizeof(GF_TrunEntry));
                if (!p) return GF_OUT_OF_MEM;
                memset(p, 0, sizeof(GF_TrunEntry));

                if (ptr->flags & GF_ISOM_TRUN_DURATION) {
                        p->Duration = gf_bs_read_u32(bs);
                        trun_size += 4;
                }
                if (ptr->flags & GF_ISOM_TRUN_SIZE) {
                        p->size = gf_bs_read_u32(bs);
                        trun_size += 4;
                }
                //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED
                if (ptr->flags & GF_ISOM_TRUN_FLAGS) {
                        p->flags = gf_bs_read_u32(bs);
                        trun_size += 4;
                }
                if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) {
                        if (ptr->version==0) {
                                p->CTS_Offset = (u32) gf_bs_read_u32(bs);
                        } else {
                                p->CTS_Offset = (s32) gf_bs_read_u32(bs);
                        }
                }
                gf_list_add(ptr->entries, p);
                ISOM_DECREASE_SIZE(ptr, trun_size);
        }
        return GF_OK;
}

GF_Box *trun_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackFragmentRunBox, GF_ISOM_BOX_TYPE_TRUN);
        tmp->entries = gf_list_new();
        //NO FLAGS SET BY DEFAULT
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err trun_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_TrunEntry *p;
        GF_Err e;
        u32 i, count;
        GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->sample_count);

        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) {
                gf_bs_write_u32(bs, ptr->data_offset);
        }
        if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) {
                gf_bs_write_u32(bs, ptr->first_sample_flags);
        }

        //if nothing to do, this will be skipped automatically
        count = gf_list_count(ptr->entries);
        for (i=0; i<count; i++) {
                p = (GF_TrunEntry*)gf_list_get(ptr->entries, i);

                if (ptr->flags & GF_ISOM_TRUN_DURATION) {
                        gf_bs_write_u32(bs, p->Duration);
                }
                if (ptr->flags & GF_ISOM_TRUN_SIZE) {
                        gf_bs_write_u32(bs, p->size);
                }
                //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED
                if (ptr->flags & GF_ISOM_TRUN_FLAGS) {
                        gf_bs_write_u32(bs, p->flags);
                }
                if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) {
                        if (ptr->version==0) {
                                gf_bs_write_u32(bs, p->CTS_Offset);
                        } else {
                                gf_bs_write_u32(bs, (u32) p->CTS_Offset);
                        }
                }
        }
        return GF_OK;
}

GF_Err trun_Size(GF_Box *s)
{
        u32 i, count;
        GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s;

        ptr->size += 4;
        //The rest depends on the flags
        if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) ptr->size += 4;
        if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) ptr->size += 4;

        //if nothing to do, this will be skipped automatically
        count = gf_list_count(ptr->entries);
        for (i=0; i<count; i++) {
                if (ptr->flags & GF_ISOM_TRUN_DURATION) ptr->size += 4;
                if (ptr->flags & GF_ISOM_TRUN_SIZE) ptr->size += 4;
                //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED
                if (ptr->flags & GF_ISOM_TRUN_FLAGS) ptr->size += 4;
                if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) ptr->size += 4;
        }

        return GF_OK;
}



#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


void tsro_del(GF_Box *s)
{
        GF_TimeOffHintEntryBox *tsro = (GF_TimeOffHintEntryBox *)s;
        gf_free(tsro);
}

GF_Err tsro_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TimeOffHintEntryBox *ptr = (GF_TimeOffHintEntryBox *)s;
        ptr->TimeOffset = gf_bs_read_u32(bs);
        return GF_OK;
}

GF_Box *tsro_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TimeOffHintEntryBox, GF_ISOM_BOX_TYPE_TSRO);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tsro_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TimeOffHintEntryBox *ptr = (GF_TimeOffHintEntryBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->TimeOffset);
        return GF_OK;
}

GF_Err tsro_Size(GF_Box *s)
{
        s->size += 4;
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


void udta_del(GF_Box *s)
{
        u32 i;
        GF_UserDataMap *map;
        GF_UserDataBox *ptr = (GF_UserDataBox *)s;
        if (ptr == NULL) return;
        i=0;
        while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
                gf_isom_box_array_del(map->other_boxes);
                gf_free(map);
        }
        gf_list_del(ptr->recordList);
        gf_free(ptr);
}

GF_UserDataMap *udta_getEntry(GF_UserDataBox *ptr, u32 box_type, bin128 *uuid)
{
        u32 i;
        GF_UserDataMap *map;
        if (ptr == NULL) return NULL;
        i=0;
        while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
                if (map->boxType == box_type) {
                        if ((box_type != GF_ISOM_BOX_TYPE_UUID) || !uuid) return map;
                        if (!memcmp(map->uuid, *uuid, 16)) return map;
                }
        }
        return NULL;
}

GF_Err udta_AddBox(GF_Box *s, GF_Box *a)
{
        GF_Err e;
        u32 box_type;
        GF_UserDataMap *map;
        GF_UserDataBox *ptr = (GF_UserDataBox *)s;
        if (!ptr) return GF_BAD_PARAM;
        if (!a) return GF_OK;

        /* for unknown udta boxes, we reference them by their original box type */
        box_type = a->type;
        if (box_type == GF_ISOM_BOX_TYPE_UNKNOWN) {
                GF_UnknownBox* unkn = (GF_UnknownBox *)a;
                if (unkn)
                        box_type = unkn->original_4cc;
        }

        map = udta_getEntry(ptr, box_type, (a->type==GF_ISOM_BOX_TYPE_UUID) ? & ((GF_UUIDBox *)a)->uuid : NULL);
        if (map == NULL) {
                map = (GF_UserDataMap *) gf_malloc(sizeof(GF_UserDataMap));
                if (map == NULL) return GF_OUT_OF_MEM;
                memset(map, 0, sizeof(GF_UserDataMap));

                map->boxType = box_type;
                if (a->type == GF_ISOM_BOX_TYPE_UUID)
                        memcpy(map->uuid, ((GF_UUIDBox *)a)->uuid, 16);
                map->other_boxes = gf_list_new();
                if (!map->other_boxes) {
                        gf_free(map);
                        return GF_OUT_OF_MEM;
                }
                e = gf_list_add(ptr->recordList, map);
                if (e) return e;
        }
        return gf_list_add(map->other_boxes, a);
}


GF_Err udta_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, udta_AddBox);
}

GF_Box *udta_New()
{
        ISOM_DECL_BOX_ALLOC(GF_UserDataBox, GF_ISOM_BOX_TYPE_UDTA);
        tmp->recordList = gf_list_new();
        if (!tmp->recordList) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err udta_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_UserDataMap *map;
        GF_UserDataBox *ptr = (GF_UserDataBox *)s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        i=0;
        while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
                //warning: here we are not passing the actual "parent" of the list
                //but the UDTA box. The parent itself is not an box, we don't care about it
                e = gf_isom_box_array_write(s, map->other_boxes, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err udta_Size(GF_Box *s)
{
        GF_Err e;
        u32 i;
        GF_UserDataMap *map;
        GF_UserDataBox *ptr = (GF_UserDataBox *)s;

        i=0;
        while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
                //warning: here we are not passing the actual "parent" of the list
                //but the UDTA box. The parent itself is not an box, we don't care about it
                e = gf_isom_box_array_size(s, map->other_boxes);
                if (e) return e;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void vmhd_del(GF_Box *s)
{
        GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err vmhd_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s;

        ptr->reserved = gf_bs_read_u64(bs);
        return GF_OK;
}

GF_Box *vmhd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_VideoMediaHeaderBox, GF_ISOM_BOX_TYPE_VMHD);
        tmp->flags = 1;
        return (GF_Box *)tmp;
}



#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err vmhd_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u64(bs, ptr->reserved);
        return GF_OK;
}

GF_Err vmhd_Size(GF_Box *s)
{
        GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s;
        ptr->size += 8;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void void_del(GF_Box *s)
{
        gf_free(s);
}


GF_Err void_Read(GF_Box *s, GF_BitStream *bs)
{
        if (s->size) return GF_ISOM_INVALID_FILE;
        return GF_OK;
}

GF_Box *void_New()
{
        ISOM_DECL_BOX_ALLOC(GF_Box, GF_ISOM_BOX_TYPE_VOID);
        return tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err void_Write(GF_Box *s, GF_BitStream *bs)
{
        gf_bs_write_u32(bs, 0);
        return GF_OK;
}

GF_Err void_Size(GF_Box *s)
{
        s->size = 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *pdin_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ProgressiveDownloadBox, GF_ISOM_BOX_TYPE_PDIN);
        tmp->flags = 1;
        return (GF_Box *)tmp;
}


void pdin_del(GF_Box *s)
{
        GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox*)s;
        if (ptr == NULL) return;
        if (ptr->rates) gf_free(ptr->rates);
        if (ptr->times) gf_free(ptr->times);
        gf_free(ptr);
}


GF_Err pdin_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox*)s;

        ptr->count = (u32) (ptr->size) / 8;
        ptr->rates = (u32*)gf_malloc(sizeof(u32)*ptr->count);
        ptr->times = (u32*)gf_malloc(sizeof(u32)*ptr->count);
        for (i=0; i<ptr->count; i++) {
                ptr->rates[i] = gf_bs_read_u32(bs);
                ptr->times[i] = gf_bs_read_u32(bs);
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err pdin_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        for (i=0; i<ptr->count; i++) {
                gf_bs_write_u32(bs, ptr->rates[i]);
                gf_bs_write_u32(bs, ptr->times[i]);
        }
        return GF_OK;
}

GF_Err pdin_Size(GF_Box *s)
{
        GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox *)s;
        ptr->size += 8*ptr->count;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/




GF_Box *sdtp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleDependencyTypeBox, GF_ISOM_BOX_TYPE_SDTP);
        tmp->flags = 1;
        return (GF_Box *)tmp;
}


void sdtp_del(GF_Box *s)
{
        GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox*)s;
        if (ptr == NULL) return;
        if (ptr->sample_info) gf_free(ptr->sample_info);
        gf_free(ptr);
}


GF_Err sdtp_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox*)s;

        /*out-of-order sdtp, assume no padding at the end*/
        if (!ptr->sampleCount) ptr->sampleCount = (u32) ptr->size;
        else if (ptr->sampleCount > (u32) ptr->size) return GF_ISOM_INVALID_FILE;

        ptr->sample_info = (u8 *) gf_malloc(sizeof(u8)*ptr->sampleCount);
        gf_bs_read_data(bs, (char*)ptr->sample_info, ptr->sampleCount);
        ISOM_DECREASE_SIZE(ptr, ptr->sampleCount);
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err sdtp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox *)s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_data(bs, (char*)ptr->sample_info, ptr->sampleCount);
        return GF_OK;
}

GF_Err sdtp_Size(GF_Box *s)
{
        GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox *)s;
        ptr->size += ptr->sampleCount;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *pasp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_PixelAspectRatioBox, GF_ISOM_BOX_TYPE_PASP);
        return (GF_Box *)tmp;
}


void pasp_del(GF_Box *s)
{
        GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox*)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err pasp_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox*)s;
        ptr->hSpacing = gf_bs_read_u32(bs);
        ptr->vSpacing = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 8);
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err pasp_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox *)s;
        GF_Err e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->hSpacing);
        gf_bs_write_u32(bs, ptr->vSpacing);
        return GF_OK;
}

GF_Err pasp_Size(GF_Box *s)
{
        s->size += 8;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *clap_New()
{
        ISOM_DECL_BOX_ALLOC(GF_CleanAppertureBox, GF_ISOM_BOX_TYPE_CLAP);
        return (GF_Box *)tmp;
}


void clap_del(GF_Box *s)
{
        GF_CleanAppertureBox *ptr = (GF_CleanAppertureBox*)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}


GF_Err clap_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_CleanAppertureBox *ptr = (GF_CleanAppertureBox*)s;
        ISOM_DECREASE_SIZE(ptr, 32);
        ptr->cleanApertureWidthN = gf_bs_read_u32(bs);
        ptr->cleanApertureWidthD = gf_bs_read_u32(bs);
        ptr->cleanApertureHeightN = gf_bs_read_u32(bs);
        ptr->cleanApertureHeightD = gf_bs_read_u32(bs);
        ptr->horizOffN = gf_bs_read_u32(bs);
        ptr->horizOffD = gf_bs_read_u32(bs);
        ptr->vertOffN = gf_bs_read_u32(bs);
        ptr->vertOffD = gf_bs_read_u32(bs);
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err clap_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_CleanAppertureBox *ptr = (GF_CleanAppertureBox *)s;
        GF_Err e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->cleanApertureWidthN);
        gf_bs_write_u32(bs, ptr->cleanApertureWidthD);
        gf_bs_write_u32(bs, ptr->cleanApertureHeightN);
        gf_bs_write_u32(bs, ptr->cleanApertureHeightD);
        gf_bs_write_u32(bs, ptr->horizOffN);
        gf_bs_write_u32(bs, ptr->horizOffD);
        gf_bs_write_u32(bs, ptr->vertOffN);
        gf_bs_write_u32(bs, ptr->vertOffD);
        return GF_OK;
}

GF_Err clap_Size(GF_Box *s)
{
        s->size += 32;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/




GF_Box *metx_New()
{
        //type is overridden by the box constructor
        ISOM_DECL_BOX_ALLOC(GF_MetaDataSampleEntryBox, GF_ISOM_BOX_TYPE_METX);
        gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}


void metx_del(GF_Box *s)
{
        GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox*)s;
        if (ptr == NULL) return;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

        if (ptr->content_encoding) gf_free(ptr->content_encoding);
        if (ptr->xml_namespace) gf_free(ptr->xml_namespace);
        if (ptr->xml_schema_loc) gf_free(ptr->xml_schema_loc);
        if (ptr->mime_type) gf_free(ptr->mime_type);
        if (ptr->config) gf_isom_box_del((GF_Box *)ptr->config);
        gf_free(ptr);
}


GF_Err metx_AddBox(GF_Box *s, GF_Box *a)
{
        GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_SINF:
                gf_list_add(ptr->protections, a);
                break;
        case GF_ISOM_BOX_TYPE_TXTC:
                //we allow the config box on metx
                if (ptr->config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->config = (GF_TextConfigBox *)a;
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err metx_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 size, i;
        GF_Err e;
        char *str;
        GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox*)s;

        e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
        if (e) return e;

        size = (u32) ptr->size - 8;
        str = gf_malloc(sizeof(char)*size);

        i=0;

        while (size) {
                str[i] = gf_bs_read_u8(bs);
                size--;
                if (!str[i])
                        break;
                i++;
        }
        if (i) {
                if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
                        ptr->xml_namespace = gf_strdup(str);
                } else {
                        ptr->content_encoding = gf_strdup(str);
                }
        }

        i=0;
        while (size) {
                str[i] = gf_bs_read_u8(bs);
                size--;
                if (!str[i])
                        break;
                i++;
        }
        if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) {
                if (i) {
                        if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
                                ptr->xml_schema_loc = gf_strdup(str);
                        } else {
                                ptr->xml_namespace = gf_strdup(str);
                        }
                }

                i=0;
                while (size) {
                        str[i] = gf_bs_read_u8(bs);
                        size--;
                        if (!str[i])
                                break;
                        i++;
                }
                if (i) {
                        if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
                                ptr->mime_type = gf_strdup(str);
                        } else {
                                ptr->xml_schema_loc = gf_strdup(str);
                        }
                }
        }
        //mett, sbtt, stxt, stpp
        else {
                if (i) ptr->mime_type = gf_strdup(str);
        }
        ptr->size = size;
        gf_free(str);
        return gf_isom_box_array_read(s, bs, metx_AddBox);
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err metx_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s;
        GF_Err e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        gf_bs_write_data(bs, ptr->reserved, 6);
        gf_bs_write_u16(bs, ptr->dataReferenceIndex);

        if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) {
                if (ptr->content_encoding)
                        gf_bs_write_data(bs, ptr->content_encoding, (u32) strlen(ptr->content_encoding));
                gf_bs_write_u8(bs, 0);
        }

        if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) {
                if (ptr->xml_namespace)
                        gf_bs_write_data(bs, ptr->xml_namespace, (u32) strlen(ptr->xml_namespace));

                gf_bs_write_u8(bs, 0);

                if (ptr->xml_schema_loc)
                        gf_bs_write_data(bs, ptr->xml_schema_loc, (u32) strlen(ptr->xml_schema_loc));
                gf_bs_write_u8(bs, 0);

                if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
                        if (ptr->mime_type)
                                gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type));

                        gf_bs_write_u8(bs, 0);
                }
        }
        //mett, sbtt, stxt
        else {
                if (ptr->mime_type)
                        gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type));

                gf_bs_write_u8(bs, 0);

                if (ptr->config) {
                        gf_isom_box_write((GF_Box *)ptr->config, bs);
                }
        }

        return gf_isom_box_array_write(s, ptr->protections, bs);
}

GF_Err metx_Size(GF_Box *s)
{
        GF_Err e;
        GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s;
        ptr->size += 8;

        if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) {
                if (ptr->content_encoding)
                        ptr->size += strlen(ptr->content_encoding);
                ptr->size++;
        }

        if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) {

                if (ptr->xml_namespace)
                        ptr->size += strlen(ptr->xml_namespace);
                ptr->size++;

                if (ptr->xml_schema_loc)
                        ptr->size += strlen(ptr->xml_schema_loc);
                ptr->size++;

                if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
                        if (ptr->mime_type)
                                ptr->size += strlen(ptr->mime_type);
                        ptr->size++;
                }

        }
        //mett, sbtt, stxt
        else {
                if (ptr->mime_type)
                        ptr->size += strlen(ptr->mime_type);
                ptr->size++;

                if (ptr->config) {
                        e = gf_isom_box_size((GF_Box *)ptr->config);
                        if (e) return e;
                        ptr->size += ptr->config->size;
                }
        }
        return gf_isom_box_array_size(s, ptr->protections);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


/* SimpleTextSampleEntry */
GF_Box *txtc_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TextConfigBox, GF_ISOM_BOX_TYPE_TXTC);
        return (GF_Box *)tmp;
}


void txtc_del(GF_Box *s)
{
        GF_TextConfigBox *ptr = (GF_TextConfigBox*)s;
        if (ptr == NULL) return;

        if (ptr->config) gf_free(ptr->config);
        gf_free(ptr);
}

GF_Err txtc_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 size, i;
        char *str;
        GF_TextConfigBox *ptr = (GF_TextConfigBox*)s;

        size = (u32) ptr->size;
        str = (char *)gf_malloc(sizeof(char)*size);

        i=0;

        while (size) {
                str[i] = gf_bs_read_u8(bs);
                size--;
                if (!str[i])
                        break;
                i++;
        }
        if (i) ptr->config = gf_strdup(str);
        gf_free(str);

        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err txtc_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_TextConfigBox *ptr = (GF_TextConfigBox *)s;
        GF_Err e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        if (ptr->config)
                gf_bs_write_data(bs, ptr->config, (u32) strlen(ptr->config));
        gf_bs_write_u8(bs, 0);
        return GF_OK;
}

GF_Err txtc_Size(GF_Box *s)
{
        GF_TextConfigBox *ptr = (GF_TextConfigBox *)s;
        if (ptr->config)
                ptr->size += strlen(ptr->config);
        ptr->size++;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Box *dac3_New()
{
        ISOM_DECL_BOX_ALLOC(GF_AC3ConfigBox, GF_ISOM_BOX_TYPE_DAC3);
        return (GF_Box *)tmp;
}

GF_Box *dec3_New()
{
        ISOM_DECL_BOX_ALLOC(GF_AC3ConfigBox, GF_ISOM_BOX_TYPE_DAC3);
        tmp->cfg.is_ec3 = 1;
        return (GF_Box *)tmp;
}

void dac3_del(GF_Box *s)
{
        GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s;
        gf_free(ptr);
}


GF_Err dac3_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s;
        if (ptr == NULL) return GF_BAD_PARAM;

        if (ptr->cfg.is_ec3) {
                u32 i;
                ptr->cfg.brcode = gf_bs_read_int(bs, 13);
                ptr->cfg.nb_streams = gf_bs_read_int(bs, 3) + 1;
                for (i=0; i<ptr->cfg.nb_streams; i++) {
                        ptr->cfg.streams[i].fscod = gf_bs_read_int(bs, 2);
                        ptr->cfg.streams[i].bsid = gf_bs_read_int(bs, 5);
                        ptr->cfg.streams[i].bsmod = gf_bs_read_int(bs, 5);
                        ptr->cfg.streams[i].acmod = gf_bs_read_int(bs, 3);
                        ptr->cfg.streams[i].lfon = gf_bs_read_int(bs, 1);
                        gf_bs_read_int(bs, 3);
                        ptr->cfg.streams[i].nb_dep_sub = gf_bs_read_int(bs, 4);
                        if (ptr->cfg.streams[i].nb_dep_sub) {
                                ptr->cfg.streams[i].chan_loc = gf_bs_read_int(bs, 9);
                        } else {
                                gf_bs_read_int(bs, 1);
                        }
                }
        } else {
                ptr->cfg.nb_streams = 1;
                ptr->cfg.streams[0].fscod = gf_bs_read_int(bs, 2);
                ptr->cfg.streams[0].bsid = gf_bs_read_int(bs, 5);
                ptr->cfg.streams[0].bsmod = gf_bs_read_int(bs, 3);
                ptr->cfg.streams[0].acmod = gf_bs_read_int(bs, 3);
                ptr->cfg.streams[0].lfon = gf_bs_read_int(bs, 1);
                ptr->cfg.brcode = gf_bs_read_int(bs, 5);
                gf_bs_read_int(bs, 5);
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err dac3_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s;

        if (ptr->cfg.is_ec3) s->type = GF_ISOM_BOX_TYPE_DEC3;
        e = gf_isom_box_write_header(s, bs);
        if (ptr->cfg.is_ec3) s->type = GF_ISOM_BOX_TYPE_DAC3;
        if (e) return e;

        if (ptr->cfg.is_ec3) {
                u32 i;
                gf_bs_write_int(bs, ptr->cfg.brcode, 13);
                gf_bs_write_int(bs, ptr->cfg.nb_streams - 1, 3);
                for (i=0; i<ptr->cfg.nb_streams; i++) {
                        gf_bs_write_int(bs, ptr->cfg.streams[i].fscod, 2);
                        gf_bs_write_int(bs, ptr->cfg.streams[i].bsid, 5);
                        gf_bs_write_int(bs, ptr->cfg.streams[i].bsmod, 5);
                        gf_bs_write_int(bs, ptr->cfg.streams[i].acmod, 3);
                        gf_bs_write_int(bs, ptr->cfg.streams[i].lfon, 1);
                        gf_bs_write_int(bs, 0, 3);
                        gf_bs_write_int(bs, ptr->cfg.streams[i].nb_dep_sub, 4);
                        if (ptr->cfg.streams[i].nb_dep_sub) {
                                gf_bs_write_int(bs, ptr->cfg.streams[i].chan_loc, 9);
                        } else {
                                gf_bs_write_int(bs, 0, 1);
                        }
                }
        } else {
                gf_bs_write_int(bs, ptr->cfg.streams[0].fscod, 2);
                gf_bs_write_int(bs, ptr->cfg.streams[0].bsid, 5);
                gf_bs_write_int(bs, ptr->cfg.streams[0].bsmod, 3);
                gf_bs_write_int(bs, ptr->cfg.streams[0].acmod, 3);
                gf_bs_write_int(bs, ptr->cfg.streams[0].lfon, 1);
                gf_bs_write_int(bs, ptr->cfg.brcode, 5);
                gf_bs_write_int(bs, 0, 5);
        }
        return GF_OK;
}

GF_Err dac3_Size(GF_Box *s)
{
        GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s;

        if (ptr->cfg.is_ec3) {
                u32 i;
                s->size += 2;
                for (i=0; i<ptr->cfg.nb_streams; i++) {
                        s->size += 3;
                        if (ptr->cfg.streams[i].nb_dep_sub)
                                s->size += 1;
                }
        } else {
                s->size += 3;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



void lsrc_del(GF_Box *s)
{
        GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s;
        if (ptr == NULL) return;
        if (ptr->hdr) gf_free(ptr->hdr);
        gf_free(ptr);
}


GF_Err lsrc_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s;
        ptr->hdr_size = (u32) ptr->size;
        ptr->hdr = gf_malloc(sizeof(char)*ptr->hdr_size);
        gf_bs_read_data(bs, ptr->hdr, ptr->hdr_size);
        return GF_OK;
}

GF_Box *lsrc_New()
{
        ISOM_DECL_BOX_ALLOC(GF_LASERConfigurationBox, GF_ISOM_BOX_TYPE_LSRC);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err lsrc_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        gf_bs_write_data(bs, ptr->hdr, ptr->hdr_size);
        return GF_OK;
}

GF_Err lsrc_Size(GF_Box *s)
{
        GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s;
        ptr->size += ptr->hdr_size;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void lsr1_del(GF_Box *s)
{
        GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
        if (ptr == NULL) return;
        gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

        if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
        if (ptr->lsr_config) gf_isom_box_del((GF_Box *) ptr->lsr_config);
        if (ptr->descr) gf_isom_box_del((GF_Box *) ptr->descr);
        gf_free(ptr);
}

GF_Err lsr1_AddBox(GF_Box *s, GF_Box *a)
{
        GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
        switch (a->type) {
        case GF_ISOM_BOX_TYPE_LSRC:
                if (ptr->lsr_config) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->lsr_config = (GF_LASERConfigurationBox *)a;
                break;
        case GF_ISOM_BOX_TYPE_M4DS:
                if (ptr->descr) ERROR_ON_DUPLICATED_BOX(a, ptr)
                        ptr->descr = (GF_MPEG4ExtensionDescriptorsBox *)a;
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err lsr1_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox*)s;

        e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
        if (e) return e;

        ISOM_DECREASE_SIZE(ptr, 8);

        return gf_isom_box_array_read(s, bs, lsr1_AddBox);
}

GF_Box *lsr1_New()
{
        ISOM_DECL_BOX_ALLOC(GF_LASeRSampleEntryBox, GF_ISOM_BOX_TYPE_LSR1);
        gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err lsr1_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        gf_bs_write_data(bs, ptr->reserved, 6);
        gf_bs_write_u16(bs, ptr->dataReferenceIndex);
        if (ptr->lsr_config) {
                e = gf_isom_box_write((GF_Box *)ptr->lsr_config, bs);
                if (e) return e;
        }
        if (ptr->descr) {
                e = gf_isom_box_write((GF_Box *)ptr->descr, bs);
                if (e) return e;
        }
        return e;
}

GF_Err lsr1_Size(GF_Box *s)
{
        GF_Err e;
        GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;

        s->size += 8;
        if (ptr->lsr_config) {
                e = gf_isom_box_size((GF_Box *)ptr->lsr_config);
                if (e) return e;
                ptr->size += ptr->lsr_config->size;
        }
        if (ptr->descr) {
                e = gf_isom_box_size((GF_Box *)ptr->descr);
                if (e) return e;
                ptr->size += ptr->descr->size;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void sidx_del(GF_Box *s)
{
        GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox *) s;
        if (ptr == NULL) return;
        if (ptr->refs) gf_free(ptr->refs);
        gf_free(ptr);
}

GF_Err sidx_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 i;
        GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s;

        ptr->reference_ID = gf_bs_read_u32(bs);
        ptr->timescale = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 8);

        if (ptr->version==0) {
                ptr->earliest_presentation_time = gf_bs_read_u32(bs);
                ptr->first_offset = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 8);
        } else {
                ptr->earliest_presentation_time = gf_bs_read_u64(bs);
                ptr->first_offset = gf_bs_read_u64(bs);
                ISOM_DECREASE_SIZE(ptr, 16);
        }
        gf_bs_read_u16(bs); /* reserved */
        ptr->nb_refs = gf_bs_read_u16(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        ptr->refs = gf_malloc(sizeof(GF_SIDXReference)*ptr->nb_refs);
        for (i=0; i<ptr->nb_refs; i++) {
                ptr->refs[i].reference_type = gf_bs_read_int(bs, 1);
                ptr->refs[i].reference_size = gf_bs_read_int(bs, 31);
                ptr->refs[i].subsegment_duration = gf_bs_read_u32(bs);
                ptr->refs[i].starts_with_SAP = gf_bs_read_int(bs, 1);
                ptr->refs[i].SAP_type = gf_bs_read_int(bs, 3);
                ptr->refs[i].SAP_delta_time = gf_bs_read_int(bs, 28);

                ISOM_DECREASE_SIZE(ptr, 12);
        }
        return GF_OK;
}

GF_Box *sidx_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SegmentIndexBox, GF_ISOM_BOX_TYPE_SIDX);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err sidx_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->reference_ID);
        gf_bs_write_u32(bs, ptr->timescale);
        if (ptr->version==0) {
                gf_bs_write_u32(bs, (u32) ptr->earliest_presentation_time);
                gf_bs_write_u32(bs, (u32) ptr->first_offset);
        } else {
                gf_bs_write_u64(bs, ptr->earliest_presentation_time);
                gf_bs_write_u64(bs, ptr->first_offset);
        }
        gf_bs_write_u16(bs, 0);
        gf_bs_write_u16(bs, ptr->nb_refs);
        for (i=0; i<ptr->nb_refs; i++ ) {
                gf_bs_write_int(bs, ptr->refs[i].reference_type, 1);
                gf_bs_write_int(bs, ptr->refs[i].reference_size, 31);
                gf_bs_write_u32(bs, ptr->refs[i].subsegment_duration);
                gf_bs_write_int(bs, ptr->refs[i].starts_with_SAP, 1);
                gf_bs_write_int(bs, ptr->refs[i].SAP_type, 3);
                gf_bs_write_int(bs, ptr->refs[i].SAP_delta_time, 28);
        }
        return GF_OK;
}

GF_Err sidx_Size(GF_Box *s)
{
        GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s;

        ptr->size += 12;
        if (ptr->version==0) {
                ptr->size += 8;
        } else {
                ptr->size += 16;
        }
        ptr->size += ptr->nb_refs * 12;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void ssix_del(GF_Box *s)
{
        u32 i;
        GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox *)s;
        if (ptr == NULL) return;
        if (ptr->subsegments) {
                for (i = 0; i < ptr->subsegment_count; i++) {
                        GF_Subsegment *subsegment = &ptr->subsegments[i];
                        if (subsegment->levels) gf_free(subsegment->levels);
                        if (subsegment->range_sizes) gf_free(subsegment->range_sizes);
                }
                gf_free(ptr->subsegments);
        }
        gf_free(ptr);
}

GF_Err ssix_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i,j;
        GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s;

        if (ptr->size < 4) return GF_BAD_PARAM;
        ptr->subsegment_count = gf_bs_read_u32(bs);
        ptr->size -= 4;
        ptr->subsegments = gf_malloc(ptr->subsegment_count*sizeof(GF_Subsegment));
        for (i = 0; i < ptr->subsegment_count; i++) {
                GF_Subsegment *subseg = &ptr->subsegments[i];
                if (ptr->size < 4) return GF_BAD_PARAM;
                subseg->range_count = gf_bs_read_u32(bs);
                ptr->size -= 4;
                if (ptr->size < subseg->range_count*4) return GF_BAD_PARAM;
                subseg->levels = gf_malloc(sizeof(u8)*subseg->range_count);
                subseg->range_sizes = gf_malloc(sizeof(u32)*subseg->range_count);
                for (j = 0; j < subseg->range_count; j++) {
                        subseg->levels[j] = gf_bs_read_u8(bs);
                        subseg->range_sizes[j] = gf_bs_read_u24(bs);
                        ptr->size -= 4;
                }
        }
        return GF_OK;
}

GF_Box *ssix_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SubsegmentIndexBox, GF_ISOM_BOX_TYPE_SSIX);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err ssix_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i, j;
        GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->subsegment_count);
        for (i = 0; i<ptr->subsegment_count; i++) {
                gf_bs_write_u32(bs, ptr->subsegments[i].range_count);
                for (j = 0; j < ptr->subsegment_count; j++) {
                        gf_bs_write_u8(bs, ptr->subsegments[i].levels[j]);
                        gf_bs_write_u24(bs, ptr->subsegments[i].range_sizes[j]);
                }
        }
        return GF_OK;
}

GF_Err ssix_Size(GF_Box *s)
{
        u32 i;
        GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s;

        ptr->size += 4;
        for (i = 0; i < ptr->subsegment_count; i++) {
                ptr->size += 4 + 4 * ptr->subsegments[i].range_count;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void leva_del(GF_Box *s)
{
        GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox *)s;
        if (ptr == NULL) return;
        if (ptr->levels) gf_free(ptr->levels);
        gf_free(ptr);
}

GF_Err leva_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s;

        if (ptr->size < 4) return GF_BAD_PARAM;
        ptr->level_count = gf_bs_read_u8(bs);
        ptr->size -= 4;
        GF_SAFE_ALLOC_N(ptr->levels, ptr->level_count, GF_LevelAssignment);
        for (i = 0; i < ptr->level_count; i++) {
                GF_LevelAssignment *level = &ptr->levels[i];
                u8 tmp;
                if (ptr->size < 5) return GF_BAD_PARAM;
                level->track_id = gf_bs_read_u32(bs);
                tmp = gf_bs_read_u8(bs);
                level->padding_flag = tmp >> 7;
                level->type = tmp & 0x7F;
                if (level->type == 0) {
                        level->grouping_type = gf_bs_read_u32(bs);
                }
                else if (level->type == 1) {
                        level->grouping_type = gf_bs_read_u32(bs);
                        level->grouping_type_parameter = gf_bs_read_u32(bs);
                }
                else if (level->type == 4) {
                        level->sub_track_id = gf_bs_read_u32(bs);
                }
        }
        return GF_OK;
}

GF_Box *leva_New()
{
        ISOM_DECL_BOX_ALLOC(GF_LevelAssignmentBox, GF_ISOM_BOX_TYPE_LEVA);
        return (GF_Box *)tmp;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err leva_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u8(bs, ptr->level_count);
        for (i = 0; i<ptr->level_count; i++) {
                gf_bs_write_u32(bs, ptr->levels[i].track_id);
                gf_bs_write_u8(bs, ptr->levels[i].padding_flag << 7 | (ptr->levels[i].type & 0x7F));
                if (ptr->levels[i].type == 0) {
                        gf_bs_write_u32(bs, ptr->levels[i].grouping_type);
                }
                else if (ptr->levels[i].type == 1) {
                        gf_bs_write_u32(bs, ptr->levels[i].grouping_type);
                        gf_bs_write_u32(bs, ptr->levels[i].grouping_type_parameter);
                }
                else if (ptr->levels[i].type == 4) {
                        gf_bs_write_u32(bs, ptr->levels[i].sub_track_id);
                }
        }
        return GF_OK;
}

GF_Err leva_Size(GF_Box *s)
{
        u32 i;
        GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s;

        ptr->size += 1;
        for (i = 0; i < ptr->level_count; i++) {
                ptr->size += 5;
                if (ptr->levels[i].type == 0 || ptr->levels[i].type == 4) {
                        ptr->size += 4;
                }
                else if (ptr->levels[i].type == 1) {
                        ptr->size += 8;
                }
        }
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Box *pcrb_New()
{
        ISOM_DECL_BOX_ALLOC(GF_PcrInfoBox, GF_ISOM_BOX_TYPE_PCRB);
        return (GF_Box *)tmp;
}

void pcrb_del(GF_Box *s)
{
        GF_PcrInfoBox *ptr = (GF_PcrInfoBox *) s;
        if (ptr == NULL) return;
        if (ptr->pcr_values) gf_free(ptr->pcr_values);
        gf_free(ptr);
}

GF_Err pcrb_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 i;
        GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s;

        ptr->subsegment_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        ptr->pcr_values = gf_malloc(sizeof(u64)*ptr->subsegment_count);
        for (i=0; i<ptr->subsegment_count; i++) {
                u64 data1 = gf_bs_read_u32(bs);
                u64 data2 = gf_bs_read_u16(bs);
                ISOM_DECREASE_SIZE(ptr, 6);
                ptr->pcr_values[i] = (data1 << 10) | (data2 >> 6);

        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err pcrb_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->subsegment_count);

        for (i=0; i<ptr->subsegment_count; i++ ) {
                u32 data1 = (u32) (ptr->pcr_values[i] >> 10);
                u16 data2 = (u16) (ptr->pcr_values[i] << 6);

                gf_bs_write_u32(bs, data1);
                gf_bs_write_u16(bs, data2);
        }
        return GF_OK;
}

GF_Err pcrb_Size(GF_Box *s)
{
        GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s;

        ptr->size += 4;
        ptr->size += ptr->subsegment_count * 6;

        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *subs_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SubSampleInformationBox, GF_ISOM_BOX_TYPE_SUBS);
        tmp->Samples = gf_list_new();
        return (GF_Box *)tmp;
}

void subs_del(GF_Box *s)
{
        GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *)s;
        if (ptr == NULL) return;

        while (gf_list_count(ptr->Samples)) {
                GF_SubSampleInfoEntry *pSamp;
                pSamp = (GF_SubSampleInfoEntry*)gf_list_get(ptr->Samples, 0);
                while (gf_list_count(pSamp->SubSamples)) {
                        GF_SubSampleEntry *pSubSamp;
                        pSubSamp = (GF_SubSampleEntry*) gf_list_get(pSamp->SubSamples, 0);
                        gf_free(pSubSamp);
                        gf_list_rem(pSamp->SubSamples, 0);
                }
                gf_list_del(pSamp->SubSamples);
                gf_free(pSamp);
                gf_list_rem(ptr->Samples, 0);
        }
        gf_list_del(ptr->Samples);
        gf_free(ptr);
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err subs_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i, j, entry_count;
        u16 subsample_count;
        GF_SubSampleInfoEntry *pSamp;
        GF_SubSampleEntry *pSubSamp;
        GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *) s;

        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        entry_count = gf_list_count(ptr->Samples);
        gf_bs_write_u32(bs, entry_count);

        for (i=0; i<entry_count; i++) {
                pSamp = (GF_SubSampleInfoEntry*) gf_list_get(ptr->Samples, i);
                subsample_count = gf_list_count(pSamp->SubSamples);
                gf_bs_write_u32(bs, pSamp->sample_delta);
                gf_bs_write_u16(bs, subsample_count);

                for (j=0; j<subsample_count; j++) {
                        pSubSamp = (GF_SubSampleEntry*) gf_list_get(pSamp->SubSamples, j);
                        if (ptr->version == 1) {
                                gf_bs_write_u32(bs, pSubSamp->subsample_size);
                        } else {
                                gf_bs_write_u16(bs, pSubSamp->subsample_size);
                        }
                        gf_bs_write_u8(bs, pSubSamp->subsample_priority);
                        gf_bs_write_u8(bs, pSubSamp->discardable);
                        gf_bs_write_u32(bs, pSubSamp->reserved);
                }
        }
        return e;
}

GF_Err subs_Size(GF_Box *s)
{
        GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *) s;
        GF_SubSampleInfoEntry *pSamp;
        u32 entry_count, i;
        u16 subsample_count;

        // add 4 byte for entry_count
        ptr->size += 4;
        entry_count = gf_list_count(ptr->Samples);
        for (i=0; i<entry_count; i++) {
                pSamp = (GF_SubSampleInfoEntry*) gf_list_get(ptr->Samples, i);
                subsample_count = gf_list_count(pSamp->SubSamples);
                // 4 byte for sample_delta, 2 byte for subsample_count
                // and 6 + (4 or 2) bytes for each subsample
                ptr->size += 4 + 2 + subsample_count * (6 + (ptr->version==1 ? 4 : 2));
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

GF_Err subs_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *)s;
        u32 entry_count, i, j;
        u16 subsample_count;

        entry_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        for (i=0; i<entry_count; i++) {
                u32 subs_size=0;
                GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry*) gf_malloc(sizeof(GF_SubSampleInfoEntry));
                if (!pSamp) return GF_OUT_OF_MEM;

                memset(pSamp, 0, sizeof(GF_SubSampleInfoEntry));
                pSamp->SubSamples = gf_list_new();
                pSamp->sample_delta = gf_bs_read_u32(bs);
                subsample_count = gf_bs_read_u16(bs);
                subs_size=6;

                for (j=0; j<subsample_count; j++) {
                        GF_SubSampleEntry *pSubSamp = (GF_SubSampleEntry*) gf_malloc(sizeof(GF_SubSampleEntry));
                        if (!pSubSamp) return GF_OUT_OF_MEM;

                        memset(pSubSamp, 0, sizeof(GF_SubSampleEntry));
                        if (ptr->version==1) {
                                pSubSamp->subsample_size = gf_bs_read_u32(bs);
                                subs_size+=4;
                        } else {
                                pSubSamp->subsample_size = gf_bs_read_u16(bs);
                                subs_size+=2;
                        }
                        pSubSamp->subsample_priority = gf_bs_read_u8(bs);
                        pSubSamp->discardable = gf_bs_read_u8(bs);
                        pSubSamp->reserved = gf_bs_read_u32(bs);
                        subs_size+=6;

                        gf_list_add(pSamp->SubSamples, pSubSamp);
                }
                gf_list_add(ptr->Samples, pSamp);
                ISOM_DECREASE_SIZE(ptr, subs_size);
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_FRAGMENTS

GF_Box *tfdt_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TFBaseMediaDecodeTimeBox, GF_ISOM_BOX_TYPE_TFDT);
        return (GF_Box *)tmp;
}

void tfdt_del(GF_Box *s)
{
        gf_free(s);
}

/*this is using chpl format according to some NeroRecode samples*/
GF_Err tfdt_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *)s;

        if (ptr->version==1) {
                ptr->baseMediaDecodeTime = gf_bs_read_u64(bs);
                ISOM_DECREASE_SIZE(ptr, 8);
        } else {
                ptr->baseMediaDecodeTime = (u32) gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 4);
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err tfdt_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *) s;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        if (ptr->version==1) {
                gf_bs_write_u64(bs, ptr->baseMediaDecodeTime);
        } else {
                gf_bs_write_u32(bs, (u32) ptr->baseMediaDecodeTime);
        }
        return GF_OK;
}

GF_Err tfdt_Size(GF_Box *s)
{
        GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *)s;

        if (ptr->baseMediaDecodeTime<=0xFFFFFFFF) {
                ptr->version = 0;
                ptr->size += 4;
        } else {
                ptr->version = 1;
                ptr->size += 8;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/


GF_Box *rvcc_New()
{
        ISOM_DECL_BOX_ALLOC(GF_RVCConfigurationBox, GF_ISOM_BOX_TYPE_RVCC);
        return (GF_Box *)tmp;
}

void rvcc_del(GF_Box *s)
{
        gf_free(s);
}

GF_Err rvcc_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox*)s;
        ptr->predefined_rvc_config = gf_bs_read_u16(bs);
        ISOM_DECREASE_SIZE(ptr, 2);
        if (!ptr->predefined_rvc_config) {
                ptr->rvc_meta_idx = gf_bs_read_u16(bs);
                ISOM_DECREASE_SIZE(ptr, 2);
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err rvcc_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox*) s;

        e = gf_isom_box_write_header(s, bs);
        if (e) return e;

        gf_bs_write_u16(bs, ptr->predefined_rvc_config);
        if (!ptr->predefined_rvc_config) {
                gf_bs_write_u16(bs, ptr->rvc_meta_idx);
        }
        return GF_OK;
}

GF_Err rvcc_Size(GF_Box *s)
{
        GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox *)s;
        ptr->size += 2;
        if (! ptr->predefined_rvc_config) ptr->size += 2;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *sbgp_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleGroupBox, GF_ISOM_BOX_TYPE_SBGP);
        return (GF_Box *)tmp;
}
void sbgp_del(GF_Box *a)
{
        GF_SampleGroupBox *p = (GF_SampleGroupBox *)a;
        if (p->sample_entries) gf_free(p->sample_entries);
        gf_free(p);
}

GF_Err sbgp_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_SampleGroupBox *ptr = (GF_SampleGroupBox *)s;

        ptr->grouping_type = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->version==1) {
                ptr->grouping_type_parameter = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 4);
        }
        ptr->entry_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        ptr->sample_entries = gf_malloc(sizeof(GF_SampleGroupEntry)*ptr->entry_count);
        if (!ptr->sample_entries) return GF_IO_ERR;
        for (i=0; i<ptr->entry_count; i++) {
                ptr->sample_entries[i].sample_count = gf_bs_read_u32(bs);
                ptr->sample_entries[i].group_description_index = gf_bs_read_u32(bs);

                ISOM_DECREASE_SIZE(ptr, 8);
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err sbgp_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_Err e;
        GF_SampleGroupBox *p = (GF_SampleGroupBox*)s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, p->grouping_type);
        if (p->version==1)
                gf_bs_write_u32(bs, p->grouping_type_parameter);

        gf_bs_write_u32(bs, p->entry_count);
        for (i = 0; i<p->entry_count; i++ ) {
                gf_bs_write_u32(bs, p->sample_entries[i].sample_count);
                gf_bs_write_u32(bs, p->sample_entries[i].group_description_index);
        }
        return GF_OK;
}

GF_Err sbgp_Size(GF_Box *s)
{
        GF_SampleGroupBox *p = (GF_SampleGroupBox*)s;

        p->size += 8;
        if (p->grouping_type_parameter) p->version=1;

        if (p->version==1) p->size += 4;
        p->size += 8*p->entry_count;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

static void *sgpd_parse_entry(u32 grouping_type, GF_BitStream *bs, u32 entry_size, u32 *total_bytes)
{
        GF_DefaultSampleGroupDescriptionEntry *ptr;
        switch (grouping_type) {
        case GF_ISOM_SAMPLE_GROUP_ROLL:
        case GF_ISOM_SAMPLE_GROUP_PROL:
        {
                GF_RollRecoveryEntry *ptr;
                GF_SAFEALLOC(ptr, GF_RollRecoveryEntry);
                if (!ptr) return NULL;
                ptr->roll_distance = gf_bs_read_int(bs, 16);
                *total_bytes = 2;
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_RAP:
        {
                GF_VisualRandomAccessEntry *ptr;
                GF_SAFEALLOC(ptr, GF_VisualRandomAccessEntry);
                if (!ptr) return NULL;
                ptr->num_leading_samples_known = gf_bs_read_int(bs, 1);
                ptr->num_leading_samples = gf_bs_read_int(bs, 7);
                *total_bytes = 1;
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_SAP:
        {
                GF_SAPEntry *ptr;
                GF_SAFEALLOC(ptr, GF_SAPEntry);
                if (!ptr) return NULL;
                ptr->dependent_flag = gf_bs_read_int(bs, 1);
                gf_bs_read_int(bs, 3);
                ptr->SAP_type = gf_bs_read_int(bs, 4);
                *total_bytes = 1;
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_TELE:
        {
                GF_TemporalLevelEntry *ptr;
                GF_SAFEALLOC(ptr, GF_TemporalLevelEntry);
                if (!ptr) return NULL;
                ptr->level_independently_decodable = gf_bs_read_int(bs, 1);
                gf_bs_read_int(bs, 7);
                *total_bytes = 1;
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_SEIG:
        {
                GF_CENCSampleEncryptionGroupEntry *ptr;
                GF_SAFEALLOC(ptr, GF_CENCSampleEncryptionGroupEntry);
                if (!ptr) return NULL;
                gf_bs_read_u8(bs); //reserved
                ptr->crypt_byte_block = gf_bs_read_int(bs, 4);
                ptr->skip_byte_block = gf_bs_read_int(bs, 4);
                ptr->IsProtected = gf_bs_read_u8(bs);
                ptr->Per_Sample_IV_size = gf_bs_read_u8(bs);
                gf_bs_read_data(bs, (char *)ptr->KID, 16);
                *total_bytes = 20;
                if ((ptr->IsProtected == 1) && !ptr->Per_Sample_IV_size) {
                        ptr->constant_IV_size = gf_bs_read_u8(bs);
                        assert((ptr->constant_IV_size == 8) || (ptr->constant_IV_size == 16));
                        gf_bs_read_data(bs, (char *)ptr->constant_IV, ptr->constant_IV_size);
                        *total_bytes += 1 + ptr->constant_IV_size;
                }
                if (!entry_size) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] seig sample group does not indicate entry size, deprecated in spec\n"));
                }
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_OINF:
        {
                GF_OperatingPointsInformation *ptr = gf_isom_oinf_new_entry();
                u32 s = (u32) gf_bs_get_position(bs);
                gf_isom_oinf_read_entry(ptr, bs);
                *total_bytes = (u32) gf_bs_get_position(bs) - s;
                if (!entry_size) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] oinf sample group does not indicate entry size, deprecated in spec\n"));
                }
                return ptr;
        }
        case GF_ISOM_SAMPLE_GROUP_LINF:
        {
                GF_LHVCLayerInformation *ptr = gf_isom_linf_new_entry();
                u32 s = (u32) gf_bs_get_position(bs);
                gf_isom_linf_read_entry(ptr, bs);
                *total_bytes = (u32) gf_bs_get_position(bs) - s;
                if (!entry_size) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] linf sample group does not indicate entry size, deprecated in spec\n"));
                }
                return ptr;
        }

        case GF_ISOM_SAMPLE_GROUP_TRIF:
                if (! entry_size) {
                        u32 flags = gf_bs_peek_bits(bs, 24, 0);
                        if (flags & 0x10000) entry_size=3;
                        else {
                                if (flags & 0x80000) entry_size=7;
                                else entry_size=11;
                                //have dependency list
                                if (flags & 0x200000) {
                                        u32 nb_entries = gf_bs_peek_bits(bs, 16, entry_size);
                                        entry_size += 2 + 2*nb_entries;
                                }
                        }
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] trif sample group does not indicate entry size, deprecated in spec\n"));
                }
                break;
        case GF_ISOM_SAMPLE_GROUP_NALM:
                if (! entry_size) {
                        u64 start = gf_bs_get_position(bs);
                        Bool rle, large_size;
                        u32 entry_count;
                        gf_bs_read_int(bs, 6);
                        large_size = gf_bs_read_int(bs, 1);
                        rle = gf_bs_read_int(bs, 1);
                        entry_count = gf_bs_read_int(bs, large_size ? 16 : 8);
                        gf_bs_seek(bs, start);
                        entry_size = 1 + large_size ? 2 : 1;
                        entry_size += entry_count * 2;
                        if (rle) entry_size += entry_count * (large_size ? 2 : 1);
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] nalm sample group does not indicate entry size, deprecated in spec\n"));
                }
                break;
        default:
                break;
        }

        if (!entry_size) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] %s sample group does not indicate entry size, cannot parse!\n", gf_4cc_to_str( grouping_type) ));
                return NULL;
        }
        GF_SAFEALLOC(ptr, GF_DefaultSampleGroupDescriptionEntry);
        if (!ptr) return NULL;
        ptr->length = entry_size;
        ptr->data = (u8 *) gf_malloc(sizeof(u8)*ptr->length);
        gf_bs_read_data(bs, (char *) ptr->data, ptr->length);
        *total_bytes = entry_size;
        return ptr;
}

static void     sgpd_del_entry(u32 grouping_type, void *entry)
{
        switch (grouping_type) {
        case GF_ISOM_SAMPLE_GROUP_ROLL:
        case GF_ISOM_SAMPLE_GROUP_PROL:
        case GF_ISOM_SAMPLE_GROUP_RAP:
        case GF_ISOM_SAMPLE_GROUP_SEIG:
        case GF_ISOM_SAMPLE_GROUP_TELE:
        case GF_ISOM_SAMPLE_GROUP_SAP:
                gf_free(entry);
                return;
        case GF_ISOM_SAMPLE_GROUP_OINF:
                gf_isom_oinf_del_entry(entry);
                return;
        case GF_ISOM_SAMPLE_GROUP_LINF:
                gf_isom_linf_del_entry(entry);
                return;
        default:
        {
                GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry;
                if (ptr->data) gf_free(ptr->data);
                gf_free(ptr);
        }
        }
}

void sgpd_write_entry(u32 grouping_type, void *entry, GF_BitStream *bs)
{
        switch (grouping_type) {
        case GF_ISOM_SAMPLE_GROUP_ROLL:
        case GF_ISOM_SAMPLE_GROUP_PROL:
                gf_bs_write_int(bs, ((GF_RollRecoveryEntry*)entry)->roll_distance, 16);
                return;
        case GF_ISOM_SAMPLE_GROUP_RAP:
                gf_bs_write_int(bs, ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known, 1);
                gf_bs_write_int(bs, ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples, 7);
                return;
        case GF_ISOM_SAMPLE_GROUP_SAP:
                gf_bs_write_int(bs, ((GF_SAPEntry*)entry)->dependent_flag, 1);
                gf_bs_write_int(bs, 0, 3);
                gf_bs_write_int(bs, ((GF_SAPEntry*)entry)->SAP_type, 4);
                return;
        case GF_ISOM_SAMPLE_GROUP_TELE:
                gf_bs_write_int(bs, ((GF_TemporalLevelEntry*)entry)->level_independently_decodable, 1);
                gf_bs_write_int(bs, 0, 7);
                return;
        case GF_ISOM_SAMPLE_GROUP_SEIG:
                gf_bs_write_u8(bs, 0x0);
                gf_bs_write_int(bs, ((GF_CENCSampleEncryptionGroupEntry*)entry)->crypt_byte_block, 4);
                gf_bs_write_int(bs, ((GF_CENCSampleEncryptionGroupEntry*)entry)->skip_byte_block, 4);
                gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->IsProtected);
                gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->Per_Sample_IV_size);
                gf_bs_write_data(bs, (char *)((GF_CENCSampleEncryptionGroupEntry *)entry)->KID, 16);
                if ((((GF_CENCSampleEncryptionGroupEntry *)entry)->IsProtected == 1) && !((GF_CENCSampleEncryptionGroupEntry *)entry)->Per_Sample_IV_size) {
                        gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV_size);
                        gf_bs_write_data(bs, (char *)((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV, ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV_size);
                }
                return;
        case GF_ISOM_SAMPLE_GROUP_OINF:
                gf_isom_oinf_write_entry(entry, bs);
                return;
        case GF_ISOM_SAMPLE_GROUP_LINF:
                gf_isom_linf_write_entry(entry, bs);
                return;
        default:
        {
                GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry;
                gf_bs_write_data(bs, (char *) ptr->data, ptr->length);
        }
        }
}

#ifndef GPAC_DISABLE_ISOM_WRITE
static u32 sgpd_size_entry(u32 grouping_type, void *entry)
{
        switch (grouping_type) {
        case GF_ISOM_SAMPLE_GROUP_ROLL:
        case GF_ISOM_SAMPLE_GROUP_PROL:
                return 2;
        case GF_ISOM_SAMPLE_GROUP_TELE:
        case GF_ISOM_SAMPLE_GROUP_RAP:
        case GF_ISOM_SAMPLE_GROUP_SAP:
                return 1;
        case GF_ISOM_SAMPLE_GROUP_SEIG:
                return ((((GF_CENCSampleEncryptionGroupEntry *)entry)->IsProtected == 1) && !((GF_CENCSampleEncryptionGroupEntry *)entry)->Per_Sample_IV_size) ? 21 + ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV_size : 20;
        case GF_ISOM_SAMPLE_GROUP_OINF:
                return gf_isom_oinf_size_entry(entry);
        case GF_ISOM_SAMPLE_GROUP_LINF:
                return gf_isom_linf_size_entry(entry);
        default:
                return ((GF_DefaultSampleGroupDescriptionEntry *)entry)->length;
        }
}
#endif

GF_Box *sgpd_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleGroupDescriptionBox, GF_ISOM_BOX_TYPE_SGPD);
        /*version 0 is deprecated, use v1 by default*/
        tmp->version = 1;
        tmp->group_descriptions = gf_list_new();
        return (GF_Box *)tmp;
}

void sgpd_del(GF_Box *a)
{
        GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)a;
        while (gf_list_count(p->group_descriptions)) {
                void *ptr = gf_list_last(p->group_descriptions);
                sgpd_del_entry(p->grouping_type, ptr);
                gf_list_rem_last(p->group_descriptions);
        }
        gf_list_del(p->group_descriptions);
        gf_free(p);
}

GF_Err sgpd_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 entry_count;
        GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s;

        p->grouping_type = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(p, 4);

        if (p->version>=1) {
                p->default_length = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(p, 4);
        }
        if (p->version>=2) {
                p->default_description_index = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(p, 4);
        }
        entry_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(p, 4);

        if (entry_count>p->size)
                return GF_ISOM_INVALID_FILE;

        while (entry_count) {
                void *ptr;
                u32 parsed_bytes;
                u32 size = p->default_length;
                if ((p->version>=1) && !size) {
                        size = gf_bs_read_u32(bs);
                        ISOM_DECREASE_SIZE(p, 4);
                }
                ptr = sgpd_parse_entry(p->grouping_type, bs, size, &parsed_bytes);
                if (!ptr) return GF_ISOM_INVALID_FILE;

                ISOM_DECREASE_SIZE(p, parsed_bytes);

                gf_list_add(p->group_descriptions, ptr);
                entry_count--;
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err sgpd_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s;
        GF_Err e;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, p->grouping_type);
        if (p->version>=1) gf_bs_write_u32(bs, p->default_length);
        if (p->version>=2) gf_bs_write_u32(bs, p->default_description_index);
        gf_bs_write_u32(bs, gf_list_count(p->group_descriptions) );

        for (i=0; i<gf_list_count(p->group_descriptions); i++) {
                void *ptr = gf_list_get(p->group_descriptions, i);
                if ((p->version >= 1) && !p->default_length) {
                        u32 size = sgpd_size_entry(p->grouping_type, ptr);
                        gf_bs_write_u32(bs, size);
                }
                sgpd_write_entry(p->grouping_type, ptr, bs);
        }
        return GF_OK;
}

GF_Err sgpd_Size(GF_Box *s)
{
        u32 i;
        GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s;

        p->size += 8;

        //we force all sample groups to version 1, v0 being deprecated
        p->version=1;
        p->size += 4;

        if (p->version>=2) p->size += 4;
        p->default_length = 0;

        for (i=0; i<gf_list_count(p->group_descriptions); i++) {
                void *ptr = gf_list_get(p->group_descriptions, i);
                u32 size = sgpd_size_entry(p->grouping_type, ptr);
                p->size += size;
                if (!p->default_length) {
                        p->default_length = size;
                } else if (p->default_length != size) {
                        p->default_length = 0;
                }
        }
        if (p->version>=1) {
                if (!p->default_length) p->size += gf_list_count(p->group_descriptions)*4;
        }
        return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/


void saiz_del(GF_Box *s)
{
        GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*)s;
        if (ptr == NULL) return;
        if (ptr->sample_info_size) gf_free(ptr->sample_info_size);
        gf_free(ptr);
}


GF_Err saiz_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*)s;

        if (ptr->flags & 1) {
                ptr->aux_info_type = gf_bs_read_u32(bs);
                ptr->aux_info_type_parameter = gf_bs_read_u32(bs);

                ISOM_DECREASE_SIZE(ptr, 8);
        }
        ptr->default_sample_info_size = gf_bs_read_u8(bs);
        ptr->sample_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 5);

        if (ptr->default_sample_info_size == 0) {
                ptr->sample_info_size = gf_malloc(sizeof(u8)*ptr->sample_count);
                gf_bs_read_data(bs, (char *) ptr->sample_info_size, ptr->sample_count);
                ISOM_DECREASE_SIZE(ptr, ptr->sample_count);
        }
        return GF_OK;
}

GF_Box *saiz_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleAuxiliaryInfoSizeBox, GF_ISOM_BOX_TYPE_SAIZ);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err saiz_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        if (ptr->flags & 1) {
                gf_bs_write_u32(bs, ptr->aux_info_type);
                gf_bs_write_u32(bs, ptr->aux_info_type_parameter);
        }
        gf_bs_write_u8(bs, ptr->default_sample_info_size);
        gf_bs_write_u32(bs, ptr->sample_count);
        if (!ptr->default_sample_info_size) {
                gf_bs_write_data(bs, (char *) ptr->sample_info_size, ptr->sample_count);
        }
        return GF_OK;
}

GF_Err saiz_Size(GF_Box *s)
{
        GF_SampleAuxiliaryInfoSizeBox *ptr = (GF_SampleAuxiliaryInfoSizeBox*)s;

        if (ptr->aux_info_type || ptr->aux_info_type_parameter) {
                ptr->flags |= 1;
        }
        if (ptr->flags & 1) ptr->size += 8;
        ptr->size += 5;
        if (ptr->default_sample_info_size==0)  ptr->size += ptr->sample_count;
        return GF_OK;
}
#endif //GPAC_DISABLE_ISOM_WRITE

void saio_del(GF_Box *s)
{
        GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox*)s;
        if (ptr == NULL) return;
        if (ptr->offsets) gf_free(ptr->offsets);
        if (ptr->offsets_large) gf_free(ptr->offsets_large);
        gf_free(ptr);
}


GF_Err saio_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *)s;

        if (ptr->flags & 1) {
                ptr->aux_info_type = gf_bs_read_u32(bs);
                ptr->aux_info_type_parameter = gf_bs_read_u32(bs);
                ISOM_DECREASE_SIZE(ptr, 8);
        }
        ptr->entry_count = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);

        if (ptr->entry_count) {
                u32 i;
                if (ptr->version==0) {
                        ptr->offsets = gf_malloc(sizeof(u32)*ptr->entry_count);
                        for (i=0; i<ptr->entry_count; i++)
                                ptr->offsets[i] = gf_bs_read_u32(bs);

                        ISOM_DECREASE_SIZE(ptr, 4*ptr->entry_count);
                } else {
                        ptr->offsets_large = gf_malloc(sizeof(u64)*ptr->entry_count);
                        for (i=0; i<ptr->entry_count; i++)
                                ptr->offsets_large[i] = gf_bs_read_u64(bs);
                        ISOM_DECREASE_SIZE(ptr, 8*ptr->entry_count);
                }
        }
        return GF_OK;
}

GF_Box *saio_New()
{
        ISOM_DECL_BOX_ALLOC(GF_SampleAuxiliaryInfoOffsetBox, GF_ISOM_BOX_TYPE_SAIO);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err saio_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        if (ptr->flags & 1) {
                gf_bs_write_u32(bs, ptr->aux_info_type);
                gf_bs_write_u32(bs, ptr->aux_info_type_parameter);
        }


        gf_bs_write_u32(bs, ptr->entry_count);
        if (ptr->entry_count) {
                u32 i;
                //store position in bitstream before writing data - offsets can be NULL if a single offset is rewritten later on (cf senc_write)
                ptr->offset_first_offset_field = gf_bs_get_position(bs);
                if (ptr->version==0) {
                        if (!ptr->offsets) {
                                gf_bs_write_u32(bs, 0);
                        } else {
                                for (i=0; i<ptr->entry_count; i++)
                                        gf_bs_write_u32(bs, ptr->offsets[i]);
                        }
                } else {
                        if (!ptr->offsets_large) {
                                gf_bs_write_u64(bs, 0);
                        } else {
                                for (i=0; i<ptr->entry_count; i++)
                                        gf_bs_write_u64(bs, ptr->offsets_large[i]);
                        }
                }
        }
        return GF_OK;
}

GF_Err saio_Size(GF_Box *s)
{
        GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox*)s;

        if (ptr->aux_info_type || ptr->aux_info_type_parameter) {
                ptr->flags |= 1;
        }
        if (ptr->offsets_large) {
                ptr->version = 1;
        }

        if (ptr->flags & 1) ptr->size += 8;
        ptr->size += 4;
        //a little optim here: in cenc, the saio always points to a single data block, only one entry is needed
        if (ptr->aux_info_type == GF_4CC('c', 'e', 'n', 'c')) {
                if (ptr->offsets_large) gf_free(ptr->offsets_large);
                if (ptr->offsets) gf_free(ptr->offsets);
                ptr->offsets_large = NULL;
                ptr->offsets = NULL;
                ptr->entry_count = 1;
        }

        ptr->size += ((ptr->version==1) ? 8 : 4) * ptr->entry_count;
        return GF_OK;
}
#endif //GPAC_DISABLE_ISOM_WRITE


void prft_del(GF_Box *s)
{
        gf_free(s);
}

GF_Err prft_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox *) s;

        ptr->refTrackID = gf_bs_read_u32(bs);
        ptr->ntp = gf_bs_read_u64(bs);
        if (ptr->version==0) {
                ptr->timestamp = gf_bs_read_u32(bs);
        } else {
                ptr->timestamp = gf_bs_read_u64(bs);
        }
        return GF_OK;
}

GF_Box *prft_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ProducerReferenceTimeBox, GF_ISOM_BOX_TYPE_PRFT);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err prft_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u32(bs, ptr->refTrackID);
        gf_bs_write_u64(bs, ptr->ntp);
        if (ptr->version==0) {
                gf_bs_write_u32(bs, (u32) ptr->timestamp);
        } else {
                gf_bs_write_u64(bs, ptr->timestamp);
        }

        return GF_OK;
}

GF_Err prft_Size(GF_Box *s)
{
        GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox*)s;

        ptr->size += 4+8+ (ptr->version ? 8 : 4);
        return GF_OK;
}
#endif //GPAC_DISABLE_ISOM_WRITE

GF_Box *trgr_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackGroupBox, GF_ISOM_BOX_TYPE_TRGR);
        tmp->groups = gf_list_new();
        if (!tmp->groups) {
                gf_free(tmp);
                return NULL;
        }
        return (GF_Box *)tmp;
}

void trgr_del(GF_Box *s)
{
        GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s;
        if (ptr == NULL) return;
        gf_isom_box_array_del(ptr->groups);
        gf_free(ptr);
}


GF_Err trgr_AddBox(GF_Box *s, GF_Box *a)
{
        GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s;
        return gf_list_add(ptr->groups, a);
}


GF_Err trgr_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read_ex(s, bs, trgr_AddBox, s->type);
}


#ifndef GPAC_DISABLE_ISOM_WRITE


GF_Err trgr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackGroupBox *ptr = (GF_TrackGroupBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_box_write_header(s, bs);
        if (e) return e;
        return gf_isom_box_array_write(s, ptr->groups, bs);
}

GF_Err trgr_Size(GF_Box *s)
{
        GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s;
        return gf_isom_box_array_size(s, ptr->groups);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *trgt_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrackGroupTypeBox, GF_ISOM_BOX_TYPE_TRGT);
        return (GF_Box *)tmp;
}

void trgt_del(GF_Box *s)
{
        GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *)s;
        if (ptr == NULL) return;
        gf_free(ptr);
}

GF_Err trgt_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *)s;
        ptr->track_group_id = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, 4);
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err trgt_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *) s;
        if (!s) return GF_BAD_PARAM;
        s->type = ptr->group_type;
        e = gf_isom_full_box_write(s, bs);
        s->type = GF_ISOM_BOX_TYPE_TRGT;
        if (e) return e;
        gf_bs_write_u32(bs, ptr->track_group_id);
        return GF_OK;
}

GF_Err trgt_Size(GF_Box *s)
{
        GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s;

        ptr->size+= 4;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *stvi_New()
{
        ISOM_DECL_BOX_ALLOC(GF_StereoVideoBox, GF_ISOM_BOX_TYPE_STVI);
        return (GF_Box *)tmp;
}

void stvi_del(GF_Box *s)
{
        GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s;
        if (ptr == NULL) return;
        if (ptr->stereo_indication_type) gf_free(ptr->stereo_indication_type);
        gf_free(ptr);
}

GF_Err stvi_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s;

        ISOM_DECREASE_SIZE(ptr, 12);
        gf_bs_read_int(bs, 30);
        ptr->single_view_allowed = gf_bs_read_int(bs, 2);
        ptr->stereo_scheme = gf_bs_read_u32(bs);
        ptr->sit_len = gf_bs_read_u32(bs);
        ISOM_DECREASE_SIZE(ptr, ptr->sit_len);
        ptr->stereo_indication_type = gf_malloc(sizeof(char)*ptr->sit_len);
        gf_bs_read_data(bs, ptr->stereo_indication_type, ptr->sit_len);
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err stvi_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_StereoVideoBox *ptr = (GF_StereoVideoBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_int(bs, 0, 30);
        gf_bs_write_int(bs, ptr->single_view_allowed, 2);
        gf_bs_write_u32(bs, ptr->stereo_scheme);
        gf_bs_write_u32(bs, ptr->sit_len);
        gf_bs_write_data(bs, ptr->stereo_indication_type, ptr->sit_len);

        return GF_OK;
}

GF_Err stvi_Size(GF_Box *s)
{
        GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s;

        ptr->size+= 12 + ptr->sit_len;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *fiin_New()
{
        ISOM_DECL_BOX_ALLOC(FDItemInformationBox, GF_ISOM_BOX_TYPE_FIIN);
        return (GF_Box *)tmp;
}

void fiin_del(GF_Box *s)
{
        FDItemInformationBox *ptr = (FDItemInformationBox *)s;
        if (ptr == NULL) return;
        if (ptr->partition_entries) gf_isom_box_array_del(ptr->partition_entries);
        if (ptr->session_info) gf_isom_box_del((GF_Box*)ptr->session_info);
        if (ptr->group_id_to_name) gf_isom_box_del((GF_Box*)ptr->group_id_to_name);
        gf_free(ptr);
}


GF_Err fiin_AddBox(GF_Box *s, GF_Box *a)
{
        FDItemInformationBox *ptr = (FDItemInformationBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_PAEN:
                if (!ptr->partition_entries) ptr->partition_entries = gf_list_new();
                return gf_list_add(ptr->partition_entries, a);
        case GF_ISOM_BOX_TYPE_SEGR:
                if (ptr->session_info) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->session_info = (FDSessionGroupBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_GITN:
                if (ptr->group_id_to_name) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->group_id_to_name = (GroupIdToNameBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err fiin_Read(GF_Box *s, GF_BitStream *bs)
{
        FDItemInformationBox *ptr = (FDItemInformationBox *)s;

        ISOM_DECREASE_SIZE(ptr, 2);
        gf_bs_read_u16(bs);
        return gf_isom_box_array_read(s, bs, fiin_AddBox);
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err fiin_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        FDItemInformationBox *ptr = (FDItemInformationBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u16(bs, gf_list_count(ptr->partition_entries) );
        e = gf_isom_box_array_write(s, ptr->partition_entries, bs);
        if (e) return e;
        if (ptr->session_info) gf_isom_box_write((GF_Box*)ptr->session_info, bs);
        if (ptr->group_id_to_name) gf_isom_box_write((GF_Box*)ptr->group_id_to_name, bs);
        return GF_OK;
}

GF_Err fiin_Size(GF_Box *s)
{
        GF_Err e;
        FDItemInformationBox *ptr = (FDItemInformationBox *)s;

        ptr->size+= 2;
        if (ptr->partition_entries) {
                e = gf_isom_box_array_size(s, ptr->partition_entries);
                if (e) return e;
        }
        if (ptr->session_info) {
                e = gf_isom_box_size((GF_Box *)ptr->session_info);
                if (e) return e;
                ptr->size += ptr->session_info->size;
        }
        if (ptr->group_id_to_name) {
                e = gf_isom_box_size((GF_Box *) ptr->group_id_to_name);
                if (e) return e;
                ptr->size += ptr->group_id_to_name->size;
        }

        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *paen_New()
{
        ISOM_DECL_BOX_ALLOC(FDPartitionEntryBox, GF_ISOM_BOX_TYPE_PAEN);
        return (GF_Box *)tmp;
}

void paen_del(GF_Box *s)
{
        FDPartitionEntryBox *ptr = (FDPartitionEntryBox *)s;
        if (ptr == NULL) return;
        if (ptr->blocks_and_symbols) gf_isom_box_del((GF_Box*)ptr->blocks_and_symbols);
        if (ptr->FEC_symbol_locations) gf_isom_box_del((GF_Box*)ptr->FEC_symbol_locations);
        if (ptr->File_symbol_locations) gf_isom_box_del((GF_Box*)ptr->File_symbol_locations);
        gf_free(ptr);
}


GF_Err paen_AddBox(GF_Box *s, GF_Box *a)
{
        FDPartitionEntryBox *ptr = (FDPartitionEntryBox *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_FPAR:
                if (ptr->blocks_and_symbols) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->blocks_and_symbols = (FilePartitionBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_FECR:
                if (ptr->FEC_symbol_locations) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->FEC_symbol_locations = (FECReservoirBox *)a;
                return GF_OK;
        case GF_ISOM_BOX_TYPE_FIRE:
                if (ptr->File_symbol_locations) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->File_symbol_locations = (FileReservoirBox *)a;
                return GF_OK;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}

GF_Err paen_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, fiin_AddBox);
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err paen_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        FDPartitionEntryBox *ptr = (FDPartitionEntryBox *) s;
        if (!s) return GF_BAD_PARAM;

        if (ptr->blocks_and_symbols) {
                e = gf_isom_box_write((GF_Box *)ptr->blocks_and_symbols, bs);
                if (e) return e;
        }
        if (ptr->FEC_symbol_locations) {
                e = gf_isom_box_write((GF_Box *)ptr->FEC_symbol_locations, bs);
                if (e) return e;
        }
        if (ptr->File_symbol_locations) {
                e = gf_isom_box_write((GF_Box *)ptr->File_symbol_locations, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err paen_Size(GF_Box *s)
{
        GF_Err e;
        FDPartitionEntryBox *ptr = (FDPartitionEntryBox *)s;

        if (ptr->blocks_and_symbols) {
                e = gf_isom_box_size((GF_Box *)ptr->blocks_and_symbols);
                if (e) return e;
                ptr->size += ptr->blocks_and_symbols->size;
        }
        if (ptr->FEC_symbol_locations) {
                e = gf_isom_box_size((GF_Box *) ptr->FEC_symbol_locations);
                if (e) return e;
                ptr->size += ptr->FEC_symbol_locations->size;
        }
        if (ptr->File_symbol_locations) {
                e = gf_isom_box_size((GF_Box *) ptr->File_symbol_locations);
                if (e) return e;
                ptr->size += ptr->File_symbol_locations->size;
        }

        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/




GF_Box *fpar_New()
{
        ISOM_DECL_BOX_ALLOC(FilePartitionBox, GF_ISOM_BOX_TYPE_FPAR);
        return (GF_Box *)tmp;
}

void fpar_del(GF_Box *s)
{
        FilePartitionBox *ptr = (FilePartitionBox *)s;
        if (ptr == NULL) return;
        if (ptr->scheme_specific_info) gf_free(ptr->scheme_specific_info);
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}

GF_Err gf_isom_read_null_terminated_string(GF_Box *s, GF_BitStream *bs, u32 size, char **out_str)
{
        u32 len=10;
        u32 i=0;

        *out_str = gf_malloc(sizeof(char)*len);
        while (1) {
                ISOM_DECREASE_SIZE(s, 1 );
                (*out_str)[i] = gf_bs_read_u8(bs);
                if (!(*out_str)[i]) break;
                i++;
                if (i==len) {
                        len += 10;
                        *out_str = gf_realloc(*out_str, sizeof(char)*len);
                }
                if (gf_bs_available(bs) == 0) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] missing null character in null terminated string\n"));
                        (*out_str)[i] = 0;
                        return GF_OK;
                }
                if (i >= size) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] string bigger than container, probably missing null character\n"));
                        (*out_str)[i] = 0;
                        return GF_OK;
                }
        }
        return GF_OK;
}

GF_Err fpar_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_Err e;
        FilePartitionBox *ptr = (FilePartitionBox *)s;

        ISOM_DECREASE_SIZE(ptr, ((ptr->version ? 4 : 2) + 12) );
        ptr->itemID = gf_bs_read_int(bs, ptr->version ? 32 : 16);
        ptr->packet_payload_size = gf_bs_read_u16(bs);
        gf_bs_read_u8(bs);
        ptr->FEC_encoding_ID = gf_bs_read_u8(bs);
        ptr->FEC_instance_ID = gf_bs_read_u16(bs);
        ptr->max_source_block_length = gf_bs_read_u16(bs);
        ptr->encoding_symbol_length = gf_bs_read_u16(bs);
        ptr->max_number_of_encoding_symbols = gf_bs_read_u16(bs);

        e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_specific_info);
        if (e) return e;

        ISOM_DECREASE_SIZE(ptr, (ptr->version ? 4 : 2) );
        ptr->nb_entries = gf_bs_read_int(bs, ptr->version ? 32 : 16);
        ISOM_DECREASE_SIZE(ptr, ptr->nb_entries * 6 );
        GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, FilePartitionEntry);
        for (i=0;i < ptr->nb_entries; i++) {
                ptr->entries[i].block_count = gf_bs_read_u16(bs);
                ptr->entries[i].block_size = gf_bs_read_u32(bs);
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err fpar_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        FilePartitionBox *ptr = (FilePartitionBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_int(bs, ptr->itemID, ptr->version ? 32 : 16);
        gf_bs_write_u16(bs, ptr->packet_payload_size);
        gf_bs_write_u8(bs, 0);
        gf_bs_write_u8(bs, ptr->FEC_encoding_ID);
        gf_bs_write_u16(bs, ptr->FEC_instance_ID);
        gf_bs_write_u16(bs, ptr->max_source_block_length);
        gf_bs_write_u16(bs, ptr->encoding_symbol_length);
        gf_bs_write_u16(bs, ptr->max_number_of_encoding_symbols);
        if (ptr->scheme_specific_info) {
                gf_bs_write_data(bs, ptr->scheme_specific_info, (u32)strlen(ptr->scheme_specific_info) );
        }
        //null terminated string
        gf_bs_write_u8(bs, 0);

        gf_bs_write_int(bs, ptr->nb_entries, ptr->version ? 32 : 16);

        for (i=0;i < ptr->nb_entries; i++) {
                gf_bs_write_u16(bs, ptr->entries[i].block_count);
                gf_bs_write_u32(bs, ptr->entries[i].block_size);
        }
        return GF_OK;
}

GF_Err fpar_Size(GF_Box *s)
{
        FilePartitionBox *ptr = (FilePartitionBox *)s;

        ptr->size+= 13 + ptr->version ? 8 : 4;
        if (ptr->scheme_specific_info)
                ptr->size += strlen(ptr->scheme_specific_info);

        ptr->size+= ptr->nb_entries * 6;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *fecr_New()
{
        ISOM_DECL_BOX_ALLOC(FECReservoirBox, GF_ISOM_BOX_TYPE_FECR);
        return (GF_Box *)tmp;
}

void fecr_del(GF_Box *s)
{
        FECReservoirBox *ptr = (FECReservoirBox *)s;
        if (ptr == NULL) return;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}

GF_Err fecr_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        FECReservoirBox *ptr = (FECReservoirBox *)s;

        ISOM_DECREASE_SIZE(ptr, (ptr->version ? 4 : 2) );
        ptr->nb_entries = gf_bs_read_int(bs, ptr->version ? 32 : 16);

        ISOM_DECREASE_SIZE(ptr, ptr->nb_entries * (ptr->version ? 8 : 6) );
        GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, FECReservoirEntry);
        for (i=0; i<ptr->nb_entries; i++) {
                ptr->entries[i].item_id = gf_bs_read_int(bs, ptr->version ? 32 : 16);
                ptr->entries[i].symbol_count = gf_bs_read_u32(bs);
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err fecr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        FECReservoirBox *ptr = (FECReservoirBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_int(bs, ptr->nb_entries, ptr->version ? 32 : 16);
        for (i=0; i<ptr->nb_entries; i++) {
                gf_bs_write_int(bs, ptr->entries[i].item_id, ptr->version ? 32 : 16);
                gf_bs_write_u32(bs, ptr->entries[i].symbol_count);
        }
        return GF_OK;
}

GF_Err fecr_Size(GF_Box *s)
{
        FECReservoirBox *ptr = (FECReservoirBox *)s;
        ptr->size += (ptr->version ? 4 : 2) +  ptr->nb_entries * (ptr->version ? 8 : 6);
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *segr_New()
{
        ISOM_DECL_BOX_ALLOC(FDSessionGroupBox, GF_ISOM_BOX_TYPE_SEGR);
        return (GF_Box *)tmp;
}

void segr_del(GF_Box *s)
{
        u32 i;
        FDSessionGroupBox *ptr = (FDSessionGroupBox *)s;
        if (ptr == NULL) return;
        for (i=0; i<ptr->num_session_groups; i++) {
                if (ptr->session_groups[i].group_ids) gf_free(ptr->session_groups[i].group_ids);
                if (ptr->session_groups[i].channels) gf_free(ptr->session_groups[i].channels);
        }
        if (ptr->session_groups) gf_free(ptr->session_groups);
        gf_free(ptr);
}

GF_Err segr_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i, k;
        FDSessionGroupBox *ptr = (FDSessionGroupBox *)s;

        ISOM_DECREASE_SIZE(ptr, 2);
        ptr->num_session_groups = gf_bs_read_u16(bs);
        if (ptr->num_session_groups*3>ptr->size) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in segr\n", ptr->num_session_groups));
                return GF_ISOM_INVALID_FILE;
        }

        GF_SAFE_ALLOC_N(ptr->session_groups, ptr->num_session_groups, SessionGroupEntry);
        for (i=0; i<ptr->num_session_groups; i++) {
                ptr->session_groups[i].nb_groups = gf_bs_read_u8(bs);
                ISOM_DECREASE_SIZE(ptr, 1);
                GF_SAFE_ALLOC_N(ptr->session_groups[i].group_ids, ptr->session_groups[i].nb_groups, u32);
                for (k=0; k<ptr->session_groups[i].nb_groups; k++) {
                        ISOM_DECREASE_SIZE(ptr, 4);
                        ptr->session_groups[i].group_ids[k] = gf_bs_read_u32(bs);
                }

                ptr->session_groups[i].nb_channels = gf_bs_read_u16(bs);
                GF_SAFE_ALLOC_N(ptr->session_groups[i].channels, ptr->session_groups[i].nb_channels, u32);
                for (k=0; k<ptr->session_groups[i].nb_channels; k++) {
                        ISOM_DECREASE_SIZE(ptr, 4);
                        ptr->session_groups[i].channels[k] = gf_bs_read_u32(bs);
                }
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err segr_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 i, k;
        FDSessionGroupBox *ptr = (FDSessionGroupBox *) s;
        if (!s) return GF_BAD_PARAM;

        gf_bs_write_u16(bs, ptr->num_session_groups);
        for (i=0; i<ptr->num_session_groups; i++) {
                gf_bs_write_u8(bs, ptr->session_groups[i].nb_groups);
                for (k=0; k<ptr->session_groups[i].nb_groups; k++) {
                        gf_bs_write_u32(bs, ptr->session_groups[i].group_ids[k]);
                }

                gf_bs_write_u16(bs, ptr->session_groups[i].nb_channels);
                for (k=0; k<ptr->session_groups[i].nb_channels; k++) {
                        gf_bs_write_u32(bs, ptr->session_groups[i].channels[k]);
                }
        }
        return GF_OK;
}

GF_Err segr_Size(GF_Box *s)
{
        u32 i;
        FDSessionGroupBox *ptr = (FDSessionGroupBox *)s;

        ptr->size += 2;

        for (i=0; i<ptr->num_session_groups; i++) {
                ptr->size += 1 + 4*ptr->session_groups[i].nb_groups;
                ptr->size += 2 + 4*ptr->session_groups[i].nb_channels;
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *gitn_New()
{
        ISOM_DECL_BOX_ALLOC(GroupIdToNameBox, GF_ISOM_BOX_TYPE_GITN);
        return (GF_Box *)tmp;
}

void gitn_del(GF_Box *s)
{
        u32 i;
        GroupIdToNameBox *ptr = (GroupIdToNameBox *)s;
        if (ptr == NULL) return;
        for (i=0; i<ptr->nb_entries; i++) {
                if (ptr->entries[i].name) gf_free(ptr->entries[i].name);
        }
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}

GF_Err gitn_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_Err e;
        GroupIdToNameBox *ptr = (GroupIdToNameBox *)s;

        ISOM_DECREASE_SIZE(ptr, 2);
        ptr->nb_entries = gf_bs_read_u16(bs);

        GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, GroupIdNameEntry);
        for (i=0; i<ptr->nb_entries; i++) {
                ISOM_DECREASE_SIZE(ptr, 4);
                ptr->entries[i].group_id = gf_bs_read_u32(bs);

                e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->entries[i].name);
                if (e) return e;
        }
        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err gitn_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GroupIdToNameBox *ptr = (GroupIdToNameBox *) s;
        if (!s) return GF_BAD_PARAM;
        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        gf_bs_write_u16(bs, ptr->nb_entries);
        for (i=0; i<ptr->nb_entries; i++) {
                gf_bs_write_u32(bs, ptr->entries[i].group_id);
                if (ptr->entries[i].name) gf_bs_write_data(bs, ptr->entries[i].name, (u32)strlen(ptr->entries[i].name) );
                gf_bs_write_u8(bs, 0);
        }
        return GF_OK;
}

GF_Err gitn_Size(GF_Box *s)
{
        u32 i;
        GroupIdToNameBox *ptr = (GroupIdToNameBox *)s;
        ptr->size += 2;

        for (i=0; i<ptr->nb_entries; i++) {
                ptr->size += 5;
                if (ptr->entries[i].name) ptr->size += strlen(ptr->entries[i].name);
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#ifndef GPAC_DISABLE_ISOM_HINTING

GF_Box *fdpa_New()
{
        ISOM_DECL_BOX_ALLOC(GF_FDpacketBox, GF_ISOM_BOX_TYPE_FDPA);
        return (GF_Box *)tmp;
}

void fdpa_del(GF_Box *s)
{
        u32 i;
        GF_FDpacketBox *ptr = (GF_FDpacketBox *)s;
        if (ptr == NULL) return;

        if (ptr->headers) {
                for (i=0; i<ptr->header_ext_count; i++) {
                        if (ptr->headers[i].data) gf_free(ptr->headers[i].data);
                }
                gf_free(ptr->headers);
        }
        gf_free(ptr);
}

GF_Err fdpa_Read(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_FDpacketBox *ptr = (GF_FDpacketBox *)s;

        ISOM_DECREASE_SIZE(ptr, 3);
        ptr->info.sender_current_time_present = gf_bs_read_int(bs, 1);
        ptr->info.expected_residual_time_present = gf_bs_read_int(bs, 1);
        ptr->info.session_close_bit = gf_bs_read_int(bs, 1);
        ptr->info.object_close_bit = gf_bs_read_int(bs, 1);
        gf_bs_read_int(bs, 4);
        ptr->info.transport_object_identifier = gf_bs_read_u16(bs);
        ISOM_DECREASE_SIZE(ptr, 2);
        ptr->header_ext_count = gf_bs_read_u16(bs);
        if (ptr->header_ext_count*2>ptr->size) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in fdpa\n", ptr->header_ext_count));
                return GF_ISOM_INVALID_FILE;
        }

        GF_SAFE_ALLOC_N(ptr->headers, ptr->header_ext_count, GF_LCTheaderExtension);
        for (i=0; i<ptr->header_ext_count; i++) {
                ptr->headers[i].header_extension_type = gf_bs_read_u8(bs);
                ISOM_DECREASE_SIZE(ptr, 1);

                if (ptr->headers[i].header_extension_type > 127) {
                        gf_bs_read_data(bs, (char *) ptr->headers[i].content, 3);
                } else {
                        ISOM_DECREASE_SIZE(ptr, 1);
                        ptr->headers[i].data_length = gf_bs_read_u8(bs);
                        if (ptr->headers[i].data_length) {
                                ptr->headers[i].data_length = 4*ptr->headers[i].data_length - 2;
                                ptr->headers[i].data = gf_malloc(sizeof(char) * ptr->headers[i].data_length);
                                gf_bs_read_data(bs, ptr->headers[i].data, ptr->headers[i].data_length);
                        }
                }
        }
        return GF_OK;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err fdpa_Write(GF_Box *s, GF_BitStream *bs)
{
        u32 i;
        GF_FDpacketBox *ptr = (GF_FDpacketBox *) s;
        if (!s) return GF_BAD_PARAM;

        gf_bs_write_int(bs, ptr->info.sender_current_time_present, 1);
        gf_bs_write_int(bs, ptr->info.expected_residual_time_present, 1);
        gf_bs_write_int(bs, ptr->info.session_close_bit, 1);
        gf_bs_write_int(bs, ptr->info.object_close_bit, 1);
        gf_bs_write_int(bs, 0, 4);
        ptr->info.transport_object_identifier = gf_bs_read_u16(bs);
        gf_bs_write_u16(bs, ptr->header_ext_count);
        for (i=0; i<ptr->header_ext_count; i++) {
                gf_bs_write_u8(bs, ptr->headers[i].header_extension_type);
                if (ptr->headers[i].header_extension_type > 127) {
                        gf_bs_write_data(bs, (const char *) ptr->headers[i].content, 3);
                } else {
                        gf_bs_write_u8(bs, ptr->headers[i].data_length ? (ptr->headers[i].data_length+2)/4 : 0);
                        if (ptr->headers[i].data_length) {
                                gf_bs_write_data(bs, ptr->headers[i].data, ptr->headers[i].data_length);
                        }
                }
        }
        return GF_OK;
}

GF_Err fdpa_Size(GF_Box *s)
{
        u32 i;
        GF_FDpacketBox *ptr = (GF_FDpacketBox *)s;

        ptr->size += 5;

        for (i=0; i<ptr->header_ext_count; i++) {
                ptr->size += 1;
                if (ptr->headers[i].header_extension_type > 127) {
                        ptr->size += 3;
                } else {
                        ptr->size += 1 + ptr->headers[i].data_length;
                }
        }
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


GF_Box *extr_New()
{
        ISOM_DECL_BOX_ALLOC(GF_ExtraDataBox, GF_ISOM_BOX_TYPE_EXTR);
        return (GF_Box *)tmp;
}

void extr_del(GF_Box *s)
{
        GF_ExtraDataBox *ptr = (GF_ExtraDataBox *)s;
        if (ptr == NULL) return;
        if (ptr->feci) gf_isom_box_del((GF_Box*)ptr->feci);

        if (ptr->data) gf_free(ptr->data);
        gf_free(ptr);
}

GF_Err extr_Read(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_ExtraDataBox *ptr = (GF_ExtraDataBox *)s;

        e = gf_isom_box_parse((GF_Box**) &ptr->feci, bs);
        if (e) return e;
        if (ptr->feci->size>ptr->size) return GF_ISOM_INVALID_MEDIA;
        ptr->data_length = (u32) (ptr->size - ptr->feci->size);
        ptr->data = gf_malloc(sizeof(char)*ptr->data_length);
        gf_bs_read_data(bs, ptr->data, ptr->data_length);

        return GF_OK;
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err extr_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_ExtraDataBox *ptr = (GF_ExtraDataBox *) s;
        if (!s) return GF_BAD_PARAM;
        if (ptr->feci) {
                e = gf_isom_box_write((GF_Box *)ptr->feci, bs);
                if (e) return e;
        }
        gf_bs_write_data(bs, ptr->data, ptr->data_length);
        return GF_OK;
}

GF_Err extr_Size(GF_Box *s)
{
        GF_Err e;
        GF_ExtraDataBox *ptr = (GF_ExtraDataBox *) s;

        if (ptr->feci) {
                e = gf_isom_box_size((GF_Box *)ptr->feci);
                if (e) return e;
                ptr->size += ptr->feci->size;
        }
        ptr->size += ptr->data_length;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/



GF_Box *fdsa_New()
{
        ISOM_DECL_BOX_ALLOC(GF_HintSample, GF_ISOM_BOX_TYPE_FDSA);
        if (!tmp) return NULL;
        tmp->packetTable = gf_list_new();
        tmp->hint_subtype = GF_ISOM_BOX_TYPE_FDP_STSD;
        return (GF_Box*)tmp;
}

void fdsa_del(GF_Box *s)
{
        GF_HintSample *ptr = (GF_HintSample *)s;
        gf_isom_box_array_del(ptr->packetTable);
        if (ptr->extra_data) gf_isom_box_del((GF_Box*)ptr->extra_data);
        gf_free(ptr);
}

GF_Err fdsa_AddBox(GF_Box *s, GF_Box *a)
{
        GF_HintSample *ptr = (GF_HintSample *)s;
        switch(a->type) {
        case GF_ISOM_BOX_TYPE_FDPA:
                gf_list_add(ptr->packetTable, a);
                break;
        case GF_ISOM_BOX_TYPE_EXTR:
                if (ptr->extra_data) ERROR_ON_DUPLICATED_BOX(a, ptr)
                ptr->extra_data = (GF_ExtraDataBox*)a;
                break;
        default:
                return gf_isom_box_add_default(s, a);
        }
        return GF_OK;
}
GF_Err fdsa_Read(GF_Box *s, GF_BitStream *bs)
{
        return gf_isom_box_array_read(s, bs, fdsa_AddBox);
}


#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err fdsa_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_HintSample *ptr = (GF_HintSample *) s;
        if (!s) return GF_BAD_PARAM;

        e = gf_isom_box_array_write(s, ptr->packetTable, bs);
        if (e) return e;
        if (ptr->extra_data) {
                e = gf_isom_box_write((GF_Box *)ptr->extra_data, bs);
                if (e) return e;
        }
        return GF_OK;
}

GF_Err fdsa_Size(GF_Box *s)
{
        GF_HintSample *ptr = (GF_HintSample*)s;
        GF_Err e;

         if (ptr->extra_data) {
                e = gf_isom_box_size((GF_Box *)ptr->extra_data);
                if (e) return e;
                ptr->size += ptr->extra_data->size;
        }
        return gf_isom_box_array_size(s, ptr->packetTable);
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

#endif /*GPAC_DISABLE_ISOM_HINTING*/


void trik_del(GF_Box *s)
{
        GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;
        if (ptr == NULL) return;
        if (ptr->entries) gf_free(ptr->entries);
        gf_free(ptr);
}

GF_Err trik_Read(GF_Box *s,GF_BitStream *bs)
{
        u32 i;
        GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;
        ptr->entry_count = (u32) ptr->size;
        ptr->entries = (GF_TrickPlayBoxEntry *) gf_malloc(ptr->entry_count * sizeof(GF_TrickPlayBoxEntry) );
        if (ptr->entries == NULL) return GF_OUT_OF_MEM;

        for (i=0; i< ptr->entry_count; i++) {
                ptr->entries[i].pic_type = gf_bs_read_int(bs, 2);
                ptr->entries[i].dependency_level = gf_bs_read_int(bs, 6);
        }
        return GF_OK;
}

GF_Box *trik_New()
{
        ISOM_DECL_BOX_ALLOC(GF_TrickPlayBox, GF_ISOM_BOX_TYPE_TRIK);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err trik_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;

        for (i=0; i < ptr->entry_count; i++ ) {
                gf_bs_write_int(bs, ptr->entries[i].pic_type, 2);
                gf_bs_write_int(bs, ptr->entries[i].dependency_level, 6);
        }
        return GF_OK;
}

GF_Err trik_Size(GF_Box *s)
{
        GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;
        ptr->size += 8 * ptr->entry_count;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


void bloc_del(GF_Box *s)
{
        gf_free(s);
}

GF_Err bloc_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_BaseLocationBox *ptr = (GF_BaseLocationBox *) s;

        ISOM_DECREASE_SIZE(s, 256)
        gf_bs_read_data(bs, (char *) ptr->baseLocation, 256);
        ISOM_DECREASE_SIZE(s, 256)
        gf_bs_read_data(bs, (char *) ptr->basePurlLocation, 256);
        ISOM_DECREASE_SIZE(s, 512)
        gf_bs_skip_bytes(bs, 512);
        return GF_OK;
}

GF_Box *bloc_New()
{
        ISOM_DECL_BOX_ALLOC(GF_BaseLocationBox, GF_ISOM_BOX_TYPE_TRIK);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err bloc_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        u32 i;
        GF_BaseLocationBox *ptr = (GF_BaseLocationBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_data(bs, (const char *) ptr->baseLocation, 256);
        gf_bs_write_data(bs, (const char *) ptr->basePurlLocation, 256);
        for (i=0; i < 64; i++ ) {
                gf_bs_write_u64(bs, 0);
        }
        return GF_OK;
}

GF_Err bloc_Size(GF_Box *s)
{
        s->size += 1024;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/

void ainf_del(GF_Box *s)
{
        GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s;
        if (ptr->APID) gf_free(ptr->APID);
        gf_free(s);
}

GF_Err ainf_Read(GF_Box *s,GF_BitStream *bs)
{
        GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s;

        ISOM_DECREASE_SIZE(s, 4)
        ptr->profile_version = gf_bs_read_u32(bs);
        return gf_isom_read_null_terminated_string(s, bs, s->size, &ptr->APID);
}

GF_Box *ainf_New()
{
        ISOM_DECL_BOX_ALLOC(GF_AssetInformationBox, GF_ISOM_BOX_TYPE_AINF);
        return (GF_Box *)tmp;
}

#ifndef GPAC_DISABLE_ISOM_WRITE

GF_Err ainf_Write(GF_Box *s, GF_BitStream *bs)
{
        GF_Err e;
        GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s;

        e = gf_isom_full_box_write(s, bs);
        if (e) return e;
        gf_bs_write_u32(bs, ptr->profile_version);
        gf_bs_write_data(bs, ptr->APID, (u32) strlen(ptr->APID) + 1);
        return GF_OK;
}

GF_Err ainf_Size(GF_Box *s)
{
        GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s;
        s->size += 4 +  strlen(ptr->APID) + 1;
        return GF_OK;
}

#endif /*GPAC_DISABLE_ISOM_WRITE*/


#endif /*GPAC_DISABLE_ISOM*/

/* [<][>][^][v][top][bottom][index][help] */