2 * gstvaapiencoder_mpeg4.c - MPEG-4 encoder
4 * Copyright (C) 2011 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #include "gstvaapiencoder_mpeg4.h"
25 #include "gst/gstclock.h"
27 #include "gstvaapiobject.h"
28 #include "gstvaapiobject_priv.h"
29 #include "gstvaapicontext.h"
30 #include "gstvaapisurface.h"
31 #include "gstvaapivideobuffer.h"
32 #include "gstvaapidisplay_priv.h"
34 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg4_encoder_debug);
35 #define GST_CAT_DEFAULT gst_vaapi_mpeg4_encoder_debug
37 #define GST_VAAPI_ENCODER_MPEG4_CAST(encoder) ((GstVaapiEncoderMpeg4 *)(encoder))
39 #define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0
40 #define VISUAL_OBJECT_SEQUENCE_END_CODE 0x000001B1
41 #define VISUAL_OBJECT_START_CODE 0x000001B5
42 #define VIDEO_OBJECT_PLANE_START_CODE 0x000001B6
43 /* Video Object Start Code range */
44 #define VIDEO_OBJECT_START_CODE_MIN 0x00000100
45 #define VIDEO_OBJECT_START_CODE_MAX 0x0000011F
46 /* Video Object Layer Start Code range 0x00000120 ~ 0x0000012F*/
47 #define VIDEO_OBJECT_LAYER_START_CODE 0x00000120
48 #define VIDEO_OBJECT_LAYER_START_CODE_MASK 0xFFFFFFF0
51 struct _GstVaapiEncoderMpeg4Private {
52 GstVaapiSurface *ref_surface; /* reference buffer*/
53 GstVaapiSurface *recon_surface; /* reconstruct buffer*/
55 VABufferID seq_param_id;
56 VABufferID pic_param_id;
57 VABufferID slice_param_id;
59 GstBuffer *codec_data;
62 G_DEFINE_TYPE(GstVaapiEncoderMpeg4, gst_vaapi_encoder_mpeg4, GST_TYPE_VAAPI_BASE_ENCODER)
64 GstVaapiEncoderMpeg4 *
65 gst_vaapi_encoder_mpeg4_new(void)
67 return GST_VAAPI_ENCODER_MPEG4_CAST(
68 g_object_new(GST_TYPE_VAAPI_ENCODER_MPEG4, NULL));
72 gst_vaapi_encoder_mpeg4_validate_attributes(
73 GstVaapiBaseEncoder *base
76 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
78 if (!ENCODER_WIDTH(encoder) ||
79 !ENCODER_HEIGHT(encoder) ||
80 !ENCODER_FPS(encoder)) {
83 if (VAProfileMPEG4Simple != encoder->profile &&
84 VAProfileMPEG4AdvancedSimple != encoder->profile) {
87 gst_vaapi_base_encoder_set_va_profile(base, encoder->profile);
89 if (!encoder->intra_period) {
90 encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
92 if (-1 == encoder->init_qp) {
93 encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
95 if (-1 == encoder->min_qp) {
96 encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
99 /* default compress ratio 1: (4*8*1.5) */
100 if (!encoder->bitrate) {
102 ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4/1024;
109 mpeg4_release_parameters(
110 GstVaapiEncoderMpeg4 *encoder
113 GstVaapiEncoderMpeg4Private *priv = encoder->priv;
114 VADisplay va_dpy = ENCODER_DISPLAY(encoder);
115 VAStatus va_status = VA_STATUS_SUCCESS;
117 VAAPI_UNUSED_ARG(va_status);
119 if (VA_INVALID_ID != priv->seq_param_id) {
120 va_status = vaDestroyBuffer(va_dpy, priv->seq_param_id);
121 priv->seq_param_id = VA_INVALID_ID;
123 if (VA_INVALID_ID != priv->pic_param_id) {
124 va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id);
125 priv->pic_param_id = VA_INVALID_ID;
127 if (VA_INVALID_ID != priv->slice_param_id) {
128 va_status = vaDestroyBuffer(va_dpy, priv->slice_param_id);
129 priv->slice_param_id = VA_INVALID_ID;
134 gst_vaapi_encoder_mpeg4_release_resource(
135 GstVaapiBaseEncoder* base
138 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
139 GstVaapiEncoderMpeg4Private *priv = encoder->priv;
140 GstVaapiContext *context = ENCODER_CONTEXT(base);
142 mpeg4_release_parameters(encoder);
144 /*remove ref_surface*/
145 if (priv->ref_surface) {
147 gst_vaapi_context_put_surface(context, priv->ref_surface);
149 g_object_unref(priv->ref_surface);
151 priv->ref_surface = NULL;
154 /*remove recon_surface*/
155 if (priv->recon_surface) {
157 gst_vaapi_context_put_surface(context, priv->recon_surface);
159 g_object_unref(priv->recon_surface);
161 priv->recon_surface = NULL;
164 if (priv->codec_data) {
165 gst_buffer_unref(priv->codec_data);
166 priv->codec_data = NULL;
173 mpeg4_get_profile_level_indication(guint32 profile)
176 case VAProfileMPEG4Simple:
177 return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL;
178 case VAProfileMPEG4AdvancedSimple:
179 return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL;
187 gst_vaapi_encoder_mpeg4_rendering(
188 GstVaapiBaseEncoder *base,
189 GstVaapiSurface *surface,
191 VABufferID coded_buf,
195 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
196 GstVaapiEncoderMpeg4Private *priv = encoder->priv;
197 GstVaapiContext *context = ENCODER_CONTEXT(base);
198 VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
199 VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
200 VABufferID va_buffers[64];
201 guint32 va_buffers_count = 0;
203 VAStatus va_status = VA_STATUS_SUCCESS;
204 EncoderStatus ret = ENCODER_NO_ERROR;
206 *is_key = (frame_index % encoder->intra_period == 0);
208 /* initialize sequence parameter set, only first time */
209 if (VA_INVALID_ID == priv->seq_param_id) { /*only the first time*/
210 VAEncSequenceParameterBufferMPEG4 seq_param = {0};
212 seq_param.profile_and_level_indication =
213 mpeg4_get_profile_level_indication(encoder->profile);
214 seq_param.intra_period = encoder->intra_period;
215 seq_param.video_object_layer_width = ENCODER_WIDTH(encoder);
216 seq_param.video_object_layer_height = ENCODER_HEIGHT(encoder);
217 seq_param.vop_time_increment_resolution = ENCODER_FPS(encoder);
218 seq_param.fixed_vop_rate = MPEG4_DEFAULT_FIXED_VOP_RATE;
219 if (seq_param.fixed_vop_rate) {
220 seq_param.fixed_vop_time_increment = 1;
222 seq_param.bits_per_second = encoder->bitrate * 1024;
223 seq_param.frame_rate = ENCODER_FPS(encoder);
224 seq_param.initial_qp = encoder->init_qp;
225 seq_param.min_qp = encoder->min_qp; //mpeg4_encoder->min_qp;
227 va_status = vaCreateBuffer(va_dpy, context_id,
228 VAEncSequenceParameterBufferType,
229 sizeof(seq_param), 1,
231 &priv->seq_param_id);
232 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
234 "mpeg4 alloc seq-buffer failed.");
235 va_buffers[va_buffers_count++] = priv->seq_param_id;
238 /* set reference and reconstructed surfaces */
239 if (!priv->ref_surface) {
240 priv->ref_surface = gst_vaapi_context_get_surface(context);
241 ENCODER_CHECK_STATUS(priv->ref_surface,
243 "mpeg4 reference surface, mpeg4_pop_free_surface failed.");
245 if (!priv->recon_surface) {
246 priv->recon_surface = gst_vaapi_context_get_surface(context);
247 ENCODER_CHECK_STATUS(priv->recon_surface,
249 "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed.");
252 /* initialize picture, every time, every frame */
253 VAEncPictureParameterBufferMPEG4 pic_param = {0};
254 pic_param.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface);
255 pic_param.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface);
256 pic_param.coded_buf = coded_buf;
257 pic_param.picture_width = ENCODER_WIDTH(encoder);
258 pic_param.picture_height = ENCODER_HEIGHT(encoder);
259 if (0 == frame_index) {
260 pic_param.modulo_time_base = 0;
262 pic_param.modulo_time_base =
263 ((frame_index%ENCODER_FPS(encoder)) == 0 ? 1 : 0);
265 pic_param.vop_time_increment = 301%ENCODER_FPS(encoder);
266 pic_param.picture_type =
267 (*is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive);
269 if (VA_INVALID_ID != priv->pic_param_id) { /* destroy first*/
270 va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id);
271 priv->pic_param_id = VA_INVALID_ID;
274 va_status = vaCreateBuffer(va_dpy,
276 VAEncPictureParameterBufferType,
277 sizeof(pic_param), 1,
279 &priv->pic_param_id);
280 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
282 "mpeg4 creating pic-param buffer failed.");
284 va_buffers[va_buffers_count++] = priv->pic_param_id;
286 /*initialize slice parameters, only ONE slice for mpeg4*/
287 VAEncSliceParameterBuffer slice_param = { 0 };
288 slice_param.start_row_number = 0;
289 slice_param.slice_height = (ENCODER_HEIGHT(encoder)+15)/16; /*MB?*/
290 slice_param.slice_flags.bits.is_intra = *is_key;
291 slice_param.slice_flags.bits.disable_deblocking_filter_idc = 0;
292 if (VA_INVALID_ID != priv->slice_param_id) {
293 vaDestroyBuffer(va_dpy, priv->slice_param_id);
294 priv->slice_param_id = VA_INVALID_ID;
297 va_status = vaCreateBuffer(va_dpy,
299 VAEncSliceParameterBufferType,
303 &priv->slice_param_id);
304 ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
306 "mpeg4 creating slice-parameters buffer failed.");
308 va_buffers[va_buffers_count++] = priv->slice_param_id;
310 ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder),
314 ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR,
316 "mpeg4 rendering slice-parameters buffer failed.");
318 /*swap ref_surface and recon_surface */
319 GstVaapiSurface *swap = priv->ref_surface;
320 priv->ref_surface = priv->recon_surface;
321 priv->recon_surface = swap;
329 gst_vaapi_encoder_mpeg4_copy_coded_buffer(GstVaapiBaseEncoder *encoder,
330 guint8 *frame, guint32 frame_size, VABufferID *coded_buf)
334 GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size);
335 memcpy(GST_BUFFER_DATA(buffer), frame, frame_size);
338 GstVaapiEncoderMpeg4 *mpeg4_encoder = GST_VAAPI_ENCODER_MPEG4_CAST(encoder);
339 if (mpeg4_encoder->profile == VAProfileMPEG4AdvancedSimple) {
340 guint8 *start_code = GST_BUFFER_DATA(buffer)+16; /*fix old issue of ASP in mrst platform*/
341 if (start_code[0] == 0x01 && start_code[1] == 0x20
342 && start_code[-1] == 0x00 && start_code[-2] == 0x00)
344 start_code[2] = 0x08;
354 find_video_object_configuration_info(
355 const guint8 *in_buffer,
357 const guint8 **out_buffer,
361 guint32 value = 0x00;
362 const guint8 *end = in_buffer + in_size;
364 while(in_buffer < end) {
365 value = ((value<<8)|(*in_buffer));
366 if (VISUAL_OBJECT_SEQUENCE_START_CODE == value) {
367 *out_buffer = in_buffer - 3;
373 if (in_buffer >= end)
376 while(in_buffer < end) {
377 value = ((value<<8)|(*in_buffer));
378 if (VIDEO_OBJECT_PLANE_START_CODE == value) {
379 *out_size = (in_buffer - 3 - *out_buffer);
388 mpeg4_encoder_generate_codec_data(
389 const guint8 *in_buffer,
391 GstBuffer **out_buffer
394 const guint8 *codec_buffer = NULL;
395 guint32 codec_size = 0;
396 guint8 *visual_obj_seq_end = NULL;
398 if (!find_video_object_configuration_info(in_buffer,
405 ENCODER_ASSERT(codec_size);
406 *out_buffer = gst_buffer_new_and_alloc(codec_size+4);
407 memcpy(GST_BUFFER_DATA(*out_buffer), codec_buffer, codec_size);
408 visual_obj_seq_end = GST_BUFFER_DATA(*out_buffer) + codec_size;
409 visual_obj_seq_end[0] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>24);
410 visual_obj_seq_end[1] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>16);
411 visual_obj_seq_end[2] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>8);
412 visual_obj_seq_end[3] = (guint8)VISUAL_OBJECT_SEQUENCE_END_CODE;
417 gst_vaapi_encoder_mpeg4_notify_frame(
418 GstVaapiBaseEncoder *base,
423 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
424 GstVaapiEncoderMpeg4Private *priv = encoder->priv;
425 if (!priv->codec_data) {
426 if (!mpeg4_encoder_generate_codec_data(buf, size, &priv->codec_data)) {
427 ENCODER_LOG_ERROR("mpeg4 encoder coded data error,"
428 "please check <mpeg4_encoder_generate_codec_data>.");
431 if (priv->codec_data) {
432 gst_vaapi_base_encoder_set_frame_notify(base, FALSE);
437 gst_vaapi_encoder_mpeg4_flush(
438 GstVaapiEncoder* base
441 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
443 mpeg4_release_parameters(encoder);
444 return ENCODER_NO_ERROR;
448 gst_vaapi_encoder_mpeg4_get_codec_data(
449 GstVaapiEncoder *base,
453 GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
454 GstVaapiEncoderMpeg4Private *priv = encoder->priv;
456 if (!priv->codec_data)
457 return ENCODER_DATA_NOT_READY;
458 *buffer = gst_buffer_ref(priv->codec_data);
459 return ENCODER_NO_ERROR;
463 gst_vaapi_encoder_mpeg4_init(GstVaapiEncoderMpeg4 *encoder)
465 GstVaapiEncoderMpeg4Private *priv = GST_VAAPI_ENCODER_MPEG4_GET_PRIVATE(encoder);
466 ENCODER_ASSERT(priv);
467 encoder->priv = priv;
470 encoder->profile = VAProfileMPEG4Simple;
471 encoder->bitrate = 0;
472 encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
473 encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
474 encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
476 gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), TRUE);
478 priv->ref_surface = NULL;
479 priv->recon_surface = NULL;
481 priv->seq_param_id = VA_INVALID_ID;
482 priv->pic_param_id = VA_INVALID_ID;
483 priv->slice_param_id = VA_INVALID_ID;
485 priv->codec_data = NULL;
489 gst_vaapi_encoder_mpeg4_finalize(GObject *object)
491 /*free private buffers*/
492 GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
494 if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
495 gst_vaapi_encoder_uninitialize(encoder);
497 G_OBJECT_CLASS(gst_vaapi_encoder_mpeg4_parent_class)->finalize(object);
501 gst_vaapi_encoder_mpeg4_class_init(GstVaapiEncoderMpeg4Class *klass)
503 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
504 GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
505 GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
507 g_type_class_add_private(klass, sizeof(GstVaapiEncoderMpeg4Private));
509 GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0,
510 "gst_va_mpeg4_encoder element");
512 object_class->finalize = gst_vaapi_encoder_mpeg4_finalize;
514 base_class->validate_attributes = gst_vaapi_encoder_mpeg4_validate_attributes;
515 base_class->pre_alloc_resource = NULL;
516 base_class->release_resource = gst_vaapi_encoder_mpeg4_release_resource;
517 base_class->render_frame = gst_vaapi_encoder_mpeg4_rendering;
518 base_class->notify_buffer = gst_vaapi_encoder_mpeg4_notify_frame;
519 base_class->wrap_buffer = NULL;
521 encoder_class->flush = gst_vaapi_encoder_mpeg4_flush;
522 encoder_class->get_codec_data = gst_vaapi_encoder_mpeg4_get_codec_data;