GF_Err sgpd_box_dump(GF_Box *a, FILE * trace)
{
	u32 i;
	GF_SampleGroupDescriptionBox *ptr = (GF_SampleGroupDescriptionBox*) a;
	if (!a) return GF_BAD_PARAM;

	gf_isom_box_dump_start(a, "SampleGroupDescriptionBox", trace);

	if (ptr->grouping_type)
		gf_fprintf(trace, "grouping_type=\"%s\"", gf_4cc_to_str(ptr->grouping_type) );
	if (ptr->version==1) gf_fprintf(trace, " default_length=\"%d\"", ptr->default_length);
	if ((ptr->version>=2) && ptr->default_description_index) gf_fprintf(trace, " default_group_index=\"%d\"", ptr->default_description_index);
	gf_fprintf(trace, ">\n");
	for (i=0; i<gf_list_count(ptr->group_descriptions); i++) {
		void *entry = gf_list_get(ptr->group_descriptions, i);
		switch (ptr->grouping_type) {
		case GF_ISOM_SAMPLE_GROUP_ROLL:
			gf_fprintf(trace, "<RollRecoveryEntry roll_distance=\"%d\" />\n", ((GF_RollRecoveryEntry*)entry)->roll_distance );
			break;
		case GF_ISOM_SAMPLE_GROUP_PROL:
			gf_fprintf(trace, "<AudioPreRollEntry roll_distance=\"%d\" />\n", ((GF_RollRecoveryEntry*)entry)->roll_distance );
			break;
		case GF_ISOM_SAMPLE_GROUP_TELE:
			gf_fprintf(trace, "<TemporalLevelEntry level_independently_decodable=\"%d\"/>\n", ((GF_TemporalLevelEntry*)entry)->level_independently_decodable);
			break;
		case GF_ISOM_SAMPLE_GROUP_RAP:
			gf_fprintf(trace, "<VisualRandomAccessEntry num_leading_samples_known=\"%s\"", ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known ? "yes" : "no");
			if (((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known)
				gf_fprintf(trace, " num_leading_samples=\"%d\"", ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples);
			gf_fprintf(trace, "/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SYNC:
			gf_fprintf(trace, "<SyncSampleGroupEntry NAL_unit_type=\"%d\"/>\n", ((GF_SYNCEntry*)entry)->NALU_type);
			break;
		case GF_ISOM_SAMPLE_GROUP_SEIG:
		{
			GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry;
			Bool use_mkey = seig->key_info[0] ? GF_TRUE : GF_FALSE;

			gf_fprintf(trace, "<CENCSampleEncryptionGroupEntry IsEncrypted=\"%d\"", seig->IsProtected);
			if (use_mkey) {
				u32 k, nb_keys, kpos=3;
				nb_keys = seig->key_info[1];
				nb_keys <<= 8;
				nb_keys |= seig->key_info[2];

				gf_fprintf(trace, ">\n");
				for (k=0; k<nb_keys; k++) {
					if (kpos + 17 > seig->key_info_size)
						break;
					u8 iv_size = seig->key_info[kpos];
					gf_fprintf(trace, "<CENCKey IV_size=\"%d\" KID=\"", iv_size);
					dump_data_hex(trace, seig->key_info+kpos+1, 16);
					kpos += 17;
					gf_fprintf(trace, "\"");
					if ((seig->IsProtected == 1) && !iv_size) {
						if (kpos + 1 >= seig->key_info_size)
							break;
						u8 const_IV_size = seig->key_info[kpos];
						gf_fprintf(trace, " constant_IV_size=\"%d\"  constant_IV=\"", const_IV_size);
						if (kpos + 1 + const_IV_size >= seig->key_info_size)
							break;
						dump_data_hex(trace, (char *)seig->key_info + kpos + 1, const_IV_size);
						kpos += 1 + const_IV_size;
						gf_fprintf(trace, "\"");
					}
					gf_fprintf(trace, "/>\n");
				}
				gf_fprintf(trace, "</CENCSampleEncryptionGroupEntry>\n");
			} else {
				gf_fprintf(trace, " IV_size=\"%d\" KID=\"", seig->key_info[3]);
				dump_data_hex(trace, seig->key_info+4, 16);
				if ((seig->IsProtected == 1) && !seig->key_info[3]) {
					gf_fprintf(trace, "\" constant_IV_size=\"%d\"  constant_IV=\"", seig->key_info[20]);
					dump_data_hex(trace, (char *)seig->key_info + 21, seig->key_info[20]);
				}
				gf_fprintf(trace, "\"/>\n");
			}
		}
			break;
		case GF_ISOM_SAMPLE_GROUP_OINF:
			oinf_entry_dump(entry, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_LINF:
			linf_dump(entry, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_TRIF:
			trif_dump(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			break;

		case GF_ISOM_SAMPLE_GROUP_NALM:
			nalm_dump(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			break;
		case GF_ISOM_SAMPLE_GROUP_SAP:
			gf_fprintf(trace, "<SAPEntry dependent_flag=\"%d\" SAP_type=\"%d\" />\n", ((GF_SAPEntry*)entry)->dependent_flag, ((GF_SAPEntry*)entry)->SAP_type);
			break;
		case GF_ISOM_SAMPLE_GROUP_SPOR:
		{
			GF_SubpictureOrderEntry *spor = (GF_SubpictureOrderEntry *) entry;
			gf_fprintf(trace, "<SubPictureOrderEntry subpic_id_info_flag=\"%d\" refs=\"", spor->subpic_id_info_flag);
			for (i=0; i<spor->num_subpic_ref_idx; i++) {
				if (i) gf_fprintf(trace, " ");
				gf_fprintf(trace, "%d", spor->subp_track_ref_idx[i]);
			}
			gf_fprintf(trace, "\"");
			if (spor->subpic_id_info_flag) {
				gf_fprintf(trace, " subpic_id_len_minus1=\"%d\" subpic_id_bit_pos=\"%d\" start_code_emul_flag=\"%d\"", spor->spinfo.subpic_id_len_minus1, spor->spinfo.subpic_id_bit_pos, spor->spinfo.start_code_emul_flag);
				gf_fprintf(trace, " %s=\"%d\"", spor->spinfo.pps_sps_subpic_id_flag ? "pps_id" : "sps_id", spor->spinfo.xps_id);
			}
			gf_fprintf(trace, "/>\n");
		}
			break;
		case GF_ISOM_SAMPLE_GROUP_SULM:
		{
			GF_SubpictureLayoutMapEntry *sulm = (GF_SubpictureLayoutMapEntry *) entry;
			gf_fprintf(trace, "<SubPictureLayoutMapEntry groupID_info_4cc=\"%s\" groupIDs=\"", gf_4cc_to_str(sulm->groupID_info_4cc) );
			for (i=0; i<sulm->nb_entries; i++) {
				if (i) gf_fprintf(trace, " ");
				gf_fprintf(trace, "%d", sulm->groupIDs[i]);
			}
			gf_fprintf(trace, "\"/>\n");
		}
			break;
		default:
			gf_fprintf(trace, "<DefaultSampleGroupDescriptionEntry size=\"%d\" data=\"", ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			dump_data(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			gf_fprintf(trace, "\"/>\n");
		}
	}
	if (!ptr->size) {
		switch (ptr->grouping_type) {
		case GF_ISOM_SAMPLE_GROUP_ROLL:
			gf_fprintf(trace, "<RollRecoveryEntry roll_distance=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_PROL:
			gf_fprintf(trace, "<AudioPreRollEntry roll_distance=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_TELE:
			gf_fprintf(trace, "<TemporalLevelEntry level_independently_decodable=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_RAP:
			gf_fprintf(trace, "<VisualRandomAccessEntry num_leading_samples_known=\"yes|no\" num_leading_samples=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SYNC:
			gf_fprintf(trace, "<SyncSampleGroupEntry NAL_unit_type=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SEIG:
			gf_fprintf(trace, "<CENCSampleEncryptionGroupEntry IsEncrypted=\"\" IV_size=\"\" KID=\"\" constant_IV_size=\"\"  constant_IV=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_OINF:
			oinf_entry_dump(NULL, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_LINF:
			linf_dump(NULL, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_TRIF:
			trif_dump(trace, NULL, 0);
			break;
		case GF_ISOM_SAMPLE_GROUP_NALM:
			nalm_dump(trace, NULL, 0);
			break;
		case GF_ISOM_SAMPLE_GROUP_SAP:
			gf_fprintf(trace, "<SAPEntry dependent_flag=\"\" SAP_type=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SPOR:
			gf_fprintf(trace, "<SubPictureOrderEntry subpic_id_info_flag=\"\" refs=\"\" subpic_id_len_minus1=\"\" subpic_id_bit_pos=\"\" start_code_emul_flag=\"\" pps_id=\"\" sps_id=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SULM:
			gf_fprintf(trace, "<SubPictureLayoutMapEntry groupID_info_4cc=\"\" groupIDs=\"\" />\n");
			break;

		default:
			gf_fprintf(trace, "<DefaultSampleGroupDescriptionEntry size=\"\" data=\"\"/>\n");
		}
	}

	gf_isom_box_dump_done("SampleGroupDescriptionBox", a, trace);
	return GF_OK;
}
GF_Err sgpd_box_dump(GF_Box *a, FILE * trace)
{
	u32 i;
	GF_SampleGroupDescriptionBox *ptr = (GF_SampleGroupDescriptionBox*) a;
	if (!a) return GF_BAD_PARAM;

	gf_isom_box_dump_start(a, "SampleGroupDescriptionBox", trace);

	if (ptr->grouping_type)
		gf_fprintf(trace, "grouping_type=\"%s\"", gf_4cc_to_str(ptr->grouping_type) );
	if (ptr->version==1) gf_fprintf(trace, " default_length=\"%d\"", ptr->default_length);
	if ((ptr->version>=2) && ptr->default_description_index) gf_fprintf(trace, " default_group_index=\"%d\"", ptr->default_description_index);
	gf_fprintf(trace, ">\n");
	for (i=0; i<gf_list_count(ptr->group_descriptions); i++) {
		void *entry = gf_list_get(ptr->group_descriptions, i);
		switch (ptr->grouping_type) {
		case GF_ISOM_SAMPLE_GROUP_ROLL:
			gf_fprintf(trace, "<RollRecoveryEntry roll_distance=\"%d\" />\n", ((GF_RollRecoveryEntry*)entry)->roll_distance );
			break;
		case GF_ISOM_SAMPLE_GROUP_PROL:
			gf_fprintf(trace, "<AudioPreRollEntry roll_distance=\"%d\" />\n", ((GF_RollRecoveryEntry*)entry)->roll_distance );
			break;
		case GF_ISOM_SAMPLE_GROUP_TELE:
			gf_fprintf(trace, "<TemporalLevelEntry level_independently_decodable=\"%d\"/>\n", ((GF_TemporalLevelEntry*)entry)->level_independently_decodable);
			break;
		case GF_ISOM_SAMPLE_GROUP_RAP:
			gf_fprintf(trace, "<VisualRandomAccessEntry num_leading_samples_known=\"%s\"", ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known ? "yes" : "no");
			if (((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known)
				gf_fprintf(trace, " num_leading_samples=\"%d\"", ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples);
			gf_fprintf(trace, "/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SYNC:
			gf_fprintf(trace, "<SyncSampleGroupEntry NAL_unit_type=\"%d\"/>\n", ((GF_SYNCEntry*)entry)->NALU_type);
			break;
		case GF_ISOM_SAMPLE_GROUP_SEIG:
		{
			GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry;
			Bool use_mkey = seig->key_info[0] ? GF_TRUE : GF_FALSE;

			gf_fprintf(trace, "<CENCSampleEncryptionGroupEntry IsEncrypted=\"%d\"", seig->IsProtected);
			if (use_mkey) {
				u32 k, nb_keys, kpos=3;
				nb_keys = seig->key_info[1];
				nb_keys <<= 8;
				nb_keys |= seig->key_info[2];

				gf_fprintf(trace, ">\n");
				for (k=0; k<nb_keys; k++) {
					if (kpos + 17 > seig->key_info_size)
						break;
					u8 iv_size = seig->key_info[kpos];
					gf_fprintf(trace, "<CENCKey IV_size=\"%d\" KID=\"", iv_size);
					dump_data_hex(trace, seig->key_info+kpos+1, 16);
					kpos += 17;
					gf_fprintf(trace, "\"");
					if ((seig->IsProtected == 1) && !iv_size) {
						if (kpos + 1 >= seig->key_info_size)
							break;
						u8 const_IV_size = seig->key_info[kpos];
						gf_fprintf(trace, " constant_IV_size=\"%d\"  constant_IV=\"", const_IV_size);
						if (kpos + 1 + const_IV_size >= seig->key_info_size)
							break;
						dump_data_hex(trace, (char *)seig->key_info + kpos + 1, const_IV_size);
						kpos += 1 + const_IV_size;
						gf_fprintf(trace, "\"");
					}
					gf_fprintf(trace, "/>\n");
				}
				gf_fprintf(trace, "</CENCSampleEncryptionGroupEntry>\n");
			} else {
				gf_fprintf(trace, " IV_size=\"%d\" KID=\"", seig->key_info[3]);
				dump_data_hex(trace, seig->key_info+4, 16);
				if ((seig->IsProtected == 1) && !seig->key_info[3]) {
					gf_fprintf(trace, "\" constant_IV_size=\"%d\"  constant_IV=\"", seig->key_info[20]);
					dump_data_hex(trace, (char *)seig->key_info + 21, seig->key_info[20]);
				}
				gf_fprintf(trace, "\"/>\n");
			}
		}
			break;
		case GF_ISOM_SAMPLE_GROUP_OINF:
			oinf_entry_dump(entry, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_LINF:
			linf_dump(entry, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_TRIF:
			trif_dump(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			break;

		case GF_ISOM_SAMPLE_GROUP_NALM:
			nalm_dump(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			break;
		case GF_ISOM_SAMPLE_GROUP_SAP:
			gf_fprintf(trace, "<SAPEntry dependent_flag=\"%d\" SAP_type=\"%d\" />\n", ((GF_SAPEntry*)entry)->dependent_flag, ((GF_SAPEntry*)entry)->SAP_type);
			break;
		case GF_ISOM_SAMPLE_GROUP_SPOR:
		{
			GF_SubpictureOrderEntry *spor = (GF_SubpictureOrderEntry *) entry;
			gf_fprintf(trace, "<SubPictureOrderEntry subpic_id_info_flag=\"%d\" refs=\"", spor->subpic_id_info_flag);
			for (i=0; i<spor->num_subpic_ref_idx; i++) {
				if (i) gf_fprintf(trace, " ");
				gf_fprintf(trace, "%d", spor->subp_track_ref_idx[i]);
			}
			gf_fprintf(trace, "\"");
			if (spor->subpic_id_info_flag) {
				gf_fprintf(trace, " subpic_id_len_minus1=\"%d\" subpic_id_bit_pos=\"%d\" start_code_emul_flag=\"%d\"", spor->spinfo.subpic_id_len_minus1, spor->spinfo.subpic_id_bit_pos, spor->spinfo.start_code_emul_flag);
				gf_fprintf(trace, " %s=\"%d\"", spor->spinfo.pps_sps_subpic_id_flag ? "pps_id" : "sps_id", spor->spinfo.xps_id);
			}
			gf_fprintf(trace, "/>\n");
		}
			break;
		case GF_ISOM_SAMPLE_GROUP_SULM:
		{
			GF_SubpictureLayoutMapEntry *sulm = (GF_SubpictureLayoutMapEntry *) entry;
			gf_fprintf(trace, "<SubPictureLayoutMapEntry groupID_info_4cc=\"%s\" groupIDs=\"", gf_4cc_to_str(sulm->groupID_info_4cc) );
			for (i=0; i<sulm->nb_entries; i++) {
				if (i) gf_fprintf(trace, " ");
				gf_fprintf(trace, "%d", sulm->groupIDs[i]);
			}
			gf_fprintf(trace, "\"/>\n");
		}
			break;
		default:
			gf_fprintf(trace, "<DefaultSampleGroupDescriptionEntry size=\"%d\" data=\"", ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			dump_data(trace, (char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data,  ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length);
			gf_fprintf(trace, "\"/>\n");
		}
	}
	if (!ptr->size) {
		switch (ptr->grouping_type) {
		case GF_ISOM_SAMPLE_GROUP_ROLL:
			gf_fprintf(trace, "<RollRecoveryEntry roll_distance=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_PROL:
			gf_fprintf(trace, "<AudioPreRollEntry roll_distance=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_TELE:
			gf_fprintf(trace, "<TemporalLevelEntry level_independently_decodable=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_RAP:
			gf_fprintf(trace, "<VisualRandomAccessEntry num_leading_samples_known=\"yes|no\" num_leading_samples=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SYNC:
			gf_fprintf(trace, "<SyncSampleGroupEntry NAL_unit_type=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SEIG:
			gf_fprintf(trace, "<CENCSampleEncryptionGroupEntry IsEncrypted=\"\" IV_size=\"\" KID=\"\" constant_IV_size=\"\"  constant_IV=\"\"/>\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_OINF:
			oinf_entry_dump(NULL, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_LINF:
			linf_dump(NULL, trace);
			break;
		case GF_ISOM_SAMPLE_GROUP_TRIF:
			trif_dump(trace, NULL, 0);
			break;
		case GF_ISOM_SAMPLE_GROUP_NALM:
			nalm_dump(trace, NULL, 0);
			break;
		case GF_ISOM_SAMPLE_GROUP_SAP:
			gf_fprintf(trace, "<SAPEntry dependent_flag=\"\" SAP_type=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SPOR:
			gf_fprintf(trace, "<SubPictureOrderEntry subpic_id_info_flag=\"\" refs=\"\" subpic_id_len_minus1=\"\" subpic_id_bit_pos=\"\" start_code_emul_flag=\"\" pps_id=\"\" sps_id=\"\" />\n");
			break;
		case GF_ISOM_SAMPLE_GROUP_SULM:
			gf_fprintf(trace, "<SubPictureLayoutMapEntry groupID_info_4cc=\"\" groupIDs=\"\" />\n");
			break;

		default:
			gf_fprintf(trace, "<DefaultSampleGroupDescriptionEntry size=\"\" data=\"\"/>\n");
		}
	}

	gf_isom_box_dump_done("SampleGroupDescriptionBox", a, trace);
	return GF_OK;
}