Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiencoder_mpeg4.c
1 /*
2  *  gstvaapiencoder_mpeg4.c - MPEG-4 encoder
3  *
4  *  Copyright (C) 2011 Intel Corporation
5  *
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.
10  *
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.
15  *
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
20  */
21
22 #include "gstvaapiencoder_mpeg4.h"
23
24 #include <string.h>
25 #include "gst/gstclock.h"
26
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"
33
34 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg4_encoder_debug);
35 #define GST_CAT_DEFAULT gst_vaapi_mpeg4_encoder_debug
36
37 #define GST_VAAPI_ENCODER_MPEG4_CAST(encoder)    ((GstVaapiEncoderMpeg4 *)(encoder))
38
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
49
50
51 struct _GstVaapiEncoderMpeg4Private {
52   GstVaapiSurface  *ref_surface;  /* reference buffer*/
53   GstVaapiSurface  *recon_surface; /* reconstruct buffer*/
54
55   VABufferID        seq_param_id;
56   VABufferID        pic_param_id;
57   VABufferID        slice_param_id;
58
59   GstBuffer        *codec_data;
60 };
61
62 G_DEFINE_TYPE(GstVaapiEncoderMpeg4, gst_vaapi_encoder_mpeg4, GST_TYPE_VAAPI_BASE_ENCODER)
63
64 GstVaapiEncoderMpeg4 *
65 gst_vaapi_encoder_mpeg4_new(void)
66 {
67   return GST_VAAPI_ENCODER_MPEG4_CAST(
68              g_object_new(GST_TYPE_VAAPI_ENCODER_MPEG4, NULL));
69 }
70
71 gboolean
72 gst_vaapi_encoder_mpeg4_validate_attributes(
73     GstVaapiBaseEncoder *base
74 )
75 {
76   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
77
78   if (!ENCODER_WIDTH(encoder) ||
79       !ENCODER_HEIGHT(encoder) ||
80       !ENCODER_FPS(encoder)) {
81     return FALSE;
82   }
83   if (VAProfileMPEG4Simple != encoder->profile &&
84       VAProfileMPEG4AdvancedSimple != encoder->profile) {
85     return FALSE;
86   }
87   gst_vaapi_base_encoder_set_va_profile(base, encoder->profile);
88
89   if (!encoder->intra_period) {
90     encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
91   }
92   if (-1 == encoder->init_qp) {
93     encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
94   }
95   if (-1 == encoder->min_qp) {
96     encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
97   }
98
99   /* default compress ratio 1: (4*8*1.5) */
100   if (!encoder->bitrate) {
101     encoder->bitrate =
102         ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4/1024;
103   }
104   return TRUE;
105
106 }
107
108 static void
109 mpeg4_release_parameters(
110     GstVaapiEncoderMpeg4 *encoder
111 )
112 {
113   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
114   VADisplay va_dpy = ENCODER_DISPLAY(encoder);
115   VAStatus va_status = VA_STATUS_SUCCESS;
116
117   VAAPI_UNUSED_ARG(va_status);
118
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;
122   }
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;
126   }
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;
130   }
131 }
132
133 static gboolean
134 gst_vaapi_encoder_mpeg4_release_resource(
135     GstVaapiBaseEncoder* base
136 )
137 {
138   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
139   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
140   GstVaapiContext *context = ENCODER_CONTEXT(base);
141
142   mpeg4_release_parameters(encoder);
143
144   /*remove ref_surface*/
145   if (priv->ref_surface) {
146     if (context) {
147       gst_vaapi_context_put_surface(context, priv->ref_surface);
148     } else {
149       g_object_unref(priv->ref_surface);
150     }
151     priv->ref_surface = NULL;
152   }
153
154   /*remove recon_surface*/
155   if (priv->recon_surface) {
156     if (context) {
157       gst_vaapi_context_put_surface(context, priv->recon_surface);
158     } else {
159       g_object_unref(priv->recon_surface);
160     }
161     priv->recon_surface = NULL;
162   }
163
164   if (priv->codec_data) {
165     gst_buffer_unref(priv->codec_data);
166     priv->codec_data = NULL;
167   }
168
169   return TRUE;
170 }
171
172 static guint32
173 mpeg4_get_profile_level_indication(guint32 profile)
174 {
175   switch(profile) {
176   case VAProfileMPEG4Simple:
177     return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL;
178   case VAProfileMPEG4AdvancedSimple:
179     return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL;
180   default:
181     return 0;
182   }
183   return 0;
184 }
185
186 static EncoderStatus
187 gst_vaapi_encoder_mpeg4_rendering(
188     GstVaapiBaseEncoder *base,
189     GstVaapiSurface *surface,
190     guint frame_index,
191     VABufferID coded_buf,
192     gboolean *is_key
193 )
194 {
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;
202
203   VAStatus va_status = VA_STATUS_SUCCESS;
204   EncoderStatus ret = ENCODER_NO_ERROR;
205
206   *is_key = (frame_index % encoder->intra_period == 0);
207
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};
211
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;
221     }
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;
226
227     va_status = vaCreateBuffer(va_dpy, context_id,
228                                VAEncSequenceParameterBufferType,
229                                sizeof(seq_param), 1,
230                                &seq_param,
231                                &priv->seq_param_id);
232     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
233                          ENCODER_ENC_RES_ERR,
234                          "mpeg4 alloc seq-buffer failed.");
235     va_buffers[va_buffers_count++] = priv->seq_param_id;
236   }
237
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,
242                          ENCODER_SURFACE_ERR,
243                          "mpeg4 reference surface, mpeg4_pop_free_surface failed.");
244   }
245   if (!priv->recon_surface) {
246     priv->recon_surface = gst_vaapi_context_get_surface(context);
247     ENCODER_CHECK_STATUS(priv->recon_surface,
248                          ENCODER_SURFACE_ERR,
249                          "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed.");
250   }
251
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;
261   } else {
262     pic_param.modulo_time_base =
263         ((frame_index%ENCODER_FPS(encoder)) == 0 ? 1 : 0);
264   }
265   pic_param.vop_time_increment = 301%ENCODER_FPS(encoder);
266   pic_param.picture_type =
267     (*is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive);
268
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;
272   }
273
274   va_status = vaCreateBuffer(va_dpy,
275                              context_id,
276                              VAEncPictureParameterBufferType,
277                              sizeof(pic_param), 1,
278                              &pic_param,
279                              &priv->pic_param_id);
280   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
281                        ENCODER_ENC_RES_ERR,
282                        "mpeg4 creating pic-param buffer failed.");
283
284   va_buffers[va_buffers_count++] = priv->pic_param_id;
285
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;
295   }
296
297   va_status = vaCreateBuffer(va_dpy,
298                              context_id,
299                              VAEncSliceParameterBufferType,
300                              sizeof(slice_param),
301                              1,
302                              &slice_param,
303                              &priv->slice_param_id);
304   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
305                        ENCODER_ENC_RES_ERR,
306                        "mpeg4 creating slice-parameters buffer failed.");
307
308   va_buffers[va_buffers_count++] = priv->slice_param_id;
309
310   ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder),
311                                          surface,
312                                          va_buffers,
313                                          va_buffers_count);
314   ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR,
315                        ENCODER_PICTURE_ERR,
316                        "mpeg4 rendering slice-parameters buffer failed.");
317
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;
322
323 end:
324   return ret;
325 }
326
327 #if 0
328 static GstBuffer *
329 gst_vaapi_encoder_mpeg4_copy_coded_buffer(GstVaapiBaseEncoder *encoder,
330             guint8 *frame, guint32 frame_size, VABufferID *coded_buf)
331
332 {
333    /*process data*/
334   GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size);
335   memcpy(GST_BUFFER_DATA(buffer), frame, frame_size);
336
337   #if 0
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)
343     {
344       start_code[2] = 0x08;
345     }
346   }
347   #endif
348
349   return buffer;
350 }
351 #endif
352
353 static gboolean
354 find_video_object_configuration_info(
355     const guint8 *in_buffer,
356     guint32 in_size,
357     const guint8 **out_buffer,
358     guint32 *out_size
359 )
360 {
361   guint32 value = 0x00;
362   const guint8 *end = in_buffer + in_size;
363
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;
368       ++in_buffer;
369       break;
370     }
371     ++in_buffer;
372   }
373   if (in_buffer >= end)
374     return FALSE;
375
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);
380       return TRUE;
381     }
382     ++in_buffer;
383   }
384   return FALSE;
385 }
386
387 static gboolean
388 mpeg4_encoder_generate_codec_data(
389     const guint8 *in_buffer,
390     guint32 in_size,
391     GstBuffer **out_buffer
392 )
393 {
394   const guint8 *codec_buffer = NULL;
395   guint32 codec_size = 0;
396   guint8 *visual_obj_seq_end = NULL;
397
398   if (!find_video_object_configuration_info(in_buffer,
399                                             in_size,
400                                             &codec_buffer,
401                                             &codec_size)
402      ) {
403     return FALSE;
404   }
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;
413   return TRUE;
414 }
415
416 static void
417 gst_vaapi_encoder_mpeg4_notify_frame(
418     GstVaapiBaseEncoder *base,
419     guint8 *buf,
420     guint32 size
421 )
422 {
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>.");
429     }
430   }
431   if (priv->codec_data) {
432     gst_vaapi_base_encoder_set_frame_notify(base, FALSE);
433   }
434 }
435
436 static EncoderStatus
437 gst_vaapi_encoder_mpeg4_flush(
438     GstVaapiEncoder* base
439 )
440 {
441   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
442
443   mpeg4_release_parameters(encoder);
444   return ENCODER_NO_ERROR;
445 }
446
447 static EncoderStatus
448 gst_vaapi_encoder_mpeg4_get_codec_data(
449     GstVaapiEncoder *base,
450     GstBuffer **buffer
451 )
452 {
453   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
454   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
455
456   if (!priv->codec_data)
457     return ENCODER_DATA_NOT_READY;
458   *buffer = gst_buffer_ref(priv->codec_data);
459   return ENCODER_NO_ERROR;
460 }
461
462 static void
463 gst_vaapi_encoder_mpeg4_init(GstVaapiEncoderMpeg4 *encoder)
464 {
465   GstVaapiEncoderMpeg4Private *priv = GST_VAAPI_ENCODER_MPEG4_GET_PRIVATE(encoder);
466   ENCODER_ASSERT(priv);
467   encoder->priv = priv;
468
469   /* init public */
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;
475
476   gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), TRUE);
477   /* init private */
478   priv->ref_surface = NULL;
479   priv->recon_surface = NULL;
480
481   priv->seq_param_id = VA_INVALID_ID;
482   priv->pic_param_id = VA_INVALID_ID;
483   priv->slice_param_id = VA_INVALID_ID;
484
485   priv->codec_data = NULL;
486 }
487
488 static void
489 gst_vaapi_encoder_mpeg4_finalize(GObject *object)
490 {
491   /*free private buffers*/
492   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
493
494   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
495     gst_vaapi_encoder_uninitialize(encoder);
496   }
497   G_OBJECT_CLASS(gst_vaapi_encoder_mpeg4_parent_class)->finalize(object);
498 }
499
500 static void
501 gst_vaapi_encoder_mpeg4_class_init(GstVaapiEncoderMpeg4Class *klass)
502 {
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);
506
507   g_type_class_add_private(klass, sizeof(GstVaapiEncoderMpeg4Private));
508
509   GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0,
510       "gst_va_mpeg4_encoder element");
511
512   object_class->finalize = gst_vaapi_encoder_mpeg4_finalize;
513
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;
520
521   encoder_class->flush = gst_vaapi_encoder_mpeg4_flush;
522   encoder_class->get_codec_data = gst_vaapi_encoder_mpeg4_get_codec_data;
523 }