From 8499eb94ad7d64471f8b004efe321056361daa32 Mon Sep 17 00:00:00 2001 From: Wind Yuan Date: Thu, 29 Sep 2011 22:08:26 +0800 Subject: [PATCH] add properties in gsth264encode; profile, level,bitrate, intra-period, init-qp --- gst/vaapiencode/gsth264encode.c | 214 ++++++++++++++++++++++++++++++++++++---- gst/vaapiencode/h264encoder.c | 35 +++++-- gst/vaapiencode/h264encoder.h | 30 +++++- 3 files changed, 249 insertions(+), 30 deletions(-) diff --git a/gst/vaapiencode/gsth264encode.c b/gst/vaapiencode/gsth264encode.c index 696bea5..f355f92 100644 --- a/gst/vaapiencode/gsth264encode.c +++ b/gst/vaapiencode/gsth264encode.c @@ -67,6 +67,11 @@ GST_BOILERPLATE( enum { PROP_0, + PROP_PROFILE, + PROP_LEVEL, + PROP_BITRATE, + PROP_INTRA_PERIOD, + PROP_INIT_QP, }; @@ -85,6 +90,9 @@ static GstFlowReturn gst_h264encode_buffer_alloc(GstPad * pad, guint64 offset, g GstCaps * caps, GstBuffer ** buf); static char* _h264_dump_caps(GstCaps *cpas); +static gboolean _h264_check_valid_profile(guint profile); +static gboolean _h264_check_valid_level(guint level); + /*gst fix functions*/ @@ -119,6 +127,47 @@ gst_h264encode_class_init(GstH264EncodeClass *klass) object_class->set_property = gst_h264encode_set_property; object_class->get_property = gst_h264encode_get_property; + g_object_class_install_property (object_class, PROP_PROFILE, + g_param_spec_uint ("profile", + "H264 Profile", + "Profile supports: 66(Baseline), 77(Main), 100(High)", + H264_PROFILE_BASELINE, + H264_PROFILE_HIGH10, + H264_DEFAULT_PROFILE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_LEVEL, + g_param_spec_uint ("level", + "H264 level idc", + "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51", + H264_LEVEL_10, + H264_LEVEL_51, + H264_DEFAULT_LEVEL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", + "H264 encoding bitrate", + "H264 encoding bitrate, 10k~100M", + 10*1000, + 100*1000*1000, + H264_DEFAULT_BITRATE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_INTRA_PERIOD, + g_param_spec_uint ("intra-period", + "H264 encoding intra-period", + "H264 encoding intra-period", + 1, + 300, + H264_DEFAULT_INTRA_PERIOD, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_INIT_QP, + g_param_spec_uint ("init-qp", + "H264 init-qp", + "H264 init-qp", + 1, + 51, + H264_DEFAULT_INIT_QP, + G_PARAM_READWRITE)); + element_class->change_state = gst_h264encode_change_state; } @@ -198,21 +247,110 @@ static void gst_h264encode_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + GstH264Encode *encode = GST_H264ENCODE(object); + H264_ASSERT(encode->encoder); + + switch (prop_id) { + case PROP_PROFILE: { + guint profile = g_value_get_uint(value); + if (_h264_check_valid_profile(profile)) { + encode->encoder->profile = profile; + } else { + H264_LOG_ERROR("h264encode set property failed.\n"); + } + } + break; + + case PROP_LEVEL: { + guint level = g_value_get_uint(value); + if (_h264_check_valid_level(level)) { + encode->encoder->level= level; + } else { + H264_LOG_ERROR("h264encode set property failed.\n"); + } + } + break; + + case PROP_BITRATE: { + encode->encoder->bitrate = g_value_get_uint(value); + } + break; + + case PROP_INTRA_PERIOD: { + encode->encoder->intra_period = g_value_get_uint(value); + } + break; + + case PROP_INIT_QP: { + encode->encoder->init_qp = g_value_get_uint(value); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void gst_h264encode_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { + GstH264Encode *encode = GST_H264ENCODE(object); + H264_ASSERT(encode->encoder); + + switch (prop_id) { + case PROP_PROFILE: + g_value_set_uint (value, encode->encoder->profile); + break; + + case PROP_LEVEL: + g_value_set_uint (value, encode->encoder->level); + break; + + case PROP_BITRATE: + g_value_set_uint (value, encode->encoder->bitrate); + break; + + case PROP_INTRA_PERIOD: + g_value_set_uint (value, encode->encoder->intra_period); + break; + + case PROP_INIT_QP: + g_value_set_uint (value, encode->encoder->init_qp); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static gboolean gst_h264encode_set_caps(GstPad *sink_pad, GstCaps *caps) { GstH264Encode *encode = GST_H264ENCODE(GST_OBJECT_PARENT(sink_pad)); + GstStructure *structure; + gint width = 0, height = 0; + gint fps_n = 0, fps_d = 0; + const GValue *fps_value = NULL; encode->sinkpad_caps = caps; - H264_LOG_INFO("gst_h264encode_set_caps,\n%s", _h264_dump_caps(caps)); gst_caps_ref(caps); + H264_LOG_INFO("gst_h264encode_set_caps,\n%s", _h264_dump_caps(caps)); + + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_get_int (structure, "width", &width)) { + encode->encoder->width = width; + } + if (gst_structure_get_int (structure, "height", &height)) { + encode->encoder->height = height; + } + fps_value = gst_structure_get_value (structure, "framerate"); + if (fps_value) { + fps_n = gst_value_get_fraction_numerator (fps_value); + fps_d = gst_value_get_fraction_denominator (fps_value); + encode->encoder->frame_rate = fps_n/fps_d; + } return TRUE; } @@ -290,26 +428,28 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf) recv_struct = gst_caps_get_structure (recv_caps, 0); GST_H264_ENCODE_CHECK_STATUS(NULL != recv_caps, GST_FLOW_ERROR, "gst_h264encode_chain, 1st buffer didn't have detailed caps.\n"); - gst_structure_get_int (recv_struct, "width", &width); - gst_structure_get_int (recv_struct, "height", &height); + if (gst_structure_get_int (recv_struct, "width", &width)) { + encode->encoder->width = width; + } + if (gst_structure_get_int (recv_struct, "height", &height)) { + encode->encoder->height = height; + } framerate = gst_structure_get_value (recv_struct, "framerate"); - fps_n = gst_value_get_fraction_numerator (framerate); - fps_d = gst_value_get_fraction_denominator (framerate); + if (framerate) { + fps_n = gst_value_get_fraction_numerator (framerate); + fps_d = gst_value_get_fraction_denominator (framerate); + encode->encoder->frame_rate = fps_n/fps_d; + } format_value = gst_structure_get_value (recv_struct, "format"); if (format_value) { GST_H264_ENCODE_CHECK_STATUS(format_value && GST_TYPE_FOURCC == G_VALUE_TYPE(format_value), GST_FLOW_ERROR, "1st buffer caps' format type is not fourcc.\n"); format = gst_value_get_fourcc (format_value); + if (format) { + gst_h264_encoder_set_input_format(encode->encoder, format); + } } - encode->encoder->profile = 66; - encode->encoder->level = 30; - encode->encoder->width = width; - encode->encoder->height = height; - encode->encoder->frame_rate = fps_n/fps_d; - encode->encoder->bitrate = 3*1000*1000; // 3M - encode->encoder->intra_period = 30; - /*set src pad caps*/ if (encode->srcpad_caps) { gst_caps_unref(encode->srcpad_caps); @@ -321,9 +461,6 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf) "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL); /*set display and initialize encoder*/ - if (format) { - gst_h264_encoder_set_input_format(encode->encoder, format); - } if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) { GstVaapiDisplay *display = NULL; GstVaapiVideoBuffer *video_buffer = GST_VAAPI_VIDEO_BUFFER(buf); @@ -332,7 +469,7 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf) //need to get surface_pool and set to h264encoder->vaapi_context //(video_buffer->priv->surface_pool); #ifdef _MRST_ - surface_pool = gst_vaapi_video_buffer_get_surface_pool(video_buffer); + surface_pool = GST_VAAPI_SURFACE_POOL(gst_vaapi_video_buffer_get_surface_pool(video_buffer)); #endif if (display) { GST_H264_ENCODE_CHECK_STATUS(gst_h264_encoder_set_display(encode->encoder,display) @@ -432,7 +569,50 @@ finish: return ret_num; } +static gboolean _h264_check_valid_profile(guint profile) +{ + static const limit_profiles[] = { + H264_PROFILE_BASELINE, + H264_PROFILE_MAIN, + H264_PROFILE_HIGH + }; + guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]); + guint i; + for (i = 0; i < n_profiles; ++i) { + if (limit_profiles[i] == profile) + return TRUE; + } + return FALSE; +} + +static gboolean _h264_check_valid_level(guint level) +{ + static const limit_levels[] = { + H264_LEVEL_10, + H264_LEVEL_11, + H264_LEVEL_12, + H264_LEVEL_13, + H264_LEVEL_20, + H264_LEVEL_21, + H264_LEVEL_22, + H264_LEVEL_30, + H264_LEVEL_31, + H264_LEVEL_32, + H264_LEVEL_40, + H264_LEVEL_41, + H264_LEVEL_42, + H264_LEVEL_50, + H264_LEVEL_51 + }; + guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]); + guint i; + for (i = 0; i < n_levels; ++i) { + if (limit_levels[i] == level) + return TRUE; + } + return FALSE; +} static char* _h264_dump_caps(GstCaps *cpas) diff --git a/gst/vaapiencode/h264encoder.c b/gst/vaapiencode/h264encoder.c index 500cbfb..b94a254 100644 --- a/gst/vaapiencode/h264encoder.c +++ b/gst/vaapiencode/h264encoder.c @@ -318,7 +318,20 @@ H264_Encode_State gst_h264_encoder_get_state(GstH264Encoder* encoder) static VAProfile h264_get_va_profile(uint32_t profile) { - return VAProfileH264Baseline; + switch (profile) { + case H264_PROFILE_BASELINE: + return VAProfileH264Baseline; + + case H264_PROFILE_MAIN: + return VAProfileH264Main; + + case H264_PROFILE_HIGH: + return VAProfileH264High; + + default: + break; + } + return (-1); } GstH264Encoder * @@ -422,14 +435,14 @@ gst_h264_encoder_finalize(GObject *object) void gst_h264_encoder_set_default_values(GstH264Encoder* encoder) { - encoder->profile = 66; - encoder->level = 30; - encoder->width = 1280; - encoder->height = 720; - encoder->frame_rate = 30; - encoder->bitrate = 3*1000*1000; // 3M - encoder->intra_period = 30; - encoder->init_qp = 30; + encoder->profile = H264_DEFAULT_PROFILE; + encoder->level = H264_DEFAULT_LEVEL; + encoder->width = 0; + encoder->height = 0; + encoder->frame_rate = H264_DEFAULT_FPS; + encoder->bitrate = H264_DEFAULT_BITRATE; + encoder->intra_period = H264_DEFAULT_INTRA_PERIOD; + encoder->init_qp = H264_DEFAULT_INIT_QP; } void @@ -561,6 +574,9 @@ gst_h264_encoder_open(GstH264Encoder* encoder) H264_ASSERT(h264_prv->vaapi_display); H264_ASSERT(!h264_prv->vaapi_context); + H264_CHECK_STATUS(encoder->width && encoder->height, H264_PARAMETER_ERR, "width/height was not set.\n"); + H264_CHECK_STATUS(-1 != va_profile, H264_PROFILE_ERR, "profile(%d) is NOT supported.\n", encoder->profile); + #ifdef _MRST_ h264_prv->vaapi_context = g_object_new( GST_VAAPI_TYPE_CONTEXT, @@ -1231,7 +1247,6 @@ gst_h264_encoder_flush(GstH264Encoder* encoder, GList *coded_pics) { H264Status ret = H264_NO_ERROR; //GstH264EncoderPrivate *h264_prv = ENCPRV(encoder); - //VAProfile va_profile = h264_get_va_profile(encoder->profile); //error: return ret; diff --git a/gst/vaapiencode/h264encoder.h b/gst/vaapiencode/h264encoder.h index f79de0e..d68cb9d 100644 --- a/gst/vaapiencode/h264encoder.h +++ b/gst/vaapiencode/h264encoder.h @@ -32,7 +32,8 @@ extern "C" { #define H264_QUERY_STATUS_ERR -8 #define H264_DATA_NOT_READY -9 #define H264_DATA_ERR -10 - +#define H264_PROFILE_ERR -11 +#define H264_PARAMETER_ERR -12 #define H264_LOG_ERROR(...) fprintf(stdout, ## __VA_ARGS__) @@ -41,7 +42,6 @@ extern "C" { typedef int H264Status; -typedef void* VADisplay; typedef struct _GstH264Encoder GstH264Encoder; typedef struct _GstH264EncoderPrivate GstH264EncoderPrivate; typedef struct _GstH264EncoderClass GstH264EncoderClass; @@ -73,7 +73,31 @@ typedef enum { H264_PROFILE_HIGH444_PREDICTIVE = 244, } H264_Profile; -#define H264_DEFAULT_INIT_QP 26 +typedef enum { + H264_LEVEL_10 = 10, /* QCIF format, < 380160 samples/sec */ + H264_LEVEL_11 = 11, /* CIF format, < 768000 samples/sec */ + H264_LEVEL_12 = 12, /* CIF format, < 1536000 samples/sec */ + H264_LEVEL_13 = 13, /* CIF format, < 3041280 samples/sec */ + H264_LEVEL_20 = 20, /* CIF format, < 3041280 samples/sec */ + H264_LEVEL_21 = 21, /* HHR format, < 5068800 samples/sec */ + H264_LEVEL_22 = 22, /* SD/4CIF format, < 5184000 samples/sec */ + H264_LEVEL_30 = 30, /* SD/4CIF format, < 10368000 samples/sec */ + H264_LEVEL_31 = 31, /* 720pHD format, < 27648000 samples/sec */ + H264_LEVEL_32 = 32, /* SXGA format, < 55296000 samples/sec */ + H264_LEVEL_40 = 40, /* 2Kx1K format, < 62914560 samples/sec */ + H264_LEVEL_41 = 41, /* 2Kx1K format, < 62914560 samples/sec */ + H264_LEVEL_42 = 42, /* 2Kx1K format, < 125829120 samples/sec */ + H264_LEVEL_50 = 50, /* 3672x1536 format, < 150994944 samples/sec */ + H264_LEVEL_51 = 51, /* 4096x2304 format, < 251658240 samples/sec */ +} H264_Level; + +#define H264_DEFAULT_PROFILE H264_PROFILE_BASELINE +#define H264_DEFAULT_LEVEL H264_LEVEL_30 +#define H264_DEFAULT_INIT_QP 24 +#define H264_DEFAULT_BITRATE 800*1000 /*800k*/ +#define H264_DEFAULT_INTRA_PERIOD 30 +#define H264_DEFAULT_FPS 30 + struct _GstH264Encoder { GObject parent; /*based on gobject*/ -- 2.7.4