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>
45 #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE
46 #define KEY_FRAME_MIN_FREQ 250000
89 #pragma pack(push, r1, 1)
92 #if SWITCH_BYTE_ORDER == __BIG_ENDIAN
97 unsigned non_referenced:1;
101 } vp8_payload_descriptor_t;
105 unsigned have_p_layer:1;
106 unsigned have_layer_ind:1;
107 unsigned is_flexible:1;
112 } vp9_payload_descriptor_t;
129 unsigned temporal_id:3;
130 unsigned temporal_up_switch:1;
131 unsigned spatial_id:3;
132 unsigned inter_layer_predicted:1;
139 unsigned reserved2:1;
141 unsigned non_referenced:1;
142 unsigned reserved1:1;
144 } vp8_payload_descriptor_t;
151 unsigned is_flexible:1;
152 unsigned have_layer_ind:1;
153 unsigned have_p_layer:1;
155 } vp9_payload_descriptor_t;
172 unsigned inter_layer_predicted:1;
173 unsigned spatial_id:3;
174 unsigned temporal_up_switch:1;
175 unsigned temporal_id:3;
181 vp8_payload_descriptor_t vp8;
182 vp9_payload_descriptor_t vp9;
183 } vpx_payload_descriptor_t;
185 #define kMaxVp9NumberOfSpatialLayers 16
189 uint8_t picture_id_sli;
191 uint64_t picture_id_rpsi;
200 uint8_t temporal_idx;
208 size_t num_spatial_layers;
210 uint16_t width[kMaxVp9NumberOfSpatialLayers];
211 uint16_t height[kMaxVp9NumberOfSpatialLayers];
217 #pragma pack(pop, r1)
221 #define __IS_VP8_KEY_FRAME(byte) !(((byte) & 0x01))
222 static inline int IS_VP8_KEY_FRAME(uint8_t *data)
237 uint8_t M = (*data) & 0x80;
241 if (X & 0x40) data++;
242 if (X & 0x30) data++;
245 if (S && (PID == 0)) {
246 return __IS_VP8_KEY_FRAME(*data);
253 #define IS_VP9_KEY_FRAME(byte) ((((byte) & 0x40) == 0) && ((byte) & 0x0A))
254 #define IS_VP9_START_PKT(byte) ((byte) & 0x08)
264 vpx_codec_iface_t *encoder_interface;
265 vpx_codec_iface_t *decoder_interface;
268 unsigned int bandwidth;
269 vpx_codec_enc_cfg_t config;
272 vpx_codec_ctx_t encoder;
273 uint8_t encoder_init;
281 const vpx_codec_cx_pkt_t *pkt;
282 vpx_codec_iter_t enc_iter;
283 vpx_codec_iter_t dec_iter;
286 vpx_codec_ctx_t decoder;
287 uint8_t decoder_init;
292 uint32_t last_received_timestamp;
295 int need_encoder_reset;
296 int need_decoder_reset;
297 int32_t change_bandwidth;
303 typedef struct vpx_context vpx_context_t;
308 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
309 vpx_codec_dec_cfg_t cfg = {0, 0, 0};
310 vpx_codec_flags_t dec_flags = 0;
313 vp8_postproc_cfg_t ppcfg;
322 if (!context->is_vp9) {
326 if (vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags) != VPX_CODEC_OK) {
332 context->last_ts = 0;
333 context->last_received_timestamp = 0;
334 context->last_received_complete_picture = 0;
335 context->decoder_init = 1;
336 context->got_key_frame = 0;
337 context->no_key_frame = 0;
338 context->got_start_frame = 0;
340 ppcfg.post_proc_flag = VP8_DEBLOCK;
342 ppcfg.deblocking_level = 1;
344 vpx_codec_control(&context->decoder, VP8_SET_POSTPROC, &ppcfg);
346 if (context->vpx_packet_buffer) {
359 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
360 vpx_codec_enc_cfg_t *config = &context->config;
365 if (!context->codec_settings.video.width) {
366 context->codec_settings.video.width = 1280;
369 if (!context->codec_settings.video.height) {
370 context->codec_settings.video.height = 720;
373 if (context->codec_settings.video.bandwidth == -1) {
374 context->codec_settings.video.bandwidth = 0;
377 if (context->codec_settings.video.bandwidth) {
378 context->bandwidth = context->codec_settings.video.bandwidth;
380 context->bandwidth =
switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 15);
386 if (context->bandwidth > sane) {
388 context->bandwidth = sane;
394 "VPX reset encoder picture from %dx%d to %dx%d %u BW\n",
395 config->g_w, config->g_h, context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth);
399 config->g_timebase.num = 1;
400 config->g_timebase.den = 1000;
401 config->g_pass = VPX_RC_ONE_PASS;
402 config->g_w = context->codec_settings.video.width;
403 config->g_h = context->codec_settings.video.height;
404 config->rc_target_bitrate = context->bandwidth;
405 config->g_lag_in_frames = 0;
406 config->kf_max_dist = 2000;
407 config->g_threads = 1;
409 if (context->is_vp9) {
411 token_parts = (cpus > 1) ? 3 : 0;
413 if (context->lossless) {
414 config->rc_min_quantizer = 0;
415 config->rc_max_quantizer = 0;
417 config->rc_min_quantizer = 0;
418 config->rc_max_quantizer = 63;
421 config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING;
422 config->ts_number_layers = 1;
423 config->ts_rate_decimator[0] = 1;
424 config->ts_periodicity = 1;
425 config->ts_layer_id[0] = 0;
429 config->g_profile = 2;
430 config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
431 token_parts = (cpus > 1) ? 3 : 0;
434 config->rc_dropframe_thresh = 0;
435 config->rc_end_usage = VPX_CBR;
437 config->kf_mode = VPX_KF_AUTO;
438 config->kf_max_dist = 1000;
441 config->rc_resize_allowed = 1;
444 config->rc_min_quantizer = 0;
445 config->rc_max_quantizer = 63;
453 config->rc_undershoot_pct = 100;
461 config->rc_overshoot_pct = 15;
469 config->rc_buf_sz = 5000;
476 config->rc_buf_initial_sz = 1000;
483 config->rc_buf_optimal_sz = 1000;
486 if (context->encoder_init) {
488 if (vpx_codec_enc_config_set(&context->encoder, config) != VPX_CODEC_OK) {
496 fprintf(stderr,
"Codec: %s\n", vpx_codec_iface_name(context->encoder_interface));
504 SHOW(g_input_bit_depth);
505 SHOW(g_timebase.num);
506 SHOW(g_timebase.den);
507 SHOW(g_error_resilient);
509 SHOW(g_lag_in_frames);
510 SHOW(rc_dropframe_thresh);
511 SHOW(rc_resize_allowed);
512 SHOW(rc_scaled_width);
513 SHOW(rc_scaled_height);
514 SHOW(rc_resize_up_thresh);
515 SHOW(rc_resize_down_thresh);
517 SHOW(rc_target_bitrate);
518 SHOW(rc_min_quantizer);
519 SHOW(rc_max_quantizer);
520 SHOW(rc_undershoot_pct);
521 SHOW(rc_overshoot_pct);
523 SHOW(rc_buf_initial_sz);
524 SHOW(rc_buf_optimal_sz);
525 SHOW(rc_2pass_vbr_bias_pct);
526 SHOW(rc_2pass_vbr_minsection_pct);
527 SHOW(rc_2pass_vbr_maxsection_pct);
533 if (vpx_codec_enc_init(&context->encoder, context->encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION) != VPX_CODEC_OK) {
538 context->encoder_init = 1;
540 if (context->is_vp9) {
541 if (context->lossless) {
542 vpx_codec_control(&context->encoder, VP9E_SET_LOSSLESS, 1);
543 vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -6);
545 vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -8);
548 vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, 100);
549 vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, token_parts);
550 vpx_codec_control(&context->encoder, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN);
554 vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, 100);
556 vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -6);
557 vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, token_parts);
560 vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, 1);
576 vpx_context_t *context = NULL;
577 int encoding, decoding;
586 memset(context, 0,
sizeof(*context));
587 context->flags = flags;
591 if (codec_settings) {
592 context->codec_settings = *codec_settings;
597 context->encoder_interface = vpx_codec_vp9_cx();
598 context->decoder_interface = vpx_codec_vp9_dx();
600 context->encoder_interface = vpx_codec_vp8_cx();
601 context->decoder_interface = vpx_codec_vp8_dx();
608 if (vpx_codec_enc_config_default(context->encoder_interface, &context->config, 0) != VPX_CODEC_OK) {
613 context->codec_settings.video.width = 320;
614 context->codec_settings.video.height = 240;
624 vpx_payload_descriptor_t *payload_descriptor;
626 uint32_t hdrlen = 0, payload_size = 0, packet_size = 0, start = 0, key = 0;
630 if ((context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->enc_iter))) {
632 if (!context->pbuffer) {
640 if (context->pbuffer) {
644 if (!context->pkt || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT || !remaining_bytes) {
652 key = (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY);
656 context->pkt->data.frame.flags, context->pkt->data.frame.pts, context->pkt->data.frame.duration, context->pkt->data.frame.partition_id);
660 *(uint8_t *)frame->
data = 0;
661 payload_descriptor = (vpx_payload_descriptor_t *) frame->
data;
665 body = ((uint8_t *)frame->
data) + hdrlen;
666 packet_size = SLICE_SIZE;
667 payload_size = packet_size - hdrlen;
672 if (context->is_vp9) {
673 payload_descriptor->vp9.start = start;
677 payload_descriptor->vp9.have_pid = 1;
679 if (payload_descriptor->vp9.have_pid) {
681 if (context->vp9.picture_id < 0) context->vp9.picture_id = 0;
683 if (context->vp9.picture_id > 0x7f) {
684 *body++ = (context->vp9.picture_id >> 8) | 0x80;
685 *body++ = context->vp9.picture_id & 0xff;
689 *body++ = context->vp9.picture_id;
698 context->vp9.picture_id++;
705 vp9_ss_t *ss = (vp9_ss_t *)body;
707 payload_descriptor->vp9.have_ss = 1;
708 payload_descriptor->vp9.have_p_layer = 0;
723 w = (uint16_t *)body;
725 h = (uint16_t *)body;
728 *w = (uint16_t)context->codec_settings.video.width;
729 *h = (uint16_t)context->codec_settings.video.height;
731 payload_size-= (ss->n_s + 1) * 4;
732 frame->
datalen+= (ss->n_s + 1) * 4;
735 payload_descriptor->vp9.have_p_layer = 1;
740 payload_descriptor->vp8.start = start;
743 if (remaining_bytes <= payload_size) {
746 frame->
datalen += remaining_bytes;
751 frame->
datalen += payload_size;
756 if (frame->
m && context->is_vp9) {
757 payload_descriptor->vp9.end = 1;
763 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
765 if (context->encoder_init) {
766 vpx_codec_destroy(&context->encoder);
768 context->last_ts = 0;
769 context->last_ms = 0;
770 context->framecount = 0;
771 context->encoder_init = 0;
773 return init_encoder(codec);
778 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
783 vpx_enc_frame_flags_t vpx_flags = 0;
788 return consume_partition(context, frame);
791 if (context->need_encoder_reset != 0) {
795 context->need_encoder_reset = 0;
798 if (frame->
img->
d_h > 1) {
802 width = frame->
img->
w;
803 height = frame->
img->
h;
806 if (context->config.g_w != width || context->config.g_h != height) {
807 context->codec_settings.video.width = width;
808 context->codec_settings.video.height = height;
809 reset_codec_encoder(codec);
811 context->need_key_frame = 3;
815 if (!context->encoder_init) {
821 if (context->change_bandwidth) {
822 context->codec_settings.video.bandwidth = context->change_bandwidth;
823 context->change_bandwidth = 0;
831 if (context->need_key_frame > 0) {
834 if (!context->last_key_frame || (now - context->last_key_frame) > KEY_FRAME_MIN_FREQ) {
836 vpx_flags |= VPX_EFLAG_FORCE_KF;
837 context->need_key_frame = 0;
838 context->last_key_frame = now;
842 context->framecount++;
844 pts = (now - context->start_time) / 1000;
846 dur = context->last_ms ? (now - context->last_ms) / 1000 : pts;
848 if ((err = vpx_codec_encode(&context->encoder,
853 VPX_DL_REALTIME)) != VPX_CODEC_OK) {
855 err, vpx_codec_error(&context->encoder), vpx_codec_error_detail(&context->encoder));
860 context->enc_iter = NULL;
862 context->last_ms = now;
864 return consume_partition(context, frame);
869 uint8_t *data = frame->
data;
878 "VIDEO VPX: seq: %d ts: %u len: %ld %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d\n",
880 *((uint8_t *)data), *((uint8_t *)data + 1),
881 *((uint8_t *)data + 2), *((uint8_t *)data + 3),
882 *((uint8_t *)data + 4), *((uint8_t *)data + 5),
883 *((uint8_t *)data + 6), *((uint8_t *)data + 7),
884 *((uint8_t *)data + 8), *((uint8_t *)data + 9),
885 *((uint8_t *)data + 10), frame->
m);
901 uint8_t M = (*data) & 0x80;
920 if (context->got_key_frame > 0) {
921 context->got_key_frame = 0;
922 context->got_start_frame = 0;
930 context->last_received_timestamp = frame->
timestamp;
933 key = __IS_VP8_KEY_FRAME(*data);
938 len = frame->
datalen - (data - (uint8_t *)frame->
data);
946 if (context->last_received_timestamp != frame->
timestamp) {
960 uint8_t *data = (uint8_t *)frame->
data;
961 uint8_t *vp9 = (uint8_t *)frame->
data;
962 vp9_payload_descriptor_t *desc = (vp9_payload_descriptor_t *)vp9;
975 *data, *(data+1), *(data+2), *(data+3), frame->
m, frame->
datalen,
978 desc->have_layer_ind,
988 if (desc->have_pid) {
995 pid = (pid << 8) + *vp9;
1006 if (desc->have_layer_ind) {
1008 vp9_p_layer_t *layer = (vp9_p_layer_t *)vp9;
1011 layer->temporal_id, layer->temporal_up_switch, layer->spatial_id, layer->inter_layer_predicted);
1015 if (!desc->is_flexible) {
1021 if (desc->have_p_layer && desc->is_flexible) {
1036 if (desc->have_ss) {
1037 vp9_ss_t *ss = (vp9_ss_t *)(vp9++);
1045 for (i=0; i<=ss->n_s; i++) {
1047 int width = ntohs(*(uint16_t *)vp9);
1048 int height = ntohs(*(uint16_t *)(vp9 + 2));
1057 uint8_t ng = *vp9++;
1059 for (i = 0; ng > 0 && i < ng; i++) {
1060 vp9_n_g_t *n_g = (vp9_n_g_t *)(vp9++);
1066 if (vp9 - data >= frame->
datalen) {
1084 len = frame->
datalen - (vp9 - data);
1098 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
1100 vpx_codec_ctx_t *decoder = NULL;
1102 int is_start = 0, is_keyframe = 0, get_refresh = 0;
1105 vp9_payload_descriptor_t *desc = (vp9_payload_descriptor_t *)frame->
data;
1106 uint8_t *data = frame->
data;
1108 *data, *(data+1), *(data+2), *(data+3), frame->
m, desc->start, desc->end, frame->
m, frame->
datalen);
1111 if (context->is_vp9) {
1112 is_keyframe = IS_VP9_KEY_FRAME(*(
unsigned char *)frame->
data);
1113 is_start = IS_VP9_START_PKT(*(
unsigned char *)frame->
data);
1121 is_start = (*(
unsigned char *)frame->
data & 0x10);
1122 is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->
data);
1129 if (!is_keyframe && context->got_key_frame <= 0) {
1130 context->no_key_frame++;
1132 if (context->no_key_frame > 50) {
1133 if ((is_keyframe = is_start)) {
1141 if (context->need_decoder_reset != 0) {
1142 vpx_codec_destroy(&context->decoder);
1143 context->decoder_init = 0;
1144 init_decoder(codec);
1145 context->need_decoder_reset = 0;
1148 if (!context->decoder_init) {
1149 init_decoder(codec);
1152 if (!context->decoder_init) {
1157 decoder = &context->decoder;
1165 context->got_start_frame = 1;
1169 if (context->got_key_frame <= 0) {
1170 context->got_key_frame = 1;
1171 context->no_key_frame = 0;
1173 context->got_key_frame++;
1175 }
else if (context->got_key_frame <= 0) {
1176 if ((--context->got_key_frame % 200) == 0) {
1182 if (!context->got_start_frame) {
1188 status = context->is_vp9 ? buffer_vp9_packets(context, frame) : buffer_vp8_packets(context, frame);
1191 if (context->dec_iter && (frame->
img = (
switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter))) {
1210 context->dec_iter = NULL;
1211 err = vpx_codec_decode(decoder, data, (
unsigned int)len, NULL, 0);
1213 if (err != VPX_CODEC_OK) {
1215 len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder));
1219 if (vpx_codec_control(decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) {
1230 frame->
img = (
switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter);
1241 context->got_key_frame = 0;
1242 context->got_start_frame = 0;
1252 context->got_key_frame = 0;
1253 context->got_start_frame = 0;
1261 if (context->got_key_frame <= 0 || get_refresh) {
1279 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
1284 int mask = *((
int *) cmd_data);
1286 context->need_encoder_reset = 1;
1289 context->need_decoder_reset = 1;
1294 context->need_key_frame = 1;
1300 context->change_bandwidth = *((
int *) cmd_data);
1304 char *bwv = (
char *) cmd_data;
1324 vpx_context_t *context = (vpx_context_t *)codec->
private_info;
1328 vpx_codec_destroy(&context->encoder);
1332 vpx_codec_destroy(&context->decoder);
1337 context->pic = NULL;
1339 if (context->vpx_packet_buffer) {
1341 context->vpx_packet_buffer = NULL;
1355 switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
1358 switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
switch_core_session_t * session
switch_time_t switch_micro_time_now(void)
Get the current epoch time in microseconds.
#define VPX_IMAGE_ABI_VERSION
Current ABI version number.
void vpx_img_free(vpx_image_t *img)
Close an image descriptor.
#define SWITCH_CHANNEL_SESSION_LOG(x)
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
#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...
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.
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
switch_memory_pool_t * pool
uint32_t switch_core_cpu_count(void)
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)
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)
switch_codec_control_command_t
switch_codec_control_type_t
const switch_codec_implementation_t * implementation
if((uint32_t)(unpack->cur-unpack->buf) > unpack->buflen)
switch_frame_flag_t flags
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
switch_memory_pool_t * memory_pool
static int32_t switch_calc_bitrate(int w, int h, int quality, double fps)
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.
An abstraction of a data frame.
#define SWITCH_MODULE_LOAD_FUNCTION(name)
#define SWITCH_SSIZE_T_FMT
#define SWITCH_ADD_CODEC(codec_int, int_name)
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)
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)
#define SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
struct apr_pool_t switch_memory_pool_t
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_status_t switch_buffer_set_partition_data(switch_buffer_t *buffer, void *data, switch_size_t datalen)
switch_time_t switch_time_now(void)
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.
#define SWITCH_SIZE_T_FMT