vlc | branch: master | Tristan Matthews <[email protected]> | Thu Feb 4 13:40:49 2016 +0100| [d4a124a3de0791a1517d08a49a2709963c911cb3] | committer: Tristan Matthews
vpx: add vp8 and vp9 encoder > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d4a124a3de0791a1517d08a49a2709963c911cb3 --- NEWS | 1 + configure.ac | 8 ++- modules/MODULES_LIST | 2 +- modules/codec/vpx.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index ee0e99e..3e69c3a 100644 --- a/NEWS +++ b/NEWS @@ -131,6 +131,7 @@ Stream Output: Encoder: * Support for Daala video in 4:2:0 and 4:4:4 + * VP8 and VP9 encoder using libvpx Muxers: * Added fragmented/streamable MP4 muxer diff --git a/configure.ac b/configure.ac index 344d93e..99fd0e8 100644 --- a/configure.ac +++ b/configure.ac @@ -2627,7 +2627,7 @@ dnl dnl libvpx decoder plugin dnl AC_ARG_ENABLE(vpx, - AS_HELP_STRING([--enable-vpx],[libvpx VP8/VP9 decoder (default auto)])) + AS_HELP_STRING([--enable-vpx],[libvpx VP8/VP9 encoder and decoder (default auto)])) AS_IF([test "${enable_vpx}" != "no"],[ PKG_CHECK_MODULES([VPX], [vpx] , [ VLC_ADD_PLUGIN([vpx]) @@ -2639,6 +2639,12 @@ AS_IF([test "${enable_vpx}" != "no"],[ AC_CHECK_LIB([vpx],[vpx_codec_vp9_dx], [ VLC_ADD_CPPFLAGS([vpx], [-DENABLE_VP9_DECODER]) ], [], [${VPX_LIBS}]) + AC_CHECK_LIB([vpx],[vpx_codec_vp8_cx], [ + VLC_ADD_CPPFLAGS([vpx], [-DENABLE_VP8_ENCODER]) + ], [], [${VPX_LIBS}]) + AC_CHECK_LIB([vpx],[vpx_codec_vp9_cx], [ + VLC_ADD_CPPFLAGS([vpx], [-DENABLE_VP9_ENCODER]) + ], [], [${VPX_LIBS}]) ], [ AS_IF([test "${enable_vpx}" = "yes"],[ AC_MSG_ERROR([libvpx was not found]) diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST index 2afbcae..394b3db 100644 --- a/modules/MODULES_LIST +++ b/modules/MODULES_LIST @@ -438,7 +438,7 @@ $Id$ * vout_ios2: iOS video provider using OpenGL ES 2 * vout_macosx: Mac OS X OpenGL provider * vout_sdl: video output module using the SDL library - * vpx: WebM decoder (VP8/VP9) + * vpx: WebM encoder and decoder (VP8/VP9) * vsxu: audio visualization using Vovoid VSXu * wall: image wall filter * wasapi: Wasapi audio output module diff --git a/modules/codec/vpx.c b/modules/codec/vpx.c index 09578bc..d774271 100644 --- a/modules/codec/vpx.c +++ b/modules/codec/vpx.c @@ -34,11 +34,28 @@ #include <vpx/vpx_decoder.h> #include <vpx/vp8dx.h> +#ifdef ENABLE_SOUT +# include <vpx/vpx_encoder.h> +# include <vpx/vp8cx.h> +#endif + /**************************************************************************** * Local prototypes ****************************************************************************/ +static const char *const ppsz_sout_options[] = { "quality-mode", NULL }; static int OpenDecoder(vlc_object_t *); static void CloseDecoder(vlc_object_t *); +#ifdef ENABLE_SOUT +static int OpenEncoder(vlc_object_t *); +static void CloseEncoder(vlc_object_t *); +static block_t *Encode(encoder_t *p_enc, picture_t *p_pict); + +#define QUALITY_MODE_TEXT N_("Quality mode") +#define QUALITY_MODE_LONGTEXT N_("Quality setting which will determine max encoding time, default 0\n" \ + " - 0: Good quality\n"\ + " - 1: Realtime\n"\ + " - 2: Best quality") +#endif /***************************************************************************** * Module descriptor @@ -51,6 +68,17 @@ vlc_module_begin () set_callbacks(OpenDecoder, CloseDecoder) set_category(CAT_INPUT) set_subcategory(SUBCAT_INPUT_VCODEC) +#ifdef ENABLE_SOUT + add_submodule() + set_shortname("vpx") + set_capability("encoder", 60) + set_description(N_("WebM video encoder")) + set_callbacks(OpenEncoder, CloseEncoder) +# define ENC_CFG_PREFIX "sout-vpx-" + add_integer( ENC_CFG_PREFIX "quality-mode", VPX_DL_GOOD_QUALITY, QUALITY_MODE_TEXT, + QUALITY_MODE_LONGTEXT, true ) + change_integer_range( 0, 2 ) +#endif vlc_module_end () static void vpx_err_msg(vlc_object_t *this, struct vpx_codec_ctx *ctx, @@ -235,3 +263,161 @@ static void CloseDecoder(vlc_object_t *p_this) free(sys); } + +#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; + + /* Allocate the memory needed to store the encoder's structure */ + p_sys = malloc(sizeof(*p_sys)); + if (p_sys == NULL) + return VLC_ENOMEM; + p_enc->p_sys = p_sys; + + const struct vpx_codec_iface *iface; + int vp_version; + + 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; + } + + struct vpx_codec_enc_cfg enccfg = {}; + vpx_codec_enc_config_default(iface, &enccfg, 0); + enccfg.g_threads = __MIN(vlc_GetCPUCount(), 4); + enccfg.g_w = p_enc->fmt_in.video.i_visible_width; + enccfg.g_h = p_enc->fmt_in.video.i_visible_height; + + msg_Dbg(p_this, "VP%d: using libvpx version %s (build options %s)", + vp_version, vpx_codec_version_str(), vpx_codec_build_config()); + + struct vpx_codec_ctx *ctx = &p_sys->ctx; + if (vpx_codec_enc_init(ctx, iface, &enccfg, 0) != VPX_CODEC_OK) { + VPX_ERR(p_this, ctx, "Failed to initialize encoder"); + free(p_sys); + return VLC_EGENERIC; + } + + p_enc->pf_encode_video = Encode; + p_enc->fmt_in.i_codec = VLC_CODEC_I420; + config_ChainParse(p_enc, ENC_CFG_PREFIX, ppsz_sout_options, p_enc->p_cfg); + + return VLC_SUCCESS; +} + +/**************************************************************************** + * 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; + + if (!p_pict) return NULL; + + vpx_image_t img = {}; + 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(p_enc, ctx, "Failed to allocate image"); + 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; + } + } + + int flags = 0; + /* Deadline (in ms) to spend in encoder */ + int quality = VPX_DL_GOOD_QUALITY; + switch (var_GetInteger(p_enc, ENC_CFG_PREFIX "quality-mode")) { + case 1: + quality = VPX_DL_REALTIME; + break; + case 2: + quality = VPX_DL_BEST_QUALITY; + break; + default: + break; + } + + vpx_codec_err_t res = vpx_codec_encode(ctx, &img, p_pict->date, 1, + flags, quality); + if (res != VPX_CODEC_OK) { + VPX_ERR(p_enc, ctx, "Failed to encode frame"); + 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(p_this, &p_sys->ctx, "Failed to destroy codec"); + free(p_sys); +} + +#endif /* ENABLE_SOUT */ _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
