[MPlayer-dev-eng] [PATCH] Integrate x265 into MEncoder
MChen
chenm003 at gmail.com
Wed Jul 20 00:28:09 EEST 2016
Index: Makefile
===================================================================
--- Makefile (revision 37877)
+++ Makefile (working copy)
@@ -628,6 +628,7 @@
SRCS_MENCODER-$(TWOLAME) += libmpcodecs/ae_twolame.c
SRCS_MENCODER-$(WIN32DLL) += libmpcodecs/ve_vfw.c
SRCS_MENCODER-$(X264) += libmpcodecs/ve_x264.c
+SRCS_MENCODER-$(X265) += libmpcodecs/ve_x265.c
SRCS_MENCODER-$(XVID4) += libmpcodecs/ve_xvid4.c
SRCS_MENCODER = mencoder.c \
Index: cfg-mencoder.h
===================================================================
--- cfg-mencoder.h (revision 37877)
+++ cfg-mencoder.h (working copy)
@@ -29,6 +29,7 @@
#include "libmpcodecs/ae_twolame.h"
#include "libmpcodecs/ve.h"
#include "libmpcodecs/ve_x264.h"
+#include "libmpcodecs/ve_x265.h"
#include "libmpdemux/muxer.h"
#include "libmpdemux/muxer_avi.h"
#include "cfg-common.h"
@@ -44,6 +45,9 @@
{"qtvideo", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_QTVIDEO, NULL},
{"nuv", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_NUV, NULL},
{"x264", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_X264, NULL},
+#ifdef CONFIG_X265
+ {"x265", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_X265, NULL},
+#endif
{"help", "\nAvailable codecs:\n"
" copy - frame copy, without re-encoding. Doesn't work with
filters.\n"
" frameno - special audio-only file for 3-pass encoding, see DOCS.\n"
@@ -67,6 +71,9 @@
#ifdef CONFIG_X264
" x264 - H.264 encoding\n"
#endif
+#ifdef CONFIG_X265
+ " x265 - H.265/HEVC encoding\n"
+#endif
"\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
{NULL, NULL, 0, 0, 0, 0, NULL}
};
@@ -254,6 +261,9 @@
#if defined(CONFIG_X264)
{"x264encopts", &x264enc_set_param, CONF_TYPE_FUNC_PARAM,
CONF_GLOBAL, 0, 0, NULL},
#endif
+#if defined(CONFIG_X265)
+ {"x265encopts", &x265enc_set_param, CONF_TYPE_FUNC_PARAM,
CONF_GLOBAL, 0, 0, NULL},
+#endif
#ifdef CONFIG_LIBLZO
{"nuvopts", nuvopts_conf, CONF_TYPE_SUBCONFIG, CONF_GLOBAL, 0, 0, NULL},
Index: configure
===================================================================
--- configure (revision 37877)
+++ configure (working copy)
@@ -404,6 +404,7 @@
--disable-xvid-lavc disable Xvid in libavcodec [autodetect]
--disable-x264 disable x264 [autodetect]
--disable-x264-lavc disable x264 in libavcodec [autodetect]
+ --disable-x265 disable x265 [autodetect]
--disable-libdirac-lavc disable Dirac in libavcodec [autodetect]
--disable-libschroedinger-lavc disable Dirac in libavcodec (Schroedinger
decoder) [autodetect]
@@ -799,6 +800,7 @@
_xvid_lavc=auto
_x264=auto
_x264_lavc=auto
+_x265=auto
_libdirac_lavc=auto
_libschroedinger_lavc=auto
_libvpx_lavc=auto
@@ -1254,6 +1256,8 @@
--disable-x264) _x264=no ;;
--enable-x264-lavc) _x264_lavc=yes ;;
--disable-x264-lavc) _x264_lavc=no ;;
+ --enable-x265) _x265=yes ;;
+ --disable-x265) _x265=no ;;
--enable-libdirac-lavc) _libdirac_lavc=yes ;;
--disable-libdirac-lavc) _libdirac_lavc=no ;;
--enable-libschroedinger-lavc) _libschroedinger_lavc=yes ;;
@@ -7380,6 +7384,31 @@
echores "$_x264"
+echocheck "x265"
+if test "$_x265" = auto && test "$_mencoder" = yes ; then
+ cat > $TMPC << EOF
+#include <inttypes.h>
+#include <x265.h>
+#if !(X265_BUILD >= 78)
+#error We do not support old versions of x265. Get the latest from git.
+#endif
+int main(void) { x265_encoder_open((void*)0); return 0; }
+EOF
+ _x265=no
+ for ld_x265 in "-lx265 -lstdc++ $ld_pthread" "-lx265 -lstdc++
$ld_pthread" ; do
+ cc_check $ld_x265 && libs_mencoder="$libs_mencoder $ld_x265" &&
_x265=yes && break
+ done
+fi
+
+if test "$_x265" = yes ; then
+ def_x264='#define CONFIG_X265 1'
+ codecmodules="x265 $codecmodules"
+else
+ def_x265='#undef CONFIG_X265'
+ nocodecmodules="x265 $nocodecmodules"
+fi
+echores "$_x265"
+
echocheck "libdirac"
if test "$_libdirac_lavc" = auto; then
_libdirac_lavc=no
@@ -8608,6 +8637,7 @@
WINVIDIX = $winvidix
X11 = $_x11
X264 = $_x264
+X265 = $_x265
XANIM_CODECS = $_xanim
XMGA = $_xmga
XMMS_PLUGINS = $_xmms
Index: libmpcodecs/ve.c
===================================================================
--- libmpcodecs/ve.c (revision 37877)
+++ libmpcodecs/ve.c (working copy)
@@ -36,6 +36,7 @@
extern const vf_info_t ve_info_qtvideo;
extern const vf_info_t ve_info_nuv;
extern const vf_info_t ve_info_x264;
+extern const vf_info_t ve_info_x265;
/* Please do not add any new encoders here. If you want to implement a new
* encoder, add it to libavcodec, except for wrappers around external
@@ -64,6 +65,9 @@
#ifdef CONFIG_X264
&ve_info_x264,
#endif
+#ifdef CONFIG_X265
+ &ve_info_x265,
+#endif
/* Please do not add any new encoders here. If you want to implement a new
* encoder, add it to libavcodec, except for wrappers around external
* libraries and encoders requiring binary support. */
Index: libmpcodecs/ve_x265.c
===================================================================
--- libmpcodecs/ve_x265.c (revision 0)
+++ libmpcodecs/ve_x265.c (working copy)
@@ -0,0 +1,319 @@
+/*****************************************************************************
+ *
+ * - H.265/HEVC encoder for mencoder using x265 -
+ *
+ * Copyright (C) 2016 Min Chen
+ *
+ * Written by Min Chen <chenm003 at gmail.com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *****************************************************************************/
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "mencoder.h"
+#include "m_option.h"
+#include "codec-cfg.h"
+#include "stream/stream.h"
+#include "libmpdemux/demuxer.h"
+#include "libmpdemux/stheader.h"
+#include "osdep/strsep.h"
+#include "stream/stream.h"
+#include "libmpdemux/muxer.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "ve.h"
+#include "ve_x265.h"
+
+#include <x265.h>
+
+typedef struct h265_module_t {
+ muxer_stream_t *mux;
+
+ const x265_api *api;
+ x265_encoder *encoder;
+ x265_picture pic;
+} h265_module_t;
+
+static x265_param params;
+static int parse_error = 0;
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts);
+static int encode_frame(struct vf_instance *vf, struct x265_picture *pic_in);
+
+void x265enc_set_param(const m_option_t* opt, char* arg)
+{
+ static int initialized = 0;
+ char *preset = NULL, *tune = NULL, *profile = NULL;
+ char *p, *copy, *name;
+
+ if (!initialized) {
+ x265_param_default(¶ms);
+ initialized = 1;
+ }
+
+ if (!arg) {
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option x265encopts: no
options provided\n");
+ parse_error = 1;
+ return;
+ } else if (!*arg)
+ /* Empty arguments, just doing initialization of default parameters. */
+ return;
+
+ /* Step 1: look for initial preset/tune. */
+ copy = p = strdup(arg);
+ while ((name = strsep(©, ":"))) {
+ char *value = strpbrk(name, "=:");
+ if (!value)
+ continue;
+ *value++ = 0;
+ if (!strcasecmp(name, "preset"))
+ preset = value;
+ else if (!strcasecmp(name, "tune"))
+ tune = value;
+ }
+ if (x265_param_default_preset(¶ms, preset, tune) < 0) {
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option x265encopts: Invalid
preset or tune.\n");
+ parse_error = 1;
+ }
+ free(p);
+
+ /* Step 2: explicit user overrides */
+ while ((name = strsep(&arg, ":")) && *name) {
+ int ret = 0;
+ char *value = strpbrk(name, "=:");
+
+ if (value)
+ *value++ = 0;
+ if (!strcasecmp(name, "profile"))
+ profile = value;
+ else if (strcasecmp(name, "preset") && strcasecmp(name, "tune")) {
+ ret = x265_param_parse(¶ms, name, value);
+ if (ret == X265_PARAM_BAD_NAME)
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option x265encopts:
Unknown suboption %s\n", name);
+ if (ret == X265_PARAM_BAD_VALUE)
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option x265encopts:
Bad argument %s=%s\n",
+ name, value ? value : "(null)");
+
+ }
+ /* mark this option as done, so it's not reparsed if there's
another -x265encopts */
+ *name = 0;
+
+ parse_error |= ret;
+ }
+
+ /* Step 3: enforce profile */
+ if (profile && x265_param_apply_profile(¶ms, profile) < 0)
+ parse_error = 1;
+}
+
+static int config(struct vf_instance *vf, int width, int height, int
d_width, int d_height, unsigned int flags, unsigned int outfmt) {
+ h265_module_t *mod=(h265_module_t*)vf->priv;
+
+ if(parse_error)
+ return 0;
+
+ if (!mod->api)
+ return 0;
+
+ mod->mux->bih->biWidth = width;
+ mod->mux->bih->biHeight = height;
+ mod->mux->bih->biSizeImage = width * height * 3;
+ mod->mux->aspect = (float)d_width/d_height;
+
+ // make sure param is initialized
+ x265enc_set_param(NULL, "");
+ params.sourceWidth = width;
+ params.sourceHeight = height;
+ params.fpsNum = mod->mux->h.dwRate;
+ params.fpsDenom = mod->mux->h.dwScale;
+ params.vui.sarWidth = d_width*height;
+ params.vui.sarHeight = d_height*width;
+
+ x265_param_parse(¶ms, "stats", passtmpfile);
+
+ switch(outfmt) {
+ case IMGFMT_Y8:
+ params.internalCsp = X265_CSP_I400;
+ break;
+ case IMGFMT_I420:
+ params.internalCsp = X265_CSP_I420;
+ break;
+ case IMGFMT_422P:
+ params.internalCsp = X265_CSP_I422;
+ break;
+ case IMGFMT_444P:
+ params.internalCsp = X265_CSP_I444;
+ break;
+ default:
+ mp_msg(MSGT_MENCODER, MSGL_ERR, "Wrong colorspace.\n");
+ return 0;
+ }
+
+ mod->encoder = mod->api->encoder_open(¶ms);
+ if(!mod->encoder) {
+ mp_msg(MSGT_MENCODER, MSGL_ERR, "x265_encoder_open failed.\n");
+ return 0;
+ }
+
+ if(!params.bRepeatHeaders){
+ x265_nal *nal;
+ int extradata_size, nnal;
+
+ extradata_size = mod->api->encoder_headers(mod->encoder, &nal, &nnal);
+
+ mod->mux->bih= realloc(mod->mux->bih, sizeof(*mod->mux->bih)
+ extradata_size);
+ memcpy(mod->mux->bih + 1, nal->payload, extradata_size);
+ mod->mux->bih->biSize= sizeof(*mod->mux->bih) + extradata_size;
+ }
+
+ if (params.bframes > 1 && params.bBPyramid)
+ mod->mux->decoder_delay = 2;
+ else
+ mod->mux->decoder_delay = params.bframes ? 1 : 0;
+
+ return 1;
+}
+
+static int control(struct vf_instance *vf, int request, void *data)
+{
+ h265_module_t *mod=(h265_module_t*)vf->priv;
+ switch(request){
+ case VFCTRL_FLUSH_FRAMES:
+ while (encode_frame(vf, NULL) > 0)
+ ;
+ return CONTROL_TRUE;
+ default:
+ return CONTROL_UNKNOWN;
+ }
+}
+
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
+ switch(fmt) {
+ case IMGFMT_Y8:
+ case IMGFMT_I420:
+ case IMGFMT_422P:
+ case IMGFMT_444P:
+ return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
+ default:
+ return 0; /* VFCAP_CSP_SUPPORTED */
+ }
+ return 0;
+}
+
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ h265_module_t *mod=(h265_module_t*)vf->priv;
+ int i;
+
+ mod->api->picture_init(¶ms, &mod->pic);
+ mod->pic.colorSpace = params.internalCsp;
+ for(i = 0; i < 3; i++) {
+ mod->pic.planes[i] = mpi->planes[i];
+ mod->pic.stride[i] = mpi->stride[i];
+ }
+
+ mod->pic.sliceType = X265_TYPE_AUTO;
+ if (is_forced_key_frame(pts))
+ mod->pic.sliceType = X265_TYPE_IDR;
+
+ return encode_frame(vf, &mod->pic) >= 0;
+}
+
+
+static int encode_frame(struct vf_instance *vf, struct x265_picture *pic_in)
+{
+ h265_module_t *mod=(h265_module_t*)vf->priv;
+ x265_picture pic_out;
+ x265_nal *nal;
+ int i_nal;
+ int i_encoded;
+ int i;
+
+ i_encoded = mod->api->encoder_encode(mod->encoder, &nal, &i_nal,
pic_in, &pic_out);
+
+ if(i_encoded < 0) {
+ mp_msg(MSGT_MENCODER, MSGL_ERR, "x265_encoder_encode failed\n");
+ return -1;
+ }
+ if(i_nal > 0) {
+ for(i = 0; i < i_nal; i++) {
+ int keyframe = (pic_out.sliceType == X265_TYPE_IDR);
+ int i_nal_size = (int)nal[i].sizeBytes;
+ memcpy(mod->mux->buffer, nal[i].payload, i_nal_size);
+ muxer_write_chunk(mod->mux, i_nal_size, (keyframe ?
AVIIF_KEYFRAME : 0), MP_NOPTS_VALUE, MP_NOPTS_VALUE);
+ }
+ }
+ else
+ ++mod->mux->encoder_delay;
+
+ return i_nal;
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ h265_module_t *mod=(h265_module_t*)vf->priv;
+ if (mod->api) {
+ if (mod->encoder) {
+ mod->api->encoder_close(mod->encoder);
+ mod->encoder = NULL;
+ }
+ }
+}
+
+static int vf_open(vf_instance_t *vf, char *args) {
+ h265_module_t *mod;
+
+ vf->config = config;
+ vf->default_caps = VFCAP_CONSTANT;
+ vf->control = control;
+ vf->query_format = query_format;
+ vf->put_image = put_image;
+ vf->uninit = uninit;
+ vf->priv = malloc(sizeof(h265_module_t));
+
+ mod=(h265_module_t*)vf->priv;
+ mod->mux = (muxer_stream_t*)args;
+ mod->mux->bih = calloc(1, sizeof(*mod->mux->bih));
+ mod->mux->bih->biSize = sizeof(*mod->mux->bih);
+ mod->mux->bih->biPlanes = 1;
+ mod->mux->bih->biBitCount = 24;
+ mod->mux->bih->biCompression = mmioFOURCC('H', 'E', 'V', 'C');
+ mod->api = x265_api_get(0); /* 0=auto_bit_depth, may set to
12/10/8 in future */
+
+ return 1;
+}
+
+const vf_info_t ve_info_x265 = {
+ "H.265/HEVC encoder",
+ "x265",
+ "Min Chen <chenm003 at gmail.com>",
+ "(C) 2016 Min Chen",
+ vf_open
+};
Index: libmpcodecs/ve_x265.h
===================================================================
--- libmpcodecs/ve_x265.h (revision 0)
+++ libmpcodecs/ve_x265.h (working copy)
@@ -0,0 +1,26 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_X265_H
+#define MPLAYER_X265_H
+
+#include "m_option.h"
+
+void x265enc_set_param(const m_option_t* opt, char* arg);
+
+#endif /* MPLAYER_X265_H */
Index: mencoder.c
===================================================================
--- mencoder.c (revision 37877)
+++ mencoder.c (working copy)
@@ -27,6 +27,7 @@
#define VCODEC_NUV 11
#define VCODEC_RAW 12
#define VCODEC_X264 13
+#define VCODEC_X265 14
#define ACODEC_COPY 0
#define ACODEC_PCM 1
@@ -961,6 +962,10 @@
sh_video->vfilter=vf_open_encoder(NULL,"nuv",(char *)mux_v); break;
case VCODEC_X264:
sh_video->vfilter=vf_open_encoder(NULL,"x264",(char *)mux_v); break;
+#ifdef CONFIG_X265
+ case VCODEC_X265:
+ sh_video->vfilter=vf_open_encoder(NULL,"x265",(char *)mux_v); break;
+#endif
}
if(!mux_v->bih || !sh_video->vfilter){
mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_EncoderOpenFailed);
More information about the MPlayer-dev-eng
mailing list