Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiencoder_h263.c
1 /*
2  *  gstvaapiencoder_h263.c - H.263 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_h263.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_h263_encoder_debug);
35 #define GST_CAT_DEFAULT gst_vaapi_h263_encoder_debug
36
37 #define GST_VAAPI_ENCODER_H263_CAST(encoder)    ((GstVaapiEncoderH263 *)(encoder))
38
39 struct _GstVaapiEncoderH263Private {
40   GstVaapiSurface  *ref_surface;  /* reference buffer*/
41   GstVaapiSurface  *recon_surface; /* reconstruct buffer*/
42
43   VABufferID        seq_param_id;
44   VABufferID        pic_param_id;
45   VABufferID        slic_param_id;
46 };
47
48 G_DEFINE_TYPE(GstVaapiEncoderH263, gst_vaapi_encoder_h263, GST_TYPE_VAAPI_BASE_ENCODER)
49
50 GstVaapiEncoderH263 *
51 gst_vaapi_encoder_h263_new(void)
52 {
53   return GST_VAAPI_ENCODER_H263_CAST(g_object_new(GST_TYPE_VAAPI_ENCODER_H263, NULL));
54 }
55
56 static gboolean
57 gst_vaapi_encoder_h263_validate_attributes(
58     GstVaapiBaseEncoder* base
59 )
60 {
61   GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base);
62   if (!ENCODER_WIDTH(encoder) ||
63       !ENCODER_HEIGHT(encoder) ||
64       !ENCODER_FPS(encoder))
65   {
66     return FALSE;
67   }
68   if (!encoder->intra_period) {
69     encoder->intra_period = H263_DEFAULT_INTRA_PERIOD;
70   }
71   if (-1 == encoder->init_qp) {
72     encoder->init_qp = H263_DEFAULT_INIT_QP;
73   }
74   if (-1 == encoder->min_qp) {
75     encoder->min_qp = H263_DEFAULT_MIN_QP;
76   }
77
78   /* default compress ratio 1: (4*8*1.5) */
79   if (!encoder->bitrate) {
80     encoder->bitrate =
81         ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4/1024;
82   }
83   gst_vaapi_base_encoder_set_va_profile(GST_VAAPI_BASE_ENCODER(encoder),
84                                         VAProfileH263Baseline);
85   return TRUE;
86
87 }
88
89
90 static void
91 h263_release_parameters(
92     GstVaapiEncoderH263 *encoder
93 )
94 {
95   GstVaapiEncoderH263Private *priv = encoder->priv;
96   VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
97   VAStatus va_status = VA_STATUS_SUCCESS;
98
99   VAAPI_UNUSED_ARG(va_status);
100
101   if (VA_INVALID_ID != priv->seq_param_id) {
102     va_status = vaDestroyBuffer(va_dpy, priv->seq_param_id);
103     priv->seq_param_id = VA_INVALID_ID;
104   }
105   if (VA_INVALID_ID != priv->pic_param_id) {
106     va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id);
107     priv->pic_param_id = VA_INVALID_ID;
108   }
109   if (VA_INVALID_ID != priv->slic_param_id) {
110     va_status = vaDestroyBuffer(va_dpy, priv->slic_param_id);
111     priv->slic_param_id = VA_INVALID_ID;
112   }
113
114 }
115
116 static gboolean
117 gst_vaapi_encoder_h263_release_resource(
118     GstVaapiBaseEncoder* base
119 )
120 {
121   GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base);
122   GstVaapiEncoderH263Private *priv = encoder->priv;
123   GstVaapiContext *context = ENCODER_CONTEXT(base);
124
125   h263_release_parameters(encoder);
126
127   /*remove ref_surface*/
128   if (priv->ref_surface) {
129     if (context) {
130       gst_vaapi_context_put_surface(context, priv->ref_surface);
131     } else {
132       g_object_unref(priv->ref_surface);
133     }
134     priv->ref_surface = NULL;
135   }
136
137   /*remove recon_surface*/
138   if (priv->recon_surface) {
139     if (context) {
140       gst_vaapi_context_put_surface(context, priv->recon_surface);
141     } else {
142       g_object_unref(priv->recon_surface);
143     }
144     priv->recon_surface = NULL;
145   }
146
147   return TRUE;
148 }
149
150 static EncoderStatus
151 gst_vaapi_encoder_h263_rendering(
152     GstVaapiBaseEncoder *base,
153     GstVaapiSurface *surface,
154     guint frame_index,
155     VABufferID coded_buf,
156     gboolean *is_key
157 )
158
159 {
160   GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base);
161   GstVaapiEncoderH263Private *priv = encoder->priv;
162   GstVaapiContext *context = ENCODER_CONTEXT(base);
163   VADisplay va_dpy = ENCODER_VA_DISPLAY(base);
164   VAContextID context_id = ENCODER_VA_CONTEXT(base);
165   VABufferID va_buffers[64];
166   guint32    va_buffers_count = 0;
167
168   VAStatus va_status = VA_STATUS_SUCCESS;
169   EncoderStatus ret = ENCODER_NO_ERROR;
170
171   *is_key = (frame_index % encoder->intra_period == 0);
172
173   /* initialize sequence parameter set, only first time */
174   if (VA_INVALID_ID == priv->seq_param_id) { /*only the first time*/
175     VAEncSequenceParameterBufferH263 seq_param = {0};
176
177     seq_param.intra_period = encoder->intra_period;
178     seq_param.bits_per_second = encoder->bitrate * 1024;
179     seq_param.frame_rate = ENCODER_FPS(encoder);
180     seq_param.initial_qp = encoder->init_qp;
181     seq_param.min_qp = encoder->min_qp;
182
183     va_status = vaCreateBuffer(va_dpy, context_id,
184                                VAEncSequenceParameterBufferType,
185                                sizeof(seq_param), 1,
186                                &seq_param,
187                                &priv->seq_param_id);
188     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
189                          ENCODER_ENC_RES_ERR,
190                          "h263 alloc seq-buffer failed.");
191     va_buffers[va_buffers_count++] = priv->seq_param_id;
192   }
193
194   /* set reference and reconstructed surfaces */
195   if (!priv->ref_surface) {
196     priv->ref_surface = gst_vaapi_context_get_surface(context);
197     ENCODER_CHECK_STATUS(priv->ref_surface,
198                          ENCODER_SURFACE_ERR,
199                          "h263 reference surface, h263_pop_free_surface failed.");
200   }
201   if (!priv->recon_surface) {
202     priv->recon_surface = gst_vaapi_context_get_surface(context);
203     ENCODER_CHECK_STATUS(priv->recon_surface,
204                          ENCODER_SURFACE_ERR,
205                          "h263 reconstructed surface, h263_pop_free_surface failed.");
206   }
207
208   /* initialize picture, every time, every frame */
209   VAEncPictureParameterBufferH263 pic_param = {0};
210   pic_param.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface);
211   pic_param.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface);
212   pic_param.coded_buf = coded_buf;
213   pic_param.picture_width = ENCODER_WIDTH(encoder);
214   pic_param.picture_height = ENCODER_HEIGHT(encoder);
215   pic_param.picture_type = (*is_key) ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
216   if (VA_INVALID_ID != priv->pic_param_id) { /* destroy first*/
217     va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id);
218     priv->pic_param_id = VA_INVALID_ID;
219   }
220
221   va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
222                                sizeof(pic_param), 1, &pic_param, &priv->pic_param_id);
223   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
224                        ENCODER_ENC_RES_ERR, "h263 creating pic-param buffer failed.");
225   va_buffers[va_buffers_count++] = priv->pic_param_id;
226
227   /*initialize slice parameters, only ONE slice for h263*/
228   VAEncSliceParameterBuffer slice_param = { 0 };
229   slice_param.start_row_number = 0;
230   slice_param.slice_height = (ENCODER_HEIGHT(encoder)+15)/16; /*MB?*/
231   slice_param.slice_flags.bits.is_intra = *is_key;
232   slice_param.slice_flags.bits.disable_deblocking_filter_idc = 0;
233   if (VA_INVALID_ID != priv->slic_param_id) {
234     vaDestroyBuffer(va_dpy, priv->slic_param_id);
235     priv->slic_param_id = VA_INVALID_ID;
236   }
237
238   va_status = vaCreateBuffer(va_dpy,
239                              context_id,
240                              VAEncSliceParameterBufferType,
241                              sizeof(slice_param),
242                              1,
243                              &slice_param,
244                              &priv->slic_param_id);
245   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
246                        ENCODER_ENC_RES_ERR,
247                        "h263 creating slice-parameters buffer failed.");
248   va_buffers[va_buffers_count++] = priv->slic_param_id;
249
250   ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder),
251                                          surface,
252                                          va_buffers,
253                                          va_buffers_count);
254   ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR,
255                        ENCODER_PICTURE_ERR,
256                        "h263 rendering slice-parameters buffer failed.");
257
258   /*swap ref_surface and recon_surface */
259   GstVaapiSurface *swap = priv->ref_surface;
260   priv->ref_surface = priv->recon_surface;
261   priv->recon_surface = swap;
262
263 end:
264   return ret;
265 }
266
267 static void
268 gst_vaapi_encoder_h263_init(GstVaapiEncoderH263 *encoder)
269 {
270   GstVaapiEncoderH263Private *priv = GST_VAAPI_ENCODER_H263_GET_PRIVATE(encoder);
271   encoder->priv = priv;
272   ENCODER_ASSERT(priv);
273
274   /* init public */
275   encoder->bitrate = 0;
276   encoder->intra_period = H263_DEFAULT_INTRA_PERIOD;
277   encoder->init_qp = H263_DEFAULT_INIT_QP;
278   encoder->min_qp = H263_DEFAULT_MIN_QP;
279
280   /* init private */
281   priv->ref_surface = NULL;
282   priv->recon_surface = NULL;
283
284   priv->seq_param_id = VA_INVALID_ID;
285   priv->pic_param_id = VA_INVALID_ID;
286   priv->slic_param_id = VA_INVALID_ID;
287 }
288
289 static void
290 gst_vaapi_encoder_h263_finalize(GObject *object)
291 {
292   /*free private buffers*/
293   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
294
295   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
296     gst_vaapi_encoder_uninitialize(encoder);
297   }
298   G_OBJECT_CLASS(gst_vaapi_encoder_h263_parent_class)->finalize(object);
299 }
300
301 static void
302 gst_vaapi_encoder_h263_class_init(GstVaapiEncoderH263Class *klass)
303 {
304   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
305   GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
306   GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
307   g_type_class_add_private(klass, sizeof(GstVaapiEncoderH263Private));
308
309   GST_DEBUG_CATEGORY_INIT (gst_vaapi_h263_encoder_debug, "gst_va_h263_encoder", 0,
310       "gst_va_h263_encoder element");
311
312   object_class->finalize = gst_vaapi_encoder_h263_finalize;
313
314   base_class->validate_attributes = gst_vaapi_encoder_h263_validate_attributes;
315   base_class->pre_alloc_resource  = NULL;
316   base_class->release_resource    = gst_vaapi_encoder_h263_release_resource;
317   base_class->render_frame = gst_vaapi_encoder_h263_rendering;
318   base_class->notify_buffer = NULL;
319   base_class->wrap_buffer = NULL;
320
321   /*
322   encoder_class->flush = gst_vaapi_encoder_h263_flush;
323   */
324   encoder_class->get_codec_data = NULL;
325
326 }