]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7508: WIP vp9 stuff
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 11 Mar 2015 23:33:20 +0000 (18:33 -0500)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:12 +0000 (12:47 -0500)
src/mod/codecs/mod_vpx/mod_vpx.c

index eb82f9fb7b91e39a3b946e5839f409cc3fda2725..b8d5b43f9ddfdabb6c9fa3b263bd86f0213b6779 100644 (file)
 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,77 +156,113 @@ 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;
+
+#if 0
+               config->g_lag_in_frames = 0; // 0- no frame lagging
+
+
+
+               // rate control settings
+               config->rc_end_usage = VPX_CBR;
+
+               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;
+
 
-       // 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;
+               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");
@@ -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);
-               // }
-
-               // 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->pbuffer) {
+               remaining_bytes = switch_buffer_inuse(context->pbuffer);
+       }
 
-       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;
+
+       // 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;
+       }
 
-               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 (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;
-
-               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;
+               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);
 
-                       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;