RTS API Documentation  1.10.11
Typedefs | Enumerations | Functions
switch_packetizer.h File Reference
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef void switch_packetizer_t
 

Enumerations

enum  switch_packetizer_bitstream_t {
  SPT_H264_BITSTREAM, SPT_H264_SIZED_BITSTREAM, SPT_H264_SIGNALE_NALU, SPT_VP8_BITSTREAM,
  SPT_VP9_BITSTREAM, SPT_INVALID_STREAM
}
 

Functions

switch_packetizer_tswitch_packetizer_create (switch_packetizer_bitstream_t type, uint32_t slice_size)
 
switch_status_t switch_packetizer_feed (switch_packetizer_t *packetizer, void *data, uint32_t size)
 
switch_status_t switch_packetizer_feed_extradata (switch_packetizer_t *packetizer, void *data, uint32_t size)
 
switch_status_t switch_packetizer_read (switch_packetizer_t *packetizer, switch_frame_t *frame)
 
void switch_packetizer_close (switch_packetizer_t **packetizer)
 

Typedef Documentation

◆ switch_packetizer_t

typedef void switch_packetizer_t

Definition at line 35 of file switch_packetizer.h.

Enumeration Type Documentation

◆ switch_packetizer_bitstream_t

Enumerator
SPT_H264_BITSTREAM 
SPT_H264_SIZED_BITSTREAM 
SPT_H264_SIGNALE_NALU 
SPT_VP8_BITSTREAM 
SPT_VP9_BITSTREAM 
SPT_INVALID_STREAM 

Definition at line 37 of file switch_packetizer.h.

Function Documentation

◆ switch_packetizer_close()

void switch_packetizer_close ( switch_packetizer_t **  packetizer)

Definition at line 386 of file switch_packetizer.c.

References h264_packetizer_s::extradata.

387 {
388  h264_packetizer_t *context = (h264_packetizer_t *)(*packetizer);
389  if (context->extradata) free(context->extradata);
390  free(context);
391  *packetizer = NULL;
392 }

◆ switch_packetizer_create()

switch_packetizer_t* switch_packetizer_create ( switch_packetizer_bitstream_t  type,
uint32_t  slice_size 
)

Definition at line 112 of file switch_packetizer.c.

References memset(), h264_packetizer_s::slice_size, and h264_packetizer_s::type.

113 {
114  h264_packetizer_t *context = malloc(sizeof(h264_packetizer_t));
115  memset(context, 0, sizeof(h264_packetizer_t));
116  context->slice_size = slice_size;
117  context->type = type;
118  return (switch_packetizer_t *)context;
119 }
switch_packetizer_bitstream_t type
void switch_packetizer_t
memset(buf, 0, buflen)

◆ switch_packetizer_feed()

switch_status_t switch_packetizer_feed ( switch_packetizer_t packetizer,
void *  data,
uint32_t  size 
)

Definition at line 214 of file switch_packetizer.c.

References our_h264_nalu_s::eat, fs_avc_find_startcode(), our_h264_nalu_s::len, MAX_NALUS, memset(), h264_packetizer_s::nalu_current_index, h264_packetizer_s::nalus, SPT_H264_SIGNALE_NALU, SPT_H264_SIZED_BITSTREAM, our_h264_nalu_s::start, SWITCH_CHANNEL_LOG, switch_log_printf(), SWITCH_LOG_WARNING, SWITCH_STATUS_MORE_DATA, SWITCH_STATUS_SUCCESS, and h264_packetizer_s::type.

215 {
216  h264_packetizer_t *context = (h264_packetizer_t *)packetizer;
217  const uint8_t *p = data;
218  const uint8_t *end = p + size;
219  int i = 0;
220 
221  // reset everytime
222  memset(context->nalus, 0, MAX_NALUS * sizeof(our_h264_nalu_t));
223  context->nalu_current_index = 0;
224 
225  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %u %x %x %x %x %x\n", size, *p, *(p+1), *(p+2), *(p+3), *(p+4));
226 
227  if (context->type == SPT_H264_SIZED_BITSTREAM) {
228  int left = size;
229  uint32_t len;
230 
231  while (left > 0) {
232  if (left < sizeof(uint32_t)) return SWITCH_STATUS_MORE_DATA;
233  len = htonl(*(uint32_t *)p);
234  left -= sizeof(uint32_t);
235  left -= len;
236  if (left < 0) return SWITCH_STATUS_MORE_DATA;
237  p += sizeof(uint32_t);
238 
239  context->nalus[i].start = p;
240  context->nalus[i].eat = p;
241  context->nalus[i].len = len;
242 
243  p += len;
244 
245  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "#%d %x len=%u\n", i, *context->nalus[i].start, context->nalus[i].len);
246  i++;
247  }
248 
249  return SWITCH_STATUS_SUCCESS;
250  }
251 
252  if (context->type == SPT_H264_SIGNALE_NALU) {
253  context->nalus[0].start = data;
254  context->nalus[0].eat = data;
255  context->nalus[0].len = size;
256 
257  return SWITCH_STATUS_SUCCESS;
258  }
259 
260  // SPT_H264_BITSTREAM
261  while ((p = fs_avc_find_startcode(p, end)) < end) {
262  if (!context->nalus[i].start) {
263  while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */
264  context->nalus[i].start = p;
265  context->nalus[i].eat = p;
266  } else {
267  context->nalus[i].len = p - context->nalus[i].start;
268  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "#%d %x len=%u\n", i, *context->nalus[i].start, context->nalus[i].len);
269  while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */
270  i++;
271  context->nalus[i].start = p;
272  context->nalus[i].eat = p;
273  }
274  if (i >= MAX_NALUS - 2) {
276  break;
277  }
278 
279  }
280 
281  context->nalus[i].len = p - context->nalus[i].start;
282 
283  return SWITCH_STATUS_SUCCESS;
284 }
#define SWITCH_CHANNEL_LOG
const uint8_t * eat
our_h264_nalu_t nalus[MAX_NALUS]
static const uint8_t * fs_avc_find_startcode(const uint8_t *p, const uint8_t *end)
#define MAX_NALUS
switch_packetizer_bitstream_t type
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
memset(buf, 0, buflen)
const uint8_t * start

◆ switch_packetizer_feed_extradata()

switch_status_t switch_packetizer_feed_extradata ( switch_packetizer_t packetizer,
void *  data,
uint32_t  size 
)

Definition at line 122 of file switch_packetizer.c.

References h264_packetizer_s::extradata, h264_packetizer_s::pps, h264_packetizer_s::pps_len, h264_packetizer_s::sps, h264_packetizer_s::sps_len, SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, switch_log_printf(), SWITCH_STATUS_FALSE, SWITCH_STATUS_MEMERR, and SWITCH_STATUS_SUCCESS.

123 {
124  h264_packetizer_t *context = (h264_packetizer_t *)packetizer;
125  uint8_t *p;
126  int left = size;
127  int n_sps = 0;
128  int n_pps = 0;
129  int sps_len;
130  int pps_len;
131  int i;
132 
133  if (left < 10) return SWITCH_STATUS_FALSE;
134 
135  if (context->extradata) {
136  context->sps = NULL;
137  context->pps = NULL;
138  context->sps_len = 0;
139  context->pps_len = 0;
140  free(context->extradata);
141  context->extradata = NULL;
142  }
143 
144  context->extradata = malloc(size);
145  if (!context->extradata) return SWITCH_STATUS_MEMERR;
146  memcpy(context->extradata, data, size);
147 
148 /*
149 0x0000 | 01 64 00 1E FF E1 00 1F 67 64 00 1E AC C8 60 33 // E1: 1SPS 00 1F: SPS 31byte
150 0x0010 | 0E F9 E6 FF C1 C6 01 C4 44 00 00 03 00 04 00 00
151 0x0020 | 03 00 B8 3C 58 B6 68 01 00 05 68 E9 78 47 2C // 01: 1PPS 00 05: PPS 5byte
152 */
153 
154  p = context->extradata;
155 
156  if (*p != 1) {
157  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT supported version: %d\n", *p);
158  return SWITCH_STATUS_FALSE;
159  }
160  p += 5;
161  left -= 5;
162 
163  //sps
164  n_sps = *p & 0x1f;
165  p += 1;
166  left -= 1;
167 
168  for (i = 0; i < n_sps; i++) {
169  sps_len = ntohs(*(uint16_t *)p);
170  p += sizeof(uint16_t);
171  left -= sizeof(uint16_t);
172 
173  if (left < sps_len) {
174  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "corrupted data %d < %u\n", left, sps_len);
175  return SWITCH_STATUS_FALSE;
176  }
177 
178  if (!context->sps) { // we only need the first one
179  context->sps = p;
180  context->sps_len = sps_len;
181  }
182 
183  p += sps_len;
184  left -= sps_len;
185  }
186 
187  if (left < 0) return SWITCH_STATUS_FALSE;
188 
189  n_pps = *p & 0x1f;
190  p += 1;
191  left -= 1;
192 
193  for (i = 0; i < n_pps; i++) {
194  pps_len = ntohs(*(uint16_t *)p);
195  p += sizeof(uint16_t);
196  left -= sizeof(uint16_t);
197 
198  if (left < pps_len) {
199  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "corrupted data %d < %u\n", left, pps_len);
200  return SWITCH_STATUS_FALSE;
201  }
202 
203  if (!context->pps) { // we only need the first one
204  context->pps = p;
205  context->pps_len = pps_len;
206  }
207  p += pps_len;
208  left -= pps_len;
209  }
210 
211  return SWITCH_STATUS_SUCCESS;
212 }
#define SWITCH_CHANNEL_LOG
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.

◆ switch_packetizer_read()

switch_status_t switch_packetizer_read ( switch_packetizer_t packetizer,
switch_frame_t frame 
)

Definition at line 286 of file switch_packetizer.c.

References switch_frame::data, switch_frame::datalen, our_h264_nalu_s::eat, our_h264_nalu_s::len, switch_frame::m, h264_packetizer_s::nalu_current_index, h264_packetizer_s::nalus, h264_packetizer_s::pps, h264_packetizer_s::pps_len, h264_packetizer_s::pps_sent, SFF_CNG, h264_packetizer_s::slice_size, h264_packetizer_s::sps, h264_packetizer_s::sps_len, h264_packetizer_s::sps_sent, SPT_H264_BITSTREAM, SPT_H264_SIZED_BITSTREAM, our_h264_nalu_s::start, SWITCH_CHANNEL_LOG, switch_clear_flag, SWITCH_LOG_ERROR, switch_log_printf(), SWITCH_STATUS_FALSE, SWITCH_STATUS_MORE_DATA, SWITCH_STATUS_SUCCESS, and h264_packetizer_s::type.

287 {
288  h264_packetizer_t *context = (h264_packetizer_t *)packetizer;
289  uint32_t slice_size = context->slice_size;
290  our_h264_nalu_t *nalu = &context->nalus[context->nalu_current_index];
291  uint8_t nalu_hdr = 0;
292  uint8_t nalu_type = 0;
293  uint8_t nri = 0;
294  int left = nalu->len - (nalu->eat - nalu->start);
295  uint8_t *p = frame->data;
296  uint8_t start = nalu->start == nalu->eat ? 0x80 : 0;
297  int n = nalu->len / slice_size + 1;
298  int real_slice_size = nalu->len / n + 1 + 2;
299 
300  if (nalu->start == NULL) {
301  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID BITSTREAM\n");
302  return SWITCH_STATUS_FALSE;
303  }
304 
305  nalu_hdr = *(uint8_t *)(nalu->start);
306  nalu_type = nalu_hdr & 0x1f;
307  nri = nalu_hdr & 0x60;
308 
309  if (real_slice_size > slice_size) real_slice_size = slice_size;
310  if (frame->datalen < slice_size) {
311  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "frame buffer too small %u < %u\n", frame->datalen, slice_size);
312  return SWITCH_STATUS_FALSE;
313  }
314 
315  if (context->type == SPT_H264_BITSTREAM || SPT_H264_SIZED_BITSTREAM) {
316  if (nalu_type == 0x05) {
317  // insert SPS/PPS before
318  if (context->sps && !context->sps_sent) {
319  memcpy(frame->data, context->sps, context->sps_len);
320  frame->datalen = context->sps_len;
321  frame->m = 0;
322  context->sps_sent = 1;
324  } else if (context->pps && !context->pps_sent) {
325  memcpy(frame->data, context->pps, context->pps_len);
326  frame->datalen = context->pps_len;
327  frame->m = 0;
328  context->pps_sent = 1;
330  }
331  } else if (nalu_type == 0x07) {
332  context->sps_sent = 1;
333  } else if (nalu_type == 0x08) {
334  context->pps_sent = 1;
335  }
336  }
337 
338  if (nalu->len <= slice_size) {
339  memcpy(frame->data, nalu->start, nalu->len);
340  frame->datalen = nalu->len;
341  context->nalu_current_index++;
342 
343  switch_clear_flag(frame, SFF_CNG);
344 
345  if (context->nalus[context->nalu_current_index].len) {
346  frame->m = 0;
348  }
349 
350  frame->m = 1;
351 
352  if (nalu_type == 0x05) {
353  context->sps_sent = 0;
354  context->pps_sent = 0;
355  }
356 
357  return SWITCH_STATUS_SUCCESS;
358  }
359 
360  if (left <= (real_slice_size - 2)) {
361  p[0] = nri | 28; // FU-A
362  p[1] = 0x40 | nalu_type;
363  memcpy(p+2, nalu->eat, left);
364  nalu->eat += left;
365  frame->datalen = left + 2;
366  context->nalu_current_index++;
367 
368  if (!context->nalus[context->nalu_current_index].len) {
369  frame->m = 1;
370  return SWITCH_STATUS_SUCCESS;
371  }
372 
374  }
375 
376  p[0] = nri | 28; // FU-A
377  p[1] = start | nalu_type;
378  if (start) nalu->eat++;
379  memcpy(p+2, nalu->eat, real_slice_size - 2);
380  nalu->eat += (real_slice_size - 2);
381  frame->datalen = real_slice_size;
382  frame->m = 0;
384 }
switch_bool_t m
Definition: switch_frame.h:83
#define SWITCH_CHANNEL_LOG
const uint8_t * eat
our_h264_nalu_t nalus[MAX_NALUS]
#define switch_clear_flag(obj, flag)
Clear a flag on an arbitrary object while locked.
Definition: switch_utils.h:724
uint32_t datalen
Definition: switch_frame.h:68
switch_packetizer_bitstream_t type
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const uint8_t * start