2 #include "gstvaapiencode.h"
7 #include "gst/vaapi/gstvaapivideobuffer.h"
8 #include "gst/vaapi/gstvaapisurfacepool.h"
10 #include "gstvaapih264encode.h"
11 #include "gstvaapih263encode.h"
12 #include "gstvaapimpeg4encode.h"
13 #include "gstvaapibaseencoder.h"
17 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug)
18 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
20 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0,
21 "vaapiencode element");
23 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug);
24 #define GST_CAT_DEFAULT gst_vaapi_encode_debug
26 #define GST_VAAPI_ENCODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VAAPI_ENCODE, GstVaapiEncodePrivate))
28 typedef struct _GstVaapiEncodePrivate GstVaapiEncodePrivate;
43 static void gst_vaapi_encode_finalize(GObject *object);
44 static void gst_vaapi_encode_set_property(GObject *object, guint prop_id,
45 const GValue *value, GParamSpec *pspec);
46 static void gst_vaapi_encode_get_property (GObject * object, guint prop_id,
47 GValue * value, GParamSpec * pspec);
49 static gboolean gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps);
50 static GstCaps *gst_vaapi_encode_get_caps(GstPad *sink_pad);
51 static GstFlowReturn gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf);
52 static GstStateChangeReturn gst_vaapi_encode_change_state(GstElement *element, GstStateChange transition);
53 static GstFlowReturn gst_vaapi_encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
54 GstCaps * caps, GstBuffer ** buf);
56 static char* _encode_dump_caps(GstCaps *cpas);
61 gst_vaapi_encode_base_init(gpointer klass)
64 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
66 gst_element_class_set_details(element_class, &gst_vaapi_encode_details);
69 gst_element_class_add_pad_template(
71 gst_static_pad_template_get(&gst_vaapi_encode_sink_factory)
75 gst_element_class_add_pad_template(
77 gst_static_pad_template_get(&gst_vaapi_encode_src_factory)
84 gst_vaapi_encode_class_init(GstVaapiEncodeClass *klass)
86 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
87 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
89 object_class->finalize = gst_vaapi_encode_finalize;
90 object_class->set_property = gst_vaapi_encode_set_property;
91 object_class->get_property = gst_vaapi_encode_get_property;
93 GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0,
94 "vaapiencode element");
96 element_class->change_state = gst_vaapi_encode_change_state;
98 klass->set_encoder_src_caps = NULL;
100 /* Registering debug symbols for function pointers */
101 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_change_state);
102 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_get_caps);
103 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_set_caps);
104 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_chain);
105 GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_buffer_alloc);
109 gst_vaapi_encode_finalize(GObject *object)
111 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(object);
113 if (encode->sinkpad_caps) {
114 gst_caps_unref(encode->sinkpad_caps);
115 encode->sinkpad_caps = NULL;
117 encode->sinkpad = NULL;
119 if (encode->srcpad_caps) {
120 gst_caps_unref(encode->srcpad_caps);
121 encode->srcpad_caps = NULL;
123 encode->srcpad = NULL;
125 if (encode->encoder) {
126 gst_vaapi_encoder_close(encode->encoder);
127 gst_vaapi_encoder_uninitialize(encode->encoder);
128 gst_vaapi_encoder_unref(encode->encoder);
129 encode->encoder = NULL;
132 G_OBJECT_CLASS(parent_class)->finalize(object);
136 gst_vaapi_encode_init(GstVaapiEncode *encode, GstVaapiEncodeClass *klass)
138 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
140 encode->sinkpad_caps = NULL;
141 encode->srcpad_caps = NULL;
142 encode->first_sink_frame = TRUE;
143 encode->first_src_frame = TRUE;
145 encode->encoder = NULL;
148 encode->sinkpad = gst_pad_new_from_template(
149 gst_element_class_get_pad_template(element_class, "sink"),
152 gst_pad_set_getcaps_function(encode->sinkpad, gst_vaapi_encode_get_caps);
153 gst_pad_set_setcaps_function(encode->sinkpad, gst_vaapi_encode_set_caps);
154 gst_pad_set_chain_function(encode->sinkpad, gst_vaapi_encode_chain);
155 gst_pad_set_bufferalloc_function(encode->sinkpad, gst_vaapi_encode_buffer_alloc);
156 /*gst_pad_set_event_function(encode->sinkpad, gst_vaapi_encode_sink_event); */
157 /*gst_pad_use_fixed_caps(encode->sinkpad);*/
158 gst_element_add_pad(GST_ELEMENT(encode), encode->sinkpad);
161 encode->srcpad = gst_pad_new_from_template(
162 gst_element_class_get_pad_template(element_class, "src"),
165 encode->srcpad_caps = NULL;
167 gst_pad_use_fixed_caps(encode->srcpad);
168 /*gst_pad_set_event_function(encode->srcpad, gst_vaapi_encode_src_event);*/
169 gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad);
174 gst_vaapi_encode_set_property(GObject *object, guint prop_id,
175 const GValue *value, GParamSpec *pspec)
177 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
178 ENCODER_ASSERT(encode->encoder);
185 gst_vaapi_encode_get_property (GObject * object, guint prop_id,
186 GValue * value, GParamSpec * pspec)
188 GstVaapiEncode *encode = GST_VAAPI_ENCODE(object);
189 ENCODER_ASSERT(encode->encoder);
196 gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps)
198 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
199 GstStructure *structure;
200 gint width = 0, height = 0;
201 gint fps_n = 0, fps_d = 0;
202 const GValue *fps_value = NULL;
203 encode->sinkpad_caps = caps;
205 ENCODER_LOG_INFO("gst_vaapi_encode_set_caps,\n%s", _encode_dump_caps(caps));
207 structure = gst_caps_get_structure (caps, 0);
208 if (gst_structure_get_int (structure, "width", &width)) {
209 encode->encoder->width = width;
211 if (gst_structure_get_int (structure, "height", &height)) {
212 encode->encoder->height = height;
214 fps_value = gst_structure_get_value (structure, "framerate");
216 fps_n = gst_value_get_fraction_numerator (fps_value);
217 fps_d = gst_value_get_fraction_denominator (fps_value);
218 encode->encoder->frame_rate = fps_n/fps_d;
224 gst_vaapi_encode_get_caps(GstPad *sink_pad)
226 GstCaps *caps = NULL;
227 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
228 if (encode->sinkpad_caps) {
229 gst_caps_ref(encode->sinkpad_caps);
230 ENCODER_LOG_INFO("get caps,\n%s", _encode_dump_caps(encode->sinkpad_caps));
231 return encode->sinkpad_caps;
233 caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad));
237 static GstStateChangeReturn
238 gst_vaapi_encode_change_state(GstElement *element, GstStateChange transition)
240 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(element);
241 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
243 switch (transition) {
244 case GST_STATE_CHANGE_READY_TO_PAUSED:
246 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
252 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
253 if (ret != GST_STATE_CHANGE_SUCCESS)
256 switch (transition) {
257 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
259 case GST_STATE_CHANGE_PAUSED_TO_READY: {
260 gst_vaapi_encoder_close(encode->encoder);
266 return GST_STATE_CHANGE_SUCCESS;
271 gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf)
273 GstFlowReturn ret = GST_FLOW_OK;
274 GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad));
275 GstVaapiEncodeClass *encode_class = GST_VAAPI_ENCODE_GET_CLASS(encode);
276 EncoderStatus encoder_ret = ENCODER_NO_ERROR;
277 GList *out_buffers = NULL;
278 GstBuffer *tmp_buffer = NULL;
280 static guint input_count = 0;
281 static guint output_count = 0;
283 ENCODER_ASSERT(encode && encode->encoder);
284 if (encode->first_sink_frame) {
285 /* get first buffer caps and set encoder values */
286 GstStructure *recv_struct, *src_struct;
287 GstCaps *recv_caps = GST_BUFFER_CAPS(buf);
289 GValue const *framerate, *format_value;
292 GstVaapiSurfacePool *surface_pool = NULL;
294 ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st recv-buffer caps,\n%s", _encode_dump_caps(recv_caps));
296 recv_struct = gst_caps_get_structure (recv_caps, 0);
297 ENCODER_CHECK_STATUS(NULL != recv_caps, GST_FLOW_ERROR, "gst_vaapi_encode_chain, 1st buffer didn't have detailed caps.");
298 if (gst_structure_get_int (recv_struct, "width", &width)) {
299 encode->encoder->width = width;
301 if (gst_structure_get_int (recv_struct, "height", &height)) {
302 encode->encoder->height = height;
304 framerate = gst_structure_get_value (recv_struct, "framerate");
306 fps_n = gst_value_get_fraction_numerator (framerate);
307 fps_d = gst_value_get_fraction_denominator (framerate);
308 encode->encoder->frame_rate = fps_n/fps_d;
310 format_value = gst_structure_get_value (recv_struct, "format");
311 if (format_value && GST_IS_H264ENCODE(encode)) {
312 ENCODER_CHECK_STATUS(format_value && GST_TYPE_FOURCC == G_VALUE_TYPE(format_value),
313 GST_FLOW_ERROR, "1st buffer caps' format type is not fourcc.");
314 format = gst_value_get_fourcc (format_value);
316 gst_vaapi_base_encoder_set_input_format(GST_VAAPI_BASE_ENCODER(encode->encoder), format);
321 if (encode->srcpad_caps) {
322 gst_caps_unref(encode->srcpad_caps);
324 encode->srcpad_caps = gst_caps_copy(gst_pad_get_pad_template_caps(encode->srcpad));
325 src_struct = gst_caps_get_structure(encode->srcpad_caps, 0);
326 gst_structure_set(src_struct, "width", G_TYPE_INT, width,
327 "height", G_TYPE_INT, height,
328 "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
330 /*set display and initialize encoder*/
331 if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
332 GstVaapiDisplay *display = NULL;
333 GstVaapiVideoBuffer *video_buffer = GST_VAAPI_VIDEO_BUFFER(buf);
334 ENCODER_ASSERT(video_buffer);
335 display = gst_vaapi_video_buffer_get_display(video_buffer);
338 surface_pool = GST_VAAPI_SURFACE_POOL(gst_vaapi_video_buffer_get_surface_pool(video_buffer));
341 ENCODER_CHECK_STATUS(gst_vaapi_encoder_set_display(encode->encoder,display)
342 , GST_FLOW_ERROR, "set display failed in gst_vaapi_encode_chain.");
345 encoder_ret = gst_vaapi_encoder_initialize(encode->encoder);
346 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, GST_FLOW_ERROR, "gst_vaapi_encoder_initialize failed.");
348 encoder_ret = gst_vaapi_encoder_open(encode->encoder, surface_pool);
350 VAAPI_UNUSED_ARG(surface_pool);
351 encoder_ret = gst_vaapi_encoder_open(encode->encoder, NULL);
353 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, GST_FLOW_ERROR, "gst_vaapi_encoder_open failed.");
355 encode->first_sink_frame = FALSE;
359 ENCODER_ASSERT(gst_vaapi_encoder_get_state(encode->encoder) >= VAAPI_ENC_OPENED);
361 ENCODER_LOG_DEBUG("input %d", input_count);
362 encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf, &out_buffers);
363 ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, GST_FLOW_ERROR, "gst_vaapi_encoder_encode failed.");
366 while (out_buffers) {
367 tmp_buffer = out_buffers->data;
368 out_buffers = g_list_remove(out_buffers, tmp_buffer);
369 /*out_buffers = g_list_next(out_buffers);*/
370 if (encode->first_src_frame) {
371 GstBuffer *codec_data = NULL;
372 ENCODER_ASSERT(encode->srcpad_caps);
373 /*replace codec data in src pad caps*/
374 if (ENCODER_NO_ERROR == gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data) && codec_data) {
375 gst_caps_set_simple(encode->srcpad_caps, "codec_data",GST_TYPE_BUFFER, codec_data, NULL);
377 if (encode_class->set_encoder_src_caps) {
378 encode_class->set_encoder_src_caps(encode, encode->srcpad_caps);
380 gst_pad_set_caps (encode->srcpad, encode->srcpad_caps);
381 GST_BUFFER_CAPS(tmp_buffer) = gst_caps_ref(encode->srcpad_caps);
382 ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s", _encode_dump_caps(encode->srcpad_caps));
383 encode->first_src_frame = FALSE;
386 ENCODER_LOG_DEBUG("output:%d, %" GST_TIME_FORMAT ", 0x%s",
388 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(tmp_buffer)),
389 vaapi_encoder_dump_bytes(GST_BUFFER_DATA(tmp_buffer),
390 (GST_BUFFER_SIZE(tmp_buffer) > 16? 16: GST_BUFFER_SIZE(tmp_buffer))));
391 gst_pad_push(encode->srcpad, tmp_buffer);
395 gst_buffer_unref(buf);
401 gst_vaapi_encode_buffer_alloc(GstPad * pad, guint64 offset, guint size,
402 GstCaps * caps, GstBuffer ** buf)
404 GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(pad));
405 GstStructure *structure = NULL;
407 GstVaapiDisplay* display = NULL;
408 GstFlowReturn ret = GST_FLOW_ERROR;
411 structure = gst_caps_get_structure(caps, 0);
413 if (!structure || gst_structure_has_name(structure, "video/x-vaapi-surface")) {
414 ENCODER_ASSERT(encode->encoder);
415 display = gst_vaapi_encoder_get_display(encode->encoder);
417 gst_vaapi_encoder_initialize(encode->encoder);
418 display = gst_vaapi_encoder_get_display(encode->encoder);
419 ENCODER_CHECK_STATUS(display, GST_FLOW_ERROR, "gst_vaapi_encoder_get_display failed in gst_vaapi_encode_buffer_alloc.");
421 buffer = gst_vaapi_video_buffer_new(display);
422 } else { /* video/x-raw-yuv */
423 buffer = gst_buffer_new_and_alloc(size);
426 ENCODER_CHECK_STATUS(buffer, GST_FLOW_ERROR, "gst_vaapi_encode_buffer_alloc failed.");
428 GST_BUFFER_OFFSET (buffer) = offset;
430 gst_buffer_set_caps(buffer, caps);
437 g_object_unref(display);
444 _encode_dump_caps(GstCaps *cpas)
447 GstStructure const *structure;
449 static char caps_string[4096*5];
452 char *cur = caps_string;
453 memset(caps_string, 0, sizeof(caps_string));
454 for (i = 0; i < gst_caps_get_size(cpas); i++) {
455 structure = gst_caps_get_structure(cpas, i);
456 const char* caps_name = gst_structure_get_name (structure);
457 sprintf(cur, "cap_%02d:%s\n", i, caps_name);
460 for (j = 0; j < gst_structure_n_fields(structure); j++) {
461 const char* name = gst_structure_nth_field_name(structure, j);
462 value = gst_structure_get_value(structure, name);
463 tmp = gst_value_serialize(value);
464 sprintf(cur, "\t%s:%s(%s)\n", name, tmp, G_VALUE_TYPE_NAME(value));
475 vaapi_encode_sets_init (GstPlugin * plugin)
479 ret &= gst_element_register (plugin, "vah264encode", GST_RANK_PRIMARY,
480 GST_TYPE_H264ENCODE);
481 ret &= gst_element_register (plugin, "vah263encode", GST_RANK_PRIMARY,
482 GST_TYPE_H263ENCODE);
483 ret &= gst_element_register (plugin, "vampeg4encode", GST_RANK_PRIMARY,
484 GST_TYPE_MPEG4ENCODE);
488 /* gstreamer looks for this structure to register mrstcamsrc */
494 vaapi_encode_sets_init,
498 "http://gstreamer.net/")