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>
28 #include "gst/vaapi/gstvaapibaseencoder.h"
30 #include "gstvaapiencode_h264.h"
31 #include "gstvaapiencode_h263.h"
32 #include "gstvaapiencode_mpeg4.h"
33 #include "gstvaapipluginutil.h"
34 #include "gstvaapipluginbuffer.h"
37 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug)
38 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
40 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0,
41 "vaapiencode element");
43 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug);
44 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
46 #define GST_VAAPI_ENCODE_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
48 GST_TYPE_VAAPI_ENCODE, \
49 GstVaapiEncodePrivate))
51 typedef struct _GstVaapiEncodePrivate GstVaapiEncodePrivate;
53 #define GstVideoContextClass GstVideoContextInterface
55 #define GST_VAAPI_ENCODE_MUTEX_LOCK(encode) \
56 G_STMT_START{ g_mutex_lock((encode)->mutex); }G_STMT_END
58 #define GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode) \
59 G_STMT_START{ g_mutex_unlock((encode)->mutex); }G_STMT_END
61 #define GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode) \
63 g_cond_wait((encode)->idle_buf_added, (encode)->mutex); \
66 #define GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode) \
68 g_cond_signal((encode)->idle_buf_added); \
71 #define GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode) \
73 g_cond_wait((encode)->busy_buf_added, (encode)->mutex); \
76 #define GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode) \
78 g_cond_signal((encode)->busy_buf_added); \
81 GST_BOILERPLATE_WITH_INTERFACE(
87 GST_TYPE_VIDEO_CONTEXT,
96 _encode_dump_caps(GstCaps *cpas)
99 GstStructure const *structure;
101 static char caps_string[4096*5];
104 char *cur = caps_string;
105 memset(caps_string, 0, sizeof(caps_string));
106 for (i = 0; i < gst_caps_get_size(cpas); i++) {
107 structure = gst_caps_get_structure(cpas, i);
108 const char* caps_name = gst_structure_get_name (structure);
109 sprintf(cur, "cap_%02d:%s\n", i, caps_name);
112 for (j = 0; j < gst_structure_n_fields(structure); j++) {
113 const char* name = gst_structure_nth_field_name(structure, j);
114 value = gst_structure_get_value(structure, name);
115 tmp = gst_value_serialize(value);
116 sprintf(cur, "\t%s:%s(%s)\n", name, tmp, G_VALUE_TYPE_NAME(value));
125 /* context(display) interface */
127 gst_vaapi_encode_set_video_context(
128 GstVideoContext *context,
133 GstVaapiEncode *encode = GST_VAAPI_ENCODE (context);
134 GstVaapiDisplay *display = NULL;
136 gst_vaapi_set_display (type, value, &display);
137 gst_vaapi_encoder_set_display(encode->encoder, display);
141 gst_video_context_supported (GstVaapiEncode *decode, GType iface_type)
143 return (iface_type == GST_TYPE_VIDEO_CONTEXT);
147 gst_video_context_interface_init(GstVideoContextInterface *iface)
149 iface->set_context = gst_vaapi_encode_set_video_context;
153 gst_vaapi_encode_query (GstPad *pad, GstQuery *query)
155 GstVaapiEncode *encode = GST_VAAPI_ENCODE (gst_pad_get_parent_element (pad));
158 if (encode->encoder &&
159 gst_vaapi_reply_to_query(query, ENCODER_DISPLAY(encode->encoder)))
162 res = gst_pad_query_default (pad, query);
164 g_object_unref (encode);
168 static inline gboolean
169 gst_vaapi_encode_ensure_display(GstVaapiEncode *encode)
171 return gst_vaapi_ensure_display(encode,
172 GST_VAAPI_DISPLAY_TYPE_ANY,
173 &ENCODER_DISPLAY(encode->encoder));
177 gst_vaapi_encode_buffer_loop(GstVaapiEncode *encode)
179 GstBuffer *buf = NULL;
180 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
183 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
184 is_running = encode->is_running;
185 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
190 gst_vaapi_encoder_get_encoded_buffer(
193 if (encoder_ret < ENCODER_NO_ERROR) {
194 ENCODER_LOG_ERROR("get encoded buffer failed");
197 GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode);
202 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
203 if (encode->first_src_frame) { /* Set src pad caps and codec data */
204 GstBuffer *codec_data = NULL;
205 if ((ENCODER_NO_ERROR ==
206 gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data)) &&
208 gst_caps_set_simple(encode->srcpad_caps,
209 "codec_data",GST_TYPE_BUFFER, codec_data,
212 gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
213 GST_BUFFER_CAPS(buf) = gst_caps_ref(encode->srcpad_caps);
214 ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s",
215 _encode_dump_caps(encode->srcpad_caps));
216 encode->first_src_frame = FALSE;
218 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
220 "output:%" GST_TIME_FORMAT ", 0x%s",
221 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
222 vaapi_encoder_dump_bytes(GST_BUFFER_DATA(buf),
223 (GST_BUFFER_SIZE(buf) > 16 ?
224 16: GST_BUFFER_SIZE(buf)))
226 gst_pad_push(encode->srcpad, buf);
230 _encoder_status_callback(
231 GstVaapiBaseEncoder* encoder,
232 EncoderStatus status,
236 GstVaapiEncode *encode = (GstVaapiEncode *)user_data;
237 gboolean ret = FALSE;
239 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
241 if (!encode->is_running) {
247 case ENCODER_NO_IDLE_BUF:
248 GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode);
252 case ENCODER_NO_BUSY_BUF:
253 GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode);
262 if (!encode->is_running)
266 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
272 gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
274 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
275 GstVaapiEncodeClass *encode_class = GST_VAAPI_ENCODE_GET_CLASS(encode);
276 GstStructure *structure = NULL, *src_struct = NULL;
277 gint width = 0, height = 0;
278 gint fps_n = 0, fps_d = 0;
279 const GValue *fps_value = NULL, *format_value;
282 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
284 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
286 encode->sinkpad_caps = caps;
288 ENCODER_LOG_INFO("gst_vaapi_encode_set_caps,\n%s",
289 _encode_dump_caps(caps));
291 structure = gst_caps_get_structure (caps, 0);
293 if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME))
294 encode->is_buffer_sharing = TRUE;
296 encode->is_buffer_sharing = FALSE;
298 if (gst_structure_get_int (structure, "width", &width)) {
299 encode->encoder->width = width;
301 if (gst_structure_get_int (structure, "height", &height)) {
302 encode->encoder->height = height;
304 fps_value = gst_structure_get_value (structure, "framerate");
306 fps_n = gst_value_get_fraction_numerator (fps_value);
307 fps_d = gst_value_get_fraction_denominator (fps_value);
308 encode->encoder->frame_rate = fps_n/fps_d;
310 format_value = gst_structure_get_value (structure, "format");
311 if (format_value && GST_IS_VAAPI_ENCODE_H264(encode)) {
312 ENCODER_CHECK_STATUS((format_value &&
313 GST_TYPE_FOURCC == G_VALUE_TYPE(format_value)),
315 "1st buffer caps' format type is not fourcc.");
316 format = gst_value_get_fourcc (format_value);
318 gst_vaapi_base_encoder_set_input_format(
319 GST_VAAPI_BASE_ENCODER(encode->encoder),
325 if (encode->srcpad_caps) {
326 gst_caps_unref(encode->srcpad_caps);
328 encode->srcpad_caps =
329 gst_caps_copy(gst_pad_get_pad_template_caps(encode->srcpad));
330 src_struct = gst_caps_get_structure(encode->srcpad_caps, 0);
331 gst_structure_set(src_struct,
332 "width", G_TYPE_INT, width,
333 "height", G_TYPE_INT, height,
334 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
336 if (encode_class->set_encoder_src_caps) {
337 encode_class->set_encoder_src_caps(encode, encode->srcpad_caps);
340 /*set display and initialize encoder*/
341 ENCODER_CHECK_STATUS(gst_vaapi_encode_ensure_display(encode),
343 "encoder ensure display failed on setting caps.");
345 gst_vaapi_base_encoder_set_notify_status(
346 GST_VAAPI_BASE_ENCODER(encode->encoder),
347 _encoder_status_callback,
349 gst_vaapi_base_encoder_set_buffer_sharing(
350 GST_VAAPI_BASE_ENCODER(encode->encoder),
351 encode->is_buffer_sharing);
353 encoder_ret = gst_vaapi_encoder_initialize(encode->encoder);
354 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
356 "gst_vaapi_encoder_initialize failed.");
358 encoder_ret = gst_vaapi_encoder_open(encode->encoder);
359 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret,
361 "gst_vaapi_encoder_open failed.");
363 encode->is_running = TRUE;
366 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
368 ret = gst_pad_start_task(encode->srcpad,
369 (GstTaskFunction)gst_vaapi_encode_buffer_loop,
372 ENCODER_LOG_INFO("gstvaapiencode start task failed.");
378 gst_vaapi_encode_get_caps(GstPad *sink_pad)
380 GstCaps *caps = NULL;
381 GstVaapiEncode * const encode =
382 GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
384 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
386 if (encode->sinkpad_caps) {
387 gst_caps_ref(encode->sinkpad_caps);
388 ENCODER_LOG_INFO("get caps,\n%s",
389 _encode_dump_caps(encode->sinkpad_caps));
390 caps = encode->sinkpad_caps;
392 caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
394 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
398 static GstStateChangeReturn
399 gst_vaapi_encode_change_state(
401 GstStateChange transition
404 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(element);
405 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
407 switch (transition) {
408 case GST_STATE_CHANGE_READY_TO_PAUSED:
410 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
412 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
414 case GST_STATE_CHANGE_PAUSED_TO_READY: {
415 GST_VAAPI_ENCODE_MUTEX_LOCK (encode);
416 encode->is_running = FALSE;
417 encode->is_buffer_sharing = FALSE;
418 GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode);
419 GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode);
420 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
421 gst_pad_stop_task(encode->srcpad);
428 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
429 if (ret != GST_STATE_CHANGE_SUCCESS)
432 switch (transition) {
433 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
435 case GST_STATE_CHANGE_PAUSED_TO_READY:
436 gst_vaapi_encoder_close(encode->encoder);
437 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
438 if (encode->video_pool) {
439 g_object_unref(encode->video_pool);
440 encode->video_pool = NULL;
442 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
448 return GST_STATE_CHANGE_SUCCESS;
452 gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf)
454 GstFlowReturn ret = GST_FLOW_OK;
455 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
456 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
457 gboolean is_buffer_sharing;
459 ENCODER_ASSERT(encode && encode->encoder);
461 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
462 is_buffer_sharing = encode->is_buffer_sharing;
463 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
465 if (!is_buffer_sharing && !GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
466 ENCODER_LOG_ERROR("gst_vaapi_encode_chain parameter doesn't have video buffer.");
467 ret = ENCODER_NO_ERROR;
472 encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf);
473 GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode);
474 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR <= encoder_ret,
476 "gst_vaapi_encoder_encode failed.");
479 gst_buffer_unref(buf);
484 gst_vaapi_encode_ensure_video_pool(
485 GstVaapiEncode *encode,
488 GstStructure *structure;
489 gint width = 0, height = 0;
491 g_return_val_if_fail(caps, FALSE);
493 structure = gst_caps_get_structure(caps, 0);
494 g_return_val_if_fail(structure, FALSE);
496 if (encode->video_pool)
499 if (!gst_structure_get_int(structure, "width", &width) ||
500 !gst_structure_get_int(structure, "height", &height))
504 gst_vaapi_surface_pool_new(ENCODER_DISPLAY(encode->encoder), caps);
505 if (!encode->video_pool)
512 gst_vaapi_encode_buffer_alloc(
520 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(pad));
521 GstStructure *structure = NULL;
522 GstBuffer *video_buffer = NULL;
523 GstFlowReturn ret = GST_FLOW_ERROR;
526 return GST_FLOW_ERROR;
528 structure = gst_caps_get_structure(caps, 0);
530 (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME) &&
531 !gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)))
532 return GST_FLOW_ERROR;
534 ENCODER_CHECK_STATUS(
535 gst_vaapi_encode_ensure_display(encode),
537 "gst_vaapi_encode_buffer_alloc can't ensure display");
539 GST_VAAPI_ENCODE_MUTEX_LOCK(encode);
540 if (!gst_vaapi_encode_ensure_video_pool(encode, caps))
543 video_buffer = gst_vaapi_video_buffer_new_from_pool(encode->video_pool);
546 GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode);
548 ENCODER_CHECK_STATUS(video_buffer,
550 "gst_vaapi_encode_buffer_alloc failed.");
552 if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)) {
553 ENCODER_CHECK_STATUS(
554 gst_vaapi_video_buffer_ensure_pointer(GST_VAAPI_VIDEO_BUFFER(video_buffer)),
556 "gst_vaapi_video_buffer_ensure_pointer failed.");
560 gst_buffer_set_caps(video_buffer, caps);
570 gst_vaapi_encode_finalize(GObject *object)
572 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(object);
574 if (encode->sinkpad_caps) {
575 gst_caps_unref(encode->sinkpad_caps);
576 encode->sinkpad_caps = NULL;
578 encode->sinkpad = NULL;
580 if (encode->srcpad_caps) {
581 gst_caps_unref(encode->srcpad_caps);
582 encode->srcpad_caps = NULL;
584 encode->srcpad = NULL;
586 if (encode->video_pool)
587 g_object_unref(encode->video_pool);
589 if (encode->encoder) {
590 gst_vaapi_encoder_close(encode->encoder);
591 gst_vaapi_encoder_uninitialize(encode->encoder);
592 gst_vaapi_encoder_unref(encode->encoder);
593 encode->encoder = NULL;
596 g_mutex_free(encode->mutex);
597 g_cond_free(encode->idle_buf_added);
598 g_cond_free(encode->busy_buf_added);
600 G_OBJECT_CLASS(parent_class)->finalize(object);
604 gst_vaapi_encode_init(
605 GstVaapiEncode *encode,
606 GstVaapiEncodeClass *klass
609 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
611 encode->sinkpad_caps = NULL;
612 encode->srcpad_caps = NULL;
613 encode->first_src_frame = TRUE;
614 encode->is_running = FALSE;
615 encode->is_buffer_sharing = FALSE;
617 encode->encoder = NULL;
618 encode->video_pool = NULL;
620 encode->mutex = g_mutex_new();
621 encode->idle_buf_added = g_cond_new();
622 encode->busy_buf_added = g_cond_new();
625 encode->sinkpad = gst_pad_new_from_template(
626 gst_element_class_get_pad_template(element_class, "sink"),
629 gst_pad_set_getcaps_function(encode->sinkpad, gst_vaapi_encode_get_caps);
630 gst_pad_set_setcaps_function(encode->sinkpad, gst_vaapi_encode_set_caps);
631 gst_pad_set_chain_function(encode->sinkpad, gst_vaapi_encode_chain);
632 gst_pad_set_bufferalloc_function(encode->sinkpad,
633 gst_vaapi_encode_buffer_alloc);
634 /*gst_pad_set_event_function(encode->sinkpad, gst_vaapi_encode_sink_event); */
635 /*gst_pad_use_fixed_caps(encode->sinkpad);*/
636 gst_pad_set_query_function(encode->sinkpad, gst_vaapi_encode_query);
637 gst_element_add_pad(GST_ELEMENT(encode), encode->sinkpad);
640 encode->srcpad = gst_pad_new_from_template(
641 gst_element_class_get_pad_template(element_class, "src"),
644 encode->srcpad_caps = NULL;
646 gst_pad_use_fixed_caps(encode->srcpad);
647 /*gst_pad_set_event_function(encode->srcpad, gst_vaapi_encode_src_event);*/
648 gst_pad_set_query_function(encode->srcpad, gst_vaapi_encode_query);
649 gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad);
653 gst_vaapi_encode_set_property(
659 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
660 ENCODER_ASSERT(encode->encoder);
667 gst_vaapi_encode_get_property (
674 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
675 ENCODER_ASSERT(encode->encoder);
682 gst_vaapi_encode_base_init(gpointer klass)
685 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
687 gst_element_class_set_details(element_class, &gst_vaapi_encode_details);
690 gst_element_class_add_pad_template(
692 gst_static_pad_template_get(&gst_vaapi_encode_sink_factory)
696 gst_element_class_add_pad_template(
698 gst_static_pad_template_get(&gst_vaapi_encode_src_factory)
704 gst_vaapi_encode_class_init(GstVaapiEncodeClass *klass)
706 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
707 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
709 object_class->finalize = gst_vaapi_encode_finalize;
710 object_class->set_property = gst_vaapi_encode_set_property;
711 object_class->get_property = gst_vaapi_encode_get_property;
713 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug,
716 "vaapiencode element");
718 element_class->change_state = gst_vaapi_encode_change_state;
720 klass->set_encoder_src_caps = NULL;
722 /* Registering debug symbols for function pointers */
723 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_change_state);
724 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_get_caps);
725 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_set_caps);
726 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_chain);
727 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_buffer_alloc);