Coverage Report

Created: 2025-12-05 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/ietf/rtp_packetizer.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
#include <gpac/maths.h>
32
33
void InitSL_RTP(GF_SLConfig *slc);
34
35
36
37
38
GF_EXPORT
39
GP_RTPPacketizer *gf_rtp_builder_new(u32 rtp_payt, GF_SLConfig *slc, u32 flags,
40
                                     void *cbk_obj,
41
                                     void (*OnNewPacket)(void *cbk, GF_RTPHeader *header),
42
                                     void (*OnPacketDone)(void *cbk, GF_RTPHeader *header),
43
                                     void (*OnDataReference)(void *cbk, u32 payload_size, u32 offset_from_orig),
44
                                     void (*OnData)(void *cbk, u8 *data, u32 data_size, Bool is_head)
45
                                    )
46
0
{
47
0
  GP_RTPPacketizer *tmp;
48
0
  if (!rtp_payt || !cbk_obj || !OnPacketDone) return NULL;
49
50
0
  GF_SAFEALLOC(tmp, GP_RTPPacketizer);
51
0
  if (!tmp) return NULL;
52
53
0
  if (slc) {
54
0
    memcpy(&tmp->sl_config, slc, sizeof(GF_SLConfig));
55
0
  } else {
56
0
    memset(&tmp->sl_config, 0, sizeof(GF_SLConfig));
57
0
    tmp->sl_config.useTimestampsFlag = 1;
58
0
    tmp->sl_config.timestampLength = 32;
59
0
  }
60
0
  tmp->OnNewPacket = OnNewPacket;
61
0
  tmp->OnDataReference = OnDataReference;
62
0
  tmp->OnData = OnData;
63
0
  tmp->cbk_obj = cbk_obj;
64
0
  tmp->OnPacketDone = OnPacketDone;
65
0
  tmp->rtp_payt = rtp_payt;
66
0
  tmp->flags = flags;
67
  //default init
68
0
  tmp->sl_header.AU_sequenceNumber = 1;
69
0
  tmp->sl_header.packetSequenceNumber = 1;
70
71
  //we assume we start on a new AU
72
0
  tmp->sl_header.accessUnitStartFlag = 1;
73
0
  return tmp;
74
0
}
75
76
GF_EXPORT
77
void gf_rtp_builder_del(GP_RTPPacketizer *builder)
78
0
{
79
0
  if (!builder) return;
80
81
0
  if (builder->payload) gf_bs_del(builder->payload);
82
0
  if (builder->pck_hdr) gf_bs_del(builder->pck_hdr);
83
0
  gf_free(builder);
84
0
}
85
86
GF_EXPORT
87
GF_Err gf_rtp_builder_process(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration, u8 descIndex)
88
0
{
89
0
  if (!builder) return GF_BAD_PARAM;
90
91
0
  switch (builder->rtp_payt) {
92
0
  case GF_RTP_PAYT_MPEG4:
93
0
    return gp_rtp_builder_do_mpeg4(builder, data, data_size, IsAUEnd, FullAUSize);
94
0
#ifndef GPAC_DISABLE_AV_PARSERS
95
0
  case GF_RTP_PAYT_MPEG12_VIDEO:
96
0
    return gp_rtp_builder_do_mpeg12_video(builder, data, data_size, IsAUEnd, FullAUSize);
97
0
#endif
98
0
  case GF_RTP_PAYT_MPEG12_AUDIO:
99
0
    return gp_rtp_builder_do_mpeg12_audio(builder, data, data_size, IsAUEnd, FullAUSize);
100
0
  case GF_RTP_PAYT_H263:
101
0
    return gp_rtp_builder_do_h263(builder, data, data_size, IsAUEnd, FullAUSize);
102
0
  case GF_RTP_PAYT_AMR:
103
0
  case GF_RTP_PAYT_AMR_WB:
104
0
    return gp_rtp_builder_do_amr(builder, data, data_size, IsAUEnd, FullAUSize);
105
0
  case GF_RTP_PAYT_3GPP_TEXT:
106
0
    return gp_rtp_builder_do_tx3g(builder, data, data_size, IsAUEnd, FullAUSize, duration, descIndex);
107
0
  case GF_RTP_PAYT_H264_AVC:
108
0
  case GF_RTP_PAYT_H264_SVC:
109
0
    return gp_rtp_builder_do_avc(builder, data, data_size, IsAUEnd, FullAUSize);
110
0
  case GF_RTP_PAYT_QCELP:
111
0
    return gp_rtp_builder_do_qcelp(builder, data, data_size, IsAUEnd, FullAUSize);
112
0
  case GF_RTP_PAYT_EVRC_SMV:
113
0
    return gp_rtp_builder_do_smv(builder, data, data_size, IsAUEnd, FullAUSize);
114
0
  case GF_RTP_PAYT_LATM:
115
0
    return gp_rtp_builder_do_latm(builder, data, data_size, IsAUEnd, FullAUSize, duration);
116
#if GPAC_ENABLE_3GPP_DIMS_RTP
117
  case GF_RTP_PAYT_3GPP_DIMS:
118
    return gp_rtp_builder_do_dims(builder, data, data_size, IsAUEnd, FullAUSize, duration);
119
#endif
120
0
  case GF_RTP_PAYT_AC3:
121
0
  case GF_RTP_PAYT_EAC3:
122
0
    return gp_rtp_builder_do_ac3(builder, data, data_size, IsAUEnd, FullAUSize);
123
0
  case GF_RTP_PAYT_HEVC:
124
0
  case GF_RTP_PAYT_LHVC:
125
0
    return gp_rtp_builder_do_hevc(builder, data, data_size, IsAUEnd, FullAUSize);
126
0
  case GF_RTP_PAYT_VVC:
127
0
    return gp_rtp_builder_do_vvc(builder, data, data_size, IsAUEnd, FullAUSize);
128
0
  case GF_RTP_PAYT_MP2T:
129
0
    return gp_rtp_builder_do_mp2t(builder, data, data_size, IsAUEnd, FullAUSize);
130
0
  case GF_RTP_PAYT_OPUS:
131
0
    return gp_rtp_builder_do_opus(builder, data, data_size, IsAUEnd, FullAUSize);
132
0
  default:
133
0
    return GF_NOT_SUPPORTED;
134
0
  }
135
0
}
136
137
138
//Compute the #params of the slMap
139
GF_EXPORT
140
void gf_rtp_builder_init(GP_RTPPacketizer *builder, u8 PayloadType, u32 PathMTU, u32 max_ptime,
141
                         u32 StreamType, u32 codecid, u32 PL_ID,
142
                         u32 avgSize, u32 maxSize,
143
                         u32 avgTS, u32 maxDTS,
144
                         u32 IV_length, u32 KI_length,
145
                         char *pref_mode)
146
0
{
147
0
  u32 k, ismacrypt_flags;
148
149
0
  memset(&builder->slMap, 0, sizeof(GP_RTPSLMap));
150
0
  builder->Path_MTU = PathMTU;
151
0
  builder->PayloadType = PayloadType;
152
0
  builder->slMap.StreamType = StreamType;
153
0
  builder->slMap.CodecID = codecid;
154
0
  builder->slMap.PL_ID = PL_ID;
155
0
  builder->max_ptime = max_ptime;
156
0
  if (pref_mode) strcpy(builder->slMap.mode, pref_mode);
157
158
159
  //some cst vars
160
0
  builder->rtp_header.Version = 2;
161
0
  builder->rtp_header.PayloadType = builder->PayloadType;
162
163
  /*our max config is with 1 packet only (SingleSL)*/
164
0
  builder->first_sl_in_rtp = GF_TRUE;
165
  /*no AUX data*/
166
0
  builder->slMap.AuxiliaryDataSizeLength = 0;
167
168
169
  /*just compute max aggregation size*/
170
0
  switch (builder->rtp_payt) {
171
0
  case GF_RTP_PAYT_QCELP:
172
0
  case GF_RTP_PAYT_EVRC_SMV:
173
0
  case GF_RTP_PAYT_AMR:
174
0
  case GF_RTP_PAYT_AMR_WB:
175
0
  {
176
0
    u32 nb_pck = 1;
177
0
    u32 block_size = 160;
178
    /*compute max frames per packet - if no avg size, use max size per codec*/
179
0
    if (builder->flags & GP_RTP_PCK_USE_MULTI) {
180
0
      if (builder->rtp_payt == GF_RTP_PAYT_QCELP) {
181
0
        if (!avgSize) avgSize = 35;
182
0
        nb_pck = (PathMTU-1) / avgSize; /*one-byte header*/
183
0
        if (nb_pck>10) nb_pck=10; /*cf RFC2658*/
184
0
      } else if (builder->rtp_payt == GF_RTP_PAYT_EVRC_SMV) {
185
0
        if (!avgSize) avgSize = 23;
186
0
        nb_pck = (PathMTU) / avgSize;
187
0
        if (nb_pck>32) nb_pck=32; /*cf RFC3558*/
188
0
      } else if (builder->rtp_payt == GF_RTP_PAYT_AMR_WB) {
189
0
        if (!avgSize) avgSize = 61;
190
0
        nb_pck = (PathMTU-1) / avgSize;
191
0
        block_size = 320;
192
0
      } else {
193
0
        if (!avgSize) avgSize = 32;
194
0
        nb_pck = (PathMTU-1) / avgSize;
195
0
      }
196
0
      if (max_ptime) {
197
0
        u32 max_pck = max_ptime / block_size;
198
0
        if (nb_pck > max_pck) nb_pck = max_pck;
199
0
      }
200
0
    }
201
0
    if (nb_pck<=1) {
202
0
      builder->flags &= ~(GP_RTP_PCK_USE_MULTI|GP_RTP_PCK_USE_INTERLEAVING);
203
0
      builder->auh_size = 1;
204
0
    } else {
205
0
      builder->auh_size = nb_pck;
206
0
    }
207
    /*remove all MPEG-4 and ISMA flags */
208
0
    builder->flags &= 0x07;
209
0
  }
210
0
  return;
211
0
  case GF_RTP_PAYT_LATM:
212
0
  case GF_RTP_PAYT_MPEG4:
213
0
    break;
214
0
  default:
215
    /*remove all MPEG-4 and ISMA flags */
216
0
    builder->flags &= 0x07;
217
    /*disable aggregation for visual streams, except for AVC where STAP/MTAP can be used*/
218
0
    if (StreamType==GF_STREAM_VISUAL) {
219
0
      if ((codecid != GF_CODECID_AVC) && (codecid != GF_CODECID_SVC) && (codecid != GF_CODECID_MVC) && (codecid != GF_CODECID_HEVC) && (codecid != GF_CODECID_LHVC)) {
220
0
        builder->flags &= ~GP_RTP_PCK_USE_MULTI;
221
0
      }
222
0
    }
223
0
    else if (avgSize && (PathMTU <= avgSize) ) {
224
0
      builder->flags &= ~GP_RTP_PCK_USE_MULTI;
225
0
    }
226
0
    return;
227
0
  }
228
229
0
  builder->slMap.IV_length = IV_length;
230
0
  builder->slMap.KI_length = KI_length;
231
232
0
  ismacrypt_flags = 0;
233
0
  if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) ismacrypt_flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION;
234
0
  if (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU) ismacrypt_flags |= GP_RTP_PCK_KEY_IDX_PER_AU;
235
236
  /*mode setup*/
237
0
  if (!strnicmp(builder->slMap.mode, "AAC", 3)) {
238
0
    builder->flags = GP_RTP_PCK_USE_MULTI | GP_RTP_PCK_SIGNAL_SIZE | GP_RTP_PCK_SIGNAL_AU_IDX | ismacrypt_flags;
239
    /*if (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) */
240
0
    builder->slMap.ConstantDuration = avgTS;
241
242
    /*AAC LBR*/
243
0
    if (maxSize < 63) {
244
0
      strcpy(builder->slMap.mode, "AAC-lbr");
245
0
      builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 2;
246
0
      builder->slMap.SizeLength = 6;
247
0
    }
248
    /*AAC HBR*/
249
0
    else {
250
0
      strcpy(builder->slMap.mode, "AAC-hbr");
251
0
      builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 3;
252
0
      builder->slMap.SizeLength = 13;
253
0
    }
254
0
    goto check_header;
255
0
  }
256
0
  if (!strnicmp(builder->slMap.mode, "CELP", 4)) {
257
    /*CELP-cbr*/
258
0
    if (maxSize == avgSize) {
259
      /*reset flags (interleaving forbidden)*/
260
0
      builder->flags = GP_RTP_PCK_USE_MULTI | ismacrypt_flags;
261
0
      strcpy(builder->slMap.mode, "CELP-cbr");
262
0
      builder->slMap.ConstantSize = avgSize;
263
0
      builder->slMap.ConstantDuration = avgTS;
264
0
    }
265
    /*CELP VBR*/
266
0
    else {
267
0
      strcpy(builder->slMap.mode, "CELP-vbr");
268
0
      builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 2;
269
0
      builder->slMap.SizeLength = 6;
270
0
      /*if (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) */builder->slMap.ConstantDuration = avgTS;
271
0
      builder->flags = GP_RTP_PCK_USE_MULTI | GP_RTP_PCK_SIGNAL_SIZE | GP_RTP_PCK_SIGNAL_AU_IDX | ismacrypt_flags;
272
0
    }
273
0
    goto check_header;
274
0
  }
275
276
  /*generic setup by flags*/
277
278
  /*size*/
279
0
  if (builder->flags & GP_RTP_PCK_SIGNAL_SIZE) {
280
0
    if (avgSize==maxSize) {
281
0
      builder->slMap.SizeLength = 0;
282
0
      builder->slMap.ConstantSize = maxSize;
283
0
    } else {
284
0
      builder->slMap.SizeLength = gf_get_bit_size(maxSize ? maxSize : PathMTU);
285
0
      builder->slMap.ConstantSize = 0;
286
0
    }
287
0
  } else {
288
0
    builder->slMap.SizeLength = 0;
289
0
    if (builder->flags & GP_RTP_PCK_USE_MULTI)
290
0
      builder->slMap.ConstantSize = (avgSize==maxSize) ? maxSize : 0;
291
0
    else
292
0
      builder->slMap.ConstantSize = 0;
293
0
  }
294
295
  /*single SL per RTP*/
296
0
  if (!(builder->flags & GP_RTP_PCK_USE_MULTI)) {
297
0
    if ( builder->sl_config.AUSeqNumLength && (builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX)) {
298
0
      builder->slMap.IndexLength = builder->sl_config.AUSeqNumLength;
299
0
    } else {
300
0
      builder->slMap.IndexLength = 0;
301
0
    }
302
    /*one packet per RTP so no delta*/
303
0
    builder->slMap.IndexDeltaLength = 0;
304
0
    builder->slMap.IV_delta_length = 0;
305
306
    /*CTS Delta is always 0 since we have one SL packet per RTP*/
307
0
    builder->slMap.CTSDeltaLength = 0;
308
309
    /*DTS Delta depends on the video type*/
310
0
    if ((builder->flags & GP_RTP_PCK_SIGNAL_TS) && maxDTS )
311
0
      builder->slMap.DTSDeltaLength = gf_get_bit_size(maxDTS);
312
0
    else
313
0
      builder->slMap.DTSDeltaLength = 0;
314
315
    /*RAP*/
316
0
    if (builder->sl_config.useRandomAccessPointFlag && (builder->flags & GP_RTP_PCK_SIGNAL_RAP)) {
317
0
      builder->slMap.RandomAccessIndication = GF_TRUE;
318
0
    } else {
319
0
      builder->slMap.RandomAccessIndication = GF_FALSE;
320
0
    }
321
322
    /*stream state*/
323
0
    if (builder->flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
324
0
      if (!builder->sl_config.AUSeqNumLength) builder->sl_config.AUSeqNumLength = 4;
325
0
      builder->slMap.StreamStateIndication = builder->sl_config.AUSeqNumLength;
326
0
    }
327
0
    goto check_header;
328
0
  }
329
330
  /*this is the avg samples we can store per RTP packet*/
331
0
  k = PathMTU / avgSize;
332
0
  if (k<=1) {
333
0
    builder->flags &= ~GP_RTP_PCK_USE_MULTI;
334
    /*keep TS signaling for B-frames (eg never default to M4V-ES when B-frames are present)*/
335
    //builder->flags &= ~GP_RTP_PCK_SIGNAL_TS;
336
0
    builder->flags &= ~GP_RTP_PCK_SIGNAL_SIZE;
337
0
    builder->flags &= ~GP_RTP_PCK_SIGNAL_AU_IDX;
338
0
    builder->flags &= ~GP_RTP_PCK_USE_INTERLEAVING;
339
0
    builder->flags &= ~GP_RTP_PCK_KEY_IDX_PER_AU;
340
0
    gf_rtp_builder_init(builder, PayloadType, PathMTU, max_ptime, StreamType, codecid, PL_ID, avgSize, maxSize, avgTS, maxDTS, IV_length, KI_length, pref_mode);
341
0
    return;
342
0
  }
343
344
  /*multiple SL per RTP - check if we have to send TS*/
345
0
  builder->slMap.ConstantDuration = builder->sl_config.CUDuration;
346
0
  if (!builder->slMap.ConstantDuration) {
347
0
    builder->flags |= GP_RTP_PCK_SIGNAL_TS;
348
0
  }
349
  /*if we have a constant duration and are not writting TSs, make sure we write AU IDX when interleaving*/
350
0
  else if (! (builder->flags & GP_RTP_PCK_SIGNAL_TS) && (builder->flags & GP_RTP_PCK_USE_INTERLEAVING)) {
351
0
    builder->flags |= GP_RTP_PCK_SIGNAL_AU_IDX;
352
0
  }
353
354
0
  if (builder->flags & GP_RTP_PCK_SIGNAL_TS) {
355
    /*compute CTS delta*/
356
0
    builder->slMap.CTSDeltaLength = gf_get_bit_size(k*avgTS);
357
358
    /*compute DTS delta. Delta is ALWAYS from the CTS of the same sample*/
359
0
    if (maxDTS)
360
0
      builder->slMap.DTSDeltaLength = gf_get_bit_size(maxDTS);
361
0
    else
362
0
      builder->slMap.DTSDeltaLength = 0;
363
0
  }
364
365
0
  if ((builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && builder->sl_config.AUSeqNumLength) {
366
0
    builder->slMap.IndexLength = builder->sl_config.AUSeqNumLength;
367
    /*and k-1 AUs in Delta*/
368
0
    builder->slMap.IndexDeltaLength = (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) ? gf_get_bit_size(k-1) : 0;
369
0
  }
370
0
  else if (builder->flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
371
0
    if (!builder->sl_config.AUSeqNumLength) builder->sl_config.AUSeqNumLength = 4;
372
0
    builder->slMap.StreamStateIndication = builder->sl_config.AUSeqNumLength;
373
0
  }
374
375
  /*RAP*/
376
0
  if (builder->sl_config.useRandomAccessPointFlag && (builder->flags & GP_RTP_PCK_SIGNAL_RAP)) {
377
0
    builder->slMap.RandomAccessIndication = GF_TRUE;
378
0
  } else {
379
0
    builder->slMap.RandomAccessIndication = GF_FALSE;
380
0
  }
381
382
0
check_header:
383
384
  /*IV delta only if interleaving (otherwise reconstruction from IV is trivial)*/
385
0
  if (IV_length && (builder->flags & GP_RTP_PCK_USE_INTERLEAVING)) {
386
0
    builder->slMap.IV_delta_length = gf_get_bit_size(maxSize);
387
0
  }
388
  /*ISMACryp video mode*/
389
0
  if ((builder->slMap.StreamType==GF_STREAM_VISUAL) && (builder->slMap.CodecID==GF_CODECID_MPEG4_PART2)
390
0
          && (builder->flags & GP_RTP_PCK_SIGNAL_RAP) && builder->slMap.IV_length
391
0
          && !(builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && !(builder->flags & GP_RTP_PCK_SIGNAL_SIZE)
392
          /*shall have SignalTS*/
393
0
          && (builder->flags & GP_RTP_PCK_SIGNAL_TS) && !(builder->flags & GP_RTP_PCK_USE_MULTI)
394
0
     ) {
395
0
    strcpy(builder->slMap.mode, "mpeg4-video");
396
0
  }
397
  /*ISMACryp AVC video mode*/
398
0
  else if ((builder->slMap.StreamType==GF_STREAM_VISUAL) && (builder->slMap.CodecID==GF_CODECID_AVC)
399
0
           && (builder->flags & GP_RTP_PCK_SIGNAL_RAP) && builder->slMap.IV_length
400
0
           && !(builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && !(builder->flags & GP_RTP_PCK_SIGNAL_SIZE)
401
           /*shall have SignalTS*/
402
0
           && (builder->flags & GP_RTP_PCK_SIGNAL_TS) && !(builder->flags & GP_RTP_PCK_USE_MULTI)
403
0
          ) {
404
0
    strcpy(builder->slMap.mode, "avc-video");
405
0
  }
406
407
  /*check if we use AU header or not*/
408
0
  if (!builder->slMap.SizeLength
409
0
          && !builder->slMap.IndexLength
410
0
          && !builder->slMap.IndexDeltaLength
411
0
          && !builder->slMap.DTSDeltaLength
412
0
          && !builder->slMap.CTSDeltaLength
413
0
          && !builder->slMap.RandomAccessIndication
414
0
          && !builder->slMap.IV_length
415
0
          && !builder->slMap.KI_length
416
0
     ) {
417
0
    builder->has_AU_header = GF_FALSE;
418
0
  } else {
419
0
    builder->has_AU_header = GF_TRUE;
420
0
  }
421
0
}
422
423
void gf_rtp_builder_set_cryp_info(GP_RTPPacketizer *builder, u64 IV, char *key_indicator, Bool is_encrypted)
424
0
{
425
0
  if (!builder) return;
426
0
  if (!key_indicator) {
427
0
    if (builder->key_indicator) {
428
      /*force flush if no provision for keyIndicator per AU*/
429
0
      builder->force_flush = (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU) ? GF_FALSE : GF_TRUE;
430
0
      gf_free(builder->key_indicator);
431
0
      builder->key_indicator = NULL;
432
0
    }
433
0
  } else if (!builder->key_indicator
434
0
             ||
435
0
             memcmp(builder->key_indicator, key_indicator, sizeof(char)*builder->slMap.KI_length)
436
0
            ) {
437
    /*force flush if no provision for keyIndicator per AU*/
438
0
    builder->force_flush = (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU) ? GF_FALSE : GF_TRUE;
439
440
0
    if (!builder->key_indicator) builder->key_indicator = (char *) gf_malloc(sizeof(char)*builder->slMap.KI_length);
441
0
    memcpy(builder->key_indicator, key_indicator, sizeof(char)*builder->slMap.KI_length);
442
0
  }
443
0
  if (builder->IV != IV) {
444
0
    builder->IV = IV;
445
0
    if (builder->slMap.IV_delta_length && (builder->slMap.IV_delta_length < gf_get_bit_size((u32) (IV - builder->first_AU_IV) ))) {
446
0
      builder->first_AU_IV = IV;
447
0
      builder->force_flush = GF_TRUE;
448
0
    }
449
0
  }
450
0
  builder->is_encrypted = is_encrypted;
451
0
}
452
453
GF_EXPORT
454
Bool gf_rtp_builder_get_payload_name(GP_RTPPacketizer *rtpb, char szPayloadName[20], char szMediaName[20])
455
0
{
456
0
  u32 flags = rtpb->flags;
457
458
0
  switch (rtpb->rtp_payt) {
459
0
  case GF_RTP_PAYT_MPEG4:
460
0
    if ((rtpb->slMap.StreamType==GF_STREAM_VISUAL) && (rtpb->slMap.CodecID==GF_CODECID_MPEG4_PART2)) {
461
0
      strcpy(szMediaName, "video");
462
      /*ISMACryp video*/
463
0
      if ( (flags & GP_RTP_PCK_SIGNAL_RAP) && rtpb->slMap.IV_length
464
0
              && !(flags & GP_RTP_PCK_SIGNAL_AU_IDX) && !(flags & GP_RTP_PCK_SIGNAL_SIZE)
465
0
              && (flags & GP_RTP_PCK_SIGNAL_TS) && !(flags & GP_RTP_PCK_USE_MULTI)
466
0
         )
467
0
      {
468
0
        strcpy(szPayloadName, "enc-mpeg4-generic");
469
0
        return GF_TRUE;
470
0
      }
471
      /*mpeg4-generic*/
472
0
      if ( (flags & GP_RTP_PCK_SIGNAL_RAP) || (flags & GP_RTP_PCK_SIGNAL_AU_IDX) || (flags & GP_RTP_PCK_SIGNAL_SIZE)
473
0
              || (flags & GP_RTP_PCK_SIGNAL_TS) || (flags & GP_RTP_PCK_USE_MULTI) ) {
474
0
        strcpy(szPayloadName, "mpeg4-generic");
475
0
        return GF_TRUE;
476
0
      } else {
477
0
        strcpy(szPayloadName, "MP4V-ES");
478
0
        return GF_TRUE;
479
0
      }
480
0
    }
481
    /*for all other types*/
482
0
    if (rtpb->slMap.StreamType==GF_STREAM_AUDIO) strcpy(szMediaName, "audio");
483
0
    else if (rtpb->slMap.StreamType==GF_STREAM_MPEGJ) strcpy(szMediaName, "application");
484
0
    else strcpy(szMediaName, "video");
485
0
    strcpy(szPayloadName, rtpb->slMap.IV_length ? "enc-mpeg4-generic" : "mpeg4-generic");
486
0
    return GF_TRUE;
487
0
  case GF_RTP_PAYT_MPEG12_VIDEO:
488
0
    strcpy(szMediaName, "video");
489
0
    strcpy(szPayloadName, "MPV");
490
0
    return GF_TRUE;
491
0
  case GF_RTP_PAYT_MPEG12_AUDIO:
492
0
    strcpy(szMediaName, "audio");
493
0
    strcpy(szPayloadName, "MPA");
494
0
    return GF_TRUE;
495
0
  case GF_RTP_PAYT_H263:
496
0
    strcpy(szMediaName, "video");
497
0
    strcpy(szPayloadName, "H263-1998");
498
0
    return GF_TRUE;
499
0
  case GF_RTP_PAYT_AMR:
500
0
    strcpy(szMediaName, "audio");
501
0
    strcpy(szPayloadName, "AMR");
502
0
    return GF_TRUE;
503
0
  case GF_RTP_PAYT_AMR_WB:
504
0
    strcpy(szMediaName, "audio");
505
0
    strcpy(szPayloadName, "AMR-WB");
506
0
    return GF_TRUE;
507
0
  case GF_RTP_PAYT_3GPP_TEXT:
508
0
    strcpy(szMediaName, "text");
509
0
    strcpy(szPayloadName, "3gpp-tt");
510
0
    return GF_TRUE;
511
0
  case GF_RTP_PAYT_H264_AVC:
512
0
    strcpy(szMediaName, "video");
513
0
    strcpy(szPayloadName, "H264");
514
0
    return GF_TRUE;
515
0
  case GF_RTP_PAYT_QCELP:
516
0
    strcpy(szMediaName, "audio");
517
0
    strcpy(szPayloadName, "QCELP");
518
0
    return GF_TRUE;
519
0
  case GF_RTP_PAYT_EVRC_SMV:
520
0
    strcpy(szMediaName, "audio");
521
0
    if ((rtpb->slMap.CodecID==0xA0) || (rtpb->slMap.CodecID==GF_CODECID_EVRC))
522
0
      strcpy(szPayloadName, "EVRC");
523
0
    else
524
0
      strcpy(szPayloadName, "SMV");
525
526
    /*header-free version*/
527
0
    if (rtpb->auh_size<=1) strcat(szPayloadName, "0");
528
0
    return GF_TRUE;
529
0
  case GF_RTP_PAYT_LATM:
530
0
    strcpy(szMediaName, "audio");
531
0
    strcpy(szPayloadName, "MP4A-LATM");
532
0
    return GF_TRUE;
533
#if GPAC_ENABLE_3GPP_DIMS_RTP
534
  case GF_RTP_PAYT_3GPP_DIMS:
535
    strcpy(szMediaName, "video");
536
    strcpy(szPayloadName, "richmedia+xml");
537
    return GF_TRUE;
538
#endif
539
0
  case GF_RTP_PAYT_AC3:
540
0
    strcpy(szMediaName, "audio");
541
0
    strcpy(szPayloadName, "ac3");
542
0
    return GF_TRUE;
543
0
  case GF_RTP_PAYT_EAC3:
544
0
    strcpy(szMediaName, "audio");
545
0
    strcpy(szPayloadName, "eac3");
546
0
    return GF_TRUE;
547
0
  case GF_RTP_PAYT_OPUS:
548
0
    strcpy(szMediaName, "audio");
549
0
    strcpy(szPayloadName, "opus");
550
0
    return GF_TRUE;
551
0
  case GF_RTP_PAYT_H264_SVC:
552
0
    strcpy(szMediaName, "video");
553
0
    strcpy(szPayloadName, "H264-SVC");
554
0
    return GF_TRUE;
555
0
  case GF_RTP_PAYT_HEVC:
556
0
    strcpy(szMediaName, "video");
557
0
    strcpy(szPayloadName, "H265");
558
0
    return GF_TRUE;
559
0
  case GF_RTP_PAYT_LHVC:
560
0
    strcpy(szMediaName, "video");
561
0
    strcpy(szPayloadName, "H265-SHVC");
562
0
    return GF_TRUE;
563
0
  case GF_RTP_PAYT_VVC:
564
0
    strcpy(szMediaName, "video");
565
0
    strcpy(szPayloadName, "H266");
566
0
    return GF_TRUE;
567
568
0
  case GF_RTP_PAYT_MP2T:
569
0
    strcpy(szMediaName, "video");
570
0
    strcpy(szPayloadName, "MP2T");
571
0
    return GF_TRUE;
572
0
  default:
573
0
    strcpy(szMediaName, "");
574
0
    strcpy(szPayloadName, "");
575
0
    return GF_FALSE;
576
0
  }
577
0
  return GF_FALSE;
578
0
}
579
580
581
GF_EXPORT
582
GF_Err gf_rtp_builder_format_sdp(GP_RTPPacketizer *builder, char *payload_name, char **out_sdp_line, char *dsi, u32 dsi_size)
583
0
{
584
0
  char buffer[100];
585
0
  u32 i;
586
0
  Bool is_first = GF_TRUE;
587
0
  GF_Err e = GF_OK;
588
0
  if (!out_sdp_line) return GF_BAD_PARAM;
589
0
  if (*out_sdp_line)
590
0
    (*out_sdp_line)[0] = 0;
591
592
0
  if ((builder->rtp_payt!=GF_RTP_PAYT_MPEG4) && (builder->rtp_payt!=GF_RTP_PAYT_LATM) ) return GF_BAD_PARAM;
593
594
0
#define SDP_ADD_INT(_name, _val) {\
595
0
    if (!is_first) gf_dynstrcat(out_sdp_line, "; ", NULL); \
596
0
    gf_dynstrcat(out_sdp_line, _name, NULL);\
597
0
    sprintf(buffer, "%d", _val);\
598
0
    gf_dynstrcat(out_sdp_line, buffer, "=");\
599
0
    is_first = 0;\
600
0
  }
601
602
0
#define SDP_ADD_STR(_name, _val) {\
603
0
    if (!is_first) gf_dynstrcat(out_sdp_line, "; ", NULL);\
604
0
    gf_dynstrcat(out_sdp_line, _name, NULL);\
605
0
    gf_dynstrcat(out_sdp_line, _val, "=");\
606
0
    is_first = 0;\
607
0
  }
608
609
0
  sprintf(buffer, "a=fmtp:%d ", builder->PayloadType);
610
0
  gf_dynstrcat(out_sdp_line, buffer, NULL);
611
612
  /*mandatory fields*/
613
0
  if (builder->slMap.PL_ID) SDP_ADD_INT("profile-level-id", builder->slMap.PL_ID);
614
615
0
  if (builder->rtp_payt == GF_RTP_PAYT_LATM) SDP_ADD_INT("cpresent", 0);
616
617
0
  if (dsi && dsi_size) {
618
0
    if (dsi_size>10000) {
619
0
      e = GF_OUT_OF_MEM;
620
0
      goto exit;
621
0
    }
622
0
    if (!is_first) gf_dynstrcat(out_sdp_line, "; ", NULL);
623
0
    gf_dynstrcat(out_sdp_line, "config=", NULL);
624
0
    buffer[2]=0;
625
0
    for (i=0; i<dsi_size; i++) {
626
0
      sprintf(buffer, "%02x", (unsigned char) dsi[i]);
627
0
      gf_dynstrcat(out_sdp_line, buffer, NULL);
628
0
    }
629
0
    is_first = 0;
630
0
  }
631
0
  if (!strcmp(payload_name, "MP4V-ES") || (builder->rtp_payt == GF_RTP_PAYT_LATM) ) {
632
0
    e = GF_OK;
633
0
    goto exit;
634
0
  }
635
636
0
  SDP_ADD_INT("streamType", builder->slMap.StreamType);
637
0
  if (strcmp(builder->slMap.mode, "") && strcmp(builder->slMap.mode, "default")) {
638
0
    SDP_ADD_STR("mode", builder->slMap.mode);
639
0
  } else {
640
0
    SDP_ADD_STR("mode", "generic");
641
0
  }
642
643
  /*optional fields*/
644
0
  if (builder->slMap.CodecID) SDP_ADD_INT("objectType", builder->slMap.CodecID);
645
0
  if (builder->slMap.ConstantSize) SDP_ADD_INT("constantSize", builder->slMap.ConstantSize);
646
0
  if (builder->slMap.ConstantDuration) SDP_ADD_INT("constantDuration", builder->slMap.ConstantDuration);
647
0
  if (builder->slMap.maxDisplacement) SDP_ADD_INT("maxDisplacement", builder->slMap.maxDisplacement);
648
0
  if (builder->slMap.deinterleaveBufferSize) SDP_ADD_INT("de-interleaveBufferSize", builder->slMap.deinterleaveBufferSize);
649
0
  if (builder->slMap.SizeLength) SDP_ADD_INT("sizeLength", builder->slMap.SizeLength);
650
0
  if (builder->slMap.IndexLength) SDP_ADD_INT("indexLength", builder->slMap.IndexLength);
651
0
  if (builder->slMap.IndexDeltaLength) SDP_ADD_INT("indexDeltaLength", builder->slMap.IndexDeltaLength);
652
0
  if (builder->slMap.CTSDeltaLength) SDP_ADD_INT("CTSDeltaLength", builder->slMap.CTSDeltaLength);
653
0
  if (builder->slMap.DTSDeltaLength) SDP_ADD_INT("DTSDeltaLength", builder->slMap.DTSDeltaLength);
654
0
  if (builder->slMap.RandomAccessIndication) SDP_ADD_INT("randomAccessIndication", builder->slMap.RandomAccessIndication);
655
0
  if (builder->slMap.StreamStateIndication) SDP_ADD_INT("streamStateIndication", builder->slMap.StreamStateIndication);
656
0
  if (builder->slMap.AuxiliaryDataSizeLength) SDP_ADD_INT("auxiliaryDataSizeLength", builder->slMap.AuxiliaryDataSizeLength);
657
658
  /*ISMACryp config*/
659
0
  if (builder->slMap.IV_length) {
660
    /*don't write default*/
661
    /*SDP_ADD_STR("ISMACrypCryptoSuite", "AES_CTR_128");*/
662
0
    if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) SDP_ADD_INT("ISMACrypSelectiveEncryption", 1);
663
0
    SDP_ADD_INT("ISMACrypIVLength", builder->slMap.IV_length);
664
0
    if (builder->slMap.IV_delta_length) SDP_ADD_INT("ISMACrypDeltaIVLength", builder->slMap.IV_delta_length);
665
0
    if (builder->slMap.KI_length) SDP_ADD_INT("ISMACrypKeyIndicatorLength", builder->slMap.KI_length);
666
0
    if (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU) SDP_ADD_INT("ISMACrypKeyIndicatorPerAU", 1);
667
0
  }
668
669
0
exit:
670
0
  if (!out_sdp_line) return GF_OUT_OF_MEM;
671
0
  return e;
672
0
}
673
674
#endif /*GPAC_DISABLE_STREAMING*/