Пример #1
0
/*switch channel quality. Return next channel or current channel if error*/
static
u32 gf_channel_switch_quality(ISOMChannel *ch, GF_ISOFile *the_file, Bool switch_up)
{
	u32 i, count, next_track, trackID, cur_track;
	s32 ref_count;

	cur_track = ch->next_track ? ch->next_track : ch->track;
	count = gf_isom_get_track_count(the_file);
	trackID = gf_isom_get_track_id(the_file, cur_track);
	next_track = 0;

	if (switch_up)
	{
		for (i = 0; i < count; i++)
		{
			ref_count = gf_isom_get_reference_count(the_file, i+1, GF_ISOM_REF_SCAL);
			if (ref_count < 0)
				return cur_track; //error
			else if (ref_count == 0)
				continue;
			/*next track is the one that has the last reference of type GF_ISOM_REF_SCAL refers to this current track*/
			else if ((u32)ref_count == gf_isom_has_track_reference(the_file, i+1, GF_ISOM_REF_SCAL, trackID))
			{
				next_track = i+1;
				break;
			}
		}
		/*this is the highest quality*/
		if (!next_track)
			return cur_track;
	}
	else
	{
		if (cur_track == ch->base_track)
			return cur_track;
		ref_count = gf_isom_get_reference_count(the_file, cur_track, GF_ISOM_REF_SCAL);
		if (ref_count < 0)
			return cur_track;
		gf_isom_get_reference(the_file, cur_track, GF_ISOM_REF_SCAL, ref_count, &next_track);
		if (!next_track)
			return cur_track;
	}

	/*in scalable mode add SPS/PPS in-band*/
	gf_isom_set_nalu_extract_mode(the_file, next_track, ch->nalu_extract_mode);

	return next_track;
}
Пример #2
0
void isor_declare_objects(ISOMReader *read)
{
	GF_ObjectDescriptor *od;
	GF_ESD *esd;
	const char *tag;
	u32 i, count, ocr_es_id, tlen, base_track, j, track_id;
	Bool highest_stream;
	char *opt;
	Bool add_ps_lower = GF_TRUE;

	ocr_es_id = 0;
	opt = (char*) gf_modules_get_option((GF_BaseInterface *)read->input, "ISOReader", "DeclareScalableXPS");
	if (!opt) {
		gf_modules_set_option((GF_BaseInterface *)read->input, "ISOReader", "DeclareScalableXPS", "yes");
	} else if (!strcmp(opt, "no")) {
		add_ps_lower = GF_FALSE;
	}

	/*TODO check for alternate tracks*/
	count = gf_isom_get_track_count(read->mov);
	for (i=0; i<count; i++) {
		if (!gf_isom_is_track_enabled(read->mov, i+1)) continue;

		switch (gf_isom_get_media_type(read->mov, i+1)) {
		case GF_ISOM_MEDIA_AUDIO:
		case GF_ISOM_MEDIA_VISUAL:
		case GF_ISOM_MEDIA_TEXT:
		case GF_ISOM_MEDIA_SUBT:
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_SUBPIC:
			break;
		default:
			continue;
		}

		/*we declare only the highest video track (i.e the track we play)*/
		highest_stream = GF_TRUE;
		track_id = gf_isom_get_track_id(read->mov, i+1);
		for (j = 0; j < count; j++) {
			if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) {
				highest_stream = GF_FALSE;
				break;
			}
		}
		if ((gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream)
			continue;
		esd = gf_media_map_esd(read->mov, i+1);
		if (esd) {
			gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track);
			esd->has_ref_base = base_track ? GF_TRUE : GF_FALSE;
			/*FIXME: if we declare only SPS/PPS of the highest layer, we have a problem in decoding even though we have all SPS/PPS inband (OpenSVC bug ?)*/
			/*so we add by default the SPS/PPS of the lower layers to this esd*/
			if (esd->has_ref_base && add_ps_lower) {
				u32 count, refIndex, ref_track, num_sps, num_pps, t;
				GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
				GF_AVCConfig *avccfg, *svccfg;

				count = gf_isom_get_reference_count(read->mov, i+1, GF_ISOM_REF_SCAL);
				for (refIndex = count; refIndex != 0; refIndex--) {
					gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_SCAL, refIndex, &ref_track);
					avccfg = gf_isom_avc_config_get(read->mov, ref_track, 1);
					svccfg = gf_isom_svc_config_get(read->mov, ref_track, 1);
					if (avccfg) {
						num_sps = gf_list_count(avccfg->sequenceParameterSets);
						for (t = 0; t < num_sps; t++) {
							GF_AVCConfigSlot *slc = gf_list_get(avccfg->sequenceParameterSets, t);
							GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
							sl->id = slc->id;
							sl->size = slc->size;
							sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
							memcpy(sl->data, slc->data, sizeof(char)*sl->size);
							gf_list_insert(cfg->sequenceParameterSets, sl, 0);
						}
						num_pps = gf_list_count(avccfg->pictureParameterSets);
						for (t = 0; t < num_sps; t++) {
							GF_AVCConfigSlot *slc = gf_list_get(avccfg->pictureParameterSets, t);
							GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
							sl->id = slc->id;
							sl->size = slc->size;
							sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
							memcpy(sl->data, slc->data, sizeof(char)*sl->size);
							gf_list_insert(cfg->pictureParameterSets, sl, 0);
						}
						gf_odf_avc_cfg_del(avccfg);
					}
					if (svccfg) {
						num_sps = gf_list_count(svccfg->sequenceParameterSets);
						for (t = 0; t < num_sps; t++) {
							GF_AVCConfigSlot *slc = gf_list_get(svccfg->sequenceParameterSets, t);
							GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
							sl->id = slc->id;
							sl->size = slc->size;
							sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
							memcpy(sl->data, slc->data, sizeof(char)*sl->size);
							gf_list_insert(cfg->sequenceParameterSets, sl, 0);
						}
						num_pps = gf_list_count(svccfg->pictureParameterSets);
						for (t = 0; t < num_pps; t++) {
							GF_AVCConfigSlot *slc = gf_list_get(svccfg->pictureParameterSets, t);
							GF_AVCConfigSlot *sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
							sl->id = slc->id;
							sl->size = slc->size;
							sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
							memcpy(sl->data, slc->data, sizeof(char)*sl->size);
							gf_list_insert(cfg->pictureParameterSets, sl, 0);
						}
						gf_odf_avc_cfg_del(svccfg);
					}
				}

				if (esd->decoderConfig->decoderSpecificInfo->data) gf_free(esd->decoderConfig->decoderSpecificInfo->data);
				gf_odf_avc_cfg_write(cfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
				gf_odf_avc_cfg_del(cfg);
			}

			od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
			od->service_ifce = read->input;
			od->objectDescriptorID = 0;
			if (!ocr_es_id) ocr_es_id = esd->ESID;
			esd->OCRESID = ocr_es_id;
			gf_list_add(od->ESDescriptors, esd);
			if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
				send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL);
			} else {
				gf_term_add_media(read->service, (GF_Descriptor*)od, GF_TRUE);
			}
		}
	}
	/*if cover art, extract it in cache*/
	if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) {
		const char *cdir = gf_modules_get_option((GF_BaseInterface *)gf_term_get_service_interface(read->service), "General", "CacheDirectory");
		if (cdir) {
			char szName[GF_MAX_PATH];
			const char *sep;
			FILE *t;
			sep = strrchr(gf_isom_get_filename(read->mov), '\\');
			if (!sep) sep = strrchr(gf_isom_get_filename(read->mov), '/');
			if (!sep) sep = gf_isom_get_filename(read->mov);

			if ((cdir[strlen(cdir)-1] != '\\') && (cdir[strlen(cdir)-1] != '/')) {
				sprintf(szName, "%s/%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg");
			} else {
				sprintf(szName, "%s%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg");
			}

			t = gf_f64_open(szName, "wb");

			if (t) {
				Bool isom_contains_video = GF_FALSE;

				/*write cover data*/
				assert(!(tlen & 0x80000000));
				gf_fwrite(tag, tlen & 0x7FFFFFFF, 1, t);
				fclose(t);

				/*don't display cover art when video is present*/
				for (i=0; i<gf_isom_get_track_count(read->mov); i++) {
					if (!gf_isom_is_track_enabled(read->mov, i+1))
						continue;
					if (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) {
						isom_contains_video = GF_TRUE;
						break;
					}
				}

				if (!isom_contains_video) {
					od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
					od->service_ifce = read->input;
					od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID;
					od->URLString = gf_strdup(szName);
					if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
						send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL);
					} else {
						gf_term_add_media(read->service, (GF_Descriptor*)od, GF_TRUE);
					}
				}
			}
		}
	}
	if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
		send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, NULL, NULL);
	} else {
		gf_term_add_media(read->service, NULL, GF_FALSE);
	}
}
Пример #3
0
static GF_Err gf_isom_streamer_setup_sdp(GF_ISOMRTPStreamer *streamer, char*sdpfilename, char **out_sdp_buffer)
{
	GF_RTPTrack *track;
	FILE *sdp_out;
	char filename[GF_MAX_PATH];
	char sdpLine[20000];
	u32 t, count;
	u8 *payload_type;

	strcpy(filename, sdpfilename ? sdpfilename : "videosession.sdp");
	sdp_out = gf_fopen(filename, "wt");
	if (!sdp_out) return GF_IO_ERR;

	if (!out_sdp_buffer) {
		sprintf(sdpLine, "v=0");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "o=MP4Streamer 3357474383 1148485440000 IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip);
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "s=livesession");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "i=This is an MP4 time-sliced Streaming demo");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "u=http://gpac.sourceforge.net");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "e=admin@");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "c=IN IP%d %s", gf_net_is_ipv6(streamer->dest_ip) ? 6 : 4, streamer->dest_ip);
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "t=0 0");
		fprintf(sdp_out, "%s\n", sdpLine);
		sprintf(sdpLine, "a=x-copyright: Streamed with GPAC (C)2000-200X - http://gpac.sourceforge.net");
		fprintf(sdp_out, "%s\n", sdpLine);
		if (streamer->base_track)
		{
			sprintf(sdpLine, "a=group:DDP L%d", streamer->base_track);
			fprintf(sdp_out, "%s", sdpLine);
			count = gf_isom_get_track_count(streamer->isom);
			for (t = 0; t < count; t++)
			{
				if (gf_isom_has_track_reference(streamer->isom, t+1, GF_ISOM_REF_BASE, gf_isom_get_track_id(streamer->isom, streamer->base_track)))
				{
					sprintf(sdpLine, " L%d", t+1);
					fprintf(sdp_out, "%s", sdpLine);
				}
			}
			fprintf(sdp_out, "\n");
		}
	}

	/*prepare array of payload type*/
	count = gf_isom_get_track_count(streamer->isom);
	payload_type = (u8 *)gf_malloc(count * sizeof(u8));
	track = streamer->stream;
	while (track) {
		payload_type[track->track_num-1] = gf_rtp_streamer_get_payload_type(track->rtp);
		track = track->next;
	}


	track = streamer->stream;
	while (track) {
		char *sdp_media=NULL;
		const char *KMS = NULL;
		char *dsi = NULL;
		u32 w, h;
		u32 dsi_len = 0;
		GF_DecoderConfig *dcd;
		//use inspect mode so that we don't aggregate xPS from the base in the enhancement ESD
		gf_isom_set_nalu_extract_mode(streamer->isom, track->track_num, GF_ISOM_NALU_EXTRACT_INSPECT);
		dcd = gf_isom_get_decoder_config(streamer->isom, track->track_num, 1);

		if (dcd && dcd->decoderSpecificInfo) {
			dsi = dcd->decoderSpecificInfo->data;
			dsi_len = dcd->decoderSpecificInfo->dataLength;
		}
		w = h = 0;
		if (gf_isom_get_media_type(streamer->isom, track->track_num) == GF_ISOM_MEDIA_VISUAL) {
			gf_isom_get_visual_info(streamer->isom, track->track_num, 1, &w, &h);
		}

		gf_isom_get_ismacryp_info(streamer->isom, track->track_num, 1, NULL, NULL, NULL, NULL, &KMS, NULL, NULL, NULL);

		/*TODO retrieve DIMS content encoding from track to set the flags */
		gf_rtp_streamer_append_sdp_extended(track->rtp, gf_isom_get_track_id(streamer->isom, track->track_num), dsi, dsi_len, streamer->isom, track->track_num, (char *)KMS, w, h, &sdp_media);
		if (streamer->base_track)
			gf_rtp_streamer_append_sdp_decoding_dependency(streamer->isom, track->track_num, payload_type, &sdp_media);
		if (sdp_media) {
			fprintf(sdp_out, "%s", sdp_media);
			gf_free(sdp_media);
		}

		if (dcd) gf_odf_desc_del((GF_Descriptor *)dcd);

		track = track->next;
	}
	fprintf(sdp_out, "\n");

	gf_fclose(sdp_out);
	if (out_sdp_buffer) {
		u64 size;
		sdp_out = gf_fopen(filename, "r");
		gf_fseek(sdp_out, 0, SEEK_END);
		size = gf_ftell(sdp_out);
		gf_fseek(sdp_out, 0, SEEK_SET);
		if (*out_sdp_buffer) gf_free(*out_sdp_buffer);
		*out_sdp_buffer = gf_malloc(sizeof(char)*(size_t)(size+1));
		size = fread(*out_sdp_buffer, 1, (size_t)size, sdp_out);
		gf_fclose(sdp_out);
		(*out_sdp_buffer)[size]=0;
	}

	gf_free(payload_type);
	return GF_OK;
}
Пример #4
0
void isor_declare_objects(ISOMReader *read)
{
	GF_ObjectDescriptor *od;
	GF_ESD *esd;
	const char *tag;
	u32 i, count, ocr_es_id, tlen, base_track, j, track_id;
	Bool highest_stream;

	ocr_es_id = 0;

	/*TODO check for alternate tracks*/
	count = gf_isom_get_track_count(read->mov);
	for (i=0; i<count; i++) {
		if (!gf_isom_is_track_enabled(read->mov, i+1))
			continue;

		switch (gf_isom_get_media_type(read->mov, i+1)) {
		case GF_ISOM_MEDIA_AUDIO:
		case GF_ISOM_MEDIA_VISUAL:
		case GF_ISOM_MEDIA_TEXT:
		case GF_ISOM_MEDIA_SUBT:
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_SUBPIC:
			break;
		default:
			continue;
		}
		//some subtypes are not declared as readable objects
		switch (gf_isom_get_media_subtype(read->mov, i+1, 1)) {
		case GF_ISOM_SUBTYPE_HVT1:
			continue;
		default:
			break;
		}
		/*we declare only the highest video track (i.e the track we play)*/
		highest_stream = GF_TRUE;
		track_id = gf_isom_get_track_id(read->mov, i+1);
		if (read->play_only_track_id && (read->play_only_track_id != track_id)) continue;

		for (j = 0; j < count; j++) {
			if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) {
				highest_stream = GF_FALSE;
				break;
			}
		}
		if ((gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) && !highest_stream)
			continue;
		esd = gf_media_map_esd(read->mov, i+1);
		if (esd) {
			gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track);
			esd->has_ref_base = base_track ? GF_TRUE : GF_FALSE;

			if (!esd->langDesc) {
				esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);
				gf_isom_get_media_language(read->mov, i+1, &esd->langDesc->full_lang_code);
			}

			od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
			od->service_ifce = read->input;
			od->objectDescriptorID = 0;
			if (!ocr_es_id) ocr_es_id = esd->ESID;
			esd->OCRESID = ocr_es_id;
			gf_list_add(od->ESDescriptors, esd);
			if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
				send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL);
			} else {
				gf_service_declare_media(read->service, (GF_Descriptor*)od, GF_TRUE);
			}
		}
	}
	/*if cover art, extract it in cache*/
	if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COVER_ART, &tag, &tlen)==GF_OK) {
		const char *cdir = gf_modules_get_option((GF_BaseInterface *)gf_service_get_interface(read->service), "General", "CacheDirectory");
		if (cdir) {
			char szName[GF_MAX_PATH];
			const char *sep;
			FILE *t;
			sep = strrchr(gf_isom_get_filename(read->mov), '\\');
			if (!sep) sep = strrchr(gf_isom_get_filename(read->mov), '/');
			if (!sep) sep = gf_isom_get_filename(read->mov);

			if ((cdir[strlen(cdir)-1] != '\\') && (cdir[strlen(cdir)-1] != '/')) {
				sprintf(szName, "%s/%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg");
			} else {
				sprintf(szName, "%s%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg");
			}

			t = gf_fopen(szName, "wb");

			if (t) {
				Bool isom_contains_video = GF_FALSE;

				/*write cover data*/
				assert(!(tlen & 0x80000000));
				gf_fwrite(tag, tlen & 0x7FFFFFFF, 1, t);
				gf_fclose(t);

				/*don't display cover art when video is present*/
				for (i=0; i<gf_isom_get_track_count(read->mov); i++) {
					if (!gf_isom_is_track_enabled(read->mov, i+1))
						continue;
					if (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_VISUAL) {
						isom_contains_video = GF_TRUE;
						break;
					}
				}

				if (!isom_contains_video) {
					od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
					od->service_ifce = read->input;
					od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID;
					od->URLString = gf_strdup(szName);
					if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
						send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, (GF_Descriptor*)od, NULL);
					} else {
						gf_service_declare_media(read->service, (GF_Descriptor*)od, GF_TRUE);
					}
				}
			}
		}
	}
	if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
		send_proxy_command(read, GF_FALSE, GF_TRUE, GF_OK, NULL, NULL);
	} else {
		gf_service_declare_media(read->service, NULL, GF_FALSE);
	}
}
Пример #5
0
/* Rewrite mode:
 * mode = 0: playback
 * mode = 1: streaming
 */
GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry)
{
	Bool is_hevc = 0;
	GF_Err e = GF_OK;
	GF_ISOSample *ref_samp;
	GF_BitStream *src_bs, *ref_bs, *dst_bs;
	u64 offset;
	u32 ref_nalu_size, data_offset, data_length, copy_size, nal_size, max_size, di, nal_unit_size_field, cur_extract_mode, extractor_mode;
	Bool rewrite_ps, rewrite_start_codes;
	u8 ref_track_ID, ref_track_num;
	s8 sample_offset, nal_type;
	u32 nal_hdr;
	char *buffer;
	GF_ISOFile *file = mdia->mediaTrack->moov->mov;

	src_bs = ref_bs = dst_bs = NULL;
	ref_samp = NULL;
	buffer = NULL;
	rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? 1 : 0;
	if (! sample->IsRAP) rewrite_ps = 0;
	rewrite_start_codes = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG) ? 1 : 0;
	extractor_mode = mdia->mediaTrack->extractor_mode&0x0000FFFF;

	if (extractor_mode == GF_ISOM_NALU_EXTRACT_INSPECT) {
		if (!rewrite_ps && !rewrite_start_codes)
			return GF_OK;
	}

	if (!entry) return GF_BAD_PARAM;
	nal_unit_size_field = 0;
	/*if svc rewrire*/
	if (entry->svc_config && entry->svc_config->config) nal_unit_size_field = entry->svc_config->config->nal_unit_size;
	/*if mvc rewrire*/

	/*otherwise do nothing*/
	else if (!rewrite_ps && !rewrite_start_codes) {
		return GF_OK;
	}

	if (!nal_unit_size_field) {
		if (entry->avc_config) nal_unit_size_field = entry->avc_config->config->nal_unit_size;
		else if (entry->hevc_config) {
			nal_unit_size_field = entry->hevc_config->config->nal_unit_size;
			is_hevc = 1;
		}
	}
	if (!nal_unit_size_field) return GF_ISOM_INVALID_FILE;

	dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	src_bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ);
	max_size = 4096;

	/*rewrite start code with NALU delim*/
	if (rewrite_start_codes) {
		gf_bs_write_int(dst_bs, 1, 32);
		if (is_hevc) {
			gf_bs_write_int(dst_bs, 0, 1);
			gf_bs_write_int(dst_bs, GF_HEVC_NALU_ACCESS_UNIT, 6);
			gf_bs_write_int(dst_bs, 0, 9);
			/*pic-type - by default we signal all slice types possible*/
			gf_bs_write_int(dst_bs, 2, 3);
			gf_bs_write_int(dst_bs, 0, 5);
		} else {
			gf_bs_write_int(dst_bs, (sample->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
			gf_bs_write_int(dst_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
		}
	}

	if (rewrite_ps) {
		if (is_hevc) {
			u32 i, count;
			count = gf_list_count(entry->hevc_config->config->param_array);
			for (i=0; i<count; i++) {
				GF_HEVCParamArray *ar = gf_list_get(entry->hevc_config->config->param_array, i);
				rewrite_nalus_list(ar->nalus, dst_bs, rewrite_start_codes, nal_unit_size_field);
			}

			/*little optimization if we are not asked to start codes: copy over the sample*/
			if (!rewrite_start_codes) {
				gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
				gf_free(sample->data);
				sample->data = NULL;
				gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
				gf_bs_del(src_bs);
				gf_bs_del(dst_bs);
				return GF_OK;
			}
		} else {

			/*this is an SVC track: get all SPS/PPS from this track down to the base layer and rewrite them*/
			if (mdia->mediaTrack->has_base_layer) {
				u32 j;
				GF_List *nalu_sps = gf_list_new();
				GF_List *nalu_pps = gf_list_new();
				GF_TrackReferenceTypeBox *dpnd = NULL;
				Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &dpnd);

#if 0
				/*get all upper layers with SCAL reference to this track*/
				for (j = 0; j < gf_isom_get_track_count(file); j++) {
					if (gf_isom_has_track_reference(file, j+1, GF_ISOM_REF_SCAL, mdia->mediaTrack->Header->trackID)) {
						u32 tkID;
						GF_TrackBox *base_track;
						GF_MPEGVisualSampleEntryBox *base_entry;
						gf_isom_get_reference_ID(file, j+1, GF_ISOM_REF_SCAL, 1, &tkID);

						base_track = GetTrackbyID(mdia->mediaTrack->moov, tkID);
						base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
						if (base_entry)
							merge_nalus(base_entry, nalu_sps, nalu_pps);
					}
				}

#endif

				merge_nalus(entry, nalu_sps, nalu_pps);
				if (dpnd) {
					for (j=0; j<dpnd->trackIDCount; j++) {
						GF_TrackBox *base_track = GetTrackbyID(mdia->mediaTrack->moov, dpnd->trackIDs[j]);
						GF_MPEGVisualSampleEntryBox *base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
						if (base_entry)
							merge_nalus(base_entry, nalu_sps, nalu_pps);
					}
				}

				//rewrite nalus
				rewrite_nalus_list(nalu_sps, dst_bs, rewrite_start_codes, nal_unit_size_field);
				rewrite_nalus_list(nalu_pps, dst_bs, rewrite_start_codes, nal_unit_size_field);

				gf_list_del(nalu_sps);
				gf_list_del(nalu_pps);
			} else {

				if (entry->avc_config) {
					rewrite_nalus_list(entry->avc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->avc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->avc_config->config->sequenceParameterSetExtensions, dst_bs, rewrite_start_codes, nal_unit_size_field);
				}

				/*add svc config */
				if (entry->svc_config) {
					rewrite_nalus_list(entry->svc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->svc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
				}

				/*little optimization if we are not asked to rewrite extractors or start codes: copy over the sample*/
				if (!entry->svc_config && !rewrite_start_codes) {
					gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
					gf_free(sample->data);
					sample->data = NULL;
					gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
					gf_bs_del(src_bs);
					gf_bs_del(dst_bs);
					return GF_OK;
				}

			}
		}
	}

	buffer = (char *)gf_malloc(sizeof(char)*max_size);

	while (gf_bs_available(src_bs))
	{
		nal_size = gf_bs_read_int(src_bs, 8*nal_unit_size_field);
		if (nal_size>max_size) {
			buffer = (char*) gf_realloc(buffer, sizeof(char)*nal_size);
			max_size = nal_size;
		}
		if (is_hevc) {
			nal_hdr = gf_bs_read_u16(src_bs);
			nal_type = (nal_hdr&0x7E00) >> 9;
		} else {
			nal_hdr = gf_bs_read_u8(src_bs);
			nal_type = nal_hdr & 0x1F;
		}

		if (is_hevc) {
			/*we already wrote this stuff*/
			if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) {
				gf_bs_skip_bytes(src_bs, nal_size-2);
				continue;
			}

			/*rewrite nal*/
			gf_bs_read_data(src_bs, buffer, nal_size-2);
			if (rewrite_start_codes)
				gf_bs_write_u32(dst_bs, 1);
			else
				gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);

			gf_bs_write_u16(dst_bs, nal_hdr);
			gf_bs_write_data(dst_bs, buffer, nal_size-2);

			continue;
		}

		/*we already wrote this stuff*/
		if (nal_type==GF_AVC_NALU_ACCESS_UNIT) {
			gf_bs_skip_bytes(src_bs, nal_size-1);
			continue;
		}

		//extractor
		if (nal_type == 31) {
			switch (extractor_mode) {
			case 0:
				gf_bs_read_int(src_bs, 24); //3 bytes of NALUHeader in extractor
				ref_track_ID = gf_bs_read_u8(src_bs);
				sample_offset = (s8) gf_bs_read_int(src_bs, 8);
				data_offset = gf_bs_read_u32(src_bs);
				data_length = gf_bs_read_u32(src_bs);

				ref_track_num = gf_isom_get_track_by_id(file, ref_track_ID);
				if (!ref_track_num) {
					e = GF_BAD_PARAM;
					goto exit;
				}
				cur_extract_mode = gf_isom_get_nalu_extract_mode(file, ref_track_num);
				gf_isom_set_nalu_extract_mode(file, ref_track_num, GF_ISOM_NALU_EXTRACT_INSPECT);
				ref_samp = gf_isom_get_sample(file, ref_track_num, sampleNumber+sample_offset, &di);
				if (!ref_samp) {
					e = GF_IO_ERR;
					goto exit;
				}
				ref_bs = gf_bs_new(ref_samp->data, ref_samp->dataLength, GF_BITSTREAM_READ);
				offset = 0;
				while (gf_bs_available(ref_bs)) {
					if (gf_bs_get_position(ref_bs) < data_offset) {
						ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
						offset += ref_nalu_size + nal_unit_size_field;
						if ((offset > data_offset) || (offset >= gf_bs_get_size(ref_bs))) {
							e = GF_BAD_PARAM;
							goto exit;
						}

						e = gf_bs_seek(ref_bs, offset);
						if (e)
							goto exit;
						continue;
					}
					ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
					copy_size = data_length ? data_length : ref_nalu_size;
					assert(copy_size <= ref_nalu_size);
					nal_hdr = gf_bs_read_u8(ref_bs); //rewrite NAL type
					if ((copy_size-1)>max_size) {
						buffer = (char*)gf_realloc(buffer, sizeof(char)*(copy_size-1));
						max_size = copy_size-1;
					}
					gf_bs_read_data(ref_bs, buffer, copy_size-1);

					if (rewrite_start_codes)
						gf_bs_write_u32(dst_bs, 1);
					else
						gf_bs_write_int(dst_bs, copy_size, 8*nal_unit_size_field);

					gf_bs_write_u8(dst_bs, nal_hdr);
					gf_bs_write_data(dst_bs, buffer, copy_size-1);
				}

				gf_isom_sample_del(&ref_samp);
				ref_samp = NULL;
				gf_bs_del(ref_bs);
				ref_bs = NULL;
				gf_isom_set_nalu_extract_mode(file, ref_track_num, cur_extract_mode);
				break;
			default:
				//skip to end of this NALU
				gf_bs_skip_bytes(src_bs, nal_size-1);
				continue;
			}
		} else {
			gf_bs_read_data(src_bs, buffer, nal_size-1);
			if (rewrite_start_codes)
				gf_bs_write_u32(dst_bs, 1);
			else
				gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);

			gf_bs_write_u8(dst_bs, nal_hdr);
			gf_bs_write_data(dst_bs, buffer, nal_size-1);
		}
	}