From: Wind Yuan Date: Fri, 30 Sep 2011 06:33:44 +0000 (+0800) Subject: support multiple h264 slices, auto calculate bitrate(=w*h*fps/4) add properties ... X-Git-Tag: accepted/2.0/20130321.180609~47 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2d93ff50a06af46b18e5a3d3e3209e6da841620c;p=profile%2Fivi%2Fgstreamer-vaapi.git support multiple h264 slices, auto calculate bitrate(=w*h*fps/4) add properties : min-qp, slice-num --- diff --git a/gst/vaapiencode/gsth264encode.c b/gst/vaapiencode/gsth264encode.c index f355f92..b183605 100644 --- a/gst/vaapiencode/gsth264encode.c +++ b/gst/vaapiencode/gsth264encode.c @@ -39,7 +39,6 @@ static const char gst_h264encode_sink_caps_str[] = GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { I420 } ") GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { NV12 } ") GST_CAPS_CODEC("video/x-vaapi-surface ") - GST_CAPS_CODEC("video/x-raw-va") ; static const char gst_h264encode_src_caps_str[] = @@ -72,6 +71,8 @@ enum { PROP_BITRATE, PROP_INTRA_PERIOD, PROP_INIT_QP, + PROP_MIN_QP, + PROP_SLICE_NUM, }; @@ -138,18 +139,18 @@ gst_h264encode_class_init(GstH264EncodeClass *klass) 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", + "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41", H264_LEVEL_10, - H264_LEVEL_51, + H264_LEVEL_41, 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, + "H264 encoding bitrate, 10k~100M, (0, auto-calculate)", + 0, 100*1000*1000, - H264_DEFAULT_BITRATE, + 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_INTRA_PERIOD, g_param_spec_uint ("intra-period", @@ -167,6 +168,22 @@ gst_h264encode_class_init(GstH264EncodeClass *klass) 51, H264_DEFAULT_INIT_QP, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_MIN_QP, + g_param_spec_uint ("min-qp", + "H264 min-qp", + "H264 min-qp", + 1, + 51, + H264_DEFAULT_MIN_QP, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_SLICE_NUM, + g_param_spec_uint ("slice-num", + "H264 slice num", + "H264 slice num", + 1, + 200, + 1, + G_PARAM_READWRITE)); element_class->change_state = gst_h264encode_change_state; } @@ -195,11 +212,6 @@ gst_h264encode_finalize(GObject *object) encode->encoder = NULL; } - if (encode->x_display) { - XCloseDisplay(encode->x_display); - encode->x_display = NULL; - } - G_OBJECT_CLASS(parent_class)->finalize(object); } @@ -212,7 +224,6 @@ gst_h264encode_init(GstH264Encode *encode, GstH264EncodeClass *klass) encode->srcpad_caps = NULL; encode->first_sink_frame = TRUE; encode->first_src_frame = TRUE; - encode->x_display = NULL; encode->encoder = gst_h264_encoder_new(); H264_ASSERT(encode->encoder); @@ -286,6 +297,16 @@ gst_h264encode_set_property(GObject *object, guint prop_id, } break; + case PROP_MIN_QP: { + encode->encoder->min_qp = g_value_get_uint(value); + } + break; + + case PROP_SLICE_NUM: { + encode->encoder->slice_num= g_value_get_uint(value); + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -320,6 +341,14 @@ gst_h264encode_get_property (GObject * object, guint prop_id, g_value_set_uint (value, encode->encoder->init_qp); break; + case PROP_MIN_QP: + g_value_set_uint (value, encode->encoder->min_qp); + break; + + case PROP_SLICE_NUM: + g_value_set_uint (value, encode->encoder->slice_num); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/vaapiencode/gsth264encode.h b/gst/vaapiencode/gsth264encode.h index 67329ee..08a0fd6 100644 --- a/gst/vaapiencode/gsth264encode.h +++ b/gst/vaapiencode/gsth264encode.h @@ -50,7 +50,6 @@ struct _GstH264Encode { GstH264Encoder *encoder; gboolean first_sink_frame; gboolean first_src_frame; - void *x_display; }; struct _GstH264EncodeClass { diff --git a/gst/vaapiencode/h264encoder.c b/gst/vaapiencode/h264encoder.c index b94a254..d16d632 100644 --- a/gst/vaapiencode/h264encoder.c +++ b/gst/vaapiencode/h264encoder.c @@ -76,6 +76,9 @@ struct _GstH264EncoderPrivate { VABufferID seq_parameter; VABufferID pic_parameter; VABufferID slice_parameter; + VAEncSliceParameterBuffer *slice_param_buffers; + uint32_t default_slice_height; + uint32_t slice_mod_mb_num; VABufferID *coded_bufs; uint32_t coded_buf_num; @@ -114,9 +117,10 @@ static const uint8_t h264_bit_mask[9] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3 static GstBufferClass *h264_encode_buffer_parent_class = NULL; -static void gst_h264_encoder_finalize(GObject *object); +static void gst_h264_encoder_finalize(GObject *object); +static void gst_h264_encoder_init_public_values(GstH264Encoder* encoder); -static VAProfile h264_get_va_profile(uint32_t profile); +static VAProfile h264_get_va_profile(uint32_t profile); static H264Status h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv); static H264Status h264_encoder_release_buffers(GstH264EncoderPrivate *h264_prv); static H264Status h264_put_raw_buffer_to_surface(GstH264EncoderPrivate *h264_prv, @@ -346,12 +350,12 @@ gst_h264_encoder_init(GstH264Encoder *encoder) { GstH264EncoderPrivate *h264_prv = ENCPRV(encoder); H264_ASSERT(h264_prv); + h264_prv->public = encoder; /* init public attributes */ - gst_h264_encoder_set_default_values(encoder); + gst_h264_encoder_init_public_values(encoder); /* init private values*/ - h264_prv->public = encoder; h264_prv->format = GST_MAKE_FOURCC('N','V','1','2'); h264_prv->es_flag = TRUE; @@ -365,6 +369,9 @@ gst_h264_encoder_init(GstH264Encoder *encoder) h264_prv->seq_parameter = VA_INVALID_ID; h264_prv->pic_parameter = VA_INVALID_ID; h264_prv->slice_parameter = VA_INVALID_ID; + h264_prv->slice_param_buffers = NULL; + h264_prv->default_slice_height = 0; + h264_prv->slice_mod_mb_num = 0; h264_prv->coded_bufs = NULL; h264_prv->coded_buf_num = DEFAULT_CODEDBUF_NUM; @@ -429,20 +436,26 @@ gst_h264_encoder_finalize(GObject *object) gst_buffer_unref(h264_prv->pps_data); h264_prv->pps_data = NULL; } + if (h264_prv->slice_param_buffers) { + g_free(h264_prv->slice_param_buffers); + h264_prv->slice_param_buffers = NULL; + } } -void -gst_h264_encoder_set_default_values(GstH264Encoder* encoder) +static void +gst_h264_encoder_init_public_values(GstH264Encoder* encoder) { - encoder->profile = H264_DEFAULT_PROFILE; - encoder->level = H264_DEFAULT_LEVEL; + encoder->profile = 0; + encoder->level = 0; 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; + encoder->frame_rate = 0; + encoder->bitrate = 0; + encoder->intra_period = 0; + encoder->init_qp = -1; + encoder->min_qp = -1; + encoder->slice_num = 0; } void @@ -547,6 +560,63 @@ gst_h264_encoder_uninitialize(GstH264Encoder* encoder) return ret; } +gboolean +gst_h264_validate_parameters(GstH264Encoder *encoder) +{ + GstH264EncoderPrivate *h264_prv = ENCPRV(encoder); + if (!encoder->width || !encoder->height || !encoder->frame_rate) { + return FALSE; + } + if (!encoder->profile) { + encoder->profile = H264_DEFAULT_PROFILE; + } + if (!encoder->level) { + encoder->level = H264_DEFAULT_LEVEL; + } + if (!encoder->intra_period) { + encoder->intra_period = H264_DEFAULT_INTRA_PERIOD; + } + if (-1 == encoder->init_qp) { + encoder->init_qp = H264_DEFAULT_INIT_QP; + } + if (-1 == encoder->min_qp) { + encoder->min_qp = H264_DEFAULT_MIN_QP; + } + + if (encoder->min_qp > encoder->init_qp) { + encoder->min_qp = encoder->init_qp; + } + + /* default compress ratio 1: (4*8*1.5) */ + if (!encoder->bitrate) { + encoder->bitrate = encoder->width*encoder->height*encoder->frame_rate/4; + } + + if (!encoder->slice_num) { + encoder->slice_num = H264_DEFAULT_SLICE_NUM; + } + + /* need calculate slice-num and each slice-height + suppose: ((encoder->height+15)/16) = 13, slice_num = 8 + then: slice_1_height = 2 + slice_2_height = 2 + slice_3_height = 2 + slice_4_height = 2 + slice_5_height = 2 + slice_6_height = 1 + slice_7_height = 1 + slice_8_height = 1 + */ + h264_prv->default_slice_height = (encoder->height+15)/16/encoder->slice_num; + if (0 == h264_prv->default_slice_height) { /* special value */ + h264_prv->default_slice_height = 1; + h264_prv->slice_mod_mb_num = 0; + encoder->slice_num = (encoder->height+15)/16; + } else { + h264_prv->slice_mod_mb_num = ((encoder->height+15)/16)%encoder->slice_num; + } + return TRUE; +} H264Status #ifdef _MRST_ @@ -557,7 +627,7 @@ gst_h264_encoder_open(GstH264Encoder* encoder) { H264Status ret = H264_NO_ERROR; GstH264EncoderPrivate *h264_prv = ENCPRV(encoder); - VAProfile va_profile = h264_get_va_profile(encoder->profile); + VAProfile va_profile = -1; VAEntrypoint entrypoints[5]; int num_entrypoints,slice_entrypoint; VAConfigAttrib attrib[5]; @@ -572,9 +642,12 @@ gst_h264_encoder_open(GstH264Encoder* encoder) return H264_STATE_ERR; } + /*check and set default values*/ + H264_CHECK_STATUS(gst_h264_validate_parameters(encoder), H264_PARAMETER_ERR, "h264encoder paramerter error.\n"); + + va_profile = h264_get_va_profile(encoder->profile); 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_ @@ -698,7 +771,7 @@ h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv) seq_h264.bits_per_second = h264_prv->public->bitrate; seq_h264.frame_rate = h264_prv->public->frame_rate; seq_h264.initial_qp = h264_prv->public->init_qp; /*qp_value; 15, 24, 26?*/ - seq_h264.min_qp = 1; /*0, 3, 10*/ + seq_h264.min_qp = h264_prv->public->min_qp; /*1, 6, 10*/ seq_h264.basic_unit_size = 0; seq_h264.intra_period = h264_prv->public->intra_period; seq_h264.intra_idr_period = h264_prv->public->intra_period; @@ -727,7 +800,11 @@ h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv) H264_ASSERT(h264_prv->available_code_buffers); - /* 3. init queue available_code_buffers */ + /*3. create slice_param_buffers*/ + h264_prv->slice_param_buffers = (VAEncSliceParameterBuffer*)g_malloc0_n(h264_prv->public->slice_num, + sizeof(h264_prv->slice_param_buffers[0])); + + /* 4. init queue available_code_buffers */ g_mutex_lock(h264_prv->code_buffer_lock); for (i = 0; i < h264_prv->coded_buf_num; i++) { g_queue_push_tail (h264_prv->available_code_buffers, &h264_prv->coded_bufs[i]); @@ -781,6 +858,11 @@ h264_encoder_release_buffers(GstH264EncoderPrivate *h264_prv) h264_prv->coded_bufs = NULL; } + if (h264_prv->slice_param_buffers) { + g_free(h264_prv->slice_param_buffers); + h264_prv->slice_param_buffers = NULL; + } + return H264_NO_ERROR; } @@ -967,7 +1049,7 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool VAStatus va_status = VA_STATUS_SUCCESS; VAEncPictureParameterBufferH264 pic_h264; - VAEncSliceParameterBuffer slice_h264; + VAEncSliceParameterBuffer *slice_h264 = NULL; H264_ASSERT(h264_prv->vaapi_display); H264_ASSERT(h264_prv->vaapi_context); @@ -992,6 +1074,7 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool h264_prv->recon_surface = h264_pop_free_surface(h264_prv); H264_CHECK_STATUS(h264_prv->recon_surface, H264_SURFACE_ERR, "reconstructed surface, h264_pop_free_surface failed.\n"); } + pic_h264.reference_picture = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface); pic_h264.reconstructed_picture = GST_VAAPI_OBJECT_ID(h264_prv->recon_surface); pic_h264.coded_buf = coded_buf; @@ -1011,20 +1094,40 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool va_status = vaRenderPicture(va_dpy, context_id, &h264_prv->pic_parameter, 1); H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "rendering pic-param buffer failed.\n"); - /*set slice parameters*/ - /* one frame, one slice */ - memset(&slice_h264, 0, sizeof(slice_h264)); - slice_h264.start_row_number = 0; - slice_h264.slice_height = (h264_prv->public->height+15)/16; /* Measured by MB */ - slice_h264.slice_flags.bits.is_intra = is_key; - slice_h264.slice_flags.bits.disable_deblocking_filter_idc = 0; + /* set slice parameters, support multiple slices */ + int i = 0; + uint32_t last_row_num = 0; + uint32_t slice_mod_num = h264_prv->slice_mod_mb_num; + + memset(h264_prv->slice_param_buffers, 0, h264_prv->public->slice_num*sizeof(h264_prv->slice_param_buffers[0])); + for (i = 0; i < h264_prv->public->slice_num; ++i) { + slice_h264 = &h264_prv->slice_param_buffers[i]; + slice_h264->start_row_number = last_row_num; /* unit MB*/ + slice_h264->slice_height = h264_prv->default_slice_height; /* unit MB */ + if (slice_mod_num) { + ++slice_h264->slice_height; + --slice_mod_num; + } + last_row_num += slice_h264->slice_height; + slice_h264->slice_flags.bits.is_intra = is_key; + slice_h264->slice_flags.bits.disable_deblocking_filter_idc = 0; + + } + H264_ASSERT(last_row_num == (h264_prv->public->height+15)/16); + if (VA_INVALID_ID != h264_prv->slice_parameter) { vaDestroyBuffer(va_dpy, h264_prv->slice_parameter); h264_prv->slice_parameter = VA_INVALID_ID; } - va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType, - sizeof(slice_h264), 1, &slice_h264, &h264_prv->slice_parameter); + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncSliceParameterBufferType, + sizeof(h264_prv->slice_param_buffers[0]), + h264_prv->public->slice_num, + h264_prv->slice_param_buffers, + &h264_prv->slice_parameter); H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "creating slice-parameters buffer failed.\n"); + va_status = vaRenderPicture(va_dpy, context_id, &h264_prv->slice_parameter, 1); H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "rendering slice-parameters buffer failed.\n"); diff --git a/gst/vaapiencode/h264encoder.h b/gst/vaapiencode/h264encoder.h index d68cb9d..fc43522 100644 --- a/gst/vaapiencode/h264encoder.h +++ b/gst/vaapiencode/h264encoder.h @@ -94,10 +94,10 @@ typedef enum { #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_MIN_QP 1 #define H264_DEFAULT_INTRA_PERIOD 30 #define H264_DEFAULT_FPS 30 - +#define H264_DEFAULT_SLICE_NUM 1 struct _GstH264Encoder { GObject parent; /*based on gobject*/ @@ -109,7 +109,9 @@ struct _GstH264Encoder { uint32_t frame_rate; uint32_t bitrate; uint32_t intra_period; - int32_t init_qp; /*default 26*/ + int32_t init_qp; /*default 24*/ + int32_t min_qp; /*default 1*/ + uint32_t slice_num; /* private data; */ }; @@ -135,11 +137,7 @@ GstVaapiDisplay *gst_h264_encoder_get_display(GstH264Encoder* encoder); H264Status gst_h264_encoder_initialize(GstH264Encoder* encoder); H264Status gst_h264_encoder_uninitialize(GstH264Encoder* encoder); -/* - set attributes here -*/ -void gst_h264_encoder_set_default_values(GstH264Encoder* encoder); - +gboolean gst_h264_validate_parameters(GstH264Encoder *encoder); /**/ #ifdef _MRST_