From 6379fb900a4070035ed1de4052cd0d92cd7a92da Mon Sep 17 00:00:00 2001 From: iive Date: Fri, 27 Aug 2004 20:43:05 +0000 Subject: [PATCH] x264 encoder support. Original patch send by Bernhard Rosenkraenzer , modifications by Loren Merritt , Jeff Clagg and me git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@13167 b3059339-0415-0410-9bf9-f77b7e298cf2 --- DOCS/man/en/mplayer.1 | 137 +++++++++++++++++- Makefile | 2 +- cfg-mencoder.h | 11 ++ configure | 37 +++++ libmpcodecs/Makefile | 2 +- libmpcodecs/ve.c | 4 + libmpcodecs/ve_x264.c | 322 ++++++++++++++++++++++++++++++++++++++++++ mencoder.c | 4 +- 8 files changed, 515 insertions(+), 4 deletions(-) create mode 100644 libmpcodecs/ve_x264.c diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index d244e15ddb..9713a80420 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -4308,7 +4308,7 @@ syntax: .RE .br .PP -Where may be: lavc, xvidenc, divx4, lame +Where may be: lavc, xvidenc, divx4, lame, x264 . . .SS divx4 (\-divx4opts) @@ -5725,6 +5725,141 @@ Print the psnr (peak signal to noise ratio) for the whole video after encoding and store the per frame psnr in a file with a name like 'psnr_hhmmss.log' in the current directory. Returned values are in dB (decibel), the higher the better. +.SS x264enc (\-x264encopts) +.TP +.B bitrate= +Sets the bitrate to be used in kbits/\:second (default: off). +This is required if you want a CBR (constant bitrate) encode. +.TP +.B iframe= +Frequency of I frames (default: 60) +.TP +.B frameref= +Number of previous frames used as predictors in a P-frame (default: 1) +.br +.I NOTE: +The current version of x264 (r38) hasn't yet implemented this feature. +.TP +.B idrframe= +Each I-Frames are IDR-Frames. +In H.264, I-Frames do not necessarily bound a closed GOP because it is +allowable for a P-frame to be predicted from more frames than just the one +frame before it (see the frameref option). +Therefore, I-frames are not necessarily seekable. IDR-Frames restrict +subsequent P-frames from referring to any frame prior to the IDR-Frame +(default: 2) +.TP +.B bframe= +Number of B-Frames between I- and P-Frames (default: 0) +.TP +.B deblock=<0|1> +Use deblocking filter (default: on) +.TP +.B deblockalpha=<-6-6> +AlphaC0 parameter of deblocking filter. +This adjusts thresholds for the H.264 deblocking filter. +First, this parameter adjusts the maximum amount of change that the filter is +allowed to cause on any one pixel. +Secondly, this parameter affects the threshold for difference across the +edge being filtered. +A positive value reduces blocking artifacts more, but will also smear details +(default: 0) +.TP +.B deblockbeta=<-6-6> +Beta parameter of deblocking filter. +Affects the maximum allowed gradient within two adjacent blocks (default: 0) +.TP +.B cabac +Use CABAC (Context-Adaptive Binary Arithmetic Coding) (default: off) +.TP +.B cabacidc= +Initial value of CABAC IDC. +The encoder must choose a context for each block it encodes, but for the +first block in a frame, there are no prior blocks to predict the context. +Adjusting this may affect bitrate by a fraction of a percent, but it doesn't +directly affect distortion. +.RSs +-1: Let the encoder decide which context (default) (it usually chooses 0) +.br +0: low complexity +.br +1: medium complexity +.br +2: high complexity +.REss +.TP +.B qp_constant=<2-51> +This selects the quantizer to use. +Lower values result in better fidelity, but higher bitrates. +Note that quantization in H.264 works differently from mpeg[124]. +H.264's QP is on a logarithmic scale. As an example, the bitrate difference +between QP=20 and QP=40 is about a factor of 10. +Useful quantizers in H.264 tend to be very large compared to mpeg[124]. +20-40 is a useful range (default: 26) +.br +.I NOTE: +This option takes effect even if you specify a cbr encode. +In such a case, the first frame encoded will use the quantization factor you +specified, but in later frames, the ratecontrol decides what quants to use. +.TP +.B qp_min=<2-51> +Minimum quantizer. CBR only. 20-40 seems to be a useful range (default: 2) +.TP +.B qp_max=<2-51> +Maximum quantizer. CBR only. +.TP +.B qp_step= +Maximum Value by which the quantizer may be incremented/decremented between +frames. +.TP +.B rc_buffer_size= +Size of the ratecontrol buffer. (default: 1 second's worth at the bitrate you +specified) +.TP +.B rc_init_buffer= +Set the initial size of ratecontrol buffer (default: 1/4 of rc_buffer_size) +.B rc_sens=<0-100> +Ratecontrol sensitivity (default: 100) +.TP +.B ip_factor= +Quantizer factor between I amd P frames (default: 2.0) +.TP +.B pb_factor= +Quantizer factor between P and B frames (default: 2.0) +.TP +.B pass=<1|2> +For 2-pass mode. The first pass saves statistics. +.TP +.B qcompress=<0-1> +Quantizer compression. This affects the ratecontrol: a lower value makes the +bitrate more constant, while a higher value makes the quantization parameter +more constant (default: 0.6) +.TP +.B qblur=<0-1> +Temporal blur of the quantization parameter. Lower values allow the quantizer +value to jump around more; higher values force it to vary more smoothly +(default: 0.5) +.TP +.B fullinter +Use all available interframe analyse methods (i4x4, psub8x8, psub16x16) +(default: 4x4, psub16x16) +.TP +.B log=<-1-3> +Adjust the amount of logging info printed to the screen. +.RSs +-1: none +.br + 0: errors (for debugging x264) +.br + 1: warnings +.br + 2: PSNR and other analysis stats when the encode finishes (default) +.br + 3: PSNR, qp, frametype, size, and other stats for every frame +.REss +.TP +.B psnr +Print signal-to-noise ratio statistics. . . .\" -------------------------------------------------------------------------- diff --git a/Makefile b/Makefile index a47018b583..5ace327b29 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ OBJS_MPLAYER = $(SRCS_MPLAYER:.c=.o) VO_LIBS = $(AA_LIB) $(X_LIB) $(SDL_LIB) $(GGI_LIB) $(MP1E_LIB) $(MLIB_LIB) $(SVGA_LIB) $(DIRECTFB_LIB) $(CACA_LIB) AO_LIBS = $(ARTS_LIB) $(ESD_LIB) $(JACK_LIB) $(NAS_LIB) $(SGIAUDIO_LIB) -CODEC_LIBS = $(AV_LIB) $(FAME_LIB) $(MAD_LIB) $(VORBIS_LIB) $(THEORA_LIB) $(FAAD_LIB) $(LIBLZO_LIB) $(DECORE_LIB) $(XVID_LIB) $(DTS_LIB) $(PNG_LIB) $(Z_LIB) $(JPEG_LIB) $(ALSA_LIB) $(XMMS_LIB) +CODEC_LIBS = $(AV_LIB) $(FAME_LIB) $(MAD_LIB) $(VORBIS_LIB) $(THEORA_LIB) $(FAAD_LIB) $(LIBLZO_LIB) $(DECORE_LIB) $(XVID_LIB) $(DTS_LIB) $(PNG_LIB) $(Z_LIB) $(JPEG_LIB) $(ALSA_LIB) $(XMMS_LIB) $(X264_LIB) COMMON_LIBS = libmpcodecs/libmpcodecs.a mp3lib/libMP3.a liba52/liba52.a libmpeg2/libmpeg2.a $(W32_LIB) $(DS_LIB) libaf/libaf.a libmpdemux/libmpdemux.a input/libinput.a postproc/libswscale.a osdep/libosdep.a $(DVDREAD_LIB) $(CODEC_LIBS) $(FREETYPE_LIB) $(TERMCAP_LIB) $(CDPARANOIA_LIB) $(MPLAYER_NETWORK_LIB) $(WIN32_LIB) $(GIF_LIB) $(MACOSX_FRAMEWORKS) $(SMBSUPPORT_LIB) $(FRIBIDI_LIB) $(FONTCONFIG_LIB) $(ENCA_LIB) CFLAGS = $(OPTFLAGS) -Ilibmpdemux -Iloader -Ilibvo $(FREETYPE_INC) $(EXTRA_INC) $(CDPARANOIA_INC) $(SDL_INC) $(X11_INC) $(FRIBIDI_INC) $(DVB_INC) $(XVID_INC) $(FONTCONFIG_INC) $(CACA_INC) # -Wall diff --git a/cfg-mencoder.h b/cfg-mencoder.h index cc4260b147..0d158f9b3a 100644 --- a/cfg-mencoder.h +++ b/cfg-mencoder.h @@ -63,6 +63,10 @@ extern m_option_t vfwopts_conf[]; extern m_option_t xvidencopts_conf[]; #endif +#if defined(HAVE_X264) +extern m_option_t x264encopts_conf[]; +#endif + extern m_option_t nuvopts_conf[]; m_option_t ovc_conf[]={ @@ -78,6 +82,7 @@ m_option_t ovc_conf[]={ {"xvid", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_XVID, NULL}, {"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}, {"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" @@ -102,6 +107,9 @@ m_option_t ovc_conf[]={ #endif #if defined(HAVE_XVID3) || defined(HAVE_XVID4) " xvid - XviD encoding\n" +#endif +#ifdef HAVE_X264 + " x264 - H.264 encoding\n" #endif "\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, {NULL, NULL, 0, 0, 0, 0, NULL} @@ -239,6 +247,9 @@ m_option_t mencoder_opts[]={ #if defined(HAVE_XVID3) || defined(HAVE_XVID4) {"xvidencopts", xvidencopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, #endif +#if defined(HAVE_X264) + {"x264encopts", x264encopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, +#endif {"nuvopts", nuvopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, diff --git a/configure b/configure index 15dccf01a5..7878b587f0 100755 --- a/configure +++ b/configure @@ -198,6 +198,7 @@ Codecs: --disable-xanim disable XAnim DLL support [autodetect] --disable-real disable RealPlayer DLL support [autodetect] --disable-xvid disable XviD codec [autodetect] + --disable-x264 disable H.264 encoder [autodetect] --disable-divx4linux disable DivX4linux/Divx5linux codec [autodetect] --enable-opendivx enable _old_ OpenDivx codec [disable] --disable-libavcodec disable libavcodec [autodetect] @@ -320,6 +321,8 @@ multiple paths separated by ':'): --with-reallibdir=DIR RealPlayer DLL files in DIR --with-xvidlibdir=DIR libxvidcore (XviD) in DIR (*) --with-xvidincdir=DIR XviD header in DIR (*) + --with-x264libdir=DIR libx264 in DIR + --with-x264incdir=DIR x264 header in DIR --with-dtslibdir=DIR libdts library in DIR (*) --with-dtsincdir=DIR libdts header in DIR (*) --with-livelibdir=DIR LIVE.COM Streaming Media libraries in DIR @@ -1298,6 +1301,7 @@ _smbsupport=auto _vidix=auto _joystick=no _xvid=auto +_x264=auto _divx4linux=auto _opendivx=no _lirc=auto @@ -1502,6 +1506,8 @@ for ac_option do --disable-joystick) _joystick=no ;; --enable-xvid) _xvid=yes ;; --disable-xvid) _xvid=no ;; + --enable-x264) _x264=yes ;; + --disable-x264) _x264=no ;; --enable-divx4linux) _divx4linux=yes ;; --disable-divx4linux) _divx4linux=no ;; --enable-opendivx) _opendivx=yes ;; @@ -1708,6 +1714,12 @@ for ac_option do --with-dtsincdir=*) _inc_libdts=-I`echo $ac_option | cut -d '=' -f 2 | sed 's,:, -I,g'` ;; + --with-x264libdir=*) + _ld_x264=-L`echo $ac_option | cut -d '=' -f 2 | sed 's,:, -L,g'` + ;; + --with-x264incdir=*) + _inc_x264=-I`echo $ac_option | cut -d '=' -f 2 |sed 's,:, -I,g'` + ;; --with-sdl-config=*) _sdlconfig=`echo $ac_option | cut -d '=' -f 2` ;; @@ -5474,6 +5486,25 @@ EOF echores "$_xvidcompat" fi +echocheck "x264" +cat > $TMPC << EOF +#include +#include +#include +int main(void) { x264_encoder_open((void*)0); return 0; } +EOF +_ld_x264="$_ld_x264 -lx264 -lm" +if test "$_x264" != no && cc_check $_inc_x264 $_ld_x264 ; then + _x264=yes + _def_x264='#define HAVE_X264 1' + _codecmodules="x264 $_codecmodules" +else + _x264=no + _ld_x264='' + _def_x264='#undef HAVE_X264' + _nocodecmodules="x264 $_nocodecmodules" +fi +echores "$_x264" echocheck "DivX4linux/DivX5linux/OpenDivX decore" # DivX5: DEC_OPT_MEMORY_REQS - DivX4: DEC_OPT_FRAME_311 @@ -6268,6 +6299,9 @@ ARCH_LIB = $_ld_arch $_ld_iconv XVID = $_xvid XVID_INC = $_inc_xvid XVID_LIB = $_ld_xvid +X264 = $_x264 +X264_INC = $_inc_x264 +X264_LIB = $_ld_x264 CONFIG_DTS = $_libdts DTS_INC = $_inc_libdts DTS_LIB = $_ld_libdts @@ -6410,6 +6444,9 @@ $_def_xvid4 $_def_decore_xvid $_def_encore_xvid +/* Define if you are using the X.264 library */ +$_def_x264 + /* Define to include support for libdv-0.9.5 */ $_def_libdv diff --git a/libmpcodecs/Makefile b/libmpcodecs/Makefile index 380f77f43d..9c492fdb84 100644 --- a/libmpcodecs/Makefile +++ b/libmpcodecs/Makefile @@ -19,7 +19,7 @@ ifeq ($(HAVE_FFPOSTPROCESS),yes) VFILTER_SRCS += vf_pp.c endif -ENCODER_SRCS=ve.c ve_divx4.c ve_lavc.c ve_vfw.c ve_raw.c ve_libdv.c ve_xvid.c ve_xvid4.c ve_qtvideo.c ve_nuv.c +ENCODER_SRCS=ve.c ve_divx4.c ve_lavc.c ve_vfw.c ve_raw.c ve_libdv.c ve_xvid.c ve_xvid4.c ve_qtvideo.c ve_nuv.c ve_x264.c NATIVE_SRCS=native/RTjpegN.c native/minilzo.c native/nuppelvideo.c native/xa_gsm.c native/decode144.c native/decode288.c diff --git a/libmpcodecs/ve.c b/libmpcodecs/ve.c index e6f2adf1a4..ac0d441fd3 100644 --- a/libmpcodecs/ve.c +++ b/libmpcodecs/ve.c @@ -17,6 +17,7 @@ extern vf_info_t ve_info_libdv; extern vf_info_t ve_info_xvid; extern vf_info_t ve_info_qtvideo; extern vf_info_t ve_info_nuv; +extern vf_info_t ve_info_x264; static vf_info_t* encoder_list[]={ #ifdef HAVE_DIVX4ENCORE @@ -37,6 +38,9 @@ static vf_info_t* encoder_list[]={ &ve_info_xvid, #endif &ve_info_nuv, +#ifdef HAVE_X264 + &ve_info_x264, +#endif NULL }; diff --git a/libmpcodecs/ve_x264.c b/libmpcodecs/ve_x264.c new file mode 100644 index 0000000000..3cdff499b3 --- /dev/null +++ b/libmpcodecs/ve_x264.c @@ -0,0 +1,322 @@ +/***************************************************************************** + * + * - H.264 encoder for mencoder using x264 - + * + * Copyright (C) 2004 LINUX4MEDIA GmbH + * Copyright (C) 2004 Ark Linux + * + * Written by Bernhard Rosenkraenzer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation, or if, and only if, + * version 2 is ruled invalid in a court of law, any later version + * of the GNU General Public License published by the Free Software + * Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTIBILITY 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + *****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "../config.h" +#include "../mp_msg.h" + +#ifdef HAVE_X264 + +#include "m_option.h" +#include "codec-cfg.h" +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" + +#include "muxer.h" + +#include "img_format.h" +#include "mp_image.h" +#include "vf.h" + +#include + +typedef struct _h264_module_t { + muxer_stream_t *mux; + x264_param_t param; + x264_t * x264; + x264_picture_t pic; +} h264_module_t; + +extern char* passtmpfile; + +static int bitrate = -1; +static int qp_constant = 26; +static int frame_ref = 1; +static int iframe = 60; +static int idrframe = 2; +static int bframe = 0; +static int deblock = 1; +static int deblockalpha = 0; +static int deblockbeta = 0; +static int cabac = 0; +static int cabacidc = -1; +static int fullinter = 0; +static float ip_factor = 2.0; +static float pb_factor = 2.0; +static int rc_buffer_size = -1; +static int rc_init_buffer = -1; +static int rc_sens = 4; +static int qp_min = 10; +static int qp_max = 51; +static int qp_step = 1; +static int pass = 0; +static float qcomp = 0.6; +static float qblur = 0.5; +static char *rc_eq = "(tex^qComp)*(avgTex^(1-qComp))"; +static int psnr = 0; +static int log_level = 2; + +m_option_t x264encopts_conf[] = { + {"bitrate", &bitrate, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, + {"qp_constant", &qp_constant, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, + {"frameref", &frame_ref, CONF_TYPE_INT, CONF_RANGE, 1, 100, NULL}, + {"iframe", &iframe, CONF_TYPE_INT, CONF_RANGE, 1, 24000000, NULL}, + {"idrframe", &idrframe, CONF_TYPE_INT, CONF_RANGE, 1, 24000000, NULL}, + {"bframe", &bframe, CONF_TYPE_INT, CONF_RANGE, 0, 10, NULL}, + {"deblock", &deblock, CONF_TYPE_INT, CONF_RANGE, 0, 1, NULL}, + {"deblockalpha", &deblockalpha, CONF_TYPE_INT, CONF_RANGE, -6, 6, NULL}, + {"deblockbeta", &deblockbeta, CONF_TYPE_INT, CONF_RANGE, -6, 6, NULL}, + {"cabac", &cabac, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"cabacidc", &cabacidc, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL}, + {"fullinter", &fullinter, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"ip_factor", &ip_factor, CONF_TYPE_FLOAT, CONF_RANGE, -10.0, 10.0, NULL}, + {"pb_factor", &pb_factor, CONF_TYPE_FLOAT, CONF_RANGE, -10.0, 10.0, NULL}, + {"rc_buffer_size", &rc_buffer_size, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, + {"rc_init_buffer", &rc_init_buffer, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, + {"rc_sens", &rc_sens, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, + {"qp_min", &qp_min, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, + {"qp_max", &qp_max, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, + {"qp_step", &qp_step, CONF_TYPE_INT, CONF_RANGE, 0, 50, NULL}, + {"pass", &pass, CONF_TYPE_INT, CONF_RANGE, 1, 3, NULL}, + {"rc_eq", &rc_eq, CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"qcomp", &qcomp, CONF_TYPE_FLOAT, CONF_RANGE, 0, 1, NULL}, + {"qblur", &qblur, CONF_TYPE_FLOAT, CONF_RANGE, 0, 99, NULL}, + {"psnr", &psnr, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"log", &log_level, CONF_TYPE_INT, CONF_RANGE, -1, 3, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + + +static int config(struct vf_instance_s* vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) { + h264_module_t *mod=(h264_module_t*)vf->priv; + mod->mux->bih->biWidth = width; + mod->mux->bih->biHeight = height; + mod->mux->aspect = (float)d_width/d_height; + + x264_param_default(&mod->param); + mod->param.i_frame_reference = frame_ref; + mod->param.i_idrframe = idrframe; + mod->param.i_iframe = iframe; + mod->param.i_bframe = bframe; + mod->param.b_deblocking_filter = deblock; + mod->param.i_deblocking_filter_alphac0 = deblockalpha; + mod->param.i_deblocking_filter_beta = deblockbeta; + mod->param.b_cabac = cabac; + mod->param.i_cabac_init_idc = cabacidc; + mod->param.i_qp_constant = qp_constant; + if(qp_min > qp_constant) + qp_min = qp_constant; + if(qp_max < qp_constant) + qp_max = qp_constant; + mod->param.i_qp_min = qp_min; + mod->param.i_qp_max = qp_max; + mod->param.i_qp_step = qp_step; +#if 0 + mod->param.i_pass = pass; + mod->param.s_rc_eq = rc_eq; + mod->param.f_qcompress = qcomp; + mod->param.f_qblur = qblur; + mod->param.s_2pass_file_out = passtmpfile; + mod->param.s_2pass_file_in = passtmpfile; + if((pass & 2) && bitrate <= 0) + { + mp_msg(MSGT_MENCODER, MSGL_ERR, + "2 pass encoding enabled, but no bitrate specified.\n"); + return 0; + } +#endif + if(bitrate > 0) { + if(rc_buffer_size <= 0) + rc_buffer_size = bitrate; + if(rc_init_buffer < 0) + rc_init_buffer = rc_buffer_size/4; + mod->param.b_cbr = 1; + mod->param.i_bitrate = bitrate; + mod->param.i_rc_buffer_size = rc_buffer_size; + mod->param.i_rc_init_buffer = rc_init_buffer; + mod->param.i_rc_sens = rc_sens; + } + if(fullinter) + mod->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_PSUB8x8; + mod->param.f_ip_factor = ip_factor; + mod->param.f_pb_factor = pb_factor; + + mod->param.i_width = width; + mod->param.i_height = height; + mod->param.i_fps_num = mod->mux->h.dwRate; + mod->param.i_fps_den = mod->mux->h.dwScale; + mod->param.analyse.b_psnr = psnr; + mod->param.i_log_level = log_level; + + switch(outfmt) { + case IMGFMT_I420: + mod->param.i_csp = X264_CSP_I420; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_YV12: + mod->param.i_csp = X264_CSP_YV12; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_422P: + mod->param.i_csp = X264_CSP_I422; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_444P: + mod->param.i_csp = X264_CSP_I444; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_YVYU: + mod->param.i_csp = X264_CSP_YUYV; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_RGB: + mod->param.i_csp = X264_CSP_RGB; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_BGR: + mod->param.i_csp = X264_CSP_BGR; + mod->mux->bih->biSizeImage = width * height * 3; + break; + case IMGFMT_BGR32: + mod->param.i_csp = X264_CSP_BGRA; + mod->mux->bih->biSizeImage = width * height * 4; + break; + default: + mp_msg(MSGT_MENCODER, MSGL_ERR, "Wrong colorspace.\n"); + return 0; + } + + mod->x264 = x264_encoder_open(&mod->param); + if(!mod->x264) { + mp_msg(MSGT_MENCODER, MSGL_ERR, "x264_encoder_open failed.\n"); + return 0; + } + + x264_picture_alloc(&mod->pic, mod->param.i_csp, mod->param.i_width, mod->param.i_height); + return 1; +} + +static int control(struct vf_instance_s* vf, int request, void *data) +{ + return CONTROL_UNKNOWN; +} + +static int query_format(struct vf_instance_s* vf, unsigned int fmt) +{ + switch(fmt) { + case IMGFMT_I420: + return (VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW); + case IMGFMT_YV12: + case IMGFMT_422P: + case IMGFMT_444P: + case IMGFMT_YVYU: + case IMGFMT_RGB: + case IMGFMT_BGR: + case IMGFMT_BGR32: + /* 2004/08/05: There seems to be some, but not complete, + support for these colorspaces in X264. Better to stay + on the safe side for now. */ + return 0; /* VFCAP_CSP_SUPPORTED */ + } + return 0; +} + +static int put_image(struct vf_instance_s *vf, mp_image_t *mpi) +{ + h264_module_t *mod=(h264_module_t*)vf->priv; + int i_nal; + x264_nal_t *nal; + int i; + + int csp=mod->pic.img.i_csp; + memset(&mod->pic, 0, sizeof(x264_picture_t)); + mod->pic.img.i_csp=csp; + mod->pic.img.i_plane=3; + for(i=0; i<4; i++) { + mod->pic.img.plane[i] = mpi->planes[i]; + mod->pic.img.i_stride[i] = mpi->stride[i]; + } + + mod->pic.i_type = X264_TYPE_AUTO; + if(x264_encoder_encode(mod->x264, &nal, &i_nal, &mod->pic) < 0) { + mp_msg(MSGT_MENCODER, MSGL_ERR, "x264_encoder_encode failed\n"); + return 0; + } + + int i_size = 0; + for(i=0; i < i_nal; i++) { + int i_data = mod->mux->buffer_size - i_size; + i_size += x264_nal_encode(mod->mux->buffer + i_size, &i_data, 1, &nal[i]); + } + if(i_size>0) { + muxer_write_chunk(mod->mux, i_size, (mod->pic.i_type == X264_TYPE_I)?0x10:0); + } + return 1; +} + +static void uninit(struct vf_instance_s *vf) +{ + // FIXME: flush delayed frames + h264_module_t *mod=(h264_module_t*)vf->priv; + x264_encoder_close(mod->x264); + //x264_picture_clean(&mod->pic); +} + +static int vf_open(vf_instance_t *vf, char *args) { + vf->config = config; + vf->control = control; + vf->query_format = query_format; + vf->put_image = put_image; + vf->uninit = uninit; + vf->priv = malloc(sizeof(h264_module_t)); + + h264_module_t *mod=(h264_module_t*)vf->priv; + mod->mux = (muxer_stream_t*)args; + mod->mux->bih = malloc(sizeof(BITMAPINFOHEADER)); + memset(mod->mux->bih, 0, sizeof(BITMAPINFOHEADER)); + mod->mux->bih->biSize = sizeof(BITMAPINFOHEADER); + mod->mux->bih->biPlanes = 1; + mod->mux->bih->biBitCount = 24; + mod->mux->bih->biCompression = mmioFOURCC('h', '2', '6', '4'); + + return 1; +} + +vf_info_t ve_info_x264 = { + "H.264 encoder", + "x264", + "Bernhard Rosenkraenzer ", + "(C) 2004 LINUX4MEDIA GmbH; (C) 2004 Ark Linux", + vf_open +}; +#endif diff --git a/mencoder.c b/mencoder.c index 668aa1b2ac..faa06ac65a 100644 --- a/mencoder.c +++ b/mencoder.c @@ -9,6 +9,7 @@ #define VCODEC_QTVIDEO 10 #define VCODEC_NUV 11 #define VCODEC_RAW 12 +#define VCODEC_X264 13 #define ACODEC_COPY 0 #define ACODEC_PCM 1 @@ -708,7 +709,8 @@ default: sh_video->vfilter=vf_open_encoder(NULL,"qtvideo",(char *)mux_v); break; case VCODEC_NUV: 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; } if(!mux_v->bih || !sh_video->vfilter){ mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_EncoderOpenFailed);