RTS API Documentation  1.10.11
switch_vpx.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2015, 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  * Anthony Minessale II <anthm@freeswitch.org>
27  * Seven Du <dujinfang@gmail.com>
28  * Sam Russell <sam.h.russell@gmail.com>
29  *
30  * mod_vpx.c -- VP8/9 Video Codec, with transcoding
31  *
32  */
33 
34 #include <switch.h>
35 #ifdef SWITCH_HAVE_YUV
36 #ifdef SWITCH_HAVE_VPX
37 #include <vpx/vpx_encoder.h>
38 #include <vpx/vpx_decoder.h>
39 #include <vpx/vp8cx.h>
40 #include <vpx/vp8dx.h>
41 #include <vpx/vp8.h>
42 
43 // #define DEBUG_VP9
44 
45 #ifdef DEBUG_VP9
46 #define VPX_SWITCH_LOG_LEVEL SWITCH_LOG_ERROR
47 #else
48 #define VPX_SWITCH_LOG_LEVEL SWITCH_LOG_DEBUG1
49 #endif
50 
51 #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE
52 #define KEY_FRAME_MIN_FREQ 250000
53 
54 #define CODEC_TYPE_ANY 0
55 #define CODEC_TYPE_VP8 8
56 #define CODEC_TYPE_VP9 9
57 
58 typedef struct my_vpx_cfg_s {
59  char name[64];
60  int lossless;
61  int cpuused;
62  int token_parts;
63  int static_thresh;
64  int noise_sensitivity;
65  int max_intra_bitrate_pct;
66  vp9e_tune_content tune_content;
67 
68  vpx_codec_enc_cfg_t enc_cfg;
69  vpx_codec_dec_cfg_t dec_cfg;
70  switch_event_t *codecs;
71 } my_vpx_cfg_t;
72 
73 #define SHOW(cfg, field) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, " %-28s = %d\n", #field, cfg->field)
74 
75 static void show_config(my_vpx_cfg_t *my_cfg, vpx_codec_enc_cfg_t *cfg)
76 {
77  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " %-28s = %s\n", "name", my_cfg->name);
78  switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, " %-28s = %d\n", "decoder.threads", my_cfg->dec_cfg.threads);
79 
80  SHOW(my_cfg, lossless);
81  SHOW(my_cfg, cpuused);
82  SHOW(my_cfg, token_parts);
83  SHOW(my_cfg, static_thresh);
84  SHOW(my_cfg, noise_sensitivity);
85  SHOW(my_cfg, max_intra_bitrate_pct);
86  SHOW(my_cfg, tune_content);
87 
88  SHOW(cfg, g_usage);
89  SHOW(cfg, g_threads);
90  SHOW(cfg, g_profile);
91  SHOW(cfg, g_w);
92  SHOW(cfg, g_h);
93  SHOW(cfg, g_bit_depth);
94  SHOW(cfg, g_input_bit_depth);
95  SHOW(cfg, g_timebase.num);
96  SHOW(cfg, g_timebase.den);
97  SHOW(cfg, g_error_resilient);
98  SHOW(cfg, g_pass);
99  SHOW(cfg, g_lag_in_frames);
100  SHOW(cfg, rc_dropframe_thresh);
101  SHOW(cfg, rc_resize_allowed);
102  SHOW(cfg, rc_scaled_width);
103  SHOW(cfg, rc_scaled_height);
104  SHOW(cfg, rc_resize_up_thresh);
105  SHOW(cfg, rc_resize_down_thresh);
106  SHOW(cfg, rc_end_usage);
107  SHOW(cfg, rc_target_bitrate);
108  SHOW(cfg, rc_min_quantizer);
109  SHOW(cfg, rc_max_quantizer);
110  SHOW(cfg, rc_undershoot_pct);
111  SHOW(cfg, rc_overshoot_pct);
112  SHOW(cfg, rc_buf_sz);
113  SHOW(cfg, rc_buf_initial_sz);
114  SHOW(cfg, rc_buf_optimal_sz);
115  SHOW(cfg, rc_2pass_vbr_bias_pct);
116  SHOW(cfg, rc_2pass_vbr_minsection_pct);
117  SHOW(cfg, rc_2pass_vbr_maxsection_pct);
118  SHOW(cfg, kf_mode);
119  SHOW(cfg, kf_min_dist);
120  SHOW(cfg, kf_max_dist);
121  SHOW(cfg, ss_number_layers);
122  SHOW(cfg, ts_number_layers);
123  SHOW(cfg, ts_periodicity);
124  SHOW(cfg, temporal_layering_mode);
125 
126  if (my_cfg->codecs) {
128 
129  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "======== Codec specific profiles ========\n");
130 
131  for (hp = my_cfg->codecs->headers; hp; hp = hp->next) {
132  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " %-28s = %s\n", hp->name, hp->value);
133  }
134  }
135 }
136 
137 /* http://tools.ietf.org/html/draft-ietf-payload-vp8-10
138 
139  The first octets after the RTP header are the VP8 payload descriptor, with the following structure.
140 #endif
141 
142  0 1 2 3 4 5 6 7
143  +-+-+-+-+-+-+-+-+
144  |X|R|N|S|R| PID | (REQUIRED)
145  +-+-+-+-+-+-+-+-+
146  X: |I|L|T|K| RSV | (OPTIONAL)
147  +-+-+-+-+-+-+-+-+
148  I: |M| PictureID | (OPTIONAL)
149  +-+-+-+-+-+-+-+-+
150  L: | TL0PICIDX | (OPTIONAL)
151  +-+-+-+-+-+-+-+-+
152  T/K:|TID|Y| KEYIDX | (OPTIONAL)
153  +-+-+-+-+-+-+-+-+
154 
155 
156  VP8 Payload Header
157 
158  0 1 2 3 4 5 6 7
159  +-+-+-+-+-+-+-+-+
160  |Size0|H| VER |P|
161  +-+-+-+-+-+-+-+-+
162  | Size1 |
163  +-+-+-+-+-+-+-+-+
164  | Size2 |
165  +-+-+-+-+-+-+-+-+
166  | Bytes 4..N of |
167  | VP8 payload |
168  : :
169  +-+-+-+-+-+-+-+-+
170  | OPTIONAL RTP |
171  | padding |
172  : :
173  +-+-+-+-+-+-+-+-+
174 */
175 
176 
177 #ifdef _MSC_VER
178 #pragma pack(push, r1, 1)
179 #endif
180 
181 #if SWITCH_BYTE_ORDER == __BIG_ENDIAN
182 
183 typedef struct {
184  unsigned extended:1;
185  unsigned reserved1:1;
186  unsigned non_referenced:1;
187  unsigned start:1;
188  unsigned reserved2:1;
189  unsigned pid:3;
190  unsigned I:1;
191  unsigned L:1;
192  unsigned T:1;
193  unsigned K:1;
194  unsigned RSV:4;
195  unsigned M:1;
196  unsigned PID:15;
197  unsigned TL0PICIDX:8;
198  unsigned TID:2;
199  unsigned Y:1;
200  unsigned KEYIDX:5;
201 } vp8_payload_descriptor_t;
202 
203 typedef struct {
204  unsigned have_pid:1;
205  unsigned have_p_layer:1;
206  unsigned have_layer_ind:1;
207  unsigned is_flexible:1;
208  unsigned start:1;
209  unsigned end:1;
210  unsigned have_ss:1;
211  unsigned zero:1;
212 } vp9_payload_descriptor_t;
213 
214 typedef struct {
215  unsigned n_s:3;
216  unsigned y:1;
217  unsigned g:1;
218  unsigned zero:3;
219 } vp9_ss_t;
220 
221 typedef struct {
222  unsigned t:3;
223  unsigned u:1;
224  unsigned r:2;
225  unsigned zero:2;
226 } vp9_n_g_t;
227 
228 typedef struct {
229  unsigned temporal_id:3;
230  unsigned temporal_up_switch:1;
231  unsigned spatial_id:3;
232  unsigned inter_layer_predicted:1;
233 } vp9_p_layer_t;
234 
235 #else /* ELSE LITTLE */
236 
237 typedef struct {
238  unsigned pid:3;
239  unsigned reserved2:1;
240  unsigned start:1;
241  unsigned non_referenced:1;
242  unsigned reserved1:1;
243  unsigned extended:1;
244  unsigned RSV:4;
245  unsigned K:1;
246  unsigned T:1;
247  unsigned L:1;
248  unsigned I:1;
249  unsigned PID:15;
250  unsigned M:1;
251  unsigned TL0PICIDX:8;
252  unsigned KEYIDX:5;
253  unsigned Y:1;
254  unsigned TID:2;
255 } vp8_payload_descriptor_t;
256 
257 typedef struct {
258  unsigned zero:1;
259  unsigned have_ss:1;
260  unsigned end:1;
261  unsigned start:1;
262  unsigned is_flexible:1;
263  unsigned have_layer_ind:1;
264  unsigned have_p_layer:1;
265  unsigned have_pid:1;
266 } vp9_payload_descriptor_t;
267 
268 typedef struct {
269  unsigned zero:3;
270  unsigned g:1;
271  unsigned y:1;
272  unsigned n_s:3;
273 } vp9_ss_t;
274 
275 typedef struct {
276  unsigned zero:2;
277  unsigned r:2;
278  unsigned u:1;
279  unsigned t:3;
280 } vp9_n_g_t;
281 
282 typedef struct {
283  unsigned inter_layer_predicted:1;
284  unsigned spatial_id:3;
285  unsigned temporal_up_switch:1;
286  unsigned temporal_id:3;
287 } vp9_p_layer_t;
288 
289 #endif
290 
291 typedef union {
292  vp8_payload_descriptor_t vp8;
293  vp9_payload_descriptor_t vp9;
294 } vpx_payload_descriptor_t;
295 
296 #define kMaxVp9NumberOfSpatialLayers 16
297 
298 typedef struct {
299  switch_bool_t has_received_sli;
300  uint8_t picture_id_sli;
301  switch_bool_t has_received_rpsi;
302  uint64_t picture_id_rpsi;
303  int16_t picture_id; // Negative value to skip pictureId.
304 
305  switch_bool_t inter_pic_predicted; // This layer frame is dependent on previously
306  // coded frame(s).
307  switch_bool_t flexible_mode;
308  switch_bool_t ss_data_available;
309 
310  int tl0_pic_idx; // Negative value to skip tl0PicIdx.
311  uint8_t temporal_idx;
312  uint8_t spatial_idx;
313  switch_bool_t temporal_up_switch;
314  switch_bool_t inter_layer_predicted; // Frame is dependent on directly lower spatial
315  // layer frame.
316  uint8_t gof_idx;
317 
318  // SS data.
319  size_t num_spatial_layers;
320  switch_bool_t spatial_layer_resolution_present;
321  uint16_t width[kMaxVp9NumberOfSpatialLayers];
322  uint16_t height[kMaxVp9NumberOfSpatialLayers];
323  // GofInfoVP9 gof;
324 } vp9_info_t;
325 
326 
327 #ifdef _MSC_VER
328 #pragma pack(pop, r1)
329 #endif
330 
331 
332 #define __IS_VP8_KEY_FRAME(byte) !(((byte) & 0x01))
333 static inline int IS_VP8_KEY_FRAME(uint8_t *data)
334 {
335  uint8_t S;
336  uint8_t DES;
337  uint8_t PID;
338 
339  DES = *data;
340  data++;
341  S = DES & 0x10;
342  PID = DES & 0x07;
343 
344  if (DES & 0x80) { // X
345  uint8_t X = *data;
346  data++;
347  if (X & 0x80) { // I
348  uint8_t M = (*data) & 0x80;
349  data++;
350  if (M) data++;
351  }
352  if (X & 0x40) data++; // L
353  if (X & 0x30) data++; // T/K
354  }
355 
356  if (S && (PID == 0)) {
357  return __IS_VP8_KEY_FRAME(*data);
358  } else {
359  // if (PID > 0) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PID: %d\n", PID);
360  return 0;
361  }
362 }
363 
364 #define IS_VP9_KEY_FRAME(byte) ((((byte) & 0x40) == 0) && ((byte) & 0x0A))
365 #define IS_VP9_START_PKT(byte) ((byte) & 0x08)
366 
367 #ifdef WIN32
368 #undef SWITCH_MOD_DECLARE_DATA
369 #define SWITCH_MOD_DECLARE_DATA __declspec(dllexport)
370 #endif
371 SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load);
372 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vpx_shutdown);
373 SWITCH_MODULE_DEFINITION(CORE_VPX_MODULE, mod_vpx_load, mod_vpx_shutdown, NULL);
374 
375 struct vpx_context {
376  int debug;
377  switch_codec_t *codec;
378  int is_vp9;
379  vp9_info_t vp9;
380  vpx_codec_iface_t *encoder_interface;
381  vpx_codec_iface_t *decoder_interface;
382  unsigned int flags;
383  switch_codec_settings_t codec_settings;
384  unsigned int bandwidth;
385  vpx_codec_enc_cfg_t config;
386  switch_time_t last_key_frame;
387 
388  vpx_codec_ctx_t encoder;
389  uint8_t encoder_init;
390  vpx_image_t *pic;
391  switch_bool_t force_key_frame;
392  int fps;
393  int format;
394  int intra_period;
395  int num;
396  int partition_index;
397  const vpx_codec_cx_pkt_t *pkt;
398  vpx_codec_iter_t enc_iter;
399  vpx_codec_iter_t dec_iter;
400  uint32_t last_ts;
401  switch_time_t last_ms;
402  vpx_codec_ctx_t decoder;
403  uint8_t decoder_init;
404  int decoded_first_frame;
405  switch_buffer_t *vpx_packet_buffer;
406  int got_key_frame;
407  int no_key_frame;
408  int got_start_frame;
409  uint32_t last_received_timestamp;
410  switch_bool_t last_received_complete_picture;
411  uint16_t last_received_seq;
412  int need_key_frame;
413  int need_encoder_reset;
414  int need_decoder_reset;
415  int32_t change_bandwidth;
416  uint64_t framecount;
418  switch_buffer_t *pbuffer;
419  switch_time_t start_time;
420  switch_image_t *patch_img;
421  int16_t picture_id;
422 };
423 typedef struct vpx_context vpx_context_t;
424 
425 #define MAX_PROFILES 100
426 
427 struct vpx_globals {
428  int debug;
429  uint32_t max_bitrate;
430  uint32_t rtp_slice_size;
431  uint32_t key_frame_min_freq;
432 
433  uint32_t dec_threads;
434  uint32_t enc_threads;
435 
436  my_vpx_cfg_t *profiles[MAX_PROFILES];
437 };
438 
439 struct vpx_globals vpx_globals = { 0 };
440 
441 static my_vpx_cfg_t *find_cfg_profile(const char *name, switch_bool_t reconfig);
442 static void parse_profile(my_vpx_cfg_t *my_cfg, switch_xml_t profile, int codec_type);
443 
444 static switch_status_t init_decoder(switch_codec_t *codec)
445 {
446  vpx_context_t *context = (vpx_context_t *)codec->private_info;
447 
448  //if (context->decoder_init) {
449  // vpx_codec_destroy(&context->decoder);
450  // context->decoder_init = 0;
451  //}
452 
453  if (context->flags & SWITCH_CODEC_FLAG_DECODE && !context->decoder_init) {
454  vpx_codec_dec_cfg_t cfg = {0, 0, 0};
455  vpx_codec_flags_t dec_flags = 0;
456  vp8_postproc_cfg_t ppcfg;
457  my_vpx_cfg_t *my_cfg = NULL;
458  vpx_codec_err_t err;
459 
460  if (context->is_vp9) {
461  my_cfg = find_cfg_profile("vp9", SWITCH_FALSE);
462  } else {
463  my_cfg = find_cfg_profile("vp8", SWITCH_FALSE);
464  }
465 
466  if (!my_cfg) return SWITCH_STATUS_FALSE;
467 
468  cfg.threads = my_cfg->dec_cfg.threads;
469 
470  if ((err = vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags)) != VPX_CODEC_OK) {
472  "VPX decoder %s codec init error: [%d:%s:%s]\n",
473  vpx_codec_iface_name(context->decoder_interface),
474  err, vpx_codec_error(&context->decoder), vpx_codec_error_detail(&context->decoder));
475  return SWITCH_STATUS_FALSE;
476  }
477 
478  context->last_ts = 0;
479  context->last_received_timestamp = 0;
480  context->last_received_complete_picture = 0;
481  context->last_received_seq = 0;
482  context->decoder_init = 1;
483  context->got_key_frame = 0;
484  context->no_key_frame = 0;
485  context->got_start_frame = 0;
486  // the types of post processing to be done, should be combination of "vp8_postproc_level"
487  ppcfg.post_proc_flag = VP8_DEBLOCK;//VP8_DEMACROBLOCK | VP8_DEBLOCK;
488  // the strength of deblocking, valid range [0, 16]
489  ppcfg.deblocking_level = 1;
490  // Set deblocking settings
491  vpx_codec_control(&context->decoder, VP8_SET_POSTPROC, &ppcfg);
492 
493  if (context->vpx_packet_buffer) {
494  switch_buffer_zero(context->vpx_packet_buffer);
495  } else {
496  switch_buffer_create_dynamic(&context->vpx_packet_buffer, 512, 512, 0);
497  }
498  }
499 
500  return SWITCH_STATUS_SUCCESS;
501 }
502 
503 static int CODEC_TYPE(const char *string)
504 {
505  if (!strcmp(string, "vp8")) {
506  return CODEC_TYPE_VP8;
507  } else if (!strcmp(string, "vp9")) {
508  return CODEC_TYPE_VP9;
509  }
510 
511  return CODEC_TYPE_ANY;
512 }
513 
514 static void parse_codec_specific_profile(my_vpx_cfg_t *my_cfg, const char *codec_name)
515 {
516  switch_xml_t cfg = NULL;
517  switch_xml_t xml = switch_xml_open_cfg("vpx.conf", &cfg, NULL);
518  switch_xml_t profiles = cfg ? switch_xml_child(cfg, "profiles") : NULL;
519 
520  // open config and find the profile to parse
521  if (profiles) {
523 
524  for (hp = my_cfg->codecs->headers; hp; hp = hp->next) {
525  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: %s\n", hp->name, hp->value);
526  if (!strcmp(hp->name, codec_name)) {
527  switch_xml_t profile;
528  for (profile = switch_xml_child(profiles, "profile"); profile; profile = profile->next) {
529  const char *name = switch_xml_attr(profile, "name");
530 
531  if (!strcmp(hp->value, name)) {
532  parse_profile(my_cfg, profile, CODEC_TYPE(codec_name));
533  }
534  }
535  }
536  }
537  }
538 
539  if (xml) switch_xml_free(xml);
540 }
541 
542 static switch_status_t init_encoder(switch_codec_t *codec)
543 {
544  vpx_context_t *context = (vpx_context_t *)codec->private_info;
545  vpx_codec_enc_cfg_t *config = &context->config;
546  my_vpx_cfg_t *my_cfg = NULL;
547  vpx_codec_err_t err;
548  char *codec_name = "vp8";
549 
550  if (context->is_vp9) {
551  codec_name = "vp9";
552  }
553 
554  if (!zstr(context->codec_settings.video.config_profile_name)) {
555  my_cfg = find_cfg_profile(context->codec_settings.video.config_profile_name, SWITCH_FALSE);
556  }
557 
558  if (!my_cfg) {
559  my_cfg = find_cfg_profile(codec_name, SWITCH_FALSE);
560  }
561 
562  if (!my_cfg) return SWITCH_STATUS_FALSE;
563 
564  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "config: %s\n", my_cfg->name);
565 
566  if (context->is_vp9) {
567  my_cfg->enc_cfg.g_profile = 0; // default build of VP9 only support 0, TODO: remove this
568  }
569 
570  if (my_cfg->codecs) {
571  parse_codec_specific_profile(my_cfg, codec_name);
572  }
573 
574  if (vpx_globals.debug) show_config(my_cfg, &my_cfg->enc_cfg);
575 
576  if (!context->codec_settings.video.width) {
577  context->codec_settings.video.width = 1280;
578  }
579 
580  if (!context->codec_settings.video.height) {
581  context->codec_settings.video.height = 720;
582  }
583 
584  if (context->codec_settings.video.bandwidth == -1) {
585  context->codec_settings.video.bandwidth = 0;
586  }
587 
588  if (context->codec_settings.video.bandwidth) {
589  context->bandwidth = context->codec_settings.video.bandwidth;
590  } else {
591  context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 15);
592  }
593 
594  if (context->bandwidth > vpx_globals.max_bitrate) {
595  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "REQUESTED BITRATE TRUNCATED FROM %d TO %d\n", context->bandwidth, vpx_globals.max_bitrate);
596  context->bandwidth = vpx_globals.max_bitrate;
597  }
598 
600  "VPX encoder reset (WxH/BW) from %dx%d/%u to %dx%d/%u\n",
601  config->g_w, config->g_h, config->rc_target_bitrate,
602  context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth);
603 
604  context->pkt = NULL;
605  context->start_time = switch_micro_time_now();
606 
607  *config = my_cfg->enc_cfg; // reset whole config to current defaults
608 
609  config->g_w = context->codec_settings.video.width;
610  config->g_h = context->codec_settings.video.height;
611  config->rc_target_bitrate = context->bandwidth;
612 
613  if (context->is_vp9) {
614  if (my_cfg->lossless) {
615  config->rc_min_quantizer = 0;
616  config->rc_max_quantizer = 0;
617  }
618  }
619 
620  if (context->encoder_init) {
621  if ((err = vpx_codec_enc_config_set(&context->encoder, config)) != VPX_CODEC_OK) {
623  "VPX encoder %s codec reconf error: [%d:%s:%s]\n",
624  vpx_codec_iface_name(context->encoder_interface),
625  err, vpx_codec_error(&context->encoder), vpx_codec_error_detail(&context->encoder));
626  return SWITCH_STATUS_FALSE;
627  }
628  } else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) {
629  if (vpx_globals.debug) {
630  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_INFO, "VPX encoder %s settings:\n", vpx_codec_iface_name(context->encoder_interface));
631  show_config(my_cfg, config);
632  }
633 
634  if ((err = vpx_codec_enc_init(&context->encoder, context->encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION)) != VPX_CODEC_OK) {
636  "VPX encoder %s codec init error: [%d:%s:%s]\n",
637  vpx_codec_iface_name(context->encoder_interface),
638  err, vpx_codec_error(&context->encoder), vpx_codec_error_detail(&context->encoder));
639  return SWITCH_STATUS_FALSE;
640  }
641 
642  context->encoder_init = 1;
643 
644  vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, my_cfg->token_parts);
645  vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, my_cfg->cpuused);
646  vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, my_cfg->static_thresh);
647 
648  if (context->is_vp9) {
649  if (my_cfg->lossless) {
650  vpx_codec_control(&context->encoder, VP9E_SET_LOSSLESS, 1);
651  }
652 
653  vpx_codec_control(&context->encoder, VP9E_SET_TUNE_CONTENT, my_cfg->tune_content);
654  } else {
655  vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, my_cfg->noise_sensitivity);
656 
657  if (my_cfg->max_intra_bitrate_pct) {
658  vpx_codec_control(&context->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT, my_cfg->max_intra_bitrate_pct);
659  }
660  }
661  }
662 
663  return SWITCH_STATUS_SUCCESS;
664 }
665 
666 static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
667 {
668  vpx_context_t *context = NULL;
669  int encoding, decoding;
670 
671  encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
672  decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
673 
674  if (!(encoding || decoding) || ((context = switch_core_alloc(codec->memory_pool, sizeof(*context))) == 0)) {
675  return SWITCH_STATUS_FALSE;
676  }
677 
678  memset(context, 0, sizeof(*context));
679  context->flags = flags;
680  codec->private_info = context;
681  context->pool = codec->memory_pool;
682 
683  if (codec_settings) {
684  context->codec_settings = *codec_settings;
685  }
686 
687  if (!strcmp(codec->implementation->iananame, "VP9")) {
688  context->is_vp9 = 1;
689  context->encoder_interface = vpx_codec_vp9_cx();
690  context->decoder_interface = vpx_codec_vp9_dx();
691  } else {
692  context->encoder_interface = vpx_codec_vp8_cx();
693  context->decoder_interface = vpx_codec_vp8_dx();
694  }
695 
696  if (codec->fmtp_in) {
697  codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
698  }
699 
700  context->codec_settings.video.width = 320;
701  context->codec_settings.video.height = 240;
702 
703  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_DEBUG, "VPX VER:%s VPX_IMAGE_ABI_VERSION:%d VPX_CODEC_ABI_VERSION:%d\n",
704  vpx_codec_version_str(), VPX_IMAGE_ABI_VERSION, VPX_CODEC_ABI_VERSION);
705 
706  if (!context->is_vp9) {
707  context->picture_id = 13; // picture Id may start from random value and must be incremented on each frame
708  } else {
709  context->vp9.picture_id = 13;
710  }
711 
712  return SWITCH_STATUS_SUCCESS;
713 }
714 
715 static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t *frame)
716 {
717  vpx_payload_descriptor_t *payload_descriptor;
718  uint8_t *body, *c = NULL;
719  uint32_t hdrlen = 0, payload_size = 0, max_payload_size = 0, start = 0, key = 0;
720  switch_size_t remaining_bytes = 0;
721  switch_status_t status;
722 
723  if (!context->pkt) {
724  if ((context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->enc_iter))) {
725  start = 1;
726  if (!context->pbuffer) {
727  switch_buffer_create_partition(context->pool, &context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
728  } else {
729  switch_buffer_set_partition_data(context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
730  }
731  }
732  }
733 
734  if (context->pbuffer) {
735  remaining_bytes = switch_buffer_inuse(context->pbuffer);
736  }
737 
738  if (!context->pkt || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT || !remaining_bytes) {
739  frame->datalen = 0;
740  frame->m = 1;
741  context->pkt = NULL;
743  return SWITCH_STATUS_SUCCESS;
744  }
745 
746  key = (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY);
747 
748 #if 0
749  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "flags: %x pts: %lld duration:%lu partition_id: %d\n",
750  context->pkt->data.frame.flags, context->pkt->data.frame.pts, context->pkt->data.frame.duration, context->pkt->data.frame.partition_id);
751 #endif
752 
753  /* reset header */
754  *(uint8_t *)frame->data = 0;
755  payload_descriptor = (vpx_payload_descriptor_t *) frame->data;
756  memset(payload_descriptor, 0, sizeof(*payload_descriptor));
757 
758 
759  if (context->is_vp9) {
760  hdrlen = 1; /* Send VP9 with 1 byte REQUIRED header. */
761  } else {
762  hdrlen = 4; /* Send VP8 with 4 byte extended header, includes 1 byte REQUIRED header, 1 byte X header and 2 bytes of I header with picture_id. */
763  }
764 
765  body = ((uint8_t *)frame->data) + hdrlen;
766 
767  if (context->is_vp9) {
768  payload_descriptor->vp9.start = start;
769 
770  if (1) {
771  // payload_descriptor->vp9.have_p_layer = key; // key?
772  payload_descriptor->vp9.have_pid = 1;
773 
774  if (payload_descriptor->vp9.have_pid) {
775  if (context->vp9.picture_id > 0x7f) {
776  *body++ = (context->vp9.picture_id >> 8) | 0x80;
777  *body++ = context->vp9.picture_id & 0xff;
778  hdrlen += 2;
779  } else {
780  *body++ = context->vp9.picture_id;
781  hdrlen++;
782  }
783  }
784 
785  if (key) {
786  vp9_ss_t *ss = (vp9_ss_t *)body;
787 
788  payload_descriptor->vp9.have_ss = 1;
789  payload_descriptor->vp9.have_p_layer = 0;
790  ss->n_s = 0;
791  ss->g = 0;
792  ss->y = 0;
793  ss->zero = 0;
794  body++;
795  hdrlen++;
796 
797  if (0) { // y ?
798  uint16_t *w;
799  uint16_t *h;
800 
801  ss->y = 1;
802 
803  w = (uint16_t *)body;
804  body+=2;
805  h = (uint16_t *)body;
806  body+=2;
807 
808  *w = (uint16_t)context->codec_settings.video.width;
809  *h = (uint16_t)context->codec_settings.video.height;
810 
811  hdrlen += (ss->n_s + 1) * 4;
812  }
813  } else {
814  payload_descriptor->vp9.have_p_layer = 1;
815  }
816  }
817  }
818 
819  if (!context->is_vp9) {
820  payload_descriptor->vp8.start = start;
821 
822  payload_descriptor->vp8.extended = 1; /* REQUIRED header. */
823 
824  payload_descriptor->vp8.I = 1; /* X header. */
825 
826  payload_descriptor->vp8.M = 1; /* I header. */
827  c = ((uint8_t *)frame->data) + 2;
828  *c++ = (context->picture_id >> 8) | 0x80;
829  *c = context->picture_id & 0xff;
830 
831  payload_descriptor->vp8.L = 0;
832  payload_descriptor->vp8.TL0PICIDX = 0;
833 
834  payload_descriptor->vp8.T = 0;
835  payload_descriptor->vp8.TID = 0;
836  payload_descriptor->vp8.Y = 0;
837  payload_descriptor->vp8.K = 0;
838  payload_descriptor->vp8.KEYIDX = 0;
839  }
840 
841  /*
842  Try to split payload to packets evenly(with largest at the end) up to vpx_globals.rtp_slice_size,
843  (assume hdrlen constant across all packets of the same picture).
844  It keeps packets being transmitted in order.
845  Without it last (and thus the smallest one) packet usually arrive out of order
846  (before the previous one)
847  */
848  max_payload_size = vpx_globals.rtp_slice_size - hdrlen;
849  payload_size = remaining_bytes / ((remaining_bytes + max_payload_size - 1) / max_payload_size);
850 
851  if (remaining_bytes <= payload_size) {
852  switch_buffer_read(context->pbuffer, body, remaining_bytes);
853  context->pkt = NULL;
854  frame->datalen = hdrlen + remaining_bytes;
855  frame->m = 1;
856 
857  // increment and wrap picture_id (if needed) after the last picture's packet
858  if (context->is_vp9) {
859  context->vp9.picture_id++;
860  if ((uint16_t)context->vp9.picture_id > 0x7fff) {
861  context->vp9.picture_id = 0;
862  }
863  } else {
864  context->picture_id++;
865  if ((uint16_t)context->picture_id > 0x7fff) {
866  context->picture_id = 0;
867  }
868  }
869 
870  status = SWITCH_STATUS_SUCCESS;
871  } else {
872  switch_buffer_read(context->pbuffer, body, payload_size);
873  frame->datalen = hdrlen + payload_size;
874  frame->m = 0;
875  status = SWITCH_STATUS_MORE_DATA;
876  }
877 
878  if (frame->m && context->is_vp9) {
879  payload_descriptor->vp9.end = 1;
880  }
881 
882  return status;
883 }
884 
885 static switch_status_t reset_codec_encoder(switch_codec_t *codec)
886 {
887  vpx_context_t *context = (vpx_context_t *)codec->private_info;
888 
889  if (context->encoder_init) {
890  vpx_codec_destroy(&context->encoder);
891  }
892  context->last_ts = 0;
893  context->last_ms = 0;
894  context->framecount = 0;
895  context->encoder_init = 0;
896  context->pkt = NULL;
897  return init_encoder(codec);
898 }
899 
900 static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *frame)
901 {
902  vpx_context_t *context = (vpx_context_t *)codec->private_info;
903  int width = 0;
904  int height = 0;
905  uint32_t dur;
906  int64_t pts;
907  vpx_enc_frame_flags_t vpx_flags = 0;
908  switch_time_t now;
909  vpx_codec_err_t err;
910 
911  if (frame->flags & SFF_SAME_IMAGE) {
912  return consume_partition(context, frame);
913  }
914 
915  if (context->need_encoder_reset != 0) {
916  if (reset_codec_encoder(codec) != SWITCH_STATUS_SUCCESS) {
917  return SWITCH_STATUS_FALSE;
918  }
919  context->need_encoder_reset = 0;
920  }
921 
922  if (frame->img->d_h > 1) {
923  width = frame->img->d_w;
924  height = frame->img->d_h;
925  } else {
926  width = frame->img->w;
927  height = frame->img->h;
928  }
929 
930  if (context->codec_settings.video.width != width || context->codec_settings.video.height != height) {
931  context->codec_settings.video.width = width;
932  context->codec_settings.video.height = height;
933  reset_codec_encoder(codec);
934  frame->flags |= SFF_PICTURE_RESET;
935  context->need_key_frame = 3;
936  }
937 
938  if (!context->encoder_init) {
939  if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
940  return SWITCH_STATUS_FALSE;
941  }
942  }
943 
944  if (context->change_bandwidth) {
945  context->codec_settings.video.bandwidth = context->change_bandwidth;
946  context->change_bandwidth = 0;
947  if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
948  return SWITCH_STATUS_FALSE;
949  }
950  }
951 
952  now = switch_time_now();
953 
954  if (context->need_key_frame > 0) {
955  // force generate a key frame
956  if (!context->last_key_frame || (now - context->last_key_frame) > vpx_globals.key_frame_min_freq) {
957  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), VPX_SWITCH_LOG_LEVEL,
958  "VPX encoder keyframe request\n");
959  vpx_flags |= VPX_EFLAG_FORCE_KF;
960  context->need_key_frame = 0;
961  context->last_key_frame = now;
962  }
963  }
964 
965  context->framecount++;
966 
967  pts = (now - context->start_time) / 1000;
968  //pts = frame->timestamp;
969 
970  dur = context->last_ms ? (now - context->last_ms) / 1000 : pts;
971 
972  if ((err = vpx_codec_encode(&context->encoder,
973  (vpx_image_t *) frame->img,
974  pts,
975  dur,
976  vpx_flags,
977  VPX_DL_REALTIME)) != VPX_CODEC_OK) {
978  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_ERROR, "VPX encode error [%d:%s:%s]\n",
979  err, vpx_codec_error(&context->encoder), vpx_codec_error_detail(&context->encoder));
980  frame->datalen = 0;
981  return SWITCH_STATUS_FALSE;
982  }
983 
984  context->enc_iter = NULL;
985  context->last_ts = frame->timestamp;
986  context->last_ms = now;
987 
988  return consume_partition(context, frame);
989 }
990 
991 static switch_status_t buffer_vp8_packets(vpx_context_t *context, switch_frame_t *frame)
992 {
993  uint8_t *data = frame->data;
994  uint8_t S;
995  uint8_t DES;
996  // uint8_t PID;
997  int len;
998 
999  if (context->debug > 0) {
1000  switch_log_printf(SWITCH_CHANNEL_LOG, context->debug,
1001  "VIDEO VPX: seq: %d ts: %u len: %u %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d\n",
1002  frame->seq, frame->timestamp, frame->datalen,
1003  *((uint8_t *)data), *((uint8_t *)data + 1),
1004  *((uint8_t *)data + 2), *((uint8_t *)data + 3),
1005  *((uint8_t *)data + 4), *((uint8_t *)data + 5),
1006  *((uint8_t *)data + 6), *((uint8_t *)data + 7),
1007  *((uint8_t *)data + 8), *((uint8_t *)data + 9),
1008  *((uint8_t *)data + 10), frame->m);
1009  }
1010 
1011  DES = *data;
1012  data++;
1013  S = (DES & 0x10);
1014  // PID = DES & 0x07;
1015 
1016  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DATA LEN %d S BIT %d PID: %d\n", frame->datalen, S, PID);
1017 
1018  if (DES & 0x80) { // X
1019  uint8_t X = *data;
1020  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "X BIT SET\n");
1021  data++;
1022  if (X & 0x80) { // I
1023  uint8_t M = (*data) & 0x80;
1024  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "I BIT SET\n");
1025  data++;
1026  if (M) {
1027  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "M BIT SET\n");
1028  data++;
1029  }
1030  }
1031  if (X & 0x40) {
1032  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "L BIT SET\n");
1033  data++; // L
1034  }
1035  if (X & 0x30) {
1036  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "T/K BIT SET\n");
1037  data++; // T/K
1038  }
1039  }
1040 
1041  if (!switch_buffer_inuse(context->vpx_packet_buffer) && !S) {
1042  if (context->got_key_frame > 0) {
1043  context->got_key_frame = 0;
1044  context->got_start_frame = 0;
1046  }
1047  return SWITCH_STATUS_MORE_DATA;
1048  }
1049 
1050  if (S) {
1051  switch_buffer_zero(context->vpx_packet_buffer);
1052  context->last_received_timestamp = frame->timestamp;
1053 #if 0
1054  if (PID == 0) {
1055  key = __IS_VP8_KEY_FRAME(*data);
1056  }
1057 #endif
1058  }
1059 
1060  len = frame->datalen - (data - (uint8_t *)frame->data);
1061  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POST PARSE: DATA LEN %d KEY %d KEYBYTE = %0x\n", len, key, *data);
1062 
1063  if (len <= 0) {
1064  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid packet %d\n", len);
1065  return SWITCH_STATUS_RESTART;
1066  }
1067 
1068  if (context->last_received_timestamp != frame->timestamp) {
1069  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "wrong timestamp %u, expect %u, packet loss?\n", frame->timestamp, context->last_received_timestamp);
1070  switch_buffer_zero(context->vpx_packet_buffer);
1071  return SWITCH_STATUS_RESTART;
1072  }
1073 
1074  switch_buffer_write(context->vpx_packet_buffer, data, len);
1075  return SWITCH_STATUS_SUCCESS;
1076 }
1077 
1078 // https://tools.ietf.org/id/draft-ietf-payload-vp9-01.txt
1079 
1080 static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t *frame)
1081 {
1082  uint8_t *data = (uint8_t *)frame->data;
1083  uint8_t *vp9 = (uint8_t *)frame->data;
1084  vp9_payload_descriptor_t *desc = (vp9_payload_descriptor_t *)vp9;
1085  int len = 0;
1086 
1087  if (context->debug > 0) {
1089  "[%02x %02x %02x %02x] m=%d len=%4d seq=%d ts=%u ssrc=%u "
1090  "have_pid=%d "
1091  "have_p_layer=%d "
1092  "have_layer_ind=%d "
1093  "is_flexible=%d "
1094  "start=%d "
1095  "end=%d "
1096  "have_ss=%d "
1097  "zero=%d\n",
1098  *data, *(data+1), *(data+2), *(data+3), frame->m, frame->datalen, frame->seq, frame->timestamp, frame->ssrc,
1099  desc->have_pid,
1100  desc->have_p_layer,
1101  desc->have_layer_ind,
1102  desc->is_flexible,
1103  desc->start,
1104  desc->end,
1105  desc->have_ss,
1106  desc->zero);
1107  }
1108 
1109  vp9++;
1110 
1111  if (desc->have_pid) {
1112 #ifdef DEBUG_VP9
1113  uint16_t pid = 0;
1114  pid = *vp9 & 0x7f; //0 bit is M , 1-7 bit is pid.
1115 #endif
1116  if (*vp9 & 0x80) { //if (M==1)
1117  vp9++;
1118 #ifdef DEBUG_VP9
1119  pid = (pid << 8) + *vp9;
1120 #endif
1121  }
1122 
1123  vp9++;
1124 
1125 #ifdef DEBUG_VP9
1126  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "have pid: %d start=%d end=%d\n", pid, desc->start, desc->end);
1127 #endif
1128 
1129  }
1130 
1131  if (desc->have_layer_ind) {
1132 #ifdef DEBUG_VP9
1133  vp9_p_layer_t *layer = (vp9_p_layer_t *)vp9;
1134 
1135  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "temporal_id=%d temporal_up_switch=%d spatial_id=%d inter_layer_predicted=%d\n",
1136  layer->temporal_id, layer->temporal_up_switch, layer->spatial_id, layer->inter_layer_predicted);
1137 #endif
1138 
1139  vp9++;
1140  if (!desc->is_flexible) {
1141  vp9++; // TL0PICIDX
1142  }
1143  }
1144 
1145  //When P and F are both set to one, indicating a non-key frame in flexible mode
1146  if (desc->have_p_layer && desc->is_flexible) { // P & F set, P_DIFF
1147  if (*vp9 & 1) { // N
1148  vp9++;
1149  if (*vp9 & 1) { // N
1150  vp9++;
1151  if (*vp9 & 1) {
1152  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid VP9 packet!");
1153  switch_buffer_zero(context->vpx_packet_buffer);
1154  goto end;
1155  }
1156  }
1157  }
1158  vp9++;
1159  }
1160 
1161  if (desc->have_ss) {
1162  vp9_ss_t *ss = (vp9_ss_t *)(vp9++);
1163 
1164 #ifdef DEBUG_VP9
1165  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "have ss: %02x n_s: %d y:%d g:%d\n", *(uint8_t *)ss, ss->n_s, ss->y, ss->g);
1166 #endif
1167  if (ss->y) {
1168  int i;
1169 
1170  for (i=0; i<=ss->n_s; i++) {
1171 #ifdef DEBUG_VP9
1172  int width = ntohs(*(uint16_t *)vp9);
1173  int height = ntohs(*(uint16_t *)(vp9 + 2));
1174  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SS: %d %dx%d\n", i, width, height);
1175 #endif
1176  vp9 += 4;
1177  }
1178  }
1179 
1180  if (ss->g) {
1181  int i;
1182  uint8_t ng = *vp9++; //N_G indicates the number of frames in a GOF
1183 
1184  for (i = 0; ng > 0 && i < ng; i++) {
1185  vp9_n_g_t *n_g = (vp9_n_g_t *)(vp9++);
1186  vp9 += n_g->r;
1187  }
1188  }
1189  }
1190 
1191  if (vp9 - data >= frame->datalen) {
1192  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Invalid VP9 Packet %" SWITCH_SSIZE_T_FMT " > %d\n", vp9 - data, frame->datalen);
1193  switch_buffer_zero(context->vpx_packet_buffer);
1194  goto end;
1195  }
1196 
1197  if (!switch_buffer_inuse(context->vpx_packet_buffer)) { // start packet
1198  if (!desc->start) {
1199  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got invalid vp9 packet, packet loss? waiting for a start packet\n");
1200  goto end;
1201  }
1202  }
1203 
1204  len = frame->datalen - (vp9 - data);
1205  switch_buffer_write(context->vpx_packet_buffer, vp9, len);
1206 
1207 end:
1208 
1209 #ifdef DEBUG_VP9
1210  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "buffered %d bytes, buffer size: %" SWITCH_SIZE_T_FMT "\n", len, switch_buffer_inuse(context->vpx_packet_buffer));
1211 #endif
1212 
1213  return SWITCH_STATUS_SUCCESS;
1214 }
1215 
1216 static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *frame)
1217 {
1218  vpx_context_t *context = (vpx_context_t *)codec->private_info;
1219  switch_size_t len;
1220  vpx_codec_ctx_t *decoder = NULL;
1222  int is_start = 0, is_keyframe = 0, get_refresh = 0;
1223 
1224  if (context->debug > 0 && context->debug < 4) {
1225  vp9_payload_descriptor_t *desc = (vp9_payload_descriptor_t *)frame->data;
1226  uint8_t *data = frame->data;
1227  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x %02x m=%d start=%d end=%d m=%d len=%d\n",
1228  *data, *(data+1), *(data+2), *(data+3), frame->m, desc->start, desc->end, frame->m, frame->datalen);
1229  }
1230 
1231  if (context->is_vp9) {
1232  is_keyframe = IS_VP9_KEY_FRAME(*(unsigned char *)frame->data);
1233  is_start = IS_VP9_START_PKT(*(unsigned char *)frame->data);
1234 
1235  if (is_keyframe) {
1236  switch_log_printf(SWITCH_CHANNEL_LOG, VPX_SWITCH_LOG_LEVEL, "================Got a key frame!!!!========================\n");
1237  }
1238 
1239  if (context->last_received_seq && context->last_received_seq + 1 != frame->seq) {
1240  switch_log_printf(SWITCH_CHANNEL_LOG, VPX_SWITCH_LOG_LEVEL, "Packet loss detected last=%d got=%d lost=%d\n", context->last_received_seq, frame->seq, frame->seq - context->last_received_seq);
1241  if (is_keyframe) switch_buffer_zero(context->vpx_packet_buffer);
1242  }
1243 
1244  context->last_received_seq = frame->seq;
1245  } else { // vp8
1246  is_start = (*(unsigned char *)frame->data & 0x10);
1247  is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data);
1248  }
1249 
1250  if (!is_keyframe && context->got_key_frame <= 0) {
1251  context->no_key_frame++;
1252  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no keyframe, %d\n", context->no_key_frame);
1253  if (context->no_key_frame > 50) {
1254  if ((is_keyframe = is_start)) {
1255  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "no keyframe, treating start as key. frames=%d\n", context->no_key_frame);
1256  }
1257  }
1258  }
1259 
1260  if (context->debug > 0 && is_keyframe) {
1261  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "GOT KEY FRAME %d\n", context->got_key_frame);
1262  }
1263 
1264  if (context->need_decoder_reset != 0) {
1265  vpx_codec_destroy(&context->decoder);
1266  context->decoder_init = 0;
1267  status = init_decoder(codec);
1268  context->need_decoder_reset = 0;
1269  }
1270 
1271  if (status != SWITCH_STATUS_SUCCESS) goto end;
1272 
1273  if (!context->decoder_init) {
1274  status = init_decoder(codec);
1275  }
1276 
1277  if (status != SWITCH_STATUS_SUCCESS) goto end;
1278 
1279  if (!context->decoder_init) {
1280  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX decoder is not initialized!\n");
1281  return SWITCH_STATUS_FALSE;
1282  }
1283 
1284  decoder = &context->decoder;
1285 
1286  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %u mark:%d\n", frame->datalen, frame->timestamp, frame->m);
1287 
1288  // context->last_received_timestamp = frame->timestamp;
1289  context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;
1290 
1291  if (is_start) {
1292  context->got_start_frame = 1;
1293  }
1294 
1295  if (is_keyframe) {
1297  if (context->got_key_frame <= 0) {
1298  context->got_key_frame = 1;
1299  context->no_key_frame = 0;
1300  } else {
1301  context->got_key_frame++;
1302  }
1303  } else if (context->got_key_frame <= 0) {
1304  if ((--context->got_key_frame % 200) == 0) {
1305  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Waiting for key frame %d\n", context->got_key_frame);
1306  }
1307 
1308  get_refresh = 1;
1309 
1310  if (!context->got_start_frame) {
1312  }
1313  }
1314 
1315 
1316  status = context->is_vp9 ? buffer_vp9_packets(context, frame) : buffer_vp8_packets(context, frame);
1317 
1318 
1319  if (context->dec_iter && (frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter))) {
1321  }
1322 
1323  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "====READ buf:%ld got_key:%d st:%d m:%d\n", switch_buffer_inuse(context->vpx_packet_buffer), context->got_key_frame, status, frame->m);
1324 
1325  len = switch_buffer_inuse(context->vpx_packet_buffer);
1326 
1327  //if (frame->m && (status != SWITCH_STATUS_SUCCESS || !len)) {
1328  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WTF????? %d %ld\n", status, len);
1329  //}
1330 
1331  if (status == SWITCH_STATUS_SUCCESS && frame->m && len) {
1332  uint8_t *data;
1333  int corrupted = 0;
1334  vpx_codec_err_t err;
1335 
1336  switch_buffer_peek_zerocopy(context->vpx_packet_buffer, (void *)&data);
1337 
1338  context->dec_iter = NULL;
1339  err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0);
1340 
1341  if (err != VPX_CODEC_OK) {
1342  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), (context->decoded_first_frame ? SWITCH_LOG_ERROR : VPX_SWITCH_LOG_LEVEL),
1343  "VPX error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n",
1344  len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder));
1345 
1346  if (err == VPX_CODEC_MEM_ERROR) {
1347  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "VPX MEM ERROR, resetting decoder!\n");
1348  context->need_decoder_reset = 1;
1349  }
1350 
1352  } else {
1353  if (!context->decoded_first_frame) context->decoded_first_frame = 1;
1354  }
1355 
1356  if (vpx_codec_control(decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) {
1357  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "VPX control error!\n");
1359  }
1360 
1361  if (corrupted) {
1362  frame->img = NULL;
1363 #ifdef DEBUG_VP9
1365 #endif
1366  } else {
1367  frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter);
1368 
1369 #ifdef DEBUG_VP9
1370  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "decoded: %dx%d\n", frame->img->d_w, frame->img->d_h);
1371 #endif
1372  }
1373 
1374  switch_buffer_zero(context->vpx_packet_buffer);
1375 
1376  if (!frame->img) {
1377  //context->need_decoder_reset = 1;
1378  context->got_key_frame = 0;
1379  context->got_start_frame = 0;
1380  status = SWITCH_STATUS_RESTART;
1381  }
1382  }
1383 
1384 end:
1385 
1386  if (status == SWITCH_STATUS_RESTART) {
1387  switch_buffer_zero(context->vpx_packet_buffer);
1388  //context->need_decoder_reset = 1;
1389  context->got_key_frame = 0;
1390  context->got_start_frame = 0;
1391  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "RESET VPX\n");
1392  }
1393 
1394  if (!frame->img || status == SWITCH_STATUS_RESTART) {
1395  status = SWITCH_STATUS_MORE_DATA;
1396  }
1397 
1398  if (context->got_key_frame <= 0 || get_refresh) {
1400  }
1401 
1402  if (frame->img && (codec->flags & SWITCH_CODEC_FLAG_VIDEO_PATCHING)) {
1403  switch_img_free(&context->patch_img);
1404  switch_img_copy(frame->img, &context->patch_img);
1405  frame->img = context->patch_img;
1406  }
1407 
1408  return status;
1409 }
1410 
1411 
1412 static switch_status_t switch_vpx_control(switch_codec_t *codec,
1415  void *cmd_data,
1417  void *cmd_arg,
1419  void **ret_data)
1420 {
1421 
1422  vpx_context_t *context = (vpx_context_t *)codec->private_info;
1423 
1424  switch(cmd) {
1425  case SCC_VIDEO_RESET:
1426  {
1427  int mask = *((int *) cmd_data);
1428  if (mask & 1) {
1429  context->need_encoder_reset = 1;
1430  }
1431  if (mask & 2) {
1432  context->need_decoder_reset = 1;
1433  }
1434  }
1435  break;
1437  context->need_key_frame = 1;
1438  break;
1439  case SCC_VIDEO_BANDWIDTH:
1440  {
1441  switch(ctype) {
1442  case SCCT_INT:
1443  context->change_bandwidth = *((int *) cmd_data);
1444  break;
1445  case SCCT_STRING:
1446  {
1447  char *bwv = (char *) cmd_data;
1448  context->change_bandwidth = switch_parse_bandwidth_string(bwv);
1449  }
1450  break;
1451  default:
1452  break;
1453  }
1454  }
1455  break;
1456  case SCC_CODEC_SPECIFIC:
1457  {
1458  const char *command = (const char *)cmd_data;
1459 
1460  if (ctype == SCCT_INT) {
1461  } else if (ctype == SCCT_STRING && !zstr(command)) {
1462  if (!strcasecmp(command, "VP8E_SET_CPUUSED")) {
1463  vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, *(int *)cmd_arg);
1464  } else if (!strcasecmp(command, "VP8E_SET_TOKEN_PARTITIONS")) {
1465  vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, *(int *)cmd_arg);
1466  } else if (!strcasecmp(command, "VP8E_SET_NOISE_SENSITIVITY")) {
1467  vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, *(int *)cmd_arg);
1468  }
1469  }
1470 
1471  }
1472  break;
1473  case SCC_DEBUG:
1474  {
1475  int32_t level = *((uint32_t *) cmd_data);
1476  context->debug = level;
1477  }
1478  break;
1479  default:
1480  break;
1481  }
1482 
1483 
1484  return SWITCH_STATUS_SUCCESS;
1485 }
1486 
1487 
1488 static switch_status_t switch_vpx_destroy(switch_codec_t *codec)
1489 {
1490  vpx_context_t *context = (vpx_context_t *)codec->private_info;
1491 
1492  if (context) {
1493 
1494  switch_img_free(&context->patch_img);
1495 
1496  if ((codec->flags & SWITCH_CODEC_FLAG_ENCODE)) {
1497  vpx_codec_destroy(&context->encoder);
1498  }
1499 
1500  if ((codec->flags & SWITCH_CODEC_FLAG_DECODE)) {
1501  vpx_codec_destroy(&context->decoder);
1502  }
1503 
1504  if (context->pic) {
1505  vpx_img_free(context->pic);
1506  context->pic = NULL;
1507  }
1508  if (context->vpx_packet_buffer) {
1509  switch_buffer_destroy(&context->vpx_packet_buffer);
1510  context->vpx_packet_buffer = NULL;
1511  }
1512  }
1513  return SWITCH_STATUS_SUCCESS;
1514 }
1515 
1516 static void init_vp8(my_vpx_cfg_t *my_cfg)
1517 {
1518  vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &my_cfg->enc_cfg, 0);
1519 
1520  my_cfg->dec_cfg.threads = vpx_globals.dec_threads;
1521  my_cfg->enc_cfg.g_threads = vpx_globals.enc_threads;
1522  my_cfg->static_thresh = 100;
1523  my_cfg->noise_sensitivity = 1;
1524 
1525  my_cfg->cpuused = -6;
1526  my_cfg->enc_cfg.g_profile = 2;
1527  my_cfg->enc_cfg.g_timebase.num = 1;
1528  my_cfg->enc_cfg.g_timebase.den = 1000;
1529  my_cfg->enc_cfg.g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
1530  my_cfg->enc_cfg.rc_resize_allowed = 1;
1531  my_cfg->enc_cfg.rc_end_usage = VPX_CBR;
1532  my_cfg->enc_cfg.rc_target_bitrate = switch_parse_bandwidth_string("1mb");
1533  my_cfg->enc_cfg.rc_min_quantizer = 4;
1534  my_cfg->enc_cfg.rc_max_quantizer = 63;
1535  my_cfg->enc_cfg.rc_overshoot_pct = 50;
1536  my_cfg->enc_cfg.rc_buf_sz = 5000;
1537  my_cfg->enc_cfg.rc_buf_initial_sz = 1000;
1538  my_cfg->enc_cfg.rc_buf_optimal_sz = 1000;
1539  my_cfg->enc_cfg.kf_max_dist = 360;
1540 }
1541 
1542 static void init_vp9(my_vpx_cfg_t *my_cfg)
1543 {
1544  vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &my_cfg->enc_cfg, 0);
1545 
1546  my_cfg->dec_cfg.threads = vpx_globals.dec_threads;
1547  my_cfg->enc_cfg.g_threads = vpx_globals.enc_threads;
1548  my_cfg->static_thresh = 1000;
1549 
1550  my_cfg->cpuused = -8;
1551  my_cfg->enc_cfg.g_profile = 0;
1552  my_cfg->enc_cfg.g_lag_in_frames = 0;
1553  my_cfg->enc_cfg.g_timebase.den = 1000;
1554  my_cfg->enc_cfg.g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
1555  my_cfg->enc_cfg.rc_resize_allowed = 1;
1556  my_cfg->enc_cfg.rc_end_usage = VPX_CBR;
1557  my_cfg->enc_cfg.rc_target_bitrate = switch_parse_bandwidth_string("1mb");
1558  my_cfg->enc_cfg.rc_min_quantizer = 4;
1559  my_cfg->enc_cfg.rc_max_quantizer = 63;
1560  my_cfg->enc_cfg.rc_overshoot_pct = 50;
1561  my_cfg->enc_cfg.rc_buf_sz = 5000;
1562  my_cfg->enc_cfg.rc_buf_initial_sz = 1000;
1563  my_cfg->enc_cfg.rc_buf_optimal_sz = 1000;
1564  my_cfg->enc_cfg.kf_max_dist = 360;
1565  my_cfg->tune_content = VP9E_CONTENT_SCREEN;
1566 }
1567 
1568 static my_vpx_cfg_t *find_cfg_profile(const char *name, switch_bool_t reconfig)
1569 {
1570  int i;
1571 
1572  for (i = 0; i < MAX_PROFILES; i++) {
1573  if (!vpx_globals.profiles[i]) {
1574  vpx_globals.profiles[i] = malloc(sizeof(my_vpx_cfg_t));
1575  switch_assert(vpx_globals.profiles[i]);
1576  memset(vpx_globals.profiles[i], 0, sizeof(my_vpx_cfg_t));
1577  switch_set_string(vpx_globals.profiles[i]->name, name);
1578 
1579  if (!strcmp(name, "vp9")) {
1580  init_vp9(vpx_globals.profiles[i]);
1581  } else {
1582  init_vp8(vpx_globals.profiles[i]);
1583  }
1584 
1585  vpx_globals.profiles[i]->token_parts = switch_core_cpu_count() > 1 ? 3 : 0;
1586 
1587  return vpx_globals.profiles[i];
1588  }
1589 
1590  if (!strcmp(name, vpx_globals.profiles[i]->name)) {
1591  if (reconfig) {
1592  memset(vpx_globals.profiles[i], 0, sizeof(my_vpx_cfg_t));
1593  switch_set_string(vpx_globals.profiles[i]->name, name);
1594  }
1595 
1596  return vpx_globals.profiles[i];
1597  }
1598  }
1599 
1600  return NULL;
1601 }
1602 
1603 #define UINTVAL(v) (v > 0 ? v : 0);
1604 #define _VPX_CHECK_ERR(fmt, ...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX config param \"%s\" -> \"%s\" value \"%s\" " fmt "\n", profile_name, name, value, __VA_ARGS__)
1605 #define _VPX_CHECK_ERRDEF(var, fmt, ...) _VPX_CHECK_ERR(fmt ", leave default %d", __VA_ARGS__, var)
1606 #define _VPX_CHECK_ERRDEF_INVL(var) _VPX_CHECK_ERRDEF(var, "%s", "is invalid")
1607 #define _VPX_CHECK_ERRDEF_NOTAPPL(var) _VPX_CHECK_ERRDEF(var, "%s", "is not applicable")
1608 #define _VPX_CHECK_MIN(var, val, min) do { int lval = val; if (lval < (min)) _VPX_CHECK_ERRDEF(var, "is lower than %d", min); else var = lval; } while(0)
1609 #define _VPX_CHECK_MAX(var, val, max) do { int lval = val; if (lval > (max)) _VPX_CHECK_ERRDEF(var, "is larger than %d", max); else var = lval; } while(0)
1610 #define _VPX_CHECK_MIN_MAX(var, val, min, max) do { int lval = val; if ((lval < (min)) || (lval > (max))) _VPX_CHECK_ERRDEF(var, "not in [%d..%d]", min, max); else var = lval; } while(0)
1611 
1612 static void parse_profile(my_vpx_cfg_t *my_cfg, switch_xml_t profile, int codec_type)
1613 {
1614  switch_xml_t param = NULL;
1615  const char *profile_name = profile->name;
1616 
1617  vpx_codec_dec_cfg_t *dec_cfg = NULL;
1618  vpx_codec_enc_cfg_t *enc_cfg = NULL;
1619 
1620  dec_cfg = &my_cfg->dec_cfg;
1621  enc_cfg = &my_cfg->enc_cfg;
1622 
1623  for (param = switch_xml_child(profile, "param"); param; param = param->next) {
1624  const char *name = switch_xml_attr(param, "name");
1625  const char *value = switch_xml_attr(param, "value");
1626  int val;
1627 
1628  if (!enc_cfg || !dec_cfg) break;
1629  if (zstr(name) || zstr(value)) continue;
1630 
1631  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: %s = %s\n", my_cfg->name, name, value);
1632 
1633  val = atoi(value);
1634 
1635  if (!strcmp(name, "dec-threads")) {
1636  _VPX_CHECK_MIN(dec_cfg->threads, switch_parse_cpu_string(value), 1);
1637  } else if (!strcmp(name, "enc-threads")) {
1638  _VPX_CHECK_MIN(enc_cfg->g_threads, switch_parse_cpu_string(value), 1);
1639  } else if (!strcmp(name, "g-profile")) {
1640  _VPX_CHECK_MIN_MAX(enc_cfg->g_profile, val, 0, 3);
1641 #if 0
1642  } else if (!strcmp(name, "g-timebase")) {
1643  int num = 0;
1644  int den = 0;
1645  char *slash = strchr(value, '/');
1646 
1647  num = UINTVAL(val);
1648 
1649  if (slash) {
1650  slash++;
1651  den = atoi(slash);
1652 
1653  if (den < 0) den = 0;
1654  }
1655 
1656  if (num && den) {
1657  enc_cfg->g_timebase.num = num;
1658  enc_cfg->g_timebase.den = den;
1659  }
1660 #endif
1661  } else if (!strcmp(name, "g-error-resilient")) {
1662  char *s = strdup(value);
1663  if (s) {
1664  vpx_codec_er_flags_t res = 0;
1665  int argc;
1666  char *argv[10];
1667  int i;
1668 
1669  argc = switch_separate_string(s, '|', argv, (sizeof(argv) / sizeof(argv[0])));
1670  for (i = 0; i < argc; i++) {
1671  if (!strcasecmp(argv[i], "DEFAULT")) {
1672  res |= VPX_ERROR_RESILIENT_DEFAULT;
1673  } else if (!strcasecmp(argv[i], "PARTITIONS")) {
1674  res |= VPX_ERROR_RESILIENT_PARTITIONS;
1675  } else {
1676  _VPX_CHECK_ERR("has invalid token \"%s\"", argv[i]);
1677  }
1678  }
1679 
1680  free(s);
1681  enc_cfg->g_error_resilient = res;
1682  }
1683  } else if (!strcmp(name, "g-pass")) {
1684  if (!strcasecmp(value, "ONE_PASS")) {
1685  enc_cfg->g_pass = VPX_RC_ONE_PASS;
1686  } else if (!strcasecmp(value, "FIRST_PASS")) {
1687  enc_cfg->g_pass = VPX_RC_FIRST_PASS;
1688  } else if (!strcasecmp(value, "LAST_PASS")) {
1689  enc_cfg->g_pass = VPX_RC_FIRST_PASS;
1690  } else {
1691  _VPX_CHECK_ERRDEF_INVL(enc_cfg->g_pass);
1692  }
1693  } else if (!strcmp(name, "g-lag-in-frames")) {
1694  _VPX_CHECK_MIN_MAX(enc_cfg->g_lag_in_frames, val, 0, 25);
1695  } else if (!strcmp(name, "rc_dropframe_thresh")) {
1696  _VPX_CHECK_MIN_MAX(enc_cfg->rc_dropframe_thresh, val, 0, 100);
1697  } else if (!strcmp(name, "rc-resize-allowed")) {
1698  _VPX_CHECK_MIN_MAX(enc_cfg->rc_resize_allowed, val, 0, 1);
1699  } else if (!strcmp(name, "rc-scaled-width")) {
1700  _VPX_CHECK_MIN(enc_cfg->rc_scaled_width, val, 0);
1701  } else if (!strcmp(name, "rc-scaled-height")) {
1702  _VPX_CHECK_MIN(enc_cfg->rc_scaled_height, val, 0);
1703  } else if (!strcmp(name, "rc-resize-up-thresh")) {
1704  _VPX_CHECK_MIN_MAX(enc_cfg->rc_resize_up_thresh, val, 0, 100);
1705  } else if (!strcmp(name, "rc-resize-down-thresh")) {
1706  _VPX_CHECK_MIN_MAX(enc_cfg->rc_resize_down_thresh, val, 0, 100);
1707  } else if (!strcmp(name, "rc-end-usage")) {
1708  if (!strcasecmp(value, "VBR")) {
1709  enc_cfg->rc_end_usage = VPX_VBR;
1710  } else if (!strcasecmp(value, "CBR")) {
1711  enc_cfg->rc_end_usage = VPX_CBR;
1712  } else if (!strcasecmp(value, "CQ")) {
1713  enc_cfg->rc_end_usage = VPX_CQ;
1714  } else if (!strcasecmp(value, "Q")) {
1715  enc_cfg->rc_end_usage = VPX_Q;
1716  } else {
1717  _VPX_CHECK_ERRDEF_INVL(enc_cfg->rc_end_usage);
1718  }
1719  } else if (!strcmp(name, "rc-target-bitrate")) {
1720  _VPX_CHECK_MIN(enc_cfg->rc_target_bitrate, switch_parse_bandwidth_string(value), 1);
1721  } else if (!strcmp(name, "rc-min-quantizer")) {
1722  _VPX_CHECK_MIN_MAX(enc_cfg->rc_min_quantizer, val, 0, 63);
1723  } else if (!strcmp(name, "rc-max-quantizer")) {
1724  _VPX_CHECK_MIN_MAX(enc_cfg->rc_max_quantizer, val, 0, 63);
1725  } else if (!strcmp(name, "rc-undershoot-pct")) {
1726  if (codec_type == CODEC_TYPE_VP9) {
1727  _VPX_CHECK_MIN_MAX(enc_cfg->rc_undershoot_pct, val, 0, 100);
1728  } else {
1729  _VPX_CHECK_MIN_MAX(enc_cfg->rc_undershoot_pct, val, 0, 1000);
1730  }
1731  } else if (!strcmp(name, "rc-overshoot-pct")) {
1732  if (codec_type == CODEC_TYPE_VP9) {
1733  _VPX_CHECK_MIN_MAX(enc_cfg->rc_overshoot_pct, val, 0, 100);
1734  } else {
1735  _VPX_CHECK_MIN_MAX(enc_cfg->rc_overshoot_pct, val, 0, 1000);
1736  }
1737  } else if (!strcmp(name, "rc-buf-sz")) {
1738  _VPX_CHECK_MIN(enc_cfg->rc_buf_sz, val, 1);
1739  } else if (!strcmp(name, "rc-buf-initial-sz")) {
1740  _VPX_CHECK_MIN(enc_cfg->rc_buf_initial_sz, val, 1);
1741  } else if (!strcmp(name, "rc-buf-optimal-sz")) {
1742  _VPX_CHECK_MIN(enc_cfg->rc_buf_optimal_sz, val, 1);
1743  } else if (!strcmp(name, "rc-2pass-vbr-bias-pct")) {
1744  _VPX_CHECK_MIN_MAX(enc_cfg->rc_2pass_vbr_bias_pct, val, 0, 100);
1745  } else if (!strcmp(name, "rc-2pass-vbr-minsection-pct")) {
1746  _VPX_CHECK_MIN(enc_cfg->rc_2pass_vbr_minsection_pct, val, 1);
1747  } else if (!strcmp(name, "rc-2pass-vbr-maxsection-pct")) {
1748  _VPX_CHECK_MIN(enc_cfg->rc_2pass_vbr_maxsection_pct, val, 1);
1749  } else if (!strcmp(name, "kf-mode")) {
1750  if (!strcasecmp(value, "AUTO")) {
1751  enc_cfg->kf_mode = VPX_KF_AUTO;
1752  } else if (!strcasecmp(value, "DISABLED")) {
1753  enc_cfg->kf_mode = VPX_KF_DISABLED;
1754  } else {
1755  _VPX_CHECK_ERRDEF_INVL(enc_cfg->kf_mode);
1756  }
1757  } else if (!strcmp(name, "kf-min-dist")) {
1758  _VPX_CHECK_MIN(enc_cfg->kf_min_dist, val, 0);
1759  } else if (!strcmp(name, "kf-max-dist")) {
1760  _VPX_CHECK_MIN(enc_cfg->kf_max_dist, val, 0);
1761  } else if (!strcmp(name, "ss-number-layers")) {
1762  _VPX_CHECK_MIN_MAX(enc_cfg->ss_number_layers, val, 0, VPX_SS_MAX_LAYERS);
1763  } else if (!strcmp(name, "ts-number-layers")) {
1764  if (codec_type == CODEC_TYPE_VP8) {
1765  _VPX_CHECK_MIN_MAX(enc_cfg->ts_number_layers, val, 0, VPX_SS_MAX_LAYERS);
1766  } else if (codec_type == CODEC_TYPE_VP9) {
1767  _VPX_CHECK_MIN_MAX(enc_cfg->ts_number_layers, val, enc_cfg->ts_number_layers, enc_cfg->ts_number_layers); // lock it
1768  } else {
1769  _VPX_CHECK_ERRDEF_NOTAPPL(enc_cfg->ts_number_layers);
1770  }
1771  } else if (!strcmp(name, "ts-periodicity")) {
1772  if (codec_type == CODEC_TYPE_VP9) {
1773  _VPX_CHECK_MIN_MAX(enc_cfg->ts_periodicity, val, enc_cfg->ts_periodicity, enc_cfg->ts_periodicity); // lock it
1774  } else {
1775  _VPX_CHECK_MIN_MAX(enc_cfg->ts_periodicity, val, 0, 16);
1776  }
1777  } else if (!strcmp(name, "temporal-layering-mode")) {
1778  if (codec_type == CODEC_TYPE_VP9) {
1779  _VPX_CHECK_MIN_MAX(enc_cfg->temporal_layering_mode, val, enc_cfg->temporal_layering_mode, enc_cfg->temporal_layering_mode); // lock it
1780  } else {
1781  _VPX_CHECK_MIN_MAX(enc_cfg->temporal_layering_mode, val, 0, 3);
1782  }
1783  } else if (!strcmp(name, "lossless")) {
1784  if (codec_type == CODEC_TYPE_VP9) {
1785  _VPX_CHECK_MIN_MAX(my_cfg->lossless, val, 0, 1);
1786  } else {
1787  _VPX_CHECK_ERRDEF_NOTAPPL(my_cfg->lossless);
1788  }
1789  } else if (!strcmp(name, "cpuused")) {
1790  if (codec_type == CODEC_TYPE_VP8) {
1791  _VPX_CHECK_MIN_MAX(my_cfg->cpuused, val, -16, 16);
1792  } else {
1793  _VPX_CHECK_MIN_MAX(my_cfg->cpuused, val, -8, 8);
1794  }
1795  } else if (!strcmp(name, "token-parts")) {
1796  _VPX_CHECK_MIN_MAX(my_cfg->token_parts, switch_parse_cpu_string(value), VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION);
1797  } else if (!strcmp(name, "static-thresh")) {
1798  _VPX_CHECK_MIN(my_cfg->static_thresh, val, 0);
1799  } else if (!strcmp(name, "noise-sensitivity")) {
1800  if (codec_type == CODEC_TYPE_VP8) {
1801  _VPX_CHECK_MIN_MAX(my_cfg->noise_sensitivity, val, 0, 6);
1802  } else {
1803  _VPX_CHECK_ERRDEF_NOTAPPL(my_cfg->noise_sensitivity);
1804  }
1805  } else if (!strcmp(name, "max-intra-bitrate-pct")) {
1806  if (codec_type == CODEC_TYPE_VP8) {
1807  _VPX_CHECK_MIN(my_cfg->max_intra_bitrate_pct, val, 0);
1808  } else {
1809  _VPX_CHECK_ERRDEF_NOTAPPL(my_cfg->max_intra_bitrate_pct);
1810  }
1811  } else if (!strcmp(name, "vp9e-tune-content")) {
1812  if (codec_type == CODEC_TYPE_VP9) {
1813  if (!strcasecmp(value, "DEFAULT")) {
1814  my_cfg->tune_content = VP9E_CONTENT_DEFAULT;
1815  } else if (!strcasecmp(value, "SCREEN")) {
1816  my_cfg->tune_content = VP9E_CONTENT_SCREEN;
1817  } else {
1818  _VPX_CHECK_ERRDEF_INVL(my_cfg->tune_content);
1819  }
1820  } else {
1821  _VPX_CHECK_ERRDEF_NOTAPPL(my_cfg->tune_content);
1822  }
1823  }
1824  } // for param
1825 }
1826 
1827 static void parse_codecs(my_vpx_cfg_t *my_cfg, switch_xml_t codecs)
1828 {
1829  switch_xml_t codec = NULL;
1830 
1831  if (!codecs) {
1832  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no codecs in %s\n", my_cfg->name);
1833  return;
1834  }
1835 
1836  codec = switch_xml_child(codecs, "codec");
1837 
1838  if (my_cfg->codecs) {
1839  switch_event_destroy(&my_cfg->codecs);
1840  }
1841 
1842  switch_event_create(&my_cfg->codecs, SWITCH_EVENT_CLONE);
1843 
1844  for (; codec; codec = codec->next) {
1845  const char *name = switch_xml_attr(codec, "name");
1846  const char *profile = switch_xml_attr(codec, "profile");
1847 
1848  if (zstr(name) || zstr(profile)) continue;
1849 
1850  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec: %s, profile: %s\n", name, profile);
1851 
1852  switch_event_add_header_string(my_cfg->codecs, SWITCH_STACK_BOTTOM, name, profile);
1853  }
1854 }
1855 
1856 static void load_config(void)
1857 {
1858  switch_xml_t cfg = NULL, xml = NULL;
1859  my_vpx_cfg_t *my_cfg = NULL;
1860 
1861  memset(&vpx_globals, 0, sizeof(vpx_globals));
1862 
1863  vpx_globals.max_bitrate = switch_calc_bitrate(1920, 1080, 5, 60);
1864  vpx_globals.rtp_slice_size = SLICE_SIZE;
1865  vpx_globals.key_frame_min_freq = KEY_FRAME_MIN_FREQ;
1866 
1867  xml = switch_xml_open_cfg("vpx.conf", &cfg, NULL);
1868 
1869  if (xml) {
1870  switch_xml_t settings = switch_xml_child(cfg, "settings");
1871  switch_xml_t profiles = switch_xml_child(cfg, "profiles");
1872 
1873  if (settings) {
1874  switch_xml_t param;
1875 
1876  for (param = switch_xml_child(settings, "param"); param; param = param->next) {
1877  const char *profile_name = "settings"; // for _VPX_CHECK_*() macroses only
1878  const char *name = switch_xml_attr(param, "name");
1879  const char *value = switch_xml_attr(param, "value");
1880 
1881  if (zstr(name) || zstr(value)) continue;
1882 
1883  if (!strcmp(name, "debug")) {
1884  vpx_globals.debug = atoi(value);
1885  } else if (!strcmp(name, "max-bitrate")) {
1886  _VPX_CHECK_MIN(vpx_globals.max_bitrate, switch_parse_bandwidth_string(value), 1);
1887  } else if (!strcmp(name, "rtp-slice-size")) {
1888  _VPX_CHECK_MIN_MAX(vpx_globals.rtp_slice_size, atoi(value), 500, 1500);
1889  } else if (!strcmp(name, "key-frame-min-freq")) {
1890  _VPX_CHECK_MIN_MAX(vpx_globals.key_frame_min_freq, atoi(value) * 1000, 10 * 1000, 3000 * 1000);
1891  } else if (!strcmp(name, "dec-threads")) {
1892  int val = switch_parse_cpu_string(value);
1893  _VPX_CHECK_MIN(vpx_globals.dec_threads, val, 1);
1894  } else if (!strcmp(name, "enc-threads")) {
1895  int val = switch_parse_cpu_string(value);
1896  _VPX_CHECK_MIN(vpx_globals.enc_threads, val, 1);
1897  }
1898  }
1899  }
1900 
1901  if (profiles) {
1902  switch_xml_t profile = switch_xml_child(profiles, "profile");
1903 
1904  for (; profile; profile = profile->next) {
1905  switch_xml_t codecs = switch_xml_child(profile, "codecs");
1906  const char *profile_name = switch_xml_attr(profile, "name");
1907  my_vpx_cfg_t *my_cfg = NULL;
1908 
1909  if (zstr(profile_name)) continue;
1910 
1911  my_cfg = find_cfg_profile(profile_name, SWITCH_TRUE);
1912 
1913  if (!my_cfg) continue;
1914 
1915  parse_profile(my_cfg, profile, CODEC_TYPE(profile_name));
1916  parse_codecs(my_cfg, codecs);
1917  } // for profile
1918  } // profiles
1919 
1920  switch_xml_free(xml);
1921  } // xml
1922 
1923  if (vpx_globals.max_bitrate <= 0) {
1924  vpx_globals.max_bitrate = switch_calc_bitrate(1920, 1080, 5, 60);
1925  }
1926 
1927  if (vpx_globals.rtp_slice_size < 500 || vpx_globals.rtp_slice_size > 1500) {
1928  vpx_globals.rtp_slice_size = SLICE_SIZE;
1929  }
1930 
1931  if (vpx_globals.key_frame_min_freq < 10000 || vpx_globals.key_frame_min_freq > 3 * 1000000) {
1932  vpx_globals.key_frame_min_freq = KEY_FRAME_MIN_FREQ;
1933  }
1934 
1935  my_cfg = find_cfg_profile("vp8", SWITCH_FALSE);
1936 
1937  if (my_cfg) {
1938  if (!my_cfg->enc_cfg.g_threads) my_cfg->enc_cfg.g_threads = 1;
1939  if (!my_cfg->dec_cfg.threads) my_cfg->dec_cfg.threads = switch_parse_cpu_string("cpu/2/4");
1940  }
1941 
1942  my_cfg = find_cfg_profile("vp9", SWITCH_FALSE);
1943 
1944  if (my_cfg) {
1945  if (!my_cfg->enc_cfg.g_threads) my_cfg->enc_cfg.g_threads = 1;
1946  if (!my_cfg->dec_cfg.threads) my_cfg->dec_cfg.threads = switch_parse_cpu_string("cpu/2/4");
1947  }
1948 }
1949 
1950 #define VPX_API_SYNTAX "<reload|debug <on|off>>"
1951 SWITCH_STANDARD_API(vpx_api_function)
1952 {
1953  if (session) {
1954  return SWITCH_STATUS_FALSE;
1955  }
1956 
1957  if (zstr(cmd)) {
1958  goto usage;
1959  }
1960 
1961  if (!strcasecmp(cmd, "reload")) {
1962  const char *err;
1963  my_vpx_cfg_t *my_cfg;
1964  int i;
1965 
1966  switch_xml_reload(&err);
1967  stream->write_function(stream, "Reload XML [%s]\n", err);
1968 
1969  load_config();
1970 
1971  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " %-26s = %d\n", "rtp-slice-size", vpx_globals.rtp_slice_size);
1972  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " %-26s = %d\n", "key-frame-min-freq", vpx_globals.key_frame_min_freq);
1973 
1974  for (i = 0; i < MAX_PROFILES; i++) {
1975  my_cfg = vpx_globals.profiles[i];
1976 
1977  if (!my_cfg) break;
1978 
1979  if (!strcmp(my_cfg->name, "vp8")) {
1980  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Codec: %s\n", vpx_codec_iface_name(vpx_codec_vp8_cx()));
1981  } else if (!strcmp(my_cfg->name, "vp9")) {
1982  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Codec: %s\n", vpx_codec_iface_name(vpx_codec_vp9_cx()));
1983  } else {
1984  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Codec: %s\n", my_cfg->name);
1985  }
1986 
1987  show_config(my_cfg, &my_cfg->enc_cfg);
1988  }
1989 
1990  stream->write_function(stream, "+OK\n");
1991  } else if (!strcasecmp(cmd, "debug")) {
1992  stream->write_function(stream, "+OK debug %s\n", vpx_globals.debug ? "on" : "off");
1993  } else if (!strcasecmp(cmd, "debug on")) {
1994  vpx_globals.debug = 1;
1995  stream->write_function(stream, "+OK debug on\n");
1996  } else if (!strcasecmp(cmd, "debug off")) {
1997  vpx_globals.debug = 0;
1998  stream->write_function(stream, "+OK debug off\n");
1999  }
2000 
2001  return SWITCH_STATUS_SUCCESS;
2002 
2003  usage:
2004  stream->write_function(stream, "USAGE: %s\n", VPX_API_SYNTAX);
2005  return SWITCH_STATUS_SUCCESS;
2006 }
2007 
2008 SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load)
2009 {
2010  switch_codec_interface_t *codec_interface;
2011  switch_api_interface_t *vpx_api_interface;
2012 
2013  memset(&vpx_globals, 0, sizeof(struct vpx_globals));
2014  load_config();
2015 
2016  /* connect my internal structure to the blank pointer passed to me */
2017  *module_interface = switch_loadable_module_create_module_interface(pool, modname);
2018 
2019  SWITCH_ADD_CODEC(codec_interface, "VP8 Video");
2020  switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP8", NULL,
2021  switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
2022  SWITCH_ADD_CODEC(codec_interface, "VP9 Video");
2023  switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP9", NULL,
2024  switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
2025 
2026  SWITCH_ADD_API(vpx_api_interface, "vpx",
2027  "VPX API", vpx_api_function, VPX_API_SYNTAX);
2028 
2029  switch_console_set_complete("add vpx reload");
2030  switch_console_set_complete("add vpx debug");
2031  switch_console_set_complete("add vpx debug on");
2032  switch_console_set_complete("add vpx debug off");
2033 
2034  /* indicate that the module should continue to be loaded */
2035  return SWITCH_STATUS_SUCCESS;
2036 }
2037 
2038 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vpx_shutdown)
2039 {
2040  int i;
2041 
2042  for (i = 0; i < MAX_PROFILES; i++) {
2043  my_vpx_cfg_t *my_cfg = vpx_globals.profiles[i];
2044 
2045  if (!my_cfg) break;
2046 
2047  if (my_cfg->codecs) {
2048  switch_event_destroy(&my_cfg->codecs);
2049  }
2050 
2051  free(my_cfg);
2052  }
2053 
2054  return SWITCH_STATUS_SUCCESS;
2055 }
2056 #endif
2057 #endif
2058 /* For Emacs:
2059  * Local Variables:
2060  * mode:c
2061  * indent-tabs-mode:t
2062  * tab-width:4
2063  * c-basic-offset:4
2064  * End:
2065  * For VIM:
2066  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
2067  */
switch_core_session_t * session
switch_time_t switch_micro_time_now(void)
Get the current epoch time in microseconds.
Definition: switch_time.c:311
switch_status_t switch_console_set_complete(const char *string)
void switch_xml_free(_In_opt_ switch_xml_t xml)
frees the memory allocated for an switch_xml structure
switch_bool_t m
Definition: switch_frame.h:83
#define VPX_IMAGE_ABI_VERSION
Current ABI version number.
Definition: switch_image.h:30
void vpx_img_free(vpx_image_t *img)
Close an image descriptor.
char * name
Definition: switch_xml.h:81
#define SWITCH_CHANNEL_SESSION_LOG(x)
Image Descriptor.
Definition: switch_image.h:88
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
Definition: switch_utils.h:700
#define SWITCH_CHANNEL_LOG
switch_size_t switch_buffer_read(_In_ switch_buffer_t *buffer, _In_ void *data, _In_ switch_size_t datalen)
Read data from a switch_buffer_t up to the ammount of datalen if it is available. Remove read data fr...
const char * switch_xml_attr(_In_opt_ switch_xml_t xml, _In_opt_z_ const char *attr)
returns the value of the requested tag attribute, or NULL if not found
void switch_img_free(switch_image_t **img)
Close an image descriptor.
static switch_status_t load_config(void)
Definition: switch_msrp.c:190
switch_status_t switch_buffer_create_dynamic(_Out_ switch_buffer_t **buffer, _In_ switch_size_t blocksize, _In_ switch_size_t start_len, _In_ switch_size_t max_len)
Allocate a new dynamic switch_buffer.
switch_bool_t
Definition: switch_types.h:437
uint32_t timestamp
Definition: switch_frame.h:80
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:733
switch_memory_pool_t * pool
Representation of an event.
Definition: switch_event.h:80
An event Header.
Definition: switch_event.h:65
const char *const const char *const const cJSON *const value
A representation of an XML tree.
Definition: switch_xml.h:79
uint32_t switch_core_cpu_count(void)
Definition: switch_core.c:1055
#define SWITCH_MODULE_SHUTDOWN_FUNCTION(name)
switch_status_t switch_xml_reload(const char **err)
Definition: switch_xml.c:2436
char const int const cJSON_bool format
Definition: switch_cJSON.h:153
static int32_t switch_calc_bitrate(int w, int h, float quality, double fps)
uint32_t ssrc
Definition: switch_frame.h:82
switch_size_t switch_buffer_write(_In_ switch_buffer_t *buffer, _In_bytecount_(datalen) const void *data, _In_ switch_size_t datalen)
Write data into a switch_buffer_t up to the length of datalen.
static int32_t switch_parse_bandwidth_string(const char *bwv)
static uint32_t switch_parse_cpu_string(const char *cpu)
#define zstr(x)
Definition: switch_utils.h:314
uint32_t switch_codec_flag_t
switch_status_t switch_buffer_create_partition(switch_memory_pool_t *pool, switch_buffer_t **buffer, void *data, switch_size_t datalen)
Definition: switch_buffer.c:85
unsigned int d_w
Definition: switch_image.h:99
switch_codec_control_command_t
#define SWITCH_SSIZE_T_FMT
static const char usage[]
Definition: switch.c:419
uint16_t seq
Definition: switch_frame.h:81
switch_codec_control_type_t
int64_t switch_time_t
Definition: switch_apr.h:188
const switch_codec_implementation_t * implementation
switch_xml_t next
Definition: switch_xml.h:91
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
unsigned int switch_separate_string(_In_ char *buf, char delim, _Post_count_(return) char **array, unsigned int arraylen)
Separate a string into an array based on a character delimiter.
A module interface to implement an api function.
uint32_t datalen
Definition: switch_frame.h:68
switch_frame_flag_t flags
Definition: switch_frame.h:85
#define SWITCH_STANDARD_API(name)
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:684
switch_memory_pool_t * memory_pool
switch_status_t switch_event_add_header_string(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *data)
Add a string header to an event.
void switch_img_copy(switch_image_t *img, switch_image_t **new_img)
Copy image to a new image.
Top level module interface to implement a series of codec implementations.
void switch_buffer_zero(_In_ switch_buffer_t *buffer)
Remove all data from the buffer.
#define SWITCH_CHANNEL_LOG_CLEAN
An abstraction of a data frame.
Definition: switch_frame.h:54
uintptr_t switch_size_t
#define SWITCH_MODULE_LOAD_FUNCTION(name)
#define SWITCH_ADD_CODEC(codec_int, int_name)
unsigned int h
Definition: switch_image.h:95
switch_image_t * img
Definition: switch_frame.h:88
#define SWITCH_SIZE_T_FMT
switch_status_t
Common return values.
static void switch_core_codec_add_video_implementation(switch_memory_pool_t *pool, switch_codec_interface_t *codec_interface, switch_payload_t ianacode, const char *iananame, char *fmtp, switch_core_codec_init_func_t init, switch_core_codec_video_encode_func_t encode, switch_core_codec_video_decode_func_t decode, switch_core_codec_control_func_t control, switch_core_codec_destroy_func_t destroy)
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:287
struct switch_event_header * next
Definition: switch_event.h:76
switch_xml_t switch_xml_open_cfg(_In_z_ const char *file_path, _Out_ switch_xml_t *node, _In_opt_ switch_event_t *params)
open a config in the core registry
switch_loadable_module_interface_t * switch_loadable_module_create_module_interface(switch_memory_pool_t *pool, const char *name)
switch_size_t switch_buffer_peek_zerocopy(_In_ switch_buffer_t *buffer, _Out_ const void **ptr)
Main Library Header.
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:384
#define SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
switch_xml_t switch_xml_child(_In_ switch_xml_t xml, _In_z_ const char *name)
returns the first child tag (one level deeper) with the given name or NULL \ if not found ...
#define SWITCH_ADD_API(api_int, int_name, descript, funcptr, syntax_string)
#define switch_set_string(_dst, _src)
Definition: switch_utils.h:734
char * key
Definition: switch_msrp.c:64
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.
int debug
Definition: switch_msrp.c:57
struct fspr_pool_t switch_memory_pool_t
const char *const name
Definition: switch_cJSON.h:250
void switch_event_destroy(switch_event_t **event)
Destroy an event.
unsigned int d_h
Definition: switch_image.h:100
#define switch_assert(expr)
switch_status_t switch_buffer_set_partition_data(switch_buffer_t *buffer, void *data, switch_size_t datalen)
Definition: switch_buffer.c:74
switch_time_t switch_time_now(void)
Definition: switch_apr.c:325
unsigned int w
Definition: switch_image.h:94
switch_size_t switch_buffer_inuse(_In_ switch_buffer_t *buffer)
Get the in use amount of a switch_buffer_t.
void switch_buffer_destroy(switch_buffer_t **buffer)
Destroy the buffer.
memset(buf, 0, buflen)