From 4a6e9fd4b042c6a1b0fdce3eff8f4e2e2d01c72f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 11 Mar 2015 18:33:20 -0500 Subject: [PATCH] FS-7508: WIP vp9 stuff --- src/mod/codecs/mod_vpx/mod_vpx.c | 438 ++++++++++++++++++++++--------- 1 file changed, 310 insertions(+), 128 deletions(-) diff --git a/src/mod/codecs/mod_vpx/mod_vpx.c b/src/mod/codecs/mod_vpx/mod_vpx.c index eb82f9fb7b..b8d5b43f9d 100644 --- a/src/mod/codecs/mod_vpx/mod_vpx.c +++ b/src/mod/codecs/mod_vpx/mod_vpx.c @@ -44,12 +44,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load); SWITCH_MODULE_DEFINITION(mod_vpx, mod_vpx_load, NULL, NULL); - -#define encoder_interface (vpx_codec_vp8_cx()) -#define decoder_interface (vpx_codec_vp8_dx()) - struct vpx_context { switch_codec_t *codec; + int is_vp9; + vpx_codec_iface_t *encoder_interface; + vpx_codec_iface_t *decoder_interface; unsigned int flags; switch_codec_settings_t codec_settings; unsigned int bandwidth; @@ -66,7 +65,6 @@ struct vpx_context { int num; int partition_index; const vpx_codec_cx_pkt_t *pkt; - int pkt_pos; vpx_codec_iter_t iter; uint32_t last_ts; vpx_codec_ctx_t decoder; @@ -81,6 +79,8 @@ struct vpx_context { int32_t change_bandwidth; uint64_t framecount; uint64_t framesum; + switch_memory_pool_t *pool; + switch_buffer_t *pbuffer; }; typedef struct vpx_context vpx_context_t; @@ -88,6 +88,9 @@ typedef struct vpx_context vpx_context_t; static switch_status_t init_decoder(switch_codec_t *codec) { vpx_context_t *context = (vpx_context_t *)codec->private_info; + vpx_codec_dec_cfg_t cfg = {0, 0, 0}; + vpx_codec_flags_t dec_flags = 0; + if (context->flags & SWITCH_CODEC_FLAG_DECODE && !context->decoder_init) { vp8_postproc_cfg_t ppcfg; @@ -96,7 +99,13 @@ static switch_status_t init_decoder(switch_codec_t *codec) // context->decoder_init = 0; //} - if (vpx_codec_dec_init(&context->decoder, decoder_interface, NULL, VPX_CODEC_USE_POSTPROC) != VPX_CODEC_OK) { + cfg.threads = switch_core_cpu_count(); + + if (!context->is_vp9) { // vp8 only + dec_flags = VPX_CODEC_USE_POSTPROC; + } + + if (vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec init error: [%d:%s]\n", context->encoder.err, context->encoder.err_detail); return SWITCH_STATUS_FALSE; } @@ -147,78 +156,114 @@ static switch_status_t init_encoder(switch_codec_t *codec) } context->pkt = NULL; - context->pkt_pos = 0; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_NOTICE, "VPX reset encoder picture from %dx%d to %dx%d %u BW\n", config->g_w, config->g_h, context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth); + if (context->is_vp9) { + config->g_w = context->codec_settings.video.width; + config->g_h = context->codec_settings.video.height; + config->g_timebase.num = 1; + config->g_timebase.den = 90000; + config->rc_target_bitrate = context->bandwidth; + config->rc_dropframe_thresh = 2; + config->g_pass = VPX_RC_ONE_PASS; + config->g_threads = (cpus > 1) ? cpus / 2 : 1; + token_parts = (cpus > 1) ? 3 : 0; - // settings - config->g_profile = 0; - config->g_w = context->codec_settings.video.width; - config->g_h = context->codec_settings.video.height; - config->rc_target_bitrate = context->bandwidth; - config->g_timebase.num = 1; - config->g_timebase.den = 90000; - config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS; - config->g_lag_in_frames = 0; // 0- no frame lagging +#if 0 + config->g_lag_in_frames = 0; // 0- no frame lagging - config->g_threads = (cpus > 1) ? 2 : 1; - token_parts = (cpus > 1) ? 3 : 0; + // rate control settings + config->rc_end_usage = VPX_CBR; - // rate control settings - config->rc_dropframe_thresh = 0; - config->rc_end_usage = VPX_CBR; - config->g_pass = VPX_RC_ONE_PASS; - config->kf_mode = VPX_KF_AUTO; - config->kf_max_dist = 1000; - //config->kf_mode = VPX_KF_DISABLED; - config->rc_resize_allowed = 1; - config->rc_min_quantizer = 0; - config->rc_max_quantizer = 63; - //Rate control adaptation undershoot control. - // This value, expressed as a percentage of the target bitrate, - // controls the maximum allowed adaptation speed of the codec. - // This factor controls the maximum amount of bits that can be - // subtracted from the target bitrate in order to compensate for - // prior overshoot. - // Valid values in the range 0-1000. - config->rc_undershoot_pct = 100; - //Rate control adaptation overshoot control. - // This value, expressed as a percentage of the target bitrate, - // controls the maximum allowed adaptation speed of the codec. - // This factor controls the maximum amount of bits that can be - // added to the target bitrate in order to compensate for prior - // undershoot. - // Valid values in the range 0-1000. - config->rc_overshoot_pct = 15; - //Decoder Buffer Size. - // This value indicates the amount of data that may be buffered - // by the decoding application. Note that this value is expressed - // in units of time (milliseconds). For example, a value of 5000 - // indicates that the client will buffer (at least) 5000ms worth - // of encoded data. Use the target bitrate (rc_target_bitrate) to - // convert to bits/bytes, if necessary. - config->rc_buf_sz = 5000; - //Decoder Buffer Initial Size. - // This value indicates the amount of data that will be buffered - // by the decoding application prior to beginning playback. - // This value is expressed in units of time (milliseconds). - // Use the target bitrate (rc_target_bitrate) to convert to - // bits/bytes, if necessary. - config->rc_buf_initial_sz = 1000; - //Decoder Buffer Optimal Size. - // This value indicates the amount of data that the encoder should - // try to maintain in the decoder's buffer. This value is expressed - // in units of time (milliseconds). - // Use the target bitrate (rc_target_bitrate) to convert to - // bits/bytes, if necessary. - config->rc_buf_optimal_sz = 1000; + config->kf_mode = VPX_KF_AUTO; + config->kf_max_dist = 1000; + config->rc_resize_allowed = 1; + config->rc_min_quantizer = 0; + config->rc_max_quantizer = 63; + + + config->rc_undershoot_pct = 100; + config->rc_overshoot_pct = 15; + config->rc_buf_sz = 5000; + config->rc_buf_initial_sz = 1000; + config->rc_buf_optimal_sz = 1000; +#endif + + } else { + + // settings + config->g_profile = 0; + config->g_w = context->codec_settings.video.width; + config->g_h = context->codec_settings.video.height; + config->rc_target_bitrate = context->bandwidth; + config->g_timebase.num = 1; + config->g_timebase.den = 90000; + config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS; + config->g_lag_in_frames = 0; // 0- no frame lagging + + + + config->g_threads = (cpus > 1) ? 2 : 1; + token_parts = (cpus > 1) ? 3 : 0; + + // rate control settings + config->rc_dropframe_thresh = 0; + config->rc_end_usage = VPX_CBR; + config->g_pass = VPX_RC_ONE_PASS; + config->kf_mode = VPX_KF_AUTO; + config->kf_max_dist = 1000; + + //config->kf_mode = VPX_KF_DISABLED; + config->rc_resize_allowed = 1; + config->rc_min_quantizer = 0; + config->rc_max_quantizer = 63; + //Rate control adaptation undershoot control. + // This value, expressed as a percentage of the target bitrate, + // controls the maximum allowed adaptation speed of the codec. + // This factor controls the maximum amount of bits that can be + // subtracted from the target bitrate in order to compensate for + // prior overshoot. + // Valid values in the range 0-1000. + config->rc_undershoot_pct = 100; + //Rate control adaptation overshoot control. + // This value, expressed as a percentage of the target bitrate, + // controls the maximum allowed adaptation speed of the codec. + // This factor controls the maximum amount of bits that can be + // added to the target bitrate in order to compensate for prior + // undershoot. + // Valid values in the range 0-1000. + config->rc_overshoot_pct = 15; + //Decoder Buffer Size. + // This value indicates the amount of data that may be buffered + // by the decoding application. Note that this value is expressed + // in units of time (milliseconds). For example, a value of 5000 + // indicates that the client will buffer (at least) 5000ms worth + // of encoded data. Use the target bitrate (rc_target_bitrate) to + // convert to bits/bytes, if necessary. + config->rc_buf_sz = 5000; + //Decoder Buffer Initial Size. + // This value indicates the amount of data that will be buffered + // by the decoding application prior to beginning playback. + // This value is expressed in units of time (milliseconds). + // Use the target bitrate (rc_target_bitrate) to convert to + // bits/bytes, if necessary. + config->rc_buf_initial_sz = 1000; + //Decoder Buffer Optimal Size. + // This value indicates the amount of data that the encoder should + // try to maintain in the decoder's buffer. This value is expressed + // in units of time (milliseconds). + // Use the target bitrate (rc_target_bitrate) to convert to + // bits/bytes, if necessary. + config->rc_buf_optimal_sz = 1000; + } + if (context->encoder_init) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "VPX ENCODER RESET\n"); if (vpx_codec_enc_config_set(&context->encoder, config) != VPX_CODEC_OK) { @@ -226,28 +271,38 @@ static switch_status_t init_encoder(switch_codec_t *codec) } } else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) { - if (vpx_codec_enc_init(&context->encoder, encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION) != VPX_CODEC_OK) { + if (vpx_codec_enc_init(&context->encoder, context->encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec init error: [%d:%s]\n", context->encoder.err, context->encoder.err_detail); return SWITCH_STATUS_FALSE; } context->encoder_init = 1; - // The static threshold imposes a change threshold on blocks below which they will be skipped by the encoder. - vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, 100); - //Set cpu usage, a bit lower than normal (-6) but higher than android (-12) - vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -6); - vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, token_parts); + if (context->is_vp9) { + //vpx_codec_control(&context->encoder, VP9E_SET_LOSSLESS, 1); + vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, 100); + vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -8); + vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, token_parts); + // Enable noise reduction + //vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, 1); - // Enable noise reduction - vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, 1); - //Set max data rate for Intra frames. - // This value controls additional clamping on the maximum size of a keyframe. - // It is expressed as a percentage of the average per-frame bitrate, with the - // special (and default) value 0 meaning unlimited, or no additional clamping - // beyond the codec's built-in algorithm. - // For example, to allocate no more than 4.5 frames worth of bitrate to a keyframe, set this to 450. - //vpx_codec_control(&context->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT, 0); + } else { + // The static threshold imposes a change threshold on blocks below which they will be skipped by the encoder. + vpx_codec_control(&context->encoder, VP8E_SET_STATIC_THRESHOLD, 100); + //Set cpu usage, a bit lower than normal (-6) but higher than android (-12) + vpx_codec_control(&context->encoder, VP8E_SET_CPUUSED, -6); + vpx_codec_control(&context->encoder, VP8E_SET_TOKEN_PARTITIONS, token_parts); + + // Enable noise reduction + vpx_codec_control(&context->encoder, VP8E_SET_NOISE_SENSITIVITY, 1); + //Set max data rate for Intra frames. + // This value controls additional clamping on the maximum size of a keyframe. + // It is expressed as a percentage of the average per-frame bitrate, with the + // special (and default) value 0 meaning unlimited, or no additional clamping + // beyond the codec's built-in algorithm. + // For example, to allocate no more than 4.5 frames worth of bitrate to a keyframe, set this to 450. + //vpx_codec_control(&context->encoder, VP8E_SET_MAX_INTRA_BITRATE_PCT, 0); + } } return SWITCH_STATUS_SUCCESS; @@ -258,7 +313,6 @@ static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_ vpx_context_t *context = NULL; int encoding, decoding; - encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); decoding = (flags & SWITCH_CODEC_FLAG_DECODE); @@ -269,21 +323,33 @@ static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_ memset(context, 0, sizeof(*context)); context->flags = flags; codec->private_info = context; + context->pool = codec->memory_pool; if (codec_settings) { context->codec_settings = *codec_settings; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", codec->implementation->iananame); + + if (!strcmp(codec->implementation->iananame, "VP9")) { + context->is_vp9 = 1; + context->encoder_interface = vpx_codec_vp9_cx(); + context->decoder_interface = vpx_codec_vp9_dx(); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "is vp9\n"); + } else { + context->encoder_interface = vpx_codec_vp8_cx(); + context->decoder_interface = vpx_codec_vp8_dx(); + } + if (codec->fmtp_in) { codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in); } - if (vpx_codec_enc_config_default(encoder_interface, &context->config, 0) != VPX_CODEC_OK) { + if (vpx_codec_enc_config_default(context->encoder_interface, &context->config, 0) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder config Error\n"); return SWITCH_STATUS_FALSE; } - /* start with 4k res cos otherwise you can't reset without re-init the whole codec */ context->codec_settings.video.width = 320; context->codec_settings.video.height = 240; @@ -328,61 +394,151 @@ static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_ +-+-+-+-+-+-+-+-+ */ + +#ifdef _MSC_VER +#pragma pack(push, r1, 1) +#endif + +#if SWITCH_BYTE_ORDER == __BIG_ENDIAN + +typedef struct { + unsigned extended:1; + unsigned reserved1:1; + unsigned non_referenced:1; + unsigned start:1; + unsigned reserved2:1; + unsigned pid:3; +} vp8_payload_descriptor_t; + +#ifdef WHAT_THEY_FUCKING_SAY +typedef struct { + unsigned have_pid:1; + unsigned have_layer_ind:1; + unsigned have_ref_ind:1; + unsigned start:1; + unsigned end:1; + unsigned have_ss:1; + unsigned have_su:1; + unsigned zero:1; +} vp9_payload_descriptor_t; + +#else +typedef struct { + unsigned dunno:6; + unsigned start:1; + unsigned key:1; +} vp9_payload_descriptor_t; +#endif + + +#else /* ELSE LITTLE */ + +typedef struct { + unsigned pid:3; + unsigned reserved2:1; + unsigned start:1; + unsigned non_referenced:1; + unsigned reserved1:1; + unsigned extended:1; +} vp8_payload_descriptor_t; + +#ifdef WHAT_THEY_FUCKING_SAY +typedef struct { + unsigned zero:1; + unsigned have_su:1; + unsigned have_ss:1; + unsigned end:1; + unsigned start:1; + unsigned have_ref_ind:1; + unsigned have_layer_ind:1; + unsigned have_pid:1; +} vp9_payload_descriptor_t; +#else +typedef struct { + unsigned key:1; + unsigned start:1; + unsigned dunno:6; +} vp9_payload_descriptor_t; +#endif + +#endif + +typedef union { + vp8_payload_descriptor_t vp8; + vp9_payload_descriptor_t vp9; +} vpx_payload_descriptor_t; + +#ifdef _MSC_VER +#pragma pack(pop, r1) +#endif + static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t *frame) { + vpx_payload_descriptor_t *payload_descriptor; + uint8_t *body; + uint32_t hdrlen = 0, payload_size = 0, packet_size = 0, start = 0, key = 0; + switch_size_t remaining_bytes = 0; + if (!context->pkt) { - context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->iter); - context->pkt_pos = 0; + if ((context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->iter))) { + start = 1; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "NEW PACKET %ld\n", context->pkt->data.frame.sz); + if (!context->pbuffer) { + switch_buffer_create_partition(context->pool, &context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz); + } else { + switch_buffer_set_partition_data(context->pbuffer, context->pkt->data.frame.buf, context->pkt->data.frame.sz); + } + } } - // if (context->pkt) { - // if (context->pkt->kind == VPX_CODEC_CX_FRAME_PKT && (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY) && context->pkt_pos == 0) { - // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "============================Got a VP8 Key Frame size:[%d]===================================\n", (int)context->pkt->data.frame.sz); - // } + if (context->pbuffer) { + remaining_bytes = switch_buffer_inuse(context->pbuffer); + } - // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size:%d flag: %x part_id: %d pts: %lld duration:%ld\n", - // (int)context->pkt->data.frame.sz, context->pkt->data.frame.flags, context->pkt->data.frame.partition_id, context->pkt->data.frame.pts, context->pkt->data.frame.duration); - //} - - if (!context->pkt || context->pkt_pos >= context->pkt->data.frame.sz - 1 || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT) { + if (!context->pkt || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT || !remaining_bytes) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "PUNT\n"); frame->datalen = 0; frame->m = 1; - context->pkt_pos = 0; context->pkt = NULL; return SWITCH_STATUS_SUCCESS; } - if (context->pkt->data.frame.sz < SLICE_SIZE) { - uint8_t hdr = 0x10; + key = (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY); + + /* reset header */ + *(uint8_t *)frame->data = 0; + payload_descriptor = (vpx_payload_descriptor_t *) frame->data; - memcpy(frame->data, &hdr, 1); - memcpy((uint8_t *)frame->data + 1, context->pkt->data.frame.buf, context->pkt->data.frame.sz); - frame->datalen = context->pkt->data.frame.sz + 1; - frame->m = 1; + // if !extended + hdrlen = 1; + body = ((uint8_t *)frame->data) + hdrlen; + packet_size = SLICE_SIZE; + payload_size = packet_size - hdrlen; + // else add extended TBD + + frame->datalen = hdrlen; + + if (context->is_vp9) { + payload_descriptor->vp9.start = start; + payload_descriptor->vp9.key = key; + } else { + payload_descriptor->vp8.start = start; + } + + if (remaining_bytes <= payload_size) { + switch_buffer_read(context->pbuffer, body, remaining_bytes); context->pkt = NULL; - context->pkt_pos = 0; + frame->datalen += remaining_bytes; + frame->m = 1; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "END %d H:%.2x\n", frame->datalen, *(uint8_t *)frame->data); return SWITCH_STATUS_SUCCESS; } else { - int left = context->pkt->data.frame.sz - context->pkt_pos; - uint8_t *p = frame->data; + switch_buffer_read(context->pbuffer, body, payload_size); + frame->datalen += payload_size; + frame->m = 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s DATA %d H:.2%x\n", start ? "start" : "middle", frame->datalen, *(uint8_t *)frame->data); - if (left < SLICE_SIZE) { - p[0] = 0; - memcpy(p+1, (uint8_t *)context->pkt->data.frame.buf + context->pkt_pos, left); - context->pkt_pos = 0; - context->pkt = NULL; - frame->datalen = left + 1; - frame->m = 1; - return SWITCH_STATUS_SUCCESS; - } else { - uint8_t hdr = context->pkt_pos == 0 ? 0x10 : 0; - - p[0] = hdr; - memcpy(p+1, (uint8_t *)context->pkt->data.frame.buf + context->pkt_pos, SLICE_SIZE - 1); - context->pkt_pos += (SLICE_SIZE - 1); - frame->datalen = SLICE_SIZE; - return SWITCH_STATUS_MORE_DATA; - } + return SWITCH_STATUS_MORE_DATA; } } @@ -396,7 +552,6 @@ static void reset_codec_encoder(switch_codec_t *codec) context->framesum = 0; context->framecount = 0; context->encoder_init = 0; - context->pkt_pos = 0; context->pkt = NULL; init_encoder(codec); } @@ -480,7 +635,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * } if (vpx_codec_encode(&context->encoder, (vpx_image_t *) frame->img, frame->timestamp, dur, vpx_flags, VPX_DL_REALTIME) != VPX_CODEC_OK) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VP8 encode error %d:%s\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VPX encode error %d:%s\n", context->encoder.err, context->encoder.err_detail); frame->datalen = 0; @@ -494,7 +649,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * return consume_partition(context, frame); } -static switch_status_t buffer_vpx_packets(vpx_context_t *context, switch_frame_t *frame) +static switch_status_t buffer_vp8_packets(vpx_context_t *context, switch_frame_t *frame) { uint8_t *data = frame->data; uint8_t S; @@ -552,6 +707,27 @@ static switch_status_t buffer_vpx_packets(vpx_context_t *context, switch_frame_t } +static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t *frame) +{ + uint8_t *data = frame->data; + uint8_t *vp9; + int len = 0; + + if (!frame) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no frame in codec!!\n"); + return SWITCH_STATUS_RESTART; + } + + vp9 = data + 1; + + len = frame->datalen - (vp9 - data); + switch_buffer_write(context->vpx_packet_buffer, vp9, len); + + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered %d bytes, buffer size: %" SWITCH_SIZE_T_FMT "\n", len, switch_buffer_inuse(context->vpx_packet_buffer)); + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *frame) { vpx_context_t *context = (vpx_context_t *)codec->private_info; @@ -560,6 +736,8 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * switch_status_t status = SWITCH_STATUS_SUCCESS; int is_keyframe = ((*(unsigned char *)frame->data) & 0x01) ? 0 : 1; + if (context->is_vp9) is_keyframe = 1; // don't know how to get it yet + if (context->need_decoder_reset != 0) { vpx_codec_destroy(&context->decoder); context->decoder_init = 0; @@ -578,7 +756,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * decoder = &context->decoder; - // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %" SWITCH_SIZE_T_FMT " mark:%d\n", frame->datalen, frame->timestamp, frame->m); + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %u mark:%d\n", frame->datalen, frame->timestamp, frame->m); if (!is_keyframe && context->last_received_timestamp && context->last_received_timestamp != frame->timestamp && (!frame->m) && (!context->last_received_complete_picture)) { @@ -592,7 +770,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * context->last_received_timestamp = frame->timestamp; context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE; - status = buffer_vpx_packets(context, frame); + status = context->is_vp9 ? buffer_vp9_packets(context, frame) : buffer_vp8_packets(context, frame); //printf("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); @@ -621,7 +799,8 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0); if (err != VPX_CODEC_OK) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%d:%s]\n", len, err, decoder->err, decoder->err_detail); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n", + len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder)); switch_goto_status(SWITCH_STATUS_RESTART, end); } @@ -749,6 +928,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load) SWITCH_ADD_CODEC(codec_interface, "VP8 Video"); switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP8", NULL, switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy); + SWITCH_ADD_CODEC(codec_interface, "VP9 Video"); + switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP9", NULL, + switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS;