x265 encoder

This commit is contained in:
Rafaël Carré 2013-09-17 18:25:55 +02:00
parent 00cd5043fa
commit f1d6824164
6 changed files with 256 additions and 0 deletions

1
NEWS
View File

@ -10,6 +10,7 @@ Decoders:
Encoder:
* Support for MPEG-2 encoding using x262
* Support for HEVC/H.265 encoding using x265
Streaming:
* WebM streaming, including live sources, compatible with all major browsers

View File

@ -2755,6 +2755,24 @@ AC_ARG_WITH(x262-tree,
fi
fi
dnl x265 encoder
AC_ARG_ENABLE(x265,
AS_HELP_STRING([--enable-x265],[H265 / HEVC encoding support with libx265 (default enabled)]))
AS_IF( [test "${enable_x265}" != "no"],[
AC_CHECK_HEADER([x265.h], [
AC_CHECK_LIB([x265],[x265_encoder_open], [
VLC_ADD_PLUGIN([x265])
VLC_ADD_LIBS([x265], [-lx265 -lstdc++ -lm -lpthread])
], [
AC_MSG_ERROR([x265 library not found])
], [-lstdc++ -lm -lpthread])
], [
AS_IF([test "${enable_x265}" = "yes"], [
AC_MSG_ERROR([x265.h not found])
])
])
])
dnl
dnl H264 encoder plugin (10-bit lib264)

View File

@ -395,6 +395,7 @@ $Id$
* x262: MPEG-2 video encoder using x262
* x26410b: H264 10 bit video encoder using x264
* x264: H264 video encoder using x264
* x265: H265 video encoder using x265
* xa: XA demuxer
* xcb_apps: List the application windows using XCB
* xcb_glx: a opengl provider using XCB OpenGL

View File

@ -342,6 +342,14 @@ endif
### X26x encoders ###
libx265_plugin_la_SOURCES = codec/x265.c
libx265_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
libx265_plugin_la_CFLAGS = $(AM_CFLAGS) $(CFLAGS_x265)
libx265_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_x265) -rpath '$(codecdir)'
libx265_plugin_la_LIBADD = $(LIBS_x265)
EXTRA_LTLIBRARIES += libx265_plugin.la
codec_LTLIBRARIES += $(LTLIBx265)
libx262_plugin_la_SOURCES = codec/x264.c
libx262_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DMODULE_NAME_IS_x262
libx262_plugin_la_CFLAGS = $(AM_CFLAGS) $(CFLAGS_x262)

227
modules/codec/x265.c Normal file
View File

@ -0,0 +1,227 @@
/*****************************************************************************
* x265.c: HEVC/H.265 video encoder
*****************************************************************************
* Copyright (C) 2013 Rafaël Carré
*
* Authors: Rafaël Carré <funman@videolanorg>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_threads.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
#include <x265.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int Open (vlc_object_t *);
static void Close(vlc_object_t *);
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)
vlc_module_end ()
struct encoder_sys_t
{
x265_t *h;
x265_param_t param;
bool write_headers;
mtime_t i_initial_delay;
mtime_t dts;
mtime_t initial_date;
#ifndef NDEBUG
mtime_t start;
#endif
};
static block_t *Encode(encoder_t *p_enc, picture_t *p_pict)
{
encoder_sys_t *p_sys = p_enc->p_sys;
x265_picture_t pic;
if (likely(p_pict)) {
if (unlikely(p_sys->initial_date == 0)) {
p_sys->initial_date = p_pict->date;
#ifndef NDEBUG
p_sys->start = mdate();
#endif
}
for (int i = 0; i < p_pict->i_planes; i++) {
pic.planes[i] = p_pict->p[i].p_pixels;
pic.stride[i] = p_pict->p[i].i_pitch;
}
}
x265_nal_t *nal;
int i_nal = 0;
x265_encoder_encode(p_sys->h, &nal, &i_nal,
likely(p_pict) ? &pic : NULL, &pic);
if (!i_nal)
return NULL;
int i_out = 0;
for (int i = 0; i < i_nal; i++)
i_out += nal[i].i_payload;
int i_extra = 0;
if (unlikely(p_sys->write_headers)) {
i_extra = p_enc->fmt_out.i_extra;
p_sys->write_headers = false;
}
block_t *p_block = block_Alloc(i_extra + i_out);
if (!p_block)
return NULL;
if (unlikely(i_extra))
memcpy(p_block->p_buffer, p_enc->fmt_out.p_extra, i_extra);
/* all payloads are sequentially laid out in memory */
memcpy(p_block->p_buffer + i_extra, nal[0].p_payload, i_out);
/* This isn't really valid for streams with B-frames */
p_block->i_length = CLOCK_FREQ *
p_enc->fmt_in.video.i_frame_rate_base /
p_enc->fmt_in.video.i_frame_rate;
p_block->i_pts = p_sys->initial_date + pic.poc * p_block->i_length;
p_block->i_dts = p_sys->initial_date + p_sys->dts++ * p_block->i_length;
#ifndef NDEBUG
msg_Dbg(p_enc, "%zu bytes (frame %"PRId64", %.2ffps)", p_block->i_buffer,
p_sys->dts, (float)p_sys->dts * CLOCK_FREQ / (mdate() - p_sys->start));
#endif
return p_block;
}
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->b_force)
return VLC_EGENERIC;
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->fmt_in.i_codec = VLC_CODEC_I420;
x265_param_t *param = &p_sys->param;
x265_param_default(param);
param->frameNumThreads = vlc_GetCPUCount();
param->bEnableWavefront = 0; // buggy in x265, use frame threading for now
param->maxCUSize = 16; /* use smaller macroblock */
param->frameRate = p_enc->fmt_in.video.i_frame_rate /
p_enc->fmt_in.video.i_frame_rate_base;
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;
}
if (param->sourceHeight & 7) {
msg_Err(p_enc, "Height (%d) must be a multiple of 8", param->sourceHeight);
free(p_sys);
return VLC_EGENERIC;
}
if (p_enc->fmt_out.i_bitrate > 0) {
param->rc.bitrate = p_enc->fmt_out.i_bitrate / 1000;
param->rc.rateControlMode = X265_RC_ABR;
}
p_sys->h = x265_encoder_open(param);
if (p_sys->h == NULL) {
msg_Err(p_enc, "cannot open x265 encoder");
free(p_sys);
return VLC_EGENERIC;
}
x265_nal_t *nal;
int i_nal;
if (x265_encoder_headers(p_sys->h, &nal, &i_nal)) {
msg_Err(p_enc, "cannot get x265 headers");
Close(VLC_OBJECT(p_enc));
return VLC_EGENERIC;
}
size_t i_extra = 0;
for (int i = 0; i < i_nal; i++)
i_extra += nal[i].i_payload;
p_enc->fmt_out.i_extra = i_extra;
uint8_t *p_extra = p_enc->fmt_out.p_extra = malloc(i_extra);
if (!p_extra) {
Close(VLC_OBJECT(p_enc));
return VLC_ENOMEM;
}
for (int i = 0; i < i_nal; i++) {
memcpy(p_extra, nal[i].p_payload, nal[i].i_payload);
p_extra += nal[i].i_payload;
}
p_sys->dts = 0;
p_sys->initial_date = 0;
p_sys->i_initial_delay = 0;
p_sys->write_headers = true;
p_enc->pf_encode_video = Encode;
p_enc->pf_encode_audio = NULL;
return VLC_SUCCESS;
}
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, NULL);
free(p_sys);
}

View File

@ -406,6 +406,7 @@ modules/codec/uleaddvaudio.c
modules/codec/vorbis.c
modules/codec/wmafixed/wma.c
modules/codec/x264.c
modules/codec/x265.c
modules/codec/xwd.c
modules/codec/zvbi.c
modules/control/dbus/dbus.c