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