Commit message: fixed #2163
CVE: CVE-2022-29340
CWE: CWE-476
Vulnerability description: GPAC 2.1-DEV-rev87-g053aae8-master. has a Null Pointer Dereference vulnerability in gf_isom_parse_movie_boxes_internal due to improper return value handling of GF_SKIP_BOX, which causes a Denial of Service. This vulnerability was fixed in commit 37592ad.

Project: gpac


GF_Box *gf_isom_box_new_ex(u32 boxType, u32 parentType, Bool skip_logs, Bool is_root_box)
{
	GF_Box *a;
	s32 idx = get_box_reg_idx(boxType, parentType, 0);
	if (idx==0) {
#ifndef GPAC_DISABLE_LOG
		if (!skip_logs && (boxType != GF_ISOM_BOX_TYPE_UNKNOWN) && (boxType != GF_ISOM_BOX_TYPE_UUID)) {
			switch (parentType) {
			case GF_ISOM_BOX_TYPE_ILST:
			case GF_ISOM_BOX_TYPE_META:
			case GF_ISOM_BOX_TYPE_UDTA:
			case GF_ISOM_BOX_TYPE_UNKNOWN:
			case GF_ISOM_BOX_TYPE_iTunesSpecificInfo:
			case GF_QT_BOX_TYPE_WAVE:
				break;
			//some sample descritions are handled as generic ones but we know them, don't warn
			case GF_ISOM_BOX_TYPE_STSD:
				if (boxType==GF_ISOM_SUBTYPE_FFV1) break;
				//fallthrough
			default:
				if (boxType==GF_ISOM_BOX_TYPE_GDAT) break;

				if (is_root_box) {
					GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] Unknown top-level box type %s\n", gf_4cc_to_str(boxType)));
				} else if (parentType) {
					char szName[GF_4CC_MSIZE];
					strcpy(szName, gf_4cc_to_str(parentType));
					GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] Unknown box type %s in parent %s\n", gf_4cc_to_str(boxType), szName));
				} else {
					GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] Unknown box type %s\n", gf_4cc_to_str(boxType)));
				}
				break;
			}
		}
#endif
        if (boxType==GF_ISOM_BOX_TYPE_UUID) {
            a = uuid_box_new();
            if (a) a->registry = &box_registry[1];
        } else {
            a = unkn_box_new();
            if (a) {
            	((GF_UnknownBox *)a)->original_4cc = boxType;
            	a->registry = &box_registry[0];
			}
        }
		return a;
	}
	a = box_registry[idx].new_fn();

	if (a) {
		if (a->type!=GF_ISOM_BOX_TYPE_UUID) {
			if (a->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
				((GF_UnknownBox *)a)->original_4cc = boxType;
			} else {
				a->type = boxType;
			}
		}
		a->registry = &box_registry[idx];

		if ((a->type==GF_ISOM_BOX_TYPE_COLR) && (parentType==GF_ISOM_BOX_TYPE_JP2H)) {
			((GF_ColourInformationBox *)a)->is_jp2 = GF_TRUE;
		}

	}
	return a;

Project: gpac
File: isom_intern.c

GF_TrackBox *gf_isom_get_track_from_id(GF_MovieBox *moov, GF_ISOTrackID trackID)
{
	u32 i, count;
	if (!moov || !trackID) return NULL;

	count = gf_list_count(moov->trackList);
	for (i = 0; i<count; i++) {
		GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(moov->trackList, i);
		if (trak->Header->trackID == trackID) return trak;
	}
	return NULL;
}

Project: gpac


GF_Box *gf_isom_box_find_child(GF_List *children, u32 code)
{
	u32 i, count;
	if (!children) return NULL;
	count = gf_list_count(children);
	for (i=0; i<count; i++) {
		GF_Box *c = gf_list_get(children, i);
		if (c->type==code) return c;

		if (c->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
			if (((GF_UnknownBox*)c)->original_4cc==code)
				return c;
		}
		if (c->type==GF_ISOM_BOX_TYPE_UUID) {
			if (((GF_UUIDBox*)c)->internal_4cc==code)
				return c;
		}
	}
	return NULL;

Project: gpac

GF_Err gf_isom_box_write_header(GF_Box *ptr, GF_BitStream *bs)
{
	u64 start;
	if (! bs || !ptr) return GF_BAD_PARAM;
	if (!ptr->size) return GF_ISOM_INVALID_FILE;

	start = gf_bs_get_position(bs);
	if (ptr->size > 0xFFFFFFFF) {
		gf_bs_write_u32(bs, 1);
	} else {
		gf_bs_write_u32(bs, (u32) ptr->size);
	}
	gf_bs_write_u32(bs, ptr->type);
	if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
		u32 i;
		Bool conv_uuid = GF_TRUE;
		GF_UUIDBox *uuidb = (GF_UUIDBox *)ptr;
		char strUUID[32];

		switch (uuidb->internal_4cc) {
		case GF_ISOM_BOX_UUID_TENC:
			memcpy(strUUID, "8974dbce7be74c5184f97148f9882554", 32);
			break;
		case GF_ISOM_BOX_UUID_PSEC:
			memcpy(strUUID, "A2394F525A9B4F14A2446C427C648DF4", 32);
			break;
		case GF_ISOM_BOX_UUID_MSSM:
			memcpy(strUUID, "A5D40B30E81411DDBA2F0800200C9A66", 32);
			break;
		case GF_ISOM_BOX_UUID_PSSH:
			memcpy(strUUID, "D08A4F1810F34A82B6C832D8ABA183D3", 32);
			break;
		case GF_ISOM_BOX_UUID_TFXD:
			memcpy(strUUID, "6D1D9B0542D544E680E2141DAFF757B2", 32);
			break;
		default:
			conv_uuid = GF_FALSE;
			break;
		}

		if (conv_uuid) {
			char uuid[16];
			for (i = 0; i < 16; i++) {
				char t[3];
				t[2] = 0;
				t[0] = strUUID[2*i];
				t[1] = strUUID[2*i+1];
				uuid[i] = (u8) strtol(t, NULL, 16);
			}
			gf_bs_write_data(bs, uuid, 16);
		} else {
			gf_bs_write_data(bs, uuidb->uuid, 16);
		}
	}
	if (ptr->size > 0xFFFFFFFF)
		gf_bs_write_u64(bs, ptr->size);

	GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Written Box type %s size "LLD" start "LLD"\n", gf_4cc_to_str(ptr->type), ptr->size, start));

	return GF_OK;
}

Project: gpac

static void convert_compact_sample_groups(GF_List *child_boxes, GF_List *sampleGroups)
{
	u32 i;
	for (i=0; i<gf_list_count(sampleGroups); i++) {
		u32 j;
		GF_SampleGroupBox *sbgp;
		GF_CompactSampleGroupBox *csgp = gf_list_get(sampleGroups, i);
		if (csgp->type != GF_ISOM_BOX_TYPE_CSGP) continue;

		gf_list_rem(sampleGroups, i);
		gf_list_del_item(child_boxes, csgp);

		sbgp = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP);
		gf_list_insert(sampleGroups, sbgp, i);
		gf_list_add(child_boxes, sbgp);
		i--;

		sbgp->grouping_type = csgp->grouping_type;
		if (csgp->grouping_type_parameter) {
			sbgp->grouping_type_parameter = csgp->grouping_type_parameter;
			sbgp->version = 1;
		}
		sbgp->entry_count = 0;
		for (j=0; j<csgp->pattern_count; j++) {
			u32 k=0;
			u32 nb_samples = csgp->patterns[j].sample_count;
			//unroll the pattern
			while (nb_samples) {
				u32 nb_same_index=1;
				if (csgp->patterns[j].length<=k)
					break;
				u32 sg_idx = csgp->patterns[j].sample_group_description_indices[k];
				while (nb_same_index+k<csgp->patterns[j].length) {
					if (csgp->patterns[j].sample_group_description_indices[k+nb_same_index] != sg_idx)
						break;
					nb_same_index++;
				}
				sbgp->sample_entries = gf_realloc(sbgp->sample_entries, sizeof(GF_SampleGroupEntry) * (sbgp->entry_count+1));
				if (nb_same_index>nb_samples)
					nb_same_index = nb_samples;

				sbgp->sample_entries[sbgp->entry_count].sample_count = nb_same_index;
				sbgp->sample_entries[sbgp->entry_count].group_description_index = sg_idx;
				nb_samples -= nb_same_index;
				sbgp->entry_count++;
				k+= nb_same_index;
				if (k==csgp->patterns[j].length)
					k = 0;
			}
		}
		gf_isom_box_del((GF_Box*)csgp);
	}
}

Project: gpac

GF_Err gf_isom_box_array_size(GF_Box *parent, GF_List *list)
{
	GF_Err e;
	u32 count, i;
	if (! list) return GF_OK;

	count = gf_list_count(list);
	for (i = 0; i < count; i++) {
		GF_Box *a = (GF_Box *)gf_list_get(list, i);
		if (a) {
			e = gf_isom_box_size(a);
			if (e) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("ISOBMF: Error %s computing box %s size\n", gf_error_to_string(e), gf_4cc_to_str(a->type) ));
				return e;
			}
			parent->size += a->size;
		}
	}
	return GF_OK;
}

Project: gpac
File: isom_intern.c

u32 gf_isom_sample_get_subsamples_count(GF_ISOFile *movie, u32 track)
{
	GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
	if (!track) return 0;
	if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return 0;
	return gf_list_count(trak->Media->information->sampleTable->sub_samples);
}

Project: gpac

GF_EXPORT
GF_Err gf_isom_box_write(GF_Box *a, GF_BitStream *bs)
{
	GF_Err e;
	u64 pos = gf_bs_get_position(bs);
	if (!a) return GF_BAD_PARAM;
	//box has been disabled, do not write
	if (!a->size) return GF_OK;
	
	if (a->registry->disabled) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Box %s disabled registry, skip write\n", gf_4cc_to_str(a->type)));
		return GF_OK;
	}

	GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Box %s size %d write\n", gf_4cc_to_str(a->type), a->size));
	e = gf_isom_box_write_listing(a, bs);
	if (e) return e;
	if (a->child_boxes) {
		e = gf_isom_box_array_write(a, a->child_boxes, bs);
	}
	pos = gf_bs_get_position(bs) - pos;
	if (pos != a->size) {
		if (a->type != GF_ISOM_BOX_TYPE_MDAT) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box %s wrote "LLU" bytes but size is "LLU"\n", gf_4cc_to_str(a->type), pos, a->size ));
		}
	}
	return e;

Project: gpac


Bool gf_isom_box_is_file_level(GF_Box *s)
{
	if (!s || !s->registry) return GF_FALSE;
	if (strstr(s->registry->parents_4cc, "file")!= NULL) return GF_TRUE;
	if (strstr(s->registry->parents_4cc, "*")!= NULL) return GF_TRUE;
	return GF_FALSE;

Project: gpac


GF_Err gf_isom_box_dump(void *ptr, FILE * trace)
{
	GF_Box *a = (GF_Box *) ptr;

	if (!a) {
		gf_fprintf(trace, "<!--ERROR: NULL Box Found-->\n");
		return GF_OK;
	}
	if (!a->registry) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isom] trying to dump box %s not registered\n", gf_4cc_to_str(a->type) ));
		return GF_ISOM_INVALID_FILE;
	}
	a->registry->dump_fn(a, trace);
	return GF_OK;

Project: gpac

void gf_isom_box_array_del(GF_List *boxlist)
{
	gf_isom_box_array_reset(boxlist);
	gf_list_del(boxlist);
}

Project: gpac

GF_EXPORT
GF_Err gf_isom_box_size(GF_Box *a)
{
	GF_Err e;
	if (!a) return GF_BAD_PARAM;
	if (a->registry->disabled) {
		a->size = 0;
		return GF_OK;
	}
	e = gf_isom_box_size_listing(a);
	if (e) return e;
	//box size set to 0 (not even a header), abort traversal
	if (!a->size) return GF_OK;

	if (a->child_boxes) {
		e = gf_isom_box_array_size(a, a->child_boxes);
		if (e) return e;
	}
	return GF_OK;

Project: gpac
File: isom_intern.c

GF_Err gf_isom_set_write_callback(GF_ISOFile *mov,
 			GF_Err (*on_block_out)(void *cbk, u8 *data, u32 block_size),
			GF_Err (*on_block_patch)(void *usr_data, u8 *block, u32 block_size, u64 block_offset, Bool is_insert),
 			void *usr_data,
 			u32 block_size)
{
#ifndef GPAC_DISABLE_ISOM_WRITE
	if (mov->finalName && !strcmp(mov->finalName, "_gpac_isobmff_redirect")) {}
	else if (mov->fileName && !strcmp(mov->fileName, "_gpac_isobmff_redirect")) {}
	else return GF_BAD_PARAM;
	mov->on_block_out = on_block_out;
	mov->on_block_patch = on_block_patch;
	mov->on_block_out_usr_data = usr_data;
	mov->on_block_out_block_size = block_size;
	return GF_OK;
#else
	return GF_NOT_SUPPORTED;
#endif
}

Project: gpac


GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs)
{
	if (!a) return GF_BAD_PARAM;
	if (!a->registry) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Read invalid box type %s without registry\n", gf_4cc_to_str(a->type) ));
		return GF_ISOM_INVALID_FILE;
	}
	return a->registry->read_fn(a, bs);

Project: gpac


void gf_isom_check_position_list(GF_Box *s, GF_List *childlist, u32 *pos)
{
	u32 i, count;
	if (!s || (s->internal_flags & GF_ISOM_ORDER_FREEZE))
		return;
	count = gf_list_count(childlist);
	for (i=0; i<count; i++) {
		GF_Box *child = gf_list_get(childlist, i);
		gf_isom_check_position(s, child, pos);
	}

Project: gpac
File: isom_intern.c

GF_ISOFile *gf_isom_new_movie()
{
	GF_ISOFile *mov = (GF_ISOFile*)gf_malloc(sizeof(GF_ISOFile));
	if (mov == NULL) {
		gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
		return NULL;
	}
	memset(mov, 0, sizeof(GF_ISOFile));

	/*init the boxes*/
	mov->TopBoxes = gf_list_new();
	if (!mov->TopBoxes) {
		gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
		gf_free(mov);
		return NULL;
	}

	/*default storage mode is flat*/
	mov->storageMode = GF_ISOM_STORE_FLAT;
	mov->es_id_default_sync = -1;
	return mov;
}

Project: gpac


void gf_isom_box_remove_from_parent(GF_Box *parent_box, GF_Box *box)
{
	if (parent_box && parent_box->registry && parent_box->registry->add_rem_fn) {
		parent_box->registry->add_rem_fn(parent_box, box, GF_TRUE);
	}

Project: gpac


static u32 get_box_reg_idx(u32 boxCode, u32 parent_type, u32 start_from)
{
	u32 i=0, count = gf_isom_get_num_supported_boxes();
	const char *parent_name = parent_type ? gf_4cc_to_str(parent_type) : NULL;

	if (!start_from) start_from = 1;

	for (i=start_from; i<count; i++) {
		u32 start_par_from;
		if (box_registry[i].box_4cc != boxCode)
			continue;

		if (!parent_type)
			return i;
		if (strstr(box_registry[i].parents_4cc, parent_name) != NULL)
			return i;
		if (strstr(box_registry[i].parents_4cc, "*") != NULL)
			return i;

		if (strstr(box_registry[i].parents_4cc, "sample_entry") == NULL)
			continue;

		/*parent is a sample entry, check if the parent_type matches a sample entry box (eg its parent must be stsd)*/

		if (parent_type==GF_QT_SUBTYPE_RAW)
			return i;

		start_par_from = 0;
		while (parent_type) {
			//locate parent registry
			u32 j = get_box_reg_idx(parent_type, 0, start_par_from);
			if (!j) break;
			//if parent registry has "stsd" as parent, this is a sample entry
			if (box_registry[j].parents_4cc && (strstr(box_registry[j].parents_4cc, "stsd") != NULL))
				return i;
			start_par_from = j+1;
		}
	}
	return 0;

Project: gpac
File: isom_intern.c

static void FixSDTPInTRAF(GF_MovieFragmentBox *moof)
{
	u32 k;
	if (!moof)
		return;

	for (k = 0; k < gf_list_count(moof->TrackList); k++) {
		GF_TrackFragmentBox *traf = gf_list_get(moof->TrackList, k);
		if (traf->sdtp) {
			GF_TrackFragmentRunBox *trun;
			u32 j = 0, sample_index = 0;

			if (traf->sdtp->sampleCount == gf_list_count(traf->TrackRuns)) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: TRAF box of track id=%u contains a SDTP. Converting to TRUN sample flags.\n", traf->tfhd->trackID));
			}

			while ((trun = (GF_TrackFragmentRunBox*)gf_list_enum(traf->TrackRuns, &j))) {
				u32 i;
				trun->flags |= GF_ISOM_TRUN_FLAGS;
				for (i=0; i<trun->nb_samples; i++) {
					GF_TrunEntry *entry = &trun->samples[i];
					const u8 info = traf->sdtp->sample_info[sample_index];
					entry->flags |= GF_ISOM_GET_FRAG_DEPEND_FLAGS(info >> 6, info >> 4, info >> 2, info);
					sample_index++;
					if (sample_index > traf->sdtp->sampleCount) {
						GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: TRAF box of track id=%u contained an inconsistent SDTP.\n", traf->tfhd->trackID));
						return;
					}
				}
			}
			if (sample_index < traf->sdtp->sampleCount) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: TRAF box of track id=%u list less samples than SDTP.\n", traf->tfhd->trackID));
			}
			gf_isom_box_del_parent(&traf->child_boxes, (GF_Box*)traf->sdtp);
			traf->sdtp = NULL;
		}
	}
}

Project: gpac
File: isom_intern.c

GF_ISOFile *gf_isom_open_file(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
{
	GF_Err e;
	u64 bytes;
	GF_ISOFile *mov = gf_isom_new_movie();
	if (!mov || !fileName) return NULL;

	mov->fileName = gf_strdup(fileName);
	mov->openMode = OpenMode;

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
	if (OpenMode==GF_ISOM_OPEN_READ_DUMP)
		mov->store_traf_map = GF_TRUE;
#endif

	if ( (OpenMode == GF_ISOM_OPEN_READ) || (OpenMode == GF_ISOM_OPEN_READ_DUMP) || (OpenMode == GF_ISOM_OPEN_READ_EDIT) ) {
		if (OpenMode == GF_ISOM_OPEN_READ_EDIT) {
			mov->openMode = GF_ISOM_OPEN_READ_EDIT;

			// create a memory edit map in case we add samples, typically during import
			e = gf_isom_datamap_new(NULL, tmp_dir, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap);
			if (e) {
				gf_isom_set_last_error(NULL, e);
				gf_isom_delete_movie(mov);
				return NULL;
			}
		} else {
			mov->openMode = GF_ISOM_OPEN_READ;
		}
		mov->es_id_default_sync = -1;
		//for open, we do it the regular way and let the GF_DataMap assign the appropriate struct
		//this can be FILE (the only one supported...) as well as remote
		//(HTTP, ...),not suported yet
		//the bitstream IS PART OF the GF_DataMap
		//as this is read-only, use a FileMapping. this is the only place where
		//we use file mapping
		e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &mov->movieFileMap);
		if (e) {
			gf_isom_set_last_error(NULL, e);
			gf_isom_delete_movie(mov);
			return NULL;
		}

		if (OpenMode == GF_ISOM_OPEN_READ_DUMP) {
			mov->FragmentsFlags |= GF_ISOM_FRAG_READ_DEBUG;
		}
	} else {

#ifdef GPAC_DISABLE_ISOM_WRITE
		//not allowed for READ_ONLY lib
		gf_isom_delete_movie(mov);
		gf_isom_set_last_error(NULL, GF_ISOM_INVALID_MODE);
		return NULL;

#else

		//set a default output name for edited file
		mov->finalName = (char*)gf_malloc(strlen(fileName) + 5);
		if (!mov->finalName) {
			gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
			gf_isom_delete_movie(mov);
			return NULL;
		}
		strcpy(mov->finalName, "out_");
		strcat(mov->finalName, fileName);

		//open the original file with edit tag
		e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_EDIT, &mov->movieFileMap);
		//if the file doesn't exist, we assume it's wanted and create one from scratch
		if (e) {
			gf_isom_set_last_error(NULL, e);
			gf_isom_delete_movie(mov);
			return NULL;
		}
		//and create a temp fileName for the edit
		e = gf_isom_datamap_new("_gpac_isobmff_tmp_edit", tmp_dir, GF_ISOM_DATA_MAP_WRITE, & mov->editFileMap);
		if (e) {
			gf_isom_set_last_error(NULL, e);
			gf_isom_delete_movie(mov);
			return NULL;
		}

		mov->es_id_default_sync = -1;

#endif
	}

	//OK, let's parse the movie...
	mov->LastError = gf_isom_parse_movie_boxes(mov, NULL, &bytes, 0);

#if 0
	if (!mov->LastError && (OpenMode == GF_ISOM_OPEN_CAT_FRAGMENTS)) {
		gf_isom_datamap_del(mov->movieFileMap);
		/*reopen the movie file map in cat mode*/
		mov->LastError = gf_isom_datamap_new(fileName, tmp_dir, GF_ISOM_DATA_MAP_CAT, & mov->movieFileMap);
	}
#endif

	if (mov->LastError) {
		gf_isom_set_last_error(NULL, mov->LastError);
		gf_isom_delete_movie(mov);
		return NULL;
	}

	mov->nb_box_init_seg = gf_list_count(mov->TopBoxes);
	return mov;
}

Project: gpac
File: isom_intern.c

GF_TrackBox *gf_isom_get_track_from_original_id(GF_MovieBox *moov, u32 originalID, u32 originalFile)
{
	u32 i, count;
	if (!moov || !originalID) return NULL;

	count = gf_list_count(moov->trackList);
	for (i = 0; i<count; i++) {
		GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(moov->trackList, i);
		if ((trak->originalFile == originalFile) && (trak->originalID == originalID)) return trak;
	}
	return NULL;
}

Project: gpac
File: isom_intern.c

u32 gf_isom_sample_get_subsample_entry(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, GF_SubSampleInfoEntry **sub_sample)
{
	u32 i, count, last_sample;
	GF_SubSampleInformationBox *sub_samples=NULL;
	GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
	if (sub_sample) *sub_sample = NULL;
	if (!track) return 0;
	if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return 0;
	count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
	for (i=0; i<count; i++) {
		sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
		if (sub_samples->flags==flags) break;
		sub_samples = NULL;
	}
	if (!sub_samples) return 0;

	last_sample = 0;
	count = gf_list_count(sub_samples->Samples);
	for (i=0; i<count; i++) {
		GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry *) gf_list_get(sub_samples->Samples, i);
		if (last_sample + pSamp->sample_delta == sampleNumber) {
			if (sub_sample) *sub_sample = pSamp;
			return gf_list_count(pSamp->SubSamples);
		}
		last_sample += pSamp->sample_delta;
	}
	return 0;
}

Project: gpac


void gf_isom_check_position(GF_Box *s, GF_Box *child, u32 *pos)
{
	if (!s || !s->child_boxes || !child || !pos) return;
	if (s->internal_flags & GF_ISOM_ORDER_FREEZE)
		return;

	s32 cur_pos = gf_list_find(s->child_boxes, child);

	//happens when partially cloning boxes 
	if (cur_pos < 0) return;

	if (cur_pos != (s32) *pos) {
		gf_list_del_item(s->child_boxes, child);
		gf_list_insert(s->child_boxes, child, *pos);
	}
	(*pos)++;

Project: gpac


static GF_Err gf_isom_full_box_read(GF_Box *ptr, GF_BitStream *bs)
{
	if (ptr->registry->max_version_plus_one) {
		GF_FullBox *self = (GF_FullBox *) ptr;
		ISOM_DECREASE_SIZE(ptr, 4)
		self->version = gf_bs_read_u8(bs);
		self->flags = gf_bs_read_u24(bs);
	}
	return GF_OK;

Project: gpac
File: isom_intern.c

void gf_isom_delete_movie(GF_ISOFile *mov)
{
	if (!mov) return;

	//these are our two main files
	if (mov->movieFileMap) gf_isom_datamap_del(mov->movieFileMap);

#ifndef GPAC_DISABLE_ISOM_WRITE
	if (mov->editFileMap) {
		gf_isom_datamap_del(mov->editFileMap);
	}
	if (mov->finalName) gf_free(mov->finalName);
#endif

	gf_isom_box_array_del(mov->TopBoxes);
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
	gf_isom_box_array_del(mov->moof_list);
	if (mov->mfra)
		gf_isom_box_del((GF_Box*)mov->mfra);
	if (mov->sidx_pts_store)
		gf_free(mov->sidx_pts_store);
	if (mov->sidx_pts_next_store)
		gf_free(mov->sidx_pts_next_store);

	if (mov->main_sidx)
		gf_isom_box_del((GF_Box*)mov->main_sidx);

	if (mov->block_buffer)
		gf_free(mov->block_buffer);
#endif
	if (mov->last_producer_ref_time)
		gf_isom_box_del((GF_Box *) mov->last_producer_ref_time);
	if (mov->fileName) gf_free(mov->fileName);
	gf_free(mov);
}

Project: gpac

GF_Err gf_isom_box_parse(GF_Box **outBox, GF_BitStream *bs)
{
	return gf_isom_box_parse_ex(outBox, bs, 0, GF_FALSE, 0);
}

Project: gpac


void gf_isom_box_freeze_order(GF_Box *box)
{
	u32 i=0;
	GF_Box *child;
	if (!box) return;
	box->internal_flags |= GF_ISOM_ORDER_FREEZE;

	while ((child = gf_list_enum(box->child_boxes, &i))) {
		gf_isom_box_freeze_order(child);
	}

Project: gpac


GF_Err gf_isom_box_dump_start(GF_Box *a, const char *name, FILE * trace)
{
	gf_fprintf(trace, "<%s ", name);
	if (a->size > 0xFFFFFFFF) {
		gf_fprintf(trace, "LargeSize=\""LLU"\" ", a->size);
	} else {
		gf_fprintf(trace, "Size=\"%u\" ", (u32) a->size);
	}
	if (a->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
		gf_fprintf(trace, "Type=\"%s\" ", gf_4cc_to_str(((GF_UnknownBox*)a)->original_4cc));
	} else {
		gf_fprintf(trace, "Type=\"%s\" ", gf_4cc_to_str(a->type));
	}

	if (a->type == GF_ISOM_BOX_TYPE_UUID) {
		u32 i;
		gf_fprintf(trace, "UUID=\"{");
		for (i=0; i<16; i++) {
			gf_fprintf(trace, "%02X", (unsigned char) ((GF_UUIDBox*)a)->uuid[i]);
			if ((i<15) && (i%4)==3) gf_fprintf(trace, "-");
		}
		gf_fprintf(trace, "}\" ");
	}

	if (a->registry->max_version_plus_one) {
		gf_fprintf(trace, "Version=\"%d\" Flags=\"%d\" ", ((GF_FullBox*)a)->version,((GF_FullBox*)a)->flags);
	}
	gf_fprintf(trace, "Specification=\"%s\" ", a->registry->spec);

	//don't write containers in test mode, that would require rewriting hashes whenever spec changes
	if (!gf_sys_is_test_mode()) {
		gf_fprintf(trace, "Container=\"%s\" ", a->registry->parents_4cc);
	}
	return GF_OK;

Project: gpac


Bool gf_isom_box_check_unique(GF_List *children, GF_Box *a)
{
	u32 i, count;
	if (!children) return GF_TRUE;
	count = gf_list_count(children);
	for (i=0; i<count; i++) {
		GF_Box *c = gf_list_get(children, i);
		if (c==a) continue;
		if (c->type==a->type) return GF_FALSE;
	}
	return GF_TRUE;

Project: gpac


void gf_isom_box_dump_done(const char *name, GF_Box *ptr, FILE *trace)
{
	if (ptr && ptr->child_boxes) {
		gf_isom_box_array_dump(ptr->child_boxes, trace);
	}
	if (name)
		gf_fprintf(trace, "</%s>\n", name);

Project: gpac

GF_EXPORT
u32 gf_isom_get_supported_box_type(u32 idx)
{
	return box_registry[idx].box_4cc;

Project: gpac
File: isom_intern.c

static void gf_isom_setup_traf_inheritance(GF_ISOFile *mov)
{
	u32 i, count;
	if (!mov->moov->mvex)
		return;
	count = gf_list_count(mov->moov->trackList);

	for (i=0; i<count; i++) {
		u32 refTrackNum=0;
		gf_isom_get_reference(mov, i+1, GF_ISOM_REF_TRIN, 1, &refTrackNum);
		if (refTrackNum) {
			GF_ISOTrackID tkid = gf_isom_get_track_id(mov, i+1);
			GF_ISOTrackID reftkid = gf_isom_get_track_id(mov, refTrackNum);
			GF_TrackExtendsBox *trex = GetTrex(mov->moov, tkid);
			if (trex) trex->inherit_from_traf_id = reftkid;
		}
	}
}

Project: gpac

GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u32 *boxType, u64 *bytesMissing, Bool progressive_mode)
{
	GF_Err e;
	GF_Blob *blob = NULL;

	//if associated file is a blob, lock blob before parsing !
	if (mov->movieFileMap && ((mov->movieFileMap->type == GF_ISOM_DATA_MEM) || (mov->movieFileMap->type == GF_ISOM_DATA_FILE))) {
		blob = ((GF_FileDataMap *)mov->movieFileMap)->blob;
	}

	if (blob)
		gf_mx_p(blob->mx);

	unused_bytes = 0;
	e = gf_isom_parse_movie_boxes_internal(mov, boxType, bytesMissing, progressive_mode);

	if (blob)
		gf_mx_v(blob->mx);
	return e;

}

Project: gpac

static GF_Err gf_isom_parse_movie_boxes_internal(GF_ISOFile *mov, u32 *boxType, u64 *bytesMissing, Bool progressive_mode)
{
	GF_Box *a;
	u64 totSize, mdat_end=0;
	GF_Err e = GF_OK;

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
	if (mov->single_moof_mode && mov->single_moof_state == 2) {
		return e;
	}

	/*restart from where we stopped last*/
	totSize = mov->current_top_box_start;
	if (mov->bytes_removed) {
		assert(totSize >= mov->bytes_removed);
		totSize -= mov->bytes_removed;
	}
	gf_bs_seek(mov->movieFileMap->bs, totSize);
#endif


	/*while we have some data, parse our boxes*/
	while (gf_bs_available(mov->movieFileMap->bs)) {
		*bytesMissing = 0;
#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs) + mov->bytes_removed;
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Parsing a top-level box at position %d\n", mov->current_top_box_start));
#endif

		e = gf_isom_parse_root_box(&a, mov->movieFileMap->bs, boxType, bytesMissing, progressive_mode);

		if (e >= 0) {
			//safety check, should never happen
			if (!a) return GF_ISOM_INVALID_FILE;
		} else if (e == GF_ISOM_INCOMPLETE_FILE) {
			/*our mdat is uncomplete, only valid for READ ONLY files...*/
			if (mov->openMode != GF_ISOM_OPEN_READ) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete MDAT while file is not read-only\n"));
				return GF_ISOM_INVALID_FILE;
			}
			if ((mov->openMode == GF_ISOM_OPEN_READ) && !progressive_mode) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete file while reading for dump - aborting parsing\n"));
				break;
			}
			return e;
		} else {
			return e;
		}

		switch (a->type) {
		/*MOOV box*/
		case GF_ISOM_BOX_TYPE_MOOV:
			if (mov->moov) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate MOOV detected!\n"));
				gf_isom_box_del(a);
				return GF_ISOM_INVALID_FILE;
			}
			mov->moov = (GF_MovieBox *)a;
			mov->original_moov_offset = mov->current_top_box_start;
			/*set our pointer to the movie*/
			mov->moov->mov = mov;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
			if (mov->moov->mvex) mov->moov->mvex->mov = mov;

#ifdef GF_ENABLE_CTRN
			if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
				gf_isom_setup_traf_inheritance(mov);
			}
#endif

#endif
			e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;

			totSize += a->size;

            if (!mov->moov->mvhd) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MovieHeaderBox\n"));
                return GF_ISOM_INVALID_FILE;
            }

            if (mov->meta) {
				gf_isom_meta_restore_items_ref(mov, mov->meta);
			}

			//dump senc info in dump mode
			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
				u32 k;
				for (k=0; k<gf_list_count(mov->moov->trackList); k++) {
					GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(mov->moov->trackList, k);

					if (trak->sample_encryption) {
						e = senc_Parse(mov->movieFileMap->bs, trak, NULL, trak->sample_encryption);
						if (e) return e;
					}
				}
			} else {
				u32 k;
				for (k=0; k<gf_list_count(mov->moov->trackList); k++) {
					GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(mov->moov->trackList, k);
					if (trak->Media->information->sampleTable->sampleGroups) {
						convert_compact_sample_groups(trak->Media->information->sampleTable->child_boxes, trak->Media->information->sampleTable->sampleGroups);
					}
				}
			}

            if (mdat_end && mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) ) {
                gf_isom_push_mdat_end(mov, mdat_end);
                mdat_end=0;
            }
			break;

		/*META box*/
		case GF_ISOM_BOX_TYPE_META:
			if (mov->meta) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate META detected!\n"));
				gf_isom_box_del(a);
				return GF_ISOM_INVALID_FILE;
			}
			mov->meta = (GF_MetaBox *)a;
			mov->original_meta_offset = mov->current_top_box_start;
			e = gf_list_add(mov->TopBoxes, a);
			if (e) {
				return e;
			}
			totSize += a->size;
			gf_isom_meta_restore_items_ref(mov, mov->meta);
			break;

		/*we only keep the MDAT in READ for dump purposes*/
		case GF_ISOM_BOX_TYPE_MDAT:
			if (!mov->first_data_toplevel_offset) {
				mov->first_data_toplevel_offset = mov->current_top_box_start;
				mov->first_data_toplevel_size = a->size;
			}
			totSize += a->size;

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
			if (mov->emsgs) {
				gf_isom_box_array_del(mov->emsgs);
				mov->emsgs = NULL;
			}
#endif

			if (mov->openMode == GF_ISOM_OPEN_READ) {
				if (!mov->mdat) {
					mov->mdat = (GF_MediaDataBox *) a;
					e = gf_list_add(mov->TopBoxes, mov->mdat);
					if (e) {
						return e;
					}
				}
#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
				else if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) gf_list_add(mov->TopBoxes, a);
#endif
				else gf_isom_box_del(a); //in other modes we don't care


				if (mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) ) {
                    mdat_end = gf_bs_get_position(mov->movieFileMap->bs);
                    if (mov->moov) {
                        gf_isom_push_mdat_end(mov, mdat_end);
                        mdat_end=0;
                    }
				}
			}
			/*if we don't have any MDAT yet, create one (edit-write mode)
			We only work with one mdat, but we're puting it at the place
			of the first mdat found when opening a file for editing*/
			else if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS)) {
				gf_isom_box_del(a);
				mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
				if (!mov->mdat) return GF_OUT_OF_MEM;
				e = gf_list_add(mov->TopBoxes, mov->mdat);
				if (e) {
					return e;
				}
			} else {
				gf_isom_box_del(a);
			}
			break;
		case GF_ISOM_BOX_TYPE_FTYP:
			/*ONE AND ONLY ONE FTYP*/
			if (mov->brand) {
				gf_isom_box_del(a);
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'ftyp' detected!\n"));
				return GF_ISOM_INVALID_FILE;
			}
			mov->brand = (GF_FileTypeBox *)a;
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;
			break;

		case GF_ISOM_BOX_TYPE_OTYP:
			/*ONE AND ONLY ONE FTYP*/
			if (mov->otyp) {
				gf_isom_box_del(a);
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'otyp' detected!\n"));
				return GF_ISOM_INVALID_FILE;
			}

			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
				mov->otyp = (GF_Box *)a;
				totSize += a->size;
				e = gf_list_add(mov->TopBoxes, a);
				if (e) return e;
			} else {
				GF_FileTypeBox *brand = (GF_FileTypeBox *) gf_isom_box_find_child(a->child_boxes, GF_ISOM_BOX_TYPE_FTYP);
				if (brand) {
					s32 pos;
					gf_list_del_item(a->child_boxes, brand);
					pos = gf_list_del_item(mov->TopBoxes, mov->brand);
					gf_isom_box_del((GF_Box *) mov->brand);
					mov->brand = brand;
					if (pos<0) pos=0;
					gf_list_insert(mov->TopBoxes, brand, pos);
				}
				gf_isom_box_del(a);
			}
			break;

		case GF_ISOM_BOX_TYPE_PDIN:
			/*ONE AND ONLY ONE PDIN*/
			if (mov->pdin) {
				gf_isom_box_del(a);
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate 'pdin'' detected!\n"));
				return GF_ISOM_INVALID_FILE;
			}
			mov->pdin = (GF_ProgressiveDownloadBox *) a;
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;
			break;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		case GF_ISOM_BOX_TYPE_STYP:
		{
			u32 brand = ((GF_FileTypeBox *)a)->majorBrand;
			switch (brand) {
			case GF_ISOM_BRAND_SISX:
			case GF_ISOM_BRAND_RISX:
			case GF_ISOM_BRAND_SSSS:
				mov->is_index_segment = GF_TRUE;
				break;
			default:
				break;
			}
		}
		/*fall-through*/

		case GF_ISOM_BOX_TYPE_SIDX:
		case GF_ISOM_BOX_TYPE_SSIX:
			if (mov->moov && !mov->first_data_toplevel_offset) {
				mov->first_data_toplevel_offset = mov->current_top_box_start;
				mov->first_data_toplevel_size = a->size;
			}
			totSize += a->size;
			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
				e = gf_list_add(mov->TopBoxes, a);
				if (e) return e;
			} else if (mov->signal_frag_bounds && !(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)  && (mov->openMode!=GF_ISOM_OPEN_KEEP_FRAGMENTS)
			) {
				if (a->type==GF_ISOM_BOX_TYPE_SIDX) {
					if (mov->root_sidx) gf_isom_box_del( (GF_Box *) mov->root_sidx);
					mov->root_sidx = (GF_SegmentIndexBox *) a;
					mov->sidx_start_offset = mov->current_top_box_start;
					mov->sidx_end_offset = gf_bs_get_position(mov->movieFileMap->bs);

				}
				else if (a->type==GF_ISOM_BOX_TYPE_STYP) {
					mov->styp_start_offset = mov->current_top_box_start;

					if (mov->seg_styp) gf_isom_box_del(mov->seg_styp);
					mov->seg_styp = a;
				} else if (a->type==GF_ISOM_BOX_TYPE_SSIX) {
					if (mov->seg_ssix) gf_isom_box_del(mov->seg_ssix);
					mov->seg_ssix = a;
				} else {
					gf_isom_box_del(a);
				}
				gf_isom_push_mdat_end(mov, mov->current_top_box_start);
			} else if (!mov->NextMoofNumber && (a->type==GF_ISOM_BOX_TYPE_SIDX)) {
				if (mov->main_sidx) gf_isom_box_del( (GF_Box *) mov->main_sidx);
				mov->main_sidx = (GF_SegmentIndexBox *) a;
				mov->main_sidx_end_pos = mov->current_top_box_start + a->size;
			} else {
				gf_isom_box_del(a);
			}
			break;

		case GF_ISOM_BOX_TYPE_MOOF:
			//no support for inplace rewrite for fragmented files
			gf_isom_disable_inplace_rewrite(mov);
			if (!mov->moov) {
				GF_LOG(mov->moof ? GF_LOG_DEBUG : GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Movie fragment but no moov (yet) - possibly broken parsing!\n"));
			}
			if (mov->single_moof_mode) {
				mov->single_moof_state++;
				if (mov->single_moof_state > 1) {
					gf_isom_box_del(a);
					return GF_OK;
				}
			}
			((GF_MovieFragmentBox *)a)->mov = mov;

			totSize += a->size;
			mov->moof = (GF_MovieFragmentBox *) a;

			/*some smooth streaming streams contain a SDTP under the TRAF: this is incorrect, convert it*/
			FixTrackID(mov);
			if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
				FixSDTPInTRAF(mov->moof);
			} else {
				u32 k;
				for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
					GF_TrackFragmentBox *traf = (GF_TrackFragmentBox *)gf_list_get(mov->moof->TrackList, k);
					if (traf->sampleGroups) {
						convert_compact_sample_groups(traf->child_boxes, traf->sampleGroups);
					}
				}
			}

			/*read & debug: store at root level*/
			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
				u32 k;
				gf_list_add(mov->TopBoxes, a);
				/*also update pointers to trex for debug*/
				if (mov->moov) {
					for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
						GF_TrackFragmentBox *traf = gf_list_get(mov->moof->TrackList, k);
						if (traf->tfhd && mov->moov->mvex && mov->moov->mvex->TrackExList) {
							GF_TrackBox *trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
							u32 j=0;
							while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
								if (traf->trex->trackID == traf->tfhd->trackID) {
									if (!traf->trex->track) traf->trex->track = trak;
									break;
								}
								traf->trex = NULL;
							}
						}
						//we should only parse senc/psec when no saiz/saio is present, otherwise we fetch the info directly
						if (traf->trex && traf->tfhd && traf->trex->track && traf->sample_encryption) {
							GF_TrackBox *trak = GetTrackbyID(mov->moov, traf->tfhd->trackID);
							if (trak) {
								trak->current_traf_stsd_idx = traf->tfhd->sample_desc_index ? traf->tfhd->sample_desc_index : traf->trex->def_sample_desc_index;
								e = senc_Parse(mov->movieFileMap->bs, trak, traf, traf->sample_encryption);
								if (e) return e;
								trak->current_traf_stsd_idx = 0;
							}
						}
					}
				} else {
					for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
						GF_TrackFragmentBox *traf = gf_list_get(mov->moof->TrackList, k);
						if (traf->sample_encryption) {
							e = senc_Parse(mov->movieFileMap->bs, NULL, traf, traf->sample_encryption);
							if (e) return e;
						}
					}

				}
			} else if (mov->openMode==GF_ISOM_OPEN_KEEP_FRAGMENTS) {
				mov->NextMoofNumber = mov->moof->mfhd->sequence_number+1;
				mov->moof = NULL;
				gf_isom_box_del(a);
			} else {
				/*merge all info*/
				e = MergeFragment((GF_MovieFragmentBox *)a, mov);
				gf_isom_box_del(a);
				if (e) return e;
			}

			//done with moov
			if (mov->root_sidx) {
				gf_isom_box_del((GF_Box *) mov->root_sidx);
				mov->root_sidx = NULL;
			}
			if (mov->root_ssix) {
				gf_isom_box_del(mov->seg_ssix);
				mov->root_ssix = NULL;
			}
			if (mov->seg_styp) {
				gf_isom_box_del(mov->seg_styp);
				mov->seg_styp = NULL;
			}
			mov->sidx_start_offset = 0;
			mov->sidx_end_offset = 0;
			mov->styp_start_offset = 0;
			break;
#endif
		case GF_ISOM_BOX_TYPE_UNKNOWN:
		{
			GF_UnknownBox *box = (GF_UnknownBox*)a;
			if (box->original_4cc == GF_ISOM_BOX_TYPE_JP) {
				u8 *c = (u8 *) box->data;
				if ((box->dataSize==4) && (GF_4CC(c[0],c[1],c[2],c[3])==(u32)0x0D0A870A))
					mov->is_jp2 = 1;
				gf_isom_box_del(a);
			} else {
				e = gf_list_add(mov->TopBoxes, a);
				if (e) return e;
			}
		}
		break;

		case GF_ISOM_BOX_TYPE_PRFT:
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
			if (!(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
				//keep the last one read
				if (mov->last_producer_ref_time)
					gf_isom_box_del(a);
				else
					mov->last_producer_ref_time = (GF_ProducerReferenceTimeBox *)a;
				break;
			}
#endif
		//fallthrough
		case GF_ISOM_BOX_TYPE_EMSG:
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
			if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
				if (!mov->emsgs) mov->emsgs = gf_list_new();
				gf_list_add(mov->emsgs, a);
				break;
			}
#endif
		case GF_ISOM_BOX_TYPE_MFRA:
		case GF_ISOM_BOX_TYPE_MFRO:
			//only keep for dump mode, otherwise we ignore these boxes and we don't want to carry them over in non-fragmented file
			if (! (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
				totSize += a->size;
				gf_isom_box_del(a);
				break;
			}
		default:
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;
			break;
		}

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		/*remember where we left, in case we append an entire number of movie fragments*/
		mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs) + mov->bytes_removed;
#endif
	}

	/*we need at least moov or meta*/
	if (!mov->moov && !mov->meta
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
	        && !mov->moof && !mov->is_index_segment
#endif
	   ) {
		return GF_ISOM_INCOMPLETE_FILE;
	}
	/*we MUST have movie header*/
	if (!gf_opts_get_bool("core", "no-check")) {
		if (mov->moov && !mov->moov->mvhd) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MVHD in MOOV!\n"));
			return GF_ISOM_INVALID_FILE;
		}

		/*we MUST have meta handler*/
		if (mov->meta && !mov->meta->handler) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing handler in META!\n"));
			return GF_ISOM_INVALID_FILE;
		}
	}

#ifndef GPAC_DISABLE_ISOM_WRITE

	if (mov->moov) {
		/*set the default interleaving time*/
		mov->interleavingTime = mov->moov->mvhd->timeScale;

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		/*in edit mode with successfully loaded fragments, delete all fragment signaling since
		file is no longer fragmented*/
		if ((mov->openMode > GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS) && mov->moov->mvex) {
			gf_isom_box_del_parent(&mov->moov->child_boxes, (GF_Box *)mov->moov->mvex);
			mov->moov->mvex = NULL;
		}
#endif

	}

	//create a default mdat if none was found
	if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_KEEP_FRAGMENTS)) {
		mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
		if (!mov->mdat) return GF_OUT_OF_MEM;
		e = gf_list_add(mov->TopBoxes, mov->mdat);
		if (e) return e;
	}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

	return GF_OK;
}

Project: gpac

GF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov)
{
	GF_Err e;
	u32 i, j;
	u64 MaxDur;
	GF_TrackFragmentBox *traf;
	GF_TrackBox *trak;
	u64 base_data_offset;

	MaxDur = 0;

	//we shall have a MOOV and its MVEX BEFORE any MOOF
	if (!mov->moov || !mov->moov->mvex) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: %s not received before merging fragment\n", mov->moov ? "mvex" : "moov" ));
		return GF_ISOM_INVALID_FILE;
	}
	//and all fragments should be continous but:
	//- dash with dependent representations may likely give R1(moofSN 1, 3, 5, 7) plus R2(moofSN 2, 4, 6, 8)
	//- smooth muxed in a single file may end up with V(1),A(1), V(2),A(2) ...
	//we do not throw an error if not as we may still want to be able to concatenate dependent representations in DASH and
	if (mov->NextMoofNumber && moof->mfhd && (mov->NextMoofNumber >= moof->mfhd->sequence_number)) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] wrong sequence number: got %d but last one was %d\n", moof->mfhd->sequence_number, mov->NextMoofNumber));
	}

	base_data_offset = mov->current_top_box_start;
	if (moof->compressed_diff)
		base_data_offset -= moof->compressed_diff;

	i=0;
	while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) {
		u32 prev_sample_count;
		if (!traf->tfhd) {
			trak = NULL;
			traf->trex = NULL;
		} else if (mov->is_smooth) {
			trak = gf_list_get(mov->moov->trackList, 0);
			traf->trex = (GF_TrackExtendsBox*)gf_list_get(mov->moov->mvex->TrackExList, 0);
			assert(traf->trex);
			traf->trex->trackID = trak->Header->trackID = traf->tfhd->trackID;
		} else {
			trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
			j=0;
			while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
				if (traf->trex->trackID == traf->tfhd->trackID) break;
				traf->trex = NULL;
			}
		}

		if (!trak || !traf->trex) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: Cannot find fragment track with ID %d\n", traf->tfhd ? traf->tfhd->trackID : 0));
			return GF_ISOM_INVALID_FILE;
		}

		prev_sample_count = trak->Media->information->sampleTable->SampleSize ? trak->Media->information->sampleTable->SampleSize->sampleCount : 0;
		e = MergeTrack(trak, traf, moof, mov->current_top_box_start, moof->compressed_diff, &base_data_offset);
		if (e) return e;
		trak->first_traf_merged = GF_TRUE;

		trak->present_in_scalable_segment = 1;

		//update trak duration
		SetTrackDuration(trak);
		if (trak->Header->duration > MaxDur)
			MaxDur = trak->Header->duration;

		//we have PSSH per moov, internally remap as a sample group of type PSSH
		if (gf_list_count(moof->PSSHs)) {
			u8 *pssh_data;
			u32 pssh_len;
			u32 j, k, nb_pssh = gf_list_count(moof->PSSHs);
			GF_BitStream *pssh_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
			gf_bs_write_u32(pssh_bs, nb_pssh);
			for (j=0; j<nb_pssh; j++) {
				GF_ProtectionSystemHeaderBox *pssh = gf_list_get(moof->PSSHs, j);
				gf_bs_write_data(pssh_bs, pssh->SystemID, 16);
				gf_bs_write_u32(pssh_bs, pssh->version);
				if (pssh->version) {
					gf_bs_write_u32(pssh_bs, pssh->KID_count);
					for (k=0; k<pssh->KID_count; k++) {
						gf_bs_write_data(pssh_bs, pssh->KIDs[k], 16);
					}
				}
				gf_bs_write_u32(pssh_bs, pssh->private_data_size);
				gf_bs_write_data(pssh_bs, pssh->private_data, pssh->private_data_size);
			}
			gf_bs_get_content(pssh_bs, &pssh_data, &pssh_len);
			gf_bs_del(pssh_bs);

			gf_isom_set_sample_group_description_internal(mov, gf_list_find(mov->moov->trackList, trak)+1, 1+prev_sample_count, GF_4CC('P','S','S','H'), 0, pssh_data, pssh_len, GF_FALSE);
			gf_free(pssh_data);
		}


		//we have emsg, internally remap as a sample group of type EMSG
		if (gf_list_count(mov->emsgs)) {
			u8 *emsg_data;
			u32 emsg_len;
			u32 j, nb_emsg = gf_list_count(mov->emsgs);
			GF_BitStream *emsg_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
			for (j=0; j<nb_emsg; j++) {
				GF_Box *emsg = gf_list_get(mov->emsgs, j);
				gf_isom_box_write(emsg, emsg_bs);
			}
			gf_bs_get_content(emsg_bs, &emsg_data, &emsg_len);
			gf_bs_del(emsg_bs);

			gf_isom_set_sample_group_description_internal(mov, gf_list_find(mov->moov->trackList, trak)+1, 1+prev_sample_count, GF_4CC('E','M','S','G'), 0, emsg_data, emsg_len, GF_FALSE);
			gf_free(emsg_data);
		}
	}
	if (mov->emsgs) {
		gf_isom_box_array_del(mov->emsgs);
		mov->emsgs = NULL;
	}

	if (moof->child_boxes) {
		GF_Box *a;
		i = 0;
		while ((a = (GF_Box *)gf_list_enum(moof->child_boxes, &i))) {
			if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
				GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(&mov->moov->child_boxes, GF_ISOM_BOX_TYPE_PSSH);
				if (!pssh) return GF_OUT_OF_MEM;
				memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
				if (((GF_ProtectionSystemHeaderBox *)a)->KIDs && ((GF_ProtectionSystemHeaderBox *)a)->KID_count > 0) {
					pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
					pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
					if (!pssh->KIDs) return GF_OUT_OF_MEM;

					memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
				}
				pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
				pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
				if (!pssh->private_data) return GF_OUT_OF_MEM;
				memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
				pssh->moof_defined = 1;
				mov->has_pssh_moof = GF_TRUE;
			}
		}
	}

	mov->NextMoofNumber = moof->mfhd ? moof->mfhd->sequence_number : 0;
	//update movie duration
	if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur;
	return GF_OK;
}

Project: gpac

GF_EdtsEntry *CreateEditEntry(u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode)
{
	GF_EdtsEntry *ent;

	ent = (GF_EdtsEntry*)gf_malloc(sizeof(GF_EdtsEntry));
	if (!ent) return NULL;

	switch (EditMode) {
	case GF_ISOM_EDIT_EMPTY:
		ent->mediaRate = 0x10000;
		ent->mediaTime = -1;
		break;

	case GF_ISOM_EDIT_DWELL:
		ent->mediaRate = 0;
		ent->mediaTime = MediaTime;
		break;
	default:
		ent->mediaRate = MediaRate;
		ent->mediaTime = MediaTime;
		break;
	}
	ent->segmentDuration = EditDuration;
	return ent;
}

Project: gpac


Bool gf_box_valid_in_parent(GF_Box *a, const char *parent_4cc)
{
	if (!a || !a->registry || !a->registry->parents_4cc) return GF_FALSE;
	if (strstr(a->registry->parents_4cc, parent_4cc) != NULL) return GF_TRUE;
	return GF_FALSE;

Project: gpac

void gf_isom_box_array_reset_parent(GF_List **child_boxes, GF_List *boxlist)
{
	u32 count, i;
	if (!boxlist) return;
	count = gf_list_count(boxlist);
	for (i = 0; i < count; i++) {
		GF_Box *a = (GF_Box *)gf_list_get(boxlist, i);
		if (a) gf_isom_box_del_parent(child_boxes, a);
	}
	gf_list_reset(boxlist);
}

Project: gpac

GF_Err gf_isom_parse_root_box(GF_Box **outBox, GF_BitStream *bs, u32 *box_type, u64 *bytesExpected, Bool progressive_mode)
{
	GF_Err ret;
	u64 start;
	start = gf_bs_get_position(bs);
	ret = gf_isom_box_parse_ex(outBox, bs, 0, GF_TRUE, 0);
	if (ret == GF_ISOM_INCOMPLETE_FILE) {
		if (!*outBox) {
			// We could not even read the box size, we at least need 8 bytes
			*bytesExpected = 8;
			if (box_type) *box_type = 0;
			GF_LOG(progressive_mode ? GF_LOG_DEBUG : GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete box - start "LLU"\n", start));
		}
		else {
			u32 type = (*outBox)->type;
			if (type==GF_ISOM_BOX_TYPE_UNKNOWN)
				type = ((GF_UnknownBox *) (*outBox))->original_4cc;

			*bytesExpected = (*outBox)->size;
			if (box_type) *box_type = (*outBox)->type;

			GF_LOG(progressive_mode ? GF_LOG_DEBUG : GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete box %s - start "LLU" size "LLU"\n", gf_4cc_to_str(type), start, (*outBox)->size));
			gf_isom_box_del(*outBox);
			*outBox = NULL;
		}
		gf_bs_seek(bs, start);
	}
	return ret;
}

Project: gpac


GF_Err gf_isom_box_array_read(GF_Box *parent, GF_BitStream *bs)
{
	GF_Err e;
	u32 parent_type = parent->type;
	GF_Box *a = NULL;
	Bool skip_logs = (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_NO_LOGS ) ? GF_TRUE : GF_FALSE;

	//we may have terminators in some QT files (4 bytes set to 0 ...)
	while (parent->size>=8) {
		e = gf_isom_box_parse_ex(&a, bs, parent_type, GF_FALSE, skip_logs ? 0 : parent->size);
		if (e) {
			if (a) gf_isom_box_del(a);
			return (e==GF_SKIP_BOX) ? GF_OK : e;
		}
		//sub box parsing aborted with no error
		if (!a) return GF_OK;

		if (parent->size < a->size) {
			if (!skip_logs) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" is larger than container box\n", gf_4cc_to_str(a->type)));
			}
			if (!gf_opts_get_bool("core", "no-check")) {
				gf_isom_box_del(a);
				return GF_ISOM_INVALID_FILE;
			}
			parent->size = 0;
		} else {
			parent->size -= a->size;
		}

		//check container validity
		if (strlen(a->registry->parents_4cc)) {
			Bool parent_OK = GF_FALSE;
			const char *parent_code = gf_4cc_to_str(parent->type);
			if (parent->type == GF_ISOM_BOX_TYPE_UNKNOWN)
				parent_code = gf_4cc_to_str( ((GF_UnknownBox*)parent)->original_4cc );
			if (strstr(a->registry->parents_4cc, parent_code) != NULL) {
				parent_OK = GF_TRUE;
			} else if (!strcmp(a->registry->parents_4cc, "*") || strstr(a->registry->parents_4cc, "* ") || strstr(a->registry->parents_4cc, " *")) {
				parent_OK = GF_TRUE;
			} else {
				//parent must be a sample entry
				if (strstr(a->registry->parents_4cc, "sample_entry") !=	NULL) {
					//parent is in an stsd
					if (strstr(parent->registry->parents_4cc, "stsd") != NULL) {
						if (strstr(a->registry->parents_4cc, "video_sample_entry") !=	NULL) {
							if (((GF_SampleEntryBox*)parent)->internal_type==GF_ISOM_SAMPLE_ENTRY_VIDEO) {
								parent_OK = GF_TRUE;
							}
						} else {
							parent_OK = GF_TRUE;
						}
					}
				}
				//other types are sample formats, eg a 3GPP text sample, RTP hint sample or VTT cue. Not handled at this level
				else if (a->type==GF_ISOM_BOX_TYPE_UNKNOWN) parent_OK = GF_TRUE;
				else if (a->type==GF_ISOM_BOX_TYPE_UUID) parent_OK = GF_TRUE;
			}
			if (! parent_OK && !skip_logs) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" is invalid in container %s\n", gf_4cc_to_str(a->type), parent_code));
			}
		}

		//always register boxes
		if (!parent->child_boxes) {
			parent->child_boxes = gf_list_new();
			if (!parent->child_boxes) return GF_OUT_OF_MEM;
		}
		e = gf_list_add(parent->child_boxes, a);
		if (e) return e;

		if (parent->registry->add_rem_fn) {
			e = parent->registry->add_rem_fn(parent, a, GF_FALSE);
			if (e) {
				if (e == GF_ISOM_INVALID_MEDIA) return GF_OK;
				//if the box is no longer present, consider it destroyed
				if (gf_list_find(parent->child_boxes, a) >=0) {
					gf_isom_box_del_parent(&parent->child_boxes, a);
				}
				return e;
			}
		}
	}
	return GF_OK;

Project: gpac

GF_Err gf_isom_box_parse_ex(GF_Box **outBox, GF_BitStream *bs, u32 parent_type, Bool is_root_box, u64 parent_size)
{
	u32 type, uuid_type, hdr_size, restore_type;
	u64 size, start, comp_start, end;
	char uuid[16];
	GF_Err e;
	GF_BitStream *uncomp_bs = NULL;
	u8 *uncomp_data = NULL;
	u32 compressed_size=0;
	GF_Box *newBox;
	Bool skip_logs = (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_NO_LOGS ) ? GF_TRUE : GF_FALSE;
	Bool is_special = GF_TRUE;
	
	if ((bs == NULL) || (outBox == NULL) ) return GF_BAD_PARAM;
	*outBox = NULL;
	if (gf_bs_available(bs) < 8) {
		return GF_ISOM_INCOMPLETE_FILE;
	}

	comp_start = start = gf_bs_get_position(bs);

	uuid_type = 0;
	size = (u64) gf_bs_read_u32(bs);
	hdr_size = 4;
	/*fix for some boxes found in some old hinted files*/
	if ((size >= 2) && (size <= 4)) {
		size = 4;
		type = GF_ISOM_BOX_TYPE_VOID;
	} else {
		type = gf_bs_read_u32(bs);
		hdr_size += 4;
		/*no size means till end of file - EXCEPT FOR some old QuickTime boxes...*/
		if (type == GF_ISOM_BOX_TYPE_TOTL)
			size = 12;
		if (!size) {
			if (is_root_box) {
				if (!skip_logs) {
					GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Warning Read Box type %s (0x%08X) size 0 reading till the end of file\n", gf_4cc_to_str(type), type));
				}
				size = gf_bs_available(bs) + 8;
			} else {
				if (!skip_logs) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Read Box type %s (0x%08X) at position "LLU" has size 0 but is not at root/file level. Forbidden, skipping end of parent box !\n", gf_4cc_to_str(type), type, start));
					return GF_SKIP_BOX;
				}
				return GF_OK;
			}
		}
		if (is_root_box && (size>=8)) {
			Bool do_uncompress = GF_FALSE;
			u8 *compb = NULL;
			u32 osize = 0;
			u32 otype = type;
			if (type==GF_4CC('!', 'm', 'o', 'f')) {
				do_uncompress = GF_TRUE;
				type = GF_ISOM_BOX_TYPE_MOOF;
			}
			else if (type==GF_4CC('!', 'm', 'o', 'v')) {
				do_uncompress = GF_TRUE;
				type = GF_ISOM_BOX_TYPE_MOOV;
			}
			else if (type==GF_4CC('!', 's', 'i', 'x')) {
				do_uncompress = GF_TRUE;
				type = GF_ISOM_BOX_TYPE_SIDX;
			}
			else if (type==GF_4CC('!', 's', 's', 'x')) {
				do_uncompress = GF_TRUE;
				type = GF_ISOM_BOX_TYPE_SSIX;
			}

			if (do_uncompress) {
				compb = gf_malloc((u32) (size-8));

				compressed_size = (u32) (size - 8);
				gf_bs_read_data(bs, compb, compressed_size);
				e = gf_gz_decompress_payload(compb, compressed_size, &uncomp_data, &osize);
				if (e) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Failed to uncompress payload for box type %s (0x%08X)\n", gf_4cc_to_str(otype), otype));
					return e;
				}

				//keep size as complete box size for tests below
				size = osize + 8;
				uncomp_bs = gf_bs_new(uncomp_data, osize, GF_BITSTREAM_READ);
				bs = uncomp_bs;
				start = 0;
				gf_free(compb);
			}
		}
	}
	/*handle uuid*/
	memset(uuid, 0, 16);
	if (type == GF_ISOM_BOX_TYPE_UUID ) {
		if (gf_bs_available(bs) < 16) {
			return GF_ISOM_INCOMPLETE_FILE;
		}
		gf_bs_read_data(bs, uuid, 16);
		hdr_size += 16;
		uuid_type = gf_isom_solve_uuid_box(uuid);
	}

	//handle large box
	if (size == 1) {
		if (gf_bs_available(bs) < 8) {
			return GF_ISOM_INCOMPLETE_FILE;
		}
		size = gf_bs_read_u64(bs);
		hdr_size += 8;
	}
	if (!skip_logs)
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Read Box type %s size "LLD" start "LLD"\n", gf_4cc_to_str(type), size,  start));

	if ( size < hdr_size ) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Box %s size "LLD" less than box header size %d\n", gf_4cc_to_str(type), size, hdr_size));
		return GF_ISOM_INVALID_FILE;
	}
	//if parent size is given, make sure box fits within parent
	if (parent_size && (parent_size<size)) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Box %s size "LLU" is larger than remaining parent size "LLU"\n", gf_4cc_to_str(type), size, parent_size ));
		return GF_ISOM_INVALID_FILE;
	}
	restore_type = 0;
	if ((parent_type==GF_ISOM_BOX_TYPE_STSD) && (type==GF_QT_SUBTYPE_RAW) ) {
		u64 cookie = gf_bs_get_cookie(bs);
		restore_type = type;
		if (cookie & GF_ISOM_BS_COOKIE_VISUAL_TRACK)
			type = GF_QT_SUBTYPE_RAW_VID;
		else
			type = GF_QT_SUBTYPE_RAW_AUD;

	}

	//some special boxes (references and track groups) are handled by a single generic box with an associated ref/group type
	if (parent_type && (parent_type == GF_ISOM_BOX_TYPE_TREF)) {
		newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT);
		if (!newBox) return GF_OUT_OF_MEM;
		((GF_TrackReferenceTypeBox*)newBox)->reference_type = type;
	} else if (parent_type && (parent_type == GF_ISOM_BOX_TYPE_IREF)) {
		newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_REFI);
		if (!newBox) return GF_OUT_OF_MEM;
		((GF_ItemReferenceTypeBox*)newBox)->reference_type = type;
	} else if (parent_type && (parent_type == GF_ISOM_BOX_TYPE_TRGR)) {
		newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_TRGT);
		if (!newBox) return GF_OUT_OF_MEM;
		((GF_TrackGroupTypeBox*)newBox)->group_type = type;
	} else if (parent_type && (parent_type == GF_ISOM_BOX_TYPE_GRPL)) {
		newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_GRPT);
		if (!newBox) return GF_OUT_OF_MEM;
		((GF_EntityToGroupTypeBox*)newBox)->grouping_type = type;
	} else {
		//OK, create the box based on the type
		is_special = GF_FALSE;
		newBox = gf_isom_box_new_ex(uuid_type ? uuid_type : type, parent_type, skip_logs, is_root_box);
		if (!newBox) return GF_OUT_OF_MEM;
	}

	//OK, init and read this box
	if (type==GF_ISOM_BOX_TYPE_UUID && !is_special) {
		memcpy(((GF_UUIDBox *)newBox)->uuid, uuid, 16);
		((GF_UUIDBox *)newBox)->internal_4cc = uuid_type;
	}

	if (!newBox->type) newBox->type = type;
	if (restore_type)
		newBox->type = restore_type;

	end = gf_bs_available(bs);
	if (size - hdr_size > end ) {
		newBox->size = size - hdr_size - end;
		*outBox = newBox;
		return GF_ISOM_INCOMPLETE_FILE;
	}

	newBox->size = size - hdr_size;

	e = gf_isom_full_box_read(newBox, bs);
	if (!e) e = gf_isom_box_read(newBox, bs);
	if (e) {
		if (gf_opts_get_bool("core", "no-check"))
			e = GF_OK;
	}
	newBox->size = size;
	end = gf_bs_get_position(bs);

	if (uncomp_bs) {
		gf_free(uncomp_data);
		gf_bs_del(uncomp_bs);
		if (e) {
			gf_isom_box_del(newBox);
			*outBox = NULL;
			return e;
		}
		//move size to real bitstream offsets for tests below
		size -= 8;
		//remember compressed vs real size info for moof in order to properly recompute data_offset/base_data_offset
		if (type==GF_ISOM_BOX_TYPE_MOOF) {
			((GF_MovieFragmentBox *)newBox)->compressed_diff = (s32)size - (s32)compressed_size;
		}
		//remember compressed vs real size info for moov in order to properly recompute chunk offset
		else if (type==GF_ISOM_BOX_TYPE_MOOV) {
			((GF_MovieBox *)newBox)->compressed_diff = (s32)size - (s32)compressed_size;
			((GF_MovieBox *)newBox)->file_offset = comp_start;
		}
		//remember compressed vs real size info for dump
		else if (type==GF_ISOM_BOX_TYPE_SIDX) {
			((GF_SegmentIndexBox *)newBox)->compressed_diff = (s32)size - (s32)compressed_size;
		}
		//remember compressed vs real size info for dump
		else if (type==GF_ISOM_BOX_TYPE_SSIX) {
			((GF_SubsegmentIndexBox *)newBox)->compressed_diff = (s32)size - (s32)compressed_size;
		}
		newBox->internal_flags = GF_ISOM_BOX_COMPRESSED;
	}


	if (e && (e != GF_ISOM_INCOMPLETE_FILE)) {
		gf_isom_box_del(newBox);
		*outBox = NULL;
		if (is_root_box && (e==GF_SKIP_BOX))
			e = GF_ISOM_INVALID_FILE;

		if (!skip_logs && (e!=GF_SKIP_BOX)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Read Box \"%s\" (start "LLU") failed (%s) - skipping\n", gf_4cc_to_str(type), start, gf_error_to_string(e)));
		}
		//we don't try to reparse known boxes that have been failing (too dangerous)
		return e;
	}

	if (end-start > size) {
		if (!skip_logs) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" size "LLU" (start "LLU") invalid (read "LLU")\n", gf_4cc_to_str(type), size, start, (end-start) ));
		}
		/*let's still try to load the file since no error was notified*/
		gf_bs_seek(bs, start+size);
	} else if (end-start < size) {
		u32 to_skip = (u32) (size-(end-start));
		if (!skip_logs) {
			if ((to_skip!=4) || gf_bs_peek_bits(bs, 32, 0)) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" (start "LLU") has %u extra bytes\n", gf_4cc_to_str(type), start, to_skip));
				unused_bytes += to_skip;
			}
		}
		gf_bs_skip_bytes(bs, to_skip);
	}
	*outBox = newBox;

	return e;
}

Project: gpac


void gf_isom_box_del_parent(GF_List **child_boxes, GF_Box*b)
{
	if (child_boxes) {
		gf_list_del_item(*child_boxes, b);
		if (!gf_list_count(*child_boxes)) {
			gf_list_del(*child_boxes);
			*child_boxes = NULL;
		}
	}
	gf_isom_box_del(b);

Project: gpac
File: isom_intern.c

GF_Err gf_isom_add_subsample_info(GF_SubSampleInformationBox *sub_samples, u32 sampleNumber, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable)
{
	u32 i, count, last_sample;
	GF_SubSampleInfoEntry *pSamp;
	GF_SubSampleEntry *pSubSamp;

	pSamp = NULL;
	last_sample = 0;
	count = gf_list_count(sub_samples->Samples);
	for (i=0; i<count; i++) {
		pSamp = (GF_SubSampleInfoEntry*) gf_list_get(sub_samples->Samples, i);
		/*TODO - do we need to support insertion of subsample info ?*/
		if (last_sample + pSamp->sample_delta > sampleNumber) return GF_NOT_SUPPORTED;
		if (last_sample + pSamp->sample_delta == sampleNumber) break;
		last_sample += pSamp->sample_delta;
		pSamp = NULL;
	}

	if (!pSamp) {
		GF_SAFEALLOC(pSamp, GF_SubSampleInfoEntry);
		if (!pSamp) return GF_OUT_OF_MEM;
		pSamp->SubSamples = gf_list_new();
		if (!pSamp->SubSamples ) {
			gf_free(pSamp);
			return GF_OUT_OF_MEM;
		}
		pSamp->sample_delta = sampleNumber - last_sample;
		gf_list_add(sub_samples->Samples, pSamp);
	}

	if ((subSampleSize>0xFFFF) && !sub_samples->version) {
		sub_samples->version = 1;
	}
	/*remove last subsample info*/
	if (!subSampleSize) {
		pSubSamp = gf_list_last(pSamp->SubSamples);
		gf_list_rem_last(pSamp->SubSamples);
		gf_free(pSubSamp);
		if (!gf_list_count(pSamp->SubSamples)) {
			gf_list_del_item(sub_samples->Samples, pSamp);
			gf_list_del(pSamp->SubSamples);
			gf_free(pSamp);
		}
		return GF_OK;
	}
	/*add subsample*/
	GF_SAFEALLOC(pSubSamp, GF_SubSampleEntry);
	if (!pSubSamp) return GF_OUT_OF_MEM;
	pSubSamp->subsample_size = subSampleSize;
	pSubSamp->subsample_priority = priority;
	pSubSamp->reserved = reserved;
	pSubSamp->discardable = discardable;
	return gf_list_add(pSamp->SubSamples, pSubSamp);
}

Project: gpac
File: isom_intern.c

GF_Err gf_isom_insert_moov(GF_ISOFile *file)
{
	GF_MovieHeaderBox *mvhd;
	if (file->moov) return GF_OK;

	//OK, create our boxes (mvhd, iods, ...)
	file->moov = (GF_MovieBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MOOV);
	if (!file->moov) return GF_OUT_OF_MEM;
	file->moov->mov = file;
	//Header SetUp
	mvhd = (GF_MovieHeaderBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVHD);
	if (!mvhd) return GF_OUT_OF_MEM;

	if (gf_sys_is_test_mode() ) {
		mvhd->creationTime = mvhd->modificationTime = 0;
	} else {
		u64 now = gf_isom_get_mp4time();
		mvhd->creationTime = now;
		if (!file->keep_utc)
			mvhd->modificationTime = now;
	}

	mvhd->nextTrackID = 1;
	//600 is our default movie TimeScale
	mvhd->timeScale = 600;

	file->interleavingTime = mvhd->timeScale;
	moov_on_child_box((GF_Box*)file->moov, (GF_Box *)mvhd, GF_FALSE);
	gf_list_add(file->TopBoxes, file->moov);
	return GF_OK;
}

Project: gpac

GF_Err GetNextMediaTime(GF_TrackBox *trak, u64 movieTime, u64 *OutMovieTime)
{
	u32 i;
	u64 time;
	GF_EdtsEntry *ent;

	*OutMovieTime = 0;
	if (! trak->editBox || !trak->editBox->editList) return GF_BAD_PARAM;

	time = 0;
	ent = NULL;
	i=0;
	while ((ent = (GF_EdtsEntry *)gf_list_enum(trak->editBox->editList->entryList, &i))) {
		if (gf_timestamp_greater_or_equal(time, trak->moov->mvhd->timeScale, movieTime, trak->Media->mediaHeader->timeScale)) {
			/*skip empty edits*/
			if (ent->mediaTime >= 0) {
				*OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
				if (*OutMovieTime>0) *OutMovieTime -= 1;
				return GF_OK;
			}
		}
		time += ent->segmentDuration;
	}
	//request for a bigger time that what we can give: return the last sample (undefined behavior...)
	*OutMovieTime = trak->moov->mvhd->duration;
	return GF_EOS;
}

Project: gpac
File: isom_intern.c

GF_ISOFile *gf_isom_create_movie(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
{
	GF_Err e;

	GF_ISOFile *mov = gf_isom_new_movie();
	if (!mov) return NULL;
	mov->openMode = OpenMode;
	//then set up our movie

	//in WRITE, the input dataMap is ALWAYS NULL
	mov->movieFileMap = NULL;

	//but we have the edit one
	if (OpenMode == GF_ISOM_OPEN_WRITE) {
		const char *ext;
		//THIS IS NOT A TEMP FILE, WRITE mode is used for "live capture"
		//this file will be the final file...
		mov->fileName = fileName ? gf_strdup(fileName) : NULL;
		e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_WRITE, &mov->editFileMap);
		if (e) goto err_exit;

		/*brand is set to ISOM or QT by default - it may be touched until sample data is added to track*/
		ext = gf_file_ext_start(fileName);
		if (ext && (!strnicmp(ext, ".mov", 4) || !strnicmp(ext, ".qt", 3))) {
			gf_isom_set_brand_info((GF_ISOFile *) mov, GF_ISOM_BRAND_QT, 512);
		} else {
			gf_isom_set_brand_info((GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1);
		}
	} else {
		//we are in EDIT mode but we are creating the file -> temp file
		mov->finalName = fileName ? gf_strdup(fileName) : NULL;
		e = gf_isom_datamap_new("_gpac_isobmff_tmp_edit", tmp_dir, GF_ISOM_DATA_MAP_WRITE, &mov->editFileMap);
		if (e) {
			gf_isom_set_last_error(NULL, e);
			gf_isom_delete_movie(mov);
			return NULL;
		}
		//brand is set to ISOM by default
		gf_isom_set_brand_info( (GF_ISOFile *) mov, GF_ISOM_BRAND_ISOM, 1);
	}

	//create an MDAT
	mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
	if (!mov->mdat) {
		gf_isom_set_last_error(NULL, GF_OUT_OF_MEM);
		gf_isom_delete_movie(mov);
		return NULL;
	}
	gf_list_add(mov->TopBoxes, mov->mdat);

	//default behavior is capture mode, no interleaving (eg, no rewrite of mdat)
	mov->storageMode = GF_ISOM_STORE_FLAT;
	return mov;

err_exit:
	gf_isom_set_last_error(NULL, e);
	if (mov) gf_isom_delete_movie(mov);
	return NULL;
}

Project: gpac
File: isom_intern.c

Bool gf_isom_get_subsample_types(GF_ISOFile *movie, u32 track, u32 subs_index, u32 *flags)
{
	GF_SubSampleInformationBox *sub_samples=NULL;
	GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);

	if (!track || !subs_index) return GF_FALSE;
	if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return GF_FALSE;
	sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, subs_index-1);
	if (!sub_samples) return GF_FALSE;
	*flags = sub_samples->flags;
	return GF_TRUE;
}

Project: gpac
File: isom_intern.c

u64 gf_isom_get_mp4time()
{
	u32 calctime, msec;
	u64 ret;
	gf_utc_time_since_1970(&calctime, &msec);
	calctime += GF_ISOM_MAC_TIME_OFFSET;
	ret = calctime;
	return ret;
}

Project: gpac
File: isom_intern.c

static void FixTrackID(GF_ISOFile *mov)
{
	if (!mov->moov) return;

	if (gf_list_count(mov->moov->trackList) == 1 && gf_list_count(mov->moof->TrackList) == 1) {
		GF_TrackFragmentBox *traf = (GF_TrackFragmentBox*)gf_list_get(mov->moof->TrackList, 0);
		GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(mov->moov->trackList, 0);
		if (!traf->tfhd || !trak->Header) return;
		if ((traf->tfhd->trackID != trak->Header->trackID)) {
			if (!mov->is_smooth) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: trackID of MOOF/TRAF(%u) is not the same as MOOV/TRAK(%u). Trying to fix.\n", traf->tfhd->trackID, trak->Header->trackID));
			} else {
				trak->Header->trackID = traf->tfhd->trackID;
			}
			traf->tfhd->trackID = trak->Header->trackID;
		}
	}
}

Project: gpac
File: isom_intern.c

GF_TrackBox *gf_isom_get_track_from_file(GF_ISOFile *movie, u32 trackNumber)
{
	GF_TrackBox *trak;
	if (!movie) return NULL;
	trak = gf_isom_get_track(movie->moov, trackNumber);
	if (!trak) movie->LastError = GF_BAD_PARAM;
	return trak;
}

Project: gpac

void gf_isom_box_array_reset(GF_List *boxlist)
{
	u32 count, i;
	if (!boxlist) return;
	count = gf_list_count(boxlist);
	for (i = 0; i < count; i++) {
		GF_Box *a = (GF_Box *)gf_list_get(boxlist, i);
		if (a) gf_isom_box_del(a);
	}
}

Project: gpac

GF_Err gf_isom_box_array_write(GF_Box *parent, GF_List *list, GF_BitStream *bs)
{
	u32 count, i;
	GF_Err e;
	if (!list) return GF_OK;
	count = gf_list_count(list);
	for (i = 0; i < count; i++) {
		GF_Box *a = (GF_Box *)gf_list_get(list, i);
		if (a) {
			e = gf_isom_box_write(a, bs);
			if (e) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("ISOBMF: Error %s writing box %s\n", gf_error_to_string(e), gf_4cc_to_str(a->type) ));
				return e;
			}
		}
	}
	return GF_OK;
}

Project: gpac


static GF_Err gf_isom_box_size_listing(GF_Box *a)
{
	if (!a) return GF_BAD_PARAM;
	if (!a->registry) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Size invalid box type %s without registry\n", gf_4cc_to_str(a->type) ));
		return GF_ISOM_INVALID_FILE;
	}
	a->size = 8;

	if (a->type == GF_ISOM_BOX_TYPE_UUID) {
		a->size += 16;
	}
	//the large size is handled during write, cause at this stage we don't know the size
	if (a->registry->max_version_plus_one) {
		a->size += 4;
	}
	return a->registry->size_fn(a);

Project: gpac


void gf_isom_registry_disable(u32 boxCode, Bool disable)
{
	u32 i=0, count = gf_isom_get_num_supported_boxes();
	for (i=1; i<count; i++) {
		if (box_registry[i].box_4cc==boxCode) {
			box_registry[i].disabled = disable;
			return;
		}
	}

Project: gpac

void gf_isom_box_array_del_parent(GF_List **child_boxes, GF_List *boxlist)
{
	if (!boxlist) return;
	gf_isom_box_array_reset_parent(child_boxes, boxlist);
	gf_list_del(boxlist);
}

Project: gpac

GF_EXPORT
void gf_isom_box_del(GF_Box *a)
{
	GF_List *child_boxes;
	const struct box_registry_entry *a_box_registry;
	if (!a) return;

	child_boxes	= a->child_boxes;
	a->child_boxes = NULL;

	a_box_registry = a->registry;
	if (!a_box_registry) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Delete invalid box type %s without registry\n", gf_4cc_to_str(a->type) ));
	} else {
		a_box_registry->del_fn(a);
	}
	//delete the other boxes after deleting the box for dumper case where all child boxes are stored in otherbox
	if (child_boxes) {
		gf_isom_box_array_del(child_boxes);
	}

Project: gpac

GF_EXPORT
GF_Err gf_isom_dump_supported_box(u32 idx, FILE * trace)
{
	u32 i;
	u32 nb_versions=0;
	GF_Err e;

	if (box_registry[idx].max_version_plus_one) {
		nb_versions = box_registry[idx].max_version_plus_one - 1;
	}
	for (i = 0; i <= nb_versions; i++) {
		GF_Box *a = box_registry[idx].new_fn();
		if (!a) return GF_OUT_OF_MEM;

		a->registry = &box_registry[idx];

		if (box_registry[idx].alt_4cc) {
			if (a->type==GF_ISOM_BOX_TYPE_REFT)
				((GF_TrackReferenceTypeBox*)a)->reference_type = box_registry[idx].alt_4cc;
			else if (a->type==GF_ISOM_BOX_TYPE_REFI)
				((GF_ItemReferenceTypeBox*)a)->reference_type = box_registry[idx].alt_4cc;
			else if (a->type==GF_ISOM_BOX_TYPE_TRGT)
				((GF_TrackGroupTypeBox*)a)->group_type = box_registry[idx].alt_4cc;
			else if (a->type==GF_ISOM_BOX_TYPE_SGPD)
				((GF_SampleGroupDescriptionBox*)a)->grouping_type = box_registry[idx].alt_4cc;
			else if (a->type==GF_ISOM_BOX_TYPE_GRPT)
				((GF_EntityToGroupTypeBox*)a)->grouping_type = box_registry[idx].alt_4cc;
		}
		if (box_registry[idx].max_version_plus_one) {
			((GF_FullBox *)a)->version = i;
		}
		if (box_registry[idx].flags) {
			u32 flag_mask=1;
			u32 flags = box_registry[idx].flags;
			((GF_FullBox *)a)->flags = 0;
			e = gf_isom_box_dump(a, trace);

			//we dump all flags individually and this for all version, in order to simplify the XSLT processing
			while (!e) {
				u32 flag = flags & flag_mask;
				flag_mask <<= 1;
				if (flag) {
					((GF_FullBox *)a)->flags = flag;
					e = gf_isom_box_dump(a, trace);
				}
				if (flag_mask > flags) break;
				if (flag_mask == 0x80000000) break;
			}

		} else {
			e = gf_isom_box_dump(a, trace);
		}

		gf_isom_box_del(a);
	}
	return e;

Project: gpac


GF_Box *gf_isom_box_new_parent(GF_List **parent, u32 code)
{
	GF_Box *b = gf_isom_box_new(code);
	if (!b) return NULL;
	if (! (*parent) ) (*parent)  = gf_list_new();
	gf_list_add(*parent, b);
	return b;

Project: gpac

GF_EXPORT
u32 gf_isom_get_num_supported_boxes()
{
	return sizeof(box_registry) / sizeof(struct box_registry_entry);

Project: gpac
File: isom_intern.c

GF_Err GetMediaTime(GF_TrackBox *trak, Bool force_non_empty, u64 movieTime, u64 *MediaTime, s64 *SegmentStartTime, s64 *MediaOffset, u8 *useEdit, u64 *next_edit_start_plus_one)
{
#if 0
	GF_Err e;
	u32 sampleNumber, prevSampleNumber;
	u64 firstDTS;
#endif
	u32 i, count;
	Bool last_is_empty = 0;
	u64 time, lastSampleTime;
	s64 mtime;
	GF_EdtsEntry *ent;
	Double scale_ts;
	GF_SampleTableBox *stbl = trak->Media->information->sampleTable;

	if (next_edit_start_plus_one) *next_edit_start_plus_one = 0;
	*useEdit = 1;
	*MediaTime = 0;
	//no segment yet...
	*SegmentStartTime = -1;
	*MediaOffset = -1;
	if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale || !stbl->SampleSize) {
		return GF_ISOM_INVALID_FILE;
	}

	//no samples...
	if (!stbl->SampleSize->sampleCount) {
		lastSampleTime = 0;
	} else {
		lastSampleTime = trak->Media->mediaHeader->duration;
	}

	//No edits, 1 to 1 mapping
	if (! trak->editBox || !trak->editBox->editList) {
		*MediaTime = movieTime;
		//check this is in our media time line
		if ((*MediaTime > lastSampleTime)
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
		        && !trak->moov->mov->moof
#endif
		   ) {
			*MediaTime = lastSampleTime;
		}
		*useEdit = 0;
		return GF_OK;
	}
	//browse the edit list and get the time
	scale_ts = trak->Media->mediaHeader->timeScale;
	scale_ts /= trak->moov->mvhd->timeScale;

	time = 0;
	ent = NULL;
	count=gf_list_count(trak->editBox->editList->entryList);
	for (i=0; i<count; i++) {
		ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, i);
		if ( (time + ent->segmentDuration) * scale_ts > movieTime) {
			if (!force_non_empty || (ent->mediaTime >= 0)) {
				if (next_edit_start_plus_one) *next_edit_start_plus_one = 1 + (u64) ((time + ent->segmentDuration) * scale_ts);
				goto ent_found;
			}
		}
		time += ent->segmentDuration;
		last_is_empty = ent->segmentDuration ? 0 : 1;
	}

	if (last_is_empty) {
		ent = (GF_EdtsEntry *)gf_list_last(trak->editBox->editList->entryList);
		if (ent->mediaRate == 0x10000) {
			*MediaTime = movieTime + ent->mediaTime;
		} else {
			ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, 0);
			if (ent->mediaRate == -0x10000) {
				u64 dur = (u64) (ent->segmentDuration * scale_ts);
				*MediaTime = (movieTime > dur) ? (movieTime-dur) : 0;
			}
		}
		*useEdit = 0;
		return GF_OK;
	}


	//we had nothing in the list (strange file but compliant...)
	//return the 1 to 1 mapped vale of the last media sample
	if (!ent) {
		*MediaTime = movieTime;
		//check this is in our media time line
		if (*MediaTime > lastSampleTime) *MediaTime = lastSampleTime;
		*useEdit = 0;
		return GF_OK;
	}
	//request for a bigger time that what we can give: return the last sample (undefined behavior...)
	*MediaTime = lastSampleTime;
	return GF_OK;

ent_found:
	//OK, we found our entry, set the SegmentTime
	*SegmentStartTime = time;

	//we request an empty list, there's no media here...
	if (ent->mediaTime < 0) {
		*MediaTime = 0;
		return GF_OK;
	}
	//we request a dwell edit
	if (! ent->mediaRate) {
		*MediaTime = ent->mediaTime;
		//no media offset
		*MediaOffset = 0;
		*useEdit = 2;
		return GF_OK;
	}

	/*WARNING: this can be "-1" when doing searchForward mode (to prevent jumping to next entry)*/
	mtime = ent->mediaTime + movieTime - (time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale);
	if (mtime<0) mtime = 0;
	*MediaTime = (u64) mtime;
	*MediaOffset = ent->mediaTime;

#if 0
	//
	//Sanity check: is the requested time valid ? This is to cope with wrong EditLists
	//we have the translated time, but we need to make sure we have a sample at this time ...
	//we have to find a COMPOSITION time
	e = stbl_findEntryForTime(stbl, (u32) *MediaTime, 1, &sampleNumber, &prevSampleNumber);
	if (e) return e;

	//first case: our time is after the last sample DTS (it's a broken editList somehow)
	//set the media time to the last sample
	if (!sampleNumber && !prevSampleNumber) {
		*MediaTime = lastSampleTime;
		return GF_OK;
	}
	//get the appropriated sample
	if (!sampleNumber) sampleNumber = prevSampleNumber;

	stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
	CTS = 0;
	if (stbl->CompositionOffset) stbl_GetSampleCTS(stbl->CompositionOffset, sampleNumber, &CTS);

	//now get the entry sample (the entry time gives the CTS, and we need the DTS
	e = stbl_findEntryForTime(stbl, (u32) ent->mediaTime, 0, &sampleNumber, &prevSampleNumber);
	if (e) return e;

	//oops, the mediaTime indicates a sample that is not in our media !
	if (!sampleNumber && !prevSampleNumber) {
		*MediaTime = lastSampleTime;
		return GF_ISOM_INVALID_FILE;
	}
	if (!sampleNumber) sampleNumber = prevSampleNumber;

	stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &firstDTS);

	//and store the "time offset" of the desired sample in this segment
	//this is weird, used to rebuild the timeStamp when reading from the track, not the
	//media ...
	*MediaOffset = firstDTS;
#endif
	return GF_OK;
}

Project: gpac

GF_EXPORT
GF_Box *gf_isom_box_new(u32 boxType)
{
	return gf_isom_box_new_ex(boxType, 0, 0, GF_FALSE);

Project: gpac

u32 gf_isom_solve_uuid_box(u8 *UUID)
{
	u32 i;
	char strUUID[33], strChar[3];
	strUUID[0] = 0;
	strUUID[32] = 0;
	for (i=0; i<16; i++) {
		snprintf(strChar, 3, "%02X", (unsigned char) UUID[i]);
		strcat(strUUID, strChar);
	}
	if (!strnicmp(strUUID, "8974dbce7be74c5184f97148f9882554", 32))
		return GF_ISOM_BOX_UUID_TENC;
	if (!strnicmp(strUUID, "A5D40B30E81411DDBA2F0800200C9A66", 32))
		return GF_ISOM_BOX_UUID_MSSM;
	if (!strnicmp(strUUID, "D4807EF2CA3946958E5426CB9E46A79F", 32))
		return GF_ISOM_BOX_UUID_TFRF;
	if (!strnicmp(strUUID, "6D1D9B0542D544E680E2141DAFF757B2", 32))
		return GF_ISOM_BOX_UUID_TFXD;
	if (!strnicmp(strUUID, "A2394F525A9B4F14A2446C427C648DF4", 32))
		return GF_ISOM_BOX_UUID_PSEC;
	if (!strnicmp(strUUID, "D08A4F1810F34A82B6C832D8ABA183D3", 32))
		return GF_ISOM_BOX_UUID_PSSH;

	return 0;
}

Project: gpac

GF_Err GetPrevMediaTime(GF_TrackBox *trak, u64 movieTime, u64 *OutMovieTime)
{
	u32 i;
	u64 time;
	GF_EdtsEntry *ent;

	*OutMovieTime = 0;
	if (! trak->editBox || !trak->editBox->editList) return GF_BAD_PARAM;

	time = 0;
	ent = NULL;
	i=0;
	while ((ent = (GF_EdtsEntry *)gf_list_enum(trak->editBox->editList->entryList, &i))) {
		if (ent->mediaTime == -1) {
			if ( gf_timestamp_greater_or_equal(time + ent->segmentDuration, trak->moov->mvhd->timeScale, movieTime, trak->Media->mediaHeader->timeScale)) {
				*OutMovieTime = gf_timestamp_rescale(time, trak->moov->mvhd->timeScale, trak->Media->mediaHeader->timeScale);
				return GF_OK;
			}
			continue;
		}
		/*get the first entry whose end is greater than or equal to the desired time*/
		time += ent->segmentDuration;
		if (gf_timestamp_greater_or_equal(time, trak->moov->mvhd->timeScale, movieTime, trak->Media->mediaHeader->timeScale)) {
			*OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
			return GF_OK;
		}
	}
	*OutMovieTime = 0;
	return GF_OK;
}

Project: gpac


GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs)
{
	if (!a) return GF_BAD_PARAM;
	if (!a->registry) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Write invalid box type %s without registry\n", gf_4cc_to_str(a->type) ));
		return GF_ISOM_INVALID_FILE;
	}
	return a->registry->write_fn(a, bs);