RTS API Documentation  1.10.11
switch_packetizer.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2020, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Seven Du <dujinfang@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Seven Du <dujinfang@gmail.com>
27  *
28  * switch_packetizer H264 packetizer
29  *
30  */
31 
32 #include <switch.h>
33 #define MAX_NALUS 256
34 
35 typedef struct our_h264_nalu_s {
36  const uint8_t *start;
37  const uint8_t *eat;
38  uint32_t len;
40 
41 typedef struct h264_packetizer_s {
43  uint32_t slice_size;
46  uint8_t *extradata;
47  uint32_t extradata_size;
48  uint8_t *sps;
49  uint8_t *pps;
50  uint32_t sps_len;
51  uint32_t pps_len;
52  int sps_sent;
53  int pps_sent;
55 
56 /* ff_avc_find_startcode is not exposed in the ffmpeg lib but you can use it
57  Either include the avc.h which available in the ffmpeg source, or
58  just add the declaration like we does following to avoid include that whole avc.h
59  The function is implemented in avc.h, guess we'll get rid of this later if we can directly use libx264
60 
61 #include <libavformat/avc.h>
62 */
63 
64 const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end);
65 
66 static const uint8_t *fs_avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
67 {
68  const uint8_t *a = p + 4 - ((intptr_t)p & 3);
69 
70  for (end -= 3; p < a && p < end; p++) {
71  if (p[0] == 0 && p[1] == 0 && p[2] == 1)
72  return p;
73  }
74 
75  for (end -= 3; p < end; p += 4) {
76  uint32_t x = *(const uint32_t*)p;
77  if ((x - 0x01010101) & (~x) & 0x80808080) {
78  if (p[1] == 0) {
79  if (p[0] == 0 && p[2] == 1)
80  return p;
81  if (p[2] == 0 && p[3] == 1)
82  return p+1;
83  }
84  if (p[3] == 0) {
85  if (p[2] == 0 && p[4] == 1)
86  return p+2;
87  if (p[4] == 0 && p[5] == 1)
88  return p+3;
89  }
90  }
91  }
92 
93  for (end += 3; p < end; p++) {
94  if (p[0] == 0 && p[1] == 0 && p[2] == 1)
95  return p;
96  }
97 
98  return end + 3;
99 }
100 
101 static const uint8_t *fs_avc_find_startcode(const uint8_t *p, const uint8_t *end)
102 {
103  const uint8_t *out= fs_avc_find_startcode_internal(p, end);
104 
105  if (p < out && out < end && !out[-1]) {
106  out--;
107  }
108 
109  return out;
110 }
111 
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 }
120 
121 // for H264
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 }
213 
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 }
285 
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 }
385 
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_bool_t m
Definition: switch_frame.h:83
void switch_packetizer_close(switch_packetizer_t **packetizer)
#define SWITCH_CHANNEL_LOG
const uint8_t * eat
switch_status_t switch_packetizer_feed(switch_packetizer_t *packetizer, void *data, uint32_t size)
switch_packetizer_t * switch_packetizer_create(switch_packetizer_bitstream_t type, uint32_t slice_size)
const uint8_t * ff_avc_find_startcode(const uint8_t *p, const uint8_t *end)
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
static const uint8_t * fs_avc_find_startcode(const uint8_t *p, const uint8_t *end)
struct our_h264_nalu_s our_h264_nalu_t
An abstraction of a data frame.
Definition: switch_frame.h:54
struct h264_packetizer_s h264_packetizer_t
#define MAX_NALUS
switch_packetizer_bitstream_t type
switch_status_t switch_packetizer_read(switch_packetizer_t *packetizer, switch_frame_t *frame)
switch_status_t switch_packetizer_feed_extradata(switch_packetizer_t *packetizer, void *data, uint32_t size)
switch_status_t
Common return values.
Main Library Header.
#define SWITCH_DECLARE(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.
switch_packetizer_bitstream_t
static const uint8_t * fs_avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
void switch_packetizer_t
memset(buf, 0, buflen)
const uint8_t * start