encoder: reduce function parameters and change variable names
[vaapi:windyuan-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 "gst/vaapi/gstvaapiobject.h"
28 #include "gst/vaapi/gstvaapiobject_priv.h"
29 #include "gst/vaapi/gstvaapicontext.h"
30 #include "gst/vaapi/gstvaapisurface.h"
31 #include "gst/vaapi/gstvaapivideobuffer.h"
32 #include "gst/vaapi/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_parameter;
56   VABufferID        pic_parameter;
57   VABufferID        slice_parameter;
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(g_object_new(GST_TYPE_VAAPI_ENCODER_MPEG4, NULL));
68 }
69
70 gboolean
71 gst_mpeg4_validate_parameters(GstVaapiBaseEncoder *base)
72 {
73   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
74   if (!ENCODER_WIDTH(encoder) || !ENCODER_HEIGHT(encoder) || !ENCODER_FPS(encoder)) {
75     return FALSE;
76   }
77   if (VAProfileMPEG4Simple != encoder->profile && VAProfileMPEG4AdvancedSimple != encoder->profile) {
78     return FALSE;
79   }
80   gst_vaapi_base_encoder_set_va_profile(base, encoder->profile);
81
82   if (!encoder->intra_period) {
83     encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
84   }
85   if (-1 == encoder->init_qp) {
86     encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
87   }
88   if (-1 == encoder->min_qp) {
89     encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
90   }
91
92   /* default compress ratio 1: (4*8*1.5) */
93   if (!encoder->bitrate) {
94     encoder->bitrate = ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4;
95   }
96   return TRUE;
97
98 }
99
100 static void
101 mpeg4_release_parameters(GstVaapiEncoderMpeg4 *encoder)
102 {
103   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
104   VADisplay va_dpy = ENCODER_DISPLAY(encoder);
105   VAStatus va_status = VA_STATUS_SUCCESS;
106
107   VAAPI_UNUSED_ARG(va_status);
108
109   if (VA_INVALID_ID != priv->seq_parameter) {
110     va_status = vaDestroyBuffer(va_dpy, priv->seq_parameter);
111     priv->seq_parameter = VA_INVALID_ID;
112   }
113   if (VA_INVALID_ID != priv->pic_parameter) {
114     va_status = vaDestroyBuffer(va_dpy, priv->pic_parameter);
115     priv->pic_parameter = VA_INVALID_ID;
116   }
117   if (VA_INVALID_ID != priv->slice_parameter) {
118     va_status = vaDestroyBuffer(va_dpy, priv->slice_parameter);
119     priv->slice_parameter = VA_INVALID_ID;
120   }
121 }
122
123 static gboolean
124 gst_vaapi_encoder_mpeg4_release_resource(GstVaapiBaseEncoder* base)
125 {
126   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
127   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
128   GstVaapiContext *context = ENCODER_CONTEXT(base);
129
130   mpeg4_release_parameters(encoder);
131
132   /*remove ref_surface*/
133   if (priv->ref_surface) {
134     if (context) {
135       gst_vaapi_context_put_surface(context, priv->ref_surface);
136     } else {
137       g_object_unref(priv->ref_surface);
138     }
139     priv->ref_surface = NULL;
140   }
141
142   /*remove recon_surface*/
143   if (priv->recon_surface) {
144     if (context) {
145       gst_vaapi_context_put_surface(context, priv->recon_surface);
146     } else {
147       g_object_unref(priv->recon_surface);
148     }
149     priv->recon_surface = NULL;
150   }
151
152   if (priv->codec_data) {
153     gst_buffer_unref(priv->codec_data);
154     priv->codec_data = NULL;
155   }
156
157   return TRUE;
158 }
159
160 static guint32
161 mpeg4_get_profile_level_indication(guint32 profile)
162 {
163   switch(profile) {
164   case VAProfileMPEG4Simple:
165     return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL;
166   case VAProfileMPEG4AdvancedSimple:
167     return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL;
168   default:
169     return 0;
170   }
171   return 0;
172 }
173
174
175 static EncoderStatus
176 gst_vaapi_encoder_mpeg4_rendering(
177     GstVaapiBaseEncoder *base,
178     GstVaapiSurface *surface,
179     guint frame_index,
180     VABufferID coded_buf,
181     gboolean *is_key
182 )
183 {
184   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
185   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
186   GstVaapiContext *context = ENCODER_CONTEXT(base);
187   VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
188   VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
189
190   VAStatus va_status = VA_STATUS_SUCCESS;
191   EncoderStatus ret = ENCODER_NO_ERROR;
192
193   *is_key = (frame_index % encoder->intra_period == 0);
194
195   /* initialize sequence parameter set, only first time */
196   if (VA_INVALID_ID == priv->seq_parameter) { /*only the first time*/
197     VAEncSequenceParameterBufferMPEG4 seq_mpeg4 = {0};
198
199     seq_mpeg4.profile_and_level_indication = mpeg4_get_profile_level_indication(encoder->profile);
200     seq_mpeg4.intra_period = encoder->intra_period;
201     seq_mpeg4.video_object_layer_width = ENCODER_WIDTH(encoder);
202     seq_mpeg4.video_object_layer_height = ENCODER_HEIGHT(encoder);
203     seq_mpeg4.vop_time_increment_resolution = ENCODER_FPS(encoder);
204     seq_mpeg4.fixed_vop_rate = MPEG4_DEFAULT_FIXED_VOP_RATE;
205     if (seq_mpeg4.fixed_vop_rate) {
206       seq_mpeg4.fixed_vop_time_increment = 1;
207     }
208     seq_mpeg4.bits_per_second = encoder->bitrate;
209     seq_mpeg4.frame_rate = ENCODER_FPS(encoder);
210     seq_mpeg4.initial_qp = encoder->init_qp;
211     seq_mpeg4.min_qp = encoder->min_qp; //mpeg4_encoder->min_qp;
212
213     va_status = vaCreateBuffer(va_dpy, context_id,
214                                VAEncSequenceParameterBufferType,
215                                sizeof(seq_mpeg4), 1, &seq_mpeg4, &priv->seq_parameter);
216     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
217                          ENCODER_ENC_RES_ERR, "mpeg4 alloc seq-buffer failed.");
218     va_status = vaRenderPicture(va_dpy, context_id, &priv->seq_parameter, 1);
219     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
220                          ENCODER_PICTURE_ERR,
221                          "mpeg4 vaRenderPicture seq-parameters failed.");
222   }
223
224   /* set reference and reconstructed surfaces */
225   if (!priv->ref_surface) {
226     priv->ref_surface = gst_vaapi_context_get_surface(context);
227     ENCODER_CHECK_STATUS(priv->ref_surface,
228                          ENCODER_SURFACE_ERR,
229                          "mpeg4 reference surface, mpeg4_pop_free_surface failed.");
230   }
231   if (!priv->recon_surface) {
232     priv->recon_surface = gst_vaapi_context_get_surface(context);
233     ENCODER_CHECK_STATUS(priv->recon_surface,
234                          ENCODER_SURFACE_ERR,
235                          "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed.");
236   }
237
238   /* initialize picture, every time, every frame */
239   VAEncPictureParameterBufferMPEG4 pic_mpeg4 = {0};
240   pic_mpeg4.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface);
241   pic_mpeg4.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface);
242   pic_mpeg4.coded_buf = coded_buf;
243   pic_mpeg4.picture_width = ENCODER_WIDTH(encoder);
244   pic_mpeg4.picture_height = ENCODER_HEIGHT(encoder);
245   if (0 == frame_index) {
246     pic_mpeg4.modulo_time_base = 0;
247   } else {
248     pic_mpeg4.modulo_time_base = ((frame_index%ENCODER_FPS(encoder)) == 0 ? 1 : 0);
249   }
250   pic_mpeg4.vop_time_increment = 301%ENCODER_FPS(encoder);
251   pic_mpeg4.picture_type = *is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
252
253   if (VA_INVALID_ID != priv->pic_parameter) { /* destroy first*/
254     va_status = vaDestroyBuffer(va_dpy, priv->pic_parameter);
255     priv->pic_parameter = VA_INVALID_ID;
256   }
257
258   va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
259                                sizeof(pic_mpeg4), 1, &pic_mpeg4, &priv->pic_parameter);
260   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
261                        ENCODER_ENC_RES_ERR,
262                        "mpeg4 creating pic-param buffer failed.");
263   va_status = vaRenderPicture(va_dpy, context_id, &priv->pic_parameter, 1);
264   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
265                        ENCODER_PICTURE_ERR,
266                        "mpeg4 rendering pic-param buffer failed.");
267   /*initialize slice parameters, only ONE slice for mpeg4*/
268   VAEncSliceParameterBuffer slice_mpeg4 = { 0 };
269   slice_mpeg4.start_row_number = 0;
270   slice_mpeg4.slice_height = (ENCODER_HEIGHT(encoder)+15)/16; /*MB?*/
271   slice_mpeg4.slice_flags.bits.is_intra = *is_key;
272   slice_mpeg4.slice_flags.bits.disable_deblocking_filter_idc = 0;
273   if (VA_INVALID_ID != priv->slice_parameter) {
274     vaDestroyBuffer(va_dpy, priv->slice_parameter);
275     priv->slice_parameter = VA_INVALID_ID;
276   }
277
278   va_status = vaCreateBuffer(va_dpy,
279                              context_id,
280                              VAEncSliceParameterBufferType,
281                              sizeof(slice_mpeg4),
282                              1,
283                              &slice_mpeg4,
284                              &priv->slice_parameter);
285   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
286                        ENCODER_ENC_RES_ERR,
287                        "mpeg4 creating slice-parameters buffer failed.");
288
289   va_status = vaRenderPicture(va_dpy, context_id, &priv->slice_parameter, 1);
290   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
291                        ENCODER_PICTURE_ERR,
292                        "mpeg4 rendering slice-parameters buffer failed.");
293
294   /*swap ref_surface and recon_surface */
295   GstVaapiSurface *swap = priv->ref_surface;
296   priv->ref_surface = priv->recon_surface;
297   priv->recon_surface = swap;
298
299 end:
300   return ret;
301 }
302
303 #if 0
304 static GstBuffer *
305 gst_vaapi_encoder_mpeg4_copy_coded_buffer(GstVaapiBaseEncoder *encoder,
306             guint8 *frame, guint32 frame_size, VABufferID *coded_buf)
307
308 {
309    /*process data*/
310   GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size);
311   memcpy(GST_BUFFER_DATA(buffer), frame, frame_size);
312
313   #if 0
314   GstVaapiEncoderMpeg4 *mpeg4_encoder = GST_VAAPI_ENCODER_MPEG4_CAST(encoder);
315   if (mpeg4_encoder->profile == VAProfileMPEG4AdvancedSimple) {
316     guint8 *start_code = GST_BUFFER_DATA(buffer)+16; /*fix old issue of ASP in mrst platform*/
317     if (start_code[0] == 0x01 && start_code[1] == 0x20
318         && start_code[-1] == 0x00 && start_code[-2] == 0x00)
319     {
320       start_code[2] = 0x08;
321     }
322   }
323   #endif
324
325   return buffer;
326 }
327 #endif
328
329 static gboolean
330 find_video_object_configuration_info(const guint8 *in_buffer, guint32 in_size,
331                                      const guint8 **out_buffer, guint32 *out_size)
332 {
333   guint32 value = 0x00;
334   const guint8 *end = in_buffer + in_size;
335
336   while(in_buffer < end) {
337     value = ((value<<8)|(*in_buffer));
338     if (VISUAL_OBJECT_SEQUENCE_START_CODE == value) {
339       *out_buffer = in_buffer - 3;
340       ++in_buffer;
341       break;
342     }
343     ++in_buffer;
344   }
345   if (in_buffer >= end)
346     return FALSE;
347
348   while(in_buffer < end) {
349     value = ((value<<8)|(*in_buffer));
350     if (VIDEO_OBJECT_PLANE_START_CODE == value) {
351       *out_size = (in_buffer - 3 - *out_buffer);
352       return TRUE;
353     }
354     ++in_buffer;
355   }
356   return FALSE;
357 }
358
359 static gboolean
360 mpeg4_encoder_generate_codec_data(
361     const guint8 *in_buffer,
362     guint32 in_size,
363     GstBuffer **out_buffer
364 )
365 {
366   const guint8 *codec_buffer = NULL;
367   guint32 codec_size = 0;
368   guint8 *visual_obj_seq_end = NULL;
369
370   if (!find_video_object_configuration_info(in_buffer,
371                                             in_size,
372                                             &codec_buffer,
373                                             &codec_size)
374      ) {
375     return FALSE;
376   }
377   ENCODER_ASSERT(codec_size);
378   *out_buffer = gst_buffer_new_and_alloc(codec_size+4);
379   memcpy(GST_BUFFER_DATA(*out_buffer), codec_buffer, codec_size);
380   visual_obj_seq_end = GST_BUFFER_DATA(*out_buffer) + codec_size;
381   visual_obj_seq_end[0] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>24);
382   visual_obj_seq_end[1] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>16);
383   visual_obj_seq_end[2] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>8);
384   visual_obj_seq_end[3] = (guint8)VISUAL_OBJECT_SEQUENCE_END_CODE;
385   return TRUE;
386 }
387
388 static void
389 gst_mpeg4_notify_frame(GstVaapiBaseEncoder *base, guint8 *buf, guint32 size)
390 {
391   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
392   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
393   if (!priv->codec_data) {
394     if (!mpeg4_encoder_generate_codec_data(buf, size, &priv->codec_data)) {
395       ENCODER_LOG_ERROR("mpeg4 encoder coded data error, please check <mpeg4_encoder_generate_codec_data>.");
396     }
397   }
398   if (priv->codec_data) {
399     gst_vaapi_base_encoder_set_frame_notify(base, FALSE);
400   }
401 }
402
403
404 static EncoderStatus
405 gst_vaapi_encoder_mpeg4_flush(
406     GstVaapiEncoder* base,
407     GList **coded_pics)
408 {
409   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
410
411   mpeg4_release_parameters(encoder);
412   return ENCODER_NO_ERROR;
413 }
414
415
416 static EncoderStatus
417 gst_vaapi_encoder_mpeg4_get_codec_data(GstVaapiEncoder *base, GstBuffer **buffer)
418 {
419   GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base);
420   GstVaapiEncoderMpeg4Private *priv = encoder->priv;
421
422   if (!priv->codec_data)
423     return ENCODER_DATA_NOT_READY;
424   *buffer = gst_buffer_ref(priv->codec_data);
425   return ENCODER_NO_ERROR;
426 }
427
428 static void
429 gst_vaapi_encoder_mpeg4_init(GstVaapiEncoderMpeg4 *encoder)
430 {
431   GstVaapiEncoderMpeg4Private *priv = GST_VAAPI_ENCODER_MPEG4_GET_PRIVATE(encoder);
432   ENCODER_ASSERT(priv);
433   encoder->priv = priv;
434
435   /* init public */
436   encoder->profile = VAProfileMPEG4Simple;
437   encoder->bitrate = 0;
438   encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
439   encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
440   encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
441
442   gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), TRUE);
443   /* init private */
444   priv->ref_surface = NULL;
445   priv->recon_surface = NULL;
446
447   priv->seq_parameter = VA_INVALID_ID;
448   priv->pic_parameter = VA_INVALID_ID;
449   priv->slice_parameter = VA_INVALID_ID;
450
451   priv->codec_data = NULL;
452 }
453
454 static void
455 gst_vaapi_encoder_mpeg4_finalize(GObject *object)
456 {
457   /*free private buffers*/
458   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
459
460   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
461     gst_vaapi_encoder_uninitialize(encoder);
462   }
463   G_OBJECT_CLASS(gst_vaapi_encoder_mpeg4_parent_class)->finalize(object);
464 }
465
466 static void
467 gst_vaapi_encoder_mpeg4_class_init(GstVaapiEncoderMpeg4Class *klass)
468 {
469   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
470   GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
471   GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
472
473   g_type_class_add_private(klass, sizeof(GstVaapiEncoderMpeg4Private));
474
475   GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0,
476       "gst_va_mpeg4_encoder element");
477
478   object_class->finalize = gst_vaapi_encoder_mpeg4_finalize;
479
480   base_class->validate_attributes = gst_mpeg4_validate_parameters;
481   base_class->pre_alloc_resource  = NULL;
482   base_class->release_resource    = gst_vaapi_encoder_mpeg4_release_resource;
483   base_class->render_frame = gst_vaapi_encoder_mpeg4_rendering;
484   base_class->notify_frame = gst_mpeg4_notify_frame;
485   base_class->copy_coded_frame = NULL;
486
487   encoder_class->flush = gst_vaapi_encoder_mpeg4_flush;
488   encoder_class->get_codec_data = gst_vaapi_encoder_mpeg4_get_codec_data;
489 }