/***************************************************************************** * Open: probe the decoder *****************************************************************************/ static int Open(vlc_object_t *p_this) { decoder_t *dec = (decoder_t *)p_this; const struct vpx_codec_iface *iface; int vp_version; switch (dec->fmt_in.i_codec) { #ifdef ENABLE_VP8_DECODER case VLC_CODEC_VP8: iface = &vpx_codec_vp8_dx_algo; vp_version = 8; break; #endif #ifdef ENABLE_VP9_DECODER case VLC_CODEC_VP9: iface = &vpx_codec_vp9_dx_algo; vp_version = 9; break; #endif default: return VLC_EGENERIC; } decoder_sys_t *sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; dec->p_sys = sys; struct vpx_codec_dec_cfg deccfg = { .threads = __MIN(vlc_GetCPUCount(), 16) }; msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)", vp_version, vpx_codec_version_str(), vpx_codec_build_config()); if (vpx_codec_dec_init(&sys->ctx, iface, &deccfg, 0) != VPX_CODEC_OK) { const char *error = vpx_codec_error(&sys->ctx); msg_Err(p_this, "Failed to initialize decoder: %s\n", error); free(sys); return VLC_EGENERIC;; } dec->pf_decode_video = Decode; dec->fmt_out.i_cat = VIDEO_ES; dec->fmt_out.video.i_width = dec->fmt_in.video.i_width; dec->fmt_out.video.i_height = dec->fmt_in.video.i_height; dec->fmt_out.i_codec = VLC_CODEC_I420; dec->b_need_packetized = true; return VLC_SUCCESS; } /***************************************************************************** * Close: decoder destruction *****************************************************************************/ static void Close(vlc_object_t *p_this) { decoder_t *dec = (decoder_t *)p_this; decoder_sys_t *sys = dec->p_sys; /* Free our PTS */ const void *iter = NULL; for (;;) { struct vpx_image *img = vpx_codec_get_frame(&sys->ctx, &iter); if (!img) break; free(img->user_priv); } vpx_codec_destroy(&sys->ctx); free(sys); }
/* * Open codec. */ static pj_status_t pj_vpx_codec_open(pjmedia_vid_codec *codec, pjmedia_vid_codec_param *attr) { vpx_private *vpx; pj_status_t status; PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL); vpx = (vpx_private*) codec->codec_data; pj_memcpy(&vpx->param, attr, sizeof(*attr)); /* Normalize encoding MTU in codec param */ if (attr->enc_mtu > PJMEDIA_MAX_VID_PAYLOAD_SIZE) { attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE; } /* Init format info and apply-param of decoder */ vpx->dec_vfi = pjmedia_get_video_format_info(NULL, vpx->param.dec_fmt.id); if (!vpx->dec_vfi) { status = PJ_EINVAL; goto on_error; } pj_bzero(&vpx->dec_vafp, sizeof(vpx->dec_vafp)); vpx->dec_vafp.size = vpx->param.dec_fmt.det.vid.size; vpx->dec_vafp.buffer = NULL; status = (*vpx->dec_vfi->apply_fmt)(vpx->dec_vfi, &vpx->dec_vafp); if (status != PJ_SUCCESS) { goto on_error; } /* Init format info and apply-param of encoder */ vpx->enc_vfi = pjmedia_get_video_format_info(NULL, vpx->param.dec_fmt.id); if (!vpx->enc_vfi) { status = PJ_EINVAL; goto on_error; } pj_bzero(&vpx->enc_vafp, sizeof(vpx->enc_vafp)); vpx->enc_vafp.size = vpx->param.enc_fmt.det.vid.size; vpx->enc_vafp.buffer = NULL; status = (*vpx->enc_vfi->apply_fmt)(vpx->enc_vfi, &vpx->enc_vafp); if (status != PJ_SUCCESS) { goto on_error; } /* Open the encoder */ TRACE_((THIS_FILE, "Open vpx version : %s build : %s", vpx_codec_version_str(), vpx_codec_build_config())); if (vpx->param.dir & PJMEDIA_DIR_ENCODING) { status = pj_vpx_encoder_open(vpx); if (status != PJ_SUCCESS) { goto on_error; } } if (vpx->param.dir & PJMEDIA_DIR_DECODING) { status = pj_vpx_decoder_open(vpx); if (status != PJ_SUCCESS) { goto on_error; } } /* Update codec attributes, e.g: encoding format may be changed by * SDP fmtp negotiation. */ pj_memcpy(attr, &vpx->param, sizeof(*attr)); return PJ_SUCCESS; on_error: pj_vpx_codec_close(codec); return status; }