1 #include "gstvaapimpeg4encoder.h"
5 #include "gst/gstclock.h"
7 #include "gst/vaapi/gstvaapiobject.h"
8 #include "gst/vaapi/gstvaapiobject_priv.h"
9 #include "gst/vaapi/gstvaapicontext.h"
10 #include "gst/vaapi/gstvaapisurface.h"
11 #include "gst/vaapi/gstvaapivideobuffer.h"
12 #include "gst/vaapi/gstvaapidisplay_priv.h"
14 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg4_encoder_debug);
15 #define GST_CAT_DEFAULT gst_vaapi_mpeg4_encoder_debug
18 struct _GstMPEG4EncoderPrivate {
19 GstVaapiSurface *ref_surface; /* reference buffer*/
20 GstVaapiSurface *recon_surface; /* reconstruct buffer*/
22 VABufferID seq_parameter;
23 VABufferID pic_parameter;
24 VABufferID slice_parameter;
25 //VABufferID coded_buffer;
27 /*total encoded frames*/
28 //guint32 frame_count;
29 GstBuffer *codec_data;
32 G_DEFINE_TYPE(GstMPEG4Encoder, gst_mpeg4_encoder, GST_TYPE_VAAPI_BASE_ENCODER);
35 static EncoderStatus gst_mpeg4_encoder_flush(GstVaapiEncoder* encoder,
36 GstVaapiDisplay *display, GstVaapiContext *context,
39 static EncoderStatus gst_mpeg4_encoder_get_codec_data(
40 GstVaapiEncoder *encoder, GstBuffer **buffer);
41 static gboolean gst_mpeg4_validate_parameters(GstVaapiBaseEncoder *encoder);
42 static gboolean gst_mpeg4_encoder_release_resource(
43 GstVaapiBaseEncoder* encoder, GstVaapiDisplay *display,
44 GstVaapiContext *context);
45 static void gst_mpeg4_notify_frame(GstVaapiBaseEncoder *encoder,
46 guint8 *buf, guint32 size);
48 static EncoderStatus gst_mpeg4_prepare_encoding(GstVaapiBaseEncoder *encoder,
49 GstVaapiDisplay *display, GstVaapiContext *context,
50 GstVaapiSurface *surface, guint frame_index,
51 VABufferID coded_buf, gboolean *is_key);
54 static void gst_mpeg4_encoder_class_init(GstMPEG4EncoderClass *klass);
55 static void gst_mpeg4_encoder_init(GstMPEG4Encoder *encoder);
56 static void gst_mpeg4_encoder_finalize(GObject *object);
58 static gboolean mpeg4_encoder_generate_codec_data(const guint8 *in_buffer,
59 guint32 in_size, GstBuffer **out_buffer);
62 gst_mpeg4_encoder_new(void)
64 return GST_MPEG4_ENCODER(g_object_new(GST_TYPE_MPEG4_ENCODER, NULL));
69 gst_mpeg4_encoder_class_init(GstMPEG4EncoderClass *klass)
71 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
72 GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
73 GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
75 g_type_class_add_private(klass, sizeof(GstMPEG4EncoderPrivate));
77 GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0,
78 "gst_va_mpeg4_encoder element");
80 object_class->finalize = gst_mpeg4_encoder_finalize;
82 base_class->validate_attributes = gst_mpeg4_validate_parameters;
83 base_class->pre_alloc_resource = NULL;
84 base_class->release_resource = gst_mpeg4_encoder_release_resource;
85 base_class->prepare_frame = gst_mpeg4_prepare_encoding;
86 base_class->notify_frame = gst_mpeg4_notify_frame;
87 base_class->copy_coded_frame = NULL;
90 encoder_class->flush = gst_mpeg4_encoder_flush;
92 encoder_class->get_codec_data = gst_mpeg4_encoder_get_codec_data;
96 gst_mpeg4_encoder_init(GstMPEG4Encoder *mpeg4_encoder)
98 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
99 GstVaapiEncoderPrivate *encoder_prv = GST_VAAPI_ENCODER_GET_PRIVATE(mpeg4_encoder);
100 ENCODER_ASSERT(mpeg4_prv);
103 mpeg4_encoder->profile = VAProfileMPEG4Simple;
104 mpeg4_encoder->bitrate = 0;
105 mpeg4_encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
106 mpeg4_encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
107 mpeg4_encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
109 gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(mpeg4_encoder), TRUE);
111 mpeg4_prv->ref_surface = NULL;
112 mpeg4_prv->recon_surface = NULL;
114 mpeg4_prv->seq_parameter = VA_INVALID_ID;
115 mpeg4_prv->pic_parameter = VA_INVALID_ID;
116 mpeg4_prv->slice_parameter = VA_INVALID_ID;
118 mpeg4_prv->codec_data = NULL;
122 gst_mpeg4_encoder_finalize(GObject *object)
124 /*free private buffers*/
125 GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
126 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(object);
128 if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
129 gst_vaapi_encoder_uninitialize(encoder);
131 G_OBJECT_CLASS(gst_mpeg4_encoder_parent_class)->finalize(object);
135 gst_mpeg4_validate_parameters(GstVaapiBaseEncoder *encoder)
137 GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
138 if (!ENCODER_WIDTH(mpeg4_encoder) || !ENCODER_HEIGHT(mpeg4_encoder) || !ENCODER_FPS(mpeg4_encoder)) {
141 if (VAProfileMPEG4Simple != mpeg4_encoder->profile && VAProfileMPEG4AdvancedSimple != mpeg4_encoder->profile) {
144 gst_vaapi_base_encoder_set_va_profile(encoder, mpeg4_encoder->profile);
146 if (!mpeg4_encoder->intra_period) {
147 mpeg4_encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
149 if (-1 == mpeg4_encoder->init_qp) {
150 mpeg4_encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
152 if (-1 == mpeg4_encoder->min_qp) {
153 mpeg4_encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
156 /* default compress ratio 1: (4*8*1.5) */
157 if (!mpeg4_encoder->bitrate) {
158 mpeg4_encoder->bitrate = ENCODER_WIDTH(mpeg4_encoder)*ENCODER_HEIGHT(mpeg4_encoder)*ENCODER_FPS(mpeg4_encoder)/4;
165 mpeg4_release_parameters(GstMPEG4Encoder *mpeg4_encoder, GstVaapiDisplay *display)
167 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
168 VADisplay va_dpy = gst_vaapi_display_get_display(display);
169 VAStatus va_status = VA_STATUS_SUCCESS;
171 if (VA_INVALID_ID != mpeg4_prv->seq_parameter) {
172 va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->seq_parameter);
173 mpeg4_prv->seq_parameter = VA_INVALID_ID;
175 if (VA_INVALID_ID != mpeg4_prv->pic_parameter) {
176 va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->pic_parameter);
177 mpeg4_prv->pic_parameter = VA_INVALID_ID;
179 if (VA_INVALID_ID != mpeg4_prv->slice_parameter) {
180 va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->slice_parameter);
181 mpeg4_prv->slice_parameter = VA_INVALID_ID;
186 gst_mpeg4_encoder_release_resource(GstVaapiBaseEncoder* encoder,
187 GstVaapiDisplay *display,
188 GstVaapiContext *context)
190 GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
191 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
193 mpeg4_release_parameters(mpeg4_encoder, display);
195 /*remove ref_surface*/
196 if (mpeg4_prv->ref_surface) {
198 gst_vaapi_context_put_surface(context, mpeg4_prv->ref_surface);
200 g_object_unref(mpeg4_prv->ref_surface);
202 mpeg4_prv->ref_surface = NULL;
205 /*remove recon_surface*/
206 if (mpeg4_prv->recon_surface) {
208 gst_vaapi_context_put_surface(context, mpeg4_prv->recon_surface);
210 g_object_unref(mpeg4_prv->recon_surface);
212 mpeg4_prv->recon_surface = NULL;
215 if (mpeg4_prv->codec_data) {
216 gst_buffer_unref(mpeg4_prv->codec_data);
217 mpeg4_prv->codec_data = NULL;
224 mpeg4_get_profile_level_indication(guint32 profile)
227 case VAProfileMPEG4Simple:
228 return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL;
229 case VAProfileMPEG4AdvancedSimple:
230 return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL;
239 gst_mpeg4_prepare_encoding(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *display,
240 GstVaapiContext *context, GstVaapiSurface *surface,
241 guint frame_index, VABufferID coded_buf, gboolean *is_key)
243 GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
244 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
245 VADisplay va_dpy = gst_vaapi_display_get_display(display);
246 VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
248 VAStatus va_status = VA_STATUS_SUCCESS;
249 EncoderStatus ret = ENCODER_NO_ERROR;
251 *is_key = (frame_index % mpeg4_encoder->intra_period == 0);
253 /* initialize sequence parameter set, only first time */
254 if (VA_INVALID_ID == mpeg4_prv->seq_parameter) { /*only the first time*/
255 VAEncSequenceParameterBufferMPEG4 seq_mpeg4 = {0};
257 seq_mpeg4.profile_and_level_indication = mpeg4_get_profile_level_indication(mpeg4_encoder->profile);
258 seq_mpeg4.intra_period = mpeg4_encoder->intra_period;
259 seq_mpeg4.video_object_layer_width = ENCODER_WIDTH(mpeg4_encoder);
260 seq_mpeg4.video_object_layer_height = ENCODER_HEIGHT(mpeg4_encoder);
261 seq_mpeg4.vop_time_increment_resolution = ENCODER_FPS(mpeg4_encoder);
262 seq_mpeg4.fixed_vop_rate = MPEG4_DEFAULT_FIXED_VOP_RATE;
263 if (seq_mpeg4.fixed_vop_rate) {
264 seq_mpeg4.fixed_vop_time_increment = 1;
266 seq_mpeg4.bits_per_second = mpeg4_encoder->bitrate;
267 seq_mpeg4.frame_rate = ENCODER_FPS(mpeg4_encoder);
268 seq_mpeg4.initial_qp = mpeg4_encoder->init_qp;
269 seq_mpeg4.min_qp = mpeg4_encoder->min_qp; //mpeg4_encoder->min_qp;
271 va_status = vaCreateBuffer(va_dpy, context_id,
272 VAEncSequenceParameterBufferType,
273 sizeof(seq_mpeg4), 1, &seq_mpeg4, &mpeg4_prv->seq_parameter);
274 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_ENC_RES_ERR, "mpeg4 alloc seq-buffer failed.\n");
275 va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->seq_parameter, 1);
276 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR, "mpeg4 vaRenderPicture seq-parameters failed.\n");
279 /* set reference and reconstructed surfaces */
280 if (!mpeg4_prv->ref_surface) {
281 mpeg4_prv->ref_surface = gst_vaapi_context_get_surface(context);
282 ENCODER_CHECK_STATUS(mpeg4_prv->ref_surface, ENCODER_SURFACE_ERR, "mpeg4 reference surface, mpeg4_pop_free_surface failed.\n");
284 if (!mpeg4_prv->recon_surface) {
285 mpeg4_prv->recon_surface = gst_vaapi_context_get_surface(context);
286 ENCODER_CHECK_STATUS(mpeg4_prv->recon_surface, ENCODER_SURFACE_ERR, "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed.\n");
289 /* initialize picture, every time, every frame */
290 VAEncPictureParameterBufferMPEG4 pic_mpeg4 = {0};
291 pic_mpeg4.reference_picture = GST_VAAPI_OBJECT_ID(mpeg4_prv->ref_surface);
292 pic_mpeg4.reconstructed_picture = GST_VAAPI_OBJECT_ID(mpeg4_prv->recon_surface);
293 pic_mpeg4.coded_buf = coded_buf;
294 pic_mpeg4.picture_width = ENCODER_WIDTH(mpeg4_encoder);
295 pic_mpeg4.picture_height = ENCODER_HEIGHT(mpeg4_encoder);
296 if (0 == frame_index) {
297 pic_mpeg4.modulo_time_base = 0;
299 pic_mpeg4.modulo_time_base = ((frame_index%ENCODER_FPS(mpeg4_encoder)) == 0 ? 1 : 0);
301 pic_mpeg4.vop_time_increment = 301%ENCODER_FPS(mpeg4_encoder);
302 pic_mpeg4.picture_type = *is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
304 if (VA_INVALID_ID != mpeg4_prv->pic_parameter) { /* destroy first*/
305 va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->pic_parameter);
306 mpeg4_prv->pic_parameter = VA_INVALID_ID;
309 va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
310 sizeof(pic_mpeg4), 1, &pic_mpeg4, &mpeg4_prv->pic_parameter);
311 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_ENC_RES_ERR, "mpeg4 creating pic-param buffer failed.\n");
312 va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->pic_parameter, 1);
313 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_PICTURE_ERR, "mpeg4 rendering pic-param buffer failed.\n");
314 /*initialize slice parameters, only ONE slice for mpeg4*/
315 VAEncSliceParameterBuffer slice_mpeg4 = { 0 };
316 slice_mpeg4.start_row_number = 0;
317 slice_mpeg4.slice_height = (ENCODER_HEIGHT(mpeg4_encoder)+15)/16; /*MB?*/
318 slice_mpeg4.slice_flags.bits.is_intra = *is_key;
319 slice_mpeg4.slice_flags.bits.disable_deblocking_filter_idc = 0;
320 if (VA_INVALID_ID != mpeg4_prv->slice_parameter) {
321 vaDestroyBuffer(va_dpy, mpeg4_prv->slice_parameter);
322 mpeg4_prv->slice_parameter = VA_INVALID_ID;
325 va_status = vaCreateBuffer(va_dpy,
327 VAEncSliceParameterBufferType,
331 &mpeg4_prv->slice_parameter);
332 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_ENC_RES_ERR, "mpeg4 creating slice-parameters buffer failed.\n");
334 va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->slice_parameter, 1);
335 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, ENCODER_PICTURE_ERR, "mpeg4 rendering slice-parameters buffer failed.\n");
337 /*swap ref_surface and recon_surface */
338 GstVaapiSurface *swap = mpeg4_prv->ref_surface;
339 mpeg4_prv->ref_surface = mpeg4_prv->recon_surface;
340 mpeg4_prv->recon_surface = swap;
347 gst_h264_encoder_copy_coded_buffer(GstVaapiBaseEncoder *encoder,
348 guint8 *frame, guint32 frame_size, VABufferID *coded_buf)
352 GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size);
353 memcpy(GST_BUFFER_DATA(buffer), frame, frame_size);
356 GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
357 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
358 if (mpeg4_encoder->profile == VAProfileMPEG4AdvancedSimple) {
359 guint8 *start_code = GST_BUFFER_DATA(buffer)+16;
360 if (start_code[0] == 0x01 && start_code[1] == 0x20
361 && start_code[-1] == 0x00 && start_code[-2] == 0x00)
363 start_code[2] = 0x08;
372 gst_mpeg4_notify_frame(GstVaapiBaseEncoder *encoder, guint8 *buf, guint32 size)
374 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(encoder);
375 if (!mpeg4_prv->codec_data) {
376 if (!mpeg4_encoder_generate_codec_data(buf, size, &mpeg4_prv->codec_data)) {
377 ENCODER_LOG_ERROR("mpeg4 encoder coded data error, please check <mpeg4_encoder_generate_codec_data>.\n");
380 if (mpeg4_prv->codec_data) {
381 gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), FALSE);
387 gst_mpeg4_encoder_flush(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
388 GstVaapiContext *context, GList **coded_pics)
390 GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
391 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
393 mpeg4_release_parameters(mpeg4_encoder, display);
394 return ENCODER_NO_ERROR;
399 gst_mpeg4_encoder_get_codec_data(GstVaapiEncoder *encoder, GstBuffer **buffer)
401 GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(encoder);
403 if (!mpeg4_prv->codec_data)
404 return ENCODER_DATA_NOT_READY;
405 *buffer = gst_buffer_ref(mpeg4_prv->codec_data);
406 return ENCODER_NO_ERROR;
409 #define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0
410 #define VISUAL_OBJECT_SEQUENCE_END_CODE 0x000001B1
411 #define VISUAL_OBJECT_START_CODE 0x000001B5
412 #define VIDEO_OBJECT_PLANE_START_CODE 0x000001B6
413 /* Video Object Start Code range */
414 #define VIDEO_OBJECT_START_CODE_MIN 0x00000100
415 #define VIDEO_OBJECT_START_CODE_MAX 0x0000011F
416 /* Video Object Layer Start Code range 0x00000120 ~ 0x0000012F*/
417 #define VIDEO_OBJECT_LAYER_START_CODE 0x00000120
418 #define VIDEO_OBJECT_LAYER_START_CODE_MASK 0xFFFFFFF0
422 find_video_object_configuration_info(const guint8 *in_buffer, guint32 in_size,
423 const guint8 **out_buffer, guint32 *out_size)
425 guint32 value = 0x00;
426 const guint8 *end = in_buffer + in_size;
428 while(in_buffer < end) {
429 value = ((value<<8)|(*in_buffer));
430 if (VISUAL_OBJECT_SEQUENCE_START_CODE == value) {
431 *out_buffer = in_buffer - 3;
437 if (in_buffer >= end)
440 while(in_buffer < end) {
441 value = ((value<<8)|(*in_buffer));
442 if (VIDEO_OBJECT_PLANE_START_CODE == value) {
443 *out_size = (in_buffer - 3 - *out_buffer);
452 mpeg4_encoder_generate_codec_data(const guint8 *in_buffer, guint32 in_size, GstBuffer **out_buffer)
454 const guint8 *codec_buffer = NULL;
455 guint32 codec_size = 0;
456 guint8 *visual_obj_seq_end = NULL;
458 if (!find_video_object_configuration_info(in_buffer, in_size, &codec_buffer, &codec_size)) {
461 ENCODER_ASSERT(codec_size);
462 *out_buffer = gst_buffer_new_and_alloc(codec_size+4);
463 memcpy(GST_BUFFER_DATA(*out_buffer), codec_buffer, codec_size);
464 visual_obj_seq_end = GST_BUFFER_DATA(*out_buffer) + codec_size;
465 visual_obj_seq_end[0] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>24);
466 visual_obj_seq_end[1] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>16);
467 visual_obj_seq_end[2] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>8);
468 visual_obj_seq_end[3] = (guint8)VISUAL_OBJECT_SEQUENCE_END_CODE;