[vlc-devel] [PATCH 2/2] vpx: add vp8 and vp9 encoder
Jean-Baptiste Kempf
jb at videolan.org
Tue Feb 9 00:29:30 CET 2016
On 08 Feb, Tristan Matthews wrote :
> diff --git a/NEWS b/NEWS
> diff --git a/configure.ac b/configure.ac
> diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
All OK.
> +++ b/modules/codec/vpx.c
> @@ -34,11 +34,21 @@
> #include <vpx/vpx_decoder.h>
> #include <vpx/vp8dx.h>
>
> +#ifdef ENABLE_SOUT
> +#include <vpx/vpx_encoder.h>
> +#include <vpx/vp8cx.h>
> +#endif
I prefer indenting in those ifdefs.
> /****************************************************************************
> * Local prototypes
> ****************************************************************************/
> -static int Open(vlc_object_t *);
> -static void Close(vlc_object_t *);
> +static int OpenDecoder(vlc_object_t *);
> +static void CloseDecoder(vlc_object_t *);
You should have done the renaming in a different patch.
> - msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)",
> + msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)",
Ynrelated to the encoder?
> +#ifdef ENABLE_SOUT
> +
> +/*****************************************************************************
> + * encoder_sys_t: libvpx encoder descriptor
> + *****************************************************************************/
> +struct encoder_sys_t
> +{
> + struct vpx_codec_ctx ctx;
> +};
> +
> +/*****************************************************************************
> + * OpenEncoder: probe the encoder
> + *****************************************************************************/
> +static int OpenEncoder(vlc_object_t *p_this)
> +{
> + encoder_t *p_enc = (encoder_t *)p_this;
> + encoder_sys_t *p_sys;
> +
> + const struct vpx_codec_iface *iface;
> + int vp_version;
> +
> + p_enc->pf_encode_video = Encode;
> + p_enc->fmt_in.i_codec = VLC_CODEC_I420;
I argue you need to set those after the easy fail cases.
> + switch (p_enc->fmt_out.i_codec)
> + {
> +#ifdef ENABLE_VP8_ENCODER
> + case VLC_CODEC_VP8:
> + iface = &vpx_codec_vp8_cx_algo;
> + vp_version = 8;
> + break;
> +#endif
> +#ifdef ENABLE_VP9_DECODER
> + case VLC_CODEC_VP9:
> + iface = &vpx_codec_vp9_cx_algo;
> + vp_version = 9;
> + break;
> +#endif
> + default:
> + return VLC_EGENERIC;
> + }
> +
> + p_sys = malloc(sizeof(*p_sys));
> + if (p_sys == NULL)
> + return VLC_ENOMEM;
> + p_enc->p_sys = p_sys;
> +
> + struct vpx_codec_enc_cfg enccfg = {};
Are you sure this is the correct way and this is portable?
> + enccfg.g_threads = __MIN(vlc_GetCPUCount(), 16);
16 is a bit much, no?
> +/****************************************************************************
> + * Encode: the whole thing
> + ****************************************************************************/
> +static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
> +{
> + encoder_sys_t *p_sys = p_enc->p_sys;
> + struct vpx_codec_ctx *ctx = &p_sys->ctx;
> + vlc_object_t *p_this = (vlc_object_t *)p_enc;
> +
> + if (!p_pict) return NULL;
> +
> + vpx_image_t img = {};
idem
> + unsigned i_w = p_enc->fmt_in.video.i_visible_width;
> + unsigned i_h = p_enc->fmt_in.video.i_visible_height;
> +
> + /* Create and initialize the vpx_image */
> + if (!vpx_img_alloc(&img, VPX_IMG_FMT_I420, i_w, i_h, 1)) {
> + vpx_err_msg(p_this, ctx, "Failed to allocate image: %s (%s)");
> + return NULL;
> + }
> +
> + for (int plane = 0; plane < p_pict->i_planes; plane++) {
> + uint8_t *src = p_pict->p[plane].p_pixels;
> + uint8_t *dst = img.planes[plane];
> + int src_stride = p_pict->p[plane].i_pitch;
> + int dst_stride = img.stride[plane];
> +
> + int size = __MIN(src_stride, dst_stride);
> + for (int line = 0; line < p_pict->p[plane].i_visible_lines; line++)
> + {
> + memcpy(dst, src, size);
> + src += src_stride;
> + dst += dst_stride;
> + }
> + }
Why do you need to copy here?
> + /* TODO: make quality configurable */
That shouldn't be hard to had, tbh.
> + int flags = 0;
> + vpx_codec_err_t res = vpx_codec_encode(ctx, &img, p_pict->date, 1,
> + flags, VPX_DL_BEST_QUALITY);
> + if (res != VPX_CODEC_OK) {
> + vpx_err_msg(p_this, ctx, "Failed to encode frame: %s (%s)");
> + vpx_img_free(&img);
> + return NULL;
> + }
> +
> + const vpx_codec_cx_pkt_t *pkt = NULL;
> + vpx_codec_iter_t iter = NULL;
> + block_t *p_out = NULL;
> + while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL)
> + {
> + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT)
> + {
> + int keyframe = pkt->data.frame.flags & VPX_FRAME_IS_KEY;
> + block_t *p_block = block_Alloc(pkt->data.frame.sz);
> +
> + memcpy(p_block->p_buffer, pkt->data.frame.buf, pkt->data.frame.sz);
> + p_block->i_dts = p_block->i_pts = pkt->data.frame.pts;
> + if (keyframe)
> + p_block->i_flags |= BLOCK_FLAG_TYPE_I;
> + block_ChainAppend(&p_out, p_block);
> + }
> + }
> + vpx_img_free(&img);
> + return p_out;
> +}
> +
> +/*****************************************************************************
> + * CloseEncoder: encoder destruction
> + *****************************************************************************/
> +static void CloseEncoder(vlc_object_t *p_this)
> +{
> + encoder_t *p_enc = (encoder_t *)p_this;
> + encoder_sys_t *p_sys = p_enc->p_sys;
> + if (vpx_codec_destroy(&p_sys->ctx))
> + vpx_err_msg(p_this, &p_sys->ctx, "Failed to destroy codec: %s (%s)");
> + free(p_sys);
> +}
Looks very cool, all in all, and a great addition!
With my kindest regards,
--
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device
More information about the vlc-devel
mailing list