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