h264encoder: auto-detect stream-format: avc/byte-stream by next linked-pad's caps
[vaapi:windyuan-gstreamer-vaapi.git] / gst / vaapiencode / gstvaapih264encode.c
1 /*
2  *  gstvaapih264encode.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 "gstvaapih264encode.h"
23 #include "gstvaapih264encoder.h"
24
25 #include <string.h>
26
27 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug);
28 #define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug
29
30 static const char gst_h264encode_sink_caps_str[] =
31     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { I420 } ")
32     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { NV12 } ")
33     GST_VAAPI_SURFACE_CAPS;
34
35 static const GstElementDetails gst_h264encode_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_h264encode_src_caps_str[] =
44     GST_CAPS_CODEC("video/x-h264");
45
46 static GstStaticPadTemplate gst_h264encode_sink_factory =
47     GST_STATIC_PAD_TEMPLATE(
48         "sink",
49         GST_PAD_SINK,
50         GST_PAD_ALWAYS,
51         GST_STATIC_CAPS(gst_h264encode_sink_caps_str));
52
53 static GstStaticPadTemplate gst_h264encode_src_factory =
54     GST_STATIC_PAD_TEMPLATE(
55         "src",
56         GST_PAD_SRC,
57         GST_PAD_ALWAYS,
58         GST_STATIC_CAPS(gst_h264encode_src_caps_str));
59
60 static void gst_h264encode_finalize(GObject *object);
61 static void gst_h264encode_set_property(GObject *object, guint prop_id,
62     const GValue *value, GParamSpec *pspec);
63 static void gst_h264encode_get_property (GObject * object, guint prop_id,
64     GValue * value, GParamSpec * pspec);
65 static gboolean _h264_check_valid_profile(guint profile);
66 static gboolean _h264_check_valid_level(guint level);
67 static gboolean  gst_h264encode_set_src_caps(GstVaapiEncode* encode, GstCaps *caps);
68
69
70 /* h264 encode */
71 GST_BOILERPLATE(
72     GstH264Encode,
73     gst_h264encode,
74     GstVaapiEncode,
75     GST_TYPE_VAAPI_ENCODE);
76
77 enum {
78     H264_PROP_0,
79     H264_PROP_PROFILE,
80     H264_PROP_LEVEL,
81     H264_PROP_BITRATE,
82     H264_PROP_INTRA_PERIOD,
83     H264_PROP_INIT_QP,
84     H264_PROP_MIN_QP,
85     H264_PROP_SLICE_NUM,
86     H264_PROP_B_FRAME_NUM,
87 };
88
89
90 static void
91 gst_h264encode_base_init(gpointer klass)
92 {
93   GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
94
95   gst_element_class_set_details(element_class, &gst_h264encode_details);
96
97   /* sink pad */
98   gst_element_class_add_pad_template(
99       element_class,
100       gst_static_pad_template_get(&gst_h264encode_sink_factory)
101   );
102
103   /* src pad */
104   gst_element_class_add_pad_template(
105       element_class,
106       gst_static_pad_template_get(&gst_h264encode_src_factory)
107   );
108 }
109
110 static void
111 gst_h264encode_class_init(GstH264EncodeClass *klass)
112 {
113   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
114   GstVaapiEncodeClass *const encode_class = GST_VAAPI_ENCODE_CLASS(klass);
115   GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encode_debug, "vaapih264encode", 0,
116       "vaapih264encode element");
117
118   GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encode_debug, "vaapih264encode", 0,
119       "vaapih264encode element");
120
121   object_class->finalize      = gst_h264encode_finalize;
122   object_class->set_property  = gst_h264encode_set_property;
123   object_class->get_property  = gst_h264encode_get_property;
124
125   encode_class->set_encoder_src_caps = gst_h264encode_set_src_caps;
126
127   g_object_class_install_property (object_class, H264_PROP_PROFILE,
128           g_param_spec_uint ("profile",
129               "H264 Profile",
130               "Profile supports: 66(Baseline), 77(Main), 100(High)",
131               H264_PROFILE_BASELINE,
132               H264_PROFILE_HIGH10,
133               H264_DEFAULT_PROFILE,
134               G_PARAM_READWRITE));
135     g_object_class_install_property (object_class, H264_PROP_LEVEL,
136           g_param_spec_uint ("level",
137               "H264 level idc",
138               "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41",
139               H264_LEVEL_10,
140               H264_LEVEL_41,
141               H264_DEFAULT_LEVEL,
142               G_PARAM_READWRITE));
143     g_object_class_install_property (object_class, H264_PROP_BITRATE,
144           g_param_spec_uint ("bitrate",
145               "H264 encoding bitrate",
146               "H264 encoding bitrate, 10k~100M, (0, auto-calculate)",
147               0,
148               100*1000*1000,
149               0,
150               G_PARAM_READWRITE));
151     g_object_class_install_property (object_class, H264_PROP_INTRA_PERIOD,
152           g_param_spec_uint ("intra-period",
153               "H264 encoding intra-period",
154               "H264 encoding intra-period",
155               1,
156               300,
157               H264_DEFAULT_INTRA_PERIOD,
158               G_PARAM_READWRITE));
159     g_object_class_install_property (object_class, H264_PROP_INIT_QP,
160           g_param_spec_uint ("init-qp",
161               "H264 init-qp",
162               "H264 init-qp",
163               1,
164               51,
165               H264_DEFAULT_INIT_QP,
166               G_PARAM_READWRITE));
167     g_object_class_install_property (object_class, H264_PROP_MIN_QP,
168           g_param_spec_uint ("min-qp",
169               "H264 min-qp",
170               "H264 min-qp",
171               1,
172               51,
173               H264_DEFAULT_MIN_QP,
174               G_PARAM_READWRITE));
175     g_object_class_install_property (object_class, H264_PROP_SLICE_NUM,
176           g_param_spec_uint ("slice-num",
177               "H264 slice num",
178               "H264 slice num",
179               1,
180               200,
181               1,
182               G_PARAM_READWRITE));
183     g_object_class_install_property (object_class, H264_PROP_B_FRAME_NUM,
184           g_param_spec_uint ("b-frame-num",
185               "B frams num",
186               "B frams num",
187               0,
188               10,
189               0,
190               G_PARAM_READWRITE));
191
192 }
193
194 static void
195 gst_h264encode_init(GstH264Encode *h264_encode, GstH264EncodeClass *klass)
196 {
197   GstVaapiEncode *encode = GST_VAAPI_ENCODE(h264_encode);
198   encode->encoder = GST_VAAPI_ENCODER(gst_h264_encoder_new());
199   ENCODER_ASSERT(encode->encoder);
200 }
201
202 static void
203 gst_h264encode_finalize(GObject *object)
204 {
205   //GstH264Encode * const h264_encode = GST_H264ENCODE(object);
206   G_OBJECT_CLASS(parent_class)->finalize(object);
207 }
208
209 static void
210 gst_h264encode_set_property(GObject *object, guint prop_id,
211     const GValue *value, GParamSpec *pspec)
212 {
213   GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
214   GstH264Encoder *h264encoder = GST_H264_ENCODER(encode->encoder);
215
216   ENCODER_ASSERT(h264encoder);
217
218   switch (prop_id) {
219     case H264_PROP_PROFILE: {
220       guint profile = g_value_get_uint(value);
221       if (_h264_check_valid_profile(profile)) {
222         h264encoder->profile = profile;
223       } else {
224         ENCODER_LOG_ERROR("h264encode set property <profile> failed.");
225       }
226     }
227       break;
228
229     case H264_PROP_LEVEL: {
230       guint level = g_value_get_uint(value);
231       if (_h264_check_valid_level(level)) {
232         h264encoder->level= level;
233       } else {
234         ENCODER_LOG_ERROR("h264encode set property <level> failed.");
235       }
236     }
237       break;
238
239     case H264_PROP_BITRATE: {
240       h264encoder->bitrate = g_value_get_uint(value);
241     }
242       break;
243
244     case H264_PROP_INTRA_PERIOD: {
245       h264encoder->intra_period = g_value_get_uint(value);
246     }
247       break;
248
249     case H264_PROP_INIT_QP: {
250       h264encoder->init_qp = g_value_get_uint(value);
251     }
252       break;
253
254     case H264_PROP_MIN_QP: {
255       h264encoder->min_qp = g_value_get_uint(value);
256     }
257       break;
258
259     case H264_PROP_SLICE_NUM: {
260       h264encoder->slice_num= g_value_get_uint(value);
261     }
262       break;
263
264     case H264_PROP_B_FRAME_NUM: {
265       h264encoder->b_frame_num= g_value_get_uint(value);
266     }
267       break;
268
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271       break;
272   }
273 }
274
275 static void
276 gst_h264encode_get_property (GObject * object, guint prop_id,
277     GValue * value, GParamSpec * pspec)
278 {
279   GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
280   GstH264Encoder *h264encoder = GST_H264_ENCODER(encode->encoder);
281   ENCODER_ASSERT(h264encoder);
282
283   switch (prop_id) {
284     case H264_PROP_PROFILE:
285       g_value_set_uint (value, h264encoder->profile);
286       break;
287
288     case H264_PROP_LEVEL:
289       g_value_set_uint (value, h264encoder->level);
290       break;
291
292     case H264_PROP_BITRATE:
293       g_value_set_uint (value, h264encoder->bitrate);
294       break;
295
296     case H264_PROP_INTRA_PERIOD:
297       g_value_set_uint (value, h264encoder->intra_period);
298       break;
299
300     case H264_PROP_INIT_QP:
301       g_value_set_uint (value, h264encoder->init_qp);
302       break;
303
304     case H264_PROP_MIN_QP:
305       g_value_set_uint (value, h264encoder->min_qp);
306       break;
307
308     case H264_PROP_SLICE_NUM:
309       g_value_set_uint (value, h264encoder->slice_num);
310       break;
311
312     case H264_PROP_B_FRAME_NUM:
313       g_value_set_uint (value, h264encoder->b_frame_num);
314       break;
315
316     default:
317       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318       break;
319   }
320 }
321
322
323 static gboolean
324 _h264_check_valid_profile(guint profile)
325 {
326    static const guint limit_profiles[] = {
327          H264_PROFILE_BASELINE,
328          H264_PROFILE_MAIN,
329          H264_PROFILE_HIGH
330         };
331    guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]);
332    guint i;
333    for (i = 0; i < n_profiles; ++i) {
334      if (limit_profiles[i] == profile)
335        return TRUE;
336    }
337    return FALSE;
338 }
339
340 static gboolean
341 _h264_check_valid_level(guint level)
342 {
343   static const guint limit_levels[] = {
344         H264_LEVEL_10,
345         H264_LEVEL_11,
346         H264_LEVEL_12,
347         H264_LEVEL_13,
348         H264_LEVEL_20,
349         H264_LEVEL_21,
350         H264_LEVEL_22,
351         H264_LEVEL_30,
352         H264_LEVEL_31,
353         H264_LEVEL_32,
354         H264_LEVEL_40,
355         H264_LEVEL_41,
356         H264_LEVEL_42,
357         H264_LEVEL_50,
358         H264_LEVEL_51
359        };
360   guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]);
361   guint i;
362   for (i = 0; i < n_levels; ++i) {
363     if (limit_levels[i] == level)
364       return TRUE;
365   }
366   return FALSE;
367
368 }
369
370
371 static gboolean
372 gst_h264encode_set_src_caps(GstVaapiEncode* encode, GstCaps *caps)
373 {
374   GstH264Encoder *h264encoder = GST_H264_ENCODER(encode->encoder);
375   GstCaps *peer_caps, *allowed_caps;
376   GstStructure *s;
377   const gchar *stream_format;
378
379   g_return_val_if_fail(caps,FALSE);
380   peer_caps = gst_pad_peer_get_caps_reffed(encode->srcpad);
381   if (peer_caps) {
382     allowed_caps = gst_caps_intersect(peer_caps, caps);
383     if (allowed_caps) {
384       allowed_caps = gst_caps_make_writable(allowed_caps);
385       gst_pad_fixate_caps(encode->srcpad, caps);
386       s = gst_caps_get_structure (allowed_caps, 0);
387       stream_format = gst_structure_get_string (s, "stream-format");
388       if (stream_format) {
389         if (!strcmp (stream_format, "avc")) {
390             gst_h264_encoder_set_avc_flag(h264encoder, TRUE);
391         } else if (!strcmp (stream_format, "byte-stream")) {
392             gst_h264_encoder_set_avc_flag(h264encoder, FALSE);
393         }
394       }
395       gst_caps_unref(allowed_caps);
396     }
397     gst_caps_unref(peer_caps);
398   }
399   gst_caps_set_simple(caps, "stream-format",
400                             G_TYPE_STRING,
401                             (gst_h264_encoder_get_avc_flag(h264encoder) ? "avc" : "byte-stream"),
402                             "alignment", G_TYPE_STRING, "au",
403                             NULL);
404   return TRUE;
405 }
406
407