[vlc-devel] [PATCH 1/2] Add x265 params support to VLC streaming module

mahesh at multicorewareinc.com mahesh at multicorewareinc.com
Mon Jul 11 15:09:08 CEST 2016


From: Mahesh <mahesh at multicorewareinc.com>

---
 modules/codec/Makefile.am |   4 +-
 modules/codec/x265.c      | 961 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 904 insertions(+), 61 deletions(-)

diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 0a23411..6967340 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -449,10 +449,10 @@ endif
 ### X26x encoders ###
 
 libx265_plugin_la_SOURCES = codec/x265.c
-libx265_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
+libx265_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DMODULE_NAME_IS_x265
 libx265_plugin_la_CFLAGS = $(AM_CFLAGS) $(CFLAGS_x265)
 libx265_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_x265) -rpath '$(codecdir)'
-libx265_plugin_la_LIBADD = $(LIBS_x265)
+libx265_plugin_la_LIBADD = $(LIBS_x265) $(LIBM)
 EXTRA_LTLIBRARIES += libx265_plugin.la
 codec_LTLIBRARIES += $(LTLIBx265)
 
diff --git a/modules/codec/x265.c b/modules/codec/x265.c
index c35cf4c..7dc016e 100644
--- a/modules/codec/x265.c
+++ b/modules/codec/x265.c
@@ -4,6 +4,8 @@
  * Copyright (C) 2013 Rafaël Carré
  *
  * Authors: Rafaël Carré <funman at videolanorg>
+ *          Mahesh Pittala <mahesh at multicorewareinc.com>
+ *          Gopi Akisetty <gopi.satykrishna at multicorewareinc.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,6 +25,7 @@
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
@@ -30,26 +33,502 @@
 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_threads.h>
 #include <vlc_sout.h>
 #include <vlc_codec.h>
+#include <vlc_charset.h>
+#include <vlc_cpu.h>
+#include <math.h>
+#include <stdio.h>
+#ifdef PTW32_STATIC_LIB
+#include <pthread.h>
+#endif
 
+#include <assert.h>
 #include <x265.h>
 
+#ifdef MODULE_NAME_IS_x265
+#define SOUT_CFG_PREFIX "sout-x265-"
+#endif
+
+#define INT_MAX 2147483647
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-static int  Open (vlc_object_t *);
-static void Close(vlc_object_t *);
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+static void x265_log( void *, int i_level, const char *psz, va_list );
+
+#define LONGTEXT N_( "Please go through x265 readthedocs for full " \
+    "information - https://x265.readthedocs.org/en/default/cli.html " )
+
+/* Frame-type options */
+
+#define KEYINT_TEXT N_("Max intra period in frames")
+
+#define MIN_KEYINT_TEXT N_("Minimum GOP size")
+
+#define OPENGOP_TEXT N_("Enable open GOP, allow I-slices to be non-IDR")
+
+#define SCENE_TEXT N_("Extra I-frames aggressivity")
+
+#define BFRAMES_TEXT N_("Maxinum number of consecutive B-frames")
+
+#define B_ADAPT_TEXT N_("Set the level of effort in determining B frame "  \
+        "placement")
+
+#define B_BIAS_TEXT N_("Bias towards B frames in slicetype decision")
+
+#define BPYRAMID_TEXT N_("Use B-frames as references, when possible")
+
+#define REF_TEXT N_("Max number of L0 references to be allowed")
+
+#define FILTER_TEXT N_("Loop filter AlphaC0 and Beta parameters alpha:beta")
+
+#define LEVEL_TEXT N_("HEVC level")
+
+#define PROFILE_TEXT N_("HEVC profile")
+
+#define INTERLACED_TEXT N_("Interlaced mode")
+
+#define INTRAREFRESH_TEXT N_("Enables Periodic Intra Refresh(PIR) instead of" \
+        "keyframe insertion")
+
+#define REPEATHEADERS_TEXT N_("If enabled, x265 will emit VPS, SPS, and PPS "  \
+        "headers with every keyframe")
+
+/* Ratecontrol */
+
+#define QP_TEXT N_("Set QP")
+
+#define CRF_TEXT N_("Quality-controlled variable bitrate")
+
+#define BITRATE_TEXT N_("Bitrate")
+
+#define VBV_MAXRATE_TEXT N_("Max local bitrate")
+
+#define VBV_BUFSIZE_TEXT N_("VBV buffer")
+
+#define VBV_INIT_TEXT N_("Initial VBV buffer occupancy")
+
+#define AQ_MODE_TEXT N_("Adaptive Quantization operating mode")
+
+#define AQ_STRENGTH_TEXT N_("Adjust the strength of the adaptive "  \
+        "quantization offsets")
+
+#define IPRATIO_TEXT N_("QP factor between I and P")
+
+#define PBRATIO_TEXT N_("QP factor between P and B")
+
+#define CHROMAB_QP_OFFSET_TEXT N_("Offset of Cb chroma QP from the luma " \
+        "QP selected by rate control")
+
+#define CHROMAR_QP_OFFSET_TEXT N_("Offset of Cr chroma QP from the luma " \
+        "QP selected by rate contro")
+
+#define PASS_TEXT N_("Enable multi-pass rate control mode")
+
+#define QCOMP_TEXT N_("qComp sets the quantizer curve compression factor")
+
+#define CPLXBLUR_TEXT N_("Reduce fluctuations in QP")
+
+#define QBLUR_TEXT N_("temporally blur complexity")
+
+/* Analysis */
+
+#define WEIGHTB_TEXT N_("Enable weighted prediction in B slices")
+
+#define WEIGHTP_TEXT N_("Enable weighted prediction in P slices")
+
+
+#define ME_TEXT N_("Integer pixel motion estimation method")
+
+#define MERANGE_TEXT N_("Maximum motion vector search range")
+
+#define PSY_RD_TEXT N_("Strength of psychovisual optimization")
+
+#define SUBME_TEXT N_("Amount of subpel refinement to perform")
+
+#define NRINTRA_TEXT N_("Noise reduction")
+
+#define NRINTER_TEXT N_("Noise reduction")
+
+#define TSKIPFAST_TEXT N_("Only evaluate transform skip for NxN intra " \
+        "predictions (4x4 blocks)")
+
+#define CTU_TEXT N_("Maximum CU size (width and height)")
+
+#define MINCUSIZE_TEXT N_("Minimum CU size (width and height)")
+
+#define RCLOOKAHEAD_TEXT N_("Number of frames for slice-type decision" \
+       "lookahead")
+
+#define LIMITREFS_TEXT N_("limit the references analyzed")
+
+#define RECT_TEXT N_("Enable analysis of rectangular motion partitions" \
+        "Nx2N and 2NxN")
+
+#define AMP_TEXT N_("Enable analysis of asymmetric motion partitions " \
+        "(75/25 splits, four directions)")
+
+#define LIMITMODES_TEXT N_("limit-modes will limit modes analyzed for " \
+        "each CU using cost metrics from the 4 sub-CUs")
+
+#define MAXMERGE_TEXT N_("Maximum number of neighbor (spatial and temporal)" \
+        "candidate blocks")
+
+#define EARLYSKIP_TEXT N_("Measure 2Nx2N merge candidates first, if no" \
+       "residual is found, additional modes at that depth are not analysed")
+
+#define FASTINTRA_TEXT N_("Perform an initial scan of every fifth intra")  
+        
+#define BINTRA_TEXT N_("Evaluation of intra modes in B slices")
+
+#define SAO_TEXT N_("Toggle Sample Adaptive Offset loop filter")
+
+#define SIGNHIDE_TEXT N_("Hide sign bit of one coeff per TU (rdo)")
+
+#define CUTREE_TEXT N_("Enable the use of lookaheads lowres motion" \
+        "vector fields")
+
+#define RD_TEXT N_("Level of RDO in mode decision")
+
+#define RDOQLEVEL_TEXT N_("amount of rate-distortion analysis to use within"  \
+        "quantization")
+
+#define TUINTRA_TEXT N_("Limits the number of extra recursion depth which" \
+        "can be attempted for intra coded units")
+
+#define TUINTER_TEXT N_("Limits the number of extra recursion depth which" \
+        "can be attempted for inter coded units")
+
+#define QPSTEP_TEXT N_("The maximum single adjustment in QP allowed")
+
+#define PSYRDOQ_TEXT N_("Influence rate distortion optimized quantization by" \
+        "favoring higher energy in the reconstructed image")
+
+#define FRAMETHREADS_TEXT N_("Number of concurrently encoded frames")
+
+#define PMODE_TEXT N_("Parallel mode decision, or distributed mode analysis")
+
+#define PME_TEXT N_("Parallel motion estimation")
+
+#define QGSIZE_TEXT N_("Minimum CU size at which QP can be adjusted")
+
+
+/* Input/Output */
+
+#define ASM_TEXT N_("CPU optimizations")
+
+#define PSNR_TEXT N_("PSNR computation")
+
+#define SSIM_TEXT N_("SSIM computation")
+
+#define AUD_TEXT N_("Access unit delimiters")
+
+#define LOOKAHEAD_SLICES_TEXT N_("Use multiple worker threads to measure the estimated cost " \
+    "of each frame within the lookahead")
+
+#define HRD_TEXT N_("HRD-timing information")
+
+#define TUNE_TEXT N_("Default tune setting used" )
+
+#define PRESET_TEXT N_("Default preset setting used" )
+
+
+static const char *const enc_me_list[] =
+  { "dia", "hex", "umh", "star", "full" };
+static const char *const enc_me_list_text[] =
+  { N_("dia"), N_("hex"), N_("umh"), N_("star"), N_("full") };
 
 vlc_module_begin ()
-    set_description(N_("H.265/HEVC encoder (x265)"))
-    set_capability("encoder", 200)
-    set_callbacks(Open, Close)
-    set_category(CAT_INPUT)
-    set_subcategory(SUBCAT_INPUT_VCODEC)
+
+#ifdef MODULE_NAME_IS_x265
+    set_description( N_("H.265/HEVC encoder (x265)"))
+    set_capability( "encoder", 200 )
+    set_callbacks( Open, Close )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_VCODEC )
+#endif
+/* Frame-type options */
+
+    add_integer( SOUT_CFG_PREFIX "keyint", 250, KEYINT_TEXT,
+                 LONGTEXT, false )
+
+    add_integer( SOUT_CFG_PREFIX "min-keyint", 25, MIN_KEYINT_TEXT,
+                 LONGTEXT, true )
+ 
+    add_bool( SOUT_CFG_PREFIX "open-gop", true, OPENGOP_TEXT,
+              LONGTEXT, true )
+   
+    add_integer( SOUT_CFG_PREFIX "scenecut", 40, SCENE_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( -1, 100 )
+
+    add_integer( SOUT_CFG_PREFIX "bframes", 4, BFRAMES_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( 0, 16 )
+
+    add_integer( SOUT_CFG_PREFIX "b-adapt", 2, B_ADAPT_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( 0, 2 )
+   
+    add_integer( SOUT_CFG_PREFIX "bframe-bias", 0, B_BIAS_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( -100, 100 )
+
+    add_bool( SOUT_CFG_PREFIX "b-pyramid", true, BPYRAMID_TEXT,
+                LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "b-pyramid", true, BPYRAMID_TEXT,
+                LONGTEXT, true )
+        
+    add_integer( SOUT_CFG_PREFIX "ref", 3, REF_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( 1, 16 )
+
+    add_string( SOUT_CFG_PREFIX "deblock", "0:0", FILTER_TEXT,
+                LONGTEXT, true )
+
+    add_float( SOUT_CFG_PREFIX "psy-rd", 1.0, PSY_RD_TEXT,
+               LONGTEXT, true )
+
+    add_string( SOUT_CFG_PREFIX "level-idc", "0", LEVEL_TEXT,
+                LONGTEXT, false )
+
+    add_string( SOUT_CFG_PREFIX "profile", "main", PROFILE_TEXT,
+                LONGTEXT, false )
+        vlc_config_set (VLC_CONFIG_LIST,
+            (sizeof(x265_profile_names) / sizeof (char*)) - 1,
+            x265_profile_names, x265_profile_names);
+
+    add_bool( SOUT_CFG_PREFIX "interlace", false, INTERLACED_TEXT, LONGTEXT,
+              true ) 
+    
+    add_bool( SOUT_CFG_PREFIX "hrd", false, HRD_TEXT, LONGTEXT, true )
+ 
+    add_bool( SOUT_CFG_PREFIX "repeat-headers", false, REPEATHEADERS_TEXT,
+              LONGTEXT, true )
+    
+      
+
+/* Ratecontrol */
+
+    add_integer( SOUT_CFG_PREFIX "qp", 0, QP_TEXT, LONGTEXT,
+                 true )
+        change_integer_range( 0, 51 ) /* QP 0 -> lossless encoding */
+    
+    add_integer( SOUT_CFG_PREFIX "bitrate", 0, BITRATE_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "crf", 28, CRF_TEXT,
+                 LONGTEXT, true )
+        change_integer_range( 0, 51 )
+
+    add_integer( SOUT_CFG_PREFIX "vbv-maxrate", 0, VBV_MAXRATE_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "vbv-bufsize", 0, VBV_BUFSIZE_TEXT,
+                 LONGTEXT, true )
+
+    add_float( SOUT_CFG_PREFIX "vbv-init", 0.9, VBV_INIT_TEXT,
+               LONGTEXT, true )
+        change_float_range( 0, 1 )
+
+    add_integer( SOUT_CFG_PREFIX "cbqpoffs", 0, CHROMAB_QP_OFFSET_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "crqpoffs", 0, CHROMAR_QP_OFFSET_TEXT,
+                 LONGTEXT, true )
+
+    add_float( SOUT_CFG_PREFIX "ipratio", 1.40, IPRATIO_TEXT,
+               LONGTEXT, true )
+        change_float_range( 1, 2 )
+
+    add_float( SOUT_CFG_PREFIX "pbratio", 1.30, PBRATIO_TEXT,
+               LONGTEXT, true )
+        change_float_range( 1, 2 )
+
+    add_integer( SOUT_CFG_PREFIX "pass", 0, PASS_TEXT,
+                 LONGTEXT, false )
+        change_integer_range( 0, 3 )
+
+    add_float( SOUT_CFG_PREFIX "qcomp", 0.60, QCOMP_TEXT,
+               LONGTEXT, true )
+        change_float_range( 0, 1 )
+
+    add_integer( SOUT_CFG_PREFIX "aq-mode", X265_AQ_VARIANCE, AQ_MODE_TEXT,
+                 LONGTEXT, true )
+         change_integer_range( 0, 3)
+    
+    add_float( SOUT_CFG_PREFIX "aq-strength", 1.0, AQ_STRENGTH_TEXT,
+               LONGTEXT, true )
+   
+    add_float( SOUT_CFG_PREFIX "cplxblur", 20.0, CPLXBLUR_TEXT,
+               LONGTEXT, true )
+    
+    add_float( SOUT_CFG_PREFIX "qblur", 0.5, QBLUR_TEXT,
+               LONGTEXT, true )  
+
+/* Analysis */
+
+     
+    add_bool( SOUT_CFG_PREFIX "weightb", false, WEIGHTB_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "tskip-fast", false, TSKIPFAST_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "tskip-fast", false, TSKIPFAST_TEXT,
+              LONGTEXT, true )
+   
+    add_bool( SOUT_CFG_PREFIX "weightp", true, WEIGHTP_TEXT,
+                 LONGTEXT, true )
+        
+    add_string( SOUT_CFG_PREFIX "me", "hex", ME_TEXT,
+                LONGTEXT, true )
+        change_string_list( enc_me_list, enc_me_list_text )
+
+    add_integer( SOUT_CFG_PREFIX "merange", 57, MERANGE_TEXT,
+                 LONGTEXT, true )
+   
+    add_integer( SOUT_CFG_PREFIX "subme", 2, SUBME_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "lookahead-slices", 0, LOOKAHEAD_SLICES_TEXT,
+                 LONGTEXT, true )
+    
+    add_bool( SOUT_CFG_PREFIX "intra-refresh", false, INTRAREFRESH_TEXT,
+              LONGTEXT, true )
+   
+    add_integer( SOUT_CFG_PREFIX "nr-intra", 0, NRINTRA_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "nr-inter", 0, NRINTER_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "ctu", 64, CTU_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "min-cu-size", 8, MINCUSIZE_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "rc-lookahead", 20, RCLOOKAHEAD_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "limit-refs", 3, LIMITREFS_TEXT,
+                 LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "rect", false, RECT_TEXT,
+              LONGTEXT, true )
+   
+    add_bool( SOUT_CFG_PREFIX "amp", false, AMP_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "limit-modes", false, LIMITMODES_TEXT,
+              LONGTEXT, true )
+    
+    add_integer( SOUT_CFG_PREFIX "max-merge", 2, MAXMERGE_TEXT,
+                 LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "early-skip", false, EARLYSKIP_TEXT,
+              LONGTEXT, true )
+    
+    add_bool( SOUT_CFG_PREFIX "fast-intra", false, FASTINTRA_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "b-intra", false, BINTRA_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "sao", true, SAO_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "signhide", true, SIGNHIDE_TEXT,
+              LONGTEXT, true )
+    
+    add_bool( SOUT_CFG_PREFIX "cutree", true, CUTREE_TEXT,
+              LONGTEXT, true )
+    
+    add_integer( SOUT_CFG_PREFIX "rd", 3, RD_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "rdoq-level", 0, RDOQLEVEL_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "tu-intra", 1, TUINTRA_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "tu-inter", 1, TUINTER_TEXT,
+                 LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "qpstep", 4, QPSTEP_TEXT,
+                 LONGTEXT, true )
+
+    add_float( SOUT_CFG_PREFIX "psy-rdoq", 0.0, PSYRDOQ_TEXT,
+               LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "frame-threads", 0, FRAMETHREADS_TEXT,
+                 LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "pmode", false, PMODE_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "pme", false, PME_TEXT,
+              LONGTEXT, true )
+
+    add_integer( SOUT_CFG_PREFIX "qg-size", 32, QGSIZE_TEXT,
+                 LONGTEXT, true )
+
+    
+/* Input/Output */
+
+    add_bool( SOUT_CFG_PREFIX "asm", true, ASM_TEXT,
+              LONGTEXT, true )
+
+     //x265 psnr = 1 (default). disable PSNR computation for speed. 
+    add_bool( SOUT_CFG_PREFIX "psnr", false, PSNR_TEXT,
+              LONGTEXT, true )
+
+    /* x265 ssim = 1 (default). disable SSIM computation for speed. */
+    add_bool( SOUT_CFG_PREFIX "ssim", false, SSIM_TEXT,
+              LONGTEXT, true )
+
+    add_bool( SOUT_CFG_PREFIX "aud", false, AUD_TEXT,
+              LONGTEXT, true )
+    
+    add_string( SOUT_CFG_PREFIX "preset", NULL , PRESET_TEXT , PRESET_TEXT, false )
+        vlc_config_set (VLC_CONFIG_LIST,
+            (sizeof(x265_preset_names) / sizeof (char*)) - 1,
+            x265_preset_names, x265_preset_names);
+    
+    add_string( SOUT_CFG_PREFIX "tune", NULL , TUNE_TEXT, TUNE_TEXT, false )
+        vlc_config_set (VLC_CONFIG_LIST,
+            (sizeof(x265_tune_names) / sizeof (char*)) - 1,
+            x265_tune_names, x265_tune_names);
+
 vlc_module_end ()
 
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static const char *const ppsz_sout_options[] = {
+    "aud", "bframes", "b-pyramid", "b-adapt", "bframe-bias", "cbqpoffs",
+    "crqpoffs", "cplxblur", "crf", "deblock", "interlace", "ipratio", "keyint",
+    "level-idc", "me", "merange", "min-keyint", "pass", "pbratio", "psnr",
+    "qblur", "qp", "qcomp", "ref", "scenecut", "ssim", "subme", "vbv-bufsize",
+    "vbv-init", "vbv-maxrate", "weightb", "weightp", "aq-mode", "aq-strength",
+    "psy-rd", "profile", "lookahead-slices", "intra-refresh", "hrd", "tune",
+    "preset", "open-gop", "bitrate", "nr-intra", "nr-inter", "tskip-fast",
+    "repeat-headers", "ctu", "min-cu-size", "rc-lookahead", "limit-refs",
+    "rect", "amp", "limit-modes", "max-merge", "early-skip", "fast-intra",
+    "b-intra", "sao", "signhide", "cutree", "rd", "rdoq-level",
+    "tu-intra", "tu-inter", "tune", "qpstep", "psy-rdoq", "frame-threads",
+    "pmode", "pme", "qg-size",
+    NULL
+};
+
+static block_t *Encode( encoder_t *, picture_t * );
+
 struct encoder_sys_t
 {
     x265_encoder    *h;
@@ -59,11 +538,49 @@ struct encoder_sys_t
 
     mtime_t         dts;
     mtime_t         initial_date;
+    char            *psz_stat_name;
+    int             i_sei_size;
+    uint32_t        i_colorspace;
+    uint8_t         *p_sei;
 #ifndef NDEBUG
     mtime_t         start;
 #endif
 };
 
+#ifdef PTW32_STATIC_LIB
+static vlc_mutex_t pthread_win32_mutex = VLC_STATIC_MUTEX;
+static int pthread_win32_count = 0;
+#endif
+
+/****************************************************************************
+ * Logging
+ ****************************************************************************/
+static void x265_log( void *data, int i_level, const char *psz, va_list args)
+{
+    encoder_t *p_enc = (encoder_t *)data;
+
+    switch( i_level )
+    {
+        case X265_LOG_ERROR:
+            i_level = VLC_MSG_ERR;
+            break;
+        case X265_LOG_WARNING:
+            i_level = VLC_MSG_WARN;
+            break;
+        case X265_LOG_INFO:
+            i_level = VLC_MSG_INFO;
+            break;
+        case X265_LOG_DEBUG:
+        default:
+            i_level = VLC_MSG_DBG;
+    }
+
+    msg_GenericVa( p_enc, i_level, psz, args );
+};
+
+/****************************************************************************
+ * Encode:
+ ****************************************************************************/
 static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
 {
     encoder_sys_t *p_sys = p_enc->p_sys;
@@ -90,7 +607,7 @@ static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
     uint32_t i_nal = 0;
     x265_encoder_encode(p_sys->h, &nal, &i_nal,
             likely(p_pict) ? &pic : NULL, &pic);
-
+    
     if (!i_nal)
         return NULL;
 
@@ -136,73 +653,377 @@ static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
     return p_block;
 }
 
-static int  Open (vlc_object_t *p_this)
+/*****************************************************************************
+ * Open: probe the encoder
+ *****************************************************************************/
+static int  Open ( 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_HEVC && !p_enc->obj.force)
+    int i_val, j_val;
+    char *psz_val;
+    int i_qmin = 0, i_qmax = 0;
+    x265_nal    *nal;
+    int i, i_nal;
+    bool fullrange = false;
+    if( p_enc->fmt_out.i_codec != VLC_CODEC_HEVC && !p_enc->b_force )
+    {
         return VLC_EGENERIC;
-
+    }
+        
+    config_ChainParse( p_enc, SOUT_CFG_PREFIX, ppsz_sout_options, p_enc->p_cfg );
+    
     p_enc->fmt_out.i_cat = VIDEO_ES;
+
     p_enc->fmt_out.i_codec = VLC_CODEC_HEVC;
-    p_enc->p_sys = p_sys = malloc(sizeof(encoder_sys_t));
-    if (!p_sys)
-        return VLC_ENOMEM;
 
+    p_enc->p_sys = p_sys = malloc( sizeof( encoder_sys_t ) );
+    if( !p_sys )
+        return VLC_ENOMEM;    
+    
     p_enc->fmt_in.i_codec = VLC_CODEC_I420;
+    p_sys->i_colorspace = X265_CSP_I420;
 
-    x265_param *param = &p_sys->param;
-    x265_param_default(param);
+    p_enc->pf_encode_video = Encode;
+    p_enc->pf_encode_audio = NULL;
+    p_sys->i_initial_delay = 0;
+    p_sys->psz_stat_name = NULL;
+    p_sys->i_sei_size = 0;
+    p_sys->p_sei = NULL;
+    char *psz_preset = NULL;
+    char *psz_tune = NULL
+    psz_preset = var_GetNonEmptyString( p_enc, SOUT_CFG_PREFIX  "preset" );
+    psz_tune = var_GetNonEmptyString( p_enc, SOUT_CFG_PREFIX  "tune" );
+    
+    x265_param_default_preset( &p_sys->param, psz_preset, psz_tune );
+        
+    free( psz_preset );
+    free( psz_tune );
+    p_sys->param.internalCsp = p_sys->i_colorspace;
 
-    param->frameNumThreads = vlc_GetCPUCount();
-    param->bEnableWavefront = 0; // buggy in x265, use frame threading for now
-    param->maxCUSize = 16; /* use smaller macroblock */
+    if( fabs(var_GetFloat( p_enc, SOUT_CFG_PREFIX "qcomp" ) - 0.60) > 0.005 )
+       p_sys->param.rc.qCompress = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qcomp" );
 
-#if X265_BUILD >= 6
-    param->fpsNum = p_enc->fmt_in.video.i_frame_rate;
-    param->fpsDenom = p_enc->fmt_in.video.i_frame_rate_base;
-    if (!param->fpsNum) {
-        param->fpsNum = 25;
-        param->fpsDenom = 1;
+    /* transcode-default bitrate is 0,
+     * set more to ABR if user specifies bitrate */
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "bitrate" );
+    j_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qp" );
+    if( i_val > 0 || p_enc->fmt_out.i_bitrate > 0)
+    {
+        p_sys->param.rc.bitrate = ((i_val > 0) ? i_val : p_enc->fmt_out.i_bitrate/1000);
+        p_sys->param.rc.rateControlMode = X265_RC_ABR;
     }
-#else
-    if (p_enc->fmt_in.video.i_frame_rate_base) {
-        param->frameRate = p_enc->fmt_in.video.i_frame_rate /
-            p_enc->fmt_in.video.i_frame_rate_base;
-    } else {
-        param->frameRate = 25;
+    else if( j_val > 0)
+    {
+       if( j_val > 0 && j_val <= 51 )
+       {
+            p_sys->param.rc.qp = j_val;
+            p_sys->param.rc.rateControlMode = X265_RC_CQP;
+       }
+    }
+    else /* Set default to CRF */
+    {
+        i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "crf" );
+        if( i_val > 0 && i_val <= 51 )
+        {
+            p_sys->param.rc.rfConstant = i_val;
+            p_sys->param.rc.rateControlMode = X265_RC_CRF;
+        }
     }
-#endif
-    param->sourceWidth = p_enc->fmt_in.video.i_visible_width;
-    param->sourceHeight = p_enc->fmt_in.video.i_visible_height;
 
-    if (param->sourceWidth & (param->maxCUSize - 1)) {
-        msg_Err(p_enc, "Width (%d) must be a multiple of %d",
-            param->sourceWidth, param->maxCUSize);
-        free(p_sys);
-        return VLC_EGENERIC;
+    p_sys->param.rc.vbvBufferInit = var_GetFloat( p_enc,
+                            SOUT_CFG_PREFIX "vbv-init" );
+    p_sys->param.rc.vbvBufferSize = var_GetInteger( p_enc,
+                            SOUT_CFG_PREFIX "vbv-bufsize" );
+
+    /* max bitrate = average bitrate -> CBR */
+    p_sys->param.rc.vbvMaxBitrate = var_GetInteger( p_enc, SOUT_CFG_PREFIX "vbv-maxrate" );
+    if( p_sys->param.rc.vbvMaxBitrate && p_sys->param.rc.rateControlMode != X265_RC_ABR )
+        p_enc->fmt_out.i_bitrate = p_sys->param.rc.vbvMaxBitrate * 1000;
+
+    psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "deblock" );
+    if( psz_val )
+    {
+        if( atoi( psz_val ) != 0 )
+        {
+           char *p = strchr( psz_val, ':' );
+           p_sys->param.deblockingFilterTCOffset = atoi( psz_val );
+           p_sys->param.deblockingFilterBetaOffset = p ?
+                    atoi( p+1 ) : p_sys->param.deblockingFilterTCOffset;
+        }
+        free( psz_val );
     }
-    if (param->sourceHeight & 7) {
-        msg_Err(p_enc, "Height (%d) must be a multiple of 8", param->sourceHeight);
-        free(p_sys);
-        return VLC_EGENERIC;
+    p_sys->param.psyRd = var_GetFloat( p_enc, SOUT_CFG_PREFIX "psy-rd" );
+    
+    psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "level-idc" );
+    if( psz_val )
+    {
+        if( us_atof (psz_val) < 6 && us_atof (psz_val) > 0 )
+            p_sys->param.levelIdc = (int) (10 * us_atof (psz_val)
+                                              + .5);
+        else if( atoi(psz_val) >= 10 && atoi(psz_val) <= 51 )
+            p_sys->param.levelIdc = atoi (psz_val);
+        free( psz_val );
+    }
+
+    p_sys->param.interlaceMode = var_GetBool( p_enc, SOUT_CFG_PREFIX "interlace" );
+
+    if( fabs(var_GetFloat( p_enc, SOUT_CFG_PREFIX "ipratio" ) - 1.4) > 0.005 )
+       p_sys->param.rc.ipFactor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "ipratio" );
+
+    if( fabs(var_GetFloat( p_enc, SOUT_CFG_PREFIX "pbratio" ) - 1.3 ) > 0.005 )
+       p_sys->param.rc.pbFactor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "pbratio" );
+
+    p_sys->param.rc.complexityBlur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "cplxblur" );
+
+    p_sys->param.rc.qblur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qblur" );
+
+    if( var_GetInteger( p_enc, SOUT_CFG_PREFIX "aq-mode" ) != X265_AQ_VARIANCE )
+       p_sys->param.rc.aqMode = var_GetInteger( p_enc, SOUT_CFG_PREFIX "aq-mode" );
+
+    if( fabs( var_GetFloat( p_enc, SOUT_CFG_PREFIX "aq-strength" ) - 1.0) > 0.005 )
+       p_sys->param.rc.aqStrength = var_GetFloat( p_enc, SOUT_CFG_PREFIX "aq-strength" );
+
+
+    if( var_GetBool( p_enc, SOUT_CFG_PREFIX "aud" ) )
+        p_sys->param.bEnableAccessUnitDelimiters = true;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "keyint" );
+    if( i_val > -1 && i_val < INT_MAX )
+    {
+        p_sys->param.keyframeMax = i_val;
+    }
+    
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "min-keyint" );
+    if( i_val > 0 && i_val != 25 ) p_sys->param.keyframeMin = i_val;
+
+    if (var_GetBool( p_enc, SOUT_CFG_PREFIX "open-gop" ))
+        p_sys->param.bOpenGOP = true;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "bframes" );
+    if( i_val >= 0 && i_val <= 16 && i_val != 3 )
+        p_sys->param.bframes = i_val;
+
+    p_sys->param.bIntraRefresh = var_GetBool( p_enc, SOUT_CFG_PREFIX "intra-refresh" );
+
+    if (var_GetBool( p_enc, SOUT_CFG_PREFIX "b-pyramid" ))
+        p_sys->param.bBPyramid = true;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "ref" );
+    if( i_val > 0 && i_val <= 16 && i_val != 3 )
+        p_sys->param.maxNumReferences = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "scenecut" );
+    if( i_val >= -1 && i_val <= 100 && i_val != 40 )
+        p_sys->param.scenecutThreshold = i_val;
+
+    
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "subme" );
+    if( i_val >= 1 && i_val != 7 )
+        p_sys->param.subpelRefine = i_val;
+
+
+    if (var_GetBool( p_enc, SOUT_CFG_PREFIX "hrd"))
+        p_sys->param.bEmitHRDSEI = true;
+		
+         
+    psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "me" );
+    if( psz_val && strcmp( psz_val, "hex" ) )
+    {
+       if( !strcmp( psz_val, "dia" ) )
+       {
+            p_sys->param.searchMethod = X265_DIA_SEARCH;
+       }
+       else if( !strcmp( psz_val, "umh" ) )
+       {
+            p_sys->param.searchMethod = X265_UMH_SEARCH;
+        }
+       else if( !strcmp( psz_val, "star" ) )
+       {
+           p_sys->param.searchMethod = X265_STAR_SEARCH;
+       }
+       else if( !strcmp( psz_val, "full" ) )
+       {
+           p_sys->param.searchMethod = X265_FULL_SEARCH;
+       }
     }
+    free( psz_val );
+      
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "merange" );
+    if( i_val >= 0 && i_val <= 64 && i_val != 16 )
+        p_sys->param.searchRange = i_val;
+   
+    p_sys->param.bEnablePsnr = var_GetBool( p_enc, SOUT_CFG_PREFIX "psnr" );
+
+    p_sys->param.bEnableSsim = var_GetBool( p_enc, SOUT_CFG_PREFIX "ssim" );
+
+    if(var_GetBool( p_enc, SOUT_CFG_PREFIX "weightb" ) )
+       p_sys->param.bEnableWeightedBiPred = true;
+
+    if( var_GetBool( p_enc, SOUT_CFG_PREFIX "weightp" ) )
+       p_sys->param.bEnableWeightedPred = true;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "b-adapt" );
+    if( i_val != 1 )
+       p_sys->param.bFrameAdaptive = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "bframe-bias" );
+    if( i_val >= -100 && i_val <= 100 && i_val != 0)
+        p_sys->param.bFrameBias = i_val;
+
+    p_sys->param.cbQpOffset = var_GetInteger( p_enc,
+                                    SOUT_CFG_PREFIX "cbqpoffs" );
+    
+    p_sys->param.crQpOffset = var_GetInteger( p_enc,
+                                    SOUT_CFG_PREFIX "crqpoffs" );
+
+
+    if( var_GetBool( p_enc, SOUT_CFG_PREFIX "tskip-fast" ) )
+       p_sys->param.bEnableTSkipFast = true;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "nr-inter" );
+    if( i_val > 0 && i_val <= 2000 )
+        p_sys->param.noiseReductionInter = i_val;
+	
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "nr-intra" );
+    if( i_val > 0 && i_val <= 2000 )
+        p_sys->param.noiseReductionIntra = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "ctu" );
+    if( i_val == 16 || i_val == 32 || i_val == 64 )
+        p_sys->param.maxCUSize = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "min-cu-size" );
+    if( i_val == 8 || i_val == 16 || i_val == 32 || i_val == 64 )
+        p_sys->param.minCUSize = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "rc-lookahead" );
+    if( i_val >= 0 && i_val <= 250 )
+        p_sys->param.lookaheadDepth = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "limit-refs" );
+    if( i_val == 0 || i_val == 1 || i_val == 2 || i_val == 3  )
+        p_sys->param.limitReferences = i_val;
+
+    p_sys->param.bEnableRectInter = var_GetBool( p_enc, SOUT_CFG_PREFIX "rect" );
+
+    p_sys->param.bEnableAMP = var_GetBool( p_enc, SOUT_CFG_PREFIX "amp" );
+
+    p_sys->param.limitModes = var_GetBool( p_enc, SOUT_CFG_PREFIX "limit-modes" );
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "max-merge" );
+    if( i_val >= 1 && i_val <= 5 )
+        p_sys->param.maxNumMergeCand = i_val;
+
+    p_sys->param.bEnableEarlySkip = var_GetBool( p_enc, SOUT_CFG_PREFIX "early-skip" );
+
+    p_sys->param.bEnableFastIntra = var_GetBool( p_enc, SOUT_CFG_PREFIX "fast-intra" );
+
+    p_sys->param.bIntraInBFrames = var_GetBool( p_enc, SOUT_CFG_PREFIX "b-intra" );
+
+    p_sys->param.bEnableSAO = var_GetBool( p_enc, SOUT_CFG_PREFIX "sao" );
+
+    p_sys->param.bEnableSignHiding = var_GetBool( p_enc, SOUT_CFG_PREFIX "signhide" );
+
+    p_sys->param.rc.cuTree = var_GetBool( p_enc, SOUT_CFG_PREFIX "cutree" );
+  
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "rd" );
+    if( i_val >= 1 && i_val <= 6  )
+        p_sys->param.rdLevel = i_val;
+  
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "rdoq-level" );
+    if( i_val == 0 || i_val == 1 || i_val == 2 )
+        p_sys->param.rdoqLevel = i_val;
 
-    if (p_enc->fmt_out.i_bitrate > 0) {
-        param->rc.bitrate = p_enc->fmt_out.i_bitrate / 1000;
-        param->rc.rateControlMode = X265_RC_ABR;
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "tu-intra" );
+    if( i_val >= 1 && i_val <= 4 )
+        p_sys->param.tuQTMaxIntraDepth = i_val;
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "tu-inter" );
+    if( i_val >= 1 && i_val <= 4 )
+        p_sys->param.tuQTMaxInterDepth = i_val;
+
+    p_sys->param.rc.qpStep = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpstep" );
+
+    p_sys->param.psyRdoq = var_GetFloat( p_enc, SOUT_CFG_PREFIX "psy-rdoq" );
+
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "frame-threads" );
+    if( i_val >= 1 && i_val <= 16 )
+        p_sys->param.frameNumThreads = i_val;
+
+    p_sys->param.bDistributeModeAnalysis = var_GetBool( p_enc, SOUT_CFG_PREFIX "pmode" );
+
+    p_sys->param.bDistributeMotionEstimation = var_GetBool( p_enc, SOUT_CFG_PREFIX "pme" );
+    
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qg-size" );
+    if( i_val == 16 || i_val == 32 || i_val == 64)
+        p_sys->param.rc.qgSize = i_val;
+
+    if( var_GetBool( p_enc, SOUT_CFG_PREFIX "asm" ) )
+        p_sys->param.cpuid = 1;
+
+    /* Check slice-options */
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "lookahead-slices" );
+    if( i_val > 0 )
+        p_sys->param.lookaheadSlices = i_val;
+
+    /* Check if user has given some profile (baseline,main,high) to limit
+     * settings, and apply those*/
+    psz_val = var_GetNonEmptyString( p_enc, SOUT_CFG_PREFIX "profile" );
+    if( psz_val && *psz_val )
+        x265_param_apply_profile( &p_sys->param, psz_val );
+    free( psz_val );
+		
+    i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "pass" );
+    if( i_val > 0 && i_val <= 3 )
+    {
+        p_sys->param.rc.bStatWrite = i_val & 1;
+        p_sys->param.rc.bStatRead = i_val & 2;
+    }
+    
+ 
+    /* We need to initialize pthreadw32 before we open the encoder,
+       but only once for the whole application. Since pthreadw32
+       doesn't keep a refcount, do it ourselves. */
+#ifdef PTW32_STATIC_LIB
+    vlc_mutex_lock( &pthread_win32_mutex );
+
+    if( pthread_win32_count == 0 )
+    {
+        if( !pthread_win32_process_attach_np() || !pthread_win32_thread_attach_np() )
+        {
+            msg_Warn( p_enc, "pthread Win32 Initialization failed" );
+            vlc_mutex_unlock( &pthread_win32_mutex );
+            return VLC_EGENERIC;
+        }
     }
 
-    p_sys->h = x265_encoder_open(param);
-    if (p_sys->h == NULL) {
-        msg_Err(p_enc, "cannot open x265 encoder");
-        free(p_sys);
+    pthread_win32_count++;
+    vlc_mutex_unlock( &pthread_win32_mutex );
+#endif
+
+    if (var_GetBool( p_enc, SOUT_CFG_PREFIX "repeat-headers" ))
+	    p_sys->param.bRepeatHeaders = true;
+    
+    p_sys->param.fpsNum = p_enc->fmt_in.video.i_frame_rate;
+    p_sys->param.fpsDenom = p_enc->fmt_in.video.i_frame_rate_base;
+    if (!p_sys->param.fpsNum)
+    {
+        p_sys->param.fpsNum = 25;
+        p_sys->param.fpsDenom = 1;
+    }
+    p_sys->param.sourceWidth = p_enc->fmt_in.video.i_visible_width;
+    p_sys->param.sourceHeight = p_enc->fmt_in.video.i_visible_height;
+    
+    /* Open the encoder */
+    p_sys->h = x265_encoder_open( &p_sys->param );
+    if( p_sys->h == NULL )
+    {
+        msg_Err( p_enc, "cannot open x265 encoder" );
+        Close( VLC_OBJECT(p_enc) );
         return VLC_EGENERIC;
     }
 
-    x265_nal *nal;
-    uint32_t i_nal;
     if (x265_encoder_headers(p_sys->h, &nal, &i_nal) < 0) {
         msg_Err(p_enc, "cannot get x265 headers");
         Close(VLC_OBJECT(p_enc));
@@ -232,16 +1053,38 @@ static int  Open (vlc_object_t *p_this)
 
     p_enc->pf_encode_video = Encode;
     p_enc->pf_encode_audio = NULL;
-
-    return VLC_SUCCESS;
+    return VLC_SUCCESS;	
 }
 
-static void Close(vlc_object_t *p_this)
+/*****************************************************************************
+ * CloseEncoder: x265 encoder destruction
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
 {
     encoder_t     *p_enc = (encoder_t *)p_this;
     encoder_sys_t *p_sys = p_enc->p_sys;
 
-    x265_encoder_close(p_sys->h);
+    free( p_sys->psz_stat_name );
+    free( p_sys->p_sei );
+
+    if( p_sys->h )
+    {
+        x265_encoder_close( p_sys->h );
+    }
+
+#ifdef PTW32_STATIC_LIB
+    vlc_mutex_lock( &pthread_win32_mutex );
+    pthread_win32_count--;
+
+    if( pthread_win32_count == 0 )
+    {
+        pthread_win32_thread_detach_np();
+        pthread_win32_process_detach_np();
+        msg_Dbg( p_enc, "pthread-win32 deinitialized" );
+    }
+
+    vlc_mutex_unlock( &pthread_win32_mutex );
+#endif
 
-    free(p_sys);
+    free( p_sys );
 }
-- 
1.8.3.1




More information about the vlc-devel mailing list