Beispiel #1
0
GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size)
{
	GF_Err e;
	u32 i;
#ifdef ADOBE_INLINED_BOOTSTRAP
	char bootstrap64[GF_MAX_PATH];
	u32 bootstrap64_len;
#endif

	fprintf(am->f, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
	fprintf(am->f, "<manifest xmlns=\"http://ns.adobe.com/f4m/2.0\">\n");
	fprintf(am->f, "<id>%s</id>\n", am->id);
	fprintf(am->f, "<baseURL>%s</baseURL>\n", am->base_url);
    fprintf(am->f, "<streamType>live</streamType>\n");

	assert(am->streams);
	for (i=0; i<gf_list_count(am->streams); i++) {
		AdobeStream *as = gf_list_get(am->streams, i);
		assert(as);
#ifdef ADOBE_INLINED_BOOTSTRAP
		fprintf(am->f, "<bootstrapInfo profile=\"named\" id=\"boot_%s_%d\">\n", as->id, as->bitrate);
		bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_size, bootstrap64, GF_MAX_PATH);
		fwrite(bootstrap64, bootstrap64_len, 1, am->f);
		if (bootstrap64_len >= GF_MAX_PATH) {
			fprintf(stderr, "Bootstrap may have been truncated for stream %s_%d.\n", as->id, as->bitrate);
			assert(0);
		}
		fprintf(am->f, "\n</bootstrapInfo>\n");
#else
		{
			char filename[GF_MAX_PATH];
			FILE *bstfile;
			sprintf(filename, "%s_%d.bootstrap", as->id, as->bitrate);
			bstfile = fopen(filename, "wb");
			gf_fwrite(bootstrap, bootstrap_size, 1, bstfile);
			fclose(bstfile);
		}
#endif
		e = adobe_gen_stream_manifest(as); 
		if (!e) { 
			if (!am->base_url && !as->base_url) 
				fprintf(stderr, "Warning: no base_url specified\n"); 

			fprintf(am->f, "<media href=\"%s_%s_%d.f4m\" bitrate=\"%d\"/>\n", am->id, as->id, as->bitrate, as->bitrate); 
		}
	}
	fprintf(am->f, "</manifest>\n");

	return GF_OK;
}
Beispiel #2
0
void gf_media_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, char *sdpLine, GF_ISOFile *file, u32 track)
{
	char buffer[2000];
	u32 w, h, i, m_w, m_h;
	s32 tx, ty;
	s16 l;
	sprintf(sdpLine, "a=fmtp:%d sver=60; ", builder->PayloadType);
	gf_isom_get_track_layout_info(file, track, &w, &h, &tx, &ty, &l);
	sprintf(buffer, "width=%d; height=%d; tx=%d; ty=%d; layer=%d; ", w, h, tx, ty, l);
	strcat(sdpLine, buffer);
	m_w = w;
	m_h = h;
	for (i=0; i<gf_isom_get_track_count(file); i++) {
		switch (gf_isom_get_media_type(file, i+1)) {
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_VISUAL:
			gf_isom_get_track_layout_info(file, i+1, &w, &h, &tx, &ty, &l);
			if (w>m_w) m_w = w;
			if (h>m_h) m_h = h;
			break;
		default:
			break;
		}
	}
	sprintf(buffer, "max-w=%d; max-h=%d", m_w, m_h);
	strcat(sdpLine, buffer);

	strcat(sdpLine, "; tx3g=");
	for (i=0; i<gf_isom_get_sample_description_count(file, track); i++) {
		char *tx3g;
		u32 tx3g_len, len;
		gf_isom_text_get_encoded_tx3g(file, track, i+1, GF_RTP_TX3G_SIDX_OFFSET, &tx3g, &tx3g_len);
		len = gf_base64_encode(tx3g, tx3g_len, buffer, 2000);
		gf_free(tx3g);
		buffer[len] = 0;
		if (i) strcat(sdpLine, ", ");
		strcat(sdpLine, buffer);
	}
}
Beispiel #3
0
GF_EXPORT
Bool gf_hinter_can_embbed_data(char *data, u32 data_size, u32 streamType)
{
	char data64[5000];
	u32 size64;

	size64 = gf_base64_encode(data, data_size, data64, 5000);
	if (!size64) return 0;
	switch (streamType) {
	case GF_STREAM_OD:
		size64 += strlen("data:application/mpeg4-od-au;base64,");
		break;
	case GF_STREAM_SCENE:
		size64 += strlen("data:application/mpeg4-bifs-au;base64,");
		break;
	default:
		/*NOT NORMATIVE*/
		size64 += strlen("data:application/mpeg4-es-au;base64,");
		break;
	}
	if (size64>=255) return 0;
	return 1;
}
Beispiel #4
0
GF_EXPORT
char *gf_seng_get_base64_iod(GF_SceneEngine *seng)
{
	u32 size, size64;
    char *buffer, *buf64;
	u32 i=0;
	GF_StreamContext*sc = NULL;

	if (!seng->ctx->root_od) return NULL;

	while ((sc = (GF_StreamContext*)gf_list_enum(seng->ctx->streams, &i))) {
		if ((sc->streamType == GF_STREAM_SCENE) && (sc->objectType != GPAC_OTI_SCENE_DIMS))
			break;
	}
	if (!sc) return NULL;

    size = 0;
    gf_odf_desc_write((GF_Descriptor *) seng->ctx->root_od, &buffer, &size);
    buf64 = gf_malloc(size*2);
    size64 = gf_base64_encode( buffer, size, buf64, size*2);
    buf64[size64] = 0;
    gf_free(buffer);
	return buf64;
}
Beispiel #5
0
GF_EXPORT
GF_Err gf_rtp_streamer_append_sdp_extended(GF_RTPStreamer *rtp, u16 ESID, char *dsi, u32 dsi_len, GF_ISOFile *isofile, u32 isotrack, char *KMS_URI, u32 width, u32 height, char **out_sdp_buffer) 
{	
	u32 size;
	u16 port;
	char mediaName[30], payloadName[30];
	char sdp[20000], sdpLine[10000];

	if (!out_sdp_buffer) return GF_BAD_PARAM;

	gf_rtp_builder_get_payload_name(rtp->packetizer, payloadName, mediaName);
	gf_rtp_get_ports(rtp->channel, &port, NULL);

	sprintf(sdp, "m=%s %d RTP/%s %d\n", mediaName, port, rtp->packetizer->slMap.IV_length ? "SAVP" : "AVP", rtp->packetizer->PayloadType);
	sprintf(sdpLine, "a=rtpmap:%d %s/%d\n", rtp->packetizer->PayloadType, payloadName, rtp->packetizer->sl_config.timestampResolution);
	strcat(sdp, sdpLine);
    if (ESID && (rtp->packetizer->rtp_payt != GF_RTP_PAYT_3GPP_DIMS)) {
		sprintf(sdpLine, "a=mpeg4-esid:%d\n", ESID);
		strcat(sdp, sdpLine);		
	}

	if (width && height) {
		if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H263) {
			sprintf(sdpLine, "a=cliprect:0,0,%d,%d\n", height, width);
			strcat(sdp, sdpLine);
		}
		/*extensions for some mobile phones*/
		sprintf(sdpLine, "a=framesize:%d %d-%d\n", rtp->packetizer->PayloadType, width, height);
		strcat(sdp, sdpLine);
	}
		
	strcpy(sdpLine, "");

	/*AMR*/
	if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_AMR_WB)) {
		sprintf(sdpLine, "a=fmtp:%d octet-align=1\n", rtp->packetizer->PayloadType);
	}
	/*Text*/
	else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) {
		gf_media_format_ttxt_sdp(rtp->packetizer, payloadName, sdpLine, isofile, isotrack);
		strcat(sdpLine, "\n");
	}
	/*EVRC/SMV in non header-free mode*/
	else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (rtp->packetizer->auh_size>1)) {
		sprintf(sdpLine, "a=fmtp:%d maxptime=%d\n", rtp->packetizer->PayloadType, rtp->packetizer->auh_size*20);
	}
	/*H264/AVC*/
	else if ((rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_AVC) || (rtp->packetizer->rtp_payt == GF_RTP_PAYT_H264_SVC)) {
		GF_AVCConfig *avcc = dsi ? gf_odf_avc_cfg_read(dsi, dsi_len) : NULL;

		if (avcc) {
			sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", rtp->packetizer->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
			if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) {
				u32 i, count, b64s;
				char b64[200];
				strcat(sdpLine, "; sprop-parameter-sets=");
				count = gf_list_count(avcc->sequenceParameterSets);
				for (i=0; i<count; i++) {
					GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->sequenceParameterSets, i);
					b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
					b64[b64s]=0;
					strcat(sdpLine, b64);
					if (i+1<count) strcat(sdpLine, ",");
				}
				if (i) strcat(sdpLine, ",");
				count = gf_list_count(avcc->pictureParameterSets);
				for (i=0; i<count; i++) {
					GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->pictureParameterSets, i);
					b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
					b64[b64s]=0;
					strcat(sdpLine, b64);
					if (i+1<count) strcat(sdpLine, ",");
				}
			}
			gf_odf_avc_cfg_del(avcc);
			strcat(sdpLine, "\n");
		}
	}
	else if (rtp->packetizer->rtp_payt == GF_RTP_PAYT_HEVC) {
#ifndef GPAC_DISABLE_HEVC
		GF_HEVCConfig *hevcc = dsi ? gf_odf_hevc_cfg_read(dsi, dsi_len, 0) : NULL;
		if (hevcc) {
			u32 count, i, j, b64s;
			char b64[200];
			sprintf(sdpLine, "a=fmtp:%d", rtp->packetizer->PayloadType);
			count = gf_list_count(hevcc->param_array);
			for (i = 0; i < count; i++) {
				GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(hevcc->param_array, i);
				if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
					strcat(sdpLine, "; sprop-sps=");						
				} else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
					strcat(sdpLine, "; sprop-pps=");
				} else if (ar->type==GF_HEVC_NALU_VID_PARAM) {
					strcat(sdpLine, "; sprop-vps=");
				}
				for (j = 0; j < gf_list_count(ar->nalus); j++) {
					GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j);
					b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
					b64[b64s]=0;
					if (j) strcat(sdpLine, ", ");
					strcat(sdpLine, b64);
				}
			}
			gf_odf_hevc_cfg_del(hevcc);
			strcat(sdpLine, "\n");
		}
#endif
	}
	/*MPEG-4 decoder config*/
	else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_MPEG4) {
		gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, sdpLine, dsi, dsi_len);
		strcat(sdpLine, "\n");

		if (rtp->packetizer->slMap.IV_length && KMS_URI) {
			if (!strnicmp(KMS_URI, "(key)", 5) || !strnicmp(KMS_URI, "(ipmp)", 6) || !strnicmp(KMS_URI, "(uri)", 5)) {
				strcat(sdpLine, "; ISMACrypKey=");
			} else {
				strcat(sdpLine, "; ISMACrypKey=(uri)");
			}
			strcat(sdpLine, KMS_URI);
			strcat(sdpLine, "\n");
		}
	}
    /*DIMS decoder config*/
    else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) {
        sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", rtp->packetizer->PayloadType, 10);
        if (rtp->packetizer->flags & GP_RTP_DIMS_COMPRESSED) {
            strcat(sdpLine, ";content-coding=deflate");
        }
		strcat(sdpLine, "\n");
    }
	/*MPEG-4 Audio LATM*/
	else if (rtp->packetizer->rtp_payt==GF_RTP_PAYT_LATM) { 
		GF_BitStream *bs; 
		char *config_bytes; 
		u32 config_size; 

		/* form config string */ 
		bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE); 
		gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */ 
		gf_bs_write_int(bs, 1, 1); /* all streams same time */ 
		gf_bs_write_int(bs, 0, 6); /* numSubFrames */ 
		gf_bs_write_int(bs, 0, 4); /* numPrograms */ 
		gf_bs_write_int(bs, 0, 3); /* numLayer */ 

		/* audio-specific config  - PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/
		if (dsi) gf_bs_write_data(bs, dsi, MIN(dsi_len, 2) ); 

		/* other data */ 
		gf_bs_write_int(bs, 0, 3); /* frameLengthType */ 
		gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */ 
		gf_bs_write_int(bs, 0, 1); /* otherDataPresent */ 
		gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */ 
		gf_bs_get_content(bs, &config_bytes, &config_size); 
		gf_bs_del(bs); 

		gf_rtp_builder_format_sdp(rtp->packetizer, payloadName, sdpLine, config_bytes, config_size); 
		gf_free(config_bytes); 
		strcat(sdpLine, "\n");
	}

	strcat(sdp, sdpLine);

	size = (u32) strlen(sdp) + (*out_sdp_buffer ? (u32) strlen(*out_sdp_buffer) : 0) + 1;
	if ( !*out_sdp_buffer) {
		*out_sdp_buffer = gf_malloc(sizeof(char)*size);
		if (! *out_sdp_buffer) return GF_OUT_OF_MEM;
		strcpy(*out_sdp_buffer, sdp);
	} else {
		*out_sdp_buffer = gf_realloc(*out_sdp_buffer, sizeof(char)*size);
		if (! *out_sdp_buffer) return GF_OUT_OF_MEM;
		strcat(*out_sdp_buffer, sdp);
	}
	return GF_OK;
} 
Beispiel #6
0
int sdp_generator(PNC_CallbackData *data, char *ip_dest, char *sdp_fmt)
{
	GF_SceneEngine *codec;
	GF_ESD *esd = NULL;
	u32 size,size64;
	char *buffer;
	char buf64[5000];
	FILE *fp;
	int ret;
	char temp[5000];
	u16 port;
	u32 socket_type;
		
	gf_sk_get_local_info(data->chan->rtp, &port, &socket_type);

	fp = fopen("broadcaster.sdp", "w+");
	if(fp == NULL) {
		fprintf(stderr, "Cannot open SDP file broadcaster.sdp\n");
		exit(1);
	}

	ret = fwrite("v=0\n", 1, 4, fp);
	sprintf(temp, "o=GpacBroadcaster 3326096807 1117107880000 IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
	ret = fwrite(temp, 1, strlen(temp), fp);

	ret = fwrite("s=MPEG4Broadcaster\n", 1, 19, fp);
	
	sprintf(temp, "c=IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	ret = fwrite("t=0 0\n", 1, 6, fp);
	
	codec = (GF_SceneEngine *) data->codec;
	if (codec) {
		buffer = NULL;
		size = 0;
		gf_odf_desc_write((GF_Descriptor *) codec->ctx->root_od, &buffer, &size);
		esd = gf_list_get(codec->ctx->root_od->ESDescriptors, 0);
	
		size64 = gf_base64_encode((unsigned char *) buffer, size, (unsigned char *) buf64, 2000);
		buf64[size64] = 0;
		free(buffer);

		sprintf(temp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", buf64);
		ret = fwrite(temp, 1, strlen(temp), fp);
	}
	
	sprintf(temp, "m=application %d RTP/AVP 96\n", port);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	ret = fwrite("a=rtpmap:96 mpeg4-generic/1000\n", 1, 31, fp);

	if (esd) {
		sprintf(temp, "a=mpeg4-esid:%d\n", esd->ESID);
		ret = fwrite(temp, 1, strlen(temp), fp);
	}
	
	sprintf(temp, "%s\n", sdp_fmt);
	ret = fwrite(temp, 1, strlen(temp), fp);
	fflush(fp);
	fclose(fp);
	dprintf(DEBUG_sdp_generator, "SDP file generated in broadcaster.sdp\n");
	return GF_OK;
}
Beispiel #7
0
GF_EXPORT
GF_Err gf_hinter_finalize(GF_ISOFile *file, u32 IOD_Profile, u32 bandwidth)
{
	u32 i, sceneT, odT, descIndex, size, size64;
	GF_InitialObjectDescriptor *iod;
	GF_SLConfig slc;
	GF_ESD *esd;
	GF_ISOSample *samp;
	Bool remove_ocr;
	char *buffer;
	char buf64[5000], sdpLine[2300];


	gf_isom_sdp_clean(file);

	if (bandwidth) {
		sprintf(buf64, "b=AS:%d", bandwidth);
		gf_isom_sdp_add_line(file, buf64);
	}
	//xtended attribute for copyright
	sprintf(buf64, "a=x-copyright: %s", "MP4/3GP File hinted with GPAC " GPAC_FULL_VERSION " (C)2000-2005 - http://gpac.sourceforge.net");
	gf_isom_sdp_add_line(file, buf64);

	if (IOD_Profile == GF_SDP_IOD_NONE) return GF_OK;

	odT = sceneT = 0;
	for (i=0; i<gf_isom_get_track_count(file); i++) {
		if (!gf_isom_is_track_in_root_od(file, i+1)) continue;
		switch (gf_isom_get_media_type(file,i+1)) {
		case GF_ISOM_MEDIA_OD:
			odT = i+1;
			break;
		case GF_ISOM_MEDIA_SCENE:
			sceneT = i+1;
			break;
		}
	}
	remove_ocr = 0;
	if (IOD_Profile == GF_SDP_IOD_ISMA_STRICT) {
		IOD_Profile = GF_SDP_IOD_ISMA;
		remove_ocr = 1;
	}

	/*if we want ISMA like iods, we need at least BIFS */
	if ( (IOD_Profile == GF_SDP_IOD_ISMA) && !sceneT ) return GF_BAD_PARAM;

	/*do NOT change PLs, we assume they are correct*/
	iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file);
	if (!iod) return GF_NOT_SUPPORTED;

	/*rewrite an IOD with good SL config - embbed data if possible*/
	if (IOD_Profile == GF_SDP_IOD_ISMA) {
		Bool is_ok = 1;
		while (gf_list_count(iod->ESDescriptors)) {
			esd = (GF_ESD*)gf_list_get(iod->ESDescriptors, 0);
			gf_odf_desc_del((GF_Descriptor *) esd);
			gf_list_rem(iod->ESDescriptors, 0);
		}


		/*get OD esd, and embbed stream data if possible*/
		if (odT) {
			esd = gf_isom_get_esd(file, odT, 1);
			if (gf_isom_get_sample_count(file, odT)==1) {
				samp = gf_isom_get_sample(file, odT, 1, &descIndex);
				if (gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_OD)) {
					InitSL_NULL(&slc);
					slc.predefined = 0;
					slc.hasRandomAccessUnitsOnlyFlag = 1;
					slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, odT);	
					slc.OCRResolution = 1000;
					slc.startCTS = samp->DTS+samp->CTS_Offset;
					slc.startDTS = samp->DTS;
					//set the SL for future extraction
					gf_isom_set_extraction_slc(file, odT, 1, &slc);

					size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000);
					buf64[size64] = 0;
					sprintf(sdpLine, "data:application/mpeg4-od-au;base64,%s", buf64);

					esd->decoderConfig->avgBitrate = 0;
					esd->decoderConfig->bufferSizeDB = samp->dataLength;
					esd->decoderConfig->maxBitrate = 0;
					size64 = strlen(sdpLine)+1;
					esd->URLString = (char*)gf_malloc(sizeof(char) * size64);
					strcpy(esd->URLString, sdpLine);
				} else {
					GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp hinter] OD sample too large to be embedded in IOD - ISMA disabled\n"));
					is_ok = 0;
				}
				gf_isom_sample_del(&samp);
			}
			if (remove_ocr) esd->OCRESID = 0;
			else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
			
			//OK, add this to our IOD
			gf_list_add(iod->ESDescriptors, esd);
		}

		esd = gf_isom_get_esd(file, sceneT, 1);
		if (gf_isom_get_sample_count(file, sceneT)==1) {
			samp = gf_isom_get_sample(file, sceneT, 1, &descIndex);
			if (gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_SCENE)) {

				slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, sceneT);	
				slc.OCRResolution = 1000;
				slc.startCTS = samp->DTS+samp->CTS_Offset;
				slc.startDTS = samp->DTS;
				//set the SL for future extraction
				gf_isom_set_extraction_slc(file, sceneT, 1, &slc);
				//encode in Base64 the sample
				size64 = gf_base64_encode(samp->data, samp->dataLength, buf64, 2000);
				buf64[size64] = 0;
				sprintf(sdpLine, "data:application/mpeg4-bifs-au;base64,%s", buf64);

				esd->decoderConfig->avgBitrate = 0;
				esd->decoderConfig->bufferSizeDB = samp->dataLength;
				esd->decoderConfig->maxBitrate = 0;
				esd->URLString = (char*)gf_malloc(sizeof(char) * (strlen(sdpLine)+1));
				strcpy(esd->URLString, sdpLine);
			} else {
				GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Scene description sample too large to be embedded in IOD - ISMA disabled\n"));
				is_ok = 0;
			}
			gf_isom_sample_del(&samp);
		}
		if (remove_ocr) esd->OCRESID = 0;
		else if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;

		gf_list_add(iod->ESDescriptors, esd);

		if (is_ok) {
			u32 has_a, has_v, has_i_a, has_i_v;
			has_a = has_v = has_i_a = has_i_v = 0;
			for (i=0; i<gf_isom_get_track_count(file); i++) {
				esd = gf_isom_get_esd(file, i+1, 1);
				if (!esd) continue;
				if (esd->decoderConfig->streamType==GF_STREAM_VISUAL) {
					if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) has_i_v ++;
					else has_v++;
				} else if (esd->decoderConfig->streamType==GF_STREAM_AUDIO) {
					if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_AUDIO_AAC_MPEG4) has_i_a ++;
					else has_a++;
				}
				gf_odf_desc_del((GF_Descriptor *)esd);
			}
			/*only 1 MPEG-4 visual max and 1 MPEG-4 audio max for ISMA compliancy*/
			if (!has_v && !has_a && (has_i_v<=1) && (has_i_a<=1)) {
				sprintf(sdpLine, "a=isma-compliance:1,1.0,1");
				gf_isom_sdp_add_line(file, sdpLine);
			}
		}
	}

	//encode the IOD
	buffer = NULL;
	size = 0;
	gf_odf_desc_write((GF_Descriptor *) iod, &buffer, &size);
	gf_odf_desc_del((GF_Descriptor *)iod);

	//encode in Base64 the iod
	size64 = gf_base64_encode(buffer, size, buf64, 2000);
	buf64[size64] = 0;
	gf_free(buffer);

	sprintf(sdpLine, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"", buf64);
	gf_isom_sdp_add_line(file, sdpLine);

	return GF_OK;
}
Beispiel #8
0
GF_EXPORT
GF_Err gf_hinter_track_finalize(GF_RTPHinter *tkHint, Bool AddSystemInfo)
{
	u32 Width, Height;
	GF_ESD *esd;
	char sdpLine[20000];
	char mediaName[30], payloadName[30];

	Width = Height = 0;
	gf_isom_sdp_clean_track(tkHint->file, tkHint->TrackNum);
	if (gf_isom_get_media_type(tkHint->file, tkHint->TrackNum) == GF_ISOM_MEDIA_VISUAL)
		gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height);

	gf_rtp_builder_get_payload_name(tkHint->rtp_p, payloadName, mediaName);

	/*TODO- extract out of rtp_p for future live tools*/
	sprintf(sdpLine, "m=%s 0 RTP/%s %d", mediaName, tkHint->rtp_p->slMap.IV_length ? "SAVP" : "AVP", tkHint->rtp_p->PayloadType);
	gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	if (tkHint->bandwidth) {
		sprintf(sdpLine, "b=AS:%d", tkHint->bandwidth);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	if (tkHint->nb_chan) {
		sprintf(sdpLine, "a=rtpmap:%d %s/%d/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution, tkHint->nb_chan);
	} else {
		sprintf(sdpLine, "a=rtpmap:%d %s/%d", tkHint->rtp_p->PayloadType, payloadName, tkHint->rtp_p->sl_config.timestampResolution);
	}
	gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	/*control for MPEG-4*/
	if (AddSystemInfo) {
		sprintf(sdpLine, "a=mpeg4-esid:%d", gf_isom_get_track_id(tkHint->file, tkHint->TrackNum));
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*control for QTSS/DSS*/
	sprintf(sdpLine, "a=control:trackID=%d", gf_isom_get_track_id(tkHint->file, tkHint->HintTrack));
	gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);

	/*H263 extensions*/
	if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H263) {
		sprintf(sdpLine, "a=cliprect:0,0,%d,%d", Height, Width);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*AMR*/
	else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR) || (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_AMR_WB)) {
		sprintf(sdpLine, "a=fmtp:%d octet-align=1", tkHint->rtp_p->PayloadType);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*Text*/
	else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_3GPP_TEXT) {
		gf_media_format_ttxt_sdp(tkHint->rtp_p, payloadName, sdpLine, tkHint->file, tkHint->TrackNum);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*EVRC/SMV in non header-free mode*/
	else if ((tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_EVRC_SMV) && (tkHint->rtp_p->auh_size>1)) {
		sprintf(sdpLine, "a=fmtp:%d maxptime=%d", tkHint->rtp_p->PayloadType, tkHint->rtp_p->auh_size*20);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*H264/AVC*/
	else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H264_AVC) {
		GF_AVCConfig *avcc = gf_isom_avc_config_get(tkHint->file, tkHint->TrackNum, 1);
		sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
		if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) {
			u32 i, count, b64s;
			char b64[200];
			strcat(sdpLine, "; sprop-parameter-sets=");
			count = gf_list_count(avcc->sequenceParameterSets);
			for (i=0; i<count; i++) {
				GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->sequenceParameterSets, i);
				b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
				b64[b64s]=0;
				strcat(sdpLine, b64);
				if (i+1<count) strcat(sdpLine, ",");
			}
			if (i) strcat(sdpLine, ",");
			count = gf_list_count(avcc->pictureParameterSets);
			for (i=0; i<count; i++) {
				GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(avcc->pictureParameterSets, i);
				b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
				b64[b64s]=0;
				strcat(sdpLine, b64);
				if (i+1<count) strcat(sdpLine, ",");
			}
		}
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
		gf_odf_avc_cfg_del(avcc);
	}
	/*MPEG-4 decoder config*/
	else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_MPEG4) {
		esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1);

		if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
			gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
		} else {
			gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, NULL, 0);
		}
		if (esd) gf_odf_desc_del((GF_Descriptor *)esd);

		if (tkHint->rtp_p->slMap.IV_length) {
			const char *kms;
			gf_isom_get_ismacryp_info(tkHint->file, tkHint->TrackNum, 1, NULL, NULL, NULL, NULL, &kms, NULL, NULL, NULL);
			if (!strnicmp(kms, "(key)", 5) || !strnicmp(kms, "(ipmp)", 6) || !strnicmp(kms, "(uri)", 5)) {
				strcat(sdpLine, "; ISMACrypKey=");
			} else {
				strcat(sdpLine, "; ISMACrypKey=(uri)");
			}
			strcat(sdpLine, kms);
		}

		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*MPEG-4 Audio LATM*/
	else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_LATM) { 
		GF_BitStream *bs; 
		char *config_bytes; 
		u32 config_size; 
 
		/* form config string */ 
		bs = gf_bs_new(NULL, 32, GF_BITSTREAM_WRITE); 
		gf_bs_write_int(bs, 0, 1); /* AudioMuxVersion */ 
		gf_bs_write_int(bs, 1, 1); /* all streams same time */ 
		gf_bs_write_int(bs, 0, 6); /* numSubFrames */ 
		gf_bs_write_int(bs, 0, 4); /* numPrograms */ 
		gf_bs_write_int(bs, 0, 3); /* numLayer */ 
 
		/* audio-specific config */ 
		esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1); 
		if (esd && esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo) { 
			/*PacketVideo patch: don't signal SBR and PS stuff, not allowed in LATM with audioMuxVersion=0*/
			gf_bs_write_data(bs, esd->decoderConfig->decoderSpecificInfo->data, MIN(esd->decoderConfig->decoderSpecificInfo->dataLength, 2) ); 
		} 
		if (esd) gf_odf_desc_del((GF_Descriptor *)esd); 
 
		/* other data */ 
		gf_bs_write_int(bs, 0, 3); /* frameLengthType */ 
		gf_bs_write_int(bs, 0xff, 8); /* latmBufferFullness */ 
		gf_bs_write_int(bs, 0, 1); /* otherDataPresent */ 
		gf_bs_write_int(bs, 0, 1); /* crcCheckPresent */ 
		gf_bs_get_content(bs, &config_bytes, &config_size); 
		gf_bs_del(bs); 
 
		gf_rtp_builder_format_sdp(tkHint->rtp_p, payloadName, sdpLine, config_bytes, config_size); 
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine); 
		gf_free(config_bytes); 
	}
	/*3GPP DIMS*/
	else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_3GPP_DIMS) { 
		GF_DIMSDescription dims;
		char fmt[200];
		gf_isom_get_visual_info(tkHint->file, tkHint->TrackNum, 1, &Width, &Height);

		gf_isom_get_dims_description(tkHint->file, tkHint->TrackNum, 1, &dims);
		sprintf(sdpLine, "a=fmtp:%d Version-profile=%d", tkHint->rtp_p->PayloadType, dims.profile);
		if (! dims.fullRequestHost) {
			strcat(sdpLine, ";useFullRequestHost=0");
			sprintf(fmt, ";pathComponents=%d", dims.pathComponents);
			strcat(sdpLine, fmt);
		}
		if (!dims.streamType) strcat(sdpLine, ";stream-type=secondary");
		if (dims.containsRedundant == 1) strcat(sdpLine, ";contains-redundant=main");
		else if (dims.containsRedundant == 2) strcat(sdpLine, ";contains-redundant=redundant");

		if (dims.textEncoding && strlen(dims.textEncoding)) {
			strcat(sdpLine, ";text-encoding=");
			strcat(sdpLine, dims.textEncoding);
		}
		if (dims.contentEncoding && strlen(dims.contentEncoding)) {
			strcat(sdpLine, ";content-coding=");
			strcat(sdpLine, dims.contentEncoding);
		}
		if (dims.content_script_types && strlen(dims.content_script_types) ) {
			strcat(sdpLine, ";content-script-types=");
			strcat(sdpLine, dims.contentEncoding);
		}
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	/*extensions for some mobile phones*/
	if (Width && Height) {
		sprintf(sdpLine, "a=framesize:%d %d-%d", tkHint->rtp_p->PayloadType, Width, Height);
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}

	esd = gf_isom_get_esd(tkHint->file, tkHint->TrackNum, 1);
	if (esd && esd->decoderConfig && (esd->decoderConfig->rvc_config || esd->decoderConfig->predefined_rvc_config)) {
		if (esd->decoderConfig->predefined_rvc_config) {
			sprintf(sdpLine, "a=rvc-config-predef:%d", esd->decoderConfig->predefined_rvc_config);
		} else {
			/*temporary ...*/
			if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) {
				sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_avc.xml");
			} else {
				sprintf(sdpLine, "a=rvc-config:%s", "http://download.tsi.telecom-paristech.fr/gpac/RVC/rvc_config_sp.xml");
			}
		}
		gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
	}
	if (esd) gf_odf_desc_del((GF_Descriptor *)esd);

	gf_isom_set_track_enabled(tkHint->file, tkHint->HintTrack, 1);
	return GF_OK;
}
Beispiel #9
0
int sdp_generator(PNC_CallbackData * data, char *ip_dest, char *sdp_fmt)
{
	GF_BifsEngine *codec;
	GF_ESD *esd;
	u32 size,size64;
	char *buffer;
	char buf64[5000];
	FILE *fp;
	int ret;
	char temp[5000];
	u16 port;
	u32 socket_type;
		
	// fonctions necessaires pour recuperer les informations necessaires a la construction du fichier
	gf_sk_get_local_info(data->chan->rtp, &port, &socket_type);

	// fprintf(stdout, "%s --------- %d\n", ip_adresse, port);
	fp = fopen("broadcaster.sdp", "w+");
	if(fp == NULL)
	{
		fprintf(stdout, "[broadcaster] : erreur, probleme a ouvrir file temp pour scene initiale\n");
		exit(1);
	}
	// ecriture du fichier SDP
	ret = fwrite("v=0\n", 1, 4, fp);
	
	sprintf(temp, "o=GpacBroadcaster 3326096807 1117107880000 IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	ret = fwrite("s=MPEG4Broadcaster\n", 1, 19, fp);
	
	sprintf(temp, "c=IN IP%d %s\n", gf_net_is_ipv6(ip_dest) ? 6 : 4, ip_dest);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	ret = fwrite("t=0 0\n", 1, 6, fp);
	
	// GF_BIFSEngine
	codec = (GF_BifsEngine *) data->codec;
	buffer = NULL;
	size = 0;
	gf_odf_desc_write((GF_Descriptor *) codec->ctx->root_od, &buffer, &size);
	esd = gf_list_get(codec->ctx->root_od->ESDescriptors, 0);
	
	//encode in Base64 the iod
	size64 = gf_base64_encode((unsigned char *) buffer, size, (unsigned char *) buf64, 2000);
	// size64 = gf_base64_encode(buffer, size, buf64, 2000);
	buf64[size64] = 0;
	free(buffer);

	// fprintf(stdout, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", buf64);
	sprintf(temp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", buf64);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	sprintf(temp, "m=application %d RTP/AVP 96\n", port);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	ret = fwrite("a=rtpmap:96 mpeg4-generic/1000\n", 1, 31, fp);

	sprintf(temp, "a=mpeg4-esid:%d\n", esd->ESID);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	// fprintf(stdout, "%s\n", sdp_fmt);
	sprintf(temp, "%s\n", sdp_fmt);
	ret = fwrite(temp, 1, strlen(temp), fp);
	
	fclose(fp);
	fprintf(stdout, "[sdp generator] : fichier SDP generater in broadcaster.sdp\n");
	return GF_OK;
}
Beispiel #10
0
int main(int argc, char **argv)
{
	/********************/
	/*   declarations   */
	/********************/
	char *input, *output, tmpstr[GF_MAX_PATH];
	GF_ISOFile *isom_file_in;
	GF_MediaImporter import;
	AdobeHDSCtx ctx;
	GF_Err e;
	u32 i;

	/*****************/
	/*   gpac init   */
	/*****************/
	gf_sys_init(GF_MemTrackerNone);
	gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);

	/***********************/
	/*   initialisations   */
	/***********************/
	input = NULL;
	output = NULL;
	isom_file_in = NULL;
	memset(&import, 0, sizeof(GF_MediaImporter));
	e = GF_OK;
	memset(&ctx, 0, sizeof(ctx));

	ctx.curr_time = 0;
	ctx.segnum = 1;

	/*********************************************/
	/*   parse arguments and build HDS context   */
	/*********************************************/
	if (GF_OK != parse_args(argc, argv, &input, &output, &ctx.curr_time, &ctx.segnum)) {
		usage(argv[0]);
		goto exit;
	}

	ctx.multirate_manifest = adobe_alloc_multirate_manifest(output);

#if 0 /*'moov' conversion tests*/
	{
		char metamoov64[GF_MAX_PATH];
		u32 metamoov64_len;
		unsigned char metamoov[GF_MAX_PATH];
		u32 metamoov_len=GF_MAX_PATH;
		FILE *f = gf_fopen("metamoov64"/*input*/, "rt");
		gf_fseek(f, 0, SEEK_END);
		metamoov64_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(metamoov64, metamoov64_len, 1, f);
		metamoov_len = gf_base64_decode(metamoov64, metamoov64_len, metamoov, metamoov_len);
		gf_fclose(f);
		f = gf_fopen("metamoov", "wb");
		fwrite(metamoov, metamoov_len, 1, f);
		gf_fclose(f);
		return 0;
	}
#endif

#if 0 /*'abst'conversion tests*/
	{
		char bootstrap64[GF_MAX_PATH];
		u32 bootstrap64_len;
		unsigned char bootstrap[GF_MAX_PATH];
		u32 bootstrap_len=GF_MAX_PATH;
		GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox *)abst_New();
		GF_BitStream *bs;
#if 1 //64
		FILE *f = gf_fopen("bootstrap64"/*input*/, "rt");
		gf_fseek(f, 0, SEEK_END);
		bootstrap64_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(bootstrap64, bootstrap64_len, 1, f);
		bootstrap_len = gf_base64_decode(bootstrap64, bootstrap64_len, bootstrap, bootstrap_len);
#else //binary bootstrap
		FILE *f = gf_fopen("bootstrap.bin"/*input*/, "rb");
		gf_fseek(f, 0, SEEK_END);
		bootstrap_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(bootstrap, bootstrap_len, 1, f);
#endif
		bs = gf_bs_new(bootstrap+8, bootstrap_len-8, GF_BITSTREAM_READ);
		abst->size = bootstrap[2]*256+bootstrap[3];
		assert(abst->size<GF_MAX_PATH);
		abst_Read((GF_Box*)abst, bs);
		gf_bs_del(bs);
		//then rewrite with just one 'afrt'
		memset(bootstrap, 0, bootstrap_len);
		bs = gf_bs_new(bootstrap, bootstrap_len, GF_BITSTREAM_WRITE);
		abst_Write((GF_Box*)abst, bs);
		bootstrap_len = (u32)gf_bs_get_position(bs);
		gf_bs_del(bs);
		gf_fclose(f);
		f = gf_fopen("bootstrap", "wt");
		bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_len, bootstrap64, GF_MAX_PATH);
		fwrite(bootstrap64, bootstrap64_len, 1, f);
		fprintf(f, "\n\n");
		abst_dump((GF_Box*)abst, f);
		gf_fclose(f);
		abst_del((GF_Box*)abst);
		return 0;
	}
#endif

	/*****************/
	/*   main loop   */
	/*****************/
	import.trackID = 0;
	import.in_name = input;
	import.flags = GF_IMPORT_PROBE_ONLY;

	//create output or open when recovering from a saved state
	sprintf(tmpstr, "%s_import.mp4", input);
	isom_file_in = gf_isom_open(tmpstr, GF_ISOM_WRITE_EDIT, NULL);
	if (!isom_file_in) {
		fprintf(stderr, "Error opening output file %s: %s\n", tmpstr, gf_error_to_string(e));
		assert(0);
		goto exit;
	}
	import.dest = isom_file_in;

	//probe input
	e = gf_media_import(&import);
	if (e) {
		fprintf(stderr, "Error while importing input file %s: %s\n", input, gf_error_to_string(e));
		assert(0);
		goto exit;
	}

	//import input data
	import.flags = 0;
	for (i=0; i<import.nb_tracks; i++) {
		import.trackID = import.tk_info[i].track_num;
		e = gf_media_import(&import);
		if (e) {
			fprintf(stderr, "Error while importing track number %u, input file %s: %s\n", import.trackID, input, gf_error_to_string(e));
			assert(0);
			goto exit;
		}
	}

	//Adobe specific stuff
	e = adobize_segment(isom_file_in, &ctx);
	if (e) {
		fprintf(stderr, "Couldn't turn the ISOM fragmented file into an Adobe f4v segment: %s\n", gf_error_to_string(e));
		assert(0);
		goto exit;
	}

	//interleave data and remove imported file
	//FIXME: set multiple fragments:
	sprintf(tmpstr, "%s_HD_100_Seg%u-Frag1", output, ctx.segnum); //FIXME: "HD", "100" and fragnum: pass as arg
	//e = gf_media_fragment_file(isom_file_in, tmpstr, 1.0);
	e = gf_media_fragment_file(isom_file_in, tmpstr, 1.0+gf_isom_get_duration(isom_file_in)/gf_isom_get_timescale(isom_file_in));
	if (e) {
		fprintf(stderr, "Error while fragmenting file to output %s: %s\n", output, gf_error_to_string(e));
		assert(0);
		goto exit;
	}
	gf_isom_delete(isom_file_in);
	isom_file_in = NULL;

	e = adobe_gen_multirate_manifest(ctx.multirate_manifest, ctx.bootstrap, ctx.bootstrap_size);
	if (e) {
		fprintf(stderr, "Couldn't generate Adobe f4m manifest: %s\n", gf_error_to_string(e));
		assert(0);
		goto exit;
	}

exit:
	//delete intermediate mp4 file
	if (isom_file_in)
		gf_isom_delete(isom_file_in);

	if (ctx.multirate_manifest)
		adobe_free_multirate_manifest(ctx.multirate_manifest);

	if (ctx.bootstrap) {
		gf_free(ctx.bootstrap);
		//ctx.bootstrap = NULL;
		//ctx.bootstrap_size = 0;
	}

	gf_sys_close();

	return !e ? 0 : 1;
}
Beispiel #11
0
void http_do_requests(GF_DownloadSession *sess)
{
	GF_Err e;
	Bool is_ice;
	GF_NETIO_Parameter par;
	char sHTTP[GF_DOWNLOAD_BUFFER_SIZE];
	char buf[1024];
	char comp[400];
	char *new_location;
	char *hdr, *hdr_val;
	u32 bytesRead, res;
	s32 LinePos, Pos;
	u32 rsp_code, ContentLength, first_byte, last_byte, total_size, range, no_range;
	s32 BodyStart;

	/*sent HTTP request*/
	if (sess->status==GF_NETIO_CONNECTED) {
		char range_buf[1024];
		char pass_buf[1024];
		const char *user_agent;
		u32 size;
		Bool has_accept, has_connection, has_range, has_agent;

		/*setup authentification*/
		strcpy(pass_buf, "");
		if (sess->user) {
			if (!sess->passwd) {
				char szUSR[50], szPASS[50];
				strcpy(szUSR, sess->user);
				strcpy(szPASS, "");
				/*failed getting pass*/
				if (!sess->dm->GetUserPassword || !sess->dm->GetUserPassword(sess->dm->usr_cbk, sess->server_name, szUSR, szPASS)) {
					sess->status = GF_NETIO_STATE_ERROR;
					return;
				}
				sess->passwd = strdup(szPASS);
			}
			sprintf(pass_buf, "%s:%s", sess->user, sess->passwd);
			size = gf_base64_encode(pass_buf, strlen(pass_buf), range_buf, 1024);
			range_buf[size] = 0;
			sprintf(pass_buf, "Authorization: Basic %s", range_buf);
		}


		/*MIX2005 KMS project*/
#if 0
		if (strstr(sess->remote_path, "getKey.php?")) {
			char *sLogin, *sPass;
			sLogin = gf_cfg_get_key(sess->dm->cfg, "General", "KMS_User");
			sPass = gf_cfg_get_key(sess->dm->cfg, "General", "KMS_Password");
			if (!sLogin) sLogin = "******";
			if (!sPass) sPass = "******";
			sprintf(https_get_buffer, "%s&login=%s&password=%s", sess->remote_path, sLogin, sPass);
		}
#endif	

		user_agent = gf_cfg_get_key(sess->dm->cfg, "Downloader", "UserAgent");
		if (!user_agent) user_agent = GF_DOWNLOAD_AGENT_NAME;

		par.error = 0;
		par.msg_type = GF_NETIO_GET_METHOD;
		par.name = NULL;
		gf_dm_sess_user_io(sess, &par);

		if (par.name) {
			if (!strcmp(par.name, "GET")) sess->http_read_type = 0;
			else if (!strcmp(par.name, "HEAD")) sess->http_read_type = 1;
			else sess->http_read_type = 2;
		} else {
			sess->http_read_type = 0;
		}

		sprintf(sHTTP, "%s %s HTTP/1.0\r\nHost: %s\r\n" ,
			par.name ? par.name : "GET", sess->remote_path, sess->server_name);

		/*signal we support title streaming*/
		if (!strcmp(sess->remote_path, "/")) strcat(sHTTP, "icy-metadata:1\r\n");

		/*get all headers*/
		has_agent = has_accept = has_connection = has_range = 0;
		while (1) {
			par.msg_type = GF_NETIO_GET_HEADER;
			par.name = NULL;
			par.value = NULL;
			gf_dm_sess_user_io(sess, &par);
			if (!par.name) break;
			strcat(sHTTP, par.name);
			strcat(sHTTP, ": ");
			strcat(sHTTP, par.value);
			strcat(sHTTP, "\r\n");
			if (!strcmp(par.name, "Accept")) has_accept = 1;
			else if (!strcmp(par.name, "Connection")) has_connection = 1;
			else if (!strcmp(par.name, "Range")) has_range = 1;
			else if (!strcmp(par.name, "User-Agent")) has_agent = 1;
		}
		if (!has_agent) {
			strcat(sHTTP, "User-Agent: ");
			strcat(sHTTP, user_agent);
			strcat(sHTTP, "\r\n");
		}
		if (!has_accept) strcat(sHTTP, "Accept: */*\r\n");
		if (!has_connection) strcat(sHTTP, "Connection: Keep-Alive\r\n");
		if (!has_range && sess->cache_start_size) {
			sprintf(range_buf, "Range: bytes=%d-\r\n", sess->cache_start_size);
			strcat(sHTTP, range_buf);
		}
		if (strlen(pass_buf)) {
			strcat(sHTTP, pass_buf);
			strcat(sHTTP, "\r\n");
		}
		if (sess->flags & GF_DOWNLOAD_IS_ICY) strcat(sHTTP, "Icy-Metadata: 1\r\n");
		
		par.msg_type = GF_NETIO_GET_CONTENT;
		par.data = NULL;
		par.size = 0;
		gf_dm_sess_user_io(sess, &par);
		if (par.data && par.size) {
			sprintf(range_buf, "Content-Length: %d\r\n", par.size);
			strcat(sHTTP, range_buf);
		}
		strcat(sHTTP, "\r\n");

#ifdef GPAC_HAS_SSL
		if (sess->ssl) {
			e = GF_IP_NETWORK_FAILURE;
			if (!SSL_write(sess->ssl, sHTTP, strlen(sHTTP))) e = GF_OK;
		} else 
#endif
			e = gf_sk_send(sess->sock, sHTTP, strlen(sHTTP));

		GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s\n\n", sHTTP));
		if (e) {
			sess->status = GF_NETIO_STATE_ERROR;
			sess->last_error = e;
			gf_dm_sess_notify_state(sess, GF_NETIO_STATE_ERROR, e);
			return;
		}

		if (par.size && par.data) {
			u32 done = 0;
			while (done<par.size) {
			
#ifdef GPAC_HAS_SSL
				if (sess->ssl) {
					e = GF_IP_NETWORK_FAILURE;
					if (!SSL_write(sess->ssl, par.data+done, par.size-done)) e = GF_OK;
				} else 
#endif
					e = gf_sk_send(sess->sock, par.data+done, par.size-done);

				if (e) {
					sess->status = GF_NETIO_STATE_ERROR;
					sess->last_error = e;
					gf_dm_sess_notify_state(sess, GF_NETIO_STATE_ERROR, e);
					return;
				}
			}
		}
		sess->status = GF_NETIO_WAIT_FOR_REPLY;
		gf_dm_sess_notify_state(sess, GF_NETIO_WAIT_FOR_REPLY, GF_OK);
		return;
	}

	/*process HTTP request*/
	if (sess->status == GF_NETIO_WAIT_FOR_REPLY) {
		bytesRead = res = 0;
		new_location = NULL;
		while (1) {
			e = gf_dm_read_data(sess, sHTTP + bytesRead, GF_DOWNLOAD_BUFFER_SIZE - bytesRead, &res);
	
			switch (e) {
			case GF_IP_NETWORK_EMPTY:
				if (!bytesRead) return;
				continue;
			/*socket has been closed while configuring, retry (not sure if the server got the GET)*/
			case GF_IP_CONNECTION_CLOSED:
				gf_dm_disconnect(sess);
				if (sess->num_retry)
					sess->status = GF_NETIO_SETUP;
				else {
					sess->last_error = e;
					sess->status = GF_NETIO_STATE_ERROR;
				}
				return;
			case GF_OK:
				if (!res) return;
				break;
			default:
				goto exit;
			}
			bytesRead += res;

			/*locate body start*/
			BodyStart = gf_token_find(sHTTP, 0, bytesRead, "\r\n\r\n");
			if (BodyStart <= 0) {
				BodyStart=0;
				continue;
			}
			BodyStart += 4;
			break;
		}
		if (bytesRead < 0) {
			e = GF_REMOTE_SERVICE_ERROR;
			goto exit;
		}
		if (!BodyStart) 
			BodyStart = bytesRead;

		sHTTP[BodyStart-1] = 0;
		GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s\n\n", sHTTP));

		LinePos = gf_token_get_line(sHTTP, 0, bytesRead, buf, 1024);
		Pos = gf_token_get(buf, 0, " \t\r\n", comp, 400);

		if (sess->mime_type) free(sess->mime_type);
		sess->mime_type = NULL;

		is_ice = 0;
		if (!strncmp("ICY", comp, 4)) {
			is_ice = 1;
			/*be prepared not to recieve any mime type from ShoutCast servers*/
			sess->mime_type = strdup("audio/mpeg");
		} else if ((strncmp("HTTP", comp, 4) != 0)) {
			e = GF_REMOTE_SERVICE_ERROR;
			goto exit;
		}
		Pos = gf_token_get(buf, Pos, " ", comp, 400);
		if (Pos <= 0) {
			e = GF_REMOTE_SERVICE_ERROR;
			goto exit;
		}
		rsp_code = (u32) atoi(comp);
		Pos = gf_token_get(buf, Pos, " \r\n", comp, 400);

		no_range = range = ContentLength = first_byte = last_byte = total_size = 0;
		//parse header
		while (1) {
			char *sep, *hdr_sep;
			if ( (u32) LinePos + 4 > BodyStart) break;
			LinePos = gf_token_get_line(sHTTP, LinePos , bytesRead, buf, 1024);
			if (LinePos < 0) break;

			hdr_sep = NULL;
			hdr_val = NULL;
			hdr = buf;
			sep = strchr(buf, ':');
			if (sep) {
				sep[0]=0;
				hdr_val = sep+1;
				while (hdr_val[0]==' ') hdr_val++;
				hdr_sep = strrchr(hdr_val, '\r');
				if (hdr_sep) hdr_sep[0] = 0;
			}

			par.error = 0;
			par.msg_type = GF_NETIO_PARSE_HEADER;
			par.name = hdr;
			par.value = hdr_val;
			gf_dm_sess_user_io(sess, &par);

			if (!stricmp(hdr, "Content-Length") ) ContentLength = (u32) atoi(hdr_val);
			else if (!stricmp(hdr, "Content-Type")) {			
				if (sess->mime_type) free(sess->mime_type);
				sess->mime_type = strdup(hdr_val);
				while (1) {
					u32 len = strlen(sess->mime_type);
					char c = len ? sess->mime_type[len-1] : 0;
					if ((c=='\r') || (c=='\n')) {
						sess->mime_type[len-1] = 0;
					} else {
						break;
					}
				}
				hdr = strchr(sess->mime_type, ';');
				if (hdr) hdr[0] = 0;
			}
			else if (!stricmp(hdr, "Content-Range")) {			
				range = 1;
				if (!strncmp(hdr_val, "bytes", 5)) {
					hdr_val += 5;
					if (hdr_val[0] == ':') hdr_val += 1;
					hdr_val += http_skip_space(hdr_val);
					if (hdr_val[0] == '*') {
						sscanf(hdr_val, "*/%d", &total_size);
					} else {
						sscanf(hdr_val, "%d-%d/%d", &first_byte, &last_byte, &total_size);
					}
				}
			}
			else if (!stricmp(hdr, "Accept-Ranges")) {
				if (strstr(hdr_val, "none")) no_range = 1;
			}
			else if (!stricmp(hdr, "Location")) 
				new_location = strdup(hdr_val);
			else if (!stricmp(hdr, "icy-metaint")) 
				sess->icy_metaint = atoi(hdr_val);
			else if (!stricmp(hdr, "ice") || !stricmp(hdr, "icy") ) 
				is_ice = 1;

			if (sep) sep[0]=':';
			if (hdr_sep) hdr_sep[0] = '\r';
		}
		if (no_range) first_byte = 0;

		if (sess->cache_start_size) {
			if (total_size && (sess->cache_start_size >= total_size) ) {
				rsp_code = 200;
				ContentLength = total_size;
			}
			if (ContentLength && (sess->cache_start_size == ContentLength) ) rsp_code = 200;
		}	

		par.msg_type = GF_NETIO_PARSE_REPLY;
		par.error = GF_OK;
		par.reply = rsp_code;
		par.value = comp;

		switch (rsp_code) {
		case 200:
		case 201:
		case 202:
		case 206:
			gf_dm_sess_user_io(sess, &par);
			e = GF_OK;
			break;
		/*redirection: extract the new location*/
		case 301:
		case 302:
			if (!new_location || !strlen(new_location) ) {
				gf_dm_sess_user_io(sess, &par);
				e = GF_URL_ERROR;
				goto exit;
			}
			while (
				(new_location[strlen(new_location)-1] == '\n') 
				|| (new_location[strlen(new_location)-1] == '\r')  )
				new_location[strlen(new_location)-1] = 0;

			/*reset and reconnect*/
			gf_dm_disconnect(sess);
			sess->status = GF_NETIO_SETUP;
			e = gf_dm_setup_from_url(sess, new_location);
			if (e) {
				sess->status = GF_NETIO_STATE_ERROR;
				sess->last_error = e;
				gf_dm_sess_notify_state(sess, sess->status, e);
				return;
			}
			return;
		case 404:
		case 416:
			/*try without cache (some servers screw up when content-length is specified)*/
			if (sess->cache_start_size) {
				gf_dm_disconnect(sess);
				sess->status = GF_NETIO_SETUP;
				return;
			} else if (is_ice && !(sess->flags & GF_DOWNLOAD_IS_ICY)) {
				gf_dm_disconnect(sess);
				sess->status = GF_NETIO_SETUP;
				sess->flags |= GF_DOWNLOAD_IS_ICY;
				return;
			}
			gf_dm_sess_user_io(sess, &par);
			e = GF_URL_ERROR;
			goto exit;
		case 503:
		default:
			gf_dm_sess_user_io(sess, &par);
			e = GF_REMOTE_SERVICE_ERROR;
			goto exit;
		}

		/*head*/
		if (sess->http_read_type==1) {
			gf_dm_disconnect(sess);
			gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK);
			sess->status = GF_NETIO_DISCONNECTED;
			sess->http_read_type = 0;
			return;
		}

		if (!ContentLength && sess->mime_type && strstr(sess->mime_type, "ogg")) is_ice = 1;

		/*some servers may reply without content length, but we MUST have it*/
//		if (!is_ice && !ContentLength) e = GF_REMOTE_SERVICE_ERROR;
		if (e) goto exit;

		/*force disabling cache (no content length)*/
		if (is_ice) {
			sess->flags |= GF_NETIO_SESSION_NOT_CACHED;
			if (sess->mime_type && !stricmp(sess->mime_type, "video/nsv")) {
				free(sess->mime_type);
				sess->mime_type = strdup("audio/aac");
			}
		}


		/*done*/
		if (sess->cache_start_size 
			&& ( (total_size && sess->cache_start_size >= total_size) || (sess->cache_start_size == ContentLength)) ) {
			sess->total_size = sess->bytes_done = sess->cache_start_size;
			/*disconnect*/
			gf_dm_disconnect(sess);
			BodyStart = bytesRead;
			gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK);
		}
		else if (sess->flags & GF_DOWNLOAD_IS_ICY) {
			sess->icy_bytes = 0;
			sess->status = GF_NETIO_DATA_EXCHANGE;
		}
		/*we don't expect anything*/
		else if (!ContentLength && sess->http_read_type) {
			gf_dm_disconnect(sess);
			gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK);
			sess->status = GF_NETIO_DISCONNECTED;
			sess->http_read_type = 0;
		}
		/*no range header, Accep-Ranges deny or dumb server : restart*/
		else if (!range || !first_byte || (first_byte != sess->cache_start_size) ) {
			sess->cache_start_size = sess->bytes_done = 0;
			sess->total_size = ContentLength;
			if (! (sess->flags & GF_NETIO_SESSION_NOT_CACHED) ) {
				sess->cache = fopen(sess->cache_name, "wb");
				if (!sess->cache) {
					e = GF_IO_ERR;
					goto exit;
				}
			}
			sess->status = GF_NETIO_DATA_EXCHANGE;
		}
		/*resume*/
		else {
			sess->total_size = ContentLength + sess->cache_start_size;
			if (! (sess->flags & GF_NETIO_SESSION_NOT_CACHED) ) {
				sess->cache = fopen(sess->cache_name, "ab");
				if (!sess->cache) {
					e = GF_IO_ERR;
					goto exit;
				}
			}
			sess->status = GF_NETIO_DATA_EXCHANGE;
			sess->bytes_done = sess->cache_start_size;
		}

		sess->window_start = sess->start_time = gf_sys_clock();
		sess->bytes_in_wnd = 0;


		//we may have existing data in this buffer ...
		if (!e && (BodyStart < (u32) bytesRead)) {
			gf_dm_data_recieved(sess, sHTTP + BodyStart, bytesRead - BodyStart);
			/*store data if no callbacks or cache*/
			if (sess->flags & GF_NETIO_SESSION_NOT_CACHED) {
				if (sess->init_data) free(sess->init_data);
				sess->init_data_size = bytesRead - BodyStart;
				sess->init_data = (char *) malloc(sizeof(char) * sess->init_data_size);
				memcpy(sess->init_data, sHTTP+BodyStart, sess->init_data_size);
			}
		}
exit:
		if (e) {
			gf_dm_disconnect(sess);
			sess->status = GF_NETIO_STATE_ERROR;
			sess->last_error = e;
			gf_dm_sess_notify_state(sess, sess->status, e);
		}
		return;
	}
	/*fetch data*/
	while (1) {
		u32 size;
#if 1
		if (sess->limit_data_rate && sess->bytes_per_sec) {
			if (sess->bytes_per_sec>sess->limit_data_rate) {
				/*update state*/
				u32 runtime = gf_sys_clock() - sess->window_start;
				sess->bytes_per_sec = (1000 * (sess->bytes_in_wnd)) / runtime;
				if (sess->bytes_per_sec > sess->limit_data_rate) return;
			}
		}
#endif
		e = gf_dm_read_data(sess, sHTTP, GF_DOWNLOAD_BUFFER_SIZE, &size);
		if (!size || e == GF_IP_NETWORK_EMPTY) {
		
			if (!sess->total_size && (gf_sys_clock() - sess->window_start > 1000)) {
				sess->total_size = sess->bytes_done;
				gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK);
			}
			return;
		}

		if (e) {
			gf_dm_disconnect(sess);
			sess->last_error = e;
			gf_dm_sess_notify_state(sess, sess->status, e);
			return;
		}
		gf_dm_data_recieved(sess, sHTTP, size);
		/*socket empty*/
		if (size < GF_DOWNLOAD_BUFFER_SIZE) return;
	}
}