2 * gstvaapiencode.c - VA-API video encoder
4 * Copyright (C) 2011 Intel Corporation
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.
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.
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
23 #include "gstvaapiencode.h"
27 #include <gst/video/videocontext.h>
29 #include "gst/vaapi/gstvaapivideobuffer.h"
30 #include "gst/vaapi/gstvaapisurfacepool.h"
32 #include "gstvaapih264encode.h"
33 #include "gstvaapih263encode.h"
34 #include "gstvaapimpeg4encode.h"
35 #include "gstvaapibaseencoder.h"
36 #include "gstvaapipluginutil.h"
39 #include <gst/vaapi/gstvaapivideobuffer_glx.h>
40 #define gst_vaapi_video_buffer_new(display) \
41 gst_vaapi_video_buffer_glx_new(GST_VAAPI_DISPLAY_GLX(display))
45 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug)
46 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
48 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0,
49 "vaapiencode element");
51 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug);
52 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
54 #define GST_VAAPI_ENCODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VAAPI_ENCODE, GstVaapiEncodePrivate))
56 typedef struct _GstVaapiEncodePrivate GstVaapiEncodePrivate;
59 #define GstVideoContextClass GstVideoContextInterface
60 GST_BOILERPLATE_WITH_INTERFACE(
66 GST_TYPE_VIDEO_CONTEXT,
76 static void gst_vaapi_encode_finalize(GObject *object);
77 static void gst_vaapi_encode_set_property(GObject *object, guint prop_id,
78 const GValue *value, GParamSpec *pspec);
79 static void gst_vaapi_encode_get_property (GObject * object, guint prop_id,
80 GValue * value, GParamSpec * pspec);
82 static gboolean gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps);
83 static GstCaps *gst_vaapi_encode_get_caps(GstPad *sink_pad);
84 static GstFlowReturn gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf);
85 static GstStateChangeReturn gst_vaapi_encode_change_state(GstElement *element, GstStateChange transition);
86 static GstFlowReturn gst_vaapi_encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
87 GstCaps * caps, GstBuffer ** buf);
89 static char* _encode_dump_caps(GstCaps *cpas);
91 /* context(display) interface */
93 gst_vaapi_encode_set_video_context(GstVideoContext *context, const gchar *type,
96 GstVaapiEncode *encode = GST_VAAPI_ENCODE (context);
97 GstVaapiDisplay *display = NULL;
98 gst_vaapi_set_display (type, value, &display);
99 gst_vaapi_encoder_set_display(encode->encoder, display);
103 gst_video_context_supported (GstVaapiEncode *decode, GType iface_type)
105 return (iface_type == GST_TYPE_VIDEO_CONTEXT);
109 gst_video_context_interface_init(GstVideoContextInterface *iface)
111 iface->set_context = gst_vaapi_encode_set_video_context;
115 gst_vaapi_encode_query (GstPad *pad, GstQuery *query) {
116 GstVaapiEncode *encode = GST_VAAPI_ENCODE (gst_pad_get_parent_element (pad));
119 if (encode->encoder && gst_vaapi_reply_to_query(query, ENCODER_DISPLAY(encode->encoder)))
122 res = gst_pad_query_default (pad, query);
124 g_object_unref (encode);
128 /*gst fix functions*/
131 gst_vaapi_encode_base_init(gpointer klass)
134 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
136 gst_element_class_set_details(element_class, &gst_vaapi_encode_details);
139 gst_element_class_add_pad_template(
141 gst_static_pad_template_get(&gst_vaapi_encode_sink_factory)
145 gst_element_class_add_pad_template(
147 gst_static_pad_template_get(&gst_vaapi_encode_src_factory)
154 gst_vaapi_encode_class_init(GstVaapiEncodeClass *klass)
156 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
157 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
159 object_class->finalize = gst_vaapi_encode_finalize;
160 object_class->set_property = gst_vaapi_encode_set_property;
161 object_class->get_property = gst_vaapi_encode_get_property;
163 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0,
164 "vaapiencode element");
166 element_class->change_state = gst_vaapi_encode_change_state;
168 klass->set_encoder_src_caps = NULL;
170 /* Registering debug symbols for function pointers */
171 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_change_state);
172 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_get_caps);
173 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_set_caps);
174 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_chain);
175 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_buffer_alloc);
179 gst_vaapi_encode_finalize(GObject *object)
181 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(object);
183 if (encode->sinkpad_caps) {
184 gst_caps_unref(encode->sinkpad_caps);
185 encode->sinkpad_caps = NULL;
187 encode->sinkpad = NULL;
189 if (encode->srcpad_caps) {
190 gst_caps_unref(encode->srcpad_caps);
191 encode->srcpad_caps = NULL;
193 encode->srcpad = NULL;
195 if (encode->encoder) {
196 gst_vaapi_encoder_close(encode->encoder);
197 gst_vaapi_encoder_uninitialize(encode->encoder);
198 gst_vaapi_encoder_unref(encode->encoder);
199 encode->encoder = NULL;
202 G_OBJECT_CLASS(parent_class)->finalize(object);
206 gst_vaapi_encode_init(GstVaapiEncode *encode, GstVaapiEncodeClass *klass)
208 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
210 encode->sinkpad_caps = NULL;
211 encode->srcpad_caps = NULL;
212 encode->first_sink_frame = TRUE;
213 encode->first_src_frame = TRUE;
215 encode->encoder = NULL;
218 encode->sinkpad = gst_pad_new_from_template(
219 gst_element_class_get_pad_template(element_class, "sink"),
222 gst_pad_set_getcaps_function(encode->sinkpad, gst_vaapi_encode_get_caps);
223 gst_pad_set_setcaps_function(encode->sinkpad, gst_vaapi_encode_set_caps);
224 gst_pad_set_chain_function(encode->sinkpad, gst_vaapi_encode_chain);
225 gst_pad_set_bufferalloc_function(encode->sinkpad, gst_vaapi_encode_buffer_alloc);
226 /*gst_pad_set_event_function(encode->sinkpad, gst_vaapi_encode_sink_event); */
227 /*gst_pad_use_fixed_caps(encode->sinkpad);*/
228 gst_pad_set_query_function(encode->sinkpad, gst_vaapi_encode_query);
229 gst_element_add_pad(GST_ELEMENT(encode), encode->sinkpad);
232 encode->srcpad = gst_pad_new_from_template(
233 gst_element_class_get_pad_template(element_class, "src"),
236 encode->srcpad_caps = NULL;
238 gst_pad_use_fixed_caps(encode->srcpad);
239 /*gst_pad_set_event_function(encode->srcpad, gst_vaapi_encode_src_event);*/
240 gst_pad_set_query_function(encode->sinkpad, gst_vaapi_encode_query);
241 gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad);
246 gst_vaapi_encode_set_property(GObject *object, guint prop_id,
247 const GValue *value, GParamSpec *pspec)
249 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
250 ENCODER_ASSERT(encode->encoder);
257 gst_vaapi_encode_get_property (GObject * object, guint prop_id,
258 GValue * value, GParamSpec * pspec)
260 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
261 ENCODER_ASSERT(encode->encoder);
268 gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
270 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
271 GstStructure *structure = NULL, *src_struct = NULL;
272 gint width = 0, height = 0;
273 gint fps_n = 0, fps_d = 0;
274 const GValue *fps_value = NULL, *format_value;
277 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
279 encode->sinkpad_caps = caps;
281 ENCODER_LOG_INFO("gst_vaapi_encode_set_caps,\n%s", _encode_dump_caps(caps));
283 structure = gst_caps_get_structure (caps, 0);
284 if (gst_structure_get_int (structure, "width", &width)) {
285 encode->encoder->width = width;
287 if (gst_structure_get_int (structure, "height", &height)) {
288 encode->encoder->height = height;
290 fps_value = gst_structure_get_value (structure, "framerate");
292 fps_n = gst_value_get_fraction_numerator (fps_value);
293 fps_d = gst_value_get_fraction_denominator (fps_value);
294 encode->encoder->frame_rate = fps_n/fps_d;
296 format_value = gst_structure_get_value (structure, "format");
297 if (format_value && GST_IS_H264ENCODE(encode)) {
298 ENCODER_CHECK_STATUS(format_value && GST_TYPE_FOURCC == G_VALUE_TYPE(format_value),
299 FALSE, "1st buffer caps' format type is not fourcc.");
300 format = gst_value_get_fourcc (format_value);
302 gst_vaapi_base_encoder_set_input_format(GST_VAAPI_BASE_ENCODER(encode->encoder), format);
307 if (encode->srcpad_caps) {
308 gst_caps_unref(encode->srcpad_caps);
310 encode->srcpad_caps = gst_caps_copy(gst_pad_get_pad_template_caps(encode->srcpad));
311 src_struct = gst_caps_get_structure(encode->srcpad_caps, 0);
312 gst_structure_set(src_struct, "width", G_TYPE_INT, width,
313 "height", G_TYPE_INT, height,
314 "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
316 /*set display and initialize encoder*/
317 ENCODER_CHECK_STATUS(gst_vaapi_ensure_display(encode, &ENCODER_DISPLAY(encode->encoder)),
318 FALSE, "encoder ensure display failed on setting caps.")
319 encoder_ret = gst_vaapi_encoder_initialize(encode->encoder);
320 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
321 FALSE, "gst_vaapi_encoder_initialize failed.");
322 encoder_ret = gst_vaapi_encoder_open(encode->encoder, NULL);
323 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
324 FALSE, "gst_vaapi_encoder_open failed.");
330 gst_vaapi_encode_get_caps(GstPad *sink_pad)
332 GstCaps *caps = NULL;
333 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
334 if (encode->sinkpad_caps) {
335 gst_caps_ref(encode->sinkpad_caps);
336 ENCODER_LOG_INFO("get caps,\n%s", _encode_dump_caps(encode->sinkpad_caps));
337 return encode->sinkpad_caps;
339 caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
343 static GstStateChangeReturn
344 gst_vaapi_encode_change_state(GstElement *element, GstStateChange transition)
346 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(element);
347 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
349 switch (transition) {
350 case GST_STATE_CHANGE_READY_TO_PAUSED:
352 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
358 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
359 if (ret != GST_STATE_CHANGE_SUCCESS)
362 switch (transition) {
363 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
365 case GST_STATE_CHANGE_PAUSED_TO_READY: {
366 gst_vaapi_encoder_close(encode->encoder);
372 return GST_STATE_CHANGE_SUCCESS;
377 gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf)
379 GstFlowReturn ret = GST_FLOW_OK;
380 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
381 GstVaapiEncodeClass *encode_class = GST_VAAPI_ENCODE_GET_CLASS(encode);
382 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
383 GList *out_buffers = NULL;
384 GstBuffer *tmp_buffer = NULL;
386 static guint input_count = 0;
387 static guint output_count = 0;
389 ENCODER_ASSERT(encode && encode->encoder);
390 if (encode->first_sink_frame) {
391 /* get first buffer caps and set encoder values */
392 if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
393 GstVaapiVideoBuffer *video_buffer = GST_VAAPI_VIDEO_BUFFER(buf);
394 ENCODER_ASSERT(video_buffer);
395 ENCODER_ASSERT(gst_vaapi_video_buffer_get_display(video_buffer) == ENCODER_DISPLAY(encode->encoder));
397 encode->first_sink_frame = FALSE;
401 ENCODER_ASSERT(gst_vaapi_encoder_get_state(encode->encoder) >= VAAPI_ENC_OPENED);
403 ENCODER_LOG_DEBUG("input %d", input_count);
404 encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf, &out_buffers);
405 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, GST_FLOW_ERROR, "gst_vaapi_encoder_encode failed.");
408 while (out_buffers) {
409 tmp_buffer = out_buffers->data;
410 out_buffers = g_list_remove(out_buffers, tmp_buffer);
411 if (encode->first_src_frame) {
412 GstBuffer *codec_data = NULL;
413 ENCODER_ASSERT(encode->srcpad_caps);
414 /*replace codec data in src pad caps*/
415 if (ENCODER_NO_ERROR == gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data) && codec_data) {
416 gst_caps_set_simple(encode->srcpad_caps, "codec_data",GST_TYPE_BUFFER, codec_data, NULL);
418 if (encode_class->set_encoder_src_caps) {
419 encode_class->set_encoder_src_caps(encode, encode->srcpad_caps);
421 gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
422 GST_BUFFER_CAPS(tmp_buffer) = gst_caps_ref(encode->srcpad_caps);
423 ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s", _encode_dump_caps(encode->srcpad_caps));
424 encode->first_src_frame = FALSE;
427 ENCODER_LOG_DEBUG("output:%d, %" GST_TIME_FORMAT ", 0x%s",
429 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(tmp_buffer)),
430 vaapi_encoder_dump_bytes(GST_BUFFER_DATA(tmp_buffer),
431 (GST_BUFFER_SIZE(tmp_buffer) > 16? 16: GST_BUFFER_SIZE(tmp_buffer))));
432 gst_pad_push(encode->srcpad, tmp_buffer);
436 gst_buffer_unref(buf);
442 gst_vaapi_encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
443 GstCaps * caps, GstBuffer ** buf)
445 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(pad));
446 GstStructure *structure = NULL;
448 GstVaapiDisplay* display = NULL;
449 GstFlowReturn ret = GST_FLOW_ERROR;
452 structure = gst_caps_get_structure(caps, 0);
454 if (!structure || gst_structure_has_name(structure, "video/x-vaapi-surface")) {
455 ENCODER_ASSERT(encode->encoder);
456 ENCODER_CHECK_STATUS(gst_vaapi_ensure_display(encode, &ENCODER_DISPLAY(encode->encoder)),
457 GST_FLOW_ERROR, "encoder ensure display failed.")
458 display = ENCODER_DISPLAY(encode->encoder);
459 buffer = gst_vaapi_video_buffer_new(display);
460 } else { /* video/x-raw-yuv */
461 buffer = gst_buffer_new_and_alloc(size);
464 ENCODER_CHECK_STATUS(buffer, GST_FLOW_ERROR, "gst_vaapi_encode_buffer_alloc failed.");
466 GST_BUFFER_OFFSET (buffer) = offset;
468 gst_buffer_set_caps(buffer, caps);
479 _encode_dump_caps(GstCaps *cpas)
482 GstStructure const *structure;
484 static char caps_string[4096*5];
487 char *cur = caps_string;
488 memset(caps_string, 0, sizeof(caps_string));
489 for (i = 0; i < gst_caps_get_size(cpas); i++) {
490 structure = gst_caps_get_structure(cpas, i);
491 const char* caps_name = gst_structure_get_name (structure);
492 sprintf(cur, "cap_%02d:%s\n", i, caps_name);
495 for (j = 0; j < gst_structure_n_fields(structure); j++) {
496 const char* name = gst_structure_nth_field_name(structure, j);
497 value = gst_structure_get_value(structure, name);
498 tmp = gst_value_serialize(value);
499 sprintf(cur, "\t%s:%s(%s)\n", name, tmp, G_VALUE_TYPE_NAME(value));
510 vaapi_encode_sets_init (GstPlugin * plugin)
514 ret &= gst_element_register (plugin, "vah264encode", GST_RANK_PRIMARY,
515 GST_TYPE_H264ENCODE);
516 ret &= gst_element_register (plugin, "vah263encode", GST_RANK_PRIMARY,
517 GST_TYPE_H263ENCODE);
518 ret &= gst_element_register (plugin, "vampeg4encode", GST_RANK_PRIMARY,
519 GST_TYPE_MPEG4ENCODE);
523 /* gstreamer looks for this structure to register mrstcamsrc */
529 vaapi_encode_sets_init,
533 "http://gstreamer.net/")