add properties in gsth264encode; profile, level,bitrate, intra-period, init-qp
[profile/ivi/gstreamer-vaapi.git] / gst / vaapiencode / gsth264encode.c
1 #include "gsth264encode.h"
2
3 #include <string.h>
4 #include <X11/Xlib.h>
5
6 #include "gst/vaapi/gstvaapivideobuffer.h"
7
8
9 #define PACKAGE "libgsth264encode"
10 #define VERSION "0.1.0"
11
12 #define GST_H264_ENCODE_CHECK_STATUS(exp, err_num, err_reason, ...)  \
13   H264_ASSERT(exp);                             \
14   if (!(exp)) {                                 \
15     ret_num = err_num;                              \
16     H264_LOG_ERROR(err_reason, ## __VA_ARGS__);                 \
17     goto finish;                                 \
18   }
19
20
21 #define GST_H264ENCODE_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_H264ENCODE, GstH264EncodePrivate))
22
23 typedef struct _GstH264EncodePrivate GstH264EncodePrivate;
24
25 static const GstElementDetails gst_h264encode_details =
26     GST_ELEMENT_DETAILS(
27         "VA-API h264 encoder",
28         "Codec/Encoder/Video",
29         "A VA-API based h264 encoder",
30         "Yuan Feng <feng.yuan@intel.com>");
31
32 /* Default templates */
33 #define GST_CAPS_CODEC(CODEC)                   \
34     CODEC ", "                                  \
35     "width  = (int) [ 1, MAX ], "               \
36     "height = (int) [ 1, MAX ]; "
37
38 static const char gst_h264encode_sink_caps_str[] =
39     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { I420 } ")
40     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { NV12 } ")
41     GST_CAPS_CODEC("video/x-vaapi-surface ")
42     GST_CAPS_CODEC("video/x-raw-va")
43     ;
44
45 static const char gst_h264encode_src_caps_str[] =
46     GST_CAPS_CODEC("video/x-h264");
47
48 static GstStaticPadTemplate gst_h264encode_sink_factory =
49     GST_STATIC_PAD_TEMPLATE(
50         "sink",
51         GST_PAD_SINK,
52         GST_PAD_ALWAYS,
53         GST_STATIC_CAPS(gst_h264encode_sink_caps_str));
54
55 static GstStaticPadTemplate gst_h264encode_src_factory =
56     GST_STATIC_PAD_TEMPLATE(
57         "src",
58         GST_PAD_SRC,
59         GST_PAD_ALWAYS,
60         GST_STATIC_CAPS(gst_h264encode_src_caps_str));
61
62 GST_BOILERPLATE(
63     GstH264Encode,
64     gst_h264encode,
65     GstElement,
66     GST_TYPE_ELEMENT);
67
68 enum {
69     PROP_0,
70     PROP_PROFILE,
71     PROP_LEVEL,
72     PROP_BITRATE,
73     PROP_INTRA_PERIOD,
74     PROP_INIT_QP,
75 };
76
77
78 /*static extern*/
79 static void gst_h264encode_finalize(GObject *object);
80 static void gst_h264encode_set_property(GObject *object, guint prop_id,
81     const GValue *value, GParamSpec *pspec);
82 static void gst_h264encode_get_property (GObject * object, guint prop_id,
83     GValue * value, GParamSpec * pspec);
84
85 static gboolean gst_h264encode_set_caps(GstPad *sink_pad, GstCaps *caps);
86 static GstCaps *gst_h264encode_get_caps(GstPad *sink_pad);
87 static GstFlowReturn gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf);
88 static GstStateChangeReturn gst_h264encode_change_state(GstElement *element, GstStateChange transition);
89 static GstFlowReturn gst_h264encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
90                            GstCaps * caps, GstBuffer ** buf);
91
92 static char* _h264_dump_caps(GstCaps *cpas);
93 static gboolean _h264_check_valid_profile(guint profile);
94 static gboolean _h264_check_valid_level(guint level);
95
96
97 /*gst fix functions*/
98
99 static void
100 gst_h264encode_base_init(gpointer klass)
101 {
102   GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
103
104   gst_element_class_set_details(element_class, &gst_h264encode_details);
105
106   /* sink pad */
107   gst_element_class_add_pad_template(
108       element_class,
109       gst_static_pad_template_get(&gst_h264encode_sink_factory)
110   );
111
112   /* src pad */
113   gst_element_class_add_pad_template(
114       element_class,
115       gst_static_pad_template_get(&gst_h264encode_src_factory)
116   );
117 }
118
119
120 static void
121 gst_h264encode_class_init(GstH264EncodeClass *klass)
122 {
123   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
124   GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
125
126   object_class->finalize      = gst_h264encode_finalize;
127   object_class->set_property  = gst_h264encode_set_property;
128   object_class->get_property  = gst_h264encode_get_property;
129
130   g_object_class_install_property (object_class, PROP_PROFILE,
131         g_param_spec_uint ("profile",
132             "H264 Profile",
133             "Profile supports: 66(Baseline), 77(Main), 100(High)",
134             H264_PROFILE_BASELINE,
135             H264_PROFILE_HIGH10,
136             H264_DEFAULT_PROFILE,
137             G_PARAM_READWRITE));
138   g_object_class_install_property (object_class, PROP_LEVEL,
139         g_param_spec_uint ("level",
140             "H264 level idc",
141             "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51",
142             H264_LEVEL_10,
143             H264_LEVEL_51,
144             H264_DEFAULT_LEVEL,
145             G_PARAM_READWRITE));
146   g_object_class_install_property (object_class, PROP_BITRATE,
147         g_param_spec_uint ("bitrate",
148             "H264 encoding bitrate",
149             "H264 encoding bitrate, 10k~100M",
150             10*1000,
151             100*1000*1000,
152             H264_DEFAULT_BITRATE,
153             G_PARAM_READWRITE));
154   g_object_class_install_property (object_class, PROP_INTRA_PERIOD,
155         g_param_spec_uint ("intra-period",
156             "H264 encoding intra-period",
157             "H264 encoding intra-period",
158             1,
159             300,
160             H264_DEFAULT_INTRA_PERIOD,
161             G_PARAM_READWRITE));
162   g_object_class_install_property (object_class, PROP_INIT_QP,
163         g_param_spec_uint ("init-qp",
164             "H264 init-qp",
165             "H264 init-qp",
166             1,
167             51,
168             H264_DEFAULT_INIT_QP,
169             G_PARAM_READWRITE));
170
171   element_class->change_state = gst_h264encode_change_state;
172 }
173
174 static void
175 gst_h264encode_finalize(GObject *object)
176 {
177   GstH264Encode * const encode = GST_H264ENCODE(object);
178
179   if (encode->sinkpad_caps) {
180     gst_caps_unref(encode->sinkpad_caps);
181     encode->sinkpad_caps = NULL;
182   }
183   encode->sinkpad = NULL;
184
185   if (encode->srcpad_caps) {
186     gst_caps_unref(encode->srcpad_caps);
187     encode->srcpad_caps = NULL;
188   }
189   encode->srcpad = NULL;
190
191   if (encode->encoder) {
192       gst_h264_encoder_close(encode->encoder);
193       gst_h264_encoder_uninitialize(encode->encoder);
194       gst_h264_encoder_unref(encode->encoder);
195       encode->encoder = NULL;
196   }
197
198   if (encode->x_display) {
199     XCloseDisplay(encode->x_display);
200     encode->x_display = NULL;
201   }
202
203   G_OBJECT_CLASS(parent_class)->finalize(object);
204 }
205
206 static void
207 gst_h264encode_init(GstH264Encode *encode, GstH264EncodeClass *klass)
208 {
209   GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
210
211   encode->sinkpad_caps       = NULL;
212   encode->srcpad_caps        = NULL;
213   encode->first_sink_frame   = TRUE;
214   encode->first_src_frame    = TRUE;
215   encode->x_display = NULL;
216
217   encode->encoder = gst_h264_encoder_new();
218   H264_ASSERT(encode->encoder);
219
220   /*sink pad */
221   encode->sinkpad = gst_pad_new_from_template(
222       gst_element_class_get_pad_template(element_class, "sink"),
223       "sink"
224   );
225   gst_pad_set_getcaps_function(encode->sinkpad, gst_h264encode_get_caps);
226   gst_pad_set_setcaps_function(encode->sinkpad, gst_h264encode_set_caps);
227   gst_pad_set_chain_function(encode->sinkpad, gst_h264encode_chain);
228   gst_pad_set_bufferalloc_function(encode->sinkpad, gst_h264encode_buffer_alloc);
229   /*gst_pad_set_event_function(encode->sinkpad, gst_h264encode_sink_event); */
230   /*gst_pad_use_fixed_caps(encode->sinkpad);*/
231   gst_element_add_pad(GST_ELEMENT(encode), encode->sinkpad);
232
233   /* src pad */
234   encode->srcpad = gst_pad_new_from_template(
235       gst_element_class_get_pad_template(element_class, "src"),
236       "src"
237   );
238   encode->srcpad_caps = NULL;
239
240   gst_pad_use_fixed_caps(encode->srcpad);
241   /*gst_pad_set_event_function(encode->srcpad, gst_h264encode_src_event);*/
242   gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad);
243 }
244
245
246 static void
247 gst_h264encode_set_property(GObject *object, guint prop_id,
248     const GValue *value, GParamSpec *pspec)
249 {
250   GstH264Encode *encode = GST_H264ENCODE(object);
251   H264_ASSERT(encode->encoder);
252
253   switch (prop_id) {
254     case PROP_PROFILE: {
255       guint profile = g_value_get_uint(value);
256       if (_h264_check_valid_profile(profile)) {
257         encode->encoder->profile = profile;
258       } else {
259         H264_LOG_ERROR("h264encode set property <profile> failed.\n");
260       }
261     }
262       break;
263
264     case PROP_LEVEL: {
265       guint level = g_value_get_uint(value);
266       if (_h264_check_valid_level(level)) {
267         encode->encoder->level= level;
268       } else {
269         H264_LOG_ERROR("h264encode set property <level> failed.\n");
270       }
271     }
272       break;
273
274     case PROP_BITRATE: {
275       encode->encoder->bitrate = g_value_get_uint(value);
276     }
277       break;
278
279     case PROP_INTRA_PERIOD: {
280       encode->encoder->intra_period = g_value_get_uint(value);
281     }
282       break;
283
284     case PROP_INIT_QP: {
285       encode->encoder->init_qp = g_value_get_uint(value);
286     }
287       break;
288
289     default:
290       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291       break;
292   }
293 }
294
295 static void
296 gst_h264encode_get_property (GObject * object, guint prop_id,
297     GValue * value, GParamSpec * pspec)
298 {
299   GstH264Encode *encode = GST_H264ENCODE(object);
300   H264_ASSERT(encode->encoder);
301
302   switch (prop_id) {
303     case PROP_PROFILE:
304       g_value_set_uint (value, encode->encoder->profile);
305       break;
306
307     case PROP_LEVEL:
308       g_value_set_uint (value, encode->encoder->level);
309       break;
310
311     case PROP_BITRATE:
312       g_value_set_uint (value, encode->encoder->bitrate);
313       break;
314
315     case PROP_INTRA_PERIOD:
316       g_value_set_uint (value, encode->encoder->intra_period);
317       break;
318
319     case PROP_INIT_QP:
320       g_value_set_uint (value, encode->encoder->init_qp);
321       break;
322
323     default:
324       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
325       break;
326   }
327 }
328
329 static gboolean
330 gst_h264encode_set_caps(GstPad *sink_pad, GstCaps *caps)
331 {
332   GstH264Encode *encode = GST_H264ENCODE(GST_OBJECT_PARENT(sink_pad));
333   GstStructure *structure;
334   gint width = 0, height = 0;
335   gint fps_n = 0, fps_d = 0;
336   const GValue *fps_value = NULL;
337   encode->sinkpad_caps = caps;
338   gst_caps_ref(caps);
339   H264_LOG_INFO("gst_h264encode_set_caps,\n%s", _h264_dump_caps(caps));
340
341   structure = gst_caps_get_structure (caps, 0);
342   if (gst_structure_get_int (structure, "width", &width)) {
343     encode->encoder->width = width;
344   }
345   if (gst_structure_get_int (structure, "height", &height)) {
346     encode->encoder->height = height;
347   }
348   fps_value = gst_structure_get_value (structure, "framerate");
349   if (fps_value) {
350     fps_n = gst_value_get_fraction_numerator (fps_value);
351     fps_d = gst_value_get_fraction_denominator (fps_value);
352     encode->encoder->frame_rate = fps_n/fps_d;
353   }
354   return TRUE;
355 }
356
357 static GstCaps *
358 gst_h264encode_get_caps(GstPad *sink_pad)
359 {
360   GstCaps *caps = NULL;
361   GstH264Encode * const encode = GST_H264ENCODE(GST_OBJECT_PARENT(sink_pad));
362   if (encode->sinkpad_caps) {
363     gst_caps_ref(encode->sinkpad_caps);
364     H264_LOG_INFO("get caps,\n%s", _h264_dump_caps(encode->sinkpad_caps));
365     return encode->sinkpad_caps;
366   }
367   caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
368   return caps;
369 }
370
371 static GstStateChangeReturn
372 gst_h264encode_change_state(GstElement *element, GstStateChange transition)
373 {
374   GstH264Encode * const encode = GST_H264ENCODE(element);
375   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
376
377   switch (transition) {
378   case GST_STATE_CHANGE_READY_TO_PAUSED:
379     break;
380   case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
381     break;
382   default:
383     break;
384   }
385
386   ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
387   if (ret != GST_STATE_CHANGE_SUCCESS)
388     return ret;
389
390   switch (transition) {
391   case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
392     break;
393   case GST_STATE_CHANGE_PAUSED_TO_READY: {
394     gst_h264_encoder_close(encode->encoder);
395   }
396     break;
397   default:
398     break;
399   }
400   return GST_STATE_CHANGE_SUCCESS;
401 }
402
403
404 static GstFlowReturn
405 gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf)
406 {
407   GstFlowReturn ret_num = GST_FLOW_OK;
408   GstH264Encode *encode = GST_H264ENCODE(GST_OBJECT_PARENT(sink_pad));
409   H264Status h264ret = H264_NO_ERROR;
410   GList *out_buffers = NULL;
411   GstBuffer *tmp_buffer = NULL;
412
413   static guint input_count = 0;
414   static guint output_count = 0;
415
416   H264_ASSERT(encode && encode->encoder);
417   if (encode->first_sink_frame) {
418     /* get first buffer caps and set encoder values */
419     GstStructure *recv_struct, *src_struct;
420     GstCaps *recv_caps = GST_BUFFER_CAPS(buf);
421     gint width, height;
422     GValue const *framerate, *format_value;
423     gint fps_n, fps_d;
424     guint32 format;
425     GstVaapiSurfacePool *surface_pool = NULL;
426
427     H264_LOG_INFO("gst_h264encode_chain 1st recv-buffer caps,\n%s", _h264_dump_caps(recv_caps));
428
429     recv_struct = gst_caps_get_structure (recv_caps, 0);
430     GST_H264_ENCODE_CHECK_STATUS(NULL != recv_caps, GST_FLOW_ERROR, "gst_h264encode_chain, 1st buffer didn't have detailed caps.\n");
431     if (gst_structure_get_int (recv_struct, "width", &width)) {
432       encode->encoder->width = width;
433     }
434     if (gst_structure_get_int (recv_struct, "height", &height)) {
435       encode->encoder->height = height;
436     }
437     framerate = gst_structure_get_value (recv_struct, "framerate");
438     if (framerate) {
439       fps_n = gst_value_get_fraction_numerator (framerate);
440       fps_d = gst_value_get_fraction_denominator (framerate);
441       encode->encoder->frame_rate = fps_n/fps_d;
442     }
443     format_value = gst_structure_get_value (recv_struct, "format");
444     if (format_value) {
445       GST_H264_ENCODE_CHECK_STATUS(format_value && GST_TYPE_FOURCC == G_VALUE_TYPE(format_value),
446                                  GST_FLOW_ERROR, "1st buffer caps' format type is not fourcc.\n");
447       format = gst_value_get_fourcc (format_value);
448       if (format) {
449         gst_h264_encoder_set_input_format(encode->encoder, format);
450       }
451     }
452
453     /*set src pad caps*/
454     if (encode->srcpad_caps) {
455       gst_caps_unref(encode->srcpad_caps);
456     }
457     encode->srcpad_caps = gst_caps_copy(gst_pad_get_pad_template_caps(encode->srcpad));
458     src_struct = gst_caps_get_structure(encode->srcpad_caps, 0);
459     gst_structure_set(src_struct, "width", G_TYPE_INT, width,
460                       "height", G_TYPE_INT, height,
461                       "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
462
463     /*set display and initialize encoder*/
464     if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
465       GstVaapiDisplay *display = NULL;
466       GstVaapiVideoBuffer *video_buffer = GST_VAAPI_VIDEO_BUFFER(buf);
467       H264_ASSERT(video_buffer);
468       display = gst_vaapi_video_buffer_get_display(video_buffer);
469       //need to get surface_pool and set to h264encoder->vaapi_context
470       //(video_buffer->priv->surface_pool);
471       #ifdef _MRST_
472       surface_pool = GST_VAAPI_SURFACE_POOL(gst_vaapi_video_buffer_get_surface_pool(video_buffer));
473       #endif
474       if (display) {
475         GST_H264_ENCODE_CHECK_STATUS(gst_h264_encoder_set_display(encode->encoder,display)
476                                     , GST_FLOW_ERROR, "set display failed in gst_h264encode_chain.\n");
477       }
478     }
479     h264ret = gst_h264_encoder_initialize(encode->encoder);
480     GST_H264_ENCODE_CHECK_STATUS (H264_NO_ERROR == h264ret, GST_FLOW_ERROR, "h264_encoder_initialize failed.\n");
481   #ifdef _MRST_
482     h264ret = gst_h264_encoder_open(encode->encoder, surface_pool);
483   #else
484     h264ret = gst_h264_encoder_open(encode->encoder);
485   #endif
486     GST_H264_ENCODE_CHECK_STATUS (H264_NO_ERROR == h264ret, GST_FLOW_ERROR, "gst_h264_encoder_open failed.\n");
487
488     encode->first_sink_frame = FALSE;
489   }
490
491   /*encoding frames*/
492   H264_ASSERT(gst_h264_encoder_get_state(encode->encoder) >= H264_ENC_OPENED);
493   ++input_count;
494   H264_LOG_INFO("input %d\n", input_count);
495   h264ret = gst_h264_encoder_encode(encode->encoder, buf, &out_buffers);
496   GST_H264_ENCODE_CHECK_STATUS (H264_NO_ERROR == h264ret, GST_FLOW_ERROR, "h264_encoder_encode failed.\n");
497
498   /*check results*/
499   while (out_buffers) {
500     tmp_buffer = out_buffers->data;
501     out_buffers = g_list_remove(out_buffers, tmp_buffer);
502     /*out_buffers = g_list_next(out_buffers);*/
503     if (encode->first_src_frame) {
504       GstBuffer *codec_data;
505       H264_ASSERT(encode->srcpad_caps);
506       /*replace codec data in src pad caps*/
507       if (H264_NO_ERROR == gst_h264_encoder_get_avcC_codec_data(encode->encoder, &codec_data)) {
508         gst_caps_set_simple(encode->srcpad_caps, "codec_data",GST_TYPE_BUFFER, codec_data, NULL);
509       }
510       gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
511       GST_BUFFER_CAPS(tmp_buffer) = gst_caps_ref(encode->srcpad_caps);
512       H264_LOG_INFO("gst_h264encode_chain 1st push-buffer caps,\n%s", _h264_dump_caps(encode->srcpad_caps));
513       encode->first_src_frame = FALSE;
514     }
515     ++output_count;
516     H264_LOG_INFO("output:%d, %" GST_TIME_FORMAT ", 0x%s\n",
517                    output_count,
518                    GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(tmp_buffer)),
519                    h264_dump_bytes(GST_BUFFER_DATA(tmp_buffer),
520                                   (GST_BUFFER_SIZE(tmp_buffer) > 16? 16: GST_BUFFER_SIZE(tmp_buffer))));
521     gst_pad_push(encode->srcpad, tmp_buffer);
522   }
523
524 finish:
525   gst_mini_object_unref(GST_MINI_OBJECT(buf));
526   return ret_num;
527
528 }
529
530 static GstFlowReturn
531 gst_h264encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
532                            GstCaps * caps, GstBuffer ** buf)
533 {
534   GstH264Encode * const encode = GST_H264ENCODE(GST_OBJECT_PARENT(pad));
535   GstStructure *structure = NULL;
536   GstBuffer *buffer;
537   GstVaapiDisplay* display = NULL;
538   GstFlowReturn ret_num = GST_FLOW_ERROR;
539
540   if (caps) {
541     structure = gst_caps_get_structure(caps, 0);
542   }
543   if (!structure || gst_structure_has_name(structure, "video/x-vaapi-surface")) {
544     H264_ASSERT(encode->encoder);
545     display = gst_h264_encoder_get_display(encode->encoder);
546     if (!display) {
547       gst_h264_encoder_initialize(encode->encoder);
548       display = gst_h264_encoder_get_display(encode->encoder);
549       GST_H264_ENCODE_CHECK_STATUS(display, GST_FLOW_ERROR, "gst_h264_encoder_get_display failed in gst_h264encode_buffer_alloc.\n");
550     }
551     buffer = gst_vaapi_video_buffer_new(display);
552   } else { /* video/x-raw-yuv */
553     buffer = gst_buffer_new_and_alloc(size);
554   }
555
556   GST_H264_ENCODE_CHECK_STATUS(buffer, GST_FLOW_ERROR, "gst_h264encode_buffer_alloc failed.\n");
557
558   GST_BUFFER_OFFSET (buffer) = offset;
559   if (caps) {
560     gst_buffer_set_caps(buffer, caps);
561   }
562   *buf = buffer;
563   ret_num = GST_FLOW_OK;
564
565 finish:
566   if (display) {
567     g_object_unref(display);
568   }
569   return ret_num;
570 }
571
572 static gboolean _h264_check_valid_profile(guint profile)
573 {
574    static const limit_profiles[] = {
575          H264_PROFILE_BASELINE,
576          H264_PROFILE_MAIN,
577          H264_PROFILE_HIGH
578         };
579    guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]);
580    guint i;
581    for (i = 0; i < n_profiles; ++i) {
582      if (limit_profiles[i] == profile)
583        return TRUE;
584    }
585    return FALSE;
586 }
587
588 static gboolean _h264_check_valid_level(guint level)
589 {
590   static const limit_levels[] = {
591         H264_LEVEL_10,
592         H264_LEVEL_11,
593         H264_LEVEL_12,
594         H264_LEVEL_13,
595         H264_LEVEL_20,
596         H264_LEVEL_21,
597         H264_LEVEL_22,
598         H264_LEVEL_30,
599         H264_LEVEL_31,
600         H264_LEVEL_32,
601         H264_LEVEL_40,
602         H264_LEVEL_41,
603         H264_LEVEL_42,
604         H264_LEVEL_50,
605         H264_LEVEL_51
606        };
607   guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]);
608   guint i;
609   for (i = 0; i < n_levels; ++i) {
610     if (limit_levels[i] == level)
611       return TRUE;
612   }
613   return FALSE;
614
615 }
616
617 static char*
618 _h264_dump_caps(GstCaps *cpas)
619 {
620   guint i = 0, j = 0;
621   GstStructure const *structure;
622   GValue const *value;
623   static char caps_string[4096*5];
624   char *tmp;
625
626   char *cur = caps_string;
627   memset(caps_string, 0, sizeof(caps_string));
628   for (i = 0; i < gst_caps_get_size(cpas); i++) {
629     structure = gst_caps_get_structure(cpas, i);
630     const char* caps_name = gst_structure_get_name (structure);
631     sprintf(cur, "cap_%02d:%s\n", i, caps_name);
632     cur += strlen(cur);
633
634     for (j = 0; j < gst_structure_n_fields(structure); j++) {
635       const char* name = gst_structure_nth_field_name(structure, j);
636       value = gst_structure_get_value(structure, name);
637       tmp = gst_value_serialize(value);
638       sprintf(cur, "\t%s:%s(%s)\n", name, tmp, G_VALUE_TYPE_NAME(value));
639       cur += strlen(cur);
640       g_free(tmp);
641     }
642   }
643
644   return caps_string;
645 }
646
647
648
649
650 /* plugin register*/
651 static gboolean
652 h264encode_init (GstPlugin * plugin)
653 {
654   return gst_element_register (plugin, "vah264encode", GST_RANK_PRIMARY,
655       GST_TYPE_H264ENCODE);
656 }
657
658 /* gstreamer looks for this structure to register mrstcamsrc */
659 GST_PLUGIN_DEFINE (
660     GST_VERSION_MAJOR,
661     GST_VERSION_MINOR,
662     "vaapiencode",
663     "Vaapi Encoder",
664     h264encode_init,
665     VERSION,
666     "LGPL",
667     "GStreamer",
668     "http://gstreamer.net/")
669
670