From: Wind Yuan Date: Mon, 29 Jul 2013 08:02:56 +0000 (+0800) Subject: plugins: add h264 encoder element. X-Git-Tag: 0.5.8~167 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f1c33feef98cc98edf780dcbecb7ebb13f7b2aca;p=platform%2Fupstream%2Fgstreamer-vaapi.git plugins: add h264 encoder element. Add GstVaapiEncodeH264 element object. The actual plug-in element is called "vaapiencode_h264". Valid properties: - rate-control: rate control mode (default: none) - bitrate: desired bitrate in kbps (default: auto-calculated) - key-period: maximal distance between two key frames (default: 30) - num-slices: number of slices per frame (default: 1) - max-bframes: number of B-frames between I and P (default: 0) - min-qp: minimal quantizer (default: 1) - init-qp: initial quantizer (default: 26) Signed-off-by: Gwenole Beauchesne --- diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am index 5c040ec..15e8cb8 100644 --- a/gst/vaapi/Makefile.am +++ b/gst/vaapi/Makefile.am @@ -58,10 +58,12 @@ libgstvaapi_source_h = \ libgstvaapi_enc_source_c = \ gstvaapiencode.c \ + gstvaapiencode_h264.c \ $(NULL) libgstvaapi_enc_source_h = \ gstvaapiencode.h \ + gstvaapiencode_h264.h \ $(NULL) if USE_ENCODERS diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c index 49c322e..07e98b6 100644 --- a/gst/vaapi/gstvaapi.c +++ b/gst/vaapi/gstvaapi.c @@ -30,6 +30,10 @@ #include "gstvaapipostproc.h" #include "gstvaapisink.h" +#if USE_ENCODERS +#include "gstvaapiencode_h264.h" +#endif + #define PLUGIN_NAME "vaapi" #define PLUGIN_DESC "VA-API based elements" #define PLUGIN_LICENSE "LGPL" @@ -54,6 +58,12 @@ plugin_init (GstPlugin *plugin) gst_element_register(plugin, "vaapisink", GST_RANK_PRIMARY, GST_TYPE_VAAPISINK); +#if USE_ENCODERS + gst_element_register(plugin, "vaapiencode_h264", + GST_RANK_PRIMARY, + GST_TYPE_VAAPIENCODE_H264); +#endif + return TRUE; } diff --git a/gst/vaapi/gstvaapiencode_h264.c b/gst/vaapi/gstvaapiencode_h264.c new file mode 100644 index 0000000..35f14ca --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.c @@ -0,0 +1,378 @@ +/* + * gstvaapiencode_h264.c - VA-API H.264 encoder + * + * Copyright (C) 2012-2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gst/vaapi/sysdeps.h" +#include "gst/vaapi/gstvaapicompat.h" + +#include "gstvaapiencode_h264.h" +#include "gstvaapipluginutil.h" +#include "gst/vaapi/gstvaapiencoder_h264.h" +#include "gst/vaapi/gstvaapiencoder_h264_priv.h" +#include "gst/vaapi/gstvaapidisplay.h" +#include "gst/vaapi/gstvaapivalue.h" +#include "gst/vaapi/gstvaapisurface.h" + +#include + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug + +#define GST_CAPS_CODEC(CODEC) CODEC "; " + +static const char gst_vaapiencode_h264_sink_caps_str[] = + GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", " + GST_CAPS_INTERLACED_FALSE "; " + GST_VAAPI_SURFACE_CAPS ", " + GST_CAPS_INTERLACED_FALSE; + +static const char gst_vaapiencode_h264_src_caps_str[] = + GST_CAPS_CODEC ("video/x-h264"); + +static GstStaticPadTemplate gst_vaapiencode_h264_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapiencode_h264_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapiencode_h264_src_factory = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (gst_vaapiencode_h264_src_caps_str)); + +/* h264 encode */ +G_DEFINE_TYPE (GstVaapiEncodeH264, gst_vaapiencode_h264, GST_TYPE_VAAPIENCODE) + +enum +{ + H264_PROP_0, + H264_PROP_RATE_CONTROL, + H264_PROP_BITRATE, + H264_PROP_KEY_PERIOD, + H264_PROP_MAX_BFRAMES, + H264_PROP_INIT_QP, + H264_PROP_MIN_QP, + H264_PROP_NUM_SLICES, +}; + +static void +gst_vaapiencode_h264_init (GstVaapiEncodeH264 * encode) +{ +} + +static void +gst_vaapiencode_h264_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vaapiencode_h264_parent_class)->finalize (object); +} + +static void +gst_vaapiencode_h264_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264 (object); + + switch (prop_id) { + case H264_PROP_RATE_CONTROL: + encode->rate_control = g_value_get_enum (value); + break; + case H264_PROP_BITRATE: + encode->bitrate = g_value_get_uint (value); + break; + case H264_PROP_KEY_PERIOD: + encode->intra_period = g_value_get_uint (value); + break; + case H264_PROP_INIT_QP: + encode->init_qp = g_value_get_uint (value); + break; + case H264_PROP_MIN_QP: + encode->min_qp = g_value_get_uint (value); + break; + case H264_PROP_NUM_SLICES: + encode->num_slices = g_value_get_uint (value); + break; + case H264_PROP_MAX_BFRAMES: + encode->max_bframes = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapiencode_h264_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264 (object); + + switch (prop_id) { + case H264_PROP_RATE_CONTROL: + g_value_set_enum (value, encode->rate_control); + break; + case H264_PROP_BITRATE: + g_value_set_uint (value, encode->bitrate); + break; + case H264_PROP_KEY_PERIOD: + g_value_set_uint (value, encode->intra_period); + break; + case H264_PROP_INIT_QP: + g_value_set_uint (value, encode->init_qp); + break; + case H264_PROP_MIN_QP: + g_value_set_uint (value, encode->min_qp); + break; + case H264_PROP_NUM_SLICES: + g_value_set_uint (value, encode->num_slices); + break; + case H264_PROP_MAX_BFRAMES: + g_value_set_uint (value, encode->max_bframes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstVaapiEncoder * +gst_vaapiencode_h264_create_encoder (GstVaapiEncode * base, + GstVaapiDisplay * display) +{ + GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264 (base); + GstVaapiEncoder *ret; + GstVaapiEncoderH264 *h264encoder; + + ret = gst_vaapi_encoder_h264_new (display); + h264encoder = GST_VAAPI_ENCODER_H264 (ret); + + h264encoder->profile = GST_VAAPI_PROFILE_UNKNOWN; + h264encoder->level = GST_VAAPI_ENCODER_H264_DEFAULT_LEVEL; + GST_VAAPI_ENCODER_RATE_CONTROL (h264encoder) = encode->rate_control; + h264encoder->bitrate = encode->bitrate; + h264encoder->intra_period = encode->intra_period; + h264encoder->init_qp = encode->init_qp; + h264encoder->min_qp = encode->min_qp; + h264encoder->slice_num = encode->num_slices; + h264encoder->b_frame_num = encode->max_bframes; + return ret; +} + +/* h264 NAL byte stream operations */ +static guint8 * +_h264_byte_stream_next_nal (guint8 * buffer, guint32 len, guint32 * nal_size) +{ + const guint8 *cur = buffer; + const guint8 *end = buffer + len; + guint8 *nal_start = NULL; + guint32 flag = 0xFFFFFFFF; + guint32 nal_start_len = 0; + + g_assert (len >= 0 && buffer && nal_size); + if (len < 3) { + *nal_size = len; + nal_start = (len ? buffer : NULL); + return nal_start; + } + + /*locate head postion */ + if (!buffer[0] && !buffer[1]) { + if (buffer[2] == 1) { /* 0x000001 */ + nal_start_len = 3; + } else if (!buffer[2] && len >= 4 && buffer[3] == 1) { /* 0x00000001 */ + nal_start_len = 4; + } + } + nal_start = buffer + nal_start_len; + cur = nal_start; + + /*find next nal start position */ + while (cur < end) { + flag = ((flag << 8) | ((*cur++) & 0xFF)); + if ((flag & 0x00FFFFFF) == 0x00000001) { + if (flag == 0x00000001) + *nal_size = cur - 4 - nal_start; + else + *nal_size = cur - 3 - nal_start; + break; + } + } + if (cur >= end) { + *nal_size = end - nal_start; + if (nal_start >= end) { + nal_start = NULL; + } + } + return nal_start; +} + +static inline void +_start_code_to_size (guint8 nal_start_code[4], guint32 nal_size) +{ + nal_start_code[0] = ((nal_size >> 24) & 0xFF); + nal_start_code[1] = ((nal_size >> 16) & 0xFF); + nal_start_code[2] = ((nal_size >> 8) & 0xFF); + nal_start_code[3] = (nal_size & 0xFF); +} + +static gboolean +_h264_convert_byte_stream_to_avc (GstBuffer * buf) +{ + GstMapInfo info; + guint32 nal_size; + guint8 *nal_start_code, *nal_body; + guint8 *frame_end; + + g_assert (buf); + + if (!gst_buffer_map (buf, &info, GST_MAP_READ | GST_MAP_WRITE)) + return FALSE; + + nal_start_code = info.data; + frame_end = info.data + info.size; + nal_size = 0; + + while ((frame_end > nal_start_code) && + (nal_body = _h264_byte_stream_next_nal (nal_start_code, + frame_end - nal_start_code, &nal_size)) != NULL) { + if (!nal_size) + goto error; + + g_assert (nal_body - nal_start_code == 4); + _start_code_to_size (nal_start_code, nal_size); + nal_start_code = nal_body + nal_size; + } + gst_buffer_unmap (buf, &info); + return TRUE; + +error: + gst_buffer_unmap (buf, &info); + return FALSE; +} + +static GstFlowReturn +gst_vaapiencode_h264_alloc_buffer (GstVaapiEncode * encode, + GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buf) +{ + GstFlowReturn ret; + GstVaapiEncoderH264 *h264encoder; + + g_return_val_if_fail (encode->encoder, GST_FLOW_ERROR); + + ret = + GST_VAAPIENCODE_CLASS (gst_vaapiencode_h264_parent_class)->allocate_buffer + (encode, coded_buf, out_buf); + if (ret != GST_FLOW_OK) + return ret; + + h264encoder = GST_VAAPI_ENCODER_H264 (encode->encoder); + if (!gst_vaapi_encoder_h264_is_avc (h264encoder)) + return ret; + + /* convert to avc format */ + if (!_h264_convert_byte_stream_to_avc (*out_buf)) { + GST_ERROR ("convert H.264 bytestream to avc buf failed."); + gst_buffer_replace (out_buf, NULL); + } + return GST_FLOW_OK; +} + +static void +gst_vaapiencode_h264_class_init (GstVaapiEncodeH264Class * klass) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + GstElementClass *const element_class = GST_ELEMENT_CLASS (klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encode_debug, + "vaapih264encode", 0, "vaapih264encode element"); + + object_class->finalize = gst_vaapiencode_h264_finalize; + object_class->set_property = gst_vaapiencode_h264_set_property; + object_class->get_property = gst_vaapiencode_h264_get_property; + + encode_class->create_encoder = gst_vaapiencode_h264_create_encoder; + encode_class->allocate_buffer = gst_vaapiencode_h264_alloc_buffer; + + gst_element_class_set_static_metadata (element_class, + "VA-API h264 encoder", + "Codec/Encoder/Video", + "A VA-API based video encoder", "Wind Yuan "); + + /* sink pad */ + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_vaapiencode_h264_sink_factory) + ); + + /* src pad */ + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_vaapiencode_h264_src_factory) + ); + + g_object_class_install_property (object_class, + H264_PROP_RATE_CONTROL, + g_param_spec_enum ("rate-control", + "Rate Control", + "Rate control mode", + GST_VAAPI_TYPE_RATE_CONTROL, + GST_VAAPI_RATECONTROL_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + H264_PROP_BITRATE, + g_param_spec_uint ("bitrate", + "Bitrate (kbps)", + "The desired bitrate expressed in kbps (0: auto-calculate)", + 0, 100 * 1024, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + H264_PROP_KEY_PERIOD, + g_param_spec_uint ("key-period", + "Key Period", + "Maximal distance between two key-frames", + 1, + 300, GST_VAAPI_ENCODER_H264_DEFAULT_INTRA_PERIOD, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + H264_PROP_MAX_BFRAMES, + g_param_spec_uint ("max-bframes", + "Max B-Frames", + "Number of B-frames between I and P", 0, 10, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + H264_PROP_INIT_QP, + g_param_spec_uint ("init-qp", + "Initial QP", + "Initial quantizer value", + 1, 51, GST_VAAPI_ENCODER_H264_DEFAULT_INIT_QP, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + H264_PROP_MIN_QP, + g_param_spec_uint ("min-qp", + "Minimum QP", + "Minimum quantizer value", + 1, 51, GST_VAAPI_ENCODER_H264_DEFAULT_MIN_QP, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + H264_PROP_NUM_SLICES, + g_param_spec_uint ("num-slices", + "Number of Slices", "Number of slices per frame", 1, 200, + 1, G_PARAM_READWRITE)); +} diff --git a/gst/vaapi/gstvaapiencode_h264.h b/gst/vaapi/gstvaapiencode_h264.h new file mode 100644 index 0000000..10fe3c8 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.h @@ -0,0 +1,80 @@ +/* + * gstvaapiencode_h264.h - VA-API H.264 encoder + * + * Copyright (C) 2012-2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIENCODE_H264_H +#define GST_VAAPIENCODE_H264_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIENCODE_H264 \ + (gst_vaapiencode_h264_get_type ()) +#define GST_IS_VAAPIENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_H264)) +#define GST_IS_VAAPIENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_H264)) + +#define GST_VAAPIENCODE_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264Class)) + +#define GST_VAAPIENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264)) + +#define GST_VAAPIENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPIENCODE_H264, \ + GstVaapiEncodeH264Class)) + +typedef struct _GstVaapiEncodeH264 GstVaapiEncodeH264; +typedef struct _GstVaapiEncodeH264Class GstVaapiEncodeH264Class; + +struct _GstVaapiEncodeH264 +{ + GstVaapiEncode parent; + + GstVaapiProfile profile; + guint32 level; + GstVaapiRateControl rate_control; + guint32 bitrate; /* kbps */ + guint32 intra_period; + guint32 init_qp; + guint32 min_qp; + guint32 num_slices; + guint32 max_bframes; +}; + +struct _GstVaapiEncodeH264Class +{ + GstVaapiEncodeClass parent_class; +}; + +GType +gst_vaapiencode_h264_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIENCODE_H264_H */