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