[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(&params);
+        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(&copy, ":"))) {
+        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(&params, 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(&params, 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(&params, 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(&params, "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(&params);
+    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(&params, &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