1 /*
2 *			GPAC - Multimedia Framework C SDK
3 *
4 *			Authors: Jean Le Feuvre
5 *			Copyright (c) Telecom ParisTech 2000-2012
6 *					All rights reserved
7 *
8 *  This file is part of GPAC / ISO Media File Format sub-project
9 *
10 *  GPAC is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License as published by
12 *  the Free Software Foundation; either version 2, or (at your option)
13 *  any later version.
14 *
15 *  GPAC is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Lesser General Public License for more details.
19 *
20 *  You should have received a copy of the GNU Lesser General Public
21 *  License along with this library; see the file COPYING.  If not, write to
22 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 
26 #include <gpac/internal/isomedia_dev.h>
27 
28 #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)
29 
ghnt_New()30 GF_Box *ghnt_New()
31 {
32 	GF_HintSampleEntryBox *tmp;
33 	GF_SAFEALLOC(tmp, GF_HintSampleEntryBox);
34 	if (tmp == NULL) return NULL;
35 	tmp->HintDataTable = gf_list_new();
36 	if (!tmp->HintDataTable) {
37 		gf_free(tmp);
38 		return NULL;
39 	}
40 	//this type is used internally for protocols that share the same base entry
41 	//currently only RTP uses this, but a flexMux could use this entry too...
42 	tmp->type = GF_ISOM_BOX_TYPE_GHNT;
43 	tmp->HintTrackVersion = 1;
44 	tmp->LastCompatibleVersion = 1;
45 	return (GF_Box *)tmp;
46 }
47 
ghnt_del(GF_Box * s)48 void ghnt_del(GF_Box *s)
49 {
50 	GF_HintSampleEntryBox *ptr;
51 
52 	ptr = (GF_HintSampleEntryBox *)s;
53 	gf_isom_box_array_del(ptr->HintDataTable);
54 	if (ptr->hint_sample) gf_isom_hint_sample_del(ptr->hint_sample);
55 	gf_free(ptr);
56 }
57 
ghnt_Read(GF_Box * s,GF_BitStream * bs)58 GF_Err ghnt_Read(GF_Box *s, GF_BitStream *bs)
59 {
60 	GF_Box *a;
61 	GF_Err e;
62 	GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
63 	if (ptr == NULL) return GF_BAD_PARAM;
64 
65 	if (ptr->size < 16) return GF_ISOM_INVALID_FILE;
66 
67 	gf_bs_read_data(bs, ptr->reserved, 6);
68 	ptr->dataReferenceIndex = gf_bs_read_u16(bs);
69 	ptr->HintTrackVersion = gf_bs_read_u16(bs);
70 	ptr->LastCompatibleVersion = gf_bs_read_u16(bs);
71 	ptr->MaxPacketSize = gf_bs_read_u32(bs);
72 	ptr->size -= 16;
73 
74 	while (ptr->size) {
75 		e = gf_isom_parse_box(&a, bs);
76 		if (e) return e;
77 		e = gf_list_add(ptr->HintDataTable, a);
78 		if (e) return e;
79 		ptr->size -= a->size;
80 	}
81 	return GF_OK;
82 }
83 
84 #ifndef GPAC_DISABLE_ISOM_WRITE
85 
ghnt_Write(GF_Box * s,GF_BitStream * bs)86 GF_Err ghnt_Write(GF_Box *s, GF_BitStream *bs)
87 {
88 	GF_Err e;
89 	GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
90 
91 	e = gf_isom_box_write_header(s, bs);
92 	if (e) return e;
93 	gf_bs_write_data(bs, ptr->reserved, 6);
94 	gf_bs_write_u16(bs, ptr->dataReferenceIndex);
95 	gf_bs_write_u16(bs, ptr->HintTrackVersion);
96 	gf_bs_write_u16(bs, ptr->LastCompatibleVersion);
97 	gf_bs_write_u32(bs, ptr->MaxPacketSize);
98 	return gf_isom_box_array_write(s, ptr->HintDataTable, bs);
99 }
100 
ghnt_Size(GF_Box * s)101 GF_Err ghnt_Size(GF_Box *s)
102 {
103 	GF_Err e;
104 	GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
105 
106 	e = gf_isom_box_get_size(s);
107 	if (e) return e;
108 	ptr->size += 16;
109 	e = gf_isom_box_array_size(s, ptr->HintDataTable);
110 	if (e) return e;
111 	return GF_OK;
112 }
113 
114 
115 #endif /*GPAC_DISABLE_ISOM_WRITE*/
116 
117 
gf_isom_hint_sample_new(u32 ProtocolType)118 GF_HintSample *gf_isom_hint_sample_new(u32 ProtocolType)
119 {
120 	GF_HintSample *tmp;
121 	u8 type;
122 
123 	switch (ProtocolType) {
124 	case GF_ISOM_BOX_TYPE_RTP_STSD:
125 		type = GF_ISMO_HINT_RTP;
126 		break;
127 	default:
128 		return NULL;
129 	}
130 	GF_SAFEALLOC(tmp, GF_HintSample);
131 	if (!tmp) return NULL;
132 	tmp->packetTable = gf_list_new();
133 	tmp->HintType = type;
134 	return tmp;
135 }
136 
gf_isom_hint_sample_del(GF_HintSample * ptr)137 void gf_isom_hint_sample_del(GF_HintSample *ptr)
138 {
139 	GF_HintPacket *pck;
140 
141 	while (gf_list_count(ptr->packetTable)) {
142 		pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, 0);
143 		gf_isom_hint_pck_del(ptr->HintType, pck);
144 		gf_list_rem(ptr->packetTable, 0);
145 	}
146 	gf_list_del(ptr->packetTable);
147 	if (ptr->AdditionalData) gf_free(ptr->AdditionalData);
148 
149 	if (ptr->sample_cache) {
150 		while (gf_list_count(ptr->sample_cache)) {
151 			GF_HintDataCache *hdc = (GF_HintDataCache *)gf_list_get(ptr->sample_cache, 0);
152 			gf_list_rem(ptr->sample_cache, 0);
153 			if (hdc->samp) gf_isom_sample_del(&hdc->samp);
154 			gf_free(hdc);
155 		}
156 		gf_list_del(ptr->sample_cache);
157 	}
158 	gf_free(ptr);
159 }
160 
gf_isom_hint_sample_read(GF_HintSample * ptr,GF_BitStream * bs,u32 sampleSize)161 GF_Err gf_isom_hint_sample_read(GF_HintSample *ptr, GF_BitStream *bs, u32 sampleSize)
162 {
163 	u16 entryCount, i;
164 	GF_HintPacket *pck;
165 	GF_Err e;
166 	u64 sizeIn, sizeOut;
167 
168 	sizeIn = gf_bs_available(bs);
169 
170 	entryCount = gf_bs_read_u16(bs);
171 	ptr->reserved = gf_bs_read_u16(bs);
172 
173 	for (i = 0; i < entryCount; i++) {
174 		pck = gf_isom_hint_pck_new(ptr->HintType);
175 		e = gf_isom_hint_pck_read(ptr->HintType, pck, bs);
176 		if (e) return e;
177 		gf_list_add(ptr->packetTable, pck);
178 	}
179 
180 	sizeOut = gf_bs_available(bs) - sizeIn;
181 
182 	//do we have some more data after the packets ??
183 	if ((u32)sizeOut < sampleSize) {
184 		ptr->dataLength = sampleSize - (u32)sizeOut;
185 		ptr->AdditionalData = (char*)gf_malloc(sizeof(char) * ptr->dataLength);
186 		gf_bs_read_data(bs, ptr->AdditionalData, ptr->dataLength);
187 	}
188 	return GF_OK;
189 }
190 
191 
192 #ifndef GPAC_DISABLE_ISOM_WRITE
193 
gf_isom_hint_sample_write(GF_HintSample * ptr,GF_BitStream * bs)194 GF_Err gf_isom_hint_sample_write(GF_HintSample *ptr, GF_BitStream *bs)
195 {
196 	u32 count, i;
197 	GF_HintPacket *pck;
198 	GF_Err e;
199 
200 	count = gf_list_count(ptr->packetTable);
201 	gf_bs_write_u16(bs, count);
202 	gf_bs_write_u16(bs, ptr->reserved);
203 	//write the packet table
204 	for (i = 0; i<count; i++) {
205 		pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
206 		e = gf_isom_hint_pck_write(ptr->HintType, pck, bs);
207 		if (e) return e;
208 	}
209 	//write additional data
210 	if (ptr->AdditionalData) {
211 		gf_bs_write_data(bs, ptr->AdditionalData, ptr->dataLength);
212 	}
213 	return GF_OK;
214 }
215 
216 
gf_isom_hint_sample_size(GF_HintSample * ptr)217 u32 gf_isom_hint_sample_size(GF_HintSample *ptr)
218 {
219 	u32 size, count, i;
220 	GF_HintPacket *pck;
221 
222 	size = 4;
223 	count = gf_list_count(ptr->packetTable);
224 	for (i = 0; i<count; i++) {
225 		pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
226 		size += gf_isom_hint_pck_size(ptr->HintType, pck);
227 	}
228 	size += ptr->dataLength;
229 	return size;
230 }
231 
232 #endif /*GPAC_DISABLE_ISOM_WRITE*/
233 
234 
235 
gf_isom_hint_pck_new(u8 HintType)236 GF_HintPacket *gf_isom_hint_pck_new(u8 HintType)
237 {
238 	switch (HintType) {
239 	case GF_ISMO_HINT_RTP:
240 		return (GF_HintPacket *)gf_isom_hint_rtp_new();
241 	default:
242 		return NULL;
243 	}
244 }
245 
gf_isom_hint_pck_del(u8 HintType,GF_HintPacket * ptr)246 void gf_isom_hint_pck_del(u8 HintType, GF_HintPacket *ptr)
247 {
248 	switch (HintType) {
249 	case GF_ISMO_HINT_RTP:
250 		gf_isom_hint_rtp_del((GF_RTPPacket *)ptr);
251 		break;
252 	default:
253 		break;
254 	}
255 }
256 
gf_isom_hint_pck_read(u8 HintType,GF_HintPacket * ptr,GF_BitStream * bs)257 GF_Err gf_isom_hint_pck_read(u8 HintType, GF_HintPacket *ptr, GF_BitStream *bs)
258 {
259 	switch (HintType) {
260 	case GF_ISMO_HINT_RTP:
261 		return gf_isom_hint_rtp_read((GF_RTPPacket *)ptr, bs);
262 	default:
263 		return GF_NOT_SUPPORTED;
264 	}
265 }
266 
267 #ifndef GPAC_DISABLE_ISOM_WRITE
268 
gf_isom_hint_pck_write(u8 HintType,GF_HintPacket * ptr,GF_BitStream * bs)269 GF_Err gf_isom_hint_pck_write(u8 HintType, GF_HintPacket *ptr, GF_BitStream *bs)
270 {
271 	switch (HintType) {
272 	case GF_ISMO_HINT_RTP:
273 		return gf_isom_hint_rtp_write((GF_RTPPacket *)ptr, bs);
274 	default:
275 		return GF_NOT_SUPPORTED;
276 	}
277 }
278 
gf_isom_hint_pck_size(u8 HintType,GF_HintPacket * ptr)279 u32 gf_isom_hint_pck_size(u8 HintType, GF_HintPacket *ptr)
280 {
281 	switch (HintType) {
282 	case GF_ISMO_HINT_RTP:
283 		return gf_isom_hint_rtp_size((GF_RTPPacket *)ptr);
284 	default:
285 		return 0;
286 	}
287 }
288 
gf_isom_hint_pck_offset(u8 HintType,GF_HintPacket * ptr,u32 offset,u32 HintSampleNumber)289 GF_Err gf_isom_hint_pck_offset(u8 HintType, GF_HintPacket *ptr, u32 offset, u32 HintSampleNumber)
290 {
291 	switch (HintType) {
292 	case GF_ISMO_HINT_RTP:
293 		return gf_isom_hint_rtp_offset((GF_RTPPacket *)ptr, offset, HintSampleNumber);
294 	default:
295 		return GF_NOT_SUPPORTED;
296 	}
297 }
298 
gf_isom_hint_pck_add_dte(u8 HintType,GF_HintPacket * ptr,GF_GenericDTE * dte,u8 AtBegin)299 GF_Err gf_isom_hint_pck_add_dte(u8 HintType, GF_HintPacket *ptr, GF_GenericDTE *dte, u8 AtBegin)
300 {
301 	switch (HintType) {
302 	case GF_ISMO_HINT_RTP:
303 		if (AtBegin)
304 			return gf_list_insert(((GF_RTPPacket *)ptr)->DataTable, dte, 0);
305 		else
306 			return gf_list_add(((GF_RTPPacket *)ptr)->DataTable, dte);
307 
308 	default:
309 		return GF_NOT_SUPPORTED;
310 	}
311 }
312 
gf_isom_hint_pck_length(u8 HintType,GF_HintPacket * ptr)313 u32 gf_isom_hint_pck_length(u8 HintType, GF_HintPacket *ptr)
314 {
315 	switch (HintType) {
316 	case GF_ISMO_HINT_RTP:
317 		return gf_isom_hint_rtp_length((GF_RTPPacket *)ptr);
318 	default:
319 		return 0;
320 	}
321 }
322 
323 
324 #endif /*GPAC_DISABLE_ISOM_WRITE*/
325 
326 
327 
328 /********************************************************************
329 Creation of DataTable entries in the RTP sample
330 ********************************************************************/
331 
New_EmptyDTE()332 GF_GenericDTE *New_EmptyDTE()
333 {
334 	GF_EmptyDTE *dte = (GF_EmptyDTE *)gf_malloc(sizeof(GF_EmptyDTE));
335 	dte->source = 0;
336 	return (GF_GenericDTE *)dte;
337 }
338 
New_ImmediateDTE()339 GF_GenericDTE *New_ImmediateDTE()
340 {
341 	GF_ImmediateDTE *dte;
342 	GF_SAFEALLOC(dte, GF_ImmediateDTE);
343 	if (dte) {
344 		dte->source = 1;
345 		dte->dataLength = 0;
346 	}
347 	return (GF_GenericDTE *)dte;
348 }
349 
New_SampleDTE()350 GF_GenericDTE *New_SampleDTE()
351 {
352 	GF_SampleDTE *dte = (GF_SampleDTE *)gf_malloc(sizeof(GF_SampleDTE));
353 	dte->source = 2;
354 	//can be -1 in QT , so init at -2
355 	dte->trackRefIndex = (s8)-2;
356 	dte->dataLength = 0;
357 	dte->sampleNumber = 0;
358 	dte->samplesPerComp = 1;
359 	dte->byteOffset = 0;
360 	dte->bytesPerComp = 1;
361 	return (GF_GenericDTE *)dte;
362 }
363 
New_StreamDescDTE()364 GF_GenericDTE *New_StreamDescDTE()
365 {
366 	GF_StreamDescDTE *dte = (GF_StreamDescDTE *)gf_malloc(sizeof(GF_StreamDescDTE));
367 	dte->source = 3;
368 	dte->byteOffset = 0;
369 	dte->dataLength = 0;
370 	dte->reserved = 0;
371 	dte->streamDescIndex = 0;
372 	//can be -1 in QT , so init at -2
373 	dte->trackRefIndex = (s8)-2;
374 	return (GF_GenericDTE *)dte;
375 }
376 
377 //creation of DTEs
NewDTE(u8 type)378 GF_GenericDTE *NewDTE(u8 type)
379 {
380 	switch (type) {
381 	case 0:
382 		return New_EmptyDTE();
383 	case 1:
384 		return New_ImmediateDTE();
385 	case 2:
386 		return New_SampleDTE();
387 	case 3:
388 		return New_StreamDescDTE();
389 	default:
390 		return NULL;
391 	}
392 }
393 
394 /********************************************************************
395 Deletion of DataTable entries in the RTP sample
396 ********************************************************************/
Del_EmptyDTE(GF_EmptyDTE * dte)397 void Del_EmptyDTE(GF_EmptyDTE *dte)
398 {
399 	gf_free(dte);
400 }
401 
Del_ImmediateDTE(GF_ImmediateDTE * dte)402 void Del_ImmediateDTE(GF_ImmediateDTE *dte)
403 {
404 	gf_free(dte);
405 }
406 
Del_SampleDTE(GF_SampleDTE * dte)407 void Del_SampleDTE(GF_SampleDTE *dte)
408 {
409 	gf_free(dte);
410 }
411 
Del_StreamDescDTE(GF_StreamDescDTE * dte)412 void Del_StreamDescDTE(GF_StreamDescDTE *dte)
413 {
414 	gf_free(dte);
415 }
416 
417 //deletion of DTEs
DelDTE(GF_GenericDTE * dte)418 void DelDTE(GF_GenericDTE *dte)
419 {
420 	switch (dte->source) {
421 	case 0:
422 		Del_EmptyDTE((GF_EmptyDTE *)dte);
423 		break;
424 	case 1:
425 		Del_ImmediateDTE((GF_ImmediateDTE *)dte);
426 		break;
427 	case 2:
428 		Del_SampleDTE((GF_SampleDTE *)dte);
429 		break;
430 	case 3:
431 		Del_StreamDescDTE((GF_StreamDescDTE *)dte);
432 		break;
433 	default:
434 		return;
435 	}
436 }
437 
438 
439 
440 /********************************************************************
441 Reading of DataTable entries in the RTP sample
442 ********************************************************************/
Read_EmptyDTE(GF_EmptyDTE * dte,GF_BitStream * bs)443 GF_Err Read_EmptyDTE(GF_EmptyDTE *dte, GF_BitStream *bs)
444 {
445 	char empty[15];
446 	//empty but always 15 bytes !!!
447 	gf_bs_read_data(bs, empty, 15);
448 	return GF_OK;
449 }
450 
Read_ImmediateDTE(GF_ImmediateDTE * dte,GF_BitStream * bs)451 GF_Err Read_ImmediateDTE(GF_ImmediateDTE *dte, GF_BitStream *bs)
452 {
453 	dte->dataLength = gf_bs_read_u8(bs);
454 	if (dte->dataLength > 14) return GF_ISOM_INVALID_FILE;
455 	gf_bs_read_data(bs, dte->data, dte->dataLength);
456 	if (dte->dataLength < 14) gf_bs_skip_bytes(bs, 14 - dte->dataLength);
457 	return GF_OK;
458 }
459 
Read_SampleDTE(GF_SampleDTE * dte,GF_BitStream * bs)460 GF_Err Read_SampleDTE(GF_SampleDTE *dte, GF_BitStream *bs)
461 {
462 	dte->trackRefIndex = gf_bs_read_u8(bs);
463 	dte->dataLength = gf_bs_read_u16(bs);
464 	dte->sampleNumber = gf_bs_read_u32(bs);
465 	dte->byteOffset = gf_bs_read_u32(bs);
466 	dte->bytesPerComp = gf_bs_read_u16(bs);
467 	dte->samplesPerComp = gf_bs_read_u16(bs);
468 	return GF_OK;
469 }
470 
Read_StreamDescDTE(GF_StreamDescDTE * dte,GF_BitStream * bs)471 GF_Err Read_StreamDescDTE(GF_StreamDescDTE *dte, GF_BitStream *bs)
472 {
473 	dte->trackRefIndex = gf_bs_read_u8(bs);
474 	dte->dataLength = gf_bs_read_u16(bs);
475 	dte->streamDescIndex = gf_bs_read_u32(bs);
476 	dte->byteOffset = gf_bs_read_u32(bs);
477 	dte->reserved = gf_bs_read_u32(bs);
478 	return GF_OK;
479 }
480 
ReadDTE(GF_GenericDTE * dte,GF_BitStream * bs)481 GF_Err ReadDTE(GF_GenericDTE *dte, GF_BitStream *bs)
482 {
483 	switch (dte->source) {
484 	case 0:
485 		//nothing to o, it is an empty entry
486 		return Read_EmptyDTE((GF_EmptyDTE *)dte, bs);
487 	case 1:
488 		return Read_ImmediateDTE((GF_ImmediateDTE *)dte, bs);
489 	case 2:
490 		return Read_SampleDTE((GF_SampleDTE *)dte, bs);
491 	case 3:
492 		return Read_StreamDescDTE((GF_StreamDescDTE *)dte, bs);
493 	default:
494 		return GF_ISOM_INVALID_FILE;
495 	}
496 }
497 
498 /********************************************************************
499 Writing of DataTable entries in the RTP sample
500 ********************************************************************/
Write_EmptyDTE(GF_EmptyDTE * dte,GF_BitStream * bs)501 GF_Err Write_EmptyDTE(GF_EmptyDTE *dte, GF_BitStream *bs)
502 {
503 	gf_bs_write_u8(bs, dte->source);
504 	//empty but always 15 bytes !!!
505 	gf_bs_write_data(bs, "empty hint DTE", 15);
506 	return GF_OK;
507 }
508 
Write_ImmediateDTE(GF_ImmediateDTE * dte,GF_BitStream * bs)509 GF_Err Write_ImmediateDTE(GF_ImmediateDTE *dte, GF_BitStream *bs)
510 {
511 	char data[14];
512 	gf_bs_write_u8(bs, dte->source);
513 	gf_bs_write_u8(bs, dte->dataLength);
514 	gf_bs_write_data(bs, dte->data, dte->dataLength);
515 	if (dte->dataLength < 14) {
516 		memset(data, 0, 14);
517 		gf_bs_write_data(bs, data, 14 - dte->dataLength);
518 	}
519 	return GF_OK;
520 }
521 
Write_SampleDTE(GF_SampleDTE * dte,GF_BitStream * bs)522 GF_Err Write_SampleDTE(GF_SampleDTE *dte, GF_BitStream *bs)
523 {
524 	gf_bs_write_u8(bs, dte->source);
525 	gf_bs_write_u8(bs, dte->trackRefIndex);
526 	gf_bs_write_u16(bs, dte->dataLength);
527 	gf_bs_write_u32(bs, dte->sampleNumber);
528 	gf_bs_write_u32(bs, dte->byteOffset);
529 	gf_bs_write_u16(bs, dte->bytesPerComp);
530 	gf_bs_write_u16(bs, dte->samplesPerComp);
531 	return GF_OK;
532 }
533 
Write_StreamDescDTE(GF_StreamDescDTE * dte,GF_BitStream * bs)534 GF_Err Write_StreamDescDTE(GF_StreamDescDTE *dte, GF_BitStream *bs)
535 {
536 	gf_bs_write_u8(bs, dte->source);
537 
538 	gf_bs_write_u8(bs, dte->trackRefIndex);
539 	gf_bs_write_u16(bs, dte->dataLength);
540 	gf_bs_write_u32(bs, dte->streamDescIndex);
541 	gf_bs_write_u32(bs, dte->byteOffset);
542 	gf_bs_write_u32(bs, dte->reserved);
543 	return GF_OK;
544 }
545 
WriteDTE(GF_GenericDTE * dte,GF_BitStream * bs)546 GF_Err WriteDTE(GF_GenericDTE *dte, GF_BitStream *bs)
547 {
548 	switch (dte->source) {
549 	case 0:
550 		//nothing to do, it is an empty entry
551 		return Write_EmptyDTE((GF_EmptyDTE *)dte, bs);
552 	case 1:
553 		return Write_ImmediateDTE((GF_ImmediateDTE *)dte, bs);
554 	case 2:
555 		return Write_SampleDTE((GF_SampleDTE *)dte, bs);
556 	case 3:
557 		return Write_StreamDescDTE((GF_StreamDescDTE *)dte, bs);
558 	default:
559 		return GF_ISOM_INVALID_FILE;
560 	}
561 }
562 
OffsetDTE(GF_GenericDTE * dte,u32 offset,u32 HintSampleNumber)563 GF_Err OffsetDTE(GF_GenericDTE *dte, u32 offset, u32 HintSampleNumber)
564 {
565 	GF_SampleDTE *sDTE;
566 	//offset shifting is only true for intra sample reference
567 	switch (dte->source) {
568 	case 2:
569 		break;
570 	default:
571 		return GF_OK;
572 	}
573 
574 	sDTE = (GF_SampleDTE *)dte;
575 	//we only adjust for intra HintTrack reference
576 	if (sDTE->trackRefIndex != (s8)-1) return GF_OK;
577 	//and in the same sample
578 	if (sDTE->sampleNumber != HintSampleNumber) return GF_OK;
579 	sDTE->byteOffset += offset;
580 	return GF_OK;
581 }
582 
gf_isom_hint_rtp_new()583 GF_RTPPacket *gf_isom_hint_rtp_new()
584 {
585 	GF_RTPPacket *tmp;
586 	GF_SAFEALLOC(tmp, GF_RTPPacket);
587 	if (!tmp) return NULL;
588 	tmp->TLV = gf_list_new();
589 	tmp->DataTable = gf_list_new();
590 	return tmp;
591 }
592 
gf_isom_hint_rtp_del(GF_RTPPacket * ptr)593 void gf_isom_hint_rtp_del(GF_RTPPacket *ptr)
594 {
595 	GF_GenericDTE *p;
596 	//the DTE
597 	while (gf_list_count(ptr->DataTable)) {
598 		p = (GF_GenericDTE *)gf_list_get(ptr->DataTable, 0);
599 		DelDTE(p);
600 		gf_list_rem(ptr->DataTable, 0);
601 	}
602 	gf_list_del(ptr->DataTable);
603 	//the TLV
604 	gf_isom_box_array_del(ptr->TLV);
605 	gf_free(ptr);
606 }
607 
gf_isom_hint_rtp_read(GF_RTPPacket * ptr,GF_BitStream * bs)608 GF_Err gf_isom_hint_rtp_read(GF_RTPPacket *ptr, GF_BitStream *bs)
609 {
610 	GF_Err e;
611 	u8 hasTLV, type;
612 	u16 i, count;
613 	u32 TLVsize, tempSize;
614 	GF_GenericDTE *dte;
615 	GF_Box *a;
616 
617 	ptr->relativeTransTime = gf_bs_read_u32(bs);
618 	//RTP Header
619 	//1- reserved fields
620 	gf_bs_read_int(bs, 2);
621 	ptr->P_bit = gf_bs_read_int(bs, 1);
622 	ptr->X_bit = gf_bs_read_int(bs, 1);
623 	gf_bs_read_int(bs, 4);
624 	ptr->M_bit = gf_bs_read_int(bs, 1);
625 	ptr->payloadType = gf_bs_read_int(bs, 7);
626 
627 	ptr->SequenceNumber = gf_bs_read_u16(bs);
628 	gf_bs_read_int(bs, 13);
629 	hasTLV = gf_bs_read_int(bs, 1);
630 	ptr->B_bit = gf_bs_read_int(bs, 1);
631 	ptr->R_bit = gf_bs_read_int(bs, 1);
632 	count = gf_bs_read_u16(bs);
633 
634 	//read the TLV
635 	if (hasTLV) {
636 		tempSize = 4;	//TLVsize includes its field length
637 		TLVsize = gf_bs_read_u32(bs);
638 		while (tempSize < TLVsize) {
639 			e = gf_isom_parse_box(&a, bs);
640 			if (e) return e;
641 			gf_list_add(ptr->TLV, a);
642 			tempSize += (u32)a->size;
643 		}
644 		if (tempSize != TLVsize) return GF_ISOM_INVALID_FILE;
645 	}
646 
647 	//read the DTEs
648 	for (i = 0; i<count; i++) {
649 		Bool add_it = 0;
650 		type = gf_bs_read_u8(bs);
651 		dte = NewDTE(type);
652 		e = ReadDTE(dte, bs);
653 		if (e) return e;
654 		/*little opt, remove empty dte*/
655 		switch (type) {
656 		case 1:
657 			if (((GF_ImmediateDTE *)dte)->dataLength) add_it = 1;
658 			break;
659 		case 2:
660 			if (((GF_SampleDTE *)dte)->dataLength) add_it = 1;
661 			break;
662 		case 3:
663 			if (((GF_StreamDescDTE *)dte)->dataLength) add_it = 1;
664 			break;
665 		}
666 		if (add_it)
667 			gf_list_add(ptr->DataTable, dte);
668 		else
669 			DelDTE(dte);
670 	}
671 	return GF_OK;
672 }
673 
gf_isom_hint_rtp_offset(GF_RTPPacket * ptr,u32 offset,u32 HintSampleNumber)674 GF_Err gf_isom_hint_rtp_offset(GF_RTPPacket *ptr, u32 offset, u32 HintSampleNumber)
675 {
676 	u32 count, i;
677 	GF_GenericDTE *dte;
678 	GF_Err e;
679 
680 	count = gf_list_count(ptr->DataTable);
681 	for (i = 0; i<count; i++) {
682 		dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
683 		e = OffsetDTE(dte, offset, HintSampleNumber);
684 		if (e) return e;
685 	}
686 	return GF_OK;
687 }
688 
689 //Gets the REAL size of the packet once rebuild, but without CSRC fields in the
690 //header
gf_isom_hint_rtp_length(GF_RTPPacket * ptr)691 u32 gf_isom_hint_rtp_length(GF_RTPPacket *ptr)
692 {
693 	u32 size, count, i;
694 	GF_GenericDTE *dte;
695 
696 	//64 bit header
697 	size = 8;
698 	//32 bit SSRC
699 	size += 4;
700 	count = gf_list_count(ptr->DataTable);
701 	for (i = 0; i<count; i++) {
702 		dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
703 		switch (dte->source) {
704 		case 0:
705 			break;
706 		case 1:
707 			size += ((GF_ImmediateDTE *)dte)->dataLength;
708 			break;
709 		case 2:
710 			size += ((GF_SampleDTE *)dte)->dataLength;
711 			break;
712 		case 3:
713 			size += ((GF_StreamDescDTE *)dte)->dataLength;
714 			break;
715 		}
716 	}
717 	return size;
718 }
719 
720 
721 #ifndef GPAC_DISABLE_ISOM_WRITE
722 
gf_isom_hint_rtp_size(GF_RTPPacket * ptr)723 u32 gf_isom_hint_rtp_size(GF_RTPPacket *ptr)
724 {
725 	GF_Box none;
726 	u32 size, count;
727 	//the RTP Header size and co
728 	size = 12;
729 	//the extra table size
730 	count = gf_list_count(ptr->TLV);
731 	if (count) {
732 		none.size = 4;	//WE INCLUDE THE SIZE FIELD LENGTH
733 		none.type = 0;
734 		//REMEMBER THAT TLV ENTRIES ARE 4-BYTES ALIGNED !!!
735 		gf_isom_box_array_size(&none, ptr->TLV);
736 		size += (u32)none.size;
737 	}
738 	//the DTE (each entry is 16 bytes)
739 	count = gf_list_count(ptr->DataTable);
740 	size += count * 16;
741 	return size;
742 }
743 
gf_isom_hint_rtp_write(GF_RTPPacket * ptr,GF_BitStream * bs)744 GF_Err gf_isom_hint_rtp_write(GF_RTPPacket *ptr, GF_BitStream *bs)
745 {
746 	GF_Err e;
747 	u32 TLVcount, DTEcount, i;
748 	GF_Box none;
749 	GF_GenericDTE *dte;
750 
751 	gf_bs_write_u32(bs, ptr->relativeTransTime);
752 	//RTP Header
753 	//	gf_bs_write_int(bs, 2, 2);
754 	//version is 2
755 	gf_bs_write_int(bs, 2, 2);
756 	gf_bs_write_int(bs, ptr->P_bit, 1);
757 	gf_bs_write_int(bs, ptr->X_bit, 1);
758 	gf_bs_write_int(bs, 0, 4);
759 	gf_bs_write_int(bs, ptr->M_bit, 1);
760 	gf_bs_write_int(bs, ptr->payloadType, 7);
761 
762 	gf_bs_write_u16(bs, ptr->SequenceNumber);
763 	gf_bs_write_int(bs, 0, 13);
764 	TLVcount = gf_list_count(ptr->TLV);
765 	DTEcount = gf_list_count(ptr->DataTable);
766 	gf_bs_write_int(bs, TLVcount ? 1 : 0, 1);
767 	gf_bs_write_int(bs, ptr->B_bit, 1);
768 	gf_bs_write_int(bs, ptr->R_bit, 1);
769 
770 	gf_bs_write_u16(bs, DTEcount);
771 
772 	if (TLVcount) {
773 		//first write the size of the table ...
774 		none.size = 4;	//WE INCLUDE THE SIZE FIELD LENGTH
775 		none.type = 0;
776 		gf_isom_box_array_size(&none, ptr->TLV);
777 		gf_bs_write_u32(bs, (u32)none.size);
778 		e = gf_isom_box_array_write(&none, ptr->TLV, bs);
779 		if (e) return e;
780 	}
781 	//write the DTE...
782 	for (i = 0; i < DTEcount; i++) {
783 		dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
784 		e = WriteDTE(dte, bs);
785 		if (e) return e;
786 	}
787 	return GF_OK;
788 }
789 
790 #endif /*GPAC_DISABLE_ISOM_WRITE*/
791 
792 GF_EXPORT
gf_isom_reset_hint_reader(GF_ISOFile * the_file,u32 trackNumber,u32 sample_start,u32 ts_offset,u32 sn_offset,u32 ssrc)793 GF_Err gf_isom_reset_hint_reader(GF_ISOFile *the_file, u32 trackNumber, u32 sample_start, u32 ts_offset, u32 sn_offset, u32 ssrc)
794 {
795 	GF_Err e;
796 	GF_TrackBox *trak;
797 	GF_HintSampleEntryBox *entry;
798 
799 	trak = gf_isom_get_track_from_file(the_file, trackNumber);
800 	if (!trak) return GF_BAD_PARAM;
801 
802 	if (!sample_start) return GF_BAD_PARAM;
803 	if (sample_start >= trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;
804 
805 	e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **)&entry, NULL);
806 	if (e) return e;
807 	switch (entry->type) {
808 	case GF_ISOM_BOX_TYPE_RTP_STSD:
809 		break;
810 	default:
811 		return GF_NOT_SUPPORTED;
812 	}
813 
814 	entry->hint_ref = NULL;
815 	e = Track_FindRef(trak, GF_ISOM_REF_HINT, &entry->hint_ref);
816 	if (e) return e;
817 
818 	entry->cur_sample = sample_start;
819 	entry->pck_sn = 1 + sn_offset;
820 	entry->ssrc = ssrc;
821 	entry->ts_offset = ts_offset;
822 	if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
823 	entry->hint_sample = NULL;
824 	return GF_OK;
825 }
826 
gf_isom_load_next_hint_sample(GF_ISOFile * the_file,u32 trackNumber,GF_TrackBox * trak,GF_HintSampleEntryBox * entry)827 static GF_Err gf_isom_load_next_hint_sample(GF_ISOFile *the_file, u32 trackNumber, GF_TrackBox *trak, GF_HintSampleEntryBox *entry)
828 {
829 	GF_BitStream *bs;
830 	u32 descIdx;
831 	GF_ISOSample *samp;
832 
833 	if (!entry->cur_sample) return GF_BAD_PARAM;
834 	if (entry->cur_sample>trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_EOS;
835 
836 	samp = gf_isom_get_sample(the_file, trackNumber, entry->cur_sample, &descIdx);
837 	if (!samp) return GF_IO_ERR;
838 	entry->cur_sample++;
839 
840 	if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
841 
842 	bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
843 	entry->hint_sample = gf_isom_hint_sample_new(entry->type);
844 	gf_isom_hint_sample_read(entry->hint_sample, bs, samp->dataLength);
845 	gf_bs_del(bs);
846 	entry->hint_sample->TransmissionTime = samp->DTS;
847 	gf_isom_sample_del(&samp);
848 	entry->hint_sample->sample_cache = gf_list_new();
849 	return GF_OK;
850 }
851 
gf_isom_get_data_sample(GF_HintSample * hsamp,GF_TrackBox * trak,u32 sample_num)852 static GF_ISOSample *gf_isom_get_data_sample(GF_HintSample *hsamp, GF_TrackBox *trak, u32 sample_num)
853 {
854 	GF_ISOSample *samp;
855 	GF_HintDataCache *hdc;
856 	u32 i, count;
857 	count = gf_list_count(hsamp->sample_cache);
858 	for (i = 0; i<count; i++) {
859 		hdc = (GF_HintDataCache *)gf_list_get(hsamp->sample_cache, i);
860 		if ((hdc->sample_num == sample_num) && (hdc->trak == trak)) return hdc->samp;
861 	}
862 
863 	samp = gf_isom_sample_new();
864 	Media_GetSample(trak->Media, sample_num, &samp, &i, 0, NULL);
865 	if (!samp) return NULL;
866 	GF_SAFEALLOC(hdc, GF_HintDataCache);
867 	if (!hdc) return NULL;
868 	hdc->samp = samp;
869 	hdc->sample_num = sample_num;
870 	hdc->trak = trak;
871 	/*we insert all new samples, since they're more likely to be fetched next (except for audio
872 	interleaving and other multiplex)*/
873 	gf_list_insert(hsamp->sample_cache, hdc, 0);
874 	return samp;
875 }
876 
877 GF_EXPORT
gf_isom_next_hint_packet(GF_ISOFile * the_file,u32 trackNumber,char ** pck_data,u32 * pck_size,Bool * disposable,Bool * repeated,u32 * trans_ts,u32 * sample_num)878 GF_Err gf_isom_next_hint_packet(GF_ISOFile *the_file, u32 trackNumber, char **pck_data, u32 *pck_size, Bool *disposable, Bool *repeated, u32 *trans_ts, u32 *sample_num)
879 {
880 	GF_RTPPacket *pck;
881 	GF_Err e;
882 	GF_BitStream *bs;
883 	GF_TrackBox *trak, *ref_trak;
884 	GF_HintSampleEntryBox *entry;
885 	u32 i, count, ts;
886 	s32 cts_off;
887 
888 	*pck_data = NULL;
889 	*pck_size = 0;
890 	if (trans_ts) *trans_ts = 0;
891 	if (disposable) *disposable = 0;
892 	if (repeated) *repeated = 0;
893 	if (sample_num) *sample_num = 0;
894 
895 	trak = gf_isom_get_track_from_file(the_file, trackNumber);
896 	if (!trak) return GF_BAD_PARAM;
897 	e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **)&entry, NULL);
898 	if (e) return e;
899 	switch (entry->type) {
900 	case GF_ISOM_BOX_TYPE_RTP_STSD:
901 		break;
902 	default:
903 		return GF_NOT_SUPPORTED;
904 	}
905 
906 	if (!entry->hint_sample) {
907 		e = gf_isom_load_next_hint_sample(the_file, trackNumber, trak, entry);
908 		if (e) return e;
909 	}
910 	pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, 0);
911 	gf_list_rem(entry->hint_sample->packetTable, 0);
912 	if (!pck) return GF_BAD_PARAM;
913 
914 	bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
915 	/*write RTP header*/
916 	gf_bs_write_int(bs, 2, 2);	/*version*/
917 	gf_bs_write_int(bs, pck->P_bit, 1);	/*P bit*/
918 	gf_bs_write_int(bs, pck->X_bit, 1);	/*X bit*/
919 	gf_bs_write_int(bs, 0, 4);	/*CSRC count*/
920 	gf_bs_write_int(bs, pck->M_bit, 1);	/*M bit*/
921 	gf_bs_write_int(bs, pck->payloadType, 7);	/*payt*/
922 	gf_bs_write_u16(bs, entry->pck_sn);	/*seq num*/
923 	entry->pck_sn++;
924 
925 	/*look for CTS offset in TLV*/
926 	cts_off = 0;
927 	count = gf_list_count(pck->TLV);
928 	for (i = 0; i<count; i++) {
929 		GF_RTPOBox *rtpo = (GF_RTPOBox *)gf_list_get(pck->TLV, i);
930 		if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
931 			cts_off = rtpo->timeOffset;
932 			break;
933 		}
934 	}
935 	/*TS - TODO check TS wrapping*/
936 	ts = (u32)(entry->hint_sample->TransmissionTime + pck->relativeTransTime + entry->ts_offset + cts_off);
937 	gf_bs_write_u32(bs, ts);
938 	gf_bs_write_u32(bs, entry->ssrc);	/*SSRC*/
939 
940 										/*then build all data*/
941 	count = gf_list_count(pck->DataTable);
942 	for (i = 0; i<count; i++) {
943 		GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(pck->DataTable, i);
944 		switch (dte->source) {
945 			/*empty*/
946 		case 0:
947 			break;
948 			/*immediate data*/
949 		case 1:
950 			gf_bs_write_data(bs, ((GF_ImmediateDTE *)dte)->data, ((GF_ImmediateDTE *)dte)->dataLength);
951 			break;
952 			/*sample data*/
953 		case 2:
954 		{
955 			GF_ISOSample *samp;
956 			GF_SampleDTE *sdte = (GF_SampleDTE *)dte;
957 			/*get track if not this one*/
958 			if (sdte->trackRefIndex != (s8)-1) {
959 				if (!entry->hint_ref || !entry->hint_ref->trackIDs) {
960 					gf_isom_hint_rtp_del(pck);
961 					gf_bs_del(bs);
962 					return GF_ISOM_INVALID_FILE;
963 				}
964 				ref_trak = gf_isom_get_track_from_id(trak->moov, entry->hint_ref->trackIDs[(u32)sdte->trackRefIndex]);
965 			}
966 			else {
967 				ref_trak = trak;
968 			}
969 			samp = gf_isom_get_data_sample(entry->hint_sample, ref_trak, sdte->sampleNumber);
970 			if (!samp) {
971 				gf_isom_hint_rtp_del(pck);
972 				gf_bs_del(bs);
973 				return GF_IO_ERR;
974 			}
975 			gf_bs_write_data(bs, samp->data + sdte->byteOffset, sdte->dataLength);
976 		}
977 		break;
978 		/*sample desc data - currently NOT SUPPORTED !!!*/
979 		case 3:
980 			break;
981 		}
982 	}
983 	if (trans_ts) *trans_ts = ts;
984 	if (disposable) *disposable = pck->B_bit;
985 	if (repeated) *repeated = pck->R_bit;
986 	if (sample_num) *sample_num = entry->cur_sample - 1;
987 
988 	gf_bs_get_content(bs, pck_data, pck_size);
989 	gf_bs_del(bs);
990 	gf_isom_hint_rtp_del(pck);
991 	if (!gf_list_count(entry->hint_sample->packetTable)) {
992 		gf_isom_hint_sample_del(entry->hint_sample);
993 		entry->hint_sample = NULL;
994 	}
995 	return GF_OK;
996 }
997 
998 #endif /* !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)*/
999