Coverage Report

Created: 2026-01-17 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/ietf/rtp_pck_3gpp.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2024
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / IETF RTP/RTSP/SDP 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/ietf_dev.h>
27
28
#ifndef GPAC_DISABLE_STREAMING
29
30
#include <gpac/constants.h>
31
32
static void rtp_amr_flush(GP_RTPPacketizer *builder)
33
0
{
34
0
  u8 *hdr;
35
0
  u32 hdr_size;
36
0
  if (!builder->bytesInPacket) return;
37
0
  gf_bs_get_content(builder->pck_hdr, &hdr, &hdr_size);
38
0
  gf_bs_del(builder->pck_hdr);
39
0
  builder->pck_hdr = NULL;
40
  /*overwrite last frame F bit*/
41
0
  hdr[builder->last_au_sn] &= 0x7F;
42
0
  builder->OnData(builder->cbk_obj, hdr, hdr_size, GF_TRUE);
43
0
  gf_free(hdr);
44
0
  builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
45
0
  builder->bytesInPacket = 0;
46
0
  builder->last_au_sn = 0;
47
0
}
48
49
GF_Err gp_rtp_builder_do_amr(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
50
0
{
51
0
  u32 offset, rtp_ts, block_size;
52
53
0
  if (!data) {
54
0
    rtp_amr_flush(builder);
55
0
    return GF_OK;
56
0
  }
57
58
0
  rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
59
60
0
  offset = 0;
61
0
  while (data_size>offset) {
62
0
    u8 ft = (data[offset] & 0x78) >> 3;
63
0
    u8 size;
64
65
0
    if (builder->rtp_payt == GF_RTP_PAYT_AMR_WB) {
66
0
      size = (u32)GF_AMR_WB_FRAME_SIZE[ft];
67
0
      block_size = 320;
68
0
    } else {
69
0
      size = (u32)GF_AMR_FRAME_SIZE[ft];
70
0
      block_size = 160;
71
0
    }
72
73
    /*packet full or too long*/
74
0
    if (builder->bytesInPacket + 1 + size > builder->Path_MTU)
75
0
      rtp_amr_flush(builder);
76
77
    /*need new*/
78
0
    if (!builder->bytesInPacket) {
79
0
      builder->rtp_header.TimeStamp = rtp_ts;
80
0
      builder->rtp_header.Marker = 0; /*never set*/
81
0
      builder->rtp_header.SequenceNumber += 1;
82
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
83
0
      gf_assert(builder->pck_hdr==NULL);
84
85
      /*always have header and TOC*/
86
0
      builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
87
      /*CMR + res (all 0, no interleaving)*/
88
0
      gf_bs_write_int(builder->pck_hdr, ft, 4);
89
0
      gf_bs_write_int(builder->pck_hdr, 0, 4);
90
0
      builder->bytesInPacket = 1;
91
      /*no interleaving*/
92
0
    }
93
94
    /*F always to 1*/
95
0
    gf_bs_write_int(builder->pck_hdr, 1, 1);
96
0
    gf_bs_write_int(builder->pck_hdr, ft, 4);
97
    /*Q*/
98
0
    gf_bs_write_int(builder->pck_hdr, (data[offset] & 0x4) ? 1 : 0, 1);
99
0
    gf_bs_write_int(builder->pck_hdr, 0, 2);
100
0
    builder->bytesInPacket ++;
101
102
    /*remove frame type byte*/
103
0
    offset++;
104
105
    /*add frame data without rate_type byte header*/
106
0
    if (builder->OnDataReference) {
107
0
      builder->OnDataReference(builder->cbk_obj, size, offset);
108
0
    } else {
109
0
      builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
110
0
    }
111
0
    builder->last_au_sn++;
112
0
    builder->bytesInPacket += size;
113
0
    offset += size;
114
0
    rtp_ts += block_size;
115
0
    gf_assert(builder->bytesInPacket<=builder->Path_MTU);
116
    /*take care of aggregation, flush if needed*/
117
0
    if (builder->last_au_sn==builder->auh_size) rtp_amr_flush(builder);
118
0
  }
119
0
  return GF_OK;
120
0
}
121
122
static GFINLINE u8 qes_get_rate_size(u32 idx, const unsigned int *rates, const unsigned int nb_rates)
123
0
{
124
0
  u32 i;
125
0
  for (i=0; i<nb_rates; i++) {
126
0
    if (rates[2*i]==idx) return rates[2*i+1];
127
0
  }
128
0
  return 0;
129
0
}
130
131
GF_Err gp_rtp_builder_do_qcelp(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
132
0
{
133
0
  u32 offset, rtp_ts;
134
0
  u8 hdr;
135
136
0
  if (!data) {
137
0
    if (builder->bytesInPacket) builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
138
0
    builder->bytesInPacket = 0;
139
0
    builder->last_au_sn = 0;
140
0
    return GF_OK;
141
0
  }
142
143
0
  rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
144
145
146
0
  offset = 0;
147
0
  while (data_size>offset) {
148
0
    u8 frame_type = data[offset];
149
0
    u8 size = qes_get_rate_size(frame_type, GF_QCELP_RATE_TO_SIZE, GF_QCELP_RATE_TO_SIZE_NB);
150
    /*reserved, not sent)*/
151
0
    if (frame_type>=5) {
152
0
      offset += size;
153
0
      continue;
154
0
    }
155
    /*packet full or too long*/
156
0
    if (builder->bytesInPacket + size > builder->Path_MTU) {
157
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
158
0
      builder->bytesInPacket = 0;
159
0
      builder->last_au_sn = 0;
160
0
    }
161
162
    /*need new*/
163
0
    if (!builder->bytesInPacket) {
164
0
      builder->rtp_header.TimeStamp = rtp_ts;
165
0
      builder->rtp_header.Marker = 0; /*never set*/
166
0
      builder->rtp_header.SequenceNumber += 1;
167
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
168
0
      hdr = 0;/*no interleaving*/
169
0
      builder->OnData(builder->cbk_obj, (char*)&hdr, 1, GF_FALSE);
170
0
      builder->bytesInPacket = 1;
171
0
    }
172
0
    if (builder->OnDataReference) {
173
0
      builder->OnDataReference(builder->cbk_obj, size, offset);
174
0
    } else {
175
0
      builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
176
0
    }
177
0
    builder->bytesInPacket += size;
178
0
    offset += size;
179
0
    rtp_ts += 160;
180
0
    gf_assert(builder->bytesInPacket<=builder->Path_MTU);
181
182
    /*take care of aggregation, flush if needed*/
183
0
    builder->last_au_sn++;
184
0
    if (builder->last_au_sn==builder->auh_size) {
185
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
186
0
      builder->bytesInPacket = 0;
187
0
      builder->last_au_sn = 0;
188
0
    }
189
0
  }
190
0
  return GF_OK;
191
0
}
192
193
static void rtp_evrc_smv_flush(GP_RTPPacketizer *builder)
194
0
{
195
0
  if (!builder->bytesInPacket) return;
196
0
  if (builder->auh_size>1) {
197
0
    u8 *hdr;
198
0
    u32 hdr_size;
199
    /*padding*/
200
0
    if (builder->last_au_sn % 2) gf_bs_write_int(builder->pck_hdr, 0, 4);
201
0
    gf_bs_get_content(builder->pck_hdr, &hdr, &hdr_size);
202
0
    gf_bs_del(builder->pck_hdr);
203
0
    builder->pck_hdr = NULL;
204
    /*overwrite count*/
205
0
    hdr[0] = 0;
206
0
    hdr[1] = builder->last_au_sn-1;/*MMM + frameCount-1*/
207
0
    builder->OnData(builder->cbk_obj, hdr, hdr_size, GF_TRUE);
208
0
    gf_free(hdr);
209
0
  }
210
0
  builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
211
0
  builder->bytesInPacket = 0;
212
0
  builder->last_au_sn = 0;
213
0
}
214
215
GF_Err gp_rtp_builder_do_smv(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
216
0
{
217
0
  u32 offset, rtp_ts;
218
219
0
  if (!data) {
220
0
    rtp_evrc_smv_flush(builder);
221
0
    return GF_OK;
222
0
  }
223
224
0
  rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
225
226
0
  offset = 0;
227
0
  while (data_size>offset) {
228
0
    u8 frame_type = data[offset];
229
0
    u8 size = qes_get_rate_size(frame_type, GF_SMV_EVRC_RATE_TO_SIZE, GF_SMV_EVRC_RATE_TO_SIZE_NB);
230
231
    /*reserved, not sent)*/
232
0
    if (frame_type>=5) {
233
0
      offset += size;
234
0
      continue;
235
0
    }
236
    /*packet full or too long*/
237
0
    if (builder->bytesInPacket + size > builder->Path_MTU)
238
0
      rtp_evrc_smv_flush(builder);
239
240
    /*need new*/
241
0
    if (!builder->bytesInPacket) {
242
0
      builder->rtp_header.TimeStamp = rtp_ts;
243
0
      builder->rtp_header.Marker = 0; /*never set*/
244
0
      builder->rtp_header.SequenceNumber += 1;
245
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
246
0
      gf_assert(builder->pck_hdr==NULL);
247
248
0
      if (builder->auh_size>1) {
249
0
        builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
250
        /*RRLLLNNN (all 0, no interleaving)*/
251
0
        gf_bs_write_u8(builder->pck_hdr, 0);
252
        /*MMM + count-1 : overridden when flushing*/
253
0
        gf_bs_write_u8(builder->pck_hdr, 0);
254
0
        builder->bytesInPacket = 2;
255
0
      }
256
0
    }
257
258
    /*bundle mode: cat rate byte to TOC, on 4 bits*/
259
0
    if (builder->auh_size>1) {
260
0
      gf_bs_write_int(builder->pck_hdr, data[offset], 4);
261
0
      if (!(builder->last_au_sn % 2)) builder->bytesInPacket += 1;
262
0
    }
263
    /*note that EVEN in header-free format the rate_type byte is removed*/
264
0
    offset++;
265
0
    size--;
266
267
    /*add frame data without rate_type byte header*/
268
0
    if (builder->OnDataReference) {
269
0
      builder->OnDataReference(builder->cbk_obj, size, offset);
270
0
    } else {
271
0
      builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
272
0
    }
273
0
    builder->last_au_sn++;
274
0
    builder->bytesInPacket += size;
275
0
    offset += size;
276
0
    rtp_ts += 160;
277
0
    gf_assert(builder->bytesInPacket<=builder->Path_MTU);
278
    /*take care of aggregation, flush if needed*/
279
0
    if (builder->last_au_sn==builder->auh_size) rtp_evrc_smv_flush(builder);
280
0
  }
281
0
  return GF_OK;
282
0
}
283
284
GF_Err gp_rtp_builder_do_h263(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
285
0
{
286
0
  u8 hdr[2];
287
0
  Bool Pbit;
288
0
  u32 offset, size, max_size;
289
290
0
  builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
291
292
  /*the H263 hinter doesn't perform inter-sample concatenation*/
293
0
  if (!data) return GF_OK;
294
295
0
  Pbit = GF_TRUE;
296
297
  /*skip 16 0'ed bits of start code*/
298
0
  offset = 2;
299
0
  data_size -= 2;
300
0
  max_size = builder->Path_MTU - 2;
301
302
0
  while(data_size > 0) {
303
0
    GF_BitStream *bs;
304
0
    if(data_size > max_size) {
305
0
      size = max_size;
306
0
      builder->rtp_header.Marker = 0;
307
0
    } else {
308
0
      size = data_size;
309
0
      builder->rtp_header.Marker = 1;
310
0
    }
311
312
0
    data_size -= size;
313
314
    /*create new RTP Packet */
315
0
    builder->rtp_header.SequenceNumber += 1;
316
0
    builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
317
318
0
    bs = gf_bs_new(hdr, 2, GF_BITSTREAM_WRITE);
319
0
    gf_bs_write_int(bs, 0, 5);
320
0
    gf_bs_write_int(bs, Pbit, 1);
321
0
    gf_bs_write_int(bs, 0, 10);
322
0
    gf_bs_del(bs);
323
324
    /*add header*/
325
0
    builder->OnData(builder->cbk_obj, (char*) hdr, 2, GF_TRUE);
326
    /*add payload*/
327
0
    if (builder->OnDataReference)
328
0
      builder->OnDataReference(builder->cbk_obj, size, offset);
329
0
    else
330
0
      builder->OnData(builder->cbk_obj, data + offset, size, GF_FALSE);
331
332
0
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
333
334
0
    offset += size;
335
0
    Pbit = GF_FALSE;
336
0
  }
337
0
  return GF_OK;
338
0
}
339
340
GF_Err gp_rtp_builder_do_mp2t(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
341
0
{
342
0
  u32 offset, size, max_size;
343
344
0
  builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
345
346
0
  if (!data) return GF_OK;
347
348
0
  max_size = builder->Path_MTU;
349
0
  offset = 0;
350
0
  while (data_size > 0) {
351
0
    if (data_size > max_size) {
352
0
      size = max_size / 188;
353
0
      size *= 188;
354
0
    } else {
355
0
      size = data_size;
356
0
    }
357
358
0
    data_size -= size;
359
360
    /*create new RTP Packet */
361
0
    builder->rtp_header.SequenceNumber += 1;
362
0
    builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
363
364
    /*add payload*/
365
0
    if (builder->OnDataReference)
366
0
      builder->OnDataReference(builder->cbk_obj, size, offset);
367
0
    else
368
0
      builder->OnData(builder->cbk_obj, data + offset, size, GF_TRUE);
369
370
0
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
371
372
0
    offset += size;
373
0
  }
374
0
  return GF_OK;
375
0
}
376
GF_Err gp_rtp_builder_do_tx3g(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration, u8 descIndex)
377
0
{
378
0
  GF_BitStream *bs;
379
0
  u8 *hdr;
380
0
  u32 samp_size, txt_size, pay_start, hdr_size, txt_done, cur_frag, nb_frag;
381
0
  Bool is_utf_16 = GF_FALSE;
382
383
0
  if (!data) {
384
    /*flush packet*/
385
0
    if (builder->bytesInPacket) {
386
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
387
0
      builder->bytesInPacket = 0;
388
0
    }
389
0
    return GF_OK;
390
0
  }
391
0
  if (data_size<2) return GF_NON_COMPLIANT_BITSTREAM;
392
393
  /*cfg packet*/
394
0
  txt_size = data[0];
395
0
  txt_size <<= 8;
396
0
  txt_size |= (unsigned char) data[1];
397
  /*remove BOM*/
398
0
  pay_start = 2;
399
0
  if (txt_size>2) {
400
0
    if (data_size<4) return GF_NON_COMPLIANT_BITSTREAM;
401
    /*seems 3GP only accepts BE UTF-16 (no LE, no UTF32)*/
402
0
    if (((u8) data[2]==(u8) 0xFE) && ((u8) data[3]==(u8) 0xFF)) {
403
0
      is_utf_16 = GF_TRUE;
404
0
      pay_start = 4;
405
0
      txt_size -= 2;
406
0
    }
407
0
  }
408
0
  samp_size = data_size - pay_start;
409
410
  /*if TTU does not fit in packet flush packet*/
411
0
  if (builder->bytesInPacket && (builder->bytesInPacket + 3 + 6 + samp_size > builder->Path_MTU)) {
412
0
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
413
0
    builder->bytesInPacket = 0;
414
0
  }
415
  //we only deal with static SIDX
416
0
  descIndex += GF_RTP_TX3G_SIDX_OFFSET;
417
418
  /*first TTU in packet*/
419
0
  if (!builder->bytesInPacket) {
420
0
    builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
421
0
    builder->rtp_header.Marker = 1;
422
0
    builder->rtp_header.SequenceNumber += 1;
423
0
    builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
424
0
  }
425
  /*fits entirely*/
426
0
  if (builder->bytesInPacket + 3 + 6 + samp_size <= builder->Path_MTU) {
427
0
    bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
428
0
    gf_bs_write_int(bs, is_utf_16, 1);
429
0
    gf_bs_write_int(bs, 0, 4);
430
0
    gf_bs_write_int(bs, 1, 3);
431
0
    gf_bs_write_u16(bs, 8 + samp_size);
432
0
    gf_bs_write_u8(bs, descIndex);
433
0
    gf_bs_write_u24(bs, duration);
434
0
    gf_bs_write_u16(bs, txt_size);
435
0
    gf_bs_get_content(bs, &hdr, &hdr_size);
436
0
    gf_bs_del(bs);
437
0
    builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
438
0
    builder->bytesInPacket += hdr_size;
439
0
    gf_free(hdr);
440
441
0
    if (txt_size) {
442
0
      if (builder->OnDataReference) {
443
0
        builder->OnDataReference(builder->cbk_obj, samp_size, pay_start);
444
0
      } else {
445
0
        builder->OnData(builder->cbk_obj, data + pay_start, samp_size, GF_FALSE);
446
0
      }
447
0
      builder->bytesInPacket += samp_size;
448
0
    }
449
    /*disable aggregation*/
450
0
    if (!(builder->flags & GP_RTP_PCK_USE_MULTI)) {
451
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
452
0
      builder->bytesInPacket = 0;
453
0
    }
454
0
    return GF_OK;
455
0
  }
456
  /*doesn't fit and already data, flush packet*/
457
0
  if (builder->bytesInPacket) {
458
0
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
459
0
    builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
460
    /*split unit*/
461
0
    builder->rtp_header.Marker = 0;
462
0
    builder->rtp_header.SequenceNumber += 1;
463
0
    builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
464
0
    builder->bytesInPacket = 0;
465
0
  }
466
  /*write all type2 units (text only) - FIXME: split at char boundaries, NOT SUPPORTED YET*/
467
0
  txt_done = 0;
468
0
  nb_frag = 1;
469
  /*all fragments needed for Type2 units*/
470
0
  while (txt_done + (builder->Path_MTU-10) < txt_size) {
471
0
    txt_done += (builder->Path_MTU-10);
472
0
    nb_frag += 1;
473
0
  }
474
  /*all fragments needed for Type3/4 units*/
475
0
  txt_done = txt_size;
476
0
  while (txt_done + (builder->Path_MTU-7) < samp_size) {
477
0
    txt_done += (builder->Path_MTU-7);
478
0
    nb_frag += 1;
479
0
  }
480
481
482
0
  cur_frag = 0;
483
0
  txt_done = 0;
484
0
  while (txt_done<txt_size) {
485
0
    u32 size;
486
0
    if (txt_done + (builder->Path_MTU-10) < txt_size) {
487
0
      size = builder->Path_MTU-10;
488
0
    } else {
489
0
      size = txt_size - txt_done;
490
0
    }
491
492
0
    bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
493
0
    gf_bs_write_int(bs, is_utf_16, 1);
494
0
    gf_bs_write_int(bs, 0, 4);
495
0
    gf_bs_write_int(bs, 2, 3);
496
0
    gf_bs_write_u16(bs, 9 + size);
497
0
    gf_bs_write_int(bs, nb_frag, 4);
498
0
    gf_bs_write_int(bs, cur_frag, 4);
499
0
    gf_bs_write_u24(bs, duration);
500
0
    gf_bs_write_u8(bs, descIndex);
501
    /*SLEN is the full original length minus text len and BOM (put here for buffer allocation purposes)*/
502
0
    gf_bs_write_u16(bs, samp_size);
503
0
    gf_bs_get_content(bs, &hdr, &hdr_size);
504
0
    gf_bs_del(bs);
505
0
    builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
506
0
    builder->bytesInPacket += hdr_size;
507
0
    gf_free(hdr);
508
509
0
    if (builder->OnDataReference) {
510
0
      builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done);
511
0
    } else {
512
0
      builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, GF_FALSE);
513
0
    }
514
0
    builder->bytesInPacket += size;
515
0
    cur_frag++;
516
517
    /*flush packet*/
518
0
    if (cur_frag == nb_frag) {
519
0
      txt_done = txt_size;
520
0
      if (pay_start + txt_done == data_size) {
521
0
        builder->rtp_header.Marker = 1;
522
0
        builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
523
0
        builder->bytesInPacket = 0;
524
0
      }
525
0
    } else {
526
0
      txt_done += size;
527
0
      builder->rtp_header.Marker = 0;
528
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
529
0
      builder->rtp_header.SequenceNumber += 1;
530
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
531
0
      builder->bytesInPacket = 0;
532
0
    }
533
0
  }
534
535
0
  txt_done = txt_size;
536
537
  /*write all modifiers - OPT: split at modifiers boundaries*/
538
0
  while (txt_done<samp_size) {
539
0
    u32 size, type;
540
0
    type = (txt_done == txt_size) ? 3 : 4;
541
542
0
    if (txt_done + (builder->Path_MTU-7) < samp_size) {
543
0
      size = builder->Path_MTU-10;
544
0
    } else {
545
0
      size = samp_size - txt_done;
546
0
    }
547
548
0
    bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
549
0
    gf_bs_write_int(bs, is_utf_16, 1);
550
0
    gf_bs_write_int(bs, 0, 4);
551
0
    gf_bs_write_int(bs, type, 3);
552
0
    gf_bs_write_u16(bs, 6 + size);
553
0
    gf_bs_write_int(bs, nb_frag, 4);
554
0
    gf_bs_write_int(bs, cur_frag, 4);
555
0
    gf_bs_write_u24(bs, duration);
556
557
0
    gf_bs_get_content(bs, &hdr, &hdr_size);
558
0
    gf_bs_del(bs);
559
0
    builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
560
0
    builder->bytesInPacket += hdr_size;
561
0
    gf_free(hdr);
562
563
0
    if (builder->OnDataReference) {
564
0
      builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done);
565
0
    } else {
566
0
      builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, GF_FALSE);
567
0
    }
568
0
    builder->bytesInPacket += size;
569
0
    cur_frag++;
570
0
    if (cur_frag==nb_frag) {
571
0
      builder->rtp_header.Marker = 1;
572
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
573
0
      builder->bytesInPacket = 0;
574
0
    } else {
575
0
      builder->rtp_header.Marker = 0;
576
0
      builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
577
0
      builder->rtp_header.SequenceNumber += 1;
578
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
579
0
      builder->bytesInPacket = 0;
580
0
    }
581
0
    txt_done += size;
582
0
  }
583
0
  return GF_OK;
584
0
}
585
586
587
#if GPAC_ENABLE_3GPP_DIMS_RTP
588
GF_Err gp_rtp_builder_do_dims(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
589
{
590
  u32 frag_state;
591
  GF_BitStream *bs;
592
  u32 offset;
593
  Bool is_last_du;
594
595
  /*the DIMS hinter doesn't perform inter-sample concatenation*/
596
  if (!data) return GF_OK;
597
598
  offset = 0;
599
  builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
600
  bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
601
  while (offset < data_size) {
602
    u32 du_offset = 0;
603
    u32 hdr_offset = 0;
604
    u32 orig_size, du_size;
605
606
    orig_size = du_size = 2+gf_bs_read_u16(bs);
607
    /*if dims size is >0xFFFF, use our internal hack for large units*/
608
    if (du_size==2) {
609
      orig_size = du_size = 2+gf_bs_read_u32(bs);
610
      hdr_offset = 4;
611
    }
612
    gf_bs_skip_bytes(bs, du_size-2);
613
614
    /*prepare M-bit*/
615
    is_last_du = (offset+du_size==data_size) ? GF_TRUE : GF_FALSE;
616
617
    frag_state = 0;
618
    while (du_size) {
619
      u32 size_offset = 0;
620
      u32 size;
621
      //size = du_size;
622
623
      /*does not fit, flush required*/
624
      if (builder->bytesInPacket && (du_size + 1 + builder->bytesInPacket > builder->Path_MTU)) {
625
        builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
626
        builder->bytesInPacket = 0;
627
      }
628
629
      /*fragmentation required*/
630
      if (du_size + 1 > builder->Path_MTU) {
631
        size = builder->Path_MTU - 1;
632
        /*first fragment*/
633
        if (!frag_state) {
634
          /*size field is skipped !!*/
635
          size_offset = 2 + hdr_offset;
636
          frag_state = 1;
637
638
          while (du_size - size_offset <= size) {
639
            size--;
640
          }
641
        }
642
        /*any middle fragment*/
643
        else frag_state = 2;
644
645
        builder->rtp_header.Marker = 0;
646
      }
647
      /*last fragment*/
648
      else if (frag_state) {
649
        size = du_size;
650
        frag_state = 3;
651
        builder->rtp_header.Marker = is_last_du;
652
      } else {
653
        size = du_size;
654
        builder->rtp_header.Marker = is_last_du;
655
      }
656
657
      if (frag_state && builder->bytesInPacket) {
658
        builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
659
        builder->bytesInPacket = 0;
660
      }
661
662
      /*need a new packet*/
663
      if (!builder->bytesInPacket) {
664
        char dims_rtp_hdr[1];
665
666
        /*the unit is critical, increase counter (coded on 3 bits)*/
667
        if (! (data[2+hdr_offset] & GF_DIMS_UNIT_P) && (frag_state <= 1) ) {
668
          builder->last_au_sn++;
669
          builder->last_au_sn %= 8;
670
        }
671
        /*set CTR value*/
672
        dims_rtp_hdr[0] = builder->last_au_sn;
673
        /*if M-bit is set in the dims unit header, replicate it*/
674
        if (data[2+hdr_offset] & (1<<1) ) dims_rtp_hdr[0] |= (1<<6);
675
        /*add unit fragmentation type*/
676
        dims_rtp_hdr[0] |= (frag_state<<3);
677
678
        builder->rtp_header.SequenceNumber += 1;
679
        builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
680
        builder->OnData(builder->cbk_obj, (char *) dims_rtp_hdr, 1, GF_TRUE);
681
        builder->bytesInPacket = 1;
682
      }
683
684
      /*add payload*/
685
      if (builder->OnDataReference)
686
        builder->OnDataReference(builder->cbk_obj, size, offset+du_offset+size_offset);
687
      else
688
        builder->OnData(builder->cbk_obj, data+offset+du_offset+size_offset, size, GF_FALSE);
689
690
      /*if fragmentation, force packet flush even on last packet since aggregation unit do not
691
      use the same packet format*/
692
      if (frag_state) {
693
        builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
694
        builder->bytesInPacket = 0;
695
      } else {
696
        builder->bytesInPacket += size;
697
      }
698
      du_offset += size+size_offset;
699
      gf_assert(du_size>= size+size_offset);
700
      du_size -= size+size_offset;
701
    }
702
    offset += orig_size;
703
  }
704
  if (builder->bytesInPacket) {
705
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
706
    builder->bytesInPacket = 0;
707
  }
708
  gf_bs_del(bs);
709
  return GF_OK;
710
}
711
#endif
712
713
714
715
static void gf_rtp_ac3_flush(GP_RTPPacketizer *builder)
716
0
{
717
0
  char hdr[2];
718
0
  if (!builder->bytesInPacket) return;
719
720
0
  hdr[0] = builder->ac3_ft;
721
0
  hdr[1] = builder->last_au_sn;
722
0
  builder->OnData(builder->cbk_obj, hdr, 2, GF_TRUE);
723
724
0
  builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
725
0
  builder->bytesInPacket = 0;
726
0
  builder->last_au_sn = 0;
727
0
  builder->ac3_ft = 0;
728
0
}
729
730
GF_Err gp_rtp_builder_do_ac3(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
731
0
{
732
0
  char hdr[2];
733
0
  u32 offset, nb_pck;
734
735
  /*flush*/
736
0
  if (!data) {
737
0
    gf_rtp_ac3_flush(builder);
738
0
    return GF_OK;
739
0
  }
740
741
0
  if (
742
      /*AU does not fit*/
743
0
      (builder->bytesInPacket + data_size > builder->Path_MTU)
744
0
      ||
745
      /*aggregation is not enabled*/
746
0
      !(builder->flags & GP_RTP_PCK_USE_MULTI)
747
0
      ||
748
      /*max ptime is exceeded*/
749
0
      (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
750
751
0
  ) {
752
0
    gf_rtp_ac3_flush(builder);
753
0
  }
754
755
  /*fits*/
756
0
  if (builder->bytesInPacket + data_size < builder->Path_MTU) {
757
    /*need a new packet*/
758
0
    if (!builder->bytesInPacket) {
759
0
      builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
760
0
      builder->ac3_ft = 0;
761
0
      builder->rtp_header.Marker = 1;
762
0
      builder->rtp_header.SequenceNumber += 1;
763
0
      builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
764
      /*2 bytes header*/
765
0
      builder->bytesInPacket = 2;
766
0
    }
767
768
    /*add payload*/
769
0
    if (builder->OnDataReference)
770
0
      builder->OnDataReference(builder->cbk_obj, data_size, 0);
771
0
    else
772
0
      builder->OnData(builder->cbk_obj, data, data_size, GF_FALSE);
773
774
0
    builder->bytesInPacket += data_size;
775
0
    builder->last_au_sn++;
776
0
    return GF_OK;
777
0
  }
778
779
  /*need fragmentation*/
780
0
  gf_assert(!builder->bytesInPacket);
781
0
  offset = 0;
782
0
  nb_pck = data_size / (builder->Path_MTU-2);
783
0
  if (data_size % (builder->Path_MTU-2)) nb_pck++;
784
0
  builder->last_au_sn = nb_pck;
785
786
0
  while (offset < data_size) {
787
0
    u32 pck_size = MIN(data_size-offset, builder->Path_MTU-2);
788
789
0
    builder->rtp_header.Marker = 0;
790
0
    builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
791
0
    builder->rtp_header.SequenceNumber += 1;
792
793
0
    if (!offset) {
794
0
      builder->ac3_ft = (pck_size > 5*data_size/8) ? 1 : 2;
795
0
    } else {
796
0
      builder->ac3_ft = 3;
797
0
      if (offset + pck_size == data_size)
798
0
        builder->rtp_header.Marker = 1;
799
0
    }
800
0
    builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
801
802
0
    hdr[0] = builder->ac3_ft;
803
0
    hdr[1] = builder->last_au_sn;
804
0
    builder->OnData(builder->cbk_obj, hdr, 2, GF_TRUE);
805
806
    /*add payload*/
807
0
    if (builder->OnDataReference)
808
0
      builder->OnDataReference(builder->cbk_obj, pck_size, offset);
809
0
    else
810
0
      builder->OnData(builder->cbk_obj, data+offset, pck_size, GF_FALSE);
811
812
0
    builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
813
0
    offset += pck_size;
814
0
    builder->bytesInPacket = 0;
815
0
  }
816
817
0
  return GF_OK;
818
0
}
819
820
GF_Err gp_rtp_builder_do_opus(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
821
0
{
822
  /*flush*/
823
0
  if (!data) return GF_OK;
824
825
  /*fits*/
826
0
  if (data_size > builder->Path_MTU) {
827
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTPOpus] Packet size %u larger MTU %u but Opus fragmentation is not yet supported, pacth welcome\n", data_size, builder->Path_MTU ));
828
0
    return GF_NOT_SUPPORTED;
829
0
  }
830
  /*send new packet*/
831
0
  builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
832
0
  builder->rtp_header.Marker = 0;
833
0
  builder->rtp_header.SequenceNumber += 1;
834
0
  builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
835
836
  /*add payload*/
837
0
  if (builder->OnDataReference)
838
0
    builder->OnDataReference(builder->cbk_obj, data_size, 0);
839
0
  else
840
0
    builder->OnData(builder->cbk_obj, data, data_size, GF_FALSE);
841
842
0
  builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
843
0
  builder->last_au_sn++;
844
0
  return GF_OK;
845
0
}
846
847
#endif /*GPAC_DISABLE_STREAMING*/
848