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