Coverage Report

Created: 2025-10-10 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/hinting.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
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
30
GF_Box *ghnt_box_new()
31
42
{
32
42
  GF_HintSampleEntryBox *tmp;
33
42
  GF_SAFEALLOC(tmp, GF_HintSampleEntryBox);
34
42
  if (!tmp) return NULL;
35
42
  gf_isom_sample_entry_init((GF_SampleEntryBox *)tmp);
36
37
  //this type is used internally for protocols that share the same base entry
38
  //currently only RTP uses this, but a flexMux could use this entry too...
39
42
  tmp->type = GF_ISOM_BOX_TYPE_GHNT;
40
42
  tmp->HintTrackVersion = 1;
41
42
  tmp->LastCompatibleVersion = 1;
42
42
  return (GF_Box *)tmp;
43
42
}
44
45
void ghnt_box_del(GF_Box *s)
46
42
{
47
42
  GF_HintSampleEntryBox *ptr;
48
49
42
  gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
50
42
  ptr = (GF_HintSampleEntryBox *)s;
51
42
  if (ptr->hint_sample) gf_isom_hint_sample_del(ptr->hint_sample);
52
42
  gf_free(ptr);
53
42
}
54
55
GF_Err ghnt_box_read(GF_Box *s, GF_BitStream *bs)
56
42
{
57
42
  GF_Err e;
58
42
  GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
59
42
  if (ptr == NULL) return GF_BAD_PARAM;
60
61
  //sample entry + 4 bytes in box
62
84
  ISOM_DECREASE_SIZE(ptr, 12)
63
64
84
  e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
65
84
  if (e) return e;
66
67
42
  ptr->HintTrackVersion = gf_bs_read_u16(bs);
68
42
  ptr->LastCompatibleVersion = gf_bs_read_u16(bs);
69
70
42
  if ((s->type == GF_ISOM_BOX_TYPE_RTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_SRTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_RRTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_RTCP_STSD)) {
71
42
    ISOM_DECREASE_SIZE(ptr, 4)
72
42
    ptr->MaxPacketSize = gf_bs_read_u32(bs);
73
42
  } else if (s->type == GF_ISOM_BOX_TYPE_FDP_STSD) {
74
0
    ISOM_DECREASE_SIZE(ptr, 4)
75
0
    ptr->partition_entry_ID = gf_bs_read_u16(bs);
76
0
    ptr->FEC_overhead = gf_bs_read_u16(bs);
77
78
0
  }
79
42
  return gf_isom_box_array_read(s, bs);
80
42
}
81
82
#ifndef GPAC_DISABLE_ISOM_WRITE
83
84
GF_Err ghnt_box_write(GF_Box *s, GF_BitStream *bs)
85
0
{
86
0
  GF_Err e;
87
0
  GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
88
89
0
  e = gf_isom_box_write_header(s, bs);
90
0
  if (e) return e;
91
0
  gf_bs_write_data(bs, ptr->reserved, 6);
92
0
  gf_bs_write_u16(bs, ptr->dataReferenceIndex);
93
0
  gf_bs_write_u16(bs, ptr->HintTrackVersion);
94
0
  gf_bs_write_u16(bs, ptr->LastCompatibleVersion);
95
0
  gf_bs_write_u32(bs, ptr->MaxPacketSize);
96
0
  return GF_OK;
97
0
}
98
99
GF_Err ghnt_box_size(GF_Box *s)
100
0
{
101
0
  GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
102
0
  ptr->size += 16;
103
0
  return GF_OK;
104
0
}
105
106
107
#endif /*GPAC_DISABLE_ISOM_WRITE*/
108
109
110
GF_HintSample *gf_isom_hint_sample_new(u32 ProtocolType)
111
0
{
112
0
  GF_HintSample *tmp;
113
0
  switch (ProtocolType) {
114
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
115
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
116
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
117
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
118
0
    break;
119
0
  case GF_ISOM_BOX_TYPE_FDP_STSD:
120
0
    return (GF_HintSample *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FDSA);
121
0
    break;
122
0
  default:
123
0
    return NULL;
124
0
  }
125
0
  GF_SAFEALLOC(tmp, GF_HintSample);
126
0
  if (!tmp) return NULL;
127
0
  tmp->packetTable = gf_list_new();
128
0
  tmp->hint_subtype = ProtocolType;
129
0
  return tmp;
130
0
}
131
132
void gf_isom_hint_sample_del(GF_HintSample *ptr)
133
0
{
134
0
  if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
135
0
    gf_isom_box_del((GF_Box*)ptr);
136
0
    return;
137
0
  }
138
139
0
  while (gf_list_count(ptr->packetTable)) {
140
0
    GF_HintPacket *pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, 0);
141
0
    gf_isom_hint_pck_del(pck);
142
0
    gf_list_rem(ptr->packetTable, 0);
143
0
  }
144
0
  gf_list_del(ptr->packetTable);
145
0
  if (ptr->AdditionalData) gf_free(ptr->AdditionalData);
146
147
0
  if (ptr->sample_cache) {
148
0
    while (gf_list_count(ptr->sample_cache)) {
149
0
      GF_HintDataCache *hdc = (GF_HintDataCache *)gf_list_get(ptr->sample_cache, 0);
150
0
      gf_list_rem(ptr->sample_cache, 0);
151
0
      if (hdc->samp) gf_isom_sample_del(&hdc->samp);
152
0
      gf_free(hdc);
153
0
    }
154
0
    gf_list_del(ptr->sample_cache);
155
0
  }
156
0
  if (ptr->extra_data)
157
0
    gf_isom_box_del((GF_Box*)ptr->extra_data);
158
0
  if (ptr->child_boxes)
159
0
    gf_isom_box_array_del(ptr->child_boxes);
160
161
0
  gf_free(ptr);
162
0
}
163
164
GF_Err gf_isom_hint_sample_read(GF_HintSample *ptr, GF_BitStream *bs, u32 sampleSize)
165
0
{
166
0
  u16 i;
167
0
  u32 type;
168
0
  GF_Err e;
169
0
#ifndef GPAC_DISABLE_LOG
170
0
  char *szName = (ptr->hint_subtype==GF_ISOM_BOX_TYPE_RTCP_STSD) ? "RTCP" : "RTP";
171
0
#endif
172
0
  u64 sizeIn, sizeOut;
173
174
0
  sizeIn = gf_bs_available(bs);
175
176
0
  switch (ptr->hint_subtype) {
177
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
178
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
179
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
180
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
181
0
    break;
182
0
  case GF_ISOM_BOX_TYPE_FDP_STSD:
183
0
    ptr->size = gf_bs_read_u32(bs);
184
0
    type = gf_bs_read_u32(bs);
185
0
    if (type != GF_ISOM_BOX_TYPE_FDSA) {
186
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] invalid FDT sample, top box type %s not fdsa\n", gf_4cc_to_str(type) ));
187
0
      return GF_ISOM_INVALID_MEDIA;
188
0
    }
189
0
    return gf_isom_box_read((GF_Box*)ptr, bs);
190
0
  default:
191
0
    return GF_NOT_SUPPORTED;
192
0
  }
193
194
0
  ptr->packetCount = gf_bs_read_u16(bs);
195
0
  ptr->reserved = gf_bs_read_u16(bs);
196
0
  if (ptr->packetCount>=sampleSize) {
197
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] broken %s sample: %d packet_count indicated but only %d bytes in samples\n", szName, ptr->packetCount, sampleSize));
198
0
    return GF_ISOM_INVALID_MEDIA;
199
0
  }
200
  
201
0
  for (i = 0; i < ptr->packetCount; i++) {
202
0
    GF_HintPacket *pck;
203
0
    if (! gf_bs_available(bs) ) {
204
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] %s hint sample has no more data but still %d entries to read\n", szName, ptr->packetCount-i));
205
0
      return GF_ISOM_INVALID_MEDIA;
206
0
    }
207
0
    pck = gf_isom_hint_pck_new(ptr->hint_subtype);
208
0
    pck->trackID = ptr->trackID;
209
0
    pck->sampleNumber = ptr->sampleNumber;
210
0
    gf_list_add(ptr->packetTable, pck);
211
212
0
    e = gf_isom_hint_pck_read(pck, bs);
213
0
    if (e) return e;
214
0
  }
215
216
0
  if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_RTCP_STSD) return GF_OK;
217
218
219
0
  sizeOut = gf_bs_available(bs) - sizeIn;
220
221
  //do we have some more data after the packets ??
222
0
  if ((u32)sizeOut < sampleSize) {
223
0
    ptr->dataLength = sampleSize - (u32)sizeOut;
224
0
    ptr->AdditionalData = (char*)gf_malloc(sizeof(char) * ptr->dataLength);
225
0
    if (!ptr->AdditionalData) return GF_OUT_OF_MEM;
226
0
    gf_bs_read_data(bs, ptr->AdditionalData, ptr->dataLength);
227
0
  }
228
0
  return GF_OK;
229
0
}
230
231
232
#ifndef GPAC_DISABLE_ISOM_WRITE
233
234
GF_Err gf_isom_hint_sample_write(GF_HintSample *ptr, GF_BitStream *bs)
235
0
{
236
0
  u32 count, i;
237
0
  GF_Err e;
238
239
0
  if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
240
0
    e = gf_isom_box_size((GF_Box*)ptr);
241
0
    if (!e) e = gf_isom_box_write((GF_Box*)ptr, bs);
242
0
    return e;
243
0
  }
244
245
0
  count = gf_list_count(ptr->packetTable);
246
0
  gf_bs_write_u16(bs, count);
247
0
  gf_bs_write_u16(bs, ptr->reserved);
248
  //write the packet table
249
0
  for (i=0; i<count; i++) {
250
0
    GF_HintPacket *pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
251
0
    e = gf_isom_hint_pck_write(pck, bs);
252
0
    if (e) return e;
253
0
  }
254
  //write additional data
255
0
  if (ptr->AdditionalData) {
256
0
    gf_bs_write_data(bs, ptr->AdditionalData, ptr->dataLength);
257
0
  }
258
0
  return GF_OK;
259
0
}
260
261
262
u32 gf_isom_hint_sample_size(GF_HintSample *ptr)
263
0
{
264
0
  u32 size, count, i;
265
0
  if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
266
0
    gf_isom_box_size((GF_Box*)ptr);
267
0
    size = (u32) ptr->size;
268
0
  } else {
269
0
    size = 4;
270
0
    count = gf_list_count(ptr->packetTable);
271
0
    for (i=0; i<count; i++) {
272
0
      GF_HintPacket *pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
273
0
      size += gf_isom_hint_pck_size(pck);
274
0
    }
275
0
    size += ptr->dataLength;
276
0
  }
277
0
  return size;
278
0
}
279
280
#endif /*GPAC_DISABLE_ISOM_WRITE*/
281
282
283
GF_EXPORT
284
GF_HintPacket *gf_isom_hint_pck_new(u32 HintType)
285
0
{
286
0
  GF_HintPacket *pck;
287
0
  switch (HintType) {
288
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
289
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
290
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
291
0
    pck = (GF_HintPacket *) gf_isom_hint_rtp_new();
292
0
    if (pck) pck->hint_subtype = HintType;
293
0
    return pck;
294
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
295
0
    pck = (GF_HintPacket *) gf_isom_hint_rtcp_new();
296
0
    if (pck) pck->hint_subtype = HintType;
297
0
    return pck;
298
0
  default:
299
0
    return NULL;
300
0
  }
301
0
}
302
303
GF_EXPORT
304
void gf_isom_hint_pck_del(GF_HintPacket *ptr)
305
0
{
306
0
  if (!ptr) return;
307
0
  switch (ptr->hint_subtype) {
308
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
309
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
310
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
311
0
    gf_isom_hint_rtp_del((GF_RTPPacket *)ptr);
312
0
    break;
313
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
314
0
    gf_isom_hint_rtcp_del((GF_RTCPPacket *)ptr);
315
0
    break;
316
0
  default:
317
0
    break;
318
0
  }
319
0
}
320
321
GF_EXPORT
322
GF_Err gf_isom_hint_pck_read(GF_HintPacket *ptr, GF_BitStream *bs)
323
0
{
324
0
  if (!ptr) return GF_BAD_PARAM;
325
0
  switch (ptr->hint_subtype) {
326
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
327
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
328
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
329
0
    return gf_isom_hint_rtp_read((GF_RTPPacket *)ptr, bs);
330
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
331
0
    return gf_isom_hint_rtcp_read((GF_RTCPPacket *)ptr, bs);
332
0
  default:
333
0
    return GF_NOT_SUPPORTED;
334
0
  }
335
0
}
336
337
#ifndef GPAC_DISABLE_ISOM_WRITE
338
339
GF_EXPORT
340
GF_Err gf_isom_hint_pck_write(GF_HintPacket *ptr, GF_BitStream *bs)
341
0
{
342
0
  if (!ptr) return GF_BAD_PARAM;
343
0
  switch (ptr->hint_subtype) {
344
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
345
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
346
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
347
0
    return gf_isom_hint_rtp_write((GF_RTPPacket *)ptr, bs);
348
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
349
0
    return gf_isom_hint_rtcp_write((GF_RTCPPacket *)ptr, bs);
350
0
  default:
351
0
    return GF_NOT_SUPPORTED;
352
0
  }
353
0
}
354
355
GF_EXPORT
356
u32 gf_isom_hint_pck_size(GF_HintPacket *ptr)
357
0
{
358
0
  if (!ptr) return GF_BAD_PARAM;
359
0
  switch (ptr->hint_subtype) {
360
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
361
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
362
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
363
0
    return gf_isom_hint_rtp_size((GF_RTPPacket *)ptr);
364
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
365
0
    return gf_isom_hint_rtcp_size((GF_RTCPPacket *)ptr);
366
0
  default:
367
0
    return 0;
368
0
  }
369
0
}
370
371
GF_Err gf_isom_hint_pck_offset(GF_HintPacket *ptr, u32 offset, u32 HintSampleNumber)
372
0
{
373
0
  if (!ptr) return GF_BAD_PARAM;
374
0
  switch (ptr->hint_subtype) {
375
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
376
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
377
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
378
0
    return gf_isom_hint_rtp_offset((GF_RTPPacket *)ptr, offset, HintSampleNumber);
379
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
380
0
    return GF_BAD_PARAM;
381
0
  default:
382
0
    return GF_NOT_SUPPORTED;
383
0
  }
384
0
}
385
386
GF_Err gf_isom_hint_pck_add_dte(GF_HintPacket *ptr, GF_GenericDTE *dte, u8 AtBegin)
387
0
{
388
0
  if (!ptr) return GF_BAD_PARAM;
389
0
  switch (ptr->hint_subtype) {
390
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
391
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
392
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
393
0
    if (AtBegin)
394
0
      return gf_list_insert( ((GF_RTPPacket *)ptr)->DataTable, dte, 0);
395
0
    else
396
0
      return gf_list_add( ((GF_RTPPacket *)ptr)->DataTable, dte);
397
398
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
399
0
    return GF_BAD_PARAM;
400
0
  default:
401
0
    return GF_NOT_SUPPORTED;
402
0
  }
403
0
}
404
405
GF_EXPORT
406
u32 gf_isom_hint_pck_length(GF_HintPacket *ptr)
407
0
{
408
0
  if (!ptr) return 0;
409
0
  switch (ptr->hint_subtype) {
410
0
  case GF_ISOM_BOX_TYPE_RTP_STSD:
411
0
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
412
0
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
413
0
    return gf_isom_hint_rtp_length((GF_RTPPacket *)ptr);
414
0
  case GF_ISOM_BOX_TYPE_RTCP_STSD:
415
0
    return gf_isom_hint_rtcp_length((GF_RTCPPacket *)ptr);
416
0
  default:
417
0
    return 0;
418
0
  }
419
0
}
420
421
422
#endif /*GPAC_DISABLE_ISOM_WRITE*/
423
424
425
426
/********************************************************************
427
    Creation of DataTable entries in the RTP sample
428
********************************************************************/
429
430
//creation of DTEs
431
GF_GenericDTE *NewDTE(u8 type)
432
0
{
433
0
  switch (type) {
434
0
  case 0:
435
0
  {
436
0
    GF_EmptyDTE *dte;
437
0
    GF_SAFEALLOC(dte, GF_EmptyDTE);
438
0
    return (GF_GenericDTE *)dte;
439
0
  }
440
0
  case 1:
441
0
  {
442
0
    GF_ImmediateDTE *dte;
443
0
    GF_SAFEALLOC(dte, GF_ImmediateDTE);
444
0
    if (dte) dte->source = 1;
445
0
    return (GF_GenericDTE *)dte;
446
0
  }
447
0
  case 2:
448
0
  {
449
0
    GF_SampleDTE *dte;
450
0
    GF_SAFEALLOC(dte, GF_SampleDTE);
451
0
    if (!dte) return NULL;
452
0
    dte->source = 2;
453
    //can be -1 in QT , so init at -2
454
0
    dte->trackRefIndex = (s8) -2;
455
0
    dte->samplesPerComp = 1;
456
0
    dte->bytesPerComp = 1;
457
0
    return (GF_GenericDTE *)dte;
458
0
  }
459
0
  case 3:
460
0
  {
461
0
    GF_StreamDescDTE *dte;
462
0
    GF_SAFEALLOC(dte, GF_StreamDescDTE);
463
0
    if (!dte) return NULL;
464
0
    dte->source = 3;
465
    //can be -1 in QT , so init at -2
466
0
    dte->trackRefIndex = (s8) -2;
467
0
    return (GF_GenericDTE *)dte;
468
0
  }
469
0
  default:
470
0
    return NULL;
471
0
  }
472
0
}
473
474
/********************************************************************
475
    Deletion of DataTable entries in the RTP sample
476
********************************************************************/
477
478
//deletion of DTEs
479
void DelDTE(GF_GenericDTE *dte)
480
0
{
481
0
  switch (dte->source) {
482
0
  case 0:
483
0
  case 1:
484
0
  case 2:
485
0
  case 3:
486
0
    gf_free(dte);
487
0
    break;
488
0
  default:
489
0
    return;
490
0
  }
491
0
}
492
493
494
495
/********************************************************************
496
    Reading of DataTable entries in the RTP sample
497
********************************************************************/
498
499
GF_Err ReadDTE(GF_GenericDTE *_dte, GF_BitStream *bs)
500
0
{
501
0
  switch (_dte->source) {
502
0
  case 0:
503
    //empty but always 15 bytes !!!
504
0
    gf_bs_skip_bytes(bs, 15);
505
0
    return GF_OK;
506
0
  case 1:
507
0
  {
508
0
    GF_ImmediateDTE *dte = (GF_ImmediateDTE *)_dte;
509
0
    dte->dataLength = gf_bs_read_u8(bs);
510
0
    if (dte->dataLength > 14) return GF_ISOM_INVALID_FILE;
511
0
    gf_bs_read_data(bs, dte->data, dte->dataLength);
512
0
    if (dte->dataLength < 14) gf_bs_skip_bytes(bs, 14 - dte->dataLength);
513
0
    return GF_OK;
514
0
  }
515
0
  case 2:
516
0
  {
517
0
    GF_SampleDTE *dte = (GF_SampleDTE *)_dte;
518
0
    dte->trackRefIndex = (s8) gf_bs_read_u8(bs);
519
0
    dte->dataLength = gf_bs_read_u16(bs);
520
0
    dte->sampleNumber = gf_bs_read_u32(bs);
521
0
    dte->byteOffset = gf_bs_read_u32(bs);
522
0
    dte->bytesPerComp = gf_bs_read_u16(bs);
523
0
    dte->samplesPerComp = gf_bs_read_u16(bs);
524
0
    if (dte->bytesPerComp != 1) {
525
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] hint packet constructor with bytesperblock %d, not 1\n", dte->bytesPerComp));
526
0
    }
527
0
    if (dte->samplesPerComp != 1) {
528
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] hint packet constructor with samplesperblock %d, not 1\n", dte->bytesPerComp));
529
0
    }
530
0
    return GF_OK;
531
0
  }
532
0
  case 3:
533
0
  {
534
0
    GF_StreamDescDTE *dte = (GF_StreamDescDTE *)_dte;
535
0
    dte->trackRefIndex = gf_bs_read_u8(bs);
536
0
    dte->dataLength = gf_bs_read_u16(bs);
537
0
    dte->streamDescIndex = gf_bs_read_u32(bs);
538
0
    dte->byteOffset = gf_bs_read_u32(bs);
539
0
    dte->reserved = gf_bs_read_u32(bs);
540
0
    return GF_OK;
541
0
  }
542
0
  default:
543
0
    return GF_ISOM_INVALID_FILE;
544
0
  }
545
0
}
546
547
/********************************************************************
548
    Writing of DataTable entries in the RTP sample
549
********************************************************************/
550
551
552
GF_Err WriteDTE(GF_GenericDTE *_dte, GF_BitStream *bs)
553
0
{
554
0
  switch (_dte->source) {
555
0
  case 0:
556
0
  {
557
0
    GF_EmptyDTE *dte = (GF_EmptyDTE *)_dte;
558
0
    gf_bs_write_u8(bs, dte->source);
559
    //empty but always 15 bytes !!!
560
0
    gf_bs_write_data(bs, "empty hint DTE", 15);
561
0
    return GF_OK;
562
0
  }
563
0
  case 1:
564
0
  {
565
0
    GF_ImmediateDTE *dte = (GF_ImmediateDTE *)_dte;
566
0
    gf_bs_write_u8(bs, dte->source);
567
0
    gf_bs_write_u8(bs, dte->dataLength);
568
0
    gf_bs_write_data(bs, dte->data, dte->dataLength);
569
0
    if (dte->dataLength < 14) {
570
0
      char data[14];
571
0
      memset(data, 0, 14);
572
0
      gf_bs_write_data(bs, data, 14 - dte->dataLength);
573
0
    }
574
0
    return GF_OK;
575
0
  }
576
0
  case 2:
577
0
  {
578
0
    GF_SampleDTE *dte = (GF_SampleDTE *)_dte;
579
0
    gf_bs_write_u8(bs, dte->source);
580
0
    gf_bs_write_u8(bs, dte->trackRefIndex);
581
0
    gf_bs_write_u16(bs, dte->dataLength);
582
0
    gf_bs_write_u32(bs, dte->sampleNumber);
583
0
    gf_bs_write_u32(bs, dte->byteOffset);
584
0
    gf_bs_write_u16(bs, dte->bytesPerComp);
585
0
    gf_bs_write_u16(bs, dte->samplesPerComp);
586
0
    return GF_OK;
587
0
  }
588
0
  case 3:
589
0
  {
590
0
    GF_StreamDescDTE *dte = (GF_StreamDescDTE *)_dte;
591
0
    gf_bs_write_u8(bs, dte->source);
592
593
0
    gf_bs_write_u8(bs, dte->trackRefIndex);
594
0
    gf_bs_write_u16(bs, dte->dataLength);
595
0
    gf_bs_write_u32(bs, dte->streamDescIndex);
596
0
    gf_bs_write_u32(bs, dte->byteOffset);
597
0
    gf_bs_write_u32(bs, dte->reserved);
598
0
    return GF_OK;
599
0
  }
600
0
  default:
601
0
    return GF_ISOM_INVALID_FILE;
602
0
  }
603
0
}
604
605
GF_Err OffsetDTE(GF_GenericDTE *dte, u32 offset, u32 HintSampleNumber)
606
0
{
607
0
  GF_SampleDTE *sDTE;
608
  //offset shifting is only true for intra sample reference
609
0
  switch (dte->source) {
610
0
  case 2:
611
0
    break;
612
0
  default:
613
0
    return GF_OK;
614
0
  }
615
616
0
  sDTE = (GF_SampleDTE *)dte;
617
  //we only adjust for intra HintTrack reference
618
0
  if (sDTE->trackRefIndex != (s8) -1) return GF_OK;
619
  //and in the same sample
620
0
  if (sDTE->sampleNumber != HintSampleNumber) return GF_OK;
621
0
  sDTE->byteOffset += offset;
622
0
  return GF_OK;
623
0
}
624
625
GF_RTPPacket *gf_isom_hint_rtp_new()
626
0
{
627
0
  GF_RTPPacket *tmp;
628
0
  GF_SAFEALLOC(tmp, GF_RTPPacket);
629
0
  if (!tmp) return NULL;
630
0
  tmp->TLV = gf_list_new();
631
0
  tmp->DataTable = gf_list_new();
632
0
  return tmp;
633
0
}
634
635
void gf_isom_hint_rtp_del(GF_RTPPacket *ptr)
636
0
{
637
  //the DTE
638
0
  while (gf_list_count(ptr->DataTable)) {
639
0
    GF_GenericDTE *p = (GF_GenericDTE *)gf_list_get(ptr->DataTable, 0);
640
0
    DelDTE(p);
641
0
    gf_list_rem(ptr->DataTable, 0);
642
0
  }
643
0
  gf_list_del(ptr->DataTable);
644
  //the TLV
645
0
  gf_isom_box_array_del(ptr->TLV);
646
0
  gf_free(ptr);
647
0
}
648
649
GF_Err gf_isom_hint_rtp_read(GF_RTPPacket *ptr, GF_BitStream *bs)
650
0
{
651
0
  GF_Err e;
652
0
  u8 hasTLV, type;
653
0
  u16 i, count;
654
0
  u32 TLVsize, tempSize;
655
0
  GF_Box *a;
656
657
0
  ptr->relativeTransTime = gf_bs_read_u32(bs);
658
  //RTP Header
659
  //1- reserved fields
660
0
  gf_bs_read_int(bs, 2);
661
0
  ptr->P_bit = gf_bs_read_int(bs, 1);
662
0
  ptr->X_bit = gf_bs_read_int(bs, 1);
663
0
  gf_bs_read_int(bs, 4);
664
0
  ptr->M_bit = gf_bs_read_int(bs, 1);
665
0
  ptr->payloadType = gf_bs_read_int(bs, 7);
666
667
0
  ptr->SequenceNumber = gf_bs_read_u16(bs);
668
0
  gf_bs_read_int(bs, 13);
669
0
  hasTLV = gf_bs_read_int(bs, 1);
670
0
  ptr->B_bit = gf_bs_read_int(bs, 1);
671
0
  ptr->R_bit = gf_bs_read_int(bs, 1);
672
0
  count = gf_bs_read_u16(bs);
673
674
  //read the TLV
675
0
  if (hasTLV) {
676
0
    tempSize = 4; //TLVsize includes its field length
677
0
    TLVsize = gf_bs_read_u32(bs);
678
0
    while (tempSize < TLVsize) {
679
0
      e = gf_isom_box_parse(&a, bs);
680
0
      if (e) return e;
681
0
      if (!a) continue;
682
0
      gf_list_add(ptr->TLV, a);
683
0
      tempSize += (u32) a->size;
684
0
    }
685
0
    if (tempSize != TLVsize) return GF_ISOM_INVALID_FILE;
686
0
  }
687
688
  //read the DTEs
689
0
  for (i=0; i<count; i++) {
690
0
    GF_GenericDTE *dte;
691
0
    Bool add_it = 0;
692
0
    type = gf_bs_read_u8(bs);
693
0
    dte = NewDTE(type);
694
0
    if (!dte) {
695
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] invalid DTE code %d in hint sample %d of trackID %d\n", type, ptr->sampleNumber, ptr->trackID));
696
0
      return GF_ISOM_INVALID_FILE;
697
0
    }
698
0
    e = ReadDTE(dte, bs);
699
0
    if (e) return e;
700
    /*little opt, remove empty dte*/
701
0
    switch (type) {
702
0
    case 1:
703
0
      if ( ((GF_ImmediateDTE *)dte)->dataLength) add_it = 1;
704
0
      break;
705
0
    case 2:
706
0
      if ( ((GF_SampleDTE *)dte)->dataLength) add_it = 1;
707
0
      break;
708
0
    case 3:
709
0
      if ( ((GF_StreamDescDTE *)dte)->dataLength) add_it = 1;
710
0
      break;
711
0
    }
712
0
    if (add_it)
713
0
      gf_list_add(ptr->DataTable, dte);
714
0
    else
715
0
      DelDTE(dte);
716
0
  }
717
0
  return GF_OK;
718
0
}
719
720
GF_Err gf_isom_hint_rtp_offset(GF_RTPPacket *ptr, u32 offset, u32 HintSampleNumber)
721
0
{
722
0
  u32 count, i;
723
0
  GF_Err e;
724
725
0
  count = gf_list_count(ptr->DataTable);
726
0
  for (i=0; i<count; i++) {
727
0
    GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
728
0
    e = OffsetDTE(dte, offset, HintSampleNumber);
729
0
    if (e) return e;
730
0
  }
731
0
  return GF_OK;
732
0
}
733
734
//Gets the REAL size of the packet once rebuild, but without CSRC fields in the
735
//header
736
u32 gf_isom_hint_rtp_length(GF_RTPPacket *ptr)
737
0
{
738
0
  u32 size, count, i;
739
740
  //64 bit header
741
0
  size = 8;
742
  //32 bit SSRC
743
0
  size += 4;
744
0
  count = gf_list_count(ptr->DataTable);
745
0
  for (i=0; i<count; i++) {
746
0
    GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
747
0
    switch (dte->source) {
748
0
    case 0:
749
0
      break;
750
0
    case 1:
751
0
      size += ((GF_ImmediateDTE *)dte)->dataLength;
752
0
      break;
753
0
    case 2:
754
0
      size += ((GF_SampleDTE *)dte)->dataLength;
755
0
      break;
756
0
    case 3:
757
0
      size += ((GF_StreamDescDTE *)dte)->dataLength;
758
0
      break;
759
0
    }
760
0
  }
761
0
  return size;
762
0
}
763
764
765
#ifndef GPAC_DISABLE_ISOM_WRITE
766
767
u32 gf_isom_hint_rtp_size(GF_RTPPacket *ptr)
768
0
{
769
0
  GF_Box none;
770
0
  u32 size, count;
771
  //the RTP Header size and co
772
0
  size = 12;
773
  //the extra table size
774
0
  count = gf_list_count(ptr->TLV);
775
0
  if (count) {
776
0
    none.size = 4;  //WE INCLUDE THE SIZE FIELD LENGTH
777
0
    none.type = 0;
778
    //REMEMBER THAT TLV ENTRIES ARE 4-BYTES ALIGNED !!!
779
0
    gf_isom_box_array_size(&none, ptr->TLV);
780
0
    size += (u32) none.size;
781
0
  }
782
  //the DTE (each entry is 16 bytes)
783
0
  count = gf_list_count(ptr->DataTable);
784
0
  size += count * 16;
785
0
  return size;
786
0
}
787
788
GF_Err gf_isom_hint_rtp_write(GF_RTPPacket *ptr, GF_BitStream *bs)
789
0
{
790
0
  GF_Err e;
791
0
  u32 TLVcount, DTEcount, i;
792
0
  GF_Box none;
793
794
0
  gf_bs_write_u32(bs, ptr->relativeTransTime);
795
  //RTP Header
796
//  gf_bs_write_int(bs, 2, 2);
797
  //version is 2
798
0
  gf_bs_write_int(bs, 2, 2);
799
0
  gf_bs_write_int(bs, ptr->P_bit, 1);
800
0
  gf_bs_write_int(bs, ptr->X_bit, 1);
801
0
  gf_bs_write_int(bs, 0, 4);
802
0
  gf_bs_write_int(bs, ptr->M_bit, 1);
803
0
  gf_bs_write_int(bs, ptr->payloadType, 7);
804
805
0
  gf_bs_write_u16(bs, ptr->SequenceNumber);
806
0
  gf_bs_write_int(bs, 0, 13);
807
0
  TLVcount = gf_list_count(ptr->TLV);
808
0
  DTEcount = gf_list_count(ptr->DataTable);
809
0
  gf_bs_write_int(bs, TLVcount ? 1 : 0, 1);
810
0
  gf_bs_write_int(bs, ptr->B_bit, 1);
811
0
  gf_bs_write_int(bs, ptr->R_bit, 1);
812
813
0
  gf_bs_write_u16(bs, DTEcount);
814
815
0
  if (TLVcount) {
816
    //first write the size of the table ...
817
0
    none.size = 4;  //WE INCLUDE THE SIZE FIELD LENGTH
818
0
    none.type = 0;
819
0
    gf_isom_box_array_size(&none, ptr->TLV);
820
0
    gf_bs_write_u32(bs, (u32) none.size);
821
0
    e = gf_isom_box_array_write(&none, ptr->TLV, bs);
822
0
    if (e) return e;
823
0
  }
824
  //write the DTE...
825
0
  for (i = 0; i < DTEcount; i++) {
826
0
    GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
827
0
    e = WriteDTE(dte, bs);
828
0
    if (e) return e;
829
0
  }
830
0
  return GF_OK;
831
0
}
832
833
#endif /*GPAC_DISABLE_ISOM_WRITE*/
834
835
836
837
GF_RTCPPacket *gf_isom_hint_rtcp_new()
838
0
{
839
0
  GF_RTCPPacket *tmp;
840
0
  GF_SAFEALLOC(tmp, GF_RTCPPacket);
841
0
  return tmp;
842
0
}
843
844
void gf_isom_hint_rtcp_del(GF_RTCPPacket *ptr)
845
0
{
846
0
  if(ptr->data) gf_free(ptr->data);
847
0
  gf_free(ptr);
848
0
}
849
850
GF_Err gf_isom_hint_rtcp_read(GF_RTCPPacket *ptr, GF_BitStream *bs)
851
0
{
852
  //RTCP Header
853
854
0
  ptr->Version = gf_bs_read_int(bs, 2);
855
0
  ptr->Padding = gf_bs_read_int(bs, 1);
856
0
  ptr->Count = gf_bs_read_int(bs, 5);
857
0
  ptr->PayloadType = gf_bs_read_u8(bs);
858
0
  ptr->length = 4 * gf_bs_read_u16(bs);
859
0
  if (ptr->length<4) return GF_ISOM_INVALID_MEDIA;
860
861
  //remove header size
862
0
  if (gf_bs_available(bs) < ptr->length) {
863
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] RTCP hint packet has more data (%d) than available\n", ptr->length ));
864
0
    return GF_ISOM_INVALID_MEDIA;
865
0
  }
866
0
  ptr->data = gf_malloc(sizeof(char) * ptr->length);
867
0
  if (!ptr->data) return GF_OUT_OF_MEM;
868
0
  gf_bs_read_data(bs, ptr->data, ptr->length);
869
0
  return GF_OK;
870
0
}
871
872
873
//Gets the REAL size of the packet once rebuild, but without CSRC fields in the
874
//header
875
u32 gf_isom_hint_rtcp_length(GF_RTCPPacket *ptr)
876
0
{
877
0
  return 4 * (ptr->length + 1);
878
0
}
879
880
881
#ifndef GPAC_DISABLE_ISOM_WRITE
882
883
u32 gf_isom_hint_rtcp_size(GF_RTCPPacket *ptr)
884
0
{
885
0
  return 4 * (ptr->length + 1);
886
0
}
887
888
GF_Err gf_isom_hint_rtcp_write(GF_RTCPPacket *ptr, GF_BitStream *bs)
889
0
{
890
  //RTP Header
891
0
  gf_bs_write_int(bs, ptr->Version, 2);
892
0
  gf_bs_write_int(bs, ptr->Padding, 1);
893
0
  gf_bs_write_int(bs, ptr->Count, 5);
894
0
  gf_bs_write_u8(bs, ptr->PayloadType);
895
0
  gf_bs_write_u16(bs, 4*ptr->length);
896
0
  gf_bs_write_data(bs, ptr->data, ptr->length);
897
0
  return GF_OK;
898
0
}
899
900
#endif /*GPAC_DISABLE_ISOM_WRITE*/
901
902
903
904
#if 0 //unused
905
906
/*small hint reader - performs data caching*/
907
908
/*resets hint reading parameters, returns an error if the hint type is not supported for reading
909
packet sequence number is always reseted to 0
910
@sample_start: indicates from where the packets should be read (regular 1-based sample number)
911
@ts_offset: constant offset for timestamps, must be expressed in media timescale (which is the hint timescale).
912
  usually 0 (no offset)
913
@sn_offset: offset for packet sequence number (first packet will have a SN of 1 + sn_offset)
914
  usually 0
915
@ssrc: sync source identifier for RTP
916
*/
917
918
GF_Err gf_isom_reset_hint_reader(GF_ISOFile *the_file, u32 trackNumber, u32 sample_start, u32 ts_offset, u32 sn_offset, u32 ssrc)
919
{
920
  GF_Err e;
921
  GF_TrackBox *trak;
922
  GF_HintSampleEntryBox *entry;
923
924
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
925
  if (!trak) return GF_BAD_PARAM;
926
927
  if (!sample_start) return GF_BAD_PARAM;
928
  if (sample_start>=trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;
929
930
  e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
931
  if (e) return e;
932
  switch (entry->type) {
933
  case GF_ISOM_BOX_TYPE_RTP_STSD:
934
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
935
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
936
    break;
937
  default:
938
    return GF_NOT_SUPPORTED;
939
  }
940
941
  entry->hint_ref = NULL;
942
  e = Track_FindRef(trak, GF_ISOM_REF_HINT, &entry->hint_ref);
943
  if (e) return e;
944
945
  entry->cur_sample = sample_start;
946
  entry->pck_sn = 1 + sn_offset;
947
  entry->ssrc = ssrc;
948
  entry->ts_offset = ts_offset;
949
  if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
950
  entry->hint_sample = NULL;
951
  return GF_OK;
952
}
953
954
static GF_Err gf_isom_load_next_hint_sample(GF_ISOFile *the_file, u32 trackNumber, GF_TrackBox *trak, GF_HintSampleEntryBox *entry)
955
{
956
  GF_BitStream *bs;
957
  u32 descIdx;
958
  GF_ISOSample *samp;
959
960
  if (!entry->cur_sample) return GF_BAD_PARAM;
961
  if (entry->cur_sample>trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_EOS;
962
963
  samp = gf_isom_get_sample(the_file, trackNumber, entry->cur_sample, &descIdx);
964
  if (!samp) return GF_IO_ERR;
965
  entry->cur_sample++;
966
967
  if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
968
969
  bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
970
  entry->hint_sample = gf_isom_hint_sample_new(entry->type);
971
  gf_isom_hint_sample_read(entry->hint_sample, bs, samp->dataLength);
972
  gf_bs_del(bs);
973
  entry->hint_sample->TransmissionTime = samp->DTS;
974
  gf_isom_sample_del(&samp);
975
  entry->hint_sample->sample_cache = gf_list_new();
976
  return GF_OK;
977
}
978
979
static GF_ISOSample *gf_isom_get_data_sample(GF_HintSample *hsamp, GF_TrackBox *trak, u32 sample_num)
980
{
981
  GF_ISOSample *samp;
982
  GF_HintDataCache *hdc;
983
  u32 i, count;
984
  count = gf_list_count(hsamp->sample_cache);
985
  for (i=0; i<count; i++) {
986
    hdc = (GF_HintDataCache *)gf_list_get(hsamp->sample_cache, i);
987
    if ((hdc->sample_num==sample_num) && (hdc->trak==trak)) return hdc->samp;
988
  }
989
990
  samp = gf_isom_sample_new();
991
  Media_GetSample(trak->Media, sample_num, &samp, &i, 0, NULL, GF_FALSE);
992
  if (!samp) return NULL;
993
  GF_SAFEALLOC(hdc, GF_HintDataCache);
994
  if (!hdc) return NULL;
995
  hdc->samp = samp;
996
  hdc->sample_num = sample_num;
997
  hdc->trak = trak;
998
  /*we insert all new samples, since they're more likely to be fetched next (except for audio
999
  interleaving and other multiplex)*/
1000
  gf_list_insert(hsamp->sample_cache, hdc, 0);
1001
  return samp;
1002
}
1003
1004
/*reads next hint packet. ALl packets are read in transmission (decoding) order
1005
returns an error if not supported, or GF_EOS when no more packets are available
1006
currently only RTP reader is supported
1007
@pck_data, @pck_size: output packet data (must be freed by caller) - contains all info to be sent
1008
  on the wire, eg for RTP contains the RTP header and the data
1009
@disposable (optional): indicates that the packet can be dropped when late (B-frames & co)
1010
@repeated (optional): indicates this is a repeated packet (same one has already been sent)
1011
@trans_ts (optional): indicates the transmission time of the packet, expressed in hint timescale, taking into account
1012
the ts_offset specified in gf_isom_reset_hint_reader. Depending on packets this may not be the same
1013
as the hint sample timestamp + ts_offset, some packets may need to be sent earlier (B-frames)
1014
@sample_num (optional): indicates hint sample number the packet belongs to
1015
*/
1016
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)
1017
{
1018
  GF_RTPPacket *pck;
1019
  GF_Err e;
1020
  GF_BitStream *bs;
1021
  GF_TrackBox *trak, *ref_trak;
1022
  GF_HintSampleEntryBox *entry;
1023
  u32 i, count, ts;
1024
  s32 cts_off;
1025
1026
  *pck_data = NULL;
1027
  *pck_size = 0;
1028
  if (trans_ts) *trans_ts = 0;
1029
  if (disposable) *disposable = 0;
1030
  if (repeated) *repeated = 0;
1031
  if (sample_num) *sample_num = 0;
1032
1033
  trak = gf_isom_get_track_from_file(the_file, trackNumber);
1034
  if (!trak) return GF_BAD_PARAM;
1035
  e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
1036
  if (e) return e;
1037
  switch (entry->type) {
1038
  case GF_ISOM_BOX_TYPE_RTP_STSD:
1039
  case GF_ISOM_BOX_TYPE_SRTP_STSD:
1040
  case GF_ISOM_BOX_TYPE_RRTP_STSD:
1041
    break;
1042
  default:
1043
    return GF_NOT_SUPPORTED;
1044
  }
1045
1046
  if (!entry->hint_sample) {
1047
    e = gf_isom_load_next_hint_sample(the_file, trackNumber, trak, entry);
1048
    if (e) return e;
1049
  }
1050
  pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, 0);
1051
  gf_list_rem(entry->hint_sample->packetTable, 0);
1052
  if (!pck) return GF_BAD_PARAM;
1053
1054
  bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
1055
  /*write RTP header*/
1056
  gf_bs_write_int(bs, 2, 2);  /*version*/
1057
  gf_bs_write_int(bs, pck->P_bit, 1); /*P bit*/
1058
  gf_bs_write_int(bs, pck->X_bit, 1); /*X bit*/
1059
  gf_bs_write_int(bs, 0, 4);  /*CSRC count*/
1060
  gf_bs_write_int(bs, pck->M_bit, 1); /*M bit*/
1061
  gf_bs_write_int(bs, pck->payloadType, 7); /*payt*/
1062
  gf_bs_write_u16(bs, entry->pck_sn); /*seq num*/
1063
  entry->pck_sn++;
1064
1065
  /*look for CTS offset in TLV*/
1066
  cts_off = 0;
1067
  count = gf_list_count(pck->TLV);
1068
  for (i=0; i<count; i++) {
1069
    GF_RTPOBox *rtpo = (GF_RTPOBox *)gf_list_get(pck->TLV, i);
1070
    if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
1071
      cts_off = rtpo->timeOffset;
1072
      break;
1073
    }
1074
  }
1075
  /*TS - TODO check TS wrapping*/
1076
  ts = (u32) (entry->hint_sample->TransmissionTime + pck->relativeTransTime + entry->ts_offset + cts_off);
1077
  gf_bs_write_u32(bs, ts );
1078
  gf_bs_write_u32(bs, entry->ssrc); /*SSRC*/
1079
1080
  /*then build all data*/
1081
  count = gf_list_count(pck->DataTable);
1082
  for (i=0; i<count; i++) {
1083
    GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(pck->DataTable, i);
1084
    switch (dte->source) {
1085
    /*empty*/
1086
    case 0:
1087
      break;
1088
    /*immediate data*/
1089
    case 1:
1090
      gf_bs_write_data(bs, ((GF_ImmediateDTE *)dte)->data, ((GF_ImmediateDTE *)dte)->dataLength);
1091
      break;
1092
    /*sample data*/
1093
    case 2:
1094
    {
1095
      GF_ISOSample *samp;
1096
      GF_SampleDTE *sdte = (GF_SampleDTE *)dte;
1097
      /*get track if not this one*/
1098
      if (sdte->trackRefIndex != (s8) -1) {
1099
        if (!entry->hint_ref || !entry->hint_ref->trackIDs) {
1100
          gf_isom_hint_rtp_del(pck);
1101
          gf_bs_del(bs);
1102
          return GF_ISOM_INVALID_FILE;
1103
        }
1104
        ref_trak = gf_isom_get_track_from_id(trak->moov, entry->hint_ref->trackIDs[(u32)sdte->trackRefIndex]);
1105
      } else {
1106
        ref_trak = trak;
1107
      }
1108
      samp = gf_isom_get_data_sample(entry->hint_sample, ref_trak, sdte->sampleNumber);
1109
      if (!samp) {
1110
        gf_isom_hint_rtp_del(pck);
1111
        gf_bs_del(bs);
1112
        return GF_IO_ERR;
1113
      }
1114
      gf_bs_write_data(bs, samp->data + sdte->byteOffset, sdte->dataLength);
1115
    }
1116
    break;
1117
    /*sample desc data - currently NOT SUPPORTED !!!*/
1118
    case 3:
1119
      break;
1120
    }
1121
  }
1122
  if (trans_ts) *trans_ts = ts;
1123
  if (disposable) *disposable = pck->B_bit;
1124
  if (repeated) *repeated = pck->R_bit;
1125
  if (sample_num) *sample_num = entry->cur_sample-1;
1126
1127
  gf_bs_get_content(bs, pck_data, pck_size);
1128
  gf_bs_del(bs);
1129
  gf_isom_hint_rtp_del(pck);
1130
  if (!gf_list_count(entry->hint_sample->packetTable)) {
1131
    gf_isom_hint_sample_del(entry->hint_sample);
1132
    entry->hint_sample = NULL;
1133
  }
1134
  return GF_OK;
1135
}
1136
1137
#endif
1138
1139
1140
#endif /* !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)*/