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[] =
PROP_BITRATE,
PROP_INTRA_PERIOD,
PROP_INIT_QP,
+ PROP_MIN_QP,
+ PROP_SLICE_NUM,
};
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",
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;
}
encode->encoder = NULL;
}
- if (encode->x_display) {
- XCloseDisplay(encode->x_display);
- encode->x_display = NULL;
- }
-
G_OBJECT_CLASS(parent_class)->finalize(object);
}
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);
}
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;
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;
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;
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,
{
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;
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;
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
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_
{
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];
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_
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;
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]);
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;
}
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);
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;
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");