Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst / vaapi / gstvaapiencode_h264.c
1 /*
2  *  gstvaapiencode_h264.c - VA-API H.264 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 "gstvaapiencode_h264.h"
23 #include "gst/vaapi/gstvaapiencoder_h264.h"
24 #include "gst/vaapi/gstvaapivalue.h"
25
26 #include <string.h>
27
28 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug);
29 #define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug
30
31 static const char gst_vaapi_encode_h264_sink_caps_str[] =
32     GST_VAAPI_SURFACE_CAPS "; "
33     GST_VAAPI_BUFFER_SHARING_CAPS;
34
35 static const GstElementDetails gst_vaapi_encode_h264_details =
36     GST_ELEMENT_DETAILS(
37         "VA-API h264 encoder",
38         "Codec/Encoder/Video",
39         "A VA-API based h264 encoder",
40         "Feng Yuan<feng.yuan@intel.com>");
41
42
43 static const char gst_vaapi_encode_h264_src_caps_str[] =
44     GST_CAPS_CODEC("video/x-h264");
45
46 static GstStaticPadTemplate gst_vaapi_encode_h264_sink_factory =
47     GST_STATIC_PAD_TEMPLATE(
48         "sink",
49         GST_PAD_SINK,
50         GST_PAD_ALWAYS,
51         GST_STATIC_CAPS(gst_vaapi_encode_h264_sink_caps_str));
52
53 static GstStaticPadTemplate gst_vaapi_encode_h264_src_factory =
54     GST_STATIC_PAD_TEMPLATE(
55         "src",
56         GST_PAD_SRC,
57         GST_PAD_ALWAYS,
58         GST_STATIC_CAPS(gst_vaapi_encode_h264_src_caps_str));
59
60 /* h264 encode */
61 GST_BOILERPLATE(
62     GstVaapiEncodeH264,
63     gst_vaapi_encode_h264,
64     GstVaapiEncode,
65     GST_TYPE_VAAPI_ENCODE)
66
67 enum {
68     H264_PROP_0,
69     H264_PROP_PROFILE,
70     H264_PROP_LEVEL,
71     H264_PROP_RATE_CONTROL,
72     H264_PROP_BITRATE,
73     H264_PROP_INTRA_PERIOD,
74     H264_PROP_INIT_QP,
75     H264_PROP_MIN_QP,
76     H264_PROP_SLICE_NUM,
77     H264_PROP_B_FRAME_NUM,
78 };
79
80 static void
81 gst_vaapi_encode_h264_init(
82     GstVaapiEncodeH264 *h264_encode,
83     GstVaapiEncodeH264Class *klass
84 )
85 {
86   GstVaapiEncode *encode = GST_VAAPI_ENCODE(h264_encode);
87   encode->encoder = GST_VAAPI_ENCODER(gst_vaapi_encoder_h264_new());
88   ENCODER_ASSERT(encode->encoder);
89 }
90
91 static void
92 gst_vaapi_encode_h264_finalize(GObject *object)
93 {
94   //GstVaapiEncodeH264 * const h264_encode = GST_VAAPI_ENCODE_H264(object);
95   G_OBJECT_CLASS(parent_class)->finalize(object);
96 }
97
98
99 static inline gboolean
100 h264_check_valid_profile(guint profile)
101 {
102    static const guint limit_profiles[] = {
103          H264_PROFILE_BASELINE,
104          H264_PROFILE_MAIN,
105          H264_PROFILE_HIGH
106         };
107    guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]);
108    guint i;
109    for (i = 0; i < n_profiles; ++i) {
110      if (limit_profiles[i] == profile)
111        return TRUE;
112    }
113    return FALSE;
114 }
115
116 static inline gboolean
117 h264_check_valid_level(guint level)
118 {
119   static const guint limit_levels[] = {
120         H264_LEVEL_10,
121         H264_LEVEL_11,
122         H264_LEVEL_12,
123         H264_LEVEL_13,
124         H264_LEVEL_20,
125         H264_LEVEL_21,
126         H264_LEVEL_22,
127         H264_LEVEL_30,
128         H264_LEVEL_31,
129         H264_LEVEL_32,
130         H264_LEVEL_40,
131         H264_LEVEL_41,
132         H264_LEVEL_42,
133         H264_LEVEL_50,
134         H264_LEVEL_51
135        };
136   guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]);
137   guint i;
138   for (i = 0; i < n_levels; ++i) {
139     if (limit_levels[i] == level)
140       return TRUE;
141   }
142   return FALSE;
143
144 }
145
146
147 static void
148 gst_vaapi_encode_h264_set_property(
149     GObject *object,
150     guint prop_id,
151     const GValue *value,
152     GParamSpec *pspec
153 )
154 {
155   GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
156   GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder);
157
158   ENCODER_ASSERT(h264encoder);
159
160   switch (prop_id) {
161     case H264_PROP_PROFILE: {
162       guint profile = g_value_get_uint(value);
163       if (h264_check_valid_profile(profile)) {
164         h264encoder->profile = profile;
165       } else {
166         ENCODER_LOG_ERROR("h264encode set property <profile> failed.");
167       }
168     }
169       break;
170
171     case H264_PROP_LEVEL: {
172       guint level = g_value_get_uint(value);
173       if (h264_check_valid_level(level)) {
174         h264encoder->level= level;
175       } else {
176         ENCODER_LOG_ERROR("h264encode set property <level> failed.");
177       }
178     }
179       break;
180
181     case H264_PROP_RATE_CONTROL: {
182       ENCODER_RATE_CONTROL(h264encoder) = g_value_get_enum(value);
183     }
184       break;
185
186     case H264_PROP_BITRATE: {
187       h264encoder->bitrate = g_value_get_uint(value);
188     }
189       break;
190
191     case H264_PROP_INTRA_PERIOD: {
192       h264encoder->intra_period = g_value_get_uint(value);
193     }
194       break;
195
196     case H264_PROP_INIT_QP: {
197       h264encoder->init_qp = g_value_get_uint(value);
198     }
199       break;
200
201     case H264_PROP_MIN_QP: {
202       h264encoder->min_qp = g_value_get_uint(value);
203     }
204       break;
205
206     case H264_PROP_SLICE_NUM: {
207       h264encoder->slice_num= g_value_get_uint(value);
208     }
209       break;
210
211     case H264_PROP_B_FRAME_NUM: {
212       h264encoder->b_frame_num= g_value_get_uint(value);
213     }
214       break;
215
216     default:
217       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
218       break;
219   }
220 }
221
222 static void
223 gst_vaapi_encode_h264_get_property (
224     GObject * object,
225     guint prop_id,
226     GValue * value,
227     GParamSpec * pspec
228 )
229 {
230   GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
231   GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder);
232   ENCODER_ASSERT(h264encoder);
233
234   switch (prop_id) {
235     case H264_PROP_PROFILE:
236       g_value_set_uint (value, h264encoder->profile);
237       break;
238
239     case H264_PROP_LEVEL:
240       g_value_set_uint (value, h264encoder->level);
241       break;
242
243     case H264_PROP_RATE_CONTROL:
244       g_value_set_enum(value, ENCODER_RATE_CONTROL(h264encoder));
245       break;
246
247     case H264_PROP_BITRATE:
248       g_value_set_uint (value, h264encoder->bitrate);
249       break;
250
251     case H264_PROP_INTRA_PERIOD:
252       g_value_set_uint (value, h264encoder->intra_period);
253       break;
254
255     case H264_PROP_INIT_QP:
256       g_value_set_uint (value, h264encoder->init_qp);
257       break;
258
259     case H264_PROP_MIN_QP:
260       g_value_set_uint (value, h264encoder->min_qp);
261       break;
262
263     case H264_PROP_SLICE_NUM:
264       g_value_set_uint (value, h264encoder->slice_num);
265       break;
266
267     case H264_PROP_B_FRAME_NUM:
268       g_value_set_uint (value, h264encoder->b_frame_num);
269       break;
270
271     default:
272       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273       break;
274   }
275 }
276
277 static gboolean
278 gst_vaapi_encode_h264_set_src_caps(
279     GstVaapiEncode* encode,
280     GstCaps *caps
281 )
282 {
283   GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder);
284   GstCaps *peer_caps, *allowed_caps;
285   GstStructure *s;
286   const gchar *stream_format;
287
288   g_return_val_if_fail(caps,FALSE);
289   peer_caps = gst_pad_peer_get_caps_reffed(encode->srcpad);
290   if (peer_caps) {
291     allowed_caps = gst_caps_intersect(peer_caps, caps);
292     if (allowed_caps) {
293       allowed_caps = gst_caps_make_writable(allowed_caps);
294       gst_pad_fixate_caps(encode->srcpad, caps);
295       s = gst_caps_get_structure (allowed_caps, 0);
296       stream_format = gst_structure_get_string (s, "stream-format");
297       if (stream_format) {
298         if (!strcmp (stream_format, "avc")) {
299             gst_vaapi_encoder_h264_set_avc_flag(h264encoder, TRUE);
300         } else if (!strcmp (stream_format, "byte-stream")) {
301             gst_vaapi_encoder_h264_set_avc_flag(h264encoder, FALSE);
302         }
303       }
304       gst_caps_unref(allowed_caps);
305     }
306     gst_caps_unref(peer_caps);
307   }
308   gst_caps_set_simple(caps, "stream-format",
309                             G_TYPE_STRING,
310                             (gst_vaapi_encoder_h264_get_avc_flag(h264encoder) ? "avc" : "byte-stream"),
311                             "alignment", G_TYPE_STRING, "au",
312                             NULL);
313   return TRUE;
314 }
315
316 static void
317 gst_vaapi_encode_h264_base_init(gpointer klass)
318 {
319   GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
320
321   gst_element_class_set_details(element_class, &gst_vaapi_encode_h264_details);
322
323   /* sink pad */
324   gst_element_class_add_pad_template(
325       element_class,
326       gst_static_pad_template_get(&gst_vaapi_encode_h264_sink_factory)
327   );
328
329   /* src pad */
330   gst_element_class_add_pad_template(
331       element_class,
332       gst_static_pad_template_get(&gst_vaapi_encode_h264_src_factory)
333   );
334 }
335
336 static void
337 gst_vaapi_encode_h264_class_init(GstVaapiEncodeH264Class *klass)
338 {
339   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
340   GstVaapiEncodeClass *const encode_class = GST_VAAPI_ENCODE_CLASS(klass);
341   GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encode_debug,
342                            "vaapih264encode",
343                            0,
344                            "vaapih264encode element");
345
346   object_class->finalize      = gst_vaapi_encode_h264_finalize;
347   object_class->set_property  = gst_vaapi_encode_h264_set_property;
348   object_class->get_property  = gst_vaapi_encode_h264_get_property;
349
350   encode_class->set_encoder_src_caps = gst_vaapi_encode_h264_set_src_caps;
351
352   g_object_class_install_property (
353       object_class,
354       H264_PROP_PROFILE,
355       g_param_spec_uint (
356           "profile",
357           "H264 Profile",
358           "Profile supports: 66(Baseline), 77(Main), 100(High)",
359           H264_PROFILE_BASELINE,
360           H264_PROFILE_HIGH10,
361           H264_DEFAULT_PROFILE,
362           G_PARAM_READWRITE));
363
364   g_object_class_install_property (
365       object_class,
366       H264_PROP_LEVEL,
367       g_param_spec_uint (
368           "level",
369           "H264 level idc",
370           "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41",
371           H264_LEVEL_10,
372           H264_LEVEL_41,
373           H264_DEFAULT_LEVEL,
374           G_PARAM_READWRITE));
375
376   g_object_class_install_property (
377       object_class,
378       H264_PROP_RATE_CONTROL,
379       g_param_spec_enum ("rate-control",
380           "rate-control",
381           "Rate control mode",
382           GST_VAAPI_TYPE_RATE_CONTROL,
383           GST_VAAPI_RATECONTROL_NONE,
384           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385
386   g_object_class_install_property (
387       object_class,
388       H264_PROP_BITRATE,
389       g_param_spec_uint (
390           "bitrate",
391           "H264 encoding bitrate(kbps)",
392           "H264 encoding bitrate(kbps), (0, auto-calculate)",
393           0,
394           100*1024,
395           0,
396           G_PARAM_READWRITE));
397
398   g_object_class_install_property (
399       object_class,
400       H264_PROP_INTRA_PERIOD,
401       g_param_spec_uint (
402           "intra-period",
403           "H264 encoding intra-period",
404           "H264 encoding intra-period",
405           1,
406           300,
407           H264_DEFAULT_INTRA_PERIOD,
408           G_PARAM_READWRITE));
409
410   g_object_class_install_property (
411       object_class,
412       H264_PROP_INIT_QP,
413       g_param_spec_uint (
414           "init-qp",
415           "H264 init-qp",
416           "H264 init-qp",
417           1,
418           51,
419           H264_DEFAULT_INIT_QP,
420           G_PARAM_READWRITE));
421
422   g_object_class_install_property (
423       object_class,
424       H264_PROP_MIN_QP,
425       g_param_spec_uint (
426           "min-qp",
427           "H264 min-qp",
428           "H264 min-qp",
429           1,
430           51,
431           H264_DEFAULT_MIN_QP,
432           G_PARAM_READWRITE));
433
434   g_object_class_install_property (
435       object_class,
436       H264_PROP_SLICE_NUM,
437       g_param_spec_uint (
438           "slice-num",
439           "H264 slice num",
440           "H264 slice num",
441           1,
442           200,
443           1,
444           G_PARAM_READWRITE));
445
446   g_object_class_install_property (
447       object_class,
448       H264_PROP_B_FRAME_NUM,
449       g_param_spec_uint (
450           "b-frame-num",
451           "B frams num",
452           "B frams num",
453           0,
454           10,
455           0,
456           G_PARAM_READWRITE));
457 }