Example #1
0
M4Err UpdateSample(MediaAtom *mdia, u32 sampleNumber, u32 size, u32 CTS, u64 offset, u8 isRap)
{
	u32 i;
	SampleTableAtom *stbl = mdia->information->sampleTable;

	//set size, offset, RAP, CTS ...
	stbl_SetSampleSize(stbl->SampleSize, sampleNumber, size);
	stbl_SetChunkOffset(mdia, sampleNumber, offset);

	//do we have a CTS?
	if (stbl->CompositionOffset) {
		stbl_SetSampleCTS(stbl, sampleNumber, CTS);
	} else {
		//do we need one ??
		if (CTS) {
			stbl->CompositionOffset = (CompositionOffsetAtom *) CreateAtom(CompositionOffsetAtomType);
			stbl_AddCTS(stbl, sampleNumber, CTS);
		}
	}
	//do we have a sync ???
	if (stbl->SyncSample) {
		stbl_SetSampleRAP(stbl->SyncSample, sampleNumber, isRap);
	} else {
		//do we need one
		if (! isRap) {
			stbl->SyncSample = (SyncSampleAtom *) CreateAtom(SyncSampleAtomType);
			//what a pain: all the sample we had have to be sync ...
			for (i=0; i<stbl->SampleSize->sampleCount; i++) {
				if (i+1 != sampleNumber) stbl_AddRAP(stbl->SyncSample, i+1);
			}
		}
	}
	return M4OK;
}
Example #2
0
M4Err Media_AddSample(MediaAtom *mdia, u64 data_offset, M4Sample *sample, u32 StreamDescIndex, u32 syncShadowNumber)
{
	M4Err e;
	SampleTableAtom *stbl;
	u32 sampleNumber, i;
	if (!mdia || !sample) return M4BadParam;

	stbl = mdia->information->sampleTable;

	//get a valid sampleNumber for this new guy
	e = stbl_AddDTS(stbl, sample->DTS, &sampleNumber, mdia->mediaHeader->timeScale);
	if (e) return e;

	//add size
	e = stbl_AddSize(stbl->SampleSize, sampleNumber, sample->dataLength);
	if (e) return e;

	//adds CTS offset
	if (sample->CTS_Offset) {
		//if we don't have a CTS table, add it...
		if (!stbl->CompositionOffset) stbl->CompositionOffset = (CompositionOffsetAtom *) CreateAtom(CompositionOffsetAtomType);
		//then add our CTS (the prev samples with no CTS offset will be automatically added...
		e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
		if (e) return e;
	} else if (stbl->CompositionOffset) {
		e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
		if (e) return e;
	}

	//The first non sync sample we see must create a syncTable
	if (sample->IsRAP) {
		//insert it only if we have a sync table
		if (stbl->SyncSample) {
			e = stbl_AddRAP(stbl->SyncSample, sampleNumber);
			if (e) return e;
		}
	} else {
		//non-sync sample. Create a SyncSample table if needed
		if (!stbl->SyncSample) {
			stbl->SyncSample = (SyncSampleAtom *) CreateAtom(SyncSampleAtomType);
			//all the prev samples are sync
			for (i=0; i<stbl->SampleSize->sampleCount; i++) {
				if (i+1 != sampleNumber) {
					e = stbl_AddRAP(stbl->SyncSample, i+1);
					if (e) return e;
				}
			}
		}
	}

	//and update the chunks
	e = stbl_AddChunkOffset(mdia, sampleNumber, StreamDescIndex, data_offset);
	if (e) return e;

	if (!syncShadowNumber) return M4OK;
	if (!stbl->ShadowSync) stbl->ShadowSync = (ShadowSyncAtom *) CreateAtom(ShadowSyncAtomType);
	return stbl_AddShadow(mdia->information->sampleTable->ShadowSync, sampleNumber, syncShadowNumber);
}
Example #3
0
M4Err Media_CreateDataRef(DataReferenceAtom *dref, char *URLname, char *URNname, u32 *dataRefIndex)
{	
	M4Err e;
	DataEntryURLAtom *entry;

	M4Err dref_AddDataEntry(DataReferenceAtom *ptr, Atom *entry);

	if (!URLname && !URNname) {
		//THIS IS SELF CONTAIN, create a regular entry if needed
		entry = (DataEntryURLAtom *) CreateAtom(DataEntryURLAtomType);
		entry->location = NULL;
		entry->flags = 0;
		entry->flags |= 1;
		e = dref_AddDataEntry(dref, (Atom *)entry);
		if (e) return e;
		*dataRefIndex = ChainGetCount(dref->atomList);
		return M4OK;
	} else if (!URNname && URLname) {
		//THIS IS URL
		entry = (DataEntryURLAtom *) CreateAtom(DataEntryURLAtomType);
		entry->flags = 0;
		entry->location = (char*)malloc(strlen(URLname)+1);
		if (! entry->location) {
			DelAtom((Atom *)entry);
			return M4OutOfMem;
		}
		strcpy(entry->location, URLname);
		e = dref_AddDataEntry(dref, (Atom *)entry);
		if (e) return e;
		*dataRefIndex = ChainGetCount(dref->atomList);
		return M4OK;
	} else {
		//THIS IS URN
		entry = (DataEntryURLAtom *) CreateAtom(DataEntryURNAtomType);
		((DataEntryURNAtom *)entry)->flags = 0;
		((DataEntryURNAtom *)entry)->nameURN = (char*)malloc(strlen(URNname)+1);
		if (! ((DataEntryURNAtom *)entry)->nameURN) {
			DelAtom((Atom *)entry);
			return M4OutOfMem;
		}
		strcpy(((DataEntryURNAtom *)entry)->nameURN, URNname);
		//check for URL
		if (URLname) {
			((DataEntryURNAtom *)entry)->location = (char*)malloc(strlen(URLname)+1);
			if (! ((DataEntryURNAtom *)entry)->location) {
				DelAtom((Atom *)entry);
				return M4OutOfMem;
			}
			strcpy(((DataEntryURNAtom *)entry)->location, URLname);
		}
		e = dref_AddDataEntry(dref, (Atom *)entry);
		if (e) return e;
		*dataRefIndex = ChainGetCount(dref->atomList);
		return M4OK;
	}
	return M4OK;
}
Example #4
0
//set the time offset of this packet. This enables packets to be placed in the hint track 
//in decoding order, but have their presentation time-stamp in the transmitted 
//packet be in a different order. Typically used for MPEG video with B-frames
M4Err M4H_RTP_SetPacketTimeOffset(M4File *the_file, u32 trackNumber, s32 timeOffset)
{
	RtpoAtom *rtpo;
	TrackAtom *trak;
	HintSampleEntryAtom *entry;
	RTPPacket *pck;
	u32 dataRefIndex, i;
	M4Err e;

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam;

	e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &dataRefIndex);
	if (e) return e;
	if (!entry->w_sample) return M4BadParam;

	pck = ChainGetEntry(entry->w_sample->packetTable, ChainGetCount(entry->w_sample->packetTable) - 1);
	if (!pck) return M4BadParam;

	//look in the TLV
	for (i=0; i<ChainGetCount(pck->TLV); i++) {
		rtpo = ChainGetEntry(pck->TLV, i);
		if (rtpo->type == rtpoAtomType) {
			rtpo->timeOffset = timeOffset;
			return M4OK;
		}
	}
	//not found, add it
	rtpo = (RtpoAtom *) CreateAtom(rtpoAtomType);
	rtpo->timeOffset = timeOffset;

	return ChainAddEntry(pck->TLV, rtpo);
}
Example #5
0
//sets the RTP SequenceNumber Offset that the server will add to the packets
//if not set, the server adds a random offset
M4Err M4H_RTP_SetSequenceNumberOffset(M4File *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 SequenceNumberOffset)
{
	TrackAtom *trak;
	HintSampleEntryAtom *hdesc;
	u32 i, count;
	SeqOffHintEntry *ent;

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam;

	//OK, create a new HintSampleDesc
	hdesc = ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, HintDescriptionIndex - 1);
	count = ChainGetCount(hdesc->HintDataTable);

	for (i=0; i< count; i++) {
		ent = ChainGetEntry(hdesc->HintDataTable, i);
		if (ent->type == snroHintEntryType) {			
			ent->SeqOffset = SequenceNumberOffset;
			return M4OK;
		}
	}
	//we have to create a new entry...
	ent = (SeqOffHintEntry *) CreateAtom(snroHintEntryType);
	ent->SeqOffset = SequenceNumberOffset;
	return ChainAddEntry(hdesc->HintDataTable, ent);
}
Example #6
0
//to use with internally supported protocols
M4Err M4H_NewHintDescription(M4File *the_file, u32 trackNumber, s32 HintTrackVersion, s32 LastCompatibleVersion, u8 Rely, u32 *HintDescriptionIndex)
{
	M4Err e;
	u32 drefIndex;
	TrackAtom *trak;
	HintSampleEntryAtom *hdesc;
	RelyHintEntry *relyA;

	M4Err stsd_AddAtom(SampleDescriptionAtom *ptr, Atom *a);

	trak = GetTrackFromFile(the_file, trackNumber);
	*HintDescriptionIndex = 0;
	if (!trak || !IsHintTrack(trak)) return M4BadParam;

	//OK, create a new HintSampleDesc
	hdesc = (HintSampleEntryAtom *) CreateAtom(GetHintFormat(trak));

	if (HintTrackVersion > 0) hdesc->HintTrackVersion = HintTrackVersion;
	if (LastCompatibleVersion > 0) hdesc->LastCompatibleVersion = LastCompatibleVersion;

	//create a data reference - WE ONLY DEAL WITH SELF-CONTAINED HINT TRACKS
	e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, NULL, NULL, &drefIndex);
	if (e) return e;
	hdesc->dataReferenceIndex = drefIndex;

	//add the entry to our table...
	e = stsd_AddAtom(trak->Media->information->sampleTable->SampleDescription, (Atom *) hdesc);
	if (e) return e;
	*HintDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);

	//RTP needs a default timeScale... use the media one.
	if (CheckHintFormat(trak, M4_Hint_RTP)) {
		e = M4H_RTP_SetTimeScale(the_file, trackNumber, *HintDescriptionIndex, trak->Media->mediaHeader->timeScale);
		if (e) return e;
	}
	if (!Rely) return M4OK;

	//we need a rely atom (common to all protocols)
	relyA = (RelyHintEntry *) CreateAtom(relyHintEntryType);
	if (Rely == 1) {
		relyA->prefered = 1;
	} else {
		relyA->required = 1;
	}
	return ChainAddEntry(hdesc->HintDataTable, relyA);
}
Example #7
0
M4Err M4_AMR_NewStreamConfig(M4File *the_file, u32 trackNumber, LPAMRCONFIGURATION param, char *URLname, char *URNname, u32 *outDescriptionIndex)
{
	TrackAtom *trak;
	M4Err e;
	u32 dataRefIndex;
	TrackReferenceTypeAtom *dpnd;
	TrackReferenceAtom *tref;
	AMRSampleEntryAtom *entry;

	e = CanAccessMovie((M4Movie *)the_file, M4_OPEN_WRITE);
	if (e) return e;
	
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !trak->Media || !param) return M4BadParam;

	dpnd = NULL;
	tref = NULL;

	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
		if (e) return e;
	}
	trak->Media->mediaHeader->modificationTime = GetMP4Time();

	//create a new entry
	entry = (AMRSampleEntryAtom *) CreateAtom(param->WideBandAMR ? WB_AMRSampleEntryAtomType : AMRSampleEntryAtomType);
	if (!entry) return M4OutOfMem;
	entry->amr_info = (AMRConfigAtom *) CreateAtom(AMRConfigAtomType);
	if (!entry->amr_info) {
		DelAtom((Atom *) entry);
		return M4OutOfMem;
	}
	entry->samplerate_hi = trak->Media->mediaHeader->timeScale;
	entry->dataReferenceIndex = dataRefIndex;
	entry->amr_info->decoder_version = param->decoder_version;
	entry->amr_info->vendor = param->vendor;
	entry->amr_info->frames_per_sample = param->frames_per_sample;
	entry->amr_info->mode_change_period = param->mode_change_period;
	entry->amr_info->mode_set = param->mode_set;
	e = ChainAddEntry(trak->Media->information->sampleTable->SampleDescription->atomList, entry);
	*outDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	return e;
}
Example #8
0
// RFC3501:  astring = 1*ASTRING-CHAR / string
//           string  = quoted / literal
// This function leaves us off with fCurrentTokenPlaceHolder immediately after
// the end of the Astring.  Call AdvanceToNextToken() to get the token after it.
char *nsIMAPGenericParser::CreateAstring()
{
  if (*fNextToken == '{')
    return CreateLiteral();		// literal
  else if (*fNextToken == '"')
    return CreateQuoted();		// quoted
  else
    return CreateAtom(true); // atom
}
Example #9
0
void MP4StblAtom::Generate()
{
    // as usual
    MP4Atom::Generate();

    // but we also need one of the chunk offset atoms
    MP4Atom* pChunkOffsetAtom;
    if (m_File.Use64Bits(GetType())) {
        pChunkOffsetAtom = CreateAtom(m_File, this, "co64");
    } else {
        pChunkOffsetAtom = CreateAtom(m_File, this, "stco");
    }

    AddChildAtom(pChunkOffsetAtom);

    // and ask it to self generate
    pChunkOffsetAtom->Generate();
}
Example #10
0
M4Err M4_H263_NewStreamConfig(M4File *the_file, u32 trackNumber, LPH263CONFIGURATION param, char *URLname, char *URNname, u32 *outDescriptionIndex)
{
	TrackAtom *trak;
	M4Err e;
	u32 dataRefIndex;
	TrackReferenceTypeAtom *dpnd;
	TrackReferenceAtom *tref;
	H263SampleEntryAtom *entry;

	e = CanAccessMovie((M4Movie *)the_file, M4_OPEN_WRITE);
	if (e) return e;
	
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !trak->Media || !param) return M4BadParam;

	dpnd = NULL;
	tref = NULL;

	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
		if (e) return e;
	}
	trak->Media->mediaHeader->modificationTime = GetMP4Time();

	//create a new entry
	entry = (H263SampleEntryAtom *) CreateAtom(H263SampleEntryAtomType);
	if (!entry) return M4OutOfMem;
	entry->h263_config = (H263ConfigAtom *) CreateAtom(H263ConfigAtomType);
	if (!entry->h263_config) {
		DelAtom((Atom *) entry);
		return M4OutOfMem;
	}
	entry->dataReferenceIndex = dataRefIndex;
	entry->h263_config->decoder_version = param->decoder_version;
	entry->h263_config->vendor = param->vendor;
	entry->h263_config->Level = param->Level;
	entry->h263_config->Profile = param->Profile;
	e = ChainAddEntry(trak->Media->information->sampleTable->SampleDescription->atomList, entry);
	*outDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	return e;
}
Example #11
0
//set shadowing on/off
M4Err M4_SetSyncShadowEnabled(M4File *the_file, u32 trackNumber, u8 SyncShadowEnabled)
{
	TrackAtom *trak;
	SampleTableAtom *stbl;

	if (((M4Movie *)the_file)->openMode == M4_OPEN_READ) return M4InvalidMP4Mode;
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak) return M4BadParam;

	stbl = trak->Media->information->sampleTable;
	if (SyncShadowEnabled) {
		if (!stbl->ShadowSync) stbl->ShadowSync = (ShadowSyncAtom *) CreateAtom(ShadowSyncAtomType);
	} else {
		if (stbl->ShadowSync) DelAtom((Atom *) stbl->ShadowSync);
	}
	return M4OK;
}
Example #12
0
//add an SDP line to the SDP container at the track level (media-specific SDP info)
M4Err M4H_SDP_TrackAddLine(M4File *the_file, u32 trackNumber, const char *text)
{
	TrackAtom *trak;
	UserDataMap *map;
	HintTrackInfoAtom *hnti;
	SDPAtom *sdp;
	M4Err e;
	char *buf;
	M4Err hnti_AddAtom(HintTrackInfoAtom *hnti, Atom *a);

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak) return M4BadParam;

	//currently, only RTP hinting supports SDP
	if (!CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam;

	map = udta_getEntry(trak->udta, HintTrackInfoAtomType);
	if (!map) return M4InvalidMP4File;

	//we should have only one HNTI in the UDTA
	if (ChainGetCount(map->atomList) != 1) return M4InvalidMP4File;

	hnti = ChainGetEntry(map->atomList, 0);
	if (!hnti->SDP) {
		e = hnti_AddAtom(hnti, CreateAtom(SDPAtomType));
		if (e) return e;
	}
	sdp = (SDPAtom *) hnti->SDP;

	if (!sdp->sdpText) {
		sdp->sdpText = malloc(sizeof(char) * (strlen(text) + 3));
		strcpy(sdp->sdpText, text);
		strcat(sdp->sdpText, "\r\n");
		return M4OK;
	}
	buf = malloc(sizeof(char) * (strlen(sdp->sdpText) + strlen(text) + 3));
	strcpy(buf, sdp->sdpText);
	strcat(buf, text);
	strcat(buf, "\r\n");
	free(sdp->sdpText);
	sdp->sdpText = buf;	
	return M4OK;
}
Example #13
0
M4Err stbl_AddOffset(Atom **a, u64 offset)
{
	ChunkOffsetAtom *stco;
	ChunkLargeOffsetAtom *co64;
	u32 i;

	if ((*a)->type == ChunkOffsetAtomType) {
		stco = (ChunkOffsetAtom *) *a;
		//if dataOffset is bigger than 0xFFFFFFFF, move to LARGE offset
		if (offset > 0xFFFFFFFF) {
			co64 = (ChunkLargeOffsetAtom *) CreateAtom(ChunkLargeOffsetAtomType);
			if (!co64) return M4OutOfMem;
			co64->entryCount = stco->entryCount + 1;
			co64->offsets = (u64*)malloc(co64->entryCount * sizeof(u64));
			if (!co64->offsets) {
				DelAtom((Atom *)co64);
				return M4OutOfMem;
			}
			for (i = 0; i< co64->entryCount - 1; i++) {
				co64->offsets[i] = (u64) stco->offsets[i];
			}
			co64->offsets[i] = offset;
			//delete the atom...
			DelAtom(*a);
			*a = (Atom *)co64;
			return M4OK;
		}
		//OK, stick with regular...
		stco->offsets = (u32*)realloc(stco->offsets, (stco->entryCount + 1) * sizeof(u32));
		if (!stco->offsets) return M4OutOfMem;
		stco->offsets[stco->entryCount] = (u32) offset;
		stco->entryCount += 1;
	} else {
		//this is a large offset
		co64 = (ChunkLargeOffsetAtom *) *a;
		co64->offsets = (u64*)realloc(co64->offsets, (co64->entryCount + 1) * sizeof(u64));
		if (!co64->offsets) return M4OutOfMem;
		co64->offsets[co64->entryCount] = offset;
		co64->entryCount += 1;
	}
	return M4OK;
}
Example #14
0
M4Err NewMedia(MediaAtom **mdia, u32 MediaType, u32 TimeScale)
{
	MediaHeaderAtom *mdhd;
	Atom *mediaInfo;
	HandlerAtom *hdlr;
	MediaInformationAtom *minf;
	DataInformationAtom *dinf;
	SampleTableAtom *stbl;
	SampleDescriptionAtom *stsd;
	DataReferenceAtom *dref;
	char *str;

	M4Err stbl_AddAtom(SampleTableAtom *ptr, Atom *a);
	M4Err mdia_AddAtom(MediaAtom *ptr, Atom *a);
	M4Err dinf_AddAtom(DataInformationAtom *ptr, Atom *a);
	M4Err minf_AddAtom(MediaInformationAtom *ptr, Atom *a);

	M4Err e;

	if (*mdia || !mdia) return M4BadParam;

	e = M4OK;
	minf = NULL;
	mdhd = NULL;
	hdlr = NULL;
	dinf = NULL;
	stbl = NULL;
	stsd = NULL;
	dref = NULL;
	mediaInfo = NULL;

	//first create the media
	*mdia = (MediaAtom *) CreateAtom(MediaAtomType);
	mdhd = (MediaHeaderAtom *) CreateAtom(MediaHeaderAtomType);

	//"handler name" is for debugging purposes. Let's stick our name here ;)
	switch (MediaType) {
	case M4_VisualMediaType:
		mediaInfo = CreateAtom(VideoMediaHeaderAtomType);
		str = "GPAC ISO Video Handler";
		break;
	case M4_AudioMediaType:
		mediaInfo = CreateAtom(SoundMediaHeaderAtomType);
		str = "GPAC ISO Audio Handler";
		break;
	case M4_HintMediaType:
		mediaInfo = CreateAtom(HintMediaHeaderAtomType);
		str = "GPAC ISO Hint Handler";
		break;
	case M4_ODMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 OD Handler";
		break;
	case M4_OCRMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 OCR Handler";
		break;
	case M4_BIFSMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 BIFS Handler";
		break;
	case M4_MPEG7MediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 MPEG-7 Handler";
		break;
	case M4_OCIMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 OCI Handler";
		break;
	case M4_IPMPMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 IPMP Handler";
		break;
	case M4_MPEGJMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC MPEG-4 MPEG-J Handler";
		break;
	case M4_TimedTextMediaType:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC Streaming Text Handler";
		break;
	default:
		mediaInfo = CreateAtom(MPEGMediaHeaderAtomType);
		str = "GPAC IsoMedia Handler";
		break;
	}
	hdlr = (HandlerAtom *) CreateAtom(HandlerAtomType);
	minf = (MediaInformationAtom *) CreateAtom(MediaInformationAtomType);

	mdhd->timeScale = TimeScale;
	hdlr->handlerType = MediaType;

	hdlr->nameLength = strlen(str) + 1;
	hdlr->nameUTF8 = (char*)malloc(sizeof(char) * hdlr->nameLength);
	if (!hdlr->nameUTF8) {
		e = M4OutOfMem;
		goto err_exit;
	}
	strcpy(hdlr->nameUTF8, str);

	//first set-up the sample table...
	stbl = (SampleTableAtom *) CreateAtom(SampleTableAtomType);
	dinf = (DataInformationAtom *) CreateAtom(DataInformationAtomType);
	//add all our sub-atoms in the sample table (only the mandatory ones)
	stbl->SampleDescription = (SampleDescriptionAtom *) CreateAtom(SampleDescriptionAtomType);
	stbl->ChunkOffset = CreateAtom(ChunkOffsetAtomType);
	//by default create a regular table
	stbl->SampleSize = (SampleSizeAtom *) CreateAtom(SampleSizeAtomType);
	stbl->SampleToChunk = (SampleToChunkAtom *) CreateAtom(SampleToChunkAtomType);
	stbl->TimeToSample = (TimeToSampleAtom *) CreateAtom(TimeToSampleAtomType);

	//Create a data reference WITHOUT DATA ENTRY (we don't know anything yet about the media Data)
	dref = (DataReferenceAtom *) CreateAtom(DataReferenceAtomType);
	e = dinf_AddAtom(dinf, (Atom *)dref); if (e) goto err_exit;

	e = minf_AddAtom(minf, (Atom *) mediaInfo); if (e) goto err_exit;
	e = minf_AddAtom(minf, (Atom *) stbl); if (e) goto err_exit;
	e = minf_AddAtom(minf, (Atom *) dinf); if (e) goto err_exit;

	e = mdia_AddAtom(*mdia, (Atom *) mdhd); if (e) goto err_exit;
	e = mdia_AddAtom(*mdia, (Atom *) minf); if (e) goto err_exit;
	e = mdia_AddAtom(*mdia, (Atom *) hdlr); if (e) goto err_exit;

	return M4OK;

err_exit:
	if (mdhd) DelAtom((Atom *)mdhd);
	if (minf) DelAtom((Atom *)minf);
	if (hdlr) {
		if (hdlr->nameUTF8) free(hdlr->nameUTF8);
		DelAtom((Atom *)hdlr);
	}
	return e;

}
Example #15
0
M4Err ParseAtom(Atom **outAtom, BitStream *bs, u64 *read)
{
	u32 type;
	u64 size;
	u8 uuid[16];
	M4Err e;
	Atom *newAtom;
	char name[5];
	name[4] = 0;
	e = M4OK;
	if ((bs == NULL) || (outAtom == NULL) ) return M4BadParam;
	*outAtom = NULL;

	//read atom header
	size = (u64) BS_ReadInt(bs, 32);
	*read = 4;
	/*fix for some atoms found in some old hinted files*/
	if ((size >= 2) && (size <= 4)) {
		size = 4;
		type = VoidAtomType;
	} else {
		type = BS_ReadInt(bs, 32);
		*read += 4;
		/*no size means till end of file - EXCEPT FOR some old QuickTime atoms...*/
		if (type == totlAtomType)
			size = 12;
		if (!size) 
			size = BS_Available(bs) + 4;
	}
	/*handle uuid*/
	memset(uuid, 0, 16);
	if (type == ExtendedAtomType ) {
		BS_ReadData(bs, (unsigned char *) uuid, 16);
		*read += 16;
	}
	
	//handle large atom
	if (size == 1) {
		size = BS_ReadInt(bs, 64);
		*read += 8;
	}

	if ( size - *read < 0 ) return M4InvalidMP4File;
	//OK, create the atom based on the type
	newAtom = CreateAtom(type);
	if (! newAtom) return M4OutOfMem;

	//OK, init and read this atom
	newAtom->size = size;
	memcpy(newAtom->uuid, uuid, 16);
	if (!newAtom->type) newAtom->type = type; 

	if (newAtom->size - *read > BS_Available(bs) ) {
		*outAtom = newAtom;
		return M4UncompleteFile;
	}
	//we need a special reading for these atoms...
	if (newAtom->type == DegradationPriorityAtomType) {
		*outAtom = newAtom;
		return M4OK;
	}

#if 0
	/*perf test*/
	switch (type) {
	case SampleTableAtomType:
	case TimeToSampleAtomType:
	case SampleToChunkAtomType:
	case CompactSampleSizeAtomType:
	case SampleSizeAtomType:
	case ChunkOffsetAtomType:
	case ChunkLargeOffsetAtomType:
		now = M4_GetSysClock();
		e = ReadAtom(newAtom, bs);
		M4_MP4TypeToString(newAtom->type, name);
		printf("Read atom %s in %d ms\n", name, M4_GetSysClock() - now);
		break;
	default:
		e = ReadAtom(newAtom, bs, read);
		break;
	}
#else
	e = ReadAtom(newAtom, bs, read);	
#endif

	//DON'T DELETE THE MDAT ATOM IF UNCOMPLETE...
	if (e < 0 && e != M4UncompleteFile) {
		DelAtom(newAtom);
		*outAtom = NULL;
		return e;
	}
	*outAtom = newAtom;
	return e;
}
Example #16
0
M4Err M4H_SetupHintTrack(M4File *the_file, u32 trackNumber, u32 HintType)
{
	M4Err e;
	TrackAtom *trak;
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *dpnd;
	HintMediaHeaderAtom *hmhd;
	//UDTA related ...
	UserDataAtom *udta;

	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);
	M4Err moov_AddAtom(MovieAtom *ptr, Atom *a);
	M4Err udta_AddAtom(UserDataAtom *ptr, Atom *a);

	//what do we support
	switch (HintType) {
	case M4_Hint_RTP:
		break;
	default:
		return M4NotSupported;
	}

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak) return M4_GetLastError(the_file);
	if (((M4Movie *)the_file)->openMode != M4_OPEN_EDIT) return M4InvalidMP4Mode;

	//check we have a hint ...
	if ( !IsHintTrack(trak)) {
		return M4BadParam;
	}
	hmhd = (HintMediaHeaderAtom *)trak->Media->information->InfoHeader;
	//make sure the subtype was not already defined
	if (hmhd->subType) return M4HintPresent;
	//store the HintTrack format for later use...
	hmhd->subType = HintType;

	
	//hint tracks always have a tref and everything ...
	if (!trak->References) {
		if (!trak->References) {
			tref = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
			e = trak_AddAtom(trak, (Atom *)tref);
			if (e) return e;
		}
	}
	tref = trak->References;

	//do we have a hint reference on this trak ???
	e = Track_FindRef(trak, HintTrackReferenceAtomType, &dpnd);
	if (e) return e;
	//if yes, return false (existing hint track...)
	if (dpnd) return M4HintPresent;

	//create our dep
	dpnd = (TrackReferenceTypeAtom *) CreateAtom(HintTrackReferenceAtomType);
	e = tref_AddAtom(tref, (Atom *) dpnd);
	if (e) return e;

	//for RTP, we need to do some UDTA-related stuff...
	if (HintType != M4_Hint_RTP) return M4OK;

	if (!trak->udta) {
		//create one
		udta = (UserDataAtom *) CreateAtom(UserDataAtomType);
		e = trak_AddAtom(trak, (Atom *) udta);
		if (e) return e;
	}
	udta = trak->udta;
	//end-of-udta marker for Darwin...
//	if (!udta->voidAtom) {
//		e = udta_AddAtom(udta, CreateAtom(VoidAtomType));
//		if (e) return e;
//	}

	//HNTI
	e = udta_AddAtom(udta, CreateAtom(HintTrackInfoAtomType));
	if (e) return e;

/*
	//NAME
	e = udta_AddAtom(udta, CreateAtom(nameAtomType));
	if (e) return e;
	//HINF
	return udta_AddAtom(udta, CreateAtom(HintInfoAtomType));
*/
	return M4OK;
}
Example #17
0
// Update the dependancies when an OD AU is inserted in the file
M4Err Media_ParseODFrame(MediaAtom *mdia, M4Sample *sample)
{
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *mpod;
	M4Err e;
	ODCommand *com;
	LPODCODEC ODencode;
	LPODCODEC ODdecode;
	u32 i, j;

	//the commands we proceed
	ESDescriptorUpdate *esdU, *esdU2;
	ESDescriptorRemove *esdR, *esdR2;
	ObjectDescriptorUpdate *odU, *odU2;

	//the desc they contain
	ObjectDescriptor *od;
	M4F_ObjectDescriptor *m4_od;
	ESDescriptor *esd;
	ES_ID_Ref *ref;
	Descriptor *desc;
	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);
	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);

	if (!mdia || !sample || !sample->data || !sample->dataLength) return M4BadParam;

	//First find the references, and create them if none
	tref = mdia->mediaTrack->References;
	if (!tref) {
		tref = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
		e = trak_AddAtom(mdia->mediaTrack, (Atom *) tref);
		if (e) return e;
	}
	//then find the OD reference, and create it if none
	e = Track_FindRef(mdia->mediaTrack, ODTrackReferenceAtomType, &mpod);
	if (e) return e;
	if (!mpod) {
		mpod = (TrackReferenceTypeAtom *) CreateAtom(ODTrackReferenceAtomType);
		e = tref_AddAtom(tref, (Atom *)mpod);
		if (e) return e;
	}

	//OK, create our codecs
	ODencode = OD_NewCodec(OD_WRITE);
	if (!ODencode) return M4OutOfMem;
	ODdecode = OD_NewCodec(OD_READ);
	if (!ODdecode) return M4OutOfMem;

	e = OD_SetBuffer(ODdecode, sample->data, sample->dataLength);
	if (e) goto err_exit;
	e = OD_DecodeAU(ODdecode);
	if (e) goto err_exit;

	while (1) {
		com = OD_GetCommand(ODdecode);
		if (!com) break;

		//check our commands
		switch (com->tag) {
		//Rewrite OD Update
		case ODUpdate_Tag:
			//duplicate our command
			odU = (ObjectDescriptorUpdate *) com;
			odU2 = (ObjectDescriptorUpdate *) OD_NewCommand(ODUpdate_Tag);

			for (i = 0; i < ChainGetCount(odU->objectDescriptors); i++) {
				desc = (Descriptor*)ChainGetEntry(odU->objectDescriptors, i);
				//both OD and IODs are accepted
				switch (desc->tag) {
				case ObjectDescriptor_Tag:
				case InitialObjectDescriptor_Tag:
					break;
				default:
					e = M4InvalidDescriptor;
					goto err_exit;
				}
				//get the esd
				e = OD_DuplicateDescriptor(desc, (Descriptor **)&od);
				if (e) goto err_exit;
				if (desc->tag == ObjectDescriptor_Tag) {
					m4_od = (M4F_ObjectDescriptor *) malloc(sizeof(M4F_ObjectDescriptor));
					m4_od->tag = MP4_OD_Tag;
				} else {
					m4_od = (M4F_ObjectDescriptor *) malloc(sizeof(M4F_InitialObjectDescriptor));
					m4_od->tag = MP4_IOD_Tag;
					//copy PL
					((M4F_InitialObjectDescriptor *)m4_od)->inlineProfileFlag = ((InitialObjectDescriptor *)od)->inlineProfileFlag;
					((M4F_InitialObjectDescriptor *)m4_od)->graphics_profileAndLevel = ((InitialObjectDescriptor *)od)->graphics_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->audio_profileAndLevel = ((InitialObjectDescriptor *)od)->audio_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->OD_profileAndLevel = ((InitialObjectDescriptor *)od)->OD_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->scene_profileAndLevel = ((InitialObjectDescriptor *)od)->scene_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->visual_profileAndLevel = ((InitialObjectDescriptor *)od)->visual_profileAndLevel;
				}
				//in OD stream only ref desc are accepted
				m4_od->ES_ID_RefDescriptors = NewChain();
				m4_od->ES_ID_IncDescriptors = NULL;
	
				//TO DO: check that a given sampleDescription exists
				m4_od->extensionDescriptors = od->extensionDescriptors;
				od->extensionDescriptors = NULL;
				m4_od->IPMPDescriptorPointers = od->IPMPDescriptorPointers;
				od->IPMPDescriptorPointers = NULL;
				m4_od->OCIDescriptors = od->OCIDescriptors;
				od->OCIDescriptors = NULL;
				m4_od->URLString = od->URLString;
				od->URLString = NULL;
				m4_od->objectDescriptorID = od->objectDescriptorID;

				for (j = 0; j < ChainGetCount(od->ESDescriptors); j++) {
					esd =(ESDescriptor*)ChainGetEntry(od->ESDescriptors, j);
					ref = (ES_ID_Ref *) OD_NewDescriptor(ES_ID_RefTag);
					//1 to 1 mapping trackID and ESID. Add this track to MPOD
					//if track does not exist, this will be remove while reading the OD stream
					e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef);
					e = OD_AddDescToDesc((Descriptor *)m4_od, (Descriptor *)ref);
					if (e) goto err_exit;
				}
				//delete our desc
				OD_DeleteDescriptor((Descriptor **)&od);
				//and add the new one to our command
				ChainAddEntry(odU2->objectDescriptors, m4_od);
			}
			//delete the command
			OD_DeleteCommand((ODCommand **)&odU);
			//and add the new one to the codec
			OD_AddCommand(ODencode, (ODCommand *)odU2);
			break;

		//Rewrite ESD Update
		case ESDUpdate_Tag:
			esdU = (ESDescriptorUpdate *) com;
			esdU2 = (ESDescriptorUpdate *) OD_NewCommand(ESDUpdate_Tag);
			esdU2->ODID = esdU->ODID;
			for (i = 0; i< ChainGetCount(esdU->ESDescriptors); i++) {
				esd = (ESDescriptor*)ChainGetEntry(esdU->ESDescriptors, i);
				ref = (ES_ID_Ref *) OD_NewDescriptor(ES_ID_RefTag);
				//1 to 1 mapping trackID and ESID
				e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef);
				e = ChainAddEntry(esdU2->ESDescriptors, ref);
				if (e) goto err_exit;
			}
			OD_DeleteCommand((ODCommand **)&esdU);
			OD_AddCommand(ODencode, (ODCommand *)esdU2);
			break;

		//Brand new case: the ESRemove has to be rewritten too according to the specs...
		case ESDRemove_Tag:
			esdR = (ESDescriptorRemove *) com;
			esdR2 = (ESDescriptorRemove *) OD_NewCommand(ESDRemove_Tag);
			//change the tag for the file format
			esdR2->tag = ESDRemove_Ref_Tag;
			esdR2->ODID = esdR->ODID;
			esdR2->NbESDs = esdR->NbESDs;
			//alloc our stuff
			esdR2->ES_ID = (unsigned short*)malloc(sizeof(u32) * esdR->NbESDs);
			if (!esdR2->ES_ID) {
				e = M4OutOfMem;
				goto err_exit;
			}
			for (i = 0; i < esdR->NbESDs; i++) {
				//1 to 1 mapping trackID and ESID
				e = reftype_AddRefTrack(mpod, esdR->ES_ID[i], &esdR2->ES_ID[i]);
				if (e) goto err_exit;
			}
			OD_DeleteCommand(&com);
			OD_AddCommand(ODencode, (ODCommand *)esdR2);
			break;

		//Add the command as is
		default:
			e = OD_AddCommand(ODencode, com);
			if (e) goto err_exit;
		}
	}

	//encode our new AU
	e = OD_EncodeAU(ODencode);
	if (e) goto err_exit;

	//and set the buffer in the sample
	free(sample->data);
	sample->data = NULL;
	sample->dataLength = 0;
	e = OD_GetEncodedAU(ODencode, &sample->data, &sample->dataLength);

err_exit:

	OD_DeleteCodec(ODencode);
	OD_DeleteCodec(ODdecode);
	return e;
}
Example #18
0
M4Err Track_SetStreamDescriptor(TrackAtom *trak, u32 StreamDescriptionIndex, u32 DataReferenceIndex, ESDescriptor *esd, u32 *outStreamIndex)
{
	M4Err e;
	MPEGSampleEntryAtom *entry;
	MPEGVisualSampleEntryAtom *entry_v;
	MPEGAudioSampleEntryAtom *entry_a;
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *dpnd;
	u16 tmpRef;

	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);
	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);
	M4Err stsd_AddAtom(SampleDescriptionAtom *ptr, Atom *a);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);

	entry = NULL;
	tref = NULL;

	if (!trak || !esd || (!outStreamIndex && !DataReferenceIndex) ) return M4BadParam;
	if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) return M4InvalidMP4Media;

	
	esd->ESID = 0;
	//set SL to predefined if no url
	if (esd->URLString == NULL) {
		esd->slConfig->predefined = SLPredef_MP4;
		esd->slConfig->durationFlag = 0;
		esd->slConfig->useTimestampsFlag = 1;
	}

	//get the REF atom if needed
	if (esd->dependsOnESID  || esd->OCRESID ) {
		if (!trak->References) {
			tref = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
			e = trak_AddAtom(trak, (Atom *)tref);
			if (e) return e;
		}
		tref = trak->References;
	}

	//Update Stream dependancies
	e = Track_FindRef(trak, M4_StreamDependence_Ref, &dpnd);
	if (e) return e;
	if (!dpnd && esd->dependsOnESID) {
		dpnd = (TrackReferenceTypeAtom *) CreateAtom(StreamDependenceAtomType);
		e = tref_AddAtom(tref, (Atom *) dpnd);
		if (e) return e;
		e = reftype_AddRefTrack(dpnd, esd->dependsOnESID, NULL);
		if (e) return e;
	} else if (dpnd && !esd->dependsOnESID) {
		Track_RemoveRef(trak, StreamDependenceAtomType);
	}
	esd->dependsOnESID = 0;

	//Update Clock dependancies
	e = Track_FindRef(trak, M4_OCR_Ref, &dpnd);
	if (e) return e;
	if (!dpnd && esd->OCRESID) {
		dpnd = (TrackReferenceTypeAtom *) CreateAtom(OCRReferenceAtomType);
		e = tref_AddAtom(tref, (Atom *) dpnd);
		if (e) return e;
		e = reftype_AddRefTrack(dpnd, esd->OCRESID, NULL);
		if (e) return e;
	} else if (dpnd && !esd->OCRESID) {
		Track_RemoveRef(trak, OCRReferenceAtomType);
	} else if (dpnd && esd->OCRESID) {
		if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
		dpnd->trackIDs[0] = esd->OCRESID;
	}
	esd->OCRESID = 0;

	//brand new case: we have to change the IPI desc
	if (esd->ipiPtr) {
		e = Track_FindRef(trak, M4_IPI_Ref, &dpnd);
		if (e) return e;
		if (!dpnd) {
			tmpRef = 0;
			dpnd = (TrackReferenceTypeAtom *) CreateAtom(IPIReferenceAtomType);
			e = tref_AddAtom(tref, (Atom *) dpnd);
			if (e) return e;
			e = reftype_AddRefTrack(dpnd, esd->ipiPtr->IPI_ES_Id, &tmpRef);
			if (e) return e;
			//and replace the tag and value...
			esd->ipiPtr->IPI_ES_Id = tmpRef;
			esd->ipiPtr->tag = IPI_DescPtr_Tag;
		} else {
			//Watch out! ONLY ONE IPI dependancy is allowed per stream
			if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
			//if an existing one is there, what shall we do ???
			//donno, erase it
			dpnd->trackIDs[0] = esd->ipiPtr->IPI_ES_Id;
			//and replace the tag and value...
			esd->ipiPtr->IPI_ES_Id = 1;
			esd->ipiPtr->tag = IPI_DescPtr_Tag;
		}
	}

	//we have a streamDescritpionIndex, use it
	if (StreamDescriptionIndex) {
		entry = (MPEGSampleEntryAtom*)ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, StreamDescriptionIndex - 1);
		if (!entry) return M4InvalidMP4File;

		switch (entry->type) {
		case MPEGSampleEntryAtomType:
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry->esd->desc);
			if (e) return e;
			entry->esd->desc = esd;
			break;
		case MPEGVisualSampleEntryAtomType:
			entry_v = (MPEGVisualSampleEntryAtom*) entry;
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry_v->esd->desc);
			if (e) return e;
			entry_v->esd->desc = esd;
			break;
		case MPEGAudioSampleEntryAtomType:
			entry_a = (MPEGAudioSampleEntryAtom*) entry;
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry_a->esd->desc);
			if (e) return e;
			entry_a->esd->desc = esd;
			break;
		}
	} else {
		//need to check we're not in URL mode where only ONE description is allowed...
		StreamDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
		if (StreamDescriptionIndex) {
			entry = (MPEGSampleEntryAtom*)ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, StreamDescriptionIndex - 1);
			if (!entry) return M4InvalidMP4File;
			if (entry->esd->desc->URLString) return M4BadParam;
		}

		//OK, check the handler and create the entry
		switch (trak->Media->handler->handlerType) {
		case M4_VisualMediaType:
			entry_v = (MPEGVisualSampleEntryAtom *) CreateAtom(MPEGVisualSampleEntryAtomType);
			if (!entry_v) return M4OutOfMem;
			//create an esdAtom
			entry_v->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry_v->esd->desc = esd;

			//type cast possible now
			entry = (MPEGSampleEntryAtom*) entry_v;
			break;
		case M4_AudioMediaType:
			entry_a = (MPEGAudioSampleEntryAtom *) CreateAtom(MPEGAudioSampleEntryAtomType);
			entry_a->samplerate_hi = trak->Media->mediaHeader->timeScale;
			if (!entry_a) return M4OutOfMem;
			//create an esdAtom
			entry_a->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry_a->esd->desc = esd;
			//type cast possible now
			entry = (MPEGSampleEntryAtom*) entry_a;
			break;
		case M4_ODMediaType:
		case M4_OCRMediaType:
		case M4_BIFSMediaType:
		case M4_MPEG7MediaType:
		case M4_OCIMediaType:
		case M4_IPMPMediaType:
		case M4_MPEGJMediaType:
			entry = (MPEGSampleEntryAtom *) CreateAtom(MPEGSampleEntryAtomType);
			//create an esdAtom
			entry->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry->esd->desc = esd;
			break;
		}
		entry->dataReferenceIndex = DataReferenceIndex;

		//and add the entry to our table...
		e = stsd_AddAtom(trak->Media->information->sampleTable->SampleDescription, (Atom *) entry);
		if (e) return e;
		if(outStreamIndex) *outStreamIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	}
	return M4OK;
}
Example #19
0
//This functions unpack the offset for easy editing, eg each sample
//is contained in one chunk...
M4Err stbl_UnpackOffsets(SampleTableAtom *stbl)
{
	M4Err e;
	u8 isEdited;
	u32 i, chunkNumber, sampleDescIndex;
	u64 dataOffset;
	stscEntry *ent;
	ChunkOffsetAtom *stco_tmp;
	ChunkLargeOffsetAtom *co64_tmp;
	SampleToChunkAtom *stsc_tmp;

	if (!stbl) return M4InvalidMP4File;

	//we should have none of the mandatory atoms (allowed in the spec)
	if (!stbl->ChunkOffset && !stbl->SampleDescription && !stbl->SampleSize && !stbl->SampleToChunk && !stbl->TimeToSample)
		return M4OK;
	//or all the mandatory ones ...
	if (!stbl->ChunkOffset || !stbl->SampleDescription || !stbl->SampleSize || !stbl->SampleToChunk || !stbl->TimeToSample)
		return M4InvalidMP4File;

	//do we need to unpack? Not if we have only one sample per chunk.
	if (stbl->SampleSize->sampleCount == ChainGetCount(stbl->SampleToChunk->entryList)) return M4OK;

	//create a new SampleToChunk table
	stsc_tmp = (SampleToChunkAtom *) CreateAtom(SampleToChunkAtomType);

	//check the offset type and create a new table...
	if (stbl->ChunkOffset->type == ChunkOffsetAtomType) {
		co64_tmp = NULL;
		stco_tmp = (ChunkOffsetAtom *) CreateAtom(ChunkOffsetAtomType);
		stco_tmp->entryCount = stbl->SampleSize->sampleCount;
		stco_tmp->offsets = (u32*)malloc(stco_tmp->entryCount * sizeof(u32));
	} else if (stbl->ChunkOffset->type == ChunkLargeOffsetAtomType) {
		stco_tmp = NULL;
		co64_tmp = (ChunkLargeOffsetAtom *) CreateAtom(ChunkLargeOffsetAtomType);
		co64_tmp->entryCount = stbl->SampleSize->sampleCount;
		co64_tmp->offsets = (u64*)malloc(co64_tmp->entryCount * sizeof(u64));
	} else {
		return M4InvalidMP4File;
	}

	ent = NULL;
	//OK write our two tables...
	for (i = 0; i < stbl->SampleSize->sampleCount; i++) {
		//get the data info for the sample
		e = stbl_GetSampleInfos(stbl, i+1, &dataOffset, &chunkNumber, &sampleDescIndex, &isEdited);
		if (e) goto err_exit;
		ent = (stscEntry*)malloc(sizeof(stscEntry));
		ent->isEdited = 0;
		ent->sampleDescriptionIndex = sampleDescIndex;
		//here's the trick: each sample is in ONE chunk
		ent->firstChunk = i+1;
		ent->nextChunk = i+2;
		ent->samplesPerChunk = 1;
		e = ChainAddEntry(stsc_tmp->entryList, ent);
		if (e) goto err_exit;
		if (stco_tmp) {
			stco_tmp->offsets[i] = (u32) dataOffset;
		} else {
			co64_tmp->offsets[i] = dataOffset;
		}
	}
	//close the list
	if (ent) ent->nextChunk = 0;
	

	//done, remove our previous tables
	DelAtom(stbl->ChunkOffset);
	DelAtom((Atom *)stbl->SampleToChunk);
	//and set these ones...
	if (stco_tmp) {
		stbl->ChunkOffset = (Atom *)stco_tmp;
	} else {
		stbl->ChunkOffset = (Atom *)co64_tmp;
	}
	stbl->SampleToChunk = stsc_tmp;
	stbl->SampleToChunk->currentEntry = (stscEntry*)ChainGetEntry(stbl->SampleToChunk->entryList, 0);
	stbl->SampleToChunk->currentIndex = 0;
	stbl->SampleToChunk->currentChunk = 0;
	stbl->SampleToChunk->firstSampleInCurrentChunk = 0;
	return M4OK;

err_exit:
	if (stco_tmp) DelAtom((Atom *) stco_tmp);
	if (co64_tmp) DelAtom((Atom *) co64_tmp);
	if (stsc_tmp) DelAtom((Atom *) stsc_tmp);
	return e;
}
Example #20
0
//add an SDP line to the SDP container at the movie level (presentation SDP info)
//NOTE: the \r\n end of line for SDP is automatically inserted
M4Err M4H_SDP_MovieAddLine(M4File *the_file, const char *text)
{
	M4Movie *mov;
	UserDataMap *map;
	RTPAtom *rtp;
	M4Err e;
	HintTrackInfoAtom *hnti;
	char *buf;

	M4Err udta_AddAtom(UserDataAtom *ptr, Atom *a);
	M4Err hnti_AddAtom(HintTrackInfoAtom *hnti, Atom *a);
	M4Err moov_AddAtom(MovieAtom *moov, Atom *a);

	mov = (M4Movie *)the_file;
	//check if we have a udta ...
	if (!mov->moov->udta) {
		e = moov_AddAtom(mov->moov, CreateAtom(UserDataAtomType));
		if (e) return e;
	}
	//find a hnti in the udta
	map = udta_getEntry(mov->moov->udta, HintTrackInfoAtomType);
	if (!map) {
		e = udta_AddAtom(mov->moov->udta, CreateAtom(HintTrackInfoAtomType));
		if (e) return e;
		map = udta_getEntry(mov->moov->udta, HintTrackInfoAtomType);
	}

	//there should be one and only one hnti
	if (!ChainGetCount(map->atomList) ) {
		e = udta_AddAtom(mov->moov->udta, CreateAtom(HintTrackInfoAtomType));
		if (e) return e;
	}
	else if (ChainGetCount(map->atomList) < 1) return M4InvalidMP4File;

	hnti = ChainGetEntry(map->atomList, 0);

	if (!hnti->SDP) {
		//we have to create it by hand, as we have a duplication of atom type 
		//(RTPSampleEntryAtom and RTPAtom have the same type...)
		rtp = malloc(sizeof(RTPAtom));
		rtp->subType = SDPAtomType;
		rtp->type = RTPAtomType;
		rtp->sdpText = NULL;
		hnti_AddAtom(hnti, (Atom *)rtp);
	}
	rtp = (RTPAtom *) hnti->SDP;

	if (!rtp->sdpText) {
		rtp->sdpText = malloc(sizeof(char) * (strlen(text) + 3));
		strcpy(rtp->sdpText, text);
		strcat(rtp->sdpText, "\r\n");
		return M4OK;
	}
	buf = malloc(sizeof(char) * (strlen(rtp->sdpText) + strlen(text) + 3));
	strcpy(buf, rtp->sdpText);
	strcat(buf, text);
	strcat(buf, "\r\n");
	free(rtp->sdpText);
	rtp->sdpText = buf;	
	return M4OK;
}