Example #1
0
u32 gf_isom_fdm_get_data(GF_FileDataMap *ptr, char *buffer, u32 bufferLength, u64 fileOffset)
{
	u32 bytesRead;

	//can we seek till that point ???
	if (fileOffset > gf_bs_get_size(ptr->bs)) return 0;

	//ouch, we are not at the previous location, do a seek
	if (ptr->curPos != fileOffset) {
		if (gf_bs_seek(ptr->bs, fileOffset) != GF_OK) return 0;
		ptr->curPos = fileOffset;
	}
	//read our data.
	bytesRead = gf_bs_read_data(ptr->bs, buffer, bufferLength);
	//update our cache
	if (bytesRead == bufferLength) {
		ptr->curPos += bytesRead;
	} else {
		//rewind to original (if seek fails, return 0 cause this means:
		//1- no support for seek on the platform
		//2- corrupted file for the OS
		if (ptr->stream) fflush(ptr->stream);
		gf_bs_seek(ptr->bs, ptr->curPos);
	}
	ptr->last_acces_was_read = 1;
	return bytesRead;
}
Example #2
0
u32 gf_isom_fdm_get_data(GF_FileDataMap *ptr, char *buffer, u32 bufferLength, u64 fileOffset)
{
	u32 bytesRead;

	//can we seek till that point ???
	if (fileOffset > gf_bs_get_size(ptr->bs)) return 0;

	//ouch, we are not at the previous location, do a seek
	if (ptr->curPos != fileOffset) {
		if (gf_bs_seek(ptr->bs, fileOffset) != GF_OK) return 0;
		ptr->curPos = fileOffset;
	}

	//read our data.
	bytesRead = gf_bs_read_data(ptr->bs, buffer, bufferLength);
	//update our cache
	if (bytesRead == bufferLength) {
		ptr->curPos += bytesRead;
	} else {
		gf_bs_get_refreshed_size(ptr->bs);
		gf_bs_seek(ptr->bs, fileOffset);
		bytesRead = gf_bs_read_data(ptr->bs, buffer, bufferLength);
		//update our cache
		if (bytesRead == bufferLength) {
			ptr->curPos += bytesRead;
		} else {
			gf_bs_seek(ptr->bs, ptr->curPos);
			bytesRead = 0;
		}
	}
	ptr->last_acces_was_read = 1;
	return bytesRead;
}
Example #3
0
GF_Err FDM_AddData(GF_FileDataMap *ptr, char *data, u32 dataSize)
{
	u32 ret;
	u64 orig;
	if (ptr->mode == GF_ISOM_DATA_MAP_READ) return GF_BAD_PARAM;

	orig = gf_bs_get_size(ptr->bs);

	/*last access was read, seek to end of file*/
	if (ptr->last_acces_was_read) {
		gf_bs_seek(ptr->bs, orig);
		ptr->last_acces_was_read = 0;
	}
	//OK, write our stuff to the datamap...
	//we don't use bs here cause we want to know more about what has been written
	ret = gf_bs_write_data(ptr->bs, data, dataSize);
	if (ret != dataSize) {
		ptr->curPos = orig;
		gf_bs_seek(ptr->bs, orig);
		return GF_IO_ERR;
	}
	ptr->curPos = gf_bs_get_position(ptr->bs);
	//flush the stream !!
	if (ptr->stream) fflush(ptr->stream);
	return GF_OK;
}
Example #4
0
GF_Err store_senc_info(GF_SampleEncryptionBox *ptr, GF_BitStream *bs)
{
	GF_Err e;
	u64 pos, new_pos;
	if (!ptr->cenc_saio) return GF_OK;

	pos = gf_bs_get_position(bs);
	if (pos>0xFFFFFFFFULL) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] \"senc\" offset larger than 32-bits , \"saio\" box version must be 1 .\n"));
	}
	e = gf_bs_seek(bs, ptr->cenc_saio->offset_first_offset_field);
	if (e) return e;
	//force using version 1 for saio box i.e offset has 64 bits
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
	if (ptr->traf) {
		new_pos = pos - ptr->traf->moof_start_in_bs;
	} else
#endif
	{
		new_pos = pos;
	}

	if (ptr->cenc_saio->offsets_large) {
		u32 i;
		u64 old_offset = ptr->cenc_saio->offsets_large[0];
		for (i=0; i<ptr->cenc_saio->entry_count; i++) {
			gf_bs_write_u64(bs, new_pos + ptr->cenc_saio->offsets_large[i] - old_offset);
			ptr->cenc_saio->offsets_large[i] = new_pos + ptr->cenc_saio->offsets_large[i] - old_offset;
		}
	} else {
		gf_bs_write_u64(bs, new_pos);
	}

	return gf_bs_seek(bs, pos);
}
Example #5
0
static Bool ADTS_SyncFrame(GF_BitStream *bs, Bool is_complete, ADTSHeader *hdr)
{
	u32 val, pos, start_pos;

	start_pos = (u32) gf_bs_get_position(bs);
	while (gf_bs_available(bs)) {
		val = gf_bs_read_u8(bs);
		if (val!=0xFF) continue;
		val = gf_bs_read_int(bs, 4);
		if (val != 0x0F) {
			gf_bs_read_int(bs, 4);
			continue;
		}
		hdr->is_mp2 = gf_bs_read_int(bs, 1);
		gf_bs_read_int(bs, 2);
		hdr->no_crc = gf_bs_read_int(bs, 1);
		pos = (u32) gf_bs_get_position(bs) - 2;

		hdr->profile = 1 + gf_bs_read_int(bs, 2);
		hdr->sr_idx = gf_bs_read_int(bs, 4);
		gf_bs_read_int(bs, 1);
		hdr->nb_ch = gf_bs_read_int(bs, 3);
		gf_bs_read_int(bs, 4);
		hdr->frame_size = gf_bs_read_int(bs, 13);
		gf_bs_read_int(bs, 11);
		gf_bs_read_int(bs, 2);
		hdr->hdr_size = 7;
		if (!hdr->no_crc) {
			gf_bs_read_u16(bs);
			hdr->hdr_size = 9;
		}
		if (hdr->frame_size < hdr->hdr_size) {
			gf_bs_seek(bs, pos+1);
			continue;
		}
		hdr->frame_size -= hdr->hdr_size;
		if (is_complete && (gf_bs_available(bs) == hdr->frame_size)) return 1;
		else if (gf_bs_available(bs) <= hdr->frame_size) break;

		gf_bs_skip_bytes(bs, hdr->frame_size);
		val = gf_bs_read_u8(bs);
		if (val!=0xFF) {
			gf_bs_seek(bs, pos+1);
			continue;
		}
		val = gf_bs_read_int(bs, 4);
		if (val!=0x0F) {
			gf_bs_read_int(bs, 4);
			gf_bs_seek(bs, pos+1);
			continue;
		}
		gf_bs_seek(bs, pos+hdr->hdr_size);
		return 1;
	}
	gf_bs_seek(bs, start_pos);
	return 0;
}
Example #6
0
GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *senc)
#endif
{
	GF_Err e;
	u32 i, j, count;
	u64 pos = gf_bs_get_position(bs);

#ifdef	GPAC_DISABLE_ISOM_FRAGMENTS
	if (!traf)
		return GF_BAD_PARAM;
#endif

	gf_bs_seek(bs, senc->bs_offset);

	count = gf_bs_read_u32(bs);
	if (!senc->samp_aux_info) senc->samp_aux_info = gf_list_new();
	for (i=0; i<count; i++) {
		u32 is_encrypted;
		u32 samp_count;
		GF_CENCSampleAuxInfo *sai = (GF_CENCSampleAuxInfo *)gf_malloc(sizeof(GF_CENCSampleAuxInfo));
		memset(sai, 0, sizeof(GF_CENCSampleAuxInfo));

		samp_count = i+1;
#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		if (trak) samp_count += trak->sample_count_at_seg_start;
#endif

		if (trak) {
			e = gf_isom_get_sample_cenc_info_ex(trak, traf, senc, samp_count, &is_encrypted, &sai->IV_size, NULL, NULL, NULL, NULL, NULL);
			if (e) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isobmf] could not get cenc info for sample %d: %s\n", samp_count, gf_error_to_string(e) ));
				return e;
			}
		}
		//no init movie setup (segment dump/inspaction, assume default encrypted and 16 bytes IV
		else {
			is_encrypted = GF_TRUE;
			sai->IV_size = 16;
		}

		if (is_encrypted) {
			gf_bs_read_data(bs, (char *)sai->IV, sai->IV_size);
			if (senc->flags & 0x00000002) {
				sai->subsample_count = gf_bs_read_u16(bs);
				sai->subsamples = (GF_CENCSubSampleEntry *)gf_malloc(sai->subsample_count*sizeof(GF_CENCSubSampleEntry));
				for (j = 0; j < sai->subsample_count; j++) {
					sai->subsamples[j].bytes_clear_data = gf_bs_read_u16(bs);
					sai->subsamples[j].bytes_encrypted_data = gf_bs_read_u32(bs);
				}
			}
		}
		gf_list_add(senc->samp_aux_info, sai);
	}
	gf_bs_seek(bs, pos);
	return GF_OK;
}
Example #7
0
static GF_Err gf_isom_cenc_get_sai_by_saiz_saio(GF_MediaBox *mdia, u32 sampleNumber, u8 IV_size, GF_CENCSampleAuxInfo **sai)
{
	GF_BitStream *bs;
	u32  prev_sai_size, size, i, j, nb_saio;
	u64 cur_position, offset;
	GF_Err e = GF_OK;
	char *buffer;

	nb_saio = size = prev_sai_size = 0;
	offset = 0;

	for (i = 0; i < gf_list_count(mdia->information->sampleTable->sai_offsets); i++) {
		GF_SampleAuxiliaryInfoOffsetBox *saio = (GF_SampleAuxiliaryInfoOffsetBox *)gf_list_get(mdia->information->sampleTable->sai_offsets, i);
		if (saio->aux_info_type == GF_4CC('c', 'e', 'n', 'c')) {
			if (saio->entry_count == 1)
				offset = saio->version ? saio->offsets_large[0] : saio->offsets[0];
			else
				offset = saio->version ? saio->offsets_large[sampleNumber-1]: saio->offsets[sampleNumber-1];
			nb_saio = saio->entry_count;
			break;
		}
	}

	for (i = 0; i < gf_list_count(mdia->information->sampleTable->sai_sizes); i++) {
		GF_SampleAuxiliaryInfoSizeBox *saiz = (GF_SampleAuxiliaryInfoSizeBox *)gf_list_get(mdia->information->sampleTable->sai_sizes, i);
		if (saiz->aux_info_type == GF_4CC('c', 'e', 'n', 'c')) {
			for (j = 0; j < sampleNumber-1; j++)
				prev_sai_size += saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[j];
			size = saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[sampleNumber-1];
			break;
		}
	}

	offset += (nb_saio == 1) ? prev_sai_size : 0;
	cur_position = gf_bs_get_position(mdia->information->dataHandler->bs);
	gf_bs_seek(mdia->information->dataHandler->bs, offset);
	buffer = (char *)gf_malloc(size);
	gf_bs_read_data(mdia->information->dataHandler->bs, buffer, size);
	gf_bs_seek(mdia->information->dataHandler->bs, cur_position);

	*sai = (GF_CENCSampleAuxInfo *)gf_malloc(sizeof(GF_CENCSampleAuxInfo));
	memset(*sai, 0, sizeof(GF_CENCSampleAuxInfo));
	bs = gf_bs_new(buffer, size, GF_BITSTREAM_READ);
	gf_bs_read_data(bs, (char *)(*sai)->IV, IV_size);
	if (size > IV_size) {
		(*sai)->subsample_count = gf_bs_read_u16(bs);
		(*sai)->subsamples = (GF_CENCSubSampleEntry *)gf_malloc(sizeof(GF_CENCSubSampleEntry)*(*sai)->subsample_count);
		for (i = 0; i < (*sai)->subsample_count; i++) {
			(*sai)->subsamples[i].bytes_clear_data = gf_bs_read_u16(bs);
			(*sai)->subsamples[i].bytes_encrypted_data = gf_bs_read_u32(bs);
		}
	}
	gf_bs_del(bs);

	return e;
}
Example #8
0
GF_EXPORT
GF_Err gf_bifs_decoder_configure_stream(GF_BifsDecoder * codec, u16 ESID, char *DecoderSpecificInfo, u32 DecoderSpecificInfoLength, u32 objectTypeIndication)
{
	GF_BitStream *bs;
	BIFSStreamInfo *pInfo;
	GF_Err e;

	if (!DecoderSpecificInfo) {
		/* Hack for T-DMB non compliant streams */
		GF_SAFEALLOC(pInfo, BIFSStreamInfo);
		pInfo->ESID = ESID;
		pInfo->config.PixelMetrics = 1;
		pInfo->config.version = (objectTypeIndication==2) ? 1 : 2;
		assert( codec );
		assert( codec->streamInfo );
		return gf_list_add(codec->streamInfo, pInfo);
	}
//	gf_mx_p(codec->mx);
	assert( codec );
	if (gf_bifs_dec_get_stream(codec, ESID) != NULL) {
//		gf_mx_v(codec->mx);
		return GF_BAD_PARAM;
	}
	bs = gf_bs_new(DecoderSpecificInfo, DecoderSpecificInfoLength, GF_BITSTREAM_READ);
	GF_SAFEALLOC(pInfo, BIFSStreamInfo);
	pInfo->ESID = ESID;

	pInfo->config.version = objectTypeIndication;
	/*parse config with indicated oti*/
	e = ParseConfig(bs, pInfo, (u32) objectTypeIndication);
	if (e) {
		pInfo->ESID = ESID;
		/*some content indicates a wrong OTI, so try to parse with v1 or v2*/
		gf_bs_seek(bs, 0);
		/*try with reverse config*/
		e = ParseConfig(bs, pInfo, (objectTypeIndication==2) ? 1 : 2);
		pInfo->config.version = (objectTypeIndication==2) ? 1 : 2;
	}

	if (e && (e != GF_ODF_INVALID_DESCRIPTOR)) {
		gf_free(pInfo);
		gf_bs_del(bs);
		return GF_BIFS_UNKNOWN_VERSION;
	}
	gf_bs_del(bs);

	assert( codec->streamInfo );
	//first stream, configure size
	if (!codec->ignore_size && !gf_list_count(codec->streamInfo)) {
		gf_sg_set_scene_size_info(codec->scenegraph, pInfo->config.Width, pInfo->config.Height, pInfo->config.PixelMetrics);
	}

	gf_list_add(codec->streamInfo, pInfo);
//	gf_mx_v(codec->mx);
	return GF_OK;
}
Example #9
0
GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *ptr)
#endif
{
	GF_Err e;
	u32 i, j, count;
	u64 pos = gf_bs_get_position(bs);

#ifdef	GPAC_DISABLE_ISOM_FRAGMENTS
	if (!traf)
		return GF_BAD_PARAM;
#endif

	gf_bs_seek(bs, ptr->bs_offset);

	count = gf_bs_read_u32(bs);
	if (!ptr->samp_aux_info) ptr->samp_aux_info = gf_list_new();
	for (i=0; i<count; i++) {
		u32 is_encrypted;
		GF_CENCSampleAuxInfo *sai = (GF_CENCSampleAuxInfo *)gf_malloc(sizeof(GF_CENCSampleAuxInfo));
		memset(sai, 0, sizeof(GF_CENCSampleAuxInfo));

		e = gf_isom_get_sample_cenc_info_ex(trak, traf, (trak ? trak->sample_count_at_seg_start : 0 )+ i+1, &is_encrypted, &sai->IV_size, NULL);
		if (e) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isobmf] could not get cenc info for sample %d: %s\n", trak->sample_count_at_seg_start + i+1, gf_error_to_string(e) ));
			return e;
		}
		if (is_encrypted) {
			gf_bs_read_data(bs, (char *)sai->IV, sai->IV_size);
			if (ptr->flags & 0x00000002) {
				sai->subsample_count = gf_bs_read_u16(bs);
				sai->subsamples = (GF_CENCSubSampleEntry *)gf_malloc(sai->subsample_count*sizeof(GF_CENCSubSampleEntry));
				for (j = 0; j < sai->subsample_count; j++) {
					sai->subsamples[j].bytes_clear_data = gf_bs_read_u16(bs);
					sai->subsamples[j].bytes_encrypted_data = gf_bs_read_u32(bs);
				}
			}
		}
		gf_list_add(ptr->samp_aux_info, sai);
	}
	gf_bs_seek(bs, pos);
	return GF_OK;
}
Example #10
0
GF_Err store_senc_info(GF_SampleEncryptionBox *ptr, GF_BitStream *bs)
{
	GF_Err e;
	u64 pos;
	if (!ptr->cenc_saio) return GF_OK;

	pos = gf_bs_get_position(bs);
	if (pos>0xFFFFFFFFULL) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] \"senc\" offset larger than 32-bits , \"saio\" box version must be 1 .\n"));
	}
	e = gf_bs_seek(bs, ptr->cenc_saio->offset_first_offset_field);
	if (e) return e;
	//force using version 1 for saio box i.e offset has 64 bits
	if (ptr->traf) {
		gf_bs_write_u64(bs, pos - ptr->traf->moof_start_in_bs );
	} else {
		gf_bs_write_u64(bs, pos);
	}
	return gf_bs_seek(bs, pos);
}
Example #11
0
GF_Err store_senc_info(GF_SampleEncryptionBox *ptr, GF_BitStream *bs)
{
	GF_Err e;
	u64 pos;
	if (!ptr->cenc_saio) return GF_OK;

	pos = gf_bs_get_position(bs);
	if (pos>0xFFFFFFFFULL) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] \"senc\" offset larger than 32-bits , cannot store.\n"));
		return GF_NOT_SUPPORTED;
	}
	e = gf_bs_seek(bs, ptr->cenc_saio->offset_first_offset_field);
	if (e) return e;
	if (ptr->traf) {
		gf_bs_write_u32(bs, (u32) ( pos - ptr->traf->moof_start_in_bs) );
	} else {
		gf_bs_write_u32(bs, (u32) pos);
	}
	return gf_bs_seek(bs, pos);
}
Example #12
0
GF_Err meta_Read(GF_Box *s, GF_BitStream *bs)
{
	u64 pos = gf_bs_get_position(bs);
	u64 size = s->size;
	GF_Err e = gf_isom_box_array_read(s, bs, meta_AddBox);
	/*try to hack around QT files which don't use a full box for meta, rewind 4 bytes*/
	if (e && (pos>4) ) {
		gf_bs_seek(bs, pos-4);
		meta_reset(s);
		s->size = size+4;
		e = gf_isom_box_array_read(s, bs, meta_AddBox);
	}
	return e;
}
Example #13
0
GF_EXPORT
GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name, char **out_data, u32 *out_size, const char **out_mime )
{
	GF_BitStream *item_bs;
	char szPath[1024];
	GF_ItemExtentEntry *extent_entry;
	FILE *resource = NULL;
	u32 i, count;
	GF_ItemLocationEntry *location_entry;
	u32 item_num;
	char *item_name = NULL;

	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
	if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;

	if (out_mime) *out_mime = NULL;

	item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
	if (item_num) {
		GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num-1);
		item_name = item_entry->item_name;
		if (out_mime) *out_mime = item_entry->content_type;
	}

	location_entry = NULL;
	count = gf_list_count(meta->item_locations->location_entries);
	for (i=0; i<count; i++) {
		location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
		if (location_entry->item_ID == item_id) break;
		location_entry = NULL;
	}

	if (!location_entry) return GF_BAD_PARAM;
	/*FIXME*/
	if (location_entry->data_reference_index) {
		char *item_url = NULL, *item_urn = NULL;
		GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, location_entry->data_reference_index-1);
		if (a->type==GF_ISOM_BOX_TYPE_URL) {
			item_url = ((GF_DataEntryURLBox*)a)->location;
		} else if (a->type==GF_ISOM_BOX_TYPE_URN) {
			item_url = ((GF_DataEntryURNBox*)a)->location;
			item_urn = ((GF_DataEntryURNBox*)a)->nameURN;
		}
		GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item already outside the ISO file at URL: %s, URN: %s\n", (item_url?item_url:"N/A"), (item_urn?item_urn:"N/A") ));
		return GF_OK;
	}

	/*don't extract self-reference item*/
	count = gf_list_count(location_entry->extent_entries);
	if (!location_entry->base_offset && (count==1)) {
		extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0);
		if (!extent_entry->extent_length
#ifndef GPAC_DISABLE_ISOM_WRITE
		        && !extent_entry->original_extent_offset
#endif
		   ) return GF_BAD_PARAM;
	}

	item_bs = NULL;

	if (out_data) {
		item_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	} else if (dump_file_name) {
		strcpy(szPath, dump_file_name);
		resource = gf_fopen(szPath, "wb");
		item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
	} else {
		if (item_name) strcpy(szPath, item_name);
		else sprintf(szPath, "item_id%02d", item_id);
		resource = gf_fopen(szPath, "wb");
		item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
	}

	for (i=0; i<count; i++) {
		char buf_cache[4096];
		u64 remain;
		GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i);
		gf_bs_seek(file->movieFileMap->bs, location_entry->base_offset + extent_entry->extent_offset);

		remain = extent_entry->extent_length;
		while (remain) {
			u32 cache_size = (remain>4096) ? 4096 : (u32) remain;
			gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
			gf_bs_write_data(item_bs, buf_cache, cache_size);
			remain -= cache_size;
		}
	}
	if (out_data) {
		gf_bs_get_content(item_bs, out_data, out_size);
	}
	if (resource) {
		gf_fclose(resource);
	}
	gf_bs_del(item_bs);
	return GF_OK;
}
Example #14
0
/**
 * A function which takes FFmpeg H264 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer.
 * @param extradata
 * @param extradata_size
 * @param dstcfg
 * @returns GF_OK is the extradata was parsed and is valid, other values otherwise.
 */
static GF_Err avc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_AVCConfig *dstcfg)
{
#ifdef GPAC_DISABLE_AV_PARSERS
	return GF_OK;
#else
	u8 nal_size;
	AVCState avc;
	GF_BitStream *bs;
	if (!extradata || (extradata_size < sizeof(u32)))
		return GF_BAD_PARAM;
	bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ);
	if (!bs)
		return GF_BAD_PARAM;
	if (gf_bs_read_u32(bs) != 0x00000001) {
		gf_bs_del(bs);
		return GF_BAD_PARAM;
	}

	//SPS
	{
		s32 idx;
		char *buffer = NULL;
		const u64 nal_start = 4;
		nal_size = gf_media_nalu_next_start_code_bs(bs);
		if (nal_start + nal_size > extradata_size) {
			gf_bs_del(bs);
			return GF_BAD_PARAM;
		}
		buffer = (char*)gf_malloc(nal_size);
		gf_bs_read_data(bs, buffer, nal_size);
		gf_bs_seek(bs, nal_start);
		if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_SEQ_PARAM) {
			gf_bs_del(bs);
			gf_free(buffer);
			return GF_BAD_PARAM;
		}

		idx = gf_media_avc_read_sps(buffer, nal_size, &avc, 0, NULL);
		if (idx < 0) {
			gf_bs_del(bs);
			gf_free(buffer);
			return GF_BAD_PARAM;
		}

		dstcfg->configurationVersion = 1;
		dstcfg->profile_compatibility = avc.sps[idx].prof_compat;
		dstcfg->AVCProfileIndication = avc.sps[idx].profile_idc;
		dstcfg->AVCLevelIndication = avc.sps[idx].level_idc;
		dstcfg->chroma_format = avc.sps[idx].chroma_format;
		dstcfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8;
		dstcfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8;

		{
			GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
			slc->size = nal_size;
			slc->id = idx;
			slc->data = buffer;
			gf_list_add(dstcfg->sequenceParameterSets, slc);
		}
	}

	//PPS
	{
		s32 idx;
		char *buffer = NULL;
		const u64 nal_start = 4 + nal_size + 4;
		gf_bs_seek(bs, nal_start);
		nal_size = gf_media_nalu_next_start_code_bs(bs);
		if (nal_start + nal_size > extradata_size) {
			gf_bs_del(bs);
			return GF_BAD_PARAM;
		}
		buffer = (char*)gf_malloc(nal_size);
		gf_bs_read_data(bs, buffer, nal_size);
		gf_bs_seek(bs, nal_start);
		if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_PIC_PARAM) {
			gf_bs_del(bs);
			gf_free(buffer);
			return GF_BAD_PARAM;
		}

		idx = gf_media_avc_read_pps(buffer, nal_size, &avc);
		if (idx < 0) {
			gf_bs_del(bs);
			gf_free(buffer);
			return GF_BAD_PARAM;
		}

		{
			GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
			slc->size = nal_size;
			slc->id = idx;
			slc->data = buffer;
			gf_list_add(dstcfg->pictureParameterSets, slc);
		}
	}

	gf_bs_del(bs);
	return GF_OK;
#endif
}
Example #15
0
File: main.c Project: ARSekkat/gpac
void RS_Deinterleaver(GF_BitStream *bs, char *out_name)
{
	u8 rs0[204], rs1[204], rs2[204], rs3[204], rs4[204], rs5[204], rs6[204], rs7[204], rs8[204], rs9[204], rs10[204], rs11[204];
	u8 *rs[12] = { rs0, rs1, rs2, rs3, rs4, rs5, rs6, rs7, rs8, rs9, rs10, rs11 };
	u8 *tmp;
	u8 buf[204];
	u32 i;
	u64 bs_data;
	u32 k = 0;

	memset(rs[0], 0, 204);
	memset(rs[1], 0, 204);
	memset(rs[2], 0, 204);
	memset(rs[3], 0, 204);
	memset(rs[4], 0, 204);
	memset(rs[5], 0, 204);
	memset(rs[6], 0, 204);
	memset(rs[7], 0, 204);
	memset(rs[8], 0, 204);
	memset(rs[9], 0, 204);
	memset(rs[10], 0, 204);
	memset(rs[11], 0, 204);

	bs_data = gf_bs_available(bs);
	while (bs_data > 204) {
		u64 pos;
		k++;
//		printf("TS Packet Number: %d\r", k);

		pos = gf_bs_get_position(bs);
		gf_bs_read_data(bs, buf, 204);
		bs_data = gf_bs_available(bs);

		while ((buf[0] != 0x47) && (bs_data > 0)) {
			printf("error in input TS %d\n", k);
			//return;
			pos++;
			gf_bs_seek(bs, pos);
			gf_bs_read_data(bs, buf, 204);
			bs_data = gf_bs_available(bs);
		}

		for (i=0; i<(17*12); i+=12) { // 1 paquet
			rs[0][i]     = buf[i];
			rs[1][i+1]   = buf[i+1];
			rs[2][i+2]	 = buf[i+2];
			rs[3][i+3]   = buf[i+3];
			rs[4][i+4]   = buf[i+4];
			rs[5][i+5]   = buf[i+5];
			rs[6][i+6]   = buf[i+6];
			rs[7][i+7]   = buf[i+7];
			rs[8][i+8]   = buf[i+8];
			rs[9][i+9]   = buf[i+9];
			rs[10][i+10] = buf[i+10];
			rs[11][i+11] = buf[i+11];
		}
		if (k >= 12) {
			if (rs[11][0] != 0x47) {
				printf("error in output TS\n");
			} else {
				save_ts(out_name, rs[11]);
			}
		}
		tmp = rs[11];
		rs[11] = rs[10];
		rs[10] = rs[9];
		rs[9] = rs[8];
		rs[8] = rs[7];
		rs[7] = rs[6];
		rs[6] = rs[5];
		rs[5] = rs[4];
		rs[4] = rs[3];
		rs[3] = rs[2];
		rs[2] = rs[1];
		rs[1] = rs[0];
		rs[0] = tmp;
	}
}
Example #16
0
GF_EXPORT
void gf_img_parse(GF_BitStream *bs, u8 *OTI, u32 *mtype, u32 *width, u32 *height, char **dsi, u32 *dsi_len)
{
	u8 b1, b2, b3;
	u32 size, type;
	u64 pos;
	pos = gf_bs_get_position(bs);
	gf_bs_seek(bs, 0);

	*mtype = *width = *height = 0;
	*OTI = 0;
	if (dsi) {
		*dsi = NULL;
		*dsi_len = 0;
	}

	b1 = gf_bs_read_u8(bs);
	b2 = gf_bs_read_u8(bs);
	b3 = gf_bs_read_u8(bs);
	/*JPEG*/
	if ((b1==0xFF) && (b2==0xD8) && (b3==0xFF)) {
		u32 offset = 0;
		u32 Xdens, Ydens, nb_comp;
		gf_bs_read_u8(bs);
		gf_bs_skip_bytes(bs, 10);	/*2 size, 5 JFIF\0, 2 version, 1 units*/
		Xdens = gf_bs_read_int(bs, 16);
		Ydens = gf_bs_read_int(bs, 16);
		nb_comp = 0;

		/*get frame header FFC0*/
		while (gf_bs_available(bs)) {
			u32 type, w, h;
			if (gf_bs_read_u8(bs) != 0xFF) continue;
			if (!offset) offset = (u32)gf_bs_get_position(bs) - 1;

			type = gf_bs_read_u8(bs);
			/*process all Start of Image markers*/
			switch (type) {
			case 0xC0:
			case 0xC1:
			case 0xC2:
			case 0xC3:
			case 0xC5:
			case 0xC6:
			case 0xC7:
			case 0xC9:
			case 0xCA:
			case 0xCB:
			case 0xCD:
			case 0xCE:
			case 0xCF:
				gf_bs_skip_bytes(bs, 3);
				h = gf_bs_read_int(bs, 16);
				w = gf_bs_read_int(bs, 16);
				if ((w > *width) || (h > *height)) {
					*width = w;
					*height = h;
				}
				nb_comp = gf_bs_read_int(bs, 8);
				break;
			}
		}
		*OTI = GPAC_OTI_IMAGE_JPEG;
		*mtype = GF_4CC('j','p','e','g');
		if (dsi) {
			GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
			gf_bs_write_u16(bs_dsi, offset);
			gf_bs_write_u16(bs_dsi, Xdens);
			gf_bs_write_u16(bs_dsi, Ydens);
			gf_bs_write_u8(bs_dsi, nb_comp);
			gf_bs_get_content(bs_dsi, dsi, dsi_len);
			gf_bs_del(bs_dsi);
		}
	}
	/*PNG*/
	else if ((b1==0x89) && (b2==0x50) && (b3==0x4E)) {
		/*check for PNG sig*/
		if ( (gf_bs_read_u8(bs) != 0x47) || (gf_bs_read_u8(bs) != 0x0D) || (gf_bs_read_u8(bs) != 0x0A)
			|| (gf_bs_read_u8(bs) != 0x1A) || (gf_bs_read_u8(bs) != 0x0A) ) goto exit;
		gf_bs_read_u32(bs);
		/*check for PNG IHDR*/
		if ( (gf_bs_read_u8(bs) != 'I') || (gf_bs_read_u8(bs) != 'H')
			|| (gf_bs_read_u8(bs) != 'D') || (gf_bs_read_u8(bs) != 'R')) goto exit;

		*width = gf_bs_read_u32(bs);
		*height = gf_bs_read_u32(bs);
		*OTI = GPAC_OTI_IMAGE_PNG;
		*mtype = GF_4CC('p','n','g',' ');
	}
	size = gf_bs_read_u8(bs);
	type = gf_bs_read_u32(bs);
	if ( ((size==12) && (type==GF_4CC('j','P',' ',' ') ))
		|| (type==GF_4CC('j','p','2','h') ) ) {

		if (type==GF_4CC('j','p','2','h')) {
			*OTI = GPAC_OTI_IMAGE_JPEG_2000;
			*mtype = GF_4CC('j','p','2',' ');
			goto j2k_restart;
		}

		type = gf_bs_read_u32(bs);
		if (type!=0x0D0A870A) goto exit;

		*OTI = GPAC_OTI_IMAGE_JPEG_2000;
		*mtype = GF_4CC('j','p','2',' ');

		while (gf_bs_available(bs)) {
j2k_restart:
			size = gf_bs_read_u32(bs);
			type = gf_bs_read_u32(bs);
			switch (type) {
			case GF_4CC('j','p','2','h'):
				goto j2k_restart;
			case GF_4CC('i','h','d','r'):
			{
				u16 nb_comp;
				u8 BPC, C, UnkC, IPR;
				*height = gf_bs_read_u32(bs);
				*width = gf_bs_read_u32(bs);
				nb_comp = gf_bs_read_u16(bs);
				BPC = gf_bs_read_u8(bs);
				C = gf_bs_read_u8(bs);
				UnkC = gf_bs_read_u8(bs);
				IPR = gf_bs_read_u8(bs);

				if (dsi) {
					GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
					gf_bs_write_u32(bs_dsi, *height);
					gf_bs_write_u32(bs_dsi, *width);
					gf_bs_write_u16(bs_dsi, nb_comp);
					gf_bs_write_u8(bs_dsi, BPC);
					gf_bs_write_u8(bs_dsi, C);
					gf_bs_write_u8(bs_dsi, UnkC);
					gf_bs_write_u8(bs_dsi, IPR);
					gf_bs_get_content(bs_dsi, dsi, dsi_len);
					gf_bs_del(bs_dsi);
				}
				goto exit;
			}
				break;
			default:
				gf_bs_skip_bytes(bs, size-8);
				break;
			}
		}
	}

exit:
	gf_bs_seek(bs, pos);
}
Example #17
0
//write the file track by track, with moov box before or after the mdat
GF_Err WriteFlat(MovieWriter *mw, u8 moovFirst, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	u64 offset, finalOffset, totSize, begin, firstSize, finalSize;
	GF_Box *a;
	GF_List *writers = gf_list_new();
	GF_ISOFile *movie = mw->movie;

	begin = totSize = 0;

	//first setup the writers
	e = SetupWriters(mw, writers, 0);
	if (e) goto exit;

	if (!moovFirst) {
		if (movie->openMode == GF_ISOM_OPEN_WRITE) {
			begin = 0;
			totSize = gf_isom_datamap_get_offset(movie->editFileMap);
			/*start boxes have not been written yet, do it*/
			if (!totSize) {
				if (movie->is_jp2) {
					gf_bs_write_u32(movie->editFileMap->bs, 12);
					gf_bs_write_u32(movie->editFileMap->bs, GF_4CC('j','P',' ',' '));
					gf_bs_write_u32(movie->editFileMap->bs, 0x0D0A870A);
					totSize += 12;
					begin += 12;
				}
				if (movie->brand) {
					e = gf_isom_box_size((GF_Box *)movie->brand); if (e) goto exit;
					e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs); if (e) goto exit;
					totSize += movie->brand->size;
					begin += movie->brand->size;
				}
				if (movie->pdin) {
					e = gf_isom_box_size((GF_Box *)movie->pdin); if (e) goto exit;
					e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs); if (e) goto exit;
					totSize += movie->pdin->size;
					begin += movie->pdin->size;
				}
			} else {
				if (movie->is_jp2) begin += 12;
				if (movie->brand) begin += movie->brand->size;
				if (movie->pdin) begin += movie->pdin->size;
			}
			totSize -= begin;
		} else {
			if (movie->is_jp2) {
				gf_bs_write_u32(bs, 12);
				gf_bs_write_u32(bs, GF_4CC('j','P',' ',' '));
				gf_bs_write_u32(bs, 0x0D0A870A);
			}
			if (movie->brand) {
				e = gf_isom_box_size((GF_Box *)movie->brand);
				if (e) goto exit;
				e = gf_isom_box_write((GF_Box *)movie->brand, bs);
				if (e) goto exit;
			}
			/*then progressive download*/
			if (movie->pdin) {
				e = gf_isom_box_size((GF_Box *)movie->pdin);
				if (e) goto exit;
				e = gf_isom_box_write((GF_Box *)movie->pdin, bs);
				if (e) goto exit;
			}
		}

		//if the moov is at the end, write directly
		i=0;
		while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
			switch (a->type) {
			/*written by hand*/
			case GF_ISOM_BOX_TYPE_MOOV:
			case GF_ISOM_BOX_TYPE_META:
			case GF_ISOM_BOX_TYPE_FTYP:
			case GF_ISOM_BOX_TYPE_PDIN:
				break;
			case GF_ISOM_BOX_TYPE_MDAT:
				//in case we're capturing
				if (movie->openMode == GF_ISOM_OPEN_WRITE) {
					//emulate a write to recreate our tables (media data already written)
					e = DoWrite(mw, writers, bs, 1, begin);
					if (e) goto exit;
					continue;
				}
				//to avoid computing the size each time write always 4 + 4 + 8 bytes before
				begin = gf_bs_get_position(bs);
				gf_bs_write_u64(bs, 0);
				gf_bs_write_u64(bs, 0);
				e = DoWrite(mw, writers, bs, 0, gf_bs_get_position(bs));
				if (e) goto exit;
				totSize = gf_bs_get_position(bs) - begin;
				break;
			default:
				e = gf_isom_box_size(a);
				if (e) goto exit;
				e = gf_isom_box_write(a, bs);
				if (e) goto exit;
				break;
			}
		}

		//OK, write the movie box.
		e = WriteMoovAndMeta(movie, writers, bs);
		if (e) goto exit;

		/*if data has been written, update mdat size*/
		if (totSize) {
			offset = gf_bs_get_position(bs);
			e = gf_bs_seek(bs, begin);
			if (e) goto exit;
			if (totSize > 0xFFFFFFFF) {
				gf_bs_write_u32(bs, 1);
			} else {
				gf_bs_write_u32(bs, (u32) totSize);
			}
			gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_MDAT);
			if (totSize > 0xFFFFFFFF) gf_bs_write_u64(bs, totSize);
			e = gf_bs_seek(bs, offset);
		}
		movie->mdat->size = totSize;
		goto exit;
	}

	//nope, we have to write the moov first. The pb is that 
	//1 - we don't know its size till the mdat is written
	//2 - we don't know the ofset at which the mdat will start...
	//3 - once the mdat is written, the chunkOffset table can have changed...
	
	if (movie->is_jp2) {
		gf_bs_write_u32(bs, 12);
		gf_bs_write_u32(bs, GF_4CC('j','P',' ',' '));
		gf_bs_write_u32(bs, 0x0D0A870A);
	}
	if (movie->brand) {
		e = gf_isom_box_size((GF_Box *)movie->brand);
		if (e) goto exit;
		e = gf_isom_box_write((GF_Box *)movie->brand, bs);
		if (e) goto exit;
	}
	/*then progressive dnload*/
	if (movie->pdin) {
		e = gf_isom_box_size((GF_Box *)movie->pdin);
		if (e) goto exit;
		e = gf_isom_box_write((GF_Box *)movie->pdin, bs);
		if (e) goto exit;
	}
	//What we will do is first emulate the write from the begining...
	//note: this will set the size of the mdat
	e = DoWrite(mw, writers, bs, 1, gf_bs_get_position(bs));
	if (e) goto exit;
	
	firstSize = GetMoovAndMetaSize(movie, writers);
	//offset = (firstSize > 0xFFFFFFFF ? firstSize + 8 : firstSize) + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0);
	offset = firstSize + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0);
	e = ShiftOffset(movie, writers, offset);
	if (e) goto exit;
	//get the size and see if it has changed (eg, we moved to 64 bit offsets)
	finalSize = GetMoovAndMetaSize(movie, writers);
	if (firstSize != finalSize) {
		//we need to remove our offsets
		ResetWriters(writers);
		//finalOffset = (finalSize > 0xFFFFFFFF ? finalSize + 8 : finalSize) + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0);
		finalOffset = finalSize + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0);
		//OK, now we're sure about the final size.
		//we don't need to re-emulate, as the only thing that changed is the offset
		//so just shift the offset
		e = ShiftOffset(movie, writers, finalOffset - offset);
		if (e) goto exit;
	}
	//now write our stuff
	e = WriteMoovAndMeta(movie, writers, bs);
	if (e) goto exit;
	e = gf_isom_box_size((GF_Box *)movie->mdat);
	if (e) goto exit;
	e = gf_isom_box_write((GF_Box *)movie->mdat, bs);
	if (e) goto exit;

	//we don't need the offset as the moov is already written...
	ResetWriters(writers);
	e = DoWrite(mw, writers, bs, 0, 0);
	if (e) goto exit;
	//then the rest
	i=0;
	while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
		switch (a->type) {
		case GF_ISOM_BOX_TYPE_MOOV:
		case GF_ISOM_BOX_TYPE_META:
		case GF_ISOM_BOX_TYPE_FTYP:
		case GF_ISOM_BOX_TYPE_PDIN:
		case GF_ISOM_BOX_TYPE_MDAT:
			break;
		default:
			e = gf_isom_box_size(a);
			if (e) goto exit;
			e = gf_isom_box_write(a, bs);
			if (e) goto exit;
		}
	}

exit:
	CleanWriters(writers);
	gf_list_del(writers);
	return e;
}
Example #18
0
GF_Err DoWriteMeta(GF_ISOFile *file, GF_MetaBox *meta, GF_BitStream *bs, Bool Emulation, u64 baseOffset, u64 *mdatSize)
{
	GF_ItemExtentEntry *entry;
	u64 maxExtendOffset, maxExtendSize;
	u32 i, j, count;

	maxExtendOffset = 0;
	maxExtendSize = 0;
	*mdatSize = 0;
	if (!meta->item_locations) return GF_OK;

	count = gf_list_count(meta->item_locations->location_entries);
	for (i=0; i<count; i++) {
		u64 it_size;
		GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
		/*get item info*/
		GF_ItemInfoEntryBox *iinf = NULL;
		j=0;
		while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) {
			if (iinf->item_ID==iloc->item_ID) break;
			iinf = NULL;
		}

		if (!iloc->base_offset && (gf_list_count(iloc->extent_entries)==1)) {
			entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
			if (!entry->extent_length && !entry->original_extent_offset) {
				entry->extent_offset = 0;
				continue;
			}
		}

		it_size = 0;
		/*for self contained only*/
		if (!iloc->data_reference_index) {
			iloc->base_offset = baseOffset;
	
			/*new resource*/
			if (iinf->full_path) {
				FILE *src=NULL;
				
				if (!iinf->data_len) {
					src = gf_f64_open(iinf->full_path, "rb");
					if (!src) continue;
					gf_f64_seek(src, 0, SEEK_END);
					it_size = gf_f64_tell(src);
					gf_f64_seek(src, 0, SEEK_SET);
				} else {
					it_size = iinf->data_len;
				}
				if (maxExtendSize<it_size) maxExtendSize = it_size;

				if (!gf_list_count(iloc->extent_entries)) {
					GF_SAFEALLOC(entry, GF_ItemExtentEntry);
					gf_list_add(iloc->extent_entries, entry);
				}
				entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
				entry->extent_offset = 0;
				entry->extent_length = it_size;

				/*OK write to mdat*/
				if (!Emulation) {
					if (src) {
						char cache_data[4096];
						u64 remain = entry->extent_length;
						while (remain) {
							u32 size_cache = (remain>4096) ? 4096 : (u32) remain;
							size_cache = fread(cache_data, sizeof(char), size_cache, src);
							gf_bs_write_data(bs, cache_data, size_cache);
							remain -= size_cache;
						}
					} else {
						gf_bs_write_data(bs, iinf->full_path, iinf->data_len);
					}
				}
				if (src) fclose(src);
			} 
			else if (gf_list_count(iloc->extent_entries)) {
				u32 j;
				j=0;
				while ((entry = (GF_ItemExtentEntry *)gf_list_enum(iloc->extent_entries, &j))) {
					if (j && (maxExtendOffset<it_size) ) maxExtendOffset = it_size;
					/*compute new offset*/
					entry->extent_offset = baseOffset + it_size;

					it_size += entry->extent_length;
					if (maxExtendSize<entry->extent_length) maxExtendSize = entry->extent_length;

					/*Reading from the input file*/
					if (!Emulation) {
						char cache_data[4096];
						u64 remain = entry->extent_length;
						gf_bs_seek(file->movieFileMap->bs, entry->original_extent_offset + iloc->original_base_offset);
						while (remain) {
							u32 size_cache = (remain>4096) ? 4096 : (u32) remain;
							gf_bs_read_data(file->movieFileMap->bs, cache_data, size_cache);
							/*Writing to the output file*/
							gf_bs_write_data(bs, cache_data, size_cache);
							remain -= size_cache;
						}
					}
				}
			}
			baseOffset += it_size;
			*mdatSize += it_size;
		} else {
			/*we MUST have at least one extent for the dref data*/
			if (!gf_list_count(iloc->extent_entries)) {
				GF_SAFEALLOC(entry, GF_ItemExtentEntry);
				gf_list_add(iloc->extent_entries, entry);
			}
			entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
			entry->extent_offset = 0;
			/*0 means full length of referenced file*/
			entry->extent_length = 0;
		}
	}
	/*update offset & size length fields*/
	if (baseOffset>0xFFFFFFFF) meta->item_locations->base_offset_size = 8;
	else if (baseOffset) meta->item_locations->base_offset_size = 4;
	
	if (maxExtendSize>0xFFFFFFFF) meta->item_locations->length_size = 8;
	else if (maxExtendSize) meta->item_locations->length_size = 4;

	if (maxExtendOffset>0xFFFFFFFF) meta->item_locations->offset_size = 8;
	else if (maxExtendOffset) meta->item_locations->offset_size = 4;
	return GF_OK;
}
Example #19
0
/**
 * A function which takes FFmpeg H265 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer.
 * @param extradata
 * @param extradata_size
 * @param dstcfg
 * @returns GF_OK is the extradata was parsed and is valid, other values otherwise.
 */
static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_HEVCConfig *dst_cfg)
{
#ifdef GPAC_DISABLE_AV_PARSERS
	return GF_OK;
#else
	HEVCState hevc;
	GF_HEVCParamArray *vpss = NULL, *spss = NULL, *ppss = NULL;
	GF_BitStream *bs;
	char *buffer = NULL;
	u32 buffer_size = 0;
	if (!extradata || (extradata_size < sizeof(u32)))
		return GF_BAD_PARAM;
	bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ);
	if (!bs)
		return GF_BAD_PARAM;

	memset(&hevc, 0, sizeof(HEVCState));
	hevc.sps_active_idx = -1;

	while (gf_bs_available(bs)) {
		s32 idx;
		GF_AVCConfigSlot *slc;
		u8 nal_unit_type, temporal_id, layer_id;
		u64 nal_start;
		u32 nal_size;

		if (gf_bs_read_u32(bs) != 0x00000001) {
			gf_bs_del(bs);
			return GF_BAD_PARAM;
		}
		nal_start = gf_bs_get_position(bs);
		nal_size = gf_media_nalu_next_start_code_bs(bs);
		if (nal_start + nal_size > extradata_size) {
			gf_bs_del(bs);
			return GF_BAD_PARAM;
		}

		if (nal_size > buffer_size) {
			buffer = (char*)gf_realloc(buffer, nal_size);
			buffer_size = nal_size;
		}
		gf_bs_read_data(bs, buffer, nal_size);
		gf_bs_seek(bs, nal_start);

		gf_media_hevc_parse_nalu(bs, &hevc, &nal_unit_type, &temporal_id, &layer_id);
		if (layer_id) {
			gf_bs_del(bs);
			gf_free(buffer);
			return GF_BAD_PARAM;
		}

		switch (nal_unit_type) {
		case GF_HEVC_NALU_VID_PARAM:
			idx = gf_media_hevc_read_vps(buffer, nal_size , &hevc);
			if (idx < 0) {
				gf_bs_del(bs);
				gf_free(buffer);
				return GF_BAD_PARAM;
			}

			assert(hevc.vps[idx].state == 1); //we don't expect multiple VPS
			if (hevc.vps[idx].state == 1) {
				hevc.vps[idx].state = 2;
				hevc.vps[idx].crc = gf_crc_32(buffer, nal_size);

				dst_cfg->avgFrameRate = hevc.vps[idx].rates[0].avg_pic_rate;
				dst_cfg->constantFrameRate = hevc.vps[idx].rates[0].constand_pic_rate_idc;
				dst_cfg->numTemporalLayers = hevc.vps[idx].max_sub_layers;
				dst_cfg->temporalIdNested = hevc.vps[idx].temporal_id_nesting;

				if (!vpss) {
					GF_SAFEALLOC(vpss, GF_HEVCParamArray);
					vpss->nalus = gf_list_new();
					gf_list_add(dst_cfg->param_array, vpss);
					vpss->array_completeness = 1;
					vpss->type = GF_HEVC_NALU_VID_PARAM;
				}

				slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
				slc->size = nal_size;
				slc->id = idx;
				slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
				memcpy(slc->data, buffer, sizeof(char)*slc->size);

				gf_list_add(vpss->nalus, slc);
			}
			break;
		case GF_HEVC_NALU_SEQ_PARAM:
			idx = gf_media_hevc_read_sps(buffer, nal_size, &hevc);
			if (idx < 0) {
				gf_bs_del(bs);
				gf_free(buffer);
				return GF_BAD_PARAM;
			}

			assert(!(hevc.sps[idx].state & AVC_SPS_DECLARED)); //we don't expect multiple SPS
			if ((hevc.sps[idx].state & AVC_SPS_PARSED) && !(hevc.sps[idx].state & AVC_SPS_DECLARED)) {
				hevc.sps[idx].state |= AVC_SPS_DECLARED;
				hevc.sps[idx].crc = gf_crc_32(buffer, nal_size);
			}

			dst_cfg->configurationVersion = 1;
			dst_cfg->profile_space = hevc.sps[idx].ptl.profile_space;
			dst_cfg->tier_flag = hevc.sps[idx].ptl.tier_flag;
			dst_cfg->profile_idc = hevc.sps[idx].ptl.profile_idc;
			dst_cfg->general_profile_compatibility_flags = hevc.sps[idx].ptl.profile_compatibility_flag;
			dst_cfg->progressive_source_flag = hevc.sps[idx].ptl.general_progressive_source_flag;
			dst_cfg->interlaced_source_flag = hevc.sps[idx].ptl.general_interlaced_source_flag;
			dst_cfg->non_packed_constraint_flag = hevc.sps[idx].ptl.general_non_packed_constraint_flag;
			dst_cfg->frame_only_constraint_flag = hevc.sps[idx].ptl.general_frame_only_constraint_flag;

			dst_cfg->constraint_indicator_flags = hevc.sps[idx].ptl.general_reserved_44bits;
			dst_cfg->level_idc = hevc.sps[idx].ptl.level_idc;

			dst_cfg->chromaFormat = hevc.sps[idx].chroma_format_idc;
			dst_cfg->luma_bit_depth = hevc.sps[idx].bit_depth_luma;
			dst_cfg->chroma_bit_depth = hevc.sps[idx].bit_depth_chroma;

			if (!spss) {
				GF_SAFEALLOC(spss, GF_HEVCParamArray);
				spss->nalus = gf_list_new();
				gf_list_add(dst_cfg->param_array, spss);
				spss->array_completeness = 1;
				spss->type = GF_HEVC_NALU_SEQ_PARAM;
			}

			slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
			slc->size = nal_size;
			slc->id = idx;
			slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
			memcpy(slc->data, buffer, sizeof(char)*slc->size);
			gf_list_add(spss->nalus, slc);
			break;
		case GF_HEVC_NALU_PIC_PARAM:
			idx = gf_media_hevc_read_pps(buffer, nal_size, &hevc);
			if (idx < 0) {
				gf_bs_del(bs);
				gf_free(buffer);
				return GF_BAD_PARAM;
			}

			assert(hevc.pps[idx].state == 1); //we don't expect multiple PPS
			if (hevc.pps[idx].state == 1) {
				hevc.pps[idx].state = 2;
				hevc.pps[idx].crc = gf_crc_32(buffer, nal_size);

				if (!ppss) {
					GF_SAFEALLOC(ppss, GF_HEVCParamArray);
					ppss->nalus = gf_list_new();
					gf_list_add(dst_cfg->param_array, ppss);
					ppss->array_completeness = 1;
					ppss->type = GF_HEVC_NALU_PIC_PARAM;
				}

				slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
				slc->size = nal_size;
				slc->id = idx;
				slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
				memcpy(slc->data, buffer, sizeof(char)*slc->size);

				gf_list_add(ppss->nalus, slc);
			}
			break;
		default:
			break;
		}

		if (gf_bs_seek(bs, nal_start+nal_size)) {
			assert(nal_start+nal_size <= gf_bs_get_size(bs));
			break;
		}
	}

	gf_bs_del(bs);
	gf_free(buffer);

	return GF_OK;
#endif
}
Example #20
0
GF_Err gp_rtp_builder_do_mpeg4(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
{
	char *sl_buffer, *payl_buffer;
	u32 sl_buffer_size, payl_buffer_size;
	u32 auh_size_tmp, bytesLeftInPacket, infoSize, pckSize;
	u64 pos;
	u8 flush_pck, no_split;

	flush_pck = 0;

	bytesLeftInPacket = data_size;
	/*flush everything*/
	if (!data) {
		if (builder->payload) goto flush_packet;
		return GF_OK;
	}
	if (builder->payload && builder->force_flush) goto flush_packet;

	//go till done
	while (bytesLeftInPacket) {
		no_split = 0;

		if (builder->sl_header.accessUnitStartFlag) {
			//init SL
			if (builder->sl_header.compositionTimeStamp != builder->sl_header.decodingTimeStamp) {
				builder->sl_header.decodingTimeStampFlag = 1;
			}
			builder->sl_header.compositionTimeStampFlag = 1;
			builder->sl_header.accessUnitLength = FullAUSize;

			//init some vars - based on the available size and the TS
			//we decide if we go with the same RTP TS serie or not
			if (builder->payload) {
				//don't store more than what we can (that is 2^slMap->CTSDelta - 1)
				if ( (builder->flags & GP_RTP_PCK_SIGNAL_TS)
					&& (builder->sl_header.compositionTimeStamp - builder->rtp_header.TimeStamp >= (u32) ( 1 << builder->slMap.CTSDeltaLength) ) ) {
					goto flush_packet;
				}
				//don't split AU if # TS , start a new RTP pck
				if (builder->sl_header.compositionTimeStamp != builder->rtp_header.TimeStamp)
					no_split = 1;
			}
		}

		/*new RTP Packet*/
		if (!builder->payload) {
			/*first SL in RTP*/
			builder->first_sl_in_rtp = 1;

			/*if this is the end of an AU we will set it to 0 as soon as an AU is splited*/
			builder->rtp_header.Marker = 1;
			builder->rtp_header.PayloadType = builder->PayloadType;
			builder->rtp_header.SequenceNumber += 1;

			builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
			/*prepare the mapped headers*/
			builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
			builder->payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
			pckSize = infoSize = 0;
			builder->bytesInPacket = 0;

			/*in multiSL there is a MSLHSize structure on 2 bytes*/
			builder->auh_size = 0;
			if (builder->has_AU_header) {
				builder->auh_size = 16;
				gf_bs_write_int(builder->pck_hdr, 0, 16);
			}
			flush_pck = 0;
			/*and create packet*/
			builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
		}

		//make sure we are not interleaving too much - this should never happen actually
		if (builder->slMap.IndexDeltaLength
			&& !builder->first_sl_in_rtp
			&& (builder->sl_header.AU_sequenceNumber - builder->last_au_sn >= (u32) 1<<builder->slMap.IndexDeltaLength)) {
			//we cannot write this packet here
			goto flush_packet;
		}
		/*check max ptime*/
		if (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
			goto flush_packet;

		auh_size_tmp = gf_rtp_build_au_hdr_size(builder, &builder->sl_header);

		infoSize = auh_size_tmp + builder->auh_size;
		infoSize /= 8;
		/*align*/
		if ( (builder->auh_size + auh_size_tmp) % 8) infoSize += 1;


		if (bytesLeftInPacket + infoSize + builder->bytesInPacket <= builder->Path_MTU) {
			//End of our data chunk
			pckSize = bytesLeftInPacket;
			builder->sl_header.accessUnitEndFlag = IsAUEnd;

			builder->auh_size += auh_size_tmp;

			builder->sl_header.paddingFlag = builder->sl_header.paddingBits ? 1 : 0;
		} else {

			//AU cannot fit in packet. If no split, start a new packet
			if (no_split) goto flush_packet;

			builder->auh_size += auh_size_tmp;

			pckSize = builder->Path_MTU - (infoSize + builder->bytesInPacket);
			//that's the end of the rtp packet
			flush_pck = 1;
			//but not of the AU -> marker is 0
			builder->rtp_header.Marker = 0;
		}

		gf_rtp_build_au_hdr_write(builder, pckSize, builder->rtp_header.TimeStamp);

		//notify the user of our data structure
		if (builder->OnDataReference)
			builder->OnDataReference(builder->cbk_obj, pckSize, data_size - bytesLeftInPacket);
		else
			gf_bs_write_data(builder->payload, data + (data_size - bytesLeftInPacket), pckSize);


		bytesLeftInPacket -= pckSize;
		builder->bytesInPacket += pckSize;
		/*update IV*/
		builder->IV += pckSize;
		builder->sl_header.paddingFlag = 0;
		builder->sl_header.accessUnitStartFlag = 0;

		//we are splitting a payload, auto increment SL seq num
		if (bytesLeftInPacket) {
			builder->sl_header.packetSequenceNumber += 1;
		} else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) {
			builder->rtp_header.Marker = 1;
			flush_pck = 1;
		}

		//first SL in RTP is done
		builder->first_sl_in_rtp = 0;

		//store current sl
		builder->last_au_sn = builder->sl_header.AU_sequenceNumber;

		if (!flush_pck) continue;

		//done with the packet
flush_packet:

		gf_bs_align(builder->pck_hdr);

		/*no aux data yet*/
		if (builder->slMap.AuxiliaryDataSizeLength)	{
			//write RSLH after the MSLH
			gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.AuxiliaryDataSizeLength);
		}
		/*rewrite the size header*/
		if (builder->has_AU_header) {
			pos = gf_bs_get_position(builder->pck_hdr);
			gf_bs_seek(builder->pck_hdr, 0);
			builder->auh_size -= 16;
			gf_bs_write_int(builder->pck_hdr, builder->auh_size, 16);
			gf_bs_seek(builder->pck_hdr, pos);
		}

		sl_buffer = NULL;
		gf_bs_get_content(builder->pck_hdr, &sl_buffer, &sl_buffer_size);
		//delete our bitstream
		gf_bs_del(builder->pck_hdr);
		builder->pck_hdr = NULL;

		payl_buffer = NULL;
		payl_buffer_size = 0;
		if (!builder->OnDataReference)
			gf_bs_get_content(builder->payload, &payl_buffer, &payl_buffer_size);

		gf_bs_del(builder->payload);
		builder->payload = NULL;

		/*notify header*/
		builder->OnData(builder->cbk_obj, sl_buffer, sl_buffer_size, 1);
		/*notify payload*/
		if (payl_buffer) {
			builder->OnData(builder->cbk_obj, payl_buffer, payl_buffer_size, 0);
			gf_free(payl_buffer);
		}
		/*flush packet*/
		builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
		gf_free(sl_buffer);
	}
	//packet is done, update AU markers
	if (IsAUEnd) {
		builder->sl_header.accessUnitStartFlag = 1;
		builder->sl_header.accessUnitEndFlag = 0;
	}
	return GF_OK;
}
Example #21
0
GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u64 *bytesMissing, Bool progressive_mode)
{
	GF_Box *a;
	u64 totSize;
	GF_Err e = GF_OK;

	totSize = 0;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
	/*restart from where we stopped last*/
	totSize = mov->current_top_box_start;
	gf_bs_seek(mov->movieFileMap->bs, mov->current_top_box_start);
#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);
#endif

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

		if (e >= 0) {
			e = GF_OK;
		} else if (e == GF_ISOM_INCOMPLETE_FILE) {
			/*our mdat is uncomplete, only valid for READ ONLY files...*/
			if (mov->openMode != GF_ISOM_OPEN_READ) {
				return GF_ISOM_INVALID_FILE;
			}
			return e;
		} else {
			return e;
		}

		switch (a->type) {
		/*MOOV box*/
		case GF_ISOM_BOX_TYPE_MOOV:
			if (mov->moov) return GF_ISOM_INVALID_FILE;
			mov->moov = (GF_MovieBox *)a;
			/*set our pointer to the movie*/
			mov->moov->mov = mov;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
            if (mov->moov->mvex) mov->moov->mvex->mov = mov;
#endif
            e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;
			totSize += a->size;
			break;

		/*META box*/
		case GF_ISOM_BOX_TYPE_META:
			if (mov->meta) return GF_ISOM_INVALID_FILE;
			mov->meta = (GF_MetaBox *)a;
			e = gf_list_add(mov->TopBoxes, a);
			if (e) return e;
			totSize += a->size;
			break;

		/*we only keep the MDAT in READ for dump purposes*/
		case GF_ISOM_BOX_TYPE_MDAT:
			totSize += a->size;
			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);
			}
			/*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_CAT_FRAGMENTS)) {
				gf_isom_box_del(a);
				mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
				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);
				return GF_ISOM_INVALID_FILE;
			}
			mov->brand = (GF_FileTypeBox *)a;
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			break;

		case GF_ISOM_BOX_TYPE_PDIN:
			/*ONE AND ONLY ONE PDIN*/
			if (mov->pdin) {
				gf_isom_box_del(a);
				return GF_ISOM_INVALID_FILE;
			}
			mov->pdin = (GF_ProgressiveDownloadBox *) a;
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			break;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
		case GF_ISOM_BOX_TYPE_STYP:
			if (((GF_SegmentTypeBox *)a)->majorBrand == GF_4CC('i', 's', 's', 's') ||
				((GF_SegmentTypeBox *)a)->majorBrand == GF_4CC('i', 'm', 's', 's')) mov->is_index_segment = 1;

		case GF_ISOM_BOX_TYPE_SIDX:
			totSize += a->size;
			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
				e = gf_list_add(mov->TopBoxes, a);
			} else {
				gf_isom_box_del(a);
			}
			break;

		case GF_ISOM_BOX_TYPE_MOOF:
			((GF_MovieFragmentBox *)a)->mov = mov;

			totSize += a->size;
            mov->moof = (GF_MovieFragmentBox *) a;
			/*read & debug: store at root level*/
			if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
                gf_list_add(mov->TopBoxes, a);
			} else if (mov->openMode==GF_ISOM_OPEN_CAT_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) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error merging fragment: %s\n", gf_error_to_string(e) ));
				}
			}
			break;
#endif
		case GF_4CC('j','P',' ',' '):
		{
			GF_UnknownBox *box = (GF_UnknownBox*)a;
			u8 *c = 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);
		}
			break;

		default:
			totSize += a->size;
			e = gf_list_add(mov->TopBoxes, a);
			break;
		}

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
//		mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs);
#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_INVALID_FILE;
	/*we MUST have movie header*/
	if (mov->moov && !mov->moov->mvhd) return GF_ISOM_INVALID_FILE;
	/*we MUST have meta handler*/
	if (mov->meta && !mov->meta->handler) 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_CAT_FRAGMENTS) && mov->moov->mvex) {
			gf_isom_box_del((GF_Box *)mov->moov->mvex);
			mov->moov->mvex = NULL;
		}
#endif

	}
#endif /*GPAC_DISABLE_ISOM_WRITE*/

	return GF_OK;
}
Example #22
0
GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u64 *bytesMissing, Bool progressive_mode)
{
    GF_Box *a;
    u64 totSize;
    GF_Err e = GF_OK;

    totSize = 0;


#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;
    gf_bs_seek(mov->movieFileMap->bs, mov->current_top_box_start);

#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);
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Current top box start before parsing %d\n", mov->current_top_box_start));
#endif

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

        if (e >= 0) {
            e = GF_OK;
        } 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;
            }
            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"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->moov = (GF_MovieBox *)a;
            /*set our pointer to the movie*/
            mov->moov->mov = mov;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
            if (mov->moov->mvex) mov->moov->mvex->mov = mov;
#endif
            e = gf_list_add(mov->TopBoxes, a);
            if (e) {
                return e;
            }
            totSize += a->size;
            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"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->meta = (GF_MetaBox *)a;
            e = gf_list_add(mov->TopBoxes, a);
            if (e) {
                return e;
            }
            totSize += a->size;
            break;

        /*we only keep the MDAT in READ for dump purposes*/
        case GF_ISOM_BOX_TYPE_MDAT:
            totSize += a->size;
            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);
            }
            /*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_CAT_FRAGMENTS)) {
                gf_isom_box_del(a);
                mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
                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);
            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);
            break;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
        case GF_ISOM_BOX_TYPE_STYP:
        {
            u32 brand = ((GF_SegmentTypeBox *)a)->majorBrand;
            switch (brand) {
            case GF_4CC('s', 'i', 's', 'x'):
            case GF_4CC('r', 'i', 's', 'x'):
            case GF_4CC('s', 's', 's', 's'):
                mov->is_index_segment = GF_TRUE;
                break;
            default:
                break;
            }
        }
        /*fall-through*/

        case GF_ISOM_BOX_TYPE_SIDX:
            totSize += a->size;
            if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
                e = gf_list_add(mov->TopBoxes, a);
            } else {
                gf_isom_box_del(a);
            }
            break;

        case GF_ISOM_BOX_TYPE_MOOF:
            if (!mov->moov) {
                GF_LOG(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;
            /*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) {
                            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->trex->track && (traf->piff_sample_encryption || traf->sample_encryption)) {
                            GF_TrackBox *trak = GetTrackbyID(mov->moov, traf->tfhd->trackID);
                            e = senc_Parse(mov->movieFileMap->bs, trak, traf, traf->piff_sample_encryption ? (GF_SampleEncryptionBox *) traf->piff_sample_encryption : traf->sample_encryption);
                        }
                    }
                }
            } else if (mov->openMode==GF_ISOM_OPEN_CAT_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);
            }
            break;
#endif
        case GF_4CC('j','P',' ',' '):
        {
            GF_UnknownBox *box = (GF_UnknownBox*)a;
            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);
        }
        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

        default:
            totSize += a->size;
            e = gf_list_add(mov->TopBoxes, a);
            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);
#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 (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_CAT_FRAGMENTS) && mov->moov->mvex) {
            gf_isom_box_del((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_CAT_FRAGMENTS)) {
        mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
        e = gf_list_add(mov->TopBoxes, mov->mdat);
        if (e) return e;
    }
#endif /*GPAC_DISABLE_ISOM_WRITE*/

    return GF_OK;
}
Example #23
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);
		}
	}