vlc | branch: master | Tristan Matthews <tma...@videolan.org> | Tue Dec 26 18:33:24 2017 -0500| [4080da1f9e6c542a4be336d54403e52fe26ed8c8] | committer: Tristan Matthews
aom: add AV1 encoding Supports I420 10 bpp and 8bpp. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=4080da1f9e6c542a4be336d54403e52fe26ed8c8 --- NEWS | 2 + modules/MODULES_LIST | 2 +- modules/codec/aom.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 6081cac9ac..e69d974f94 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ Platform support changes: - Android 4.1.x or later (API-16) - GCC 5.0 or Clang 3.4 (or equivalent) +Codecs: + * Support for experimental AV1 video encoding Changes between 2.2.x and 3.0.0-git: -------------------------------- diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST index 1d0fe9bae4..280ea264cc 100644 --- a/modules/MODULES_LIST +++ b/modules/MODULES_LIST @@ -41,7 +41,7 @@ $Id$ * android_logger: logger output to native Android logs (adb logcat) * android_window: Android direct/undirect rendering video output * antiflicker: anti-flicker video filter - * aom: AOM decoder (AV1) + * aom: AOM encoder and decoder (AV1) * araw: Pseudo audio decoder for raw PCM * archive: libarchive based access and stream filter and stream_extractor * aribcam: ARIB STD-B25 decoder/virtual CAM diff --git a/modules/codec/aom.c b/modules/codec/aom.c index 0f3b866ee9..65055b80c2 100644 --- a/modules/codec/aom.c +++ b/modules/codec/aom.c @@ -35,11 +35,21 @@ #include <aom/aom_decoder.h> #include <aom/aomdx.h> +#ifdef ENABLE_SOUT +# include <aom/aomcx.h> +# include <aom/aom_image.h> +#endif + /**************************************************************************** * Local prototypes ****************************************************************************/ 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); +#endif /***************************************************************************** * Module descriptor @@ -52,6 +62,13 @@ vlc_module_begin () set_callbacks(OpenDecoder, CloseDecoder) set_category(CAT_INPUT) set_subcategory(SUBCAT_INPUT_VCODEC) +#ifdef ENABLE_SOUT + add_submodule() + set_shortname("aom") + set_capability("encoder", 60) + set_description(N_("AOM video encoder")) + set_callbacks(OpenEncoder, CloseEncoder) +#endif vlc_module_end () static void aom_err_msg(vlc_object_t *this, aom_codec_ctx_t *ctx, @@ -307,3 +324,159 @@ static void CloseDecoder(vlc_object_t *p_this) free(sys); } + +#ifdef ENABLE_SOUT + +/***************************************************************************** + * encoder_sys_t: libaom encoder descriptor + *****************************************************************************/ +struct encoder_sys_t +{ + struct aom_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; + + if (p_enc->fmt_out.i_codec != VLC_CODEC_AV1) + return VLC_EGENERIC; + + /* 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 aom_codec_iface *iface = &aom_codec_av1_cx_algo; + + struct aom_codec_enc_cfg enccfg = {}; + aom_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; + + int enc_flags; + switch (p_enc->fmt_in.i_codec) { + case VLC_CODEC_I420_10L: + enc_flags = AOM_CODEC_USE_HIGHBITDEPTH; + /* Profile 1: 10-bit and 12-bit color only, with 4:2:0 sampling. */ + enccfg.g_profile = 2; + enccfg.g_bit_depth = 10; + break; + case VLC_CODEC_I420: + enc_flags = 0; + /* Profile 0: 8-bit 4:2:0 only. */ + enccfg.g_profile = 0; + enccfg.g_bit_depth = 8; + break; + default: + msg_Err(p_this, "Unsupported input format %s", + vlc_fourcc_GetDescription(VIDEO_ES, p_enc->fmt_in.i_codec)); + free(p_sys); + return VLC_EGENERIC; + } + + msg_Dbg(p_this, "AV1: using libaom version %s (build options %s)", + aom_codec_version_str(), aom_codec_build_config()); + + struct aom_codec_ctx *ctx = &p_sys->ctx; + if (aom_codec_enc_init(ctx, iface, &enccfg, enc_flags) != AOM_CODEC_OK) + { + AOM_ERR(p_this, ctx, "Failed to initialize encoder"); + free(p_sys); + return VLC_EGENERIC; + } + + p_enc->pf_encode_video = Encode; + + 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 aom_codec_ctx *ctx = &p_sys->ctx; + + if (!p_pict) return NULL; + + aom_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; + const aom_img_fmt_t img_fmt = p_enc->fmt_in.i_codec == VLC_CODEC_I420_10L ? + AOM_IMG_FMT_I42016 : AOM_IMG_FMT_I420; + + /* Create and initialize the aom_image */ + if (!aom_img_alloc(&img, img_fmt, i_w, i_h, 16)) + { + AOM_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++) + { + /* FIXME: do this in-place */ + memcpy(dst, src, size); + src += src_stride; + dst += dst_stride; + } + } + + aom_codec_err_t res = aom_codec_encode(ctx, &img, p_pict->date, 1, 0, + AOM_DL_GOOD_QUALITY); + if (res != AOM_CODEC_OK) { + AOM_ERR(p_enc, ctx, "Failed to encode frame"); + aom_img_free(&img); + return NULL; + } + + const aom_codec_cx_pkt_t *pkt = NULL; + aom_codec_iter_t iter = NULL; + block_t *p_out = NULL; + while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) + { + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) + { + int keyframe = pkt->data.frame.flags & AOM_FRAME_IS_KEY; + block_t *p_block = block_Alloc(pkt->data.frame.sz); + + /* FIXME: do this in-place */ + 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); + } + } + aom_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 (aom_codec_destroy(&p_sys->ctx)) + AOM_ERR(p_this, &p_sys->ctx, "Failed to destroy codec"); + free(p_sys); +} + +#endif /* ENABLE_SOUT */ _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits